generic user tracking
This commit is contained in:
parent
becb98cfc5
commit
70a9237951
@ -267,6 +267,10 @@ button.purple:hover {
|
||||
align-self: stretch;
|
||||
}
|
||||
|
||||
.panel.no-border {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.panel h3 {
|
||||
color: #fff;
|
||||
}
|
||||
@ -554,7 +558,7 @@ button.purple:hover {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
form {
|
||||
.form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
@ -562,7 +566,7 @@ form {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
form .form-group {
|
||||
.form .form-group {
|
||||
margin: 10px 20px 5px 20px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@ -572,14 +576,14 @@ form .form-group {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
form .form-group label {
|
||||
.form .form-group label {
|
||||
flex: 1;
|
||||
padding: 10px;
|
||||
text-align: right;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
form .form-group .widget {
|
||||
.form .form-group .widget {
|
||||
flex: 3;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@ -588,9 +592,9 @@ form .form-group .widget {
|
||||
align-self: stretch;
|
||||
}
|
||||
|
||||
form .form-group input,
|
||||
form .form-group select,
|
||||
form .form-group textarea {
|
||||
.form .form-group input,
|
||||
.form .form-group select,
|
||||
.form .form-group textarea {
|
||||
flex: 1;
|
||||
padding: 10px 5px 10px 5px;
|
||||
border: 1px solid #EEE;
|
||||
@ -598,23 +602,23 @@ form .form-group textarea {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
form .form-group input[type=checkbox] {
|
||||
.form .form-group input[type=checkbox] {
|
||||
flex: 0;
|
||||
}
|
||||
|
||||
form .form-group .trigger {
|
||||
.form .form-group .trigger {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
form .form-group select.trigger {
|
||||
.form .form-group select.trigger {
|
||||
max-width: 120px;
|
||||
}
|
||||
|
||||
form .form-group span {
|
||||
.form .form-group span {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
form .actions {
|
||||
.form .actions {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
@ -623,25 +627,25 @@ form .actions {
|
||||
align-self: stretch;
|
||||
}
|
||||
|
||||
form .actions button.green,
|
||||
form .actions button {
|
||||
.form .actions button.green,
|
||||
.form .actions button {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
form .actions button.green:hover {
|
||||
.form .actions button.green:hover {
|
||||
background: white;
|
||||
color: rgb(14, 239, 95);
|
||||
border-color: rgb(14, 239, 95);
|
||||
}
|
||||
|
||||
form .actions button.btn-normal {
|
||||
.form .actions button.btn-normal {
|
||||
color: #999;
|
||||
border-color: #999;
|
||||
font-size: 18px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
form .actions button.btn-normal:hover {
|
||||
.form .actions button.btn-normal:hover {
|
||||
color: #555;
|
||||
border-color: #555;
|
||||
}
|
||||
@ -677,19 +681,19 @@ footer .version {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.card form {
|
||||
.card .form {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card form .form-group {
|
||||
.card .form .form-group {
|
||||
margin: 0 0 30px 0;
|
||||
padding: 0;
|
||||
}
|
||||
.card form .form-group .widget {
|
||||
.card .form .form-group .widget {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.card form .form-group label {
|
||||
.card .form .form-group label {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
@ -757,4 +761,97 @@ a.badge:hover {
|
||||
margin-left: 34px;
|
||||
color: #999;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.explorer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
align-self: stretch;
|
||||
}
|
||||
|
||||
|
||||
.explorer .left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
align-self: stretch;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.explorer .right {
|
||||
flex: 3;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.panel.panel-menu {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
align-self: stretch;
|
||||
margin-right: 0;
|
||||
border-color: #692fbd;
|
||||
}
|
||||
|
||||
.panel.panel-menu ul {
|
||||
flex: 1;
|
||||
max-width: 250px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-self: stretch;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.panel.panel-menu ul li {
|
||||
margin: 3px 0;
|
||||
}
|
||||
|
||||
.panel.panel-menu ul li a {
|
||||
padding: 5px 15px 5px 15px;
|
||||
color: inherit;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.panel.panel-menu ul li:hover {
|
||||
color: #555;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.panel.panel-menu ul li.active {
|
||||
color: #692fbd;
|
||||
background: #692fbd22;
|
||||
border-radius: 4px;
|
||||
font-weight: bold;
|
||||
border: 1px solid #692fbd;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.explorer .panel-active {
|
||||
background: white;
|
||||
color: #AAA;
|
||||
border-color: #BBB;
|
||||
}
|
||||
.explorer .panel-active h3 {
|
||||
color: #0bc44e;
|
||||
}
|
||||
|
||||
|
||||
.explorer .panel-inactive {
|
||||
background: white;
|
||||
color: #AAA;
|
||||
border-color: #BBB;
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
jQuery(document).ready(function ($) {
|
||||
const $tableActive = $('table.active-users');
|
||||
const $tableInactive = $('table.inactive-users');
|
||||
const $modalsRoot = $('.modals');
|
||||
|
||||
const getId = function ($el) {
|
||||
return $el.is('tr') ? $el.attr('data-level') : $el.parents('tr:eq(0)').attr('data-level');
|
||||
@ -15,16 +14,6 @@ jQuery(document).ready(function ($) {
|
||||
$(this).find('tr.empty-tr').addClass('hidden');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const showModal = function (modalClass) {
|
||||
$modalsRoot.removeClass('hidden').find('form').trigger('reset');
|
||||
$modalsRoot.find('.modal').addClass('hidden');
|
||||
$modalsRoot.find('.modal.' + modalClass).removeClass('hidden');
|
||||
};
|
||||
|
||||
const hideModal = function () {
|
||||
$modalsRoot.addClass('hidden').find('form').trigger('reset');
|
||||
};
|
||||
|
||||
const main = function () {
|
||||
@ -72,10 +61,6 @@ jQuery(document).ready(function ($) {
|
||||
;
|
||||
});
|
||||
|
||||
$(document).on('click', '.modal-close', function () {
|
||||
hideModal();
|
||||
});
|
||||
|
||||
$(document).on('click', '.user-add', function () {
|
||||
showModal('modal-user-add');
|
||||
$('.modal-user-add input:eq(0)').focus().select();
|
||||
@ -108,11 +93,5 @@ jQuery(document).ready(function ($) {
|
||||
}
|
||||
});
|
||||
|
||||
$(document).keyup(function (e) {
|
||||
if (e.key === "Escape") {
|
||||
hideModal();
|
||||
}
|
||||
});
|
||||
|
||||
main();
|
||||
});
|
||||
64
data/www/js/fleet/node-player-groups.js
Normal file
64
data/www/js/fleet/node-player-groups.js
Normal file
@ -0,0 +1,64 @@
|
||||
jQuery(document).ready(function ($) {
|
||||
|
||||
const getId = function ($el) {
|
||||
return $el.is('tr') ? $el.attr('data-level') : $el.parents('tr:eq(0)').attr('data-level');
|
||||
};
|
||||
|
||||
const updateTable = function () {
|
||||
$('table').each(function () {
|
||||
if ($(this).find('tbody tr.node-player-group-item:visible').length === 0) {
|
||||
$(this).find('tr.empty-tr').removeClass('hidden');
|
||||
} else {
|
||||
$(this).find('tr.empty-tr').addClass('hidden');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const main = function () {
|
||||
|
||||
};
|
||||
|
||||
$(document).on('change', '#node-player-group-add-type', function () {
|
||||
const value = $(this).val();
|
||||
const inputType = $(this).find('option').filter(function (i, el) {
|
||||
return $(el).val() === value;
|
||||
}).data('input');
|
||||
|
||||
$('.node-player-group-add-object-input')
|
||||
.addClass('hidden')
|
||||
.prop('disabled', true)
|
||||
.filter('#node-player-group-add-object-input-' + inputType)
|
||||
.removeClass('hidden')
|
||||
.prop('disabled', false)
|
||||
;
|
||||
});
|
||||
|
||||
$(document).on('click', '.node-player-group-add', function () {
|
||||
showModal('modal-node-player-group-add');
|
||||
$('.modal-node-player-group-add input:eq(0)').focus().select();
|
||||
});
|
||||
|
||||
$(document).on('click', '.node-player-group-edit', function () {
|
||||
const nodePlayerGroup = JSON.parse($(this).parents('tr:eq(0)').attr('data-entity'));
|
||||
showModal('modal-node-player-group-edit');
|
||||
$('.modal-node-player-group-edit input:visible:eq(0)').focus().select();
|
||||
$('#node-player-group-edit-name').val(nodePlayerGroup.name);
|
||||
$('#node-player-group-edit-id').val(nodePlayerGroup.id);
|
||||
});
|
||||
|
||||
$(document).on('click', '.node-player-group-delete', function () {
|
||||
if (confirm(l.js_fleet_node_player_delete_confirmation)) {
|
||||
const $tr = $(this).parents('tr:eq(0)');
|
||||
$tr.remove();
|
||||
updateTable();
|
||||
$.ajax({
|
||||
method: 'DELETE',
|
||||
url: '/fleet/node-player-group/delete',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
data: JSON.stringify({id: getId($(this))}),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
main();
|
||||
});
|
||||
@ -1,7 +1,6 @@
|
||||
jQuery(document).ready(function ($) {
|
||||
const $tableActive = $('table.active-node-players');
|
||||
const $tableInactive = $('table.inactive-node-players');
|
||||
const $modalsRoot = $('.modals');
|
||||
|
||||
const getId = function ($el) {
|
||||
return $el.is('tr') ? $el.attr('data-level') : $el.parents('tr:eq(0)').attr('data-level');
|
||||
@ -18,16 +17,6 @@ jQuery(document).ready(function ($) {
|
||||
updatePositions();
|
||||
};
|
||||
|
||||
const showModal = function (modalClass) {
|
||||
$modalsRoot.removeClass('hidden').find('form').trigger('reset');
|
||||
$modalsRoot.find('.modal').addClass('hidden');
|
||||
$modalsRoot.find('.modal.' + modalClass).removeClass('hidden');
|
||||
};
|
||||
|
||||
const hideModal = function () {
|
||||
$modalsRoot.addClass('hidden').find('form').trigger('reset');
|
||||
};
|
||||
|
||||
const updatePositions = function (table, row) {
|
||||
const positions = {};
|
||||
$('.node-player-item').each(function (index) {
|
||||
@ -83,9 +72,6 @@ jQuery(document).ready(function ($) {
|
||||
;
|
||||
});
|
||||
|
||||
$(document).on('click', '.modal-close', function () {
|
||||
hideModal();
|
||||
});
|
||||
|
||||
$(document).on('click', '.node-player-add', function () {
|
||||
showModal('modal-node-player-add');
|
||||
@ -115,11 +101,5 @@ jQuery(document).ready(function ($) {
|
||||
}
|
||||
});
|
||||
|
||||
$(document).keyup(function (e) {
|
||||
if (e.key === "Escape") {
|
||||
hideModal();
|
||||
}
|
||||
});
|
||||
|
||||
main();
|
||||
});
|
||||
@ -1,7 +1,6 @@
|
||||
jQuery(document).ready(function ($) {
|
||||
const $tableActive = $('table.active-node-studios');
|
||||
const $tableInactive = $('table.inactive-node-studios');
|
||||
const $modalsRoot = $('.modals');
|
||||
|
||||
const getId = function ($el) {
|
||||
return $el.is('tr') ? $el.attr('data-level') : $el.parents('tr:eq(0)').attr('data-level');
|
||||
@ -18,16 +17,6 @@ jQuery(document).ready(function ($) {
|
||||
updatePositions();
|
||||
};
|
||||
|
||||
const showModal = function (modalClass) {
|
||||
$modalsRoot.removeClass('hidden').find('form').trigger('reset');
|
||||
$modalsRoot.find('.modal').addClass('hidden');
|
||||
$modalsRoot.find('.modal.' + modalClass).removeClass('hidden');
|
||||
};
|
||||
|
||||
const hideModal = function () {
|
||||
$modalsRoot.addClass('hidden').find('form').trigger('reset');
|
||||
};
|
||||
|
||||
const updatePositions = function (table, row) {
|
||||
const positions = {};
|
||||
$('.node-studio-item').each(function (index) {
|
||||
@ -83,10 +72,6 @@ jQuery(document).ready(function ($) {
|
||||
;
|
||||
});
|
||||
|
||||
$(document).on('click', '.modal-close', function () {
|
||||
hideModal();
|
||||
});
|
||||
|
||||
$(document).on('click', '.node-studio-add', function () {
|
||||
showModal('modal-node-studio-add');
|
||||
$('.modal-node-studio-add input:eq(0)').focus().select();
|
||||
@ -116,11 +101,5 @@ jQuery(document).ready(function ($) {
|
||||
}
|
||||
});
|
||||
|
||||
$(document).keyup(function (e) {
|
||||
if (e.key === "Escape") {
|
||||
hideModal();
|
||||
}
|
||||
});
|
||||
|
||||
main();
|
||||
});
|
||||
@ -1,4 +1,25 @@
|
||||
const $modalsRoot = $('.modals');
|
||||
|
||||
const showModal = function (modalClass) {
|
||||
$modalsRoot.removeClass('hidden').find('form').trigger('reset');
|
||||
$modalsRoot.find('.modal').addClass('hidden');
|
||||
$modalsRoot.find('.modal.' + modalClass).removeClass('hidden');
|
||||
};
|
||||
|
||||
const hideModal = function () {
|
||||
$modalsRoot.addClass('hidden').find('form').trigger('reset');
|
||||
};
|
||||
|
||||
jQuery(document).ready(function ($) {
|
||||
$(document).on('click', '.modal-close', function () {
|
||||
hideModal();
|
||||
});
|
||||
|
||||
$(document).keyup(function (e) {
|
||||
if (e.key === "Escape") {
|
||||
hideModal();
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('click', '.protected', function(e) {
|
||||
e.preventDefault();
|
||||
@ -15,5 +36,15 @@ jQuery(document).ready(function ($) {
|
||||
}
|
||||
|
||||
return false;
|
||||
})
|
||||
});
|
||||
|
||||
$(document).on('click', '.item-utrack', function () {
|
||||
const entity = JSON.parse($(this).parents('tr:eq(0)').attr('data-entity'));
|
||||
showModal('modal-entity-utrack');
|
||||
$('#entity-utrack-created-by').val(entity.created_by);
|
||||
$('#entity-utrack-updated-by').val(entity.updated_by);
|
||||
$('#entity-utrack-created-at').val(prettyTimestamp(entity.created_at * 1000));
|
||||
$('#entity-utrack-updated-at').val(prettyTimestamp(entity.updated_at * 1000));
|
||||
});
|
||||
|
||||
});
|
||||
@ -1,7 +1,6 @@
|
||||
jQuery(document).ready(function ($) {
|
||||
const $tableActive = $('table.active-playlists');
|
||||
const $tableInactive = $('table.inactive-playlists');
|
||||
const $modalsRoot = $('.modals');
|
||||
|
||||
const getId = function ($el) {
|
||||
return $el.is('tr') ? $el.attr('data-level') : $el.parents('tr:eq(0)').attr('data-level');
|
||||
@ -17,16 +16,6 @@ jQuery(document).ready(function ($) {
|
||||
});
|
||||
};
|
||||
|
||||
const showModal = function (modalClass) {
|
||||
$modalsRoot.removeClass('hidden').find('form').trigger('reset');
|
||||
$modalsRoot.find('.modal').addClass('hidden');
|
||||
$modalsRoot.find('.modal.' + modalClass).removeClass('hidden');
|
||||
};
|
||||
|
||||
const hideModal = function () {
|
||||
$modalsRoot.addClass('hidden').find('form').trigger('reset');
|
||||
};
|
||||
|
||||
const main = function () {
|
||||
|
||||
};
|
||||
@ -50,10 +39,6 @@ jQuery(document).ready(function ($) {
|
||||
updateTable();
|
||||
});
|
||||
|
||||
$(document).on('click', '.modal-close', function () {
|
||||
hideModal();
|
||||
});
|
||||
|
||||
$(document).on('click', '.playlist-add', function () {
|
||||
showModal('modal-playlist-add');
|
||||
$('.modal-playlist-add input:eq(0)').focus().select();
|
||||
@ -87,11 +72,5 @@ jQuery(document).ready(function ($) {
|
||||
}
|
||||
});
|
||||
|
||||
$(document).keyup(function (e) {
|
||||
if (e.key === "Escape") {
|
||||
hideModal();
|
||||
}
|
||||
});
|
||||
|
||||
main();
|
||||
});
|
||||
|
||||
@ -1,24 +1,8 @@
|
||||
jQuery(document).ready(function ($) {
|
||||
const $modalsRoot = $('.modals');
|
||||
|
||||
const showModal = function (modalClass) {
|
||||
$modalsRoot.removeClass('hidden').find('form').trigger('reset');
|
||||
$modalsRoot.find('.modal').addClass('hidden');
|
||||
$modalsRoot.find('.modal.' + modalClass).removeClass('hidden');
|
||||
};
|
||||
|
||||
const hideModal = function () {
|
||||
$modalsRoot.addClass('hidden').find('form').trigger('reset');
|
||||
};
|
||||
|
||||
const main = function () {
|
||||
|
||||
};
|
||||
|
||||
$(document).on('click', '.modal-close', function () {
|
||||
hideModal();
|
||||
});
|
||||
|
||||
$(document).on('click', '.variable-edit', function () {
|
||||
const variable = JSON.parse($(this).parents('tr:eq(0)').attr('data-entity'));
|
||||
|
||||
@ -42,11 +26,5 @@ jQuery(document).ready(function ($) {
|
||||
$('#variable-edit-id').val(variable.id);
|
||||
});
|
||||
|
||||
$(document).keyup(function (e) {
|
||||
if (e.key === "Escape") {
|
||||
hideModal();
|
||||
}
|
||||
});
|
||||
|
||||
main();
|
||||
});
|
||||
@ -1,18 +1,12 @@
|
||||
jQuery(document).ready(function ($) {
|
||||
const $tableActive = $('table.active-slides');
|
||||
const $tableInactive = $('table.inactive-slides');
|
||||
const $modalsRoot = $('.modals');
|
||||
|
||||
const getCronDateTime = function(cronExpression) {
|
||||
const [minutes, hours, day, month, _, year] = cronExpression.split(' ');
|
||||
return `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')} ${hours.padStart(2, '0')}:${minutes.padStart(2, '0')}`;
|
||||
};
|
||||
|
||||
const prettyTimestamp = function(timestamp) {
|
||||
const d = new Date(timestamp);
|
||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')} ${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}:${String(d.getSeconds()).padStart(2, '0')} `
|
||||
}
|
||||
|
||||
const loadDateTimePicker = function($els) {
|
||||
$els.each(function() {
|
||||
var $el = $(this);
|
||||
@ -50,16 +44,6 @@ jQuery(document).ready(function ($) {
|
||||
}
|
||||
}).tableDnDUpdate();
|
||||
updatePositions();
|
||||
}
|
||||
|
||||
const showModal = function (modalClass) {
|
||||
$modalsRoot.removeClass('hidden').find('form').trigger('reset');
|
||||
$modalsRoot.find('.modal').addClass('hidden');
|
||||
$modalsRoot.find('.modal.' + modalClass).removeClass('hidden');
|
||||
};
|
||||
|
||||
const hideModal = function () {
|
||||
$modalsRoot.addClass('hidden').find('form').trigger('reset');
|
||||
};
|
||||
|
||||
const updatePositions = function (table, row) {
|
||||
@ -178,10 +162,6 @@ jQuery(document).ready(function ($) {
|
||||
|
||||
$(document).on('change', '#slide-add-type', inputTypeUpdate);
|
||||
|
||||
$(document).on('click', '.modal-close', function () {
|
||||
hideModal();
|
||||
});
|
||||
|
||||
$(document).on('click', '.slide-add', function () {
|
||||
showModal('modal-slide-add');
|
||||
loadDateTimePicker($('.modal-slide-add .datetimepicker'))
|
||||
@ -190,15 +170,6 @@ jQuery(document).ready(function ($) {
|
||||
$('.modal-slide-add input:eq(0)').focus().select();
|
||||
});
|
||||
|
||||
$(document).on('click', '.slide-utrack', function () {
|
||||
const slide = JSON.parse($(this).parents('tr:eq(0)').attr('data-entity'));
|
||||
showModal('modal-slide-utrack');
|
||||
$('#slide-utrack-created-by').val(slide.created_by);
|
||||
$('#slide-utrack-updated-by').val(slide.updated_by);
|
||||
$('#slide-utrack-created-at').val(prettyTimestamp(slide.created_at * 1000));
|
||||
$('#slide-utrack-updated-at').val(prettyTimestamp(slide.updated_at * 1000));
|
||||
});
|
||||
|
||||
$(document).on('click', '.slide-edit', function () {
|
||||
const slide = JSON.parse($(this).parents('tr:eq(0)').attr('data-entity'));
|
||||
showModal('modal-slide-edit');
|
||||
@ -254,11 +225,5 @@ jQuery(document).ready(function ($) {
|
||||
}
|
||||
});
|
||||
|
||||
$(document).keyup(function (e) {
|
||||
if (e.key === "Escape") {
|
||||
hideModal();
|
||||
}
|
||||
});
|
||||
|
||||
main();
|
||||
});
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
const prettyTimestamp = function(timestamp) {
|
||||
const d = new Date(timestamp);
|
||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')} ${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}:${String(d.getSeconds()).padStart(2, '0')} `
|
||||
};
|
||||
|
||||
const validateCronDateTime = function(cronExpression) {
|
||||
const pattern = /^(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+\*\s+(\d+)$/;
|
||||
return pattern.test(cronExpression);
|
||||
|
||||
16
lang/en.json
16
lang/en.json
@ -59,6 +59,7 @@
|
||||
"playlist_form_button_cancel": "Cancel",
|
||||
"js_playlist_delete_confirmation": "Are you sure?",
|
||||
"playlist_delete_has_slides": "Playlist has slides, please remove them before and retry",
|
||||
"playlist_delete_has_node_player_groups": "Playlist has player groups, please remove them before and retry",
|
||||
|
||||
"fleet_node_studio_page_title": "Studios",
|
||||
"fleet_node_studio_button_add": "Add a studio",
|
||||
@ -99,6 +100,21 @@
|
||||
"fleet_node_player_form_button_cancel": "Cancel",
|
||||
"js_fleet_node_player_delete_confirmation": "Are you sure?",
|
||||
|
||||
"fleet_node_player_group_page_title": "Player Groups",
|
||||
"fleet_node_player_group_button_add": "Add a player group",
|
||||
"fleet_node_player_group_panel_active": "Active player groups",
|
||||
"fleet_node_player_group_panel_empty": "Currently, there are no player groups. %link% now.",
|
||||
"fleet_node_player_group_panel_th_name": "Name",
|
||||
"fleet_node_player_group_panel_th_activity": "Activity",
|
||||
"fleet_node_player_group_form_add_title": "Add Player Group",
|
||||
"fleet_node_player_group_form_add_submit": "Add",
|
||||
"fleet_node_player_group_form_edit_title": "Edit Player Group",
|
||||
"fleet_node_player_group_form_edit_submit": "Save",
|
||||
"fleet_node_player_group_form_label_name": "Name",
|
||||
"fleet_node_player_group_form_button_cancel": "Cancel",
|
||||
"js_fleet_node_player_group_delete_confirmation": "Are you sure?",
|
||||
"node_player_group_delete_has_node_player": "Player group has players, please remove or unassign them before and retry",
|
||||
|
||||
"login_page_title": "Login",
|
||||
"auth_page_title": "Users",
|
||||
"auth_user_button_add": "Add a user",
|
||||
|
||||
26
lang/fr.json
26
lang/fr.json
@ -59,6 +59,7 @@
|
||||
"playlist_form_button_cancel": "Annuler",
|
||||
"js_playlist_delete_confirmation": "Êtes-vous sûr ?",
|
||||
"playlist_delete_has_slides": "La liste de lecture contient des slides, supprimez-les avant et réessayez",
|
||||
"playlist_delete_has_node_player_groups": "La liste de lecture contient des groupes de lecteur, supprimez-les avant et réessayez",
|
||||
|
||||
"fleet_node_studio_page_title": "Studios",
|
||||
"fleet_node_studio_button_add": "Ajouter un studio",
|
||||
@ -81,24 +82,39 @@
|
||||
"fleet_node_studio_form_button_cancel": "Annuler",
|
||||
"js_fleet_node_studio_delete_confirmation": "Êtes-vous sûr ?",
|
||||
|
||||
"fleet_node_player_page_title": "Players",
|
||||
"fleet_node_player_button_add": "Ajouter un player",
|
||||
"fleet_node_player_page_title": "Lecteurs",
|
||||
"fleet_node_player_button_add": "Ajouter un lecteur",
|
||||
"fleet_node_player_panel_active": "Players actifs",
|
||||
"fleet_node_player_panel_inactive": "Players inactifs",
|
||||
"fleet_node_player_panel_empty": "Actuellement, il n'y a pas de players. %link% maintenant.",
|
||||
"fleet_node_player_panel_empty": "Actuellement, il n'y a pas de lecteurs. %link% maintenant.",
|
||||
"fleet_node_player_panel_th_name": "Nom",
|
||||
"fleet_node_player_panel_th_host": "Hôte",
|
||||
"fleet_node_player_panel_th_enabled": "Activé",
|
||||
"fleet_node_player_panel_th_activity": "Options",
|
||||
"fleet_node_player_form_add_title": "Ajout d'un player",
|
||||
"fleet_node_player_form_add_title": "Ajout d'un lecteur",
|
||||
"fleet_node_player_form_add_submit": "Ajouter",
|
||||
"fleet_node_player_form_edit_title": "Modification d'un player",
|
||||
"fleet_node_player_form_edit_title": "Modification d'un lecteur",
|
||||
"fleet_node_player_form_edit_submit": "Enregistrer",
|
||||
"fleet_node_player_form_label_name": "Nom",
|
||||
"fleet_node_player_form_label_host": "Hôte",
|
||||
"fleet_node_player_form_button_cancel": "Annuler",
|
||||
"js_fleet_node_player_delete_confirmation": "Êtes-vous sûr ?",
|
||||
|
||||
"fleet_node_player_group_page_title": "Groupes de lecteurs",
|
||||
"fleet_node_player_group_button_add": "Ajouter un groupe de lecteur",
|
||||
"fleet_node_player_group_panel_active": "Groupes de lecteur",
|
||||
"fleet_node_player_group_panel_empty": "Actuellement, il n'y a pas de groupes de lecteur. %link% maintenant.",
|
||||
"fleet_node_player_group_panel_th_name": "Nom",
|
||||
"fleet_node_player_group_panel_th_activity": "Options",
|
||||
"fleet_node_player_group_form_add_title": "Ajout d'un groupe de lecteur",
|
||||
"fleet_node_player_group_form_add_submit": "Ajouter",
|
||||
"fleet_node_player_group_form_edit_title": "Modification d'un groupe de lecteur",
|
||||
"fleet_node_player_group_form_edit_submit": "Enregistrer",
|
||||
"fleet_node_player_group_form_label_name": "Nom",
|
||||
"fleet_node_player_group_form_button_cancel": "Annuler",
|
||||
"js_fleet_node_player_group_delete_confirmation": "Êtes-vous sûr ?",
|
||||
"node_player_group_delete_has_node_player": "Le groupe de lecteur a des lecteurs, supprimez-les ou réassignez-les avant de le supprimer",
|
||||
|
||||
"login_page_title": "Connexion",
|
||||
"auth_page_title": "Utilisateurs",
|
||||
"auth_user_button_add": "Ajouter un utilisateur",
|
||||
|
||||
50
src/controller/FleetNodePlayerGroupController.py
Normal file
50
src/controller/FleetNodePlayerGroupController.py
Normal file
@ -0,0 +1,50 @@
|
||||
import json
|
||||
|
||||
from flask import Flask, render_template, redirect, request, url_for, jsonify
|
||||
from src.service.ModelStore import ModelStore
|
||||
from src.model.entity.NodePlayerGroup import NodePlayerGroup
|
||||
from src.interface.ObController import ObController
|
||||
|
||||
|
||||
class FleetNodePlayerGroupController(ObController):
|
||||
|
||||
def guard_fleet(self, f):
|
||||
def decorated_function(*args, **kwargs):
|
||||
if not self._model_store.variable().map().get('fleet_player_enabled').as_bool():
|
||||
return redirect(url_for('manage'))
|
||||
return f(*args, **kwargs)
|
||||
|
||||
return decorated_function
|
||||
|
||||
def register(self):
|
||||
self._app.add_url_rule('/fleet/node-player-group/list', 'fleet_node_player_group_list', self.guard_fleet(self._auth(self.fleet_node_player_group_list)), methods=['GET'])
|
||||
self._app.add_url_rule('/fleet/node-player-group/add', 'fleet_node_player_group_add', self.guard_fleet(self._auth(self.fleet_node_player_group_add)), methods=['POST'])
|
||||
self._app.add_url_rule('/fleet/node-player-group/edit', 'fleet_node_player_group_edit', self.guard_fleet(self._auth(self.fleet_node_player_group_edit)), methods=['POST'])
|
||||
self._app.add_url_rule('/fleet/node-player-group/delete', 'fleet_node_player_group_delete', self.guard_fleet(self._auth(self.fleet_node_player_group_delete)), methods=['DELETE'])
|
||||
|
||||
def fleet_node_player_group_list(self):
|
||||
return render_template(
|
||||
'fleet/player-group/list.jinja.html',
|
||||
node_player_groups=self._model_store.node_player_group().get_all(),
|
||||
)
|
||||
|
||||
def fleet_node_player_group_add(self):
|
||||
self._model_store.node_player_group().add_form(NodePlayerGroup(
|
||||
name=request.form['name'],
|
||||
playlist_id=request.form['playlist_id'],
|
||||
))
|
||||
return redirect(url_for('fleet_node_player_group_list'))
|
||||
|
||||
def fleet_node_player_group_edit(self):
|
||||
self._model_store.node_player_group().update_form(request.form['id'], request.form['name'], request.form['playlist_id'])
|
||||
return redirect(url_for('fleet_node_player_group_list'))
|
||||
|
||||
def fleet_node_player_group_delete(self):
|
||||
data = request.get_json()
|
||||
id = data.get('id')
|
||||
|
||||
if self._model_store.node_player().count_node_players_for_group(id) > 0:
|
||||
return jsonify({'status': 'error', 'message': self.t('node_player_group_delete_has_node_player')}), 400
|
||||
|
||||
self._model_store.playlist().delete(id)
|
||||
return jsonify({'status': 'ok'})
|
||||
@ -64,7 +64,12 @@ class PlaylistController(ObController):
|
||||
def playlist_delete(self):
|
||||
data = request.get_json()
|
||||
id = data.get('id')
|
||||
|
||||
if self._model_store.slide().count_slides_for_playlist(id) > 0:
|
||||
return jsonify({'status': 'error', 'message': self.t('playlist_delete_has_slides')}), 400
|
||||
|
||||
if self._model_store.node_player_group().count_node_player_groups_for_playlist(id) > 0:
|
||||
return jsonify({'status': 'error', 'message': self.t('playlist_delete_has_node_player_groups')}), 400
|
||||
|
||||
self._model_store.playlist().delete(id)
|
||||
return jsonify({'status': 'ok'})
|
||||
|
||||
@ -47,7 +47,7 @@ class SlideshowController(ObController):
|
||||
name=request.form['name'],
|
||||
type=str_to_enum(request.form['type'], SlideType),
|
||||
duration=request.form['duration'],
|
||||
playlist=request.form['playlist'] if 'playlist' in request.form else None,
|
||||
playlist_id=request.form['playlist_id'] if 'playlist_id' in request.form else None,
|
||||
cron_schedule=get_optional_string(request.form['cron_schedule']),
|
||||
cron_schedule_end=get_optional_string(request.form['cron_schedule_end']),
|
||||
)
|
||||
@ -72,8 +72,8 @@ class SlideshowController(ObController):
|
||||
self._model_store.slide().add_form(slide)
|
||||
self._post_update()
|
||||
|
||||
if slide.playlist:
|
||||
return redirect(url_for('slideshow_slide_list_playlist_use', playlist_id=slide.playlist))
|
||||
if slide.playlist_id:
|
||||
return redirect(url_for('slideshow_slide_list_playlist_use', playlist_id=slide.playlist_id))
|
||||
|
||||
return redirect(url_for('slideshow_slide_list'))
|
||||
|
||||
@ -88,8 +88,8 @@ class SlideshowController(ObController):
|
||||
)
|
||||
self._post_update()
|
||||
|
||||
if slide.playlist:
|
||||
return redirect(url_for('slideshow_slide_list_playlist_use', playlist_id=slide.playlist))
|
||||
if slide.playlist_id:
|
||||
return redirect(url_for('slideshow_slide_list_playlist_use', playlist_id=slide.playlist_id))
|
||||
|
||||
return redirect(url_for('slideshow_slide_list'))
|
||||
|
||||
|
||||
111
src/manager/NodePlayerGroupManager.py
Normal file
111
src/manager/NodePlayerGroupManager.py
Normal file
@ -0,0 +1,111 @@
|
||||
from typing import Dict, Optional, List, Tuple, Union
|
||||
|
||||
from src.model.entity.NodePlayerGroup import NodePlayerGroup
|
||||
from src.manager.DatabaseManager import DatabaseManager
|
||||
from src.manager.LangManager import LangManager
|
||||
from src.manager.UserManager import UserManager
|
||||
from src.manager.VariableManager import VariableManager
|
||||
from src.service.ModelManager import ModelManager
|
||||
|
||||
|
||||
class NodePlayerGroupManager(ModelManager):
|
||||
|
||||
TABLE_NAME = "fleet_player_group"
|
||||
TABLE_MODEL = [
|
||||
"name CHAR(255)",
|
||||
"playlist_id INTEGER",
|
||||
"created_by CHAR(255)",
|
||||
"updated_by CHAR(255)",
|
||||
"created_at INTEGER",
|
||||
"updated_at INTEGER"
|
||||
]
|
||||
|
||||
def __init__(self, lang_manager: LangManager, database_manager: DatabaseManager, user_manager: UserManager, variable_manager: VariableManager):
|
||||
super().__init__(lang_manager, database_manager, user_manager, variable_manager)
|
||||
self._db = database_manager.open(self.TABLE_NAME, self.TABLE_MODEL)
|
||||
|
||||
def hydrate_object(self, raw_node_player_group: dict, id: Optional[int] = None) -> NodePlayerGroup:
|
||||
if id:
|
||||
raw_node_player_group['id'] = id
|
||||
|
||||
return NodePlayerGroup(**raw_node_player_group)
|
||||
|
||||
def hydrate_list(self, raw_node_player_groups: list) -> List[NodePlayerGroup]:
|
||||
return [self.hydrate_object(raw_node_player_group) for raw_node_player_group in raw_node_player_groups]
|
||||
|
||||
def get(self, id: int) -> Optional[NodePlayerGroup]:
|
||||
object = self._db.get_by_id(self.TABLE_NAME, id)
|
||||
return self.hydrate_object(object, id) if object else None
|
||||
|
||||
def get_by(self, query, sort: Optional[str] = None) -> List[NodePlayerGroup]:
|
||||
return self.hydrate_list(self._db.get_by_query(self.TABLE_NAME, query=query, sort=sort))
|
||||
|
||||
def get_one_by(self, query) -> Optional[NodePlayerGroup]:
|
||||
object = self._db.get_one_by_query(self.TABLE_NAME, query=query)
|
||||
|
||||
if not object:
|
||||
return None
|
||||
|
||||
return self.hydrate_object(object)
|
||||
|
||||
def get_all(self, sort: bool = False) -> List[NodePlayerGroup]:
|
||||
return self.hydrate_list(self._db.get_all(self.TABLE_NAME, "name" if sort else None))
|
||||
|
||||
def get_node_players_groups(self, playlist_id: Optional[int] = None) -> List[NodePlayerGroup]:
|
||||
query = ""
|
||||
if playlist_id:
|
||||
query = "{} {}".format(query, "AND playlist_id = {}".format(playlist_id))
|
||||
else:
|
||||
query = "{} {}".format(query, "AND playlist_id is NULL")
|
||||
|
||||
return self.get_by(query=query, sort="name")
|
||||
|
||||
def forget_user(self, user_id: int):
|
||||
node_player_groups = self.get_by("created_by = '{}' or updated_by = '{}'".format(user_id, user_id))
|
||||
edits_node_player_groups = self.user_manager.forget_user_for_entity(node_player_groups, user_id)
|
||||
|
||||
for node_player_group_id, edits in edits_node_player_groups.items():
|
||||
self._db.update_by_id(self.TABLE_NAME, node_player_group_id, edits)
|
||||
|
||||
def pre_add(self, node_player_group: Dict) -> Dict:
|
||||
self.user_manager.track_user_on_create(node_player_group)
|
||||
self.user_manager.track_user_on_update(node_player_group)
|
||||
return node_player_group
|
||||
|
||||
def pre_update(self, node_player_group: Dict) -> Dict:
|
||||
self.user_manager.track_user_on_update(node_player_group)
|
||||
return node_player_group
|
||||
|
||||
def pre_delete(self, node_player_group_id: str) -> str:
|
||||
return node_player_group_id
|
||||
|
||||
def post_add(self, node_player_group_id: str) -> str:
|
||||
return node_player_group_id
|
||||
|
||||
def post_update(self, node_player_group_id: str) -> str:
|
||||
return node_player_group_id
|
||||
|
||||
def update_form(self, id: int, name: str, playlist_id: Optional[int]) -> None:
|
||||
self._db.update_by_id(self.TABLE_NAME, id, self.pre_update({"name": name, "playlist_id": playlist_id}))
|
||||
self.post_update(id)
|
||||
|
||||
def add_form(self, node_player_group: Union[NodePlayerGroup, Dict]) -> None:
|
||||
form = node_player_group
|
||||
|
||||
if not isinstance(node_player_group, dict):
|
||||
form = node_player_group.to_dict()
|
||||
del form['id']
|
||||
|
||||
self._db.add(self.TABLE_NAME, self.pre_add(form))
|
||||
self.post_add(node_player_group.id)
|
||||
|
||||
def delete(self, id: int) -> None:
|
||||
self.pre_delete(id)
|
||||
self._db.delete_by_id(self.TABLE_NAME, id)
|
||||
self.post_delete(id)
|
||||
|
||||
def to_dict(self, node_player_groups: List[NodePlayerGroup]) -> List[Dict]:
|
||||
return [node_player_group.to_dict() for node_player_group in node_player_groups]
|
||||
|
||||
def count_node_player_groups_for_playlist(self, id: int) -> int:
|
||||
return len(self.get_node_players_groups(playlist_id=id))
|
||||
@ -14,6 +14,7 @@ class NodePlayerManager(ModelManager):
|
||||
TABLE_MODEL = [
|
||||
"name CHAR(255)",
|
||||
"enabled INTEGER DEFAULT 0",
|
||||
"group_id INTEGER",
|
||||
"position INTEGER",
|
||||
"host CHAR(255)",
|
||||
"created_by CHAR(255)",
|
||||
@ -53,6 +54,15 @@ class NodePlayerManager(ModelManager):
|
||||
def get_all(self, sort: bool = False) -> List[NodePlayer]:
|
||||
return self.hydrate_list(self._db.get_all(self.TABLE_NAME, "position" if sort else None))
|
||||
|
||||
def get_node_players(self, group_id: Optional[int] = None) -> List[NodePlayer]:
|
||||
query = "enabled = {}".format("1" if enabled else "0")
|
||||
if group_id:
|
||||
query = "{} {}".format(query, "AND group_id = {}".format(group_id))
|
||||
else:
|
||||
query = "{} {}".format(query, "AND group_id is NULL")
|
||||
|
||||
return self.get_by(query=query, sort="position")
|
||||
|
||||
def forget_user(self, user_id: int):
|
||||
node_players = self.get_by("created_by = '{}' or updated_by = '{}'".format(user_id, user_id))
|
||||
edits_node_players = self.user_manager.forget_user_for_entity(node_players, user_id)
|
||||
@ -113,3 +123,6 @@ class NodePlayerManager(ModelManager):
|
||||
|
||||
def to_dict(self, node_players: List[NodePlayer]) -> List[Dict]:
|
||||
return [node_player.to_dict() for node_player in node_players]
|
||||
|
||||
def count_node_players_for_group(self, id: int) -> int:
|
||||
return len(self.get_node_players(group_id=id))
|
||||
|
||||
@ -20,7 +20,7 @@ class SlideManager(ModelManager):
|
||||
"name CHAR(255)",
|
||||
"type CHAR(30)",
|
||||
"enabled INTEGER DEFAULT 0",
|
||||
"playlist INTEGER",
|
||||
"playlist_id INTEGER",
|
||||
"duration INTEGER",
|
||||
"position INTEGER",
|
||||
"location TEXT",
|
||||
@ -78,9 +78,9 @@ class SlideManager(ModelManager):
|
||||
def get_slides(self, playlist_id: Optional[int] = None, enabled: bool = True) -> List[Slide]:
|
||||
query = "enabled = {}".format("1" if enabled else "0")
|
||||
if playlist_id:
|
||||
query = "{} {}".format(query, "AND playlist = {}".format(playlist_id))
|
||||
query = "{} {}".format(query, "AND playlist_id = {}".format(playlist_id))
|
||||
else:
|
||||
query = "{} {}".format(query, "AND playlist is NULL")
|
||||
query = "{} {}".format(query, "AND playlist_id is NULL")
|
||||
|
||||
return self.get_by(query=query, sort="position")
|
||||
|
||||
@ -170,4 +170,4 @@ class SlideManager(ModelManager):
|
||||
return [slide.to_dict() for slide in slides]
|
||||
|
||||
def count_slides_for_playlist(self, id: int) -> int:
|
||||
return len(self.get_slides(playlist_id=id))
|
||||
return len(self.get_slides(playlist_id=id))
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import json
|
||||
import time
|
||||
|
||||
from typing import Optional, Union
|
||||
|
||||
|
||||
@ -6,8 +6,9 @@ from typing import Optional, Union
|
||||
|
||||
class NodePlayer:
|
||||
|
||||
def __init__(self, host: str = '', enabled: bool = False, name: str = 'Untitled', position: int = 999, id: Optional[int] = None, created_by: Optional[str] = None, updated_by: Optional[str] = None, created_at: Optional[int] = None, updated_at: Optional[int] = None):
|
||||
def __init__(self, host: str = '', enabled: bool = False, name: str = 'Untitled', position: int = 999, id: Optional[int] = None, group_id: Optional[int] = None, created_by: Optional[str] = None, updated_by: Optional[str] = None, created_at: Optional[int] = None, updated_at: Optional[int] = None):
|
||||
self._id = id if id else None
|
||||
self._group_id = group_id
|
||||
self._host = host
|
||||
self._enabled = enabled
|
||||
self._name = name
|
||||
@ -21,6 +22,14 @@ class NodePlayer:
|
||||
def id(self) -> Optional[int]:
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def group_id(self) -> Optional[int]:
|
||||
return self._group_id
|
||||
|
||||
@group_id.setter
|
||||
def group_id(self, value: Optional[int]):
|
||||
self._group_id = value
|
||||
|
||||
@property
|
||||
def host(self) -> str:
|
||||
return self._host
|
||||
@ -88,6 +97,7 @@ class NodePlayer:
|
||||
def __str__(self) -> str:
|
||||
return f"NodePlayer(" \
|
||||
f"id='{self.id}',\n" \
|
||||
f"group_id='{self.group_id}',\n" \
|
||||
f"name='{self.name}',\n" \
|
||||
f"enabled='{self.enabled}',\n" \
|
||||
f"position='{self.position}',\n" \
|
||||
@ -98,12 +108,18 @@ class NodePlayer:
|
||||
f"updated_at='{self.updated_at}',\n" \
|
||||
f")"
|
||||
|
||||
def to_json(self) -> str:
|
||||
return json.dumps(self.to_dict())
|
||||
def to_json(self, edits: dict = {}) -> str:
|
||||
obj = self.to_dict()
|
||||
|
||||
for k, v in edits.items():
|
||||
obj[k] = v
|
||||
|
||||
return json.dumps(obj)
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"id": self.id,
|
||||
"group_id": self.group_id,
|
||||
"name": self.name,
|
||||
"enabled": self.enabled,
|
||||
"position": self.position,
|
||||
|
||||
101
src/model/entity/NodePlayerGroup.py
Normal file
101
src/model/entity/NodePlayerGroup.py
Normal file
@ -0,0 +1,101 @@
|
||||
import json
|
||||
import time
|
||||
|
||||
from typing import Optional, Union
|
||||
|
||||
|
||||
class NodePlayerGroup:
|
||||
|
||||
def __init__(self, name: str = 'Untitled', playlist_id: Optional[int] = None, id: Optional[int] = None, created_by: Optional[str] = None, updated_by: Optional[str] = None, created_at: Optional[int] = None, updated_at: Optional[int] = None):
|
||||
self._id = id if id else None
|
||||
self._playlist_id = playlist_id
|
||||
self._name = name
|
||||
self._created_by = created_by if created_by else None
|
||||
self._updated_by = updated_by if updated_by else None
|
||||
self._created_at = int(created_at if created_at else time.time())
|
||||
self._updated_at = int(updated_at if updated_at else time.time())
|
||||
|
||||
@property
|
||||
def id(self) -> Optional[int]:
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def playlist_id(self) -> Optional[int]:
|
||||
return self._playlist_id
|
||||
|
||||
@playlist_id.setter
|
||||
def playlist_id(self, value: Optional[int]):
|
||||
self._playlist_id = value
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, value: str):
|
||||
self._name = value
|
||||
|
||||
@property
|
||||
def created_by(self) -> str:
|
||||
return self._created_by
|
||||
|
||||
@created_by.setter
|
||||
def created_by(self, value: str):
|
||||
self._created_by = value
|
||||
|
||||
@property
|
||||
def updated_by(self) -> str:
|
||||
return self._updated_by
|
||||
|
||||
@updated_by.setter
|
||||
def updated_by(self, value: str):
|
||||
self._updated_by = value
|
||||
|
||||
@property
|
||||
def created_at(self) -> int:
|
||||
return self._created_at
|
||||
|
||||
@created_at.setter
|
||||
def created_at(self, value: int):
|
||||
self._created_at = value
|
||||
|
||||
@property
|
||||
def updated_at(self) -> int:
|
||||
return self._updated_at
|
||||
|
||||
@updated_at.setter
|
||||
def updated_at(self, value: int):
|
||||
self._updated_at = value
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"NodePlayer(" \
|
||||
f"id='{self.id}',\n" \
|
||||
f"name='{self.name}',\n" \
|
||||
f"playlist_id='{self.playlist_id}',\n" \
|
||||
f"created_by='{self.created_by}',\n" \
|
||||
f"updated_by='{self.updated_by}',\n" \
|
||||
f"created_at='{self.created_at}',\n" \
|
||||
f"updated_at='{self.updated_at}',\n" \
|
||||
f")"
|
||||
|
||||
def to_json(self, edits: dict = {}) -> str:
|
||||
obj = self.to_dict()
|
||||
|
||||
for k, v in edits.items():
|
||||
obj[k] = v
|
||||
|
||||
return json.dumps(obj)
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"id": self.id,
|
||||
"name": self.name,
|
||||
"playlist_id": self.playlist_id,
|
||||
"created_by": self.created_by,
|
||||
"updated_by": self.updated_by,
|
||||
"created_at": self.created_at,
|
||||
"updated_at": self.updated_at,
|
||||
}
|
||||
|
||||
def is_root(self) -> bool:
|
||||
return not self._playlist_id
|
||||
@ -108,8 +108,13 @@ class NodeStudio:
|
||||
f"updated_at='{self.updated_at}',\n" \
|
||||
f")"
|
||||
|
||||
def to_json(self) -> str:
|
||||
return json.dumps(self.to_dict())
|
||||
def to_json(self, edits: dict = {}) -> str:
|
||||
obj = self.to_dict()
|
||||
|
||||
for k, v in edits.items():
|
||||
obj[k] = v
|
||||
|
||||
return json.dumps(obj)
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
|
||||
@ -101,7 +101,7 @@ class Playlist:
|
||||
def to_json(self, edits: dict = {}) -> str:
|
||||
obj = self.to_dict()
|
||||
|
||||
for k,v in edits.items():
|
||||
for k, v in edits.items():
|
||||
obj[k] = v
|
||||
|
||||
return json.dumps(obj)
|
||||
|
||||
@ -8,10 +8,10 @@ from src.util.utils import str_to_enum
|
||||
|
||||
class Slide:
|
||||
|
||||
def __init__(self, location: str = '', playlist: Optional[int] = None, duration: int = 3, type: Union[SlideType, str] = SlideType.URL, enabled: bool = False, name: str = 'Untitled', position: int = 999, id: Optional[int] = None, cron_schedule: Optional[str] = None, cron_schedule_end: Optional[str] = None, created_by: Optional[str] = None, updated_by: Optional[str] = None, created_at: Optional[int] = None, updated_at: Optional[int] = None):
|
||||
def __init__(self, location: str = '', playlist_id: Optional[int] = None, duration: int = 3, type: Union[SlideType, str] = SlideType.URL, enabled: bool = False, name: str = 'Untitled', position: int = 999, id: Optional[int] = None, cron_schedule: Optional[str] = None, cron_schedule_end: Optional[str] = None, created_by: Optional[str] = None, updated_by: Optional[str] = None, created_at: Optional[int] = None, updated_at: Optional[int] = None):
|
||||
self._id = id if id else None
|
||||
self._location = location
|
||||
self._playlist = playlist
|
||||
self._playlist_id = playlist_id
|
||||
self._duration = duration
|
||||
self._type = str_to_enum(type, SlideType) if isinstance(type, str) else type
|
||||
self._enabled = enabled
|
||||
@ -77,12 +77,12 @@ class Slide:
|
||||
self._type = value
|
||||
|
||||
@property
|
||||
def playlist(self) -> Optional[int]:
|
||||
return self._playlist
|
||||
def playlist_id(self) -> Optional[int]:
|
||||
return self._playlist_id
|
||||
|
||||
@playlist.setter
|
||||
def playlist(self, value: Optional[int]):
|
||||
self._playlist = value
|
||||
@playlist_id.setter
|
||||
def playlist_id(self, value: Optional[int]):
|
||||
self._playlist_id = value
|
||||
|
||||
@property
|
||||
def cron_schedule(self) -> Optional[str]:
|
||||
@ -145,7 +145,7 @@ class Slide:
|
||||
f"updated_by='{self.updated_by}',\n" \
|
||||
f"created_at='{self.created_at}',\n" \
|
||||
f"updated_at='{self.updated_at}',\n" \
|
||||
f"playlist='{self.playlist}',\n" \
|
||||
f"playlist_id='{self.playlist_id}',\n" \
|
||||
f"cron_schedule='{self.cron_schedule}',\n" \
|
||||
f"cron_schedule_end='{self.cron_schedule_end}',\n" \
|
||||
f")"
|
||||
@ -153,7 +153,7 @@ class Slide:
|
||||
def to_json(self, edits: dict = {}) -> str:
|
||||
obj = self.to_dict(with_virtual=True)
|
||||
|
||||
for k,v in edits.items():
|
||||
for k, v in edits.items():
|
||||
obj[k] = v
|
||||
|
||||
return json.dumps(obj)
|
||||
@ -171,7 +171,7 @@ class Slide:
|
||||
"updated_by": self.updated_by,
|
||||
"created_at": self.created_at,
|
||||
"updated_at": self.updated_at,
|
||||
"playlist": self.playlist,
|
||||
"playlist_id": self.playlist_id,
|
||||
"cron_schedule": self.cron_schedule,
|
||||
"cron_schedule_end": self.cron_schedule_end,
|
||||
}
|
||||
|
||||
@ -87,8 +87,13 @@ class User:
|
||||
f"updated_at='{self.updated_at}',\n" \
|
||||
f")"
|
||||
|
||||
def to_json(self) -> str:
|
||||
return json.dumps(self.to_dict())
|
||||
def to_json(self, edits: dict = {}) -> str:
|
||||
obj = self.to_dict()
|
||||
|
||||
for k, v in edits.items():
|
||||
obj[k] = v
|
||||
|
||||
return json.dumps(obj)
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
|
||||
@ -22,6 +22,11 @@ class HookType(Enum):
|
||||
H_FLEET_NODE_PLAYER_CSS = 'h_fleet_node_player_css'
|
||||
H_FLEET_NODE_PLAYER_JAVASCRIPT = 'h_fleet_node_player_javascript'
|
||||
|
||||
H_FLEET_NODE_PLAYER_GROUP_TOOLBAR_ACTIONS_START = 'h_fleet_node_player_group_toolbar_actions_start'
|
||||
H_FLEET_NODE_PLAYER_GROUP_TOOLBAR_ACTIONS_END = 'h_fleet_node_player_group_toolbar_actions_end'
|
||||
H_FLEET_NODE_PLAYER_GROUP_CSS = 'h_fleet_node_player_group_css'
|
||||
H_FLEET_NODE_PLAYER_GROUP_JAVASCRIPT = 'h_fleet_node_player_group_javascript'
|
||||
|
||||
H_PLAYLIST_TOOLBAR_ACTIONS_START = 'h_playlist_toolbar_actions_start'
|
||||
H_PLAYLIST_TOOLBAR_ACTIONS_END = 'h_playlist_toolbar_actions_end'
|
||||
H_PLAYLIST_CSS = 'h_playlist_css'
|
||||
|
||||
@ -5,6 +5,7 @@ from src.manager.SlideManager import SlideManager
|
||||
from src.manager.FolderManager import FolderManager
|
||||
from src.manager.NodeStudioManager import NodeStudioManager
|
||||
from src.manager.NodePlayerManager import NodePlayerManager
|
||||
from src.manager.NodePlayerGroupManager import NodePlayerGroupManager
|
||||
from src.manager.UserManager import UserManager
|
||||
from src.manager.VariableManager import VariableManager
|
||||
from src.manager.LangManager import LangManager
|
||||
@ -35,6 +36,7 @@ class ModelStore:
|
||||
self._folder_manager = FolderManager(lang_manager=self._lang_manager, database_manager=self._database_manager, user_manager=self._user_manager, variable_manager=self._variable_manager)
|
||||
self._node_studio_manager = NodeStudioManager(lang_manager=self._lang_manager, database_manager=self._database_manager, user_manager=self._user_manager, variable_manager=self._variable_manager)
|
||||
self._node_player_manager = NodePlayerManager(lang_manager=self._lang_manager, database_manager=self._database_manager, user_manager=self._user_manager, variable_manager=self._variable_manager)
|
||||
self._node_player_group_manager = NodePlayerGroupManager(lang_manager=self._lang_manager, database_manager=self._database_manager, user_manager=self._user_manager, variable_manager=self._variable_manager)
|
||||
self._playlist_manager = PlaylistManager(lang_manager=self._lang_manager, database_manager=self._database_manager, user_manager=self._user_manager, variable_manager=self._variable_manager)
|
||||
self._slide_manager = SlideManager(lang_manager=self._lang_manager, database_manager=self._database_manager, user_manager=self._user_manager, variable_manager=self._variable_manager)
|
||||
self._variable_manager.reload()
|
||||
@ -63,6 +65,9 @@ class ModelStore:
|
||||
def node_player(self) -> NodePlayerManager:
|
||||
return self._node_player_manager
|
||||
|
||||
def node_player_group(self) -> NodePlayerGroupManager:
|
||||
return self._node_player_group_manager
|
||||
|
||||
def folder_manager(self) -> FolderManager:
|
||||
return self._folder_manager
|
||||
|
||||
@ -78,6 +83,7 @@ class ModelStore:
|
||||
def on_user_delete(self, user_id: int) -> None:
|
||||
self._playlist_manager.forget_user(user_id)
|
||||
self._folder_manager.forget_user(user_id)
|
||||
self._node_player_group_manager.forget_user(user_id)
|
||||
self._node_player_manager.forget_user(user_id)
|
||||
self._node_studio_manager.forget_user(user_id)
|
||||
self._slide_manager.forget_user(user_id)
|
||||
|
||||
@ -12,6 +12,7 @@ from src.controller.PlayerController import PlayerController
|
||||
from src.controller.SlideshowController import SlideshowController
|
||||
from src.controller.FleetNodeStudioController import FleetNodeStudioController
|
||||
from src.controller.FleetNodePlayerController import FleetNodePlayerController
|
||||
from src.controller.FleetNodePlayerGroupController import FleetNodePlayerGroupController
|
||||
from src.controller.PlaylistController import PlaylistController
|
||||
from src.controller.AuthController import AuthController
|
||||
from src.controller.SysinfoController import SysinfoController
|
||||
@ -108,6 +109,7 @@ class WebServer:
|
||||
SysinfoController(self, self._app, self.auth_required, self._model_store, self._template_renderer)
|
||||
FleetNodeStudioController(self, self._app, self.auth_required, self._model_store, self._template_renderer)
|
||||
FleetNodePlayerController(self, self._app, self.auth_required, self._model_store, self._template_renderer)
|
||||
FleetNodePlayerGroupController(self, self._app, self.auth_required, self._model_store, self._template_renderer)
|
||||
PlaylistController(self, self._app, self.auth_required, self._model_store, self._template_renderer)
|
||||
AuthController(self, self._app, self.auth_required, self._model_store, self._template_renderer)
|
||||
|
||||
|
||||
@ -2,6 +2,11 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ l.auth_user_panel_th_username }}</th>
|
||||
{% if AUTH_ENABLED %}
|
||||
<th class="tac">
|
||||
<i class="fa fa-user"></i>
|
||||
</th>
|
||||
{% endif %}
|
||||
<th class="tac">{{ l.auth_user_panel_th_enabled }}</th>
|
||||
<th class="tac">{{ l.auth_user_panel_th_activity }}</th>
|
||||
</tr>
|
||||
@ -16,7 +21,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
{% for user in users %}
|
||||
<tr class="user-item" data-level="{{ user.id }}" data-entity="{{ user.to_json() }}">
|
||||
<tr class="user-item" data-level="{{ user.id }}" data-entity="{{ user.to_json({"created_by": track_created(user).username, "updated_by": track_updated(user).username}) }}">
|
||||
<td class="infos">
|
||||
<div class="inner">
|
||||
<div class="badge"><i class="fa fa-key icon-left"></i> {{ user.id }}</div>
|
||||
@ -25,6 +30,14 @@
|
||||
{{ user.username }}
|
||||
</div>
|
||||
</td>
|
||||
{% if AUTH_ENABLED %}
|
||||
<td class="tac">
|
||||
{% set creator = track_created(user) %}
|
||||
<a href="javascript:void(0);" class="badge item-utrack user-utrack {% if not creator.enabled %}anonymous{% endif %}">
|
||||
{{ creator.username }}
|
||||
</a>
|
||||
</td>
|
||||
{% endif %}
|
||||
<td class="tac">
|
||||
<label class="pure-material-switch">
|
||||
<input type="checkbox" {% if user.enabled %}checked="checked"{% endif %}><span></span>
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
|
||||
{% block page %}
|
||||
<div class="toolbar">
|
||||
<h2>{{ l.auth_page_title }}</h2>
|
||||
<h2><i class="fa fa-user icon-left"></i>{{ l.auth_page_title }}</h2>
|
||||
|
||||
<div class="toolbar-actions">
|
||||
{{ HOOK(H_AUTH_TOOLBAR_ACTIONS_START) }}
|
||||
@ -56,6 +56,7 @@
|
||||
<div class="modals-inner">
|
||||
{% include 'auth/modal/add.jinja.html' %}
|
||||
{% include 'auth/modal/edit.jinja.html' %}
|
||||
{% include 'core/utrack.jinja.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
<h3>
|
||||
{{ l.login_form_title }}
|
||||
</h3>
|
||||
<form action="{{ url_for('login') }}" method="post">
|
||||
<form class="form" action="{{ url_for('login') }}" method="post">
|
||||
<div class="form-group">
|
||||
<label for="password">{{ l.login_form_username }}</label>
|
||||
<div class="widget">
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
{{ l.auth_user_form_add_title }}
|
||||
</h2>
|
||||
|
||||
<form action="/auth/user/add" method="POST" enctype="multipart/form-data">
|
||||
<form class="form" action="/auth/user/add" method="POST" enctype="multipart/form-data">
|
||||
<div class="form-group">
|
||||
<label for="user-add-name">{{ l.auth_user_form_label_username }}</label>
|
||||
<div class="widget">
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
{{ l.auth_user_form_edit_title }}
|
||||
</h2>
|
||||
|
||||
<form action="/auth/user/edit" method="POST">
|
||||
<form class="form" action="/auth/user/edit" method="POST">
|
||||
<input type="hidden" name="id" id="user-edit-id" />
|
||||
|
||||
<div class="form-group">
|
||||
|
||||
@ -76,6 +76,11 @@
|
||||
<i class="fa fa-tv"></i> {{ l.fleet_node_player_page_title }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="{{ 'active' if request.url_rule.endpoint == 'fleet_node_player_group_list' }}">
|
||||
<a href="{{ url_for('fleet_node_player_group_list') }}">
|
||||
<i class="fa fa-group"></i> {{ l.fleet_node_player_group_page_title }}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if AUTH_ENABLED %}
|
||||
<li class="{{ 'active' if request.url_rule.endpoint == 'auth_user_list' }}">
|
||||
@ -132,6 +137,7 @@
|
||||
'js_common_are_you_sure': '{{ l.common_are_you_sure }}',
|
||||
'js_playlist_delete_confirmation': '{{ l.js_playlist_delete_confirmation }}',
|
||||
'js_slideshow_slide_delete_confirmation': '{{ l.js_slideshow_slide_delete_confirmation }}',
|
||||
'js_fleet_node_player_group_delete_confirmation': '{{ l.js_fleet_node_player_group_delete_confirmation }}',
|
||||
'js_fleet_node_player_delete_confirmation': '{{ l.js_fleet_node_player_delete_confirmation }}',
|
||||
'js_fleet_node_studio_delete_confirmation': '{{ l.js_fleet_node_studio_delete_confirmation }}',
|
||||
'js_auth_user_delete_confirmation': '{{ l.js_auth_user_delete_confirmation }}',
|
||||
|
||||
@ -1,35 +1,35 @@
|
||||
<div class="modal modal-slide-utrack modal-slide">
|
||||
<div class="modal modal-entity-utrack modal-entity">
|
||||
<h2>
|
||||
{{ l.utrack_title }}
|
||||
</h2>
|
||||
|
||||
<form action="/slideshow/slide/add" method="POST" enctype="multipart/form-data">
|
||||
<div class="form">
|
||||
|
||||
<div class="form-group">
|
||||
<label>{{ l.created_by }}</label>
|
||||
<div class="widget">
|
||||
<input name="name" type="text" id="slide-utrack-created-by" disabled="disabled" />
|
||||
<input name="name" type="text" id="entity-utrack-created-by" disabled="disabled" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>{{ l.updated_by }}</label>
|
||||
<div class="widget">
|
||||
<input name="name" type="text" id="slide-utrack-updated-by" disabled="disabled" />
|
||||
<input name="name" type="text" id="entity-utrack-updated-by" disabled="disabled" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>{{ l.created_at }}</label>
|
||||
<div class="widget">
|
||||
<input name="name" type="text" id="slide-utrack-created-at" disabled="disabled" />
|
||||
<input name="name" type="text" id="entity-utrack-created-at" disabled="disabled" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>{{ l.updated_at }}</label>
|
||||
<div class="widget">
|
||||
<input name="name" type="text" id="slide-utrack-updated-at" disabled="disabled" />
|
||||
<input name="name" type="text" id="entity-utrack-updated-at" disabled="disabled" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -39,5 +39,5 @@
|
||||
{{ l.close }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
55
views/fleet/player-group/component/table.jinja.html
Normal file
55
views/fleet/player-group/component/table.jinja.html
Normal file
@ -0,0 +1,55 @@
|
||||
<table class="{{ tclass }}-node-players">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ l.fleet_node_player_group_panel_th_name }}</th>
|
||||
{% if AUTH_ENABLED %}
|
||||
<th class="tac">
|
||||
<i class="fa fa-user"></i>
|
||||
</th>
|
||||
{% endif %}
|
||||
<th class="tac">{{ l.fleet_node_player_group_panel_th_activity }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="empty-tr {% if node_player_groups|length != 0 %}hidden{% endif %}">
|
||||
<td colspan="4">
|
||||
{{ l.fleet_node_player_group_panel_empty|replace(
|
||||
'%link%',
|
||||
('<a href="javascript:void(0);" class="item-add node-player-group-add">'~l.fleet_node_player_group_button_add~'</a>')|safe
|
||||
) }}
|
||||
</td>
|
||||
</tr>
|
||||
{% for node_player_group in node_player_groups %}
|
||||
<tr class="node-player-group-item" data-level="{{ node_player_group.id }}" data-entity="{{ node_player_group.to_json({"created_by": track_created(node_player_group).username, "updated_by": track_updated(node_player_group).username}) }}">
|
||||
<td class="infos">
|
||||
<div class="inner">
|
||||
<a href="javascript:void(0);" class="item-sort node-player-group-sort">
|
||||
<i class="fa fa-sort icon-left"></i>
|
||||
</a>
|
||||
|
||||
<div class="badge"><i class="fa fa-key icon-left"></i> {{ node_player_group.id }}</div>
|
||||
|
||||
<i class="fa fa-server icon-left"></i>
|
||||
{{ node_player_group.name }}
|
||||
</div>
|
||||
</td>
|
||||
{% if AUTH_ENABLED %}
|
||||
<td class="tac">
|
||||
{% set creator = track_created(node_player_group) %}
|
||||
<a href="javascript:void(0);" class="badge item-utrack node-player-group-utrack {% if not creator.enabled %}anonymous{% endif %}">
|
||||
{{ creator.username }}
|
||||
</a>
|
||||
</td>
|
||||
{% endif %}
|
||||
<td class="actions tac">
|
||||
<a href="javascript:void(0);" class="item-edit node-player-group-edit">
|
||||
<i class="fa fa-pencil"></i>
|
||||
</a>
|
||||
<a href="javascript:void(0);" class="item-delete node-player-group-delete">
|
||||
<i class="fa fa-trash"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
50
views/fleet/player-group/list.jinja.html
Normal file
50
views/fleet/player-group/list.jinja.html
Normal file
@ -0,0 +1,50 @@
|
||||
{% extends 'base.jinja.html' %}
|
||||
|
||||
{% block page_title %}
|
||||
{{ l.fleet_node_player_group_page_title }}
|
||||
{% endblock %}
|
||||
|
||||
{% block add_css %}
|
||||
{{ HOOK(H_FLEET_NODE_PLAYER_GROUP_CSS) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block add_js %}
|
||||
<script src="{{ STATIC_PREFIX }}js/fleet/node-player-groups.js"></script>
|
||||
{{ HOOK(H_FLEET_NODE_PLAYER_GROUP_JAVASCRIPT) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block page %}
|
||||
<div class="toolbar">
|
||||
<h2><i class="fa fa-group icon-left"></i>{{ l.fleet_node_player_group_page_title }}</h2>
|
||||
|
||||
<div class="toolbar-actions">
|
||||
{{ HOOK(H_FLEET_NODE_PLAYER_GROUP_TOOLBAR_ACTIONS_START) }}
|
||||
<button class="purple node-player-group-add item-add"><i class="fa fa-plus icon-left"></i>{{ l.fleet_node_player_group_button_add }}</button>
|
||||
{{ HOOK(H_FLEET_NODE_PLAYER_GROUP_TOOLBAR_ACTIONS_END) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-body">
|
||||
<h3>{{ l.fleet_node_player_group_panel_active }}</h3>
|
||||
|
||||
{% with tclass='active', node_player_groups=node_player_groups %}
|
||||
{% include 'fleet/player-group/component/table.jinja.html' %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modals hidden">
|
||||
<div class="modals-outer">
|
||||
<a href="javascript:void(0);" class="modal-close">
|
||||
<i class="fa fa-close"></i>
|
||||
</a>
|
||||
<div class="modals-inner">
|
||||
{% include 'fleet/player-group/modal/add.jinja.html' %}
|
||||
{% include 'fleet/player-group/modal/edit.jinja.html' %}
|
||||
{% include 'core/utrack.jinja.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
24
views/fleet/player-group/modal/add.jinja.html
Normal file
24
views/fleet/player-group/modal/add.jinja.html
Normal file
@ -0,0 +1,24 @@
|
||||
<div class="modal modal-node-player-group-add">
|
||||
<h2>
|
||||
{{ l.fleet_node_player_group_form_add_title }}
|
||||
</h2>
|
||||
|
||||
<form class="form" action="/fleet/node-player-group/add" method="POST" enctype="multipart/form-data">
|
||||
<div class="form-group">
|
||||
<label for="node-player-group-add-name">{{ l.fleet_node_player_group_form_label_name }}</label>
|
||||
<div class="widget">
|
||||
<input name="name" type="text" id="node-player-group-add-name" required="required" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="actions">
|
||||
<button type="button" class="btn-normal modal-close">
|
||||
{{ l.fleet_node_player_group_form_button_cancel }}
|
||||
</button>
|
||||
<button type="submit" class="green">
|
||||
<i class="fa fa-plus icon-left"></i> {{ l.fleet_node_player_group_form_add_submit }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
26
views/fleet/player-group/modal/edit.jinja.html
Normal file
26
views/fleet/player-group/modal/edit.jinja.html
Normal file
@ -0,0 +1,26 @@
|
||||
<div class="modal modal-node-player-group-edit hidden">
|
||||
<h2>
|
||||
{{ l.fleet_node_player_group_form_edit_title }}
|
||||
</h2>
|
||||
|
||||
<form class="form" action="/fleet/node-player-group/edit" method="POST">
|
||||
<input type="hidden" name="id" id="node-player-group-edit-id" />
|
||||
|
||||
<div class="form-group">
|
||||
<label for="node-player-group-edit-name">{{ l.fleet_node_player_group_form_label_name }}</label>
|
||||
<div class="widget">
|
||||
<input type="text" name="name" id="node-player-group-edit-name" required="required" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="actions">
|
||||
<button type="button" class="btn-normal modal-close">
|
||||
{{ l.fleet_node_player_group_form_button_cancel }}
|
||||
</button>
|
||||
<button type="submit" class="green">
|
||||
<i class="fa fa-save icon-left"></i>{{ l.fleet_node_player_group_form_edit_submit }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@ -2,6 +2,11 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ l.fleet_node_player_panel_th_name }}</th>
|
||||
{% if AUTH_ENABLED %}
|
||||
<th class="tac">
|
||||
<i class="fa fa-user"></i>
|
||||
</th>
|
||||
{% endif %}
|
||||
<th class="tac">{{ l.fleet_node_player_panel_th_host }}</th>
|
||||
<th class="tac">{{ l.fleet_node_player_panel_th_enabled }}</th>
|
||||
<th class="tac">{{ l.fleet_node_player_panel_th_activity }}</th>
|
||||
@ -17,7 +22,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
{% for node_player in node_players %}
|
||||
<tr class="node-player-item" data-level="{{ node_player.id }}" data-entity="{{ node_player.to_json() }}">
|
||||
<tr class="node-player-item" data-level="{{ node_player.id }}" data-entity="{{ node_player.to_json({"created_by": track_created(node_player).username, "updated_by": track_updated(node_player).username}) }}">
|
||||
<td class="infos">
|
||||
<div class="inner">
|
||||
<a href="javascript:void(0);" class="item-sort node-player-sort">
|
||||
@ -30,6 +35,14 @@
|
||||
{{ node_player.name }}
|
||||
</div>
|
||||
</td>
|
||||
{% if AUTH_ENABLED %}
|
||||
<td class="tac">
|
||||
{% set creator = track_created(node_player) %}
|
||||
<a href="javascript:void(0);" class="badge item-utrack node-player-utrack {% if not creator.enabled %}anonymous{% endif %}">
|
||||
{{ creator.username }}
|
||||
</a>
|
||||
</td>
|
||||
{% endif %}
|
||||
<td class="tac">
|
||||
{{ node_player.host }}
|
||||
</td>
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
|
||||
{% block page %}
|
||||
<div class="toolbar">
|
||||
<h2>{{ l.fleet_node_player_page_title }}</h2>
|
||||
<h2><i class="fa fa-tv icon-left"></i>{{ l.fleet_node_player_page_title }}</h2>
|
||||
|
||||
<div class="toolbar-actions">
|
||||
{{ HOOK(H_FLEET_NODE_PLAYER_TOOLBAR_ACTIONS_START) }}
|
||||
@ -24,7 +24,9 @@
|
||||
{{ HOOK(H_FLEET_NODE_PLAYER_TOOLBAR_ACTIONS_END) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel">
|
||||
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-body">
|
||||
<h3>{{ l.fleet_node_player_panel_active }}</h3>
|
||||
|
||||
@ -43,7 +45,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="modals hidden">
|
||||
<div class="modals-outer">
|
||||
<a href="javascript:void(0);" class="modal-close">
|
||||
@ -52,6 +53,7 @@
|
||||
<div class="modals-inner">
|
||||
{% include 'fleet/player/modal/add.jinja.html' %}
|
||||
{% include 'fleet/player/modal/edit.jinja.html' %}
|
||||
{% include 'core/utrack.jinja.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
{{ l.fleet_node_player_form_add_title }}
|
||||
</h2>
|
||||
|
||||
<form action="/fleet/node-player/add" method="POST" enctype="multipart/form-data">
|
||||
<form class="form" action="/fleet/node-player/add" method="POST" enctype="multipart/form-data">
|
||||
<div class="form-group">
|
||||
<label for="node-player-add-name">{{ l.fleet_node_player_form_label_name }}</label>
|
||||
<div class="widget">
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
{{ l.fleet_node_player_form_edit_title }}
|
||||
</h2>
|
||||
|
||||
<form action="/fleet/node-player/edit" method="POST">
|
||||
<form class="form" action="/fleet/node-player/edit" method="POST">
|
||||
<input type="hidden" name="id" id="node-player-edit-id" />
|
||||
|
||||
<div class="form-group">
|
||||
|
||||
@ -2,6 +2,11 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ l.fleet_node_studio_panel_th_name }}</th>
|
||||
{% if AUTH_ENABLED %}
|
||||
<th class="tac">
|
||||
<i class="fa fa-user"></i>
|
||||
</th>
|
||||
{% endif %}
|
||||
<th class="tac">{{ l.fleet_node_studio_panel_th_host }}</th>
|
||||
<th class="tac">{{ l.fleet_node_studio_panel_th_port }}</th>
|
||||
<th class="tac">{{ l.fleet_node_studio_panel_th_enabled }}</th>
|
||||
@ -18,7 +23,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
{% for node_studio in node_studios %}
|
||||
<tr class="node-studio-item" data-level="{{ node_studio.id }}" data-entity="{{ node_studio.to_json() }}">
|
||||
<tr class="node-studio-item" data-level="{{ node_studio.id }}" data-entity="{{ node_studio.to_json({"created_by": track_created(node_studio).username, "updated_by": track_updated(node_studio).username}) }}">
|
||||
<td class="infos">
|
||||
<div class="inner">
|
||||
<a href="javascript:void(0);" class="item-sort node-studio-sort">
|
||||
@ -31,6 +36,14 @@
|
||||
{{ node_studio.name }}
|
||||
</div>
|
||||
</td>
|
||||
{% if AUTH_ENABLED %}
|
||||
<td class="tac">
|
||||
{% set creator = track_created(node_studio) %}
|
||||
<a href="javascript:void(0);" class="badge item-utrack node-studio-utrack {% if not creator.enabled %}anonymous{% endif %}">
|
||||
{{ creator.username }}
|
||||
</a>
|
||||
</td>
|
||||
{% endif %}
|
||||
<td class="tac">
|
||||
{{ node_studio.host }}
|
||||
</td>
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
|
||||
{% block page %}
|
||||
<div class="toolbar">
|
||||
<h2>{{ l.fleet_node_studio_page_title }}</h2>
|
||||
<h2><i class="fa fa-server icon-left"></i>{{ l.fleet_node_studio_page_title }}</h2>
|
||||
|
||||
<div class="toolbar-actions">
|
||||
{{ HOOK(H_FLEET_NODE_STUDIO_TOOLBAR_ACTIONS_START) }}
|
||||
@ -53,6 +53,7 @@
|
||||
<div class="modals-inner">
|
||||
{% include 'fleet/studio/modal/add.jinja.html' %}
|
||||
{% include 'fleet/studio/modal/edit.jinja.html' %}
|
||||
{% include 'core/utrack.jinja.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
{{ l.fleet_node_studio_form_add_title }}
|
||||
</h2>
|
||||
|
||||
<form action="/fleet/node-studio/add" method="POST" enctype="multipart/form-data">
|
||||
<form class="form" action="/fleet/node-studio/add" method="POST" enctype="multipart/form-data">
|
||||
<div class="form-group">
|
||||
<label for="node-studio-add-name">{{ l.fleet_node_studio_form_label_name }}</label>
|
||||
<div class="widget">
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
{{ l.fleet_node_studio_form_edit_title }}
|
||||
</h2>
|
||||
|
||||
<form action="/fleet/node-studio/edit" method="POST">
|
||||
<form class="form" action="/fleet/node-studio/edit" method="POST">
|
||||
<input type="hidden" name="id" id="node-studio-edit-id" />
|
||||
|
||||
<div class="form-group">
|
||||
|
||||
@ -2,6 +2,11 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ l.playlist_panel_th_name }}</th>
|
||||
{% if AUTH_ENABLED %}
|
||||
<th class="tac">
|
||||
<i class="fa fa-user"></i>
|
||||
</th>
|
||||
{% endif %}
|
||||
<th class="tac"><i class="fa fa-compass"></i></th>
|
||||
<th class="tac">{{ l.playlist_panel_th_enabled }}</th>
|
||||
<th class="tac">{{ l.playlist_panel_th_duration }}</th>
|
||||
@ -18,7 +23,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
{% for playlist in playlists %}
|
||||
<tr class="playlist-item" data-level="{{ playlist.id }}" data-entity="{{ playlist.to_json() }}">
|
||||
<tr class="playlist-item" data-level="{{ playlist.id }}" data-entity="{{ playlist.to_json({"created_by": track_created(playlist).username, "updated_by": track_updated(playlist).username}) }}">
|
||||
<td class="infos">
|
||||
<div class="inner">
|
||||
{% if playlist.id %}
|
||||
@ -31,6 +36,16 @@
|
||||
{{ playlist.name }}
|
||||
</div>
|
||||
</td>
|
||||
{% if AUTH_ENABLED %}
|
||||
<td class="tac">
|
||||
{% if playlist.id %}
|
||||
{% set creator = track_created(playlist) %}
|
||||
<a href="javascript:void(0);" class="badge item-utrack playlist-utrack {% if not creator.enabled %}anonymous{% endif %}">
|
||||
{{ creator.username }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
<td class="tac">
|
||||
{% if playlist.time_sync %}
|
||||
✅
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
|
||||
{% block page %}
|
||||
<div class="toolbar">
|
||||
<h2>{{ l.playlist_page_title }}</h2>
|
||||
<h2><i class="fa fa-bars-staggered icon-left"></i>{{ l.playlist_page_title }}</h2>
|
||||
|
||||
<div class="toolbar-actions">
|
||||
{{ HOOK(H_PLAYLIST_TOOLBAR_ACTIONS_START) }}
|
||||
@ -55,6 +55,7 @@
|
||||
<div class="modals-inner">
|
||||
{% include 'playlist/modal/add.jinja.html' %}
|
||||
{% include 'playlist/modal/edit.jinja.html' %}
|
||||
{% include 'core/utrack.jinja.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
{{ l.playlist_form_add_title }}
|
||||
</h2>
|
||||
|
||||
<form action="/playlist/add" method="POST" enctype="multipart/form-data">
|
||||
<form class="form" action="/playlist/add" method="POST" enctype="multipart/form-data">
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
</h2>
|
||||
|
||||
|
||||
<form action="/playlist/edit" method="POST">
|
||||
<form class="form" action="/playlist/edit" method="POST">
|
||||
|
||||
<input type="hidden" name="id" id="playlist-edit-id" />
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
|
||||
{% block page %}
|
||||
<div class="toolbar">
|
||||
<h2>{{ l.settings_page_title }}</h2>
|
||||
<h2><i class="fa fa-cogs icon-left"></i>{{ l.settings_page_title }}</h2>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<div class="panel-body">
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
{{ l.settings_variable_form_edit_title }}
|
||||
</h2>
|
||||
|
||||
<form action="/settings/variable/edit" method="POST">
|
||||
<form class="form" action="/settings/variable/edit" method="POST">
|
||||
<input type="hidden" name="id" id="variable-edit-id" />
|
||||
|
||||
<div class="form-group">
|
||||
|
||||
@ -23,10 +23,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
{% for slide in slides %}
|
||||
<tr class="slide-item" data-level="{{ slide.id }}" data-entity="{{ slide.to_json({
|
||||
"created_by": track_created(slide).username,
|
||||
"updated_by": track_updated(slide).username
|
||||
}) }}">
|
||||
<tr class="slide-item" data-level="{{ slide.id }}" data-entity="{{ slide.to_json({"created_by": track_created(slide).username, "updated_by": track_updated(slide).username}) }}">
|
||||
<td class="infos">
|
||||
<div class="inner">
|
||||
<a href="javascript:void(0);" class="item-sort slide-sort">
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
|
||||
{% block page %}
|
||||
<div class="toolbar">
|
||||
<h2>{{ l.slideshow_page_title }}</h2>
|
||||
<h2><i class="fa-regular fa-clock icon-left"></i>{{ l.slideshow_page_title }}</h2>
|
||||
|
||||
<div class="toolbar-actions">
|
||||
{{ HOOK(H_SLIDESHOW_TOOLBAR_ACTIONS_START) }}
|
||||
@ -91,7 +91,7 @@
|
||||
<div class="modals-inner">
|
||||
{% include 'slideshow/modal/add.jinja.html' %}
|
||||
{% include 'slideshow/modal/edit.jinja.html' %}
|
||||
{% include 'slideshow/modal/utrack.jinja.html' %}
|
||||
{% include 'core/utrack.jinja.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -3,14 +3,14 @@
|
||||
{{ l.slideshow_slide_form_add_title }}
|
||||
</h2>
|
||||
|
||||
<form action="/slideshow/slide/add" method="POST" enctype="multipart/form-data">
|
||||
<form class="form" action="/slideshow/slide/add" method="POST" enctype="multipart/form-data">
|
||||
|
||||
<h3>
|
||||
{{ l.slideshow_slide_form_section_content }}
|
||||
</h3>
|
||||
|
||||
{% if current_playlist %}
|
||||
<input name="playlist" type="hidden" id="slide-add-playlist" value="{{ current_playlist.id }}">
|
||||
<input name="playlist_id" type="hidden" id="slide-add-playlist-id" value="{{ current_playlist.id }}">
|
||||
{% endif %}
|
||||
|
||||
<div class="form-group">
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
</h2>
|
||||
|
||||
|
||||
<form action="/slideshow/slide/edit" method="POST">
|
||||
<form class="form" action="/slideshow/slide/edit" method="POST">
|
||||
|
||||
<h3>
|
||||
{{ l.slideshow_slide_form_section_content }}
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
|
||||
{% block page %}
|
||||
<div class="toolbar">
|
||||
<h2>{{ l.sysinfo_page_title }}</h2>
|
||||
<h2><i class="fa fa-list-check icon-left"></i>{{ l.sysinfo_page_title }}</h2>
|
||||
<div class="toolbar-actions">
|
||||
{{ HOOK(H_SYSINFO_TOOLBAR_ACTIONS_START) }}
|
||||
<button class="purple sysinfo-restart"><i class="fa fa-refresh icon-left"></i>{{ l.sysinfo_panel_button_restart }}</button>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user