From 220ff161e9cd3130cb3e1f5a03e882c1868e5143 Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Mon, 22 Dec 2014 05:58:48 -0500 Subject: [PATCH] Bug 11431: Add additional sound options This patch set replaces and extends Koha's current sound options. This is implemented be removing the existing sound system, and re-engineering using a table of selector/sound combinations such that the highest precedence selector that is found in the DOM will trigger and audio alert. The existing audio behaviors are implemented as a set of default audio alerts. Test Plan: 1) Apply this patch set 2) Run updatedatabase.pl 3) Enable the AudioAlerts system preference 4) Test existing sounds 5) Enter the new alerts editor in the admin section 6) Add a new audo alert with the following selector: "body:contains('Check in message')", choose any sound alert you wish, make sure it's not one of the 3 sounds already used! Make this selector precedence 1 4) Browse to the checkins page, you should hear the default sound 5) Attempt to return an invalid barcode, you should hear your custom sound! Signed-off-by: Nick Clemens Signed-off-by: Katrin Fischer --- Koha/AudioAlert.pm | 79 +++++++++ Koha/AudioAlerts.pm | 157 ++++++++++++++++++ Koha/Object.pm | 3 +- Koha/Template/Plugin/Koha.pm | 14 +- admin/audio_alerts.pl | 60 +++++++ circ/circulation.pl | 2 +- circ/returns.pl | 2 +- .../prog/en/includes/admin-menu.inc | 1 + .../prog/en/includes/doc-head-close.inc | 47 ++++-- .../prog/en/includes/intranet-bottom.inc | 1 + .../intranet-tmpl/prog/en/js/staff-global.js | 8 + .../prog/en/modules/admin/admin-home.tt | 2 + .../prog/en/modules/admin/audio_alerts.tt | 131 +++++++++++++++ .../admin/preferences/circulation.pref | 7 - .../admin/preferences/staff_client.pref | 6 + .../prog/en/modules/circ/circulation.tt | 15 +- .../prog/en/modules/circ/returns.tt | 41 +---- .../en/modules/help/admin/audio_alerts.tt | 29 ++++ 18 files changed, 537 insertions(+), 68 deletions(-) create mode 100644 Koha/AudioAlert.pm create mode 100644 Koha/AudioAlerts.pm create mode 100755 admin/audio_alerts.pl create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/admin/audio_alerts.tt create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/help/admin/audio_alerts.tt diff --git a/Koha/AudioAlert.pm b/Koha/AudioAlert.pm new file mode 100644 index 0000000000..4bedbb9bfb --- /dev/null +++ b/Koha/AudioAlert.pm @@ -0,0 +1,79 @@ +package Koha::AudioAlert; + +# Copyright ByWater Solutions 2014 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Carp; + +use Koha::Database; + +use base qw(Koha::Object); + +=head1 NAME + +Koha::AudioAlert - Koha Borrower Object class + +=head1 API + +=head2 Class Methods + +=head3 store + +Override base store to set default precedence +if there is not one set already. + +=cut + +sub store { + my ($self) = @_; + + $self->precedence( Koha::AudioAlerts->get_next_precedence() ) unless defined $self->precedence(); + + return $self->SUPER::store(); +} + +=head3 move + +$alert->move('up'); + +Changes the alert's precedence up, down, top, or bottom + +=cut + +sub move { + my ( $self, $where ) = @_; + + return Koha::AudioAlerts->move( { audio_alert => $self, where => $where } ); +} + +=head3 type + +=cut + +sub type { + return 'AudioAlert'; +} + +=head1 AUTHOR + +Kyle M Hall + +=cut + +1; diff --git a/Koha/AudioAlerts.pm b/Koha/AudioAlerts.pm new file mode 100644 index 0000000000..1127297075 --- /dev/null +++ b/Koha/AudioAlerts.pm @@ -0,0 +1,157 @@ +package Koha::AudioAlerts; + +# Copyright ByWater Solutions 2014 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Carp; + +use Koha::Database; + +use Koha::AudioAlert; + +use base qw(Koha::Objects); + +=head1 NAME + +Koha::AudioAlert - Koha Borrower Object class + +=head1 API + +=head2 Class Methods + +=head3 search + +Overrides default search such that +the default ordering is by precedence + +=cut + +sub search { + my ( $self, $params, $attributes ) = @_; + + $attributes->{order_by} ||= 'precedence'; + + return $self->SUPER::search( $params, $attributes ); +} + +=head3 get_next_precedence + +Gets the next precedence value for audio alerts + +=cut + +sub get_next_precedence { + my ($self) = @_; + + return $self->get_last_precedence() + 1; +} + +=head3 get_last_precedence + +Gets the last precedence value for audio alerts + +=cut + +sub get_last_precedence { + my ($self) = @_; + + return $self->_resultset()->get_column('precedence')->max(); +} + +=head3 move + +Koha::AudioAlerts->move( { audio_alert => $audio_alert, where => $where } ); + +Moves the given alert precedence 'up', 'down', 'top' or 'bottom' + +=cut + +sub move { + my ( $self, $params ) = @_; + + my $alert = $params->{audio_alert}; + my $where = $params->{where}; + + return unless ( $alert && $where ); + + if ( $where eq 'up' ) { + unless ( $alert->precedence() == 1 ) { + my ($other) = $self->search( { precedence => $alert->precedence() - 1 } ); + $other->precedence( $alert->precedence() )->store(); + $alert->precedence( $alert->precedence() - 1 )->store(); + } + } + elsif ( $where eq 'down' ) { + unless ( $alert->precedence() == $self->get_last_precedence() ) { + my ($other) = $self->search( { precedence => $alert->precedence() + 1 } ); + $other->precedence( $alert->precedence() )->store(); + $alert->precedence( $alert->precedence() + 1 )->store(); + } + } + elsif ( $where eq 'top' ) { + $alert->precedence(0)->store(); + $self->fix_precedences(); + } + elsif ( $where eq 'bottom' ) { + $alert->precedence( $self->get_next_precedence() )->store(); + $self->fix_precedences(); + } +} + +=head3 fix_precedences + +Koha::AudioAlerts->fix_precedences(); + +Updates precedence numbers to start with 1 +and to have no gaps + +=cut + +sub fix_precedences { + my ($self) = @_; + + my @alerts = $self->search(); + + my $i = 1; + map { $_->precedence( $i++ )->store() } @alerts; +} + +=head3 type + +=cut + +sub type { + return 'AudioAlert'; +} + +=head3 object_class + +=cut + +sub object_class { + return 'Koha::AudioAlert'; +} + +=head1 AUTHOR + +Kyle M Hall + +=cut + +1; diff --git a/Koha/Object.pm b/Koha/Object.pm index d8f2b42a64..93fdbe0dfe 100644 --- a/Koha/Object.pm +++ b/Koha/Object.pm @@ -255,7 +255,8 @@ sub AUTOLOAD { # Using direct setter/getter like $item->barcode() or $item->barcode($barcode); if ( grep {/^$method$/} @columns ) { if ( @_ ) { - return $self->_result()->set_column( $method, @_ ); + $self->_result()->set_column( $method, @_ ); + return $self; } else { my $value = $self->_result()->get_column( $method ); return $value; diff --git a/Koha/Template/Plugin/Koha.pm b/Koha/Template/Plugin/Koha.pm index 86f9e77ec0..be69c448cb 100644 --- a/Koha/Template/Plugin/Koha.pm +++ b/Koha/Template/Plugin/Koha.pm @@ -18,6 +18,8 @@ package Koha::Template::Plugin::Koha; # along with Koha; if not, see . use Modern::Perl; +use Encode qw( encode ); +use JSON; use base qw( Template::Plugin ); @@ -47,16 +49,20 @@ sub Preference { sub Version { my $version_string = Koha::version(); - my ($major,$minor,$maintenance,$development) = split('\.',$version_string); + my ( $major, $minor, $maintenance, $development ) = split( '\.', $version_string ); return { major => $major, release => $major . "." . $minor, maintenance => $major . "." . $minor . "." . $maintenance, - development => ( $development ne '000' ) - ? $development - : undef + development => ( $development ne '000' ) ? $development : undef, }; } +sub AudioAlerts { + my $dbh = C4::Context->dbh; + my $audio_alerts = $dbh->selectall_arrayref( 'SELECT * FROM audio_alerts ORDER BY precedence', { Slice => {} } ); + return encode_json($audio_alerts); +} + 1; diff --git a/admin/audio_alerts.pl b/admin/audio_alerts.pl new file mode 100755 index 0000000000..f62bacdd4e --- /dev/null +++ b/admin/audio_alerts.pl @@ -0,0 +1,60 @@ +#!/usr/bin/perl + +# Copyright 2014 ByWater Solutions +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use CGI; +use C4::Auth; +use C4::Output; +use Koha::AudioAlert; +use Koha::AudioAlerts; + +my $cgi = new CGI; + +my $selector = $cgi->param('selector'); +my $sound = $cgi->param('sound'); +my $id = $cgi->param('id'); +my $action = $cgi->param('action'); +my $where = $cgi->param('where'); +my @delete = $cgi->param('delete'); + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { + template_name => "admin/audio_alerts.tt", + query => $cgi, + type => "intranet", + authnotrequired => 0, + flagsrequired => { parameters => 'parameters_remaining_permissions' }, + debug => 1, + } +); + +if ( $selector && $sound ) { + Koha::AudioAlert->new( { selector => $selector, sound => $sound } )->store(); +} + +map { Koha::AudioAlerts->find($_)->delete() } @delete; + +if ( $id && $action && $where && $action eq 'move' ) { + Koha::AudioAlerts->find($id)->move($where); +} + +$template->param( audio_alerts => scalar Koha::AudioAlerts->search() ); + +output_html_with_http_headers $cgi, $cookie, $template->output; diff --git a/circ/circulation.pl b/circ/circulation.pl index bac91d7497..c8e787257e 100755 --- a/circ/circulation.pl +++ b/circ/circulation.pl @@ -601,7 +601,7 @@ $template->param( is_child => ($borrowernumber && $borrower->{'category_type'} eq 'C'), $view => 1, batch_allowed => $batch_allowed, - soundon => C4::Context->preference("SoundOn"), + AudioAlerts => C4::Context->preference("AudioAlerts"), fast_cataloging => $fast_cataloging, CircAutoPrintQuickSlip => C4::Context->preference("CircAutoPrintQuickSlip"), activeBorrowerRelationship => (C4::Context->preference('borrowerRelationship') ne ''), diff --git a/circ/returns.pl b/circ/returns.pl index 3948a6ea07..bb47552587 100755 --- a/circ/returns.pl +++ b/circ/returns.pl @@ -620,7 +620,7 @@ $template->param( dropboxdate => output_pref($dropboxdate), forgivemanualholdsexpire => $forgivemanualholdsexpire, overduecharges => $overduecharges, - soundon => C4::Context->preference("SoundOn"), + AudioAlerts => C4::Context->preference("AudioAlerts"), BlockReturnOfWithdrawnItems => C4::Context->preference("BlockReturnOfWithdrawnItems"), ); diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc index 281bb54f8c..e38b0b43c1 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc @@ -64,6 +64,7 @@
  • Z39.50/SRU servers
  • Did you mean?
  • Columns settings
  • +
  • Audio alerts
  • diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/doc-head-close.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/doc-head-close.inc index 08d3c20156..e553a86e1c 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/doc-head-close.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/doc-head-close.inc @@ -1,14 +1,16 @@ +[% USE Koha %] +[% USE String %] + [% INCLUDE intranetstylesheet.inc %] -[% IF ( bidi ) %] - -[% END %] +[% IF ( bidi ) %][% END %] [% IF ( IntranetUserCSS ) %][% END %] + @@ -23,6 +25,7 @@ + [% INCLUDE 'validator-strings.inc' %] [% IF ( IntranetUserJS ) %] [% END %] + [% IF ( virtualshelves || intranetbookbag ) %] - + + [% END %] + [% IF LocalCoverImages %] - - + + +[% END %] + +[% IF Koha.Preference('AudioAlerts') %] + [% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/intranet-bottom.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/intranet-bottom.inc index d937656e6c..f9103ce41d 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/intranet-bottom.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/intranet-bottom.inc @@ -65,5 +65,6 @@ [% END %] [% END %] + diff --git a/koha-tmpl/intranet-tmpl/prog/en/js/staff-global.js b/koha-tmpl/intranet-tmpl/prog/en/js/staff-global.js index 2636ec8d99..3552e18993 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/js/staff-global.js +++ b/koha-tmpl/intranet-tmpl/prog/en/js/staff-global.js @@ -120,3 +120,11 @@ function toUC(f) { function confirmDelete(message) { return (confirm(message) ? true : false); } + +function playSound( sound ) { + // This is way faster than substring + if ( ! ( sound.charAt(4) == ':' && sound.charAt(5) == '/' && sound.charAt(6) == '/' ) ) { + sound = AUDIO_ALERT_PATH + sound; + } + document.getElementById("audio-alert").innerHTML = ''; +} diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt index c85aa8ecf0..885654aba6 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt @@ -111,6 +111,8 @@
    Choose which plugins to use to suggest searches to patrons and staff.
    Configure columns
    Hide or show columns for tables.
    +
    Audio alerts
    +
    Define which events trigger which sounds
    diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/audio_alerts.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/audio_alerts.tt new file mode 100644 index 0000000000..d3471cedd6 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/audio_alerts.tt @@ -0,0 +1,131 @@ +[% INCLUDE 'doc-head-open.inc' %] +Koha › Administration › Audio alerts +[% INCLUDE 'doc-head-close.inc' %] + + + + + +[% INCLUDE 'header.inc' %] +[% INCLUDE 'patrons-admin-search.inc' %] + + + +
    +
    +
    +
    +
    +
    + Add new alert + + + + + + +
    + + + + +
    +
    + +
    + + + + + + + + + + + + + [% FOREACH a IN audio_alerts %] + + + + + + + + [% END %] + +
     Precedence SelectorSound
    [% a.precedence %] + + Go up + + + + Go top + + + + Go bottom + + + + Go down + + [% a.selector %][% a.sound %]
    + +

    + +

    +
    +
    +
    +[% INCLUDE 'admin-menu.inc' %] +
    +
    +[% INCLUDE 'intranet-bottom.inc' %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref index d0d2aca781..6a0954df64 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref @@ -39,12 +39,6 @@ Circulation: asc: earliest to latest desc: latest to earliest - due date. - - - - pref: soundon - choices: - yes: "Enable" - no: "Don't enable" - - circulation sounds during checkin and checkout in the staff interface. Not supported by all web browsers yet. - - pref: SpecifyDueDate choices: @@ -704,7 +698,6 @@ Circulation: yes: Show no: "Don't show" - "the print receipt popup dialog when self checkout is finished" - Course Reserves: - - pref: UseCourseReserves diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_client.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_client.pref index 9dfafd6884..992f4123af 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_client.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_client.pref @@ -134,3 +134,9 @@ Staff Client: yes: Show no: "Don't show" - WYSIWYG editor when editing certain HTML system preferences. + - + - pref: AudioAlerts + choices: + yes: "Enable" + no: "Don't enable" + - audio alerts for events defined in the audio alerts section of administration. diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt index 322a0824cc..07ef6cef50 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt @@ -209,7 +209,7 @@ $(document).ready(function() { [% IF ( NEEDSCONFIRMATION ) %]
    -
    +
    [% IF CAN_user_circulate_force_checkout %]

    Please confirm checkout

    [% ELSE %] @@ -403,12 +403,8 @@ $(document).ready(function() { [% IF ( IMPOSSIBLE ) %] -[% IF ( soundon ) %] - -[% END %] -
    -
    +
      [% IF ( STATS ) %] @@ -524,15 +520,12 @@ $(document).ready(function() {
    [% ELSE %] -[% IF ( soundon ) %] - -[% END %] - [% IF (forceallow) %]
    Restriction overridden temporarily
    [% END %] +[% END %] - [% END %] + [% IF ( issued ) %]

    Item checked out

    diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt index aa43b75a0e..4fda4e1163 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt @@ -105,6 +105,7 @@ $(document).ready(function () { + [% INCLUDE 'header.inc' %] [% INCLUDE 'checkin-search.inc' %] @@ -199,11 +200,7 @@ $(document).ready(function () { [% IF ( waiting ) %] -[% IF ( soundon ) %] - -[% END %] - -
    +

    Hold found (item is already waiting): [% title |html %]

    [% IF ( reservenotes ) %]

    Notes: [% reservenotes %]

    [% END %]

    Hold for:

    @@ -251,10 +248,7 @@ $(document).ready(function () { [% IF ( diffbranch ) %] - [% IF ( soundon ) %] - - [% END %] -
    +

    Hold needing transfer found: [% title |html %]

    Hold for:

      @@ -298,20 +292,14 @@ $(document).ready(function () { [% IF ( transfer ) %] -
      +

      Please return [% title or "item" |html %] to [% Branches.GetName( returnbranch ) %]
      ( Print slip )

      - [% IF ( soundon ) %] - - [% END %] [% END %] [% IF ( needstransfer ) %] - [% IF ( soundon ) %] - - [% END %] -

      This item needs to be transferred to [% Branches.GetName( returnbranch ) %]

      +

      This item needs to be transferred to [% Branches.GetName( returnbranch ) %]

      Transfer now?
      [% IF itemnumber %] @@ -337,10 +325,7 @@ $(document).ready(function () { [% IF ( diffbranch ) %] - [% IF ( soundon ) %] - - [% END %] -

      Item consigned:

      +

      Item consigned:

      @@ -369,11 +354,7 @@ $(document).ready(function () { [% IF ( reserved ) %] - [% IF ( soundon ) %] - - [% END %] - -
      +

      Hold found: [% title |html %]

      [% IF ( reservenotes ) %]

      Notes: [% reservenotes %]

      [% END %]
      Hold for:
      @@ -424,7 +405,7 @@ $(document).ready(function () { [% END %] [% IF ( errmsgloop ) %] -
      +

      Check in message

      [% FOREACH errmsgloo IN errmsgloop %] [% IF ( errmsgloo.NotForLoanStatusUpdated ) %] @@ -483,13 +464,7 @@ $(document).ready(function () { [% END %] [% END %] -[% IF ( soundon ) %] - -[% END %] [% ELSE %] -[% IF ( soundon ) %] - -[% END %] [% END %]
      diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/help/admin/audio_alerts.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/help/admin/audio_alerts.tt new file mode 100644 index 0000000000..eccae8b76b --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/help/admin/audio_alerts.tt @@ -0,0 +1,29 @@ +[% INCLUDE 'help-top.inc' %] + +

      Audio alerts

      + +

      This section of Koha lets you specify a given sound to play when a given jQuery selector is matched.

      + +

      Adding a new alert

      + +

      To add a new alert:

      + +
        +
      • Locate the "Add new alert" form.
      • +
      • Enter a selector in the "selector" input, you can see documentation on jQuery selectors here. +
      • Enter a sound to be played, you can either select a built-in Koha sound using the pulldown selector, or you can enter a full URL to a sound file on another server
      • +
      • At this point, you can preview your sound by clicking the "Play sound" button
      • +
      • Click "Save alert" and your done!
      • +
      + +

      Sound precedence

      + +

      Sounds will be played in order from top to bottom. That is, the first select that finds a match will have its sound played.

      + +

      To change the precedence of a given alert, use the four arrows to move it up, down, or to the top or bottom of the list. + +

      Deleting alerts

      + +

      To delete one or more alerts, check the checkboxes for those alerts you wish to delete, then click the "Delete selected alerts" button and confirm you want to delete those alerts. + +[% INCLUDE 'help-bottom.inc' %] -- 2.39.5

      [% title |html %]