View | Details | Raw Unified | Return to bug 40896
Collapse All | Expand All

(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/reports-toolbar.inc (-1 / +1 lines)
Lines 65-71 Link Here
65
    [% IF ( showsql || execute || editsql || save_successful ) %]
65
    [% IF ( showsql || execute || editsql || save_successful ) %]
66
        [% UNLESS ( errors ) # Unless there are errors saving a report %]
66
        [% UNLESS ( errors ) # Unless there are errors saving a report %]
67
            <div class="btn-group">
67
            <div class="btn-group">
68
                <a id="runreport" class="btn btn-default" href="/cgi-bin/koha/reports/guided_reports.pl?id=[% id | html %]&amp;op=run"> <i class="fa fa-play"></i> Run report </a>
68
                [% INCLUDE 'throttled-button.inc' element_type='link' id='runreport' href='/cgi-bin/koha/reports/guided_reports.pl?id=' _ id _ '&op=run' classes='btn btn-default' label=t('Run report') %]
69
            </div>
69
            </div>
70
            [% IF templates.count %]
70
            [% IF templates.count %]
71
                <div class="btn-group">
71
                <div class="btn-group">
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/throttled-button.inc (+23 lines)
Line 0 Link Here
1
[%# USAGE [ INCLUDE 'throttled-button.inc' element_type='button' classes='btn btn-primary' label=t('Run report') attrs={ name => 'op', value => 'cud-run' } ] %]
2
3
[% DEFAULT element_type = 'link' %]
4
[% DEFAULT ready_icon = 'fa fa-play' %]
5
[% DEFAULT active_icon = 'fa fa-spinner fa-spin' %]
6
[% DEFAULT classes = 'btn btn-default' %]
7
[% DEFAULT href = '#' %]
8
9
[%# Common attributes shared by both button and link %]
10
[% BLOCK common_attrs %]class="[% classes | html %]"[% IF id %]id="[% id | html %]"[% END %] data-state="ready" data-throttled-button [% IF attrs %][% FOREACH key IN attrs.keys %][% key | html %]="[% attrs.$key | html %]"[% END %][% END %][% END %]
11
12
[%# Inner content shared by both button and link %]
13
[% BLOCK inner_content %]
14
    <span class="button-icon-ready"><i class="[% ready_icon | html %]"></i></span>
15
    <span class="button-icon-running" style="display: none;"><i class="[% active_icon | html %]"></i></span>
16
    [% UNLESS icon_only %][% label | html %][% END %]
17
[% END %]
18
19
[% IF element_type == 'button' -%]
20
    <button type="submit" [% PROCESS common_attrs %]> [% PROCESS inner_content %] </button>
21
[%- ELSE -%]
22
    <a [% PROCESS common_attrs %] href="[% href | html %]"> [% PROCESS inner_content %] </a>
23
[%- END %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/reports/guided_reports_start.tt (-72 / +61 lines)
Lines 379-386 Link Here
379
                                                        <td>
379
                                                        <td>
380
                                                            <div class="btn-group dropup">
380
                                                            <div class="btn-group dropup">
381
                                                                [%# There should be no space between these two buttons, it would render badly %]
381
                                                                [%# There should be no space between these two buttons, it would render badly %]
382
                                                                <a class="btn btn-default btn-xs" role="button" href="/cgi-bin/koha/reports/guided_reports.pl?id=[% savedreport.id | html %]&amp;op=run"><i class="fa fa-play"></i> Run</a
382
                                                                [% INCLUDE 'throttled-button.inc' element_type='link' href='/cgi-bin/koha/reports/guided_reports.pl?id=' _ savedreport.id _ '&op=run' classes='btn btn-default btn-xs' label=t('Run') attrs={ role => 'button' } %]<a
383
                                                                ><a class="btn btn-default btn-xs dropdown-toggle" id="reportactions[% savedreport.id | html %]" role="button" data-bs-toggle="dropdown" href="#"></a>
383
                                                                    class="btn btn-default btn-xs dropdown-toggle"
384
                                                                    id="reportactions[% savedreport.id | html %]"
385
                                                                    role="button"
386
                                                                    data-bs-toggle="dropdown"
387
                                                                    href="#"
388
                                                                ></a>
384
                                                                <ul class="dropdown-menu" role="menu" aria-labelledby="reportactions[% savedreport.id | html %]">
389
                                                                <ul class="dropdown-menu" role="menu" aria-labelledby="reportactions[% savedreport.id | html %]">
385
                                                                    <li
390
                                                                    <li
386
                                                                        ><a class="dropdown-item" href="/cgi-bin/koha/reports/guided_reports.pl?id=[% savedreport.id | uri %]&amp;op=show"
391
                                                                        ><a class="dropdown-item" href="/cgi-bin/koha/reports/guided_reports.pl?id=[% savedreport.id | uri %]&amp;op=show"
Lines 930-936 Link Here
930
                                [% IF ( template_id ) %]
935
                                [% IF ( template_id ) %]
931
                                    <input type="hidden" name="template" value="[% template_id | html %]" />
936
                                    <input type="hidden" name="template" value="[% template_id | html %]" />
932
                                [% END %]
937
                                [% END %]
933
                                <button type="submit" class="btn btn-primary"><i class="fa fa-play"></i> Run the report</button>
938
                                [% INCLUDE 'throttled-button.inc' element_type='button' classes='btn btn-primary' label=t('Run the report') %]
934
                            </fieldset>
939
                            </fieldset>
935
                        </form>
940
                        </form>
936
                    [% END # / IF ( auth_val_error ) %]
941
                    [% END # / IF ( auth_val_error ) %]
Lines 1575-1581 Link Here
1575
1580
1576
                        <fieldset class="action">
1581
                        <fieldset class="action">
1577
                            <button class="btn btn-primary" type="submit" name="op" value="cud-update_sql">Update SQL</button>
1582
                            <button class="btn btn-primary" type="submit" name="op" value="cud-update_sql">Update SQL</button>
1578
                            <button class="btn btn-default" type="submit" name="op" value="cud-update_and_run_sql">Update and run SQL</button>
1583
                            [% INCLUDE 'throttled-button.inc' element_type='button' classes='btn btn-default' label=t('Update and run SQL') attrs={ name => 'op', value => 'cud-update_and_run_sql' } %]
1579
                            <a href="/cgi-bin/koha/reports/guided_reports.pl?op=list" class="cancel">Cancel</a>
1584
                            <a href="/cgi-bin/koha/reports/guided_reports.pl?op=list" class="cancel">Cancel</a>
1580
                        </fieldset>
1585
                        </fieldset>
1581
                    </form>
1586
                    </form>
Lines 1738-1743 Link Here
1738
    [% Asset.js( "lib/codemirror/highlight.js" ) | $raw %]
1743
    [% Asset.js( "lib/codemirror/highlight.js" ) | $raw %]
1739
    [% Asset.css("lib/codemirror/highlight.css") | $raw %]
1744
    [% Asset.css("lib/codemirror/highlight.css") | $raw %]
1740
    [% Asset.js( "js/mana.js" ) | $raw %]
1745
    [% Asset.js( "js/mana.js" ) | $raw %]
1746
    [% Asset.js( "js/throttledButton.js" ) | $raw %]
1741
    [% INCLUDE 'select2.inc' %]
1747
    [% INCLUDE 'select2.inc' %]
1742
    <script>
1748
    <script>
1743
        //  if the report param form has multiselects override default form submission
1749
        //  if the report param form has multiselects override default form submission
Lines 2005-2022 Link Here
2005
            }
2011
            }
2006
        }
2012
        }
2007
2013
2008
        const toggleReportRunButton = (element => {
2009
            if ($(element).attr('disabled') === undefined) {
2010
                $(element).attr('disabled', 'disabled');
2011
                $(element).addClass('disabled');
2012
                $(element).find('i.fa-play').first().replaceWith('<i class=\"fa fa-spinner fa-spin\" style=\"--fa-animation-duration: 2s;\"></i>');
2013
            } else {
2014
                $(element).removeAttr('disabled');
2015
                $(element).removeClass('disabled');
2016
                $(element).find('i.fa-spinner').first().replaceWith('<i class=\"fa fa-play\"></i>');
2017
            }
2018
        });
2019
2020
        $(document).ready(function(){
2014
        $(document).ready(function(){
2021
2015
2022
            var activeTab = localStorage.getItem("sql_reports_activetab");
2016
            var activeTab = localStorage.getItem("sql_reports_activetab");
Lines 2493-2532 Link Here
2493
                $(selectField).select2();
2487
                $(selectField).select2();
2494
            });
2488
            });
2495
2489
2496
            $('a[href*="/cgi-bin/koha/reports/guided_reports.pl"]').each((idx, element) => {
2497
                const params = new URLSearchParams($(element).attr('href'));
2498
                const op = params.get('op');
2499
2500
                if (op !== 'run') {
2501
                    return;
2502
                }
2503
2504
                $(element).on('click', event => {
2505
                    event.preventDefault();
2506
                    const href = $(element).attr('href');
2507
2508
                    toggleReportRunButton(element);
2509
                    setTimeout(() => {
2510
                        toggleReportRunButton(element);
2511
                    }, 120000);
2512
2513
                    window.location.href = href;
2514
                    return false;
2515
                });
2516
            });
2517
2518
            $('#report_param_form').on('submit', event => {
2519
                const button = $('button[type="submit"]');
2520
2521
                if (button.length < 1) {
2522
                    return;
2523
                }
2524
2525
                toggleReportRunButton(button);
2526
                setTimeout(() => {
2527
                    toggleReportRunButton(button);
2528
                }, 120000);
2529
            });
2530
        });
2490
        });
2531
2491
2532
        $("#toggle_auto_links").on("click", function(e){
2492
        $("#toggle_auto_links").on("click", function(e){
Lines 2669-2701 Link Here
2669
2629
2670
        // Adapted from https://gist.github.com/jnormore/7418776
2630
        // Adapted from https://gist.github.com/jnormore/7418776
2671
        function previewSql(reportid) {
2631
        function previewSql(reportid) {
2672
            var yes_label = "";
2673
            var no_label = "";
2674
            var message = $("#previewSql" + reportid ).val();
2632
            var message = $("#previewSql" + reportid ).val();
2675
            var title = $("#previewSql" + reportid ).data("title");
2633
            var title = $("#previewSql" + reportid ).data("title");
2676
            if( $("#preview-sql-modal").length > 0) {
2634
            if( $("#preview-sql-modal").length > 0) {
2677
                $("#preview-sql-modal").remove();
2635
                $("#preview-sql-modal").remove();
2678
            }
2636
            }
2679
            $("body").append('<div id="preview-sql-modal" tabindex="-1" role="dialog" aria-hidden="true" class="modal">\
2637
2680
                <div class="modal-dialog modal-xl">\
2638
            // Clone the template content
2681
                    <div class="modal-content">\
2639
            var template = document.getElementById('preview-sql-modal-template');
2682
                        <div class="modal-header" style="min-height:40px;">\
2640
            var clone = document.importNode(template.content, true);
2683
                            <h1 class="modal-title">' + title + '</h1>\
2641
2684
                            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="' + _("Close") + '"></button>\
2642
            // Fill in the placeholders
2685
                        </div>\
2643
            clone.querySelector('[data-placeholder="title"]').textContent = title;
2686
                        <div class="modal-body"><textarea id="code' + reportid + '">' + message + '</textarea>\
2644
2687
                        </div>\
2645
            Object.assign(clone.querySelector('[data-placeholder="code"]'), {
2688
                        <div class="modal-footer">\
2646
                id: 'code' + reportid,
2689
                            <a id="preview-modal-editreport" class="btn btn-default" href="/cgi-bin/koha/reports/guided_reports.pl?id=' + reportid + '&amp;op=edit_form"><i class="fa-solid fa-pencil" aria-hidden="true"></i> ' + _("Edit") + '</a>\
2647
                textContent: message
2690
                            <a id="preview-modal-duplicate" class="btn btn-default" href="/cgi-bin/koha/reports/guided_reports.pl?op=duplicate&amp;id=' + reportid + '"><i class="fa fa-copy" aria-hidden="true"></i> ' + _("Duplicate") + '</a>\
2648
            });
2691
                            <a id="preview-modal-duplicate" class="btn btn-default" href="/cgi-bin/koha/tools/scheduler.pl?id=' + reportid + '"><i class="fa-solid fa-clock" aria-hidden="true"></i> ' + _("Schedule") + '</a>\
2649
2692
                            <a class="btn btn-default submit-form-link" href="#" data-id="' + reportid + '" data-action="guided_reports.pl" data-method="post" data-op="cud-delete" data-confirmation-msg="' + _("Are you sure you want to delete this report?") + '"><i class="fa fa-trash-can" aria-hidden="true"></i> ' + _("Delete") + '</a>\
2650
            clone.querySelector('[data-placeholder="edit-href"]').href = '/cgi-bin/koha/reports/guided_reports.pl?id=' + encodeURIComponent(reportid) + '&op=edit_form';
2693
                            <a id="preview-modal-runreport" class="btn btn-default" href="/cgi-bin/koha/reports/guided_reports.pl?id=' + reportid + '&amp;op=run"><i class="fa fa-play" aria-hidden="true"></i> ' + _("Run report") + '</a>\
2651
            clone.querySelector('[data-placeholder="duplicate-href"]').href = '/cgi-bin/koha/reports/guided_reports.pl?op=duplicate&id=' + encodeURIComponent(reportid);
2694
                            <a href="#" id="preview-sql-modal-cancel" data-bs-dismiss="modal" class="btn btn-default"><i class="fa fa-times" aria-hidden="true"></i> ' + _("Close") + '</a>\
2652
            clone.querySelector('[data-placeholder="schedule-href"]').href = '/cgi-bin/koha/tools/scheduler.pl?id=' + encodeURIComponent(reportid);
2695
                        </div>\
2653
2696
                    </div>\
2654
            Object.assign(clone.querySelector('[data-placeholder="delete-attrs"]').dataset, {
2697
                </div>\
2655
                id: reportid,
2698
            </div>');
2656
                action: 'guided_reports.pl',
2657
                method: 'post',
2658
                op: 'cud-delete'
2659
            });
2660
2661
            clone.querySelector('[data-placeholder="run-href"]').href = '/cgi-bin/koha/reports/guided_reports.pl?id=' + encodeURIComponent(reportid) + '&op=run';
2662
2663
            document.body.appendChild(clone);
2699
2664
2700
            $("#preview-sql-modal").on("shown.bs.modal", function(){
2665
            $("#preview-sql-modal").on("shown.bs.modal", function(){
2701
                CodeMirror.fromTextArea( document.getElementById("code" + reportid ), {
2666
                CodeMirror.fromTextArea( document.getElementById("code" + reportid ), {
Lines 2710-2715 Link Here
2710
    </script>
2675
    </script>
2711
[% END %]
2676
[% END %]
2712
2677
2678
<template id="preview-sql-modal-template">
2679
    <div id="preview-sql-modal" tabindex="-1" role="dialog" aria-hidden="true" class="modal">
2680
        <div class="modal-dialog modal-xl">
2681
            <div class="modal-content">
2682
                <div class="modal-header" style="min-height:40px;">
2683
                    <h1 class="modal-title" data-placeholder="title"></h1>
2684
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="[% t('Close') | html %]"></button>
2685
                </div>
2686
                <div class="modal-body"><textarea data-placeholder="code"></textarea></div>
2687
                <div class="modal-footer">
2688
                    <a id="preview-modal-editreport" class="btn btn-default" data-placeholder="edit-href"><i class="fa-solid fa-pencil" aria-hidden="true"></i> Edit</a>
2689
                    <a id="preview-modal-duplicate" class="btn btn-default" data-placeholder="duplicate-href"><i class="fa fa-copy" aria-hidden="true"></i> Duplicate</a>
2690
                    <a id="preview-modal-schedule" class="btn btn-default" data-placeholder="schedule-href"><i class="fa-solid fa-clock" aria-hidden="true"></i> Schedule</a>
2691
                    <a class="btn btn-default submit-form-link" href="#" data-placeholder="delete-attrs" data-confirmation-msg="[% t('Are you sure you want to delete this report?') | html %]"
2692
                        ><i class="fa fa-trash-can" aria-hidden="true"></i> Delete</a
2693
                    >
2694
                    [% INCLUDE 'throttled-button.inc' element_type='link' id='preview-modal-runreport' classes='btn btn-default' label=t('Run report') attrs={ 'data-placeholder' => 'run-href' } %]
2695
                    <a href="#" id="preview-sql-modal-cancel" data-bs-dismiss="modal" class="btn btn-default"><i class="fa fa-times" aria-hidden="true"></i> Close</a>
2696
                </div>
2697
            </div>
2698
        </div>
2699
    </div>
2700
</template>
2701
2713
[% INCLUDE 'intranet-bottom.inc' %]
2702
[% INCLUDE 'intranet-bottom.inc' %]
2714
2703
2715
[% BLOCK group_and_subgroup_selection %]
2704
[% BLOCK group_and_subgroup_selection %]
(-)a/koha-tmpl/intranet-tmpl/prog/js/throttledButton.js (-1 / +71 lines)
Line 0 Link Here
0
- 
1
(() => {
2
    const DEFAULT_TIMEOUT = 3000;
3
4
    const toggleButton = element => {
5
        const isDisabled = element.hasAttribute("disabled");
6
        const readyIcon = element.querySelector(".button-icon-ready");
7
        const runningIcon = element.querySelector(".button-icon-running");
8
9
        if (!readyIcon || !runningIcon) {
10
            return;
11
        }
12
13
        if (!isDisabled) {
14
            element.setAttribute("disabled", "disabled");
15
            element.setAttribute("aria-busy", "true");
16
            element.classList.add("disabled");
17
            element.dataset.state = "running";
18
            readyIcon.style.display = "none";
19
            runningIcon.style.display = "";
20
        } else {
21
            element.removeAttribute("disabled");
22
            element.removeAttribute("aria-busy");
23
            element.classList.remove("disabled");
24
            element.dataset.state = "ready";
25
            readyIcon.style.display = "";
26
            runningIcon.style.display = "none";
27
        }
28
    };
29
30
    // Use event delegation to handle both static and dynamically created links
31
    document.addEventListener("click", event => {
32
        const link = event.target.closest("a[data-throttled-button]");
33
        if (link) {
34
            event.preventDefault();
35
            const href = link.getAttribute("href");
36
37
            toggleButton(link);
38
            window.location.href = href;
39
        }
40
    });
41
42
    // Handle button elements within forms
43
    document.addEventListener("submit", event => {
44
        const submitter = event.submitter;
45
        if (submitter && submitter.hasAttribute("data-throttled-button")) {
46
            const timeoutValue = parseInt(
47
                submitter.dataset.throttleTimeout,
48
                10
49
            );
50
            const timeout = isNaN(timeoutValue)
51
                ? DEFAULT_TIMEOUT
52
                : timeoutValue;
53
54
            requestAnimationFrame(() => {
55
                toggleButton(submitter);
56
                setTimeout(() => toggleButton(submitter), timeout);
57
            });
58
        }
59
    });
60
61
    // Reset button state when page is restored from bfcache
62
    window.addEventListener("pageshow", event => {
63
        if (event.persisted) {
64
            document
65
                .querySelectorAll("[data-throttled-button][disabled]")
66
                .forEach(button => {
67
                    toggleButton(button);
68
                });
69
        }
70
    });
71
})();

Return to bug 40896