284 lines
10 KiB
Twig
284 lines
10 KiB
Twig
|
|
{#
|
||
|
|
/**
|
||
|
|
* Copyright (C) 2024 Xibo Signage Ltd
|
||
|
|
*
|
||
|
|
* Xibo - Digital Signage - https://xibosignage.com
|
||
|
|
*
|
||
|
|
* This file is part of Xibo.
|
||
|
|
*
|
||
|
|
* Xibo is free software: you can redistribute it and/or modify
|
||
|
|
* it under the terms of the GNU Affero General Public License as published by
|
||
|
|
* the Free Software Foundation, either version 3 of the License, or
|
||
|
|
* any later version.
|
||
|
|
*
|
||
|
|
* Xibo 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 Affero General Public License for more details.
|
||
|
|
*
|
||
|
|
* You should have received a copy of the GNU Affero General Public License
|
||
|
|
* along with Xibo. If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
*/
|
||
|
|
#}
|
||
|
|
{% extends "authed.twig" %}
|
||
|
|
{% import "inline.twig" as inline %}
|
||
|
|
|
||
|
|
{% block title %}{{ "Notification Centre"|trans }} | {% endblock %}
|
||
|
|
|
||
|
|
{% block actionMenu %}
|
||
|
|
<div class="widget-action-menu pull-right">
|
||
|
|
{% if currentUser.featureEnabled("notification.add") %}
|
||
|
|
<button class="btn btn-success XiboFormButton" href="{{ url_for("notification.add.form") }}"><i class="fa fa-plus-circle" aria-hidden="true"></i> {% trans "Add Notification" %}</button>
|
||
|
|
{% endif %}
|
||
|
|
<button class="btn btn-primary" id="refreshGrid" title="{% trans "Refresh the Table" %}" href="#"><i class="fa fa-refresh" aria-hidden="true"></i></button>
|
||
|
|
</div>
|
||
|
|
{% endblock %}
|
||
|
|
|
||
|
|
{% block pageContent %}
|
||
|
|
<div class="widget">
|
||
|
|
<div class="widget-title">{% trans "Notification Centre" %}</div>
|
||
|
|
<div class="widget-body">
|
||
|
|
<div class="XiboGrid" id="{{ random() }}" data-grid-name="notificationView">
|
||
|
|
<div class="XiboFilter card mb-3 bg-light">
|
||
|
|
<div class="FilterDiv card-body" id="Filter">
|
||
|
|
<form class="form-inline">
|
||
|
|
{% set title %}{% trans "Status" %}{% endset %}
|
||
|
|
{% set option1 = "My Read"|trans %}
|
||
|
|
{% set option2 = "My Unread"|trans %}
|
||
|
|
{% set option3 = "All"|trans %}
|
||
|
|
{% set values = [{id: 1, value: option1}, {id: 0, value: option2}] %}
|
||
|
|
{% if currentUser.isSuperAdmin() %}
|
||
|
|
{% set values = values|merge([{id:null, value:option3}]) %}
|
||
|
|
{% endif %}
|
||
|
|
{{ inline.dropdown("read", "single", title, 0, values, "id", "value") }}
|
||
|
|
|
||
|
|
{% set options = [
|
||
|
|
{ optionid: "", option: "All" },
|
||
|
|
{ optionid: "custom", option: "Custom"|trans },
|
||
|
|
{ optionid: "dataset", option: "DataSet"|trans },
|
||
|
|
{ optionid: "display", option: "Display"|trans },
|
||
|
|
{ optionid: "layout", option: "Layout"|trans },
|
||
|
|
{ optionid: "library", option: "Library"|trans },
|
||
|
|
{ optionid: "report", option: "Report"|trans },
|
||
|
|
{ optionid: "schedule", option: "Schedule"|trans },
|
||
|
|
] %}
|
||
|
|
{% set title %}{% trans "Type" %}{% endset %}
|
||
|
|
|
||
|
|
{{ inline.dropdown("type", "single", title, "", options, "optionid", "option", helpText) }}
|
||
|
|
|
||
|
|
{% set title %}{% trans "Date" %}{% endset %}
|
||
|
|
{{ inline.dateTime("releaseDt", title, "", helpText, "", "") }}
|
||
|
|
</form>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div class="XiboData card pt-3">
|
||
|
|
<table id="notifications" class="table table-striped" data-state-preference-name="notificationGrid">
|
||
|
|
<thead>
|
||
|
|
<tr>
|
||
|
|
<th>{% trans "Subject" %}</th>
|
||
|
|
<th>{% trans "Type" %}</th>
|
||
|
|
<th>{% trans "Date" %}</th>
|
||
|
|
<th>{% trans "Interrupt?" %}</th>
|
||
|
|
<th class="rowMenu"></th>
|
||
|
|
</tr>
|
||
|
|
</thead>
|
||
|
|
<tbody>
|
||
|
|
|
||
|
|
</tbody>
|
||
|
|
</table>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
{% endblock %}
|
||
|
|
|
||
|
|
{% block javaScript %}
|
||
|
|
<script type="text/javascript" nonce="{{ cspNonce }}">
|
||
|
|
$(function() {
|
||
|
|
var table = $("#notifications").DataTable({
|
||
|
|
language: dataTablesLanguage,
|
||
|
|
dom: dataTablesTemplate,
|
||
|
|
serverSide: true,
|
||
|
|
stateSave: true,
|
||
|
|
stateDuration: 0,
|
||
|
|
responsive: true,
|
||
|
|
stateLoadCallback: dataTableStateLoadCallback,
|
||
|
|
stateSaveCallback: dataTableStateSaveCallback,
|
||
|
|
filter: false,
|
||
|
|
searchDelay: 3000,
|
||
|
|
order: [[ 1, 'desc']],
|
||
|
|
ajax: {
|
||
|
|
url: "{{ url_for('notification.search') }}",
|
||
|
|
data: function(d) {
|
||
|
|
$.extend(d, $('#notifications').closest('.XiboGrid').find('.FilterDiv form').serializeObject());
|
||
|
|
}
|
||
|
|
},
|
||
|
|
columns: [
|
||
|
|
{
|
||
|
|
data: 'subject',
|
||
|
|
responsivePriority: 2
|
||
|
|
},
|
||
|
|
{
|
||
|
|
data: 'type',
|
||
|
|
responsivePriority: 2
|
||
|
|
},
|
||
|
|
{
|
||
|
|
data: 'releaseDt',
|
||
|
|
responsivePriority: 2,
|
||
|
|
render: dataTableDateFromUnix
|
||
|
|
},
|
||
|
|
{
|
||
|
|
data: 'isInterrupt',
|
||
|
|
responsivePriority: 3,
|
||
|
|
render: dataTableTickCrossColumn
|
||
|
|
},
|
||
|
|
{
|
||
|
|
orderable: false,
|
||
|
|
responsivePriority : 1,
|
||
|
|
data: dataTableButtonsColumn
|
||
|
|
}
|
||
|
|
]
|
||
|
|
});
|
||
|
|
|
||
|
|
table.on('draw', dataTableDraw);
|
||
|
|
table.on('processing.dt', dataTableProcessing);
|
||
|
|
dataTableAddButtons(table, $('#notifications_wrapper').find('.dataTables_buttons'));
|
||
|
|
|
||
|
|
$("#refreshGrid").click(function () {
|
||
|
|
table.ajax.reload();
|
||
|
|
});
|
||
|
|
|
||
|
|
const notificationShow = _.debounce(function() {
|
||
|
|
const data = table.row($(this)).data();
|
||
|
|
let showUrl = "{{ url_for('notification.show', {id: ':rowId'}) }}".replace(':rowId', data.notificationId);
|
||
|
|
XiboFormRender(showUrl);
|
||
|
|
}, 500);
|
||
|
|
|
||
|
|
$("#notifications tbody").on('dblclick', 'tr', notificationShow);
|
||
|
|
});
|
||
|
|
|
||
|
|
var attachmentFormSubmit = function(dialog) {
|
||
|
|
var form = $(dialog);
|
||
|
|
|
||
|
|
// Update any text editor instances we have
|
||
|
|
for(var editor in formHelpers.ckEditorInstances) {
|
||
|
|
formHelpers.updateCKEditor(
|
||
|
|
formHelpers.ckEditorInstances[editor].id,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Submit via ajax - change the attachment color on success
|
||
|
|
$.ajax({
|
||
|
|
type: form.attr("method"),
|
||
|
|
url: form.attr("action"),
|
||
|
|
cache: false,
|
||
|
|
dataType: "json",
|
||
|
|
data: $(form).serialize(),
|
||
|
|
success: function(xhr, textStatus, error) {
|
||
|
|
|
||
|
|
XiboSubmitResponse(xhr, form);
|
||
|
|
|
||
|
|
if (xhr.success) {
|
||
|
|
console.debug('success');
|
||
|
|
}
|
||
|
|
},
|
||
|
|
error: function(xhr, textStatus, errorThrown) {
|
||
|
|
SystemMessage(xhr.responseText, false);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
var attachmentFormSetup = function(dialog) {
|
||
|
|
// Conjure up a text editor
|
||
|
|
formHelpers.createCKEditor('notificationMessage', $('#body')).then((editor) => {
|
||
|
|
// Update text area when unfocusing editor
|
||
|
|
editor.ui.focusTracker.on('change:isFocused', (evt, name, isFocused ) => {
|
||
|
|
if (!isFocused) {
|
||
|
|
// Update editor
|
||
|
|
formHelpers.updateCKEditor('notificationMessage');
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// Make sure when we close the dialog we also destroy the editor
|
||
|
|
dialog.on("hide.bs.modal", function(event) {
|
||
|
|
if ($(event.target).hasClass('bootbox')) {
|
||
|
|
formHelpers.destroyCKEditor('notificationMessage');
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
var attachmentImageList = $('#attachmentImageId');
|
||
|
|
var attachmentChanged = false;
|
||
|
|
|
||
|
|
// Bind to the attachment add button click
|
||
|
|
$("#attachmentAddButton").on("click", function(e) {
|
||
|
|
notificationAddFormAttachmentButtonClicked(e, dialog);
|
||
|
|
});
|
||
|
|
|
||
|
|
// Validate form
|
||
|
|
forms.validateForm(
|
||
|
|
dialog.find('#notificationForm'), // form
|
||
|
|
dialog, // container
|
||
|
|
{
|
||
|
|
submitHandler: attachmentFormSubmit,
|
||
|
|
},
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Add notification attachment add image button
|
||
|
|
* @param e the event
|
||
|
|
* @param dialog the dialog
|
||
|
|
*/
|
||
|
|
function notificationAddFormAttachmentButtonClicked(e, dialog) {
|
||
|
|
e.preventDefault();
|
||
|
|
|
||
|
|
// Open an upload form
|
||
|
|
var upload = openUploadForm({
|
||
|
|
url: "{{ url_for("notification.addattachment") }}",
|
||
|
|
title: "{% trans "Browse/Add attachment" %}",
|
||
|
|
videoImageCovers: false,
|
||
|
|
animateDialog: false,
|
||
|
|
className: "second-dialog",
|
||
|
|
buttons: {
|
||
|
|
main: {
|
||
|
|
label: "{% trans "Done" %}",
|
||
|
|
className: "btn-primary btn-bb-main",
|
||
|
|
callback: function () {
|
||
|
|
upload.modal('hide');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
},
|
||
|
|
templateOptions: {
|
||
|
|
multi: false,
|
||
|
|
trans: {
|
||
|
|
addFiles: "{% trans "Browse/Add Attachment" %}",
|
||
|
|
startUpload: "{% trans "Start Upload" %}",
|
||
|
|
cancelUpload: "{% trans "Cancel Upload" %}"
|
||
|
|
},
|
||
|
|
upload: {
|
||
|
|
maxSize: {{ libraryUpload.maxSize }},
|
||
|
|
maxSizeMessage: "{{ libraryUpload.maxSizeMessage }}",
|
||
|
|
validExt: "jpg|jpeg|png|bmp|gif|zip|pdf"
|
||
|
|
},
|
||
|
|
folderSelector: false
|
||
|
|
},
|
||
|
|
uploadDoneEvent: function (data) {
|
||
|
|
// Get the attachment filename
|
||
|
|
var filename = data.result.files[0].name;
|
||
|
|
|
||
|
|
dialog.find("input[name='attachedFilename']").remove();
|
||
|
|
|
||
|
|
// Create a hidden field with the filename
|
||
|
|
$("#notificationForm").append($("<input type='hidden' name='attachedFilename' value='" + filename + "'/>"));
|
||
|
|
|
||
|
|
// Close
|
||
|
|
upload.modal('hide');
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
|
||
|
|
{# CKEDITOR #}
|
||
|
|
<script src="{{ theme.rootUri() }}dist/wysiwygEditor.bundle.min.js?v={{ version }}&rev={{revision}}" nonce="{{ cspNonce }}"></script>
|
||
|
|
{% endblock %}
|