- Updated various views to replace 'dashboard-card' with 'content-card' for consistency in styling. - Modified filter and table card classes across multiple pages including applications, campaigns, commands, datasets, dayparts, displays, display groups, display profiles, fonts, layouts, libraries, menu boards, modules, player software, playlists, resolutions, schedules, settings, sync groups, tags, tasks, templates, transitions, users, and user groups.
408 lines
28 KiB
Twig
408 lines
28 KiB
Twig
{#
|
|
/**
|
|
* Copyright (C) 2023 Xibo Signage Ltd
|
|
*
|
|
* Xibo - Digital Signage - http://www.xibo.org.uk
|
|
*
|
|
* 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 %}{{ "Displays"|trans }} | {% endblock %}
|
|
|
|
{% block actionMenu %}{% endblock %}
|
|
|
|
{% block headContent %}
|
|
{# Add page source code bundle ( CSS ) #}
|
|
<script nonce="{{ cspNonce }}">
|
|
(function(){
|
|
try{
|
|
var stored = localStorage.getItem('ots-theme-mode');
|
|
var prefersLight = window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches;
|
|
var mode = stored || (prefersLight ? 'light' : 'light');
|
|
if(mode === 'light') document.documentElement.classList.add('ots-light-mode');
|
|
else document.documentElement.classList.remove('ots-light-mode');
|
|
}catch(e){}
|
|
})();
|
|
|
|
(function(){
|
|
// Apply collapsed sidebar state early to prevent header flashing
|
|
try {
|
|
var collapsed = localStorage.getItem('otsTheme:sidebarCollapsed');
|
|
if (collapsed === 'true') {
|
|
try { console.debug && console.debug('otsTheme:sidebarCollapsed early (page):', collapsed); } catch(e){}
|
|
document.documentElement.classList.add('ots-sidebar-collapsed');
|
|
if (document.body) document.body.classList.add('ots-sidebar-collapsed');
|
|
try { console.debug && console.debug('applied ots-sidebar-collapsed early (page)'); } catch(e){}
|
|
} else {
|
|
try { console.debug && console.debug('otsTheme:sidebarCollapsed early (page): not set'); } catch(e){}
|
|
}
|
|
} catch (e) {}
|
|
})();
|
|
</script>
|
|
<style nonce="{{ cspNonce }}">html,body{background:#ffffff!important;color:#111111!important}
|
|
/* Hide the topbar strip entirely — actions are now in .ots-page-actions */
|
|
.row.header.header-side,
|
|
.ots-topbar-strip { display: none !important; height: 0 !important; margin: 0 !important; padding: 0 !important; overflow: hidden !important; }
|
|
</style>
|
|
|
|
<link rel="stylesheet" href="{{ theme.rootUri() }}dist/pages/display-page.bundle.min.css?v={{ version }}&rev={{revision }}">
|
|
{% endblock %}
|
|
|
|
{% block pageContent %}
|
|
<div class="ots-displays-page">
|
|
<div class="page-header ots-page-header">
|
|
<h1>{% trans "Displays" %}</h1>
|
|
<p class="text-muted">{% trans "Manage your player fleet and status." %}</p>
|
|
</div>
|
|
|
|
<div class="widget content-card ots-displays-card">
|
|
<div class="widget-body ots-displays-body">
|
|
<div class="XiboGrid" id="{{ random() }}" data-grid-name="displayView">
|
|
<div class="XiboFilter card mb-3 bg-light content-card ots-filter-card">
|
|
<div class="ots-filter-header">
|
|
<h3 class="ots-filter-title">{% trans "Filter Displays" %}</h3>
|
|
<button type="button" class="ots-filter-toggle" id="ots-filter-collapse-btn" title="{% trans 'Toggle filter panel' %}">
|
|
<i class="fa fa-chevron-down"></i>
|
|
</button>
|
|
</div>
|
|
<div class="ots-filter-content collapsed" id="ots-filter-content">
|
|
<div class="FilterDiv card-body" id="Filter">
|
|
<ul class="nav nav-tabs" role="tablist">
|
|
<li class="nav-item"><a class="nav-link active" href="#filter-general" role="tab" data-toggle="tab">{% trans "General" %}</a></li>
|
|
<li class="nav-item"><a class="nav-link" href="#filter-advanced" role="tab" data-toggle="tab">{% trans "Advanced" %}</a></li>
|
|
</ul>
|
|
<form class="form-inline">
|
|
<div class="tab-content">
|
|
<div class="tab-pane active" id="filter-general">
|
|
{% set title %}{% trans "ID" %}{% endset %}
|
|
{{ inline.number("displayId", title) }}
|
|
|
|
{% set title %}{% trans "Name" %}{% endset %}
|
|
{{ inline.inputNameGrid('display', title) }}
|
|
|
|
{% set title %}{% trans "Status" %}{% endset %}
|
|
{% set check %}{% trans "Up to date" %}{% endset %}
|
|
{% set cross %}{% trans "Downloading" %}{% endset %}
|
|
{% set cloud %}{% trans "Out of date" %}{% endset %}
|
|
{% set options = [
|
|
{ optionid: "", option: "" },
|
|
{ optionid: "1", option: check},
|
|
{ optionid: "2", option: cross},
|
|
{ optionid: "3", option: cloud}
|
|
] %}
|
|
{{ inline.dropdown("mediaInventoryStatus", "single", title, "", options, "optionid", "option") }}
|
|
|
|
{% set title %}{% trans "Logged In?" %}{% endset %}
|
|
{% set yesOption %}{% trans "Yes" %}{% endset %}
|
|
{% set noOption %}{% trans "No" %}{% endset %}
|
|
{% set options = [
|
|
{ optionid: "", option: "" },
|
|
{ optionid: "1", option: yesOption},
|
|
{ optionid: "0", option: noOption}
|
|
] %}
|
|
{{ inline.dropdown("loggedIn", "single", title, "", options, "optionid", "option") }}
|
|
|
|
{% set title %}{% trans "Authorised?" %}{% endset %}
|
|
{% set yesOption %}{% trans "Yes" %}{% endset %}
|
|
{% set noOption %}{% trans "No" %}{% endset %}
|
|
{% set options = [
|
|
{ optionid: "", option: "" },
|
|
{ optionid: "1", option: yesOption },
|
|
{ optionid: "0", option: noOption},
|
|
] %}
|
|
{{ inline.dropdown("authorised", "single", title, "", options, "optionid", "option") }}
|
|
|
|
{% set title %}{% trans "XMR Registered?" %}{% endset %}
|
|
{% set yesOption %}{% trans "Yes" %}{% endset %}
|
|
{% set noOption %}{% trans "No" %}{% endset %}
|
|
{% set options = [
|
|
{ optionid: "", option: "" },
|
|
{ optionid: 1, option: yesOption},
|
|
{ optionid: 0, option: noOption},
|
|
] %}
|
|
{{ inline.dropdown("xmrRegistered", "single", title, "", options, "optionid", "option") }}
|
|
|
|
{% if currentUser.featureEnabled("tag.tagging") %}
|
|
{% set title %}{% trans "Tags" %}{% endset %}
|
|
{% set exactTagTitle %}{% trans "Exact match?" %}{% endset %}
|
|
{% set logicalOperatorTitle %}{% trans "When filtering by multiple Tags, which logical operator should be used?" %}{% endset %}
|
|
{% set helpText %}{% trans "A comma separated list of tags to filter by. Enter a tag|tag value to filter tags with values. Enter --no-tag to filter all items without tags. Enter - before a tag or tag value to exclude from results." %}{% endset %}
|
|
{{ inline.inputWithTags("tags", title, null, helpText, null, null, null, "exactTags", exactTagTitle, logicalOperatorTitle) }}
|
|
{% endif %}
|
|
|
|
{% if currentUser.featureEnabled("displaygroup.view") %}
|
|
{% set title %}{% trans "Display Group" %}{% endset %}
|
|
{% set attributes = [
|
|
{ name: "data-width", value: "100%" },
|
|
{ name: "data-allow-clear", value: "true" },
|
|
{ name: "data-placeholder--id", value: null },
|
|
{ name: "data-placeholder--value", value: "" },
|
|
{ name: "data-search-url", value: url_for("displayGroup.search") },
|
|
{ name: "data-filter-options", value: '{"isDisplaySpecific":0}' },
|
|
{ name: "data-search-term", value: "displayGroup" },
|
|
{ name: "data-id-property", value: "displayGroupId" },
|
|
{ name: "data-text-property", value: "displayGroup" },
|
|
{ name: "data-initial-key", value: "displayGroupId" },
|
|
] %}
|
|
{{ inline.dropdown("displayGroupId", "single", title, "", null, "displayGroupId", "displayGroup", helpText, "pagedSelect", "", "", "", attributes) }}
|
|
{% endif %}
|
|
|
|
{% if currentUser.featureEnabled("displayprofile.view") %}
|
|
{% set title %}{% trans "Display Profile" %}{% endset %}
|
|
{{ inline.dropdown("displayProfileId", "single", title, "", [{displayProfileId:null, name:""}]|merge(displayProfiles), "displayProfileId", "name") }}
|
|
{% endif %}
|
|
|
|
{{ inline.hidden("folderId") }}
|
|
</div>
|
|
|
|
<div class="tab-pane" id="filter-advanced">
|
|
{% set title %}{% trans "Last Accessed" %}{% endset %}
|
|
{{ inline.date("lastAccessed", title) }}
|
|
|
|
{% set title %}{% trans "Player Type" %}{% endset %}
|
|
{% set android %}{% trans "Android" %}{% endset %}
|
|
{% set chromeos %}{% trans "ChromeOS" %}{% endset %}
|
|
{% set windows %}{% trans "Windows" %}{% endset %}
|
|
{% set webos %}{% trans "webOS" %}{% endset %}
|
|
{% set sssp %}{% trans "Tizen" %}{% endset %}
|
|
{% set linux %}{% trans "Linux" %}{% endset %}
|
|
{% set options = [
|
|
{ optionid: "", option: "" },
|
|
{ optionid: "android", option: android},
|
|
{ optionid: "chromeos", option: chromeos},
|
|
{ optionid: "windows", option: windows},
|
|
{ optionid: "lg", option: webos},
|
|
{ optionid: "sssp", option: sssp},
|
|
{ optionid: "linux", option: linux},
|
|
] %}
|
|
{{ inline.dropdown("clientType", "single", title, "", options, "optionid", "option") }}
|
|
|
|
{% set title %}{% trans "Player Code" %}{% endset %}
|
|
{{ inline.input("clientCode", title) }}
|
|
|
|
{% set title %}{% trans "Custom ID" %}{% endset %}
|
|
{{ inline.input("customId", title) }}
|
|
|
|
{% set title %}{% trans "Mac Address" %}{% endset %}
|
|
{{ inline.input("macAddress", title) }}
|
|
|
|
{% set title %}{% trans "IP Address" %}{% endset %}
|
|
{{ inline.input("clientAddress", title) }}
|
|
|
|
{% set title %}{% trans "Orientation" %}{% endset %}
|
|
{% set landscape %}{% trans "Landscape" %}{% endset %}
|
|
{% set portrait %}{% trans "Portrait" %}{% endset %}
|
|
{% set options = [
|
|
{ optionid: "", option: "" },
|
|
{ optionid: "landscape", option: landscape},
|
|
{ optionid: "portrait", option: portrait}
|
|
] %}
|
|
{{ inline.dropdown("orientation", "single", title, "", options, "optionid", "option") }}
|
|
|
|
{% set title %}{% trans "Commercial Licence" %}{% endset %}
|
|
{% set licensed %}{% trans "Licensed fully" %}{% endset %}
|
|
{% set trial %}{% trans "Trial" %}{% endset %}
|
|
{% set notLinceced %}{% trans "Not licenced" %}{% endset %}
|
|
{% set notApplicable %}{% trans "Not applicable" %}{% endset %}
|
|
{% set options = [
|
|
{ optionid: "", option: "" },
|
|
{ optionid: "1", option: licensed},
|
|
{ optionid: "2", option: trial},
|
|
{ optionid: "0", option: notLinceced},
|
|
{ optionid: "3", option: notApplicable}
|
|
] %}
|
|
{{ inline.dropdown("commercialLicence", "single", title, "", options, "optionid", "option") }}
|
|
|
|
{% set title %}{% trans "Player supported?" %}{% endset %}
|
|
{% set yesOption %}{% trans "Yes" %}{% endset %}
|
|
{% set noOption %}{% trans "No" %}{% endset %}
|
|
{% set options = [
|
|
{ optionid: "", option: "" },
|
|
{ optionid: 1, option: yesOption},
|
|
{ optionid: 0, option: noOption},
|
|
] %}
|
|
{{ inline.dropdown("isPlayerSupported", "single", title, "", options, "optionid", "option") }}
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="grid-with-folders-container ots-grid-with-folders">
|
|
<div class="grid-folder-tree-container p-3 content-card ots-folder-tree" id="grid-folder-filter">
|
|
<input id="jstree-search" class="form-control" type="text" placeholder="{% trans "Search" %}">
|
|
<div class="form-check">
|
|
<input type="checkbox" class="form-check-input" id="folder-tree-clear-selection-button">
|
|
<label class="form-check-label" for="folder-tree-clear-selection-button" title="{% trans "Search in all folders" %}">{% trans "All Folders" %}</label>
|
|
</div>
|
|
<div class="folder-search-no-results d-none">
|
|
<p>{% trans 'No Folders matching the search term' %}</p>
|
|
</div>
|
|
<div id="container-folder-tree"></div>
|
|
</div>
|
|
<div id="datatable-container">
|
|
<div class="XiboData card py-3 content-card ots-table-card">
|
|
<div class="ots-table-toolbar">
|
|
<button type="button" id="folder-tree-select-folder-button" class="btn btn-sm btn-outline-secondary ots-toolbar-btn" title="{{ "Open / Close Folder Search options"|trans }}"><i class="fas fa-folder"></i></button>
|
|
<div id="breadcrumbs"></div>
|
|
<button type="button" id="map_button" class="btn btn-sm btn-outline-secondary ots-toolbar-btn" title="{{ "Map"|trans }}"><i class="fa fa-map"></i></button>
|
|
<button type="button" id="list_button" class="btn btn-sm btn-outline-secondary ots-toolbar-btn" title="{{ "List"|trans }}"><i class="fa fa-list"></i></button>
|
|
{% if currentUser.featureEnabled("displays.add") %}
|
|
<button class="btn btn-sm btn-success ots-toolbar-btn XiboFormButton" title="{% trans "Add a Display via user_code displayed on the Player screen" %}" href="{{ url_for("display.addViaCode.form") }}"><i class="fa fa-plus-circle" aria-hidden="true"></i></button>
|
|
{% endif %}
|
|
<button class="btn btn-sm btn-primary ots-toolbar-btn" id="refreshGrid" title="{% trans "Refresh the Table" %}" href="#"><i class="fa fa-refresh" aria-hidden="true"></i></button>
|
|
</div>
|
|
<table id="displays" class="table table-striped" data-content-type="display" data-content-id-name="displayId" data-state-preference-name="displayGrid" style="width: 100%;">
|
|
<thead>
|
|
<tr>
|
|
<th>{% trans "ID" %}</th>
|
|
<th>{% trans "Display" %}</th>
|
|
<th>{% trans "Display Type" %}</th>
|
|
<th>{% trans "Address" %}</th>
|
|
<th>{% trans "Status" %}</th>
|
|
<th>{% trans "Authorised?" %}</th>
|
|
<th>{% trans "Current Layout" %}</th>
|
|
<th>{% trans "Storage Available" %}</th>
|
|
<th>{% trans "Storage Total" %}</th>
|
|
<th>{% trans "Storage Free %" %}</th>
|
|
<th>{% trans "Description" %}</th>
|
|
<th>{% trans "Orientation" %}</th>
|
|
<th>{% trans "Resolution" %}</th>
|
|
{% if currentUser.featureEnabled("tag.tagging") %}<th>{% trans "Tags" %}</th>{% endif %}
|
|
<th>{% trans "Default Layout" %}</th>
|
|
<th>{% trans "Interleave Default" %}</th>
|
|
<th>{% trans "Email Alert" %}</th>
|
|
<th>{% trans "Logged In" %}</th>
|
|
<th>{% trans "Last Accessed" %}</th>
|
|
<th>{% trans "Display Profile" %}</th>
|
|
<th>{% trans "Version" %}</th>
|
|
<th>{% trans "Supported?" %}</th>
|
|
<th>{% trans "Device Name" %}</th>
|
|
<th>{% trans "IP Address" %}</th>
|
|
<th>{% trans "Mac Address" %}</th>
|
|
<th>{% trans "Timezone" %}</th>
|
|
<th>{% trans "Languages" %}</th>
|
|
<th>{% trans "Latitude" %}</th>
|
|
<th>{% trans "Longitude" %}</th>
|
|
<th>{% trans "Screen shot?" %}</th>
|
|
<th>{% trans "Thumbnail" %}</th>
|
|
<th>{% trans "CMS Transfer?" %}</th>
|
|
<th>{% trans "Bandwidth Limit" %}</th>
|
|
<th>{% trans "Last Command" %}</th>
|
|
<th>{% trans "XMR Registered" %}</th>
|
|
<th>{% trans "Commercial Licence" %}</th>
|
|
<th>{% trans "Remote" %}</th>
|
|
<th>{% trans "Sharing" %}</th>
|
|
<th>{% trans "Screen Size" %}</th>
|
|
<th>{% trans "Is Mobile?" %}</th>
|
|
<th>{% trans "Outdoor?" %}</th>
|
|
<th>{% trans "Reference 1" %}</th>
|
|
<th>{% trans "Reference 2" %}</th>
|
|
<th>{% trans "Reference 3" %}</th>
|
|
<th>{% trans "Reference 4" %}</th>
|
|
<th>{% trans "Reference 5" %}</th>
|
|
<th>{% trans "Custom ID" %}</th>
|
|
<th>{% trans "Cost Per Play" %}</th>
|
|
<th>{% trans "Impressions Per Play" %}</th>
|
|
<th>{% trans "Created Date" %}</th>
|
|
<th>{% trans "Modified Date" %}</th>
|
|
<th>{% trans "Faults?" %}</th>
|
|
<th>{% trans "OS Version" %}</th>
|
|
<th>{% trans "OS SDK" %}</th>
|
|
<th>{% trans "Manufacturer" %}</th>
|
|
<th>{% trans "Brand" %}</th>
|
|
<th>{% trans "Model" %}</th>
|
|
<th class="rowMenu"></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
|
|
</tbody>
|
|
</table>
|
|
|
|
<!-- Map -->
|
|
<div class="row">
|
|
<div class="col-sm-12">
|
|
<div class="map-legend" style="display:none; position: absolute; z-index: 500; right: 20px; top: 10px;">
|
|
<div class="display-map-legend" style="font-size: 12px;">
|
|
<div>Logged in</div>
|
|
<div><img style="width: 15%" src='{{ theme.rootUri() }}dist/assets/map-marker-green-check.png'/> - Up to date</div>
|
|
<div><img style="width: 15%" src='{{ theme.rootUri() }}dist/assets/map-marker-yellow-check.png'/> - Out of date</div>
|
|
<div><img style="width: 15%" src='{{ theme.rootUri() }}dist/assets/map-marker-red-check.png'/> - Downloading/Unknown</div>
|
|
</br>
|
|
<div>Logged out</div>
|
|
<div><img style="width: 15%" src='{{ theme.rootUri() }}dist/assets/map-marker-green-cross.png'/> - Up to date</div>
|
|
<div><img style="width: 15%" src='{{ theme.rootUri() }}dist/assets/map-marker-yellow-cross.png'/> - Out of date</div>
|
|
<div><img style="width: 15%" src='{{ theme.rootUri() }}dist/assets/map-marker-red-cross.png'/> - Downloading/Unknown</div>
|
|
</div>
|
|
</div>
|
|
<div id="display-map" class="content-card ots-map-card" data-displays-url="{{ url_for("display.map") }}">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block javaScript %}
|
|
{# Initialise JS variables and translations #}
|
|
<script type="text/javascript" nonce="{{ cspNonce }}" defer>
|
|
{# JS variables #}
|
|
var publicPath = "{{ theme.rootUri() }}";
|
|
var displaySearchURL = "{{ url_for('display.search') }}";
|
|
var layoutSearchURL = "{{ url_for('layout.search') }}";
|
|
var mapConfig = {{ mapConfig| json_encode | raw }};
|
|
var playerVersionSupport = "{{playerVersion}}";
|
|
var folderViewEnabled = "{{ currentUser.featureEnabled('folder.view') }}";
|
|
var taggingEnabled = "{{ currentUser.featureEnabled('tag.tagging') }}";
|
|
var showThumbnailColumn = "{{ currentUser.getOptionValue('showThumbnailColumn', 1) }}";
|
|
var SHOW_DISPLAY_AS_VNCLINK = "{{ settings.SHOW_DISPLAY_AS_VNCLINK }}";
|
|
var SHOW_DISPLAY_AS_VNC_TGT = "{{ settings.SHOW_DISPLAY_AS_VNC_TGT }}";
|
|
|
|
{# Custom translations #}
|
|
var displayPageTrans = {
|
|
back: "{% trans "Back" %}",
|
|
yes: "{% trans "Yes" %}",
|
|
no: "{% trans "No" %}",
|
|
daysOfTheWeek: {
|
|
monday: "{% trans "Monday" %}",
|
|
tuesday: "{% trans "Tuesday" %}",
|
|
wednesday: "{% trans "Wednesday" %}",
|
|
thursday: "{% trans "Thursday" %}",
|
|
friday: "{% trans "Friday" %}",
|
|
saturday: "{% trans "Saturday" %}",
|
|
sunday: "{% trans "Sunday" %}",
|
|
},
|
|
playerStatusWindow: "{% trans "Player Status Window" %}",
|
|
VNCtoThisDisplay: "{% trans "VNC to this Display" %}",
|
|
TeamViewertoThisDisplay: "{% trans "TeamViewer to this Display" %}",
|
|
WebkeytoThisDisplay: "{% trans "Webkey to this Display" %}",
|
|
};
|
|
</script>
|
|
|
|
{# Add page source code bundle ( JS ) #}
|
|
<script src="{{ theme.rootUri() }}dist/leaflet.bundle.min.js?v={{ version }}&rev={{revision}}" nonce="{{ cspNonce }}"></script>
|
|
<script src="{{ theme.rootUri() }}dist/pages/display-page.bundle.min.js?v={{ version }}&rev={{revision}}" nonce="{{ cspNonce }}"></script>
|
|
{% endblock %}
|