Files
OTSSignsTheme/custom/otssignange/views/applications-page.twig
Matt Batchelder 29b56bef4f Refactor dashboard card classes to use 'content-card' instead of 'dashboard-card'
- 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.
2026-02-11 09:17:45 -05:00

269 lines
11 KiB
Twig

{#
/*
* OTS Signs Theme - Applications Page
* Based on Xibo CMS applications-page.twig with OTS styling
*/
#}
{% extends "authed.twig" %}
{% import "inline.twig" as inline %}
{% block title %}{{ "Applications"|trans }} | {% endblock %}
{% block actionMenu %}{% endblock %}
{% block pageContent %}
<div class="ots-displays-page">
<div class="page-header ots-page-header">
<h1>{% trans "Applications" %}</h1>
<p class="text-muted">{% trans "Manage API applications and connectors." %}</p>
</div>
<div class="widget content-card ots-displays-card">
<div class="widget-body ots-displays-body">
<div class="XiboGrid" id="{{ random() }}">
<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 Applications" %}</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">
<form class="form-inline">
{% set title %}{% trans "Name" %}{% endset %}
{{ inline.inputNameGrid('name', title) }}
</form>
</div>
</div>
</div>
<div class="XiboData card pt-3 content-card ots-table-card">
<div class="ots-table-toolbar">
<button class="btn btn-sm btn-success ots-toolbar-btn XiboFormButton" title="{% trans "Add an Application" %}" href="{{ url_for("application.add.form") }}"><i class="fa fa-plus-circle" aria-hidden="true"></i></button>
<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="applications" class="table table-striped">
<thead>
<tr>
<th>{% trans "Name" %}</th>
<th>{% trans "Owner" %}</th>
<th class="rowMenu"></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="widget content-card ots-displays-card mt-2">
<div class="widget-body ots-displays-body">
<div class="page-header ots-page-header">
<h1>{% trans "Connectors" %}</h1>
</div>
<div id="connectors" class="card-deck">
{% if theme.getThemeConfig("app_name") == "Xibo" %}
<div class="card p3 mt-2" style="min-width: 250px; max-width: 250px;">
<img class="card-img-top" style="max-height: 250px" src="{{ theme.rootUri() }}theme/default/img/connectors/canva_logo.png" alt="Canva">
<div class="card-body">
<h5 class="card-title">Canva</h5>
<p class="card-text">
Publish your designs from Canva to Xibo at the push of a button.
<br/>
<br/>
This connector is configured in Canva using the "Publish menu".
</p>
</div>
<div class="card-footer">
<a class="btn btn-primary" href="https://canva.com" target="_blank">Visit Canva</a>
</div>
</div>
{% endif %}
</div>
</div>
</div>
{% endblock %}
{% block javaScript %}
<script type="text/javascript" nonce="{{ cspNonce }}">
{% autoescape "js" %}
var copyToClipboardTrans = "{{ "Copy to Clipboard"|trans }}";
var couldNotCopyTrans = "{{ "Could not copy"|trans }}";
var copiedTrans = "{{ "Copied!"|trans }}";
{% endautoescape %}
var table;
$(document).ready(function() {
table = $('#applications').DataTable({
language: dataTablesLanguage,
dom: dataTablesTemplate,
serverSide: true,
stateSave: true,
responsive: true,
stateDuration: 0,
stateLoadCallback: dataTableStateLoadCallback,
stateSaveCallback: dataTableStateSaveCallback,
filter: false,
searchDelay: 3000,
"order": [[ 0, "asc"]],
ajax: {
url: "{{ url_for('application.search') }}",
data: function (d) {
$.extend(d, $('#applications').closest(".XiboGrid").find(".FilterDiv form").serializeObject());
}
},
"columns": [
{ "data": "name", "render": dataTableSpacingPreformatted },
{ "data": "owner" },
{
"orderable": false,
responsivePriority: 1,
"data": dataTableButtonsColumn
}
]
});
table.on('draw', dataTableDraw);
table.on('processing.dt', dataTableProcessing);
dataTableAddButtons(table, $('#applications_wrapper').find('.dataTables_buttons'));
$("#refreshGrid").click(function () {
table.ajax.reload();
});
// Connectors
loadConnectors();
});
function loadConnectors() {
var connectorTemplate = Handlebars.compile($('#template-connector-cards').html());
var $connectorContainer = $('#connectors');
$connectorContainer.find('.connector').remove();
$.ajax({
type: 'GET',
url: '{{ url_for("connector.search") }}?isVisible=1&showUninstalled=1',
cache: false,
dataType:"json",
success: function(xhr, textStatus, error) {
$.each(xhr.data, function(index, element) {
if (element.isHidden) {
return;
}
element.configureUrl = '{{ url_for("connector.edit.form", {id: ":id"}) }}'.replace(':id', element.connectorId);
element.proxyUrl = '{{ url_for("connector.edit.form.proxy", {id: ":id", method: ":method"}) }}'.replace(':id', element.connectorId);
element.thumbnail = element.thumbnail || 'theme/default/img/thumbs/placeholder.png';
if (!element.thumbnail.startsWith('http')) {
element.thumbnail = '{{ theme.rootUri() }}' + element.thumbnail;
}
element.enabledIcon = (element.isEnabled) ? 'fa-check' : 'fa-times';
element.classNameLast = element.className.substr(element.className.lastIndexOf('\\') + 1);
$connectorContainer.append(connectorTemplate(element));
});
$connectorContainer.trigger('connectors.loaded');
XiboInitialise('#connectors');
}
});
}
function connectorFormSubmit() {
XiboFormSubmit($('#connectorEditForm'), null, function() {
loadConnectors();
});
}
function copyFromSecretInput(dialog) {
$('#copy-button').tooltip();
$('#copy-button').bind('click', function() {
var input = $('#clientSecret');
input.focus();
input.select();
try {
var success = document.execCommand('copy');
if (success) {
$('#copy-button').trigger('copied', [copiedTrans]);
} else {
$('#copy-button').trigger('copied', [couldNotCopyTrans]);
}
} catch (err) {
$('#copy-button').trigger('copied', [couldNotCopyTrans]);
}
input.blur();
});
$('#copy-button').bind('copied', function(event, message) {
const $self = $(this);
$(this).tooltip('hide')
.attr('data-original-title', message)
.tooltip('show');
setTimeout(function() {
$self.tooltip('hide').attr('data-original-title', copyToClipboardTrans);
}, 1000);
});
onAuthCodeChanged(dialog);
$(dialog).find('#authCode').on('change', function() {
onAuthCodeChanged(dialog);
});
}
function onAuthCodeChanged(dialog) {
var authCode = $(dialog).find("#authCode").is(":checked");
var $authCodeTab = $(dialog).find(".tabForAuthCode");
if (authCode) {
$authCodeTab.removeClass("d-none");
} else {
$authCodeTab.addClass("d-none");
}
}
</script>
{% for js in connectorJavaScript %}
{% include js ~ ".twig" %}
{% endfor %}
{% endblock %}
{% block javaScriptTemplates %}
{{ parent() }}
{% verbatim %}
<script type="text/x-handlebars-template" id="template-connector-cards">
<div class="connector card p3 mt-2" style="min-width: 250px; max-width: 250px;"
data-proxy-url="{{proxyUrl}}"
data-connector-class-name="{{className}}"
data-connector-class-name-last="{{classNameLast}}"
data-connector-id="{{ connectorId }}">
{{#if thumbnail}}<img class="card-img-top" style="max-height: 250px" src="{{ thumbnail }}" alt="{{ title }}">{{/if}}
<div class="card-body">
<h5 class="card-title">{{ title }}</h5>
<p class="card-text">
{{ description }}
<br/>
<br/>
{{#if isInstalled }}
{% endverbatim %}{{ "Enabled"|trans }}{% verbatim %}: <span class="fa {{ enabledIcon }}"></span>
{{/if}}
{{#unless isInstalled }}
{% endverbatim %}{{ "Installed"|trans }}{% verbatim %}: <span class="fa fa-times"></span>
{{/unless}}
</p>
</div>
<div class="card-footer">
<button class="btn btn-primary XiboFormButton" href="{{ configureUrl }}">
{% endverbatim %}{{ "Configure"|trans }}{% verbatim %}
</button>
</div>
</div>
</script>
{% endverbatim %}
{% endblock %}