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

(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/reports-toolbar.inc (-3 / +1 lines)
Lines 64-72 Link Here
64
64
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"> [% 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') %] </div>
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>
69
            </div>
70
            [% IF templates.count %]
68
            [% IF templates.count %]
71
                <div class="btn-group">
69
                <div class="btn-group">
72
                    <button type="button" class="btn btn-default dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <i class="fa fa-code"></i> Run with template </button>
70
                    <button type="button" class="btn btn-default dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <i class="fa fa-code"></i> Run with template </button>
(-)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 407-414 Link Here
407
                                                        <td>
407
                                                        <td>
408
                                                            <div class="btn-group dropup">
408
                                                            <div class="btn-group dropup">
409
                                                                [%# There should be no space between these two buttons, it would render badly %]
409
                                                                [%# There should be no space between these two buttons, it would render badly %]
410
                                                                <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
410
                                                                [% 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
411
                                                                ><a class="btn btn-default btn-xs dropdown-toggle" id="reportactions[% savedreport.id | html %]" role="button" data-bs-toggle="dropdown" href="#"></a>
411
                                                                    class="btn btn-default btn-xs dropdown-toggle"
412
                                                                    id="reportactions[% savedreport.id | html %]"
413
                                                                    role="button"
414
                                                                    data-bs-toggle="dropdown"
415
                                                                    href="#"
416
                                                                ></a>
412
                                                                <ul class="dropdown-menu" role="menu" aria-labelledby="reportactions[% savedreport.id | html %]">
417
                                                                <ul class="dropdown-menu" role="menu" aria-labelledby="reportactions[% savedreport.id | html %]">
413
                                                                    <li
418
                                                                    <li
414
                                                                        ><a class="dropdown-item" href="/cgi-bin/koha/reports/guided_reports.pl?id=[% savedreport.id | uri %]&amp;op=show"
419
                                                                        ><a class="dropdown-item" href="/cgi-bin/koha/reports/guided_reports.pl?id=[% savedreport.id | uri %]&amp;op=show"
Lines 959-965 Link Here
959
                                [% IF ( template_id ) %]
964
                                [% IF ( template_id ) %]
960
                                    <input type="hidden" name="template" value="[% template_id | html %]" />
965
                                    <input type="hidden" name="template" value="[% template_id | html %]" />
961
                                [% END %]
966
                                [% END %]
962
                                <button type="submit" class="btn btn-primary"><i class="fa fa-play"></i> Run the report</button>
967
                                [% INCLUDE 'throttled-button.inc' element_type='button' classes='btn btn-primary' label=t('Run the report') %]
963
                            </fieldset>
968
                            </fieldset>
964
                        </form>
969
                        </form>
965
                    [% END # / IF ( auth_val_error ) %]
970
                    [% END # / IF ( auth_val_error ) %]
Lines 1606-1612 Link Here
1606
1611
1607
                        <fieldset class="action">
1612
                        <fieldset class="action">
1608
                            <button class="btn btn-primary" type="submit" name="op" value="cud-update_sql">Update SQL</button>
1613
                            <button class="btn btn-primary" type="submit" name="op" value="cud-update_sql">Update SQL</button>
1609
                            <button class="btn btn-default" type="submit" name="op" value="cud-update_and_run_sql">Update and run SQL</button>
1614
                            [% 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' } %]
1610
                            <a href="/cgi-bin/koha/reports/guided_reports.pl?op=list" class="cancel">Cancel</a>
1615
                            <a href="/cgi-bin/koha/reports/guided_reports.pl?op=list" class="cancel">Cancel</a>
1611
                        </fieldset>
1616
                        </fieldset>
1612
                    </form>
1617
                    </form>
Lines 1769-1774 Link Here
1769
    [% Asset.js( "lib/codemirror/highlight.js" ) | $raw %]
1774
    [% Asset.js( "lib/codemirror/highlight.js" ) | $raw %]
1770
    [% Asset.css("lib/codemirror/highlight.css") | $raw %]
1775
    [% Asset.css("lib/codemirror/highlight.css") | $raw %]
1771
    [% Asset.js( "js/mana.js" ) | $raw %]
1776
    [% Asset.js( "js/mana.js" ) | $raw %]
1777
    [% Asset.js( "js/throttledButton.js" ) | $raw %]
1772
    [% INCLUDE 'select2.inc' %]
1778
    [% INCLUDE 'select2.inc' %]
1773
    <script>
1779
    <script>
1774
        //  if the report param form has multiselects override default form submission
1780
        //  if the report param form has multiselects override default form submission
Lines 2036-2053 Link Here
2036
            }
2042
            }
2037
        }
2043
        }
2038
2044
2039
        const toggleReportRunButton = (element => {
2040
            if ($(element).attr('disabled') === undefined) {
2041
                $(element).attr('disabled', 'disabled');
2042
                $(element).addClass('disabled');
2043
                $(element).find('i.fa-play').first().replaceWith('<i class=\"fa fa-spinner fa-spin\" style=\"--fa-animation-duration: 2s;\"></i>');
2044
            } else {
2045
                $(element).removeAttr('disabled');
2046
                $(element).removeClass('disabled');
2047
                $(element).find('i.fa-spinner').first().replaceWith('<i class=\"fa fa-play\"></i>');
2048
            }
2049
        });
2050
2051
        $(document).ready(function(){
2045
        $(document).ready(function(){
2052
2046
2053
            var activeTab = localStorage.getItem("sql_reports_activetab");
2047
            var activeTab = localStorage.getItem("sql_reports_activetab");
Lines 2524-2563 Link Here
2524
                $(selectField).select2();
2518
                $(selectField).select2();
2525
            });
2519
            });
2526
2520
2527
            $('a[href*="/cgi-bin/koha/reports/guided_reports.pl"]').each((idx, element) => {
2528
                const params = new URLSearchParams($(element).attr('href'));
2529
                const op = params.get('op');
2530
2531
                if (op !== 'run') {
2532
                    return;
2533
                }
2534
2535
                $(element).on('click', event => {
2536
                    event.preventDefault();
2537
                    const href = $(element).attr('href');
2538
2539
                    toggleReportRunButton(element);
2540
                    setTimeout(() => {
2541
                        toggleReportRunButton(element);
2542
                    }, 120000);
2543
2544
                    window.location.href = href;
2545
                    return false;
2546
                });
2547
            });
2548
2549
            $('#report_param_form').on('submit', event => {
2550
                const button = $('button[type="submit"]');
2551
2552
                if (button.length < 1) {
2553
                    return;
2554
                }
2555
2556
                toggleReportRunButton(button);
2557
                setTimeout(() => {
2558
                    toggleReportRunButton(button);
2559
                }, 120000);
2560
            });
2561
        });
2521
        });
2562
2522
2563
        $("#toggle_auto_links").on("click", function(e){
2523
        $("#toggle_auto_links").on("click", function(e){
Lines 2700-2732 Link Here
2700
2660
2701
        // Adapted from https://gist.github.com/jnormore/7418776
2661
        // Adapted from https://gist.github.com/jnormore/7418776
2702
        function previewSql(reportid) {
2662
        function previewSql(reportid) {
2703
            var yes_label = "";
2704
            var no_label = "";
2705
            var message = $("#previewSql" + reportid ).val();
2663
            var message = $("#previewSql" + reportid ).val();
2706
            var title = $("#previewSql" + reportid ).data("title");
2664
            var title = $("#previewSql" + reportid ).data("title");
2707
            if( $("#preview-sql-modal").length > 0) {
2665
            if( $("#preview-sql-modal").length > 0) {
2708
                $("#preview-sql-modal").remove();
2666
                $("#preview-sql-modal").remove();
2709
            }
2667
            }
2710
            $("body").append('<div id="preview-sql-modal" tabindex="-1" role="dialog" aria-hidden="true" class="modal">\
2668
2711
                <div class="modal-dialog modal-xl">\
2669
            // Clone the template content
2712
                    <div class="modal-content">\
2670
            var template = document.getElementById('preview-sql-modal-template');
2713
                        <div class="modal-header" style="min-height:40px;">\
2671
            var clone = document.importNode(template.content, true);
2714
                            <h1 class="modal-title">' + title + '</h1>\
2672
2715
                            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="' + _("Close") + '"></button>\
2673
            // Fill in the placeholders
2716
                        </div>\
2674
            clone.querySelector('[data-placeholder="title"]').textContent = title;
2717
                        <div class="modal-body"><textarea id="code' + reportid + '">' + message + '</textarea>\
2675
2718
                        </div>\
2676
            Object.assign(clone.querySelector('[data-placeholder="code"]'), {
2719
                        <div class="modal-footer">\
2677
                id: 'code' + reportid,
2720
                            <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>\
2678
                textContent: message
2721
                            <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>\
2679
            });
2722
                            <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>\
2680
2723
                            <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>\
2681
            clone.querySelector('[data-placeholder="edit-href"]').href = '/cgi-bin/koha/reports/guided_reports.pl?id=' + encodeURIComponent(reportid) + '&op=edit_form';
2724
                            <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>\
2682
            clone.querySelector('[data-placeholder="duplicate-href"]').href = '/cgi-bin/koha/reports/guided_reports.pl?op=duplicate&id=' + encodeURIComponent(reportid);
2725
                            <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>\
2683
            clone.querySelector('[data-placeholder="schedule-href"]').href = '/cgi-bin/koha/tools/scheduler.pl?id=' + encodeURIComponent(reportid);
2726
                        </div>\
2684
2727
                    </div>\
2685
            Object.assign(clone.querySelector('[data-placeholder="delete-attrs"]').dataset, {
2728
                </div>\
2686
                id: reportid,
2729
            </div>');
2687
                action: 'guided_reports.pl',
2688
                method: 'post',
2689
                op: 'cud-delete'
2690
            });
2691
2692
            clone.querySelector('[data-placeholder="run-href"]').href = '/cgi-bin/koha/reports/guided_reports.pl?id=' + encodeURIComponent(reportid) + '&op=run';
2693
2694
            document.body.appendChild(clone);
2730
2695
2731
            $("#preview-sql-modal").on("shown.bs.modal", function(){
2696
            $("#preview-sql-modal").on("shown.bs.modal", function(){
2732
                CodeMirror.fromTextArea( document.getElementById("code" + reportid ), {
2697
                CodeMirror.fromTextArea( document.getElementById("code" + reportid ), {
Lines 2741-2746 Link Here
2741
    </script>
2706
    </script>
2742
[% END %]
2707
[% END %]
2743
2708
2709
<template id="preview-sql-modal-template">
2710
    <div id="preview-sql-modal" tabindex="-1" role="dialog" aria-hidden="true" class="modal">
2711
        <div class="modal-dialog modal-xl">
2712
            <div class="modal-content">
2713
                <div class="modal-header" style="min-height:40px;">
2714
                    <h1 class="modal-title" data-placeholder="title"></h1>
2715
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="[% t('Close') | html %]"></button>
2716
                </div>
2717
                <div class="modal-body"><textarea data-placeholder="code"></textarea></div>
2718
                <div class="modal-footer">
2719
                    <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>
2720
                    <a id="preview-modal-duplicate" class="btn btn-default" data-placeholder="duplicate-href"><i class="fa fa-copy" aria-hidden="true"></i> Duplicate</a>
2721
                    <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>
2722
                    <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 %]"
2723
                        ><i class="fa fa-trash-can" aria-hidden="true"></i> Delete</a
2724
                    >
2725
                    [% INCLUDE 'throttled-button.inc' element_type='link' id='preview-modal-runreport' classes='btn btn-default' label=t('Run report') attrs={ 'data-placeholder' => 'run-href' } %]
2726
                    <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>
2727
                </div>
2728
            </div>
2729
        </div>
2730
    </div>
2731
</template>
2732
2744
[% INCLUDE 'intranet-bottom.inc' %]
2733
[% INCLUDE 'intranet-bottom.inc' %]
2745
2734
2746
[% BLOCK group_and_subgroup_selection %]
2735
[% 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