From f392e5d016122fcf3ddc005ec665a15bc4c79119 Mon Sep 17 00:00:00 2001 From: Matt Batchelder Date: Wed, 4 Feb 2026 15:26:44 -0500 Subject: [PATCH] almost functional --- custom/otssignange/css/override-dark.css | 282 ++++++- custom/otssignange/css/override.css | 695 +++++++++++++++--- custom/otssignange/js/theme.js | 183 ++++- custom/otssignange/views/about-page.twig | 91 +++ custom/otssignange/views/about-text.twig | 55 ++ custom/otssignange/views/authed-sidebar.twig | 685 +++++++++-------- custom/otssignange/views/authed.twig | 135 ++++ custom/otssignange/views/campaign-page.twig | 186 +++++ custom/otssignange/views/command-page.twig | 162 ++++ .../views/dashboard-status-page.twig | 412 ++++++++--- custom/otssignange/views/dataset-page.twig | 599 +++++++++++++++ custom/otssignange/views/daypart-page.twig | 261 +++++++ custom/otssignange/views/display-page.twig | 9 +- .../otssignange/views/displaygroup-page.twig | 381 ++++++++++ .../views/displayprofile-page.twig | 168 +++++ custom/otssignange/views/inline.twig | 327 ++++++++ custom/otssignange/views/layout-page.twig | 536 ++++++++++++++ custom/otssignange/views/library-page.twig | 576 +++++++++++++++ custom/otssignange/views/menuboard-page.twig | 198 +++++ custom/otssignange/views/override-styles.twig | 301 ++++++-- .../views/playersoftware-page.twig | 198 +++++ custom/otssignange/views/playlist-page.twig | 554 ++++++++++++++ custom/otssignange/views/resolution-page.twig | 133 ++++ custom/otssignange/views/schedule-page.twig | 355 +++++++++ custom/otssignange/views/syncgroup-page.twig | 190 +++++ custom/otssignange/views/template-page.twig | 293 ++++++++ .../views/theme-dashboard-message.twig | 5 +- custom/otssignange/views/theme-scripts.twig | 7 +- tmp/xibo-campaign-page.twig | 173 +++++ tmp/xibo-context-menu.twig | 1 + tmp/xibo-dataset-page.twig | 584 +++++++++++++++ tmp/xibo-daypart-page.twig | 248 +++++++ tmp/xibo-layout-page.twig | 523 +++++++++++++ tmp/xibo-menuboard-page.twig | 194 +++++ tmp/xibo-resolution-page.twig | 120 +++ tmp/xibo-schedule-page.twig | 342 +++++++++ tmp/xibo-table-context-menu.twig | 1 + tmp/xibo-template-page-new.twig | 277 +++++++ tmp/xibo-template-page.twig | 277 +++++++ 39 files changed, 10115 insertions(+), 602 deletions(-) create mode 100644 custom/otssignange/views/about-page.twig create mode 100644 custom/otssignange/views/about-text.twig create mode 100644 custom/otssignange/views/authed.twig create mode 100644 custom/otssignange/views/campaign-page.twig create mode 100644 custom/otssignange/views/command-page.twig create mode 100644 custom/otssignange/views/dataset-page.twig create mode 100644 custom/otssignange/views/daypart-page.twig create mode 100644 custom/otssignange/views/displaygroup-page.twig create mode 100644 custom/otssignange/views/displayprofile-page.twig create mode 100644 custom/otssignange/views/inline.twig create mode 100644 custom/otssignange/views/layout-page.twig create mode 100644 custom/otssignange/views/library-page.twig create mode 100644 custom/otssignange/views/menuboard-page.twig create mode 100644 custom/otssignange/views/playersoftware-page.twig create mode 100644 custom/otssignange/views/playlist-page.twig create mode 100644 custom/otssignange/views/resolution-page.twig create mode 100644 custom/otssignange/views/schedule-page.twig create mode 100644 custom/otssignange/views/syncgroup-page.twig create mode 100644 custom/otssignange/views/template-page.twig create mode 100644 tmp/xibo-campaign-page.twig create mode 100644 tmp/xibo-context-menu.twig create mode 100644 tmp/xibo-dataset-page.twig create mode 100644 tmp/xibo-daypart-page.twig create mode 100644 tmp/xibo-layout-page.twig create mode 100644 tmp/xibo-menuboard-page.twig create mode 100644 tmp/xibo-resolution-page.twig create mode 100644 tmp/xibo-schedule-page.twig create mode 100644 tmp/xibo-table-context-menu.twig create mode 100644 tmp/xibo-template-page-new.twig create mode 100644 tmp/xibo-template-page.twig diff --git a/custom/otssignange/css/override-dark.css b/custom/otssignange/css/override-dark.css index 2cc43b8..29b5414 100644 --- a/custom/otssignange/css/override-dark.css +++ b/custom/otssignange/css/override-dark.css @@ -187,68 +187,274 @@ hr { #sidebar-wrapper { background: var(--ots-surface); border-right: 1px solid var(--ots-border); + display: flex; + flex-direction: column; + height: 100vh; + overflow: hidden; } /* OTS sidebar override marker */ .ots-sidebar-wrapper { - box-shadow: inset 0 0 0 1px rgba(79, 140, 255, 0.2); + display: flex; + flex-direction: column; + height: 100vh; + background: var(--ots-surface); } -.ots-sidebar .sidebar-list a, -.ots-sidebar .sidebar-main a { +/* Sidebar Header */ +.ots-sidebar-header { display: flex; align-items: center; - gap: 10px; + gap: 12px; + padding: 16px; + border-bottom: 1px solid var(--ots-border); + background: var(--ots-surface); } +.ots-brand-logo { + width: 40px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + background: rgba(79, 140, 255, 0.15); + border: 1px solid rgba(79, 140, 255, 0.3); + border-radius: 6px; + font-size: 18px; + color: var(--ots-primary); + flex-shrink: 0; +} + +.ots-brand-text { + flex: 1; + min-width: 0; +} + +.ots-brand-name { + display: block; + font-size: 14px; + font-weight: 600; + color: var(--ots-text); + letter-spacing: 0.5px; +} + +.ots-sidebar-close { + background: none; + border: none; + color: var(--ots-text-secondary); + cursor: pointer; + padding: 4px; + display: flex; + align-items: center; + justify-content: center; + transition: color var(--ots-transition); + flex-shrink: 0; +} + +.ots-sidebar-close:hover { + color: var(--ots-text); +} + +/* Sidebar Content */ +.ots-sidebar { + flex: 1; + list-style: none; + margin: 0; + padding: 12px 0; + overflow-y: auto; + overflow-x: hidden; +} + +.ots-sidebar li { + margin: 0; + padding: 0; +} + +/* Sidebar Main Item */ +.ots-sidebar li.sidebar-main > a { + display: flex; + align-items: center; + gap: 12px; + margin: 0 8px; + padding: 10px 12px; + border-radius: 6px; + color: var(--ots-text); + text-decoration: none; + transition: background var(--ots-transition), color var(--ots-transition); + font-size: 14px; + font-weight: 500; +} + +.ots-sidebar li.sidebar-main > a:hover { + background: rgba(79, 140, 255, 0.12); + color: var(--ots-primary); +} + +.ots-sidebar li.sidebar-main > a.active { + background: rgba(79, 140, 255, 0.2); + color: var(--ots-primary); +} + +/* Sidebar Section (Collapsible) */ +.ots-sidebar li.sidebar-section > a.sidebar-section-toggle { + display: flex; + align-items: center; + gap: 12px; + margin: 0 8px; + padding: 10px 12px; + border-radius: 6px; + color: var(--ots-text); + text-decoration: none; + transition: background var(--ots-transition), color var(--ots-transition); + font-size: 14px; + font-weight: 500; + cursor: pointer; + background: none; + border: none; + text-align: left; + width: calc(100% - 16px); +} + +.ots-sidebar li.sidebar-section > a.sidebar-section-toggle:hover { + background: rgba(79, 140, 255, 0.12); + color: var(--ots-primary); +} + +.ots-sidebar li.sidebar-section > a.sidebar-section-toggle.active { + background: rgba(79, 140, 255, 0.12); + color: var(--ots-primary); +} + +.ots-section-toggle-icon { + margin-left: auto; + font-size: 12px; + transition: transform var(--ots-transition); +} + +.ots-sidebar li.sidebar-section > a.sidebar-section-toggle.active .ots-section-toggle-icon { + transform: rotate(180deg); +} + +/* Sidebar Subsection */ +.ots-sidebar .sidebar-subsection { + list-style: none; + margin: 0; + padding: 4px 0; + display: none; + background: rgba(79, 140, 255, 0.05); +} + +.ots-sidebar .sidebar-subsection.active { + display: block; +} + +.ots-sidebar .sidebar-subsection li { + margin: 0; + padding: 0; +} + +/* Sidebar List Item */ +.ots-sidebar li.sidebar-list > a { + display: flex; + align-items: center; + gap: 12px; + margin: 2px 12px 2px 28px; + padding: 8px 12px; + border-radius: 4px; + color: var(--ots-text-secondary); + text-decoration: none; + transition: background var(--ots-transition), color var(--ots-transition); + font-size: 13px; +} + +.ots-sidebar li.sidebar-list > a:hover { + background: rgba(79, 140, 255, 0.12); + color: var(--ots-primary); +} + +.ots-sidebar li.sidebar-list > a.active { + background: rgba(79, 140, 255, 0.15); + color: var(--ots-primary); +} + +/* Navigation Icons and Text */ .ots-nav-icon { - width: 18px; + width: 16px; + height: 16px; + display: flex; + align-items: center; + justify-content: center; text-align: center; opacity: 0.85; font-size: 14px; + flex-shrink: 0; } .ots-nav-text { flex: 1; min-width: 0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } -/* Xibo sidebar refinements (dark) */ -#sidebar-wrapper .sidebar-title a { - color: var(--ots-text-faint); +/* Sidebar Spacer */ +.sidebar-spacer { + height: 12px; + margin-top: auto; +} + +/* Sidebar Footer */ +.ots-sidebar-footer { + display: flex; + align-items: center; + gap: 12px; + padding: 12px 16px; + border-top: 1px solid var(--ots-border); + background: var(--ots-surface); +} + +.ots-user-section { + flex: 1; + min-width: 0; +} + +.ots-user-role { font-size: 11px; - letter-spacing: 0.08em; + color: var(--ots-text-secondary); text-transform: uppercase; - padding: 12px 16px 6px; + letter-spacing: 0.5px; + margin-bottom: 2px; } -#sidebar-wrapper .sidebar-list a, -#sidebar-wrapper .sidebar-main a { - display: block; - margin: 2px 8px; - padding: 10px 12px; - border-radius: var(--ots-radius-sm); +.ots-user-name { + font-size: 13px; + font-weight: 500; + color: var(--ots-text); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.ots-user-profile-link { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + border-radius: 4px; + color: var(--ots-text-secondary); + text-decoration: none; transition: background var(--ots-transition), color var(--ots-transition); + font-size: 16px; + flex-shrink: 0; } -#sidebar-wrapper .sidebar-list a:hover, -#sidebar-wrapper .sidebar-main a:hover { +.ots-user-profile-link:hover { background: rgba(79, 140, 255, 0.12); color: var(--ots-primary); } -#sidebar-wrapper .sidebar { - padding: 14px 0; -} - -#sidebar-wrapper .sidebar-main a, -#sidebar-wrapper .sidebar-list a { - display: block; - padding: 10px 18px; - color: var(--ots-text); - border-left: 3px solid transparent; -} - #sidebar-wrapper .sidebar-main a:hover, #sidebar-wrapper .sidebar-list a:hover { background: rgba(79, 140, 255, 0.12); @@ -534,6 +740,22 @@ textarea:focus { .modal-content { border-radius: var(--ots-radius-lg); + background-color: var(--ots-surface-2) !important; +} + +.modal, +.modal-header, +.modal-body, +.modal-footer { + background-color: transparent !important; +} + +.modal-backdrop, +.modal-backdrop.show, +.modal-backdrop.in { + background-color: rgba(0, 0, 0, 0.3) !important; + backdrop-filter: blur(4px) !important; + opacity: 1 !important; } .modal-footer { diff --git a/custom/otssignange/css/override.css b/custom/otssignange/css/override.css index a933705..ad0d92e 100644 --- a/custom/otssignange/css/override.css +++ b/custom/otssignange/css/override.css @@ -55,8 +55,8 @@ body { padding: 0; display: flex; flex-direction: column; - overflow-y: auto; - z-index: 1000; + overflow: hidden; + z-index: 1200; } .ots-main { @@ -66,6 +66,11 @@ body { margin-left: 260px; } +.ots-main, +#page-wrapper { + position: relative; +} + .ots-content { flex: 1; padding: 32px; @@ -106,12 +111,13 @@ body { ============================================================================ */ .sidebar-header { - padding: 20px 16px; + padding: 18px 16px; border-bottom: 1px solid var(--color-border); display: flex; align-items: center; justify-content: space-between; gap: 12px; + flex-shrink: 0; } .brand-link { @@ -139,16 +145,18 @@ body { flex: 1; padding: 12px 0; overflow-y: auto; + min-height: 0; } .sidebar-nav { list-style: none; margin: 0; - padding: 12px 0 120px; + padding: 12px 0 140px; } .sidebar-nav li { display: block; + margin-top: 6px; } /* Compatibility: Xibo sidebar markup uses `sidebar-list`, `sidebar-main`, `sidebar-title`. @@ -157,10 +165,9 @@ body { .ots-sidebar li.sidebar-list > a, .ots-sidebar li.sidebar-main > a, .ots-sidebar li.sidebar-title > a { - display: grid; - grid-template-columns: 20px 1fr; + display: flex; align-items: center; - column-gap: 12px; + gap: 12px; padding: 8px 12px; color: #c8d5ee; text-decoration: none; @@ -171,7 +178,7 @@ body { border-left: 2px solid transparent; margin: 3px 10px; border-radius: 12px; - min-height: 40px; + min-height: 48px; line-height: 1.25; } @@ -192,15 +199,15 @@ body { } .ots-sidebar .ots-nav-icon { - width: 24px; - height: 24px; - display: flex; + width: 28px; + height: 28px; + display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; font-size: 16px; color: currentColor; - justify-self: center; + margin-left: 0; } .ots-sidebar .ots-nav-text { @@ -210,6 +217,11 @@ body { line-height: 1.2; } +.sidebar-group-toggle .ots-nav-icon, +.ots-sidebar-nav .ots-nav-icon { + justify-self: start; +} + .ots-sidebar li.sidebar-title > a { display: block; font-size: 10px; @@ -223,6 +235,181 @@ body { line-height: 1; } +.brand-logo { + width: 32px; + height: 32px; + object-fit: contain; +} + +.brand-text { + color: var(--color-text-primary); + font-size: 18px; + font-weight: 600; + letter-spacing: 0.02em; +} + +.sidebar-header { + padding: 18px 16px; + border-bottom: 1px solid rgba(255, 255, 255, 0.08); + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + flex-shrink: 0; + height: 72px; + box-sizing: border-box; + position: sticky; + top: 0; + background: #08132a; + z-index: 1210; +} + +.sidebar-collapse-btn { + width: 32px; + height: 32px; + border-radius: 8px; + border: 0; + background: rgba(255, 255, 255, 0.08); + color: #d7e2f8; + display: inline-flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all var(--transition-fast); +} + +.sidebar-collapse-btn:hover { + background: rgba(255, 255, 255, 0.16); + color: #ffffff; +} + +.ots-sidebar.collapsed { + width: 88px; +} + +.ots-sidebar.collapsed .brand-text, +.ots-sidebar.collapsed .sidebar-group-toggle .ots-nav-text, +.ots-sidebar.collapsed .sidebar-list .ots-nav-text, +.ots-sidebar.collapsed .sidebar-submenu, +.ots-sidebar.collapsed .sidebar-group-caret, +.ots-sidebar.collapsed .user-details { + display: none !important; +} + +.ots-sidebar.collapsed .sidebar-group-toggle, +.ots-sidebar.collapsed .sidebar-list > a { + justify-content: center; + padding: 10px; +} + +/* Center icons when collapsed */ +.ots-sidebar.collapsed .ots-nav-icon { + justify-self: center !important; + margin-left: 0 !important; +} + +.ots-sidebar-collapsed #page-wrapper, +.ots-sidebar-collapsed .ots-main { + margin-left: 88px !important; +} + +.ots-sidebar-nav { + padding: 12px 0 140px; + padding-top: 8px; +} + +.sidebar-group { + margin-top: 6px; +} + +.sidebar-group-toggle { + display: flex; + align-items: center; + gap: 12px; + padding: 10px 12px; + margin: 6px 10px; + border-radius: 12px; + color: #d7e2f8; + text-decoration: none; + background: rgba(255, 255, 255, 0.03); + transition: all var(--transition-fast); +} + +.sidebar-group-toggle:hover { + background: rgba(255, 255, 255, 0.08); + color: #ffffff; +} + +.sidebar-group-caret { + margin-left: auto; + font-size: 12px; + opacity: 0.8; +} + +.sidebar-submenu { + list-style: none; + margin: 4px 0 8px; + padding: 0 0 0 12px; + border-left: 1px solid rgba(255, 255, 255, 0.08); +} + +.sidebar-group.is-open .sidebar-group-caret { + transform: rotate(180deg); +} + +.sidebar-submenu .sidebar-list > a { + margin: 4px 10px 4px 18px; + background: rgba(255, 255, 255, 0.04); +} + +.sidebar-submenu .sidebar-list > a:hover { + background: rgba(255, 255, 255, 0.1); +} + +.sidebar-submenu .sidebar-list.active > a, +.sidebar-submenu .sidebar-list > a.active { + color: #0b1221; + background-color: #ffffff; + box-shadow: 0 8px 18px rgba(15, 23, 42, 0.25); +} + +.sidebar-footer { + border-top: 1px solid rgba(255, 255, 255, 0.08); + padding: 16px; + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + background-color: rgba(15, 23, 42, 0.6); +} + +.sidebar-theme-toggle { + width: 36px; + height: 36px; + border-radius: 10px; + border: 0; + background: rgba(255, 255, 255, 0.08); + color: #ffffff; + display: inline-flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all var(--transition-fast); +} + +.sidebar-theme-toggle:hover { + background: rgba(255, 255, 255, 0.16); +} + +.user-role { + display: inline-flex; + align-items: center; + gap: 8px; + font-size: 12px; + color: var(--color-text-secondary); + margin-bottom: 4px; +} + .nav-section-divider { padding: 12px 16px 8px; margin-top: 8px; @@ -299,6 +486,7 @@ body { border-top: 1px solid var(--color-border); padding: 16px; background-color: rgba(59, 130, 246, 0.05); + flex-shrink: 0; } .sidebar-user { @@ -353,7 +541,6 @@ body { .ots-topbar { background-color: var(--color-surface-elevated); - border-bottom: 2px solid var(--color-border); padding: 10px 32px; display: flex; align-items: center; @@ -395,10 +582,13 @@ body { white-space: nowrap; transition: all var(--transition-fast); position: relative; + border: 0 !important; + background: transparent !important; + box-shadow: none !important; } .ots-topbar .nav-link:hover { - background-color: rgba(59, 130, 246, 0.08); + background-color: rgba(59, 130, 246, 0.06); color: var(--color-primary); } @@ -430,8 +620,8 @@ body { border-radius: 8px; padding: 6px 0; margin-top: 4px; - box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); - border: 1px solid var(--color-border); + box-shadow: none; + border: 0 !important; background-color: var(--color-surface); min-width: 180px; z-index: 1100; @@ -688,6 +878,99 @@ body { overflow: hidden; } +/* Make DataTables button collections compatible with OTS dropdown styling */ +.dt-buttons { + position: relative; + display: inline-block; +} + +.dt-button-collection { + position: absolute; + top: 100%; + right: 0; + margin-top: 6px; + display: none; + z-index: 1002; + min-width: 160px; + background-color: var(--color-surface-elevated); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 8px; + box-shadow: 0 20px 45px rgba(0, 0, 0, 0.3); + overflow: hidden; + padding: 6px 0; +} + +.dt-buttons.active .dt-button-collection, +.dt-button-collection.active, +.dt-button-collection.show { + display: block; + animation: slideDown 150ms ease-out; +} + +/* Ensure collection items are visible and styled */ +.dt-button-collection .dt-button, +.dt-button-collection button, +.dt-button-collection a { + display: block; + width: 100%; + padding: 6px 12px; + color: var(--color-text-primary); + background: transparent; + text-decoration: none; + font-size: 13px; + text-align: left; + border: none; +} + +.dt-button-collection .dt-button:hover, +.dt-button-collection a:hover, +.dt-button-collection button:hover { + background-color: rgba(59, 130, 246, 0.06); + color: var(--color-primary); +} + +.dt-button-collection input[type="checkbox"] { + margin-right: 8px; + vertical-align: middle; +} + +.dt-button-collection .dt-button:focus, +.dt-button-collection a:focus, +.dt-button-collection button:focus { + outline: none; + box-shadow: none; +} + +/* DataTables sometimes nests a `div.dropdown-menu` inside the collection. + Ensure that inner dropdown-menu is visible when the collection is shown. */ +.dt-button-collection .dropdown-menu { + display: block !important; + position: static !important; + background: transparent !important; + border: none !important; + box-shadow: none !important; + padding: 0 !important; + min-width: 160px !important; +} + +.dt-button-collection .dropdown-menu .dropdown-item, +.dt-button-collection .dropdown-menu a, +.dt-button-collection .dropdown-menu .dt-button { + display: block !important; + padding: 6px 12px !important; + color: var(--color-text-primary) !important; + text-decoration: none !important; + background: transparent !important; + text-align: left !important; +} + +.dt-button-collection .dropdown-menu .dropdown-item:hover, +.dt-button-collection .dropdown-menu a:hover, +.dt-button-collection .dropdown-menu .dt-button:hover { + background-color: rgba(59, 130, 246, 0.06) !important; + color: var(--color-primary) !important; +} + .dropdown.active .dropdown-menu, .dropdown:focus-within .dropdown-menu { display: block; @@ -995,90 +1278,138 @@ body { background: linear-gradient(180deg, rgba(59, 130, 246, 0.06), rgba(59, 130, 246, 0.02)); border: 1px solid rgba(59, 130, 246, 0.18); box-shadow: 0 12px 26px rgba(8, 15, 30, 0.35); - display: flex; - flex-direction: column; - min-height: 360px; - align-items: stretch; + display: flex !important; + flex-direction: column !important; + min-height: 380px; + height: 380px; + align-items: stretch !important; + overflow: visible !important; +} + +.dashboard-chart-card > * { + width: 100% !important; + float: none !important; + clear: both !important; } .dashboard-chart-header { - display: flex; - justify-content: space-between; - align-items: center; - gap: 16px; - width: 100%; - box-sizing: border-box; - float: none; - flex-wrap: wrap; + display: flex !important; + flex-direction: column !important; + gap: 10px !important; + align-items: flex-start !important; + padding: 12px 16px !important; + box-sizing: border-box !important; + width: 100% !important; + background: transparent !important; + border: none !important; + float: none !important; + clear: both !important; position: static !important; inset: auto !important; + overflow: visible !important; + height: auto !important; + max-width: none !important; + flex: 0 0 auto !important; } -.dashboard-chart-card .widget-title, -.dashboard-chart-card .widget-body { - width: 100%; - float: none !important; - clear: both; - display: block !important; - position: static !important; +.panel .dashboard-chart-header { + padding: 12px 20px !important; } -.dashboard-chart-card .widget-title { - flex: 0 0 auto; -} - -.dashboard-chart-card .widget-body { - position: relative !important; -} - -.dashboard-chart-title { - display: flex; - align-items: center; - gap: 12px; +.dashboard-chart-info { + display: flex !important; + align-items: center !important; + gap: 10px !important; + flex: 0 0 auto !important; + min-width: 0 !important; } .dashboard-chart-icon { - width: 40px; - height: 40px; - border-radius: 12px; - background: rgba(59, 130, 246, 0.18); - color: var(--color-primary-light); - display: inline-flex; - align-items: center; - justify-content: center; - font-size: 18px; - flex-shrink: 0; + width: 32px !important; + height: 32px !important; + border-radius: 10px !important; + background: rgba(59, 130, 246, 0.18) !important; + color: var(--color-primary-light) !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + font-size: 16px !important; + flex-shrink: 0 !important; + border: none !important; + padding: 0 !important; + margin: 0 !important; +} + +.dashboard-chart-meta { + display: flex !important; + flex-direction: column !important; + gap: 2px !important; + flex-shrink: 0 !important; } .dashboard-chart-heading { margin: 0; - font-size: 16px; + font-size: 15px; font-weight: 700; + line-height: 1.2; } .dashboard-chart-subtitle { - margin: 4px 0 0; - font-size: 12px; + margin: 0; + font-size: 11px; color: var(--color-text-secondary); + line-height: 1.2; } -.dashboard-chart-link { +.dashboard-chart-actions { + display: flex !important; + align-items: center !important; + gap: 12px !important; + width: 100% !important; + flex-shrink: 0 !important; + padding: 0 !important; + border: none !important; +} + +.dashboard-chart-toggle { + display: inline-flex; + align-items: center; + gap: 4px; + padding: 4px; + border-radius: 999px; + background: rgba(15, 23, 42, 0.45); +} + +.dashboard-chart-toggle-button { + border: none; + background: transparent; + color: var(--color-text-secondary); font-size: 12px; font-weight: 600; - color: var(--color-primary); - text-decoration: none; - padding: 6px 10px; + width: 40px; + height: 34px; + padding: 0; border-radius: 999px; - border: 1px solid rgba(59, 130, 246, 0.24); - background: rgba(59, 130, 246, 0.12); - transition: all var(--transition-fast); - white-space: nowrap; + cursor: pointer; + transition: all 150ms ease; + display: inline-flex; + align-items: center; + justify-content: center; } -.dashboard-chart-link:hover { +.dashboard-chart-toggle-button:hover { color: var(--color-text-primary); - border-color: rgba(59, 130, 246, 0.5); +} + +.dashboard-chart-toggle-button.is-active { background: rgba(59, 130, 246, 0.22); + color: var(--color-text-primary); +} + +.dashboard-chart-toggle-button i { + font-size: 16px; + line-height: 1; + display: inline-block; } .dashboard-chart-body { @@ -1097,11 +1428,12 @@ body { border: 1px solid rgba(255, 255, 255, 0.05); border-radius: 12px; padding: 12px; - height: clamp(220px, 32vh, 280px); + height: 200px; width: 100%; position: relative; overflow: hidden; flex: 1; + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.2); } .dashboard-chart-canvas canvas { @@ -1118,6 +1450,103 @@ body { min-height: 0 !important; } +/* Enhanced chart container styling */ +.dashboard-chart-card { + transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1) !important; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important; +} + +.dashboard-chart-card:hover { + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25) !important; + transform: translateY(-2px); +} + +/* Chart action improvements */ +.dashboard-chart-actions { + gap: 16px !important; +} + +.dashboard-chart-link { + font-size: 13px; + font-weight: 500; + color: var(--color-primary-light); + text-decoration: none; + white-space: nowrap; + transition: all 150ms ease; + padding: 4px 8px; + border-radius: 6px; + display: inline-block; +} + +.dashboard-chart-link:hover { + color: var(--color-primary); + background: rgba(59, 130, 246, 0.1); +} + +/* Modern toggle improvements */ +.dashboard-chart-toggle { + background: rgba(15, 23, 42, 0.6); + border: 1px solid rgba(59, 130, 246, 0.2); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +} + +.dashboard-chart-toggle-button { + transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1); + border: 1px solid transparent; +} + +.dashboard-chart-toggle-button:hover { + background: rgba(59, 130, 246, 0.12); + border-color: rgba(59, 130, 246, 0.2); +} + +.dashboard-chart-toggle-button.is-active { + background: linear-gradient(135deg, rgba(59, 130, 246, 0.3), rgba(59, 130, 246, 0.2)); + border-color: rgba(59, 130, 246, 0.3); + box-shadow: 0 0 12px rgba(59, 130, 246, 0.2); +} + +.dashboard-chart-toggle-button i { + transition: transform 200ms ease; +} + +.dashboard-chart-toggle-button:hover i { + transform: scale(1.15); +} + +/* Responsive chart cards */ +@media (max-width: 1200px) { + .dashboard-chart-canvas { + height: 180px; + } +} + +@media (max-width: 768px) { + .dashboard-chart-card { + max-height: none; + } + + .dashboard-chart-header { + flex-direction: row !important; + justify-content: space-between !important; + align-items: center !important; + gap: 12px !important; + } + + .dashboard-chart-info { + flex: 1; + min-width: 0; + } + + .dashboard-chart-actions { + flex-shrink: 0; + } + + .dashboard-chart-canvas { + height: 200px; + } +} + .panel { background-color: var(--color-surface); border: 1px solid var(--color-border); @@ -1329,8 +1758,8 @@ body .panel .panel-heading, align-items: center; justify-content: space-between; padding: 14px 16px; - border-bottom: 1px solid rgba(148, 163, 184, 0.2); - background: rgba(15, 23, 42, 0.3); + border-bottom: none; + background: transparent; } .ots-filter-title { @@ -1362,15 +1791,19 @@ body .panel .panel-heading, .ots-filter-content { padding: 16px; - max-height: 600px; - overflow: hidden; + max-height: none; + min-height: auto; + overflow: visible; transition: max-height 300ms ease-out, padding 300ms ease-out; + display: block; } .ots-filter-content.collapsed { max-height: 0; + min-height: 0; padding: 0 16px; overflow: hidden; + display: none; } .ots-filter-card .nav-tabs { @@ -1936,6 +2369,58 @@ body .panel .panel-heading, color: var(--color-text-primary); } +/* Minimal Icon-Only Buttons */ +.btn-icon { + width: 40px !important; + height: 40px !important; + padding: 0 !important; + border-radius: 8px !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + background-color: var(--color-surface-elevated) !important; + border: 1px solid var(--color-border) !important; + color: var(--color-text-secondary) !important; + font-size: 0 !important; + transition: all 150ms cubic-bezier(0.4, 0, 0.2, 1) !important; + cursor: pointer !important; + position: relative !important; + margin-left: 6px !important; + flex-shrink: 0 !important; +} + +.btn-icon:hover { + background-color: rgba(59, 130, 246, 0.12) !important; + border-color: rgba(59, 130, 246, 0.3) !important; + color: var(--color-primary-light) !important; + box-shadow: 0 2px 8px rgba(59, 130, 246, 0.1) !important; +} + +.btn-icon:active { + background-color: rgba(59, 130, 246, 0.2) !important; + border-color: rgba(59, 130, 246, 0.4) !important; + transform: scale(0.95); +} + +.btn-icon i, +.btn-icon svg { + font-size: 17px !important; + line-height: 1 !important; + display: inline-block !important; +} + +.btn-icon.btn-success { + background-color: rgba(34, 197, 94, 0.08) !important; + border-color: rgba(34, 197, 94, 0.2) !important; + color: rgb(34, 197, 94) !important; +} + +.btn-icon.btn-success:hover { + background-color: rgba(34, 197, 94, 0.15) !important; + border-color: rgba(34, 197, 94, 0.4) !important; + box-shadow: 0 2px 8px rgba(34, 197, 94, 0.1) !important; +} + /* ============================================================================ UTILITY CLASSES ============================================================================ */ @@ -2083,7 +2568,9 @@ canvas { #sidebar-wrapper .sidebar-list a, #sidebar-wrapper .sidebar-main a { - display: block; + display: flex; + align-items: center; + gap: 12px; margin: 2px 8px; padding: 10px 12px; border-radius: 8px; @@ -2383,17 +2870,34 @@ legend { /* Dropdowns, modals, and popovers */ .dropdown-menu, .dropdown-toggle, -.popover, -.modal, -.modal-content, -.modal-header, -.modal-body, -.modal-footer { +.popover { background-color: var(--color-surface) !important; color: var(--color-text-primary) !important; border: 1px solid var(--color-border) !important; } +.modal, +.modal-body, +.modal-footer { + background-color: transparent !important; + color: var(--color-text-primary) !important; + border: 1px solid var(--color-border) !important; +} + +.modal-content { + background-color: var(--color-surface) !important; + color: var(--color-text-primary) !important; + border: 1px solid var(--color-border) !important; +} + +.modal-backdrop, +.modal-backdrop.show, +.modal-backdrop.in { + background-color: rgba(0, 0, 0, 0.3) !important; + backdrop-filter: blur(4px) !important; + opacity: 1 !important; +} + .modal-header { background-color: var(--color-surface-elevated) !important; border-bottom: 1px solid var(--color-border) !important; @@ -2666,3 +3170,30 @@ a.text-muted:hover { .invisible { visibility: hidden !important; } + +/* ============================================================================ + FILTER FIELDS PADDING + ============================================================================ */ + +.FilterDiv.card-body { + padding-top: 20px !important; +} +/* ============================================================================ + LOGO WITH TEXT STYLING + ============================================================================ */ + +.navbar-brand.xibo-logo-container { + display: flex; + align-items: center; + gap: 12px; + padding: 0; + margin-right: 16px; +} + +.xibo-logo-text { + color: var(--color-text-primary); + font-size: 18px; + font-weight: 600; + margin: 0; + white-space: nowrap; +} \ No newline at end of file diff --git a/custom/otssignange/js/theme.js b/custom/otssignange/js/theme.js index c9a5e3f..effed8e 100644 --- a/custom/otssignange/js/theme.js +++ b/custom/otssignange/js/theme.js @@ -16,19 +16,51 @@ function initSidebarToggle() { const toggleBtn = document.querySelector('[data-action="toggle-sidebar"]'); const sidebar = document.querySelector('.ots-sidebar'); + const closeBtn = document.querySelector('.ots-sidebar-close'); + const collapseBtn = document.querySelector('.sidebar-collapse-btn'); + const body = document.body; - if (!toggleBtn || !sidebar) return; + if (!sidebar) return; - toggleBtn.addEventListener('click', function(e) { - e.preventDefault(); - sidebar.classList.toggle('active'); - }); + // Handle sidebar close button + if (closeBtn) { + closeBtn.addEventListener('click', function(e) { + e.preventDefault(); + sidebar.classList.remove('active'); + }); + } + + if (toggleBtn) { + toggleBtn.addEventListener('click', function(e) { + e.preventDefault(); + sidebar.classList.toggle('active'); + }); + } + + if (collapseBtn) { + const isCollapsed = localStorage.getItem(STORAGE_KEYS.sidebarCollapsed) === 'true'; + if (isCollapsed) { + sidebar.classList.add('collapsed'); + body.classList.add('ots-sidebar-collapsed'); + } + + collapseBtn.addEventListener('click', function(e) { + e.preventDefault(); + const nowCollapsed = !sidebar.classList.contains('collapsed'); + sidebar.classList.toggle('collapsed'); + body.classList.toggle('ots-sidebar-collapsed', nowCollapsed); + localStorage.setItem(STORAGE_KEYS.sidebarCollapsed, nowCollapsed ? 'true' : 'false'); + }); + } + + // Initialize sidebar section toggles + initSidebarSectionToggles(); // Close sidebar when clicking outside on mobile document.addEventListener('click', function(e) { if (window.innerWidth <= 768) { const isClickInsideSidebar = sidebar.contains(e.target); - const isClickOnToggle = toggleBtn.contains(e.target); + const isClickOnToggle = toggleBtn && toggleBtn.contains(e.target); if (!isClickInsideSidebar && !isClickOnToggle && sidebar.classList.contains('active')) { sidebar.classList.remove('active'); @@ -37,27 +69,47 @@ }); } + /** + * Initialize sidebar section collapse/expand functionality + */ + function initSidebarSectionToggles() { + const groupToggles = document.querySelectorAll('.sidebar-group-toggle'); + + groupToggles.forEach(toggle => { + toggle.addEventListener('click', function(e) { + e.preventDefault(); + + const group = toggle.closest('.sidebar-group'); + const submenu = group ? group.querySelector('.sidebar-submenu') : null; + if (!submenu) return; + + const isOpen = group.classList.contains('is-open'); + group.classList.toggle('is-open', !isOpen); + toggle.setAttribute('aria-expanded', (!isOpen).toString()); + submenu.style.display = isOpen ? 'none' : 'block'; + }); + }); + } + /** * Initialize dropdown menus */ function initDropdowns() { const dropdowns = document.querySelectorAll('.dropdown'); - + dropdowns.forEach(dropdown => { - const button = dropdown.querySelector('.dropdown-menu'); - - if (!button) return; - + const toggle = dropdown.querySelector('.dropdown-toggle, [data-toggle="dropdown"], .dt-button'); const menu = dropdown.querySelector('.dropdown-menu'); - - // Toggle menu on button click - dropdown.addEventListener('click', function(e) { - if (e.target.closest('.user-btn') || e.target.closest('[aria-label="User menu"]')) { - e.preventDefault(); - dropdown.classList.toggle('active'); - } + + if (!toggle || !menu) return; + + // Toggle menu on toggle click + toggle.addEventListener('click', function(e) { + e.preventDefault(); + e.stopPropagation(); + dropdown.classList.toggle('active'); }); - + // Close menu when clicking outside document.addEventListener('click', function(e) { if (!dropdown.contains(e.target)) { @@ -65,6 +117,99 @@ } }); }); + // Support DataTables Buttons collections which are not wrapped by .dropdown + document.addEventListener('click', function(e) { + const btn = e.target.closest('.dt-button'); + + if (btn) { + e.preventDefault(); + e.stopPropagation(); + + const wrapper = btn.closest('.dt-buttons') || btn.parentElement; + + // close other open dt-buttons collections + document.querySelectorAll('.dt-buttons.active').forEach(w => { + if (w !== wrapper) w.classList.remove('active'); + }); + + wrapper.classList.toggle('active'); + + // If DataTables placed the collection on the body, find it and position it under the clicked button + const allCollections = Array.from(document.querySelectorAll('.dt-button-collection')); + let collection = wrapper.querySelector('.dt-button-collection') || allCollections.find(c => !wrapper.contains(c)); + + // If DataTables didn't create a collection element, create one as a fallback + if (!collection) { + collection = document.createElement('div'); + collection.className = 'dt-button-collection'; + // prefer to append near wrapper for positioning; fallback to body + (wrapper || document.body).appendChild(collection); + } + + if (collection) { + // hide other collections + allCollections.forEach(c => { if (c !== collection) { c.classList.remove('show'); c.style.display = 'none'; } }); + + const rect = btn.getBoundingClientRect(); + const top = rect.bottom + window.scrollY; + const left = rect.left + window.scrollX; + + collection.style.position = 'absolute'; + collection.style.top = `${top}px`; + collection.style.left = `${left}px`; + collection.style.display = 'block'; + collection.classList.add('show'); + // DEBUG: log collection contents + try { + console.log('dt-button-collection opened, children:', collection.children.length, collection); + } catch (err) {} + + // If the collection is empty or visually empty, build a fallback column list from the nearest table + const isEmpty = collection.children.length === 0 || collection.textContent.trim() === '' || collection.offsetHeight < 10; + if (isEmpty) { + try { + let table = btn.closest('table') || wrapper.querySelector('table') || document.querySelector('table'); + if (table && window.jQuery && jQuery.fn && jQuery.fn.dataTable && jQuery.fn.dataTable.isDataTable(table)) { + const dt = jQuery(table).DataTable(); + // clear existing + collection.innerHTML = ''; + const thead = table.querySelectorAll('thead th'); + thead.forEach((th, idx) => { + const text = (th.textContent || th.innerText || `Column ${idx+1}`).trim(); + const item = document.createElement('div'); + item.style.padding = '6px 12px'; + item.style.display = 'flex'; + item.style.alignItems = 'center'; + item.style.gap = '8px'; + const checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.checked = dt.column(idx).visible(); + checkbox.addEventListener('change', function() { + dt.column(idx).visible(this.checked); + }); + const label = document.createElement('span'); + label.textContent = text; + label.style.color = 'var(--color-text-primary)'; + item.appendChild(checkbox); + item.appendChild(label); + collection.appendChild(item); + }); + console.log('Fallback: populated collection with', collection.children.length, 'items'); + } else { + console.log('Fallback: no DataTable instance found to populate column visibility'); + } + } catch (err) { + console.warn('Error building fallback column list', err); + } + } + } + + return; + } + + // click outside dt-button -> close any open collections + document.querySelectorAll('.dt-buttons.active').forEach(w => w.classList.remove('active')); + }); } /** diff --git a/custom/otssignange/views/about-page.twig b/custom/otssignange/views/about-page.twig new file mode 100644 index 0000000..553e903 --- /dev/null +++ b/custom/otssignange/views/about-page.twig @@ -0,0 +1,91 @@ +{# +/** + * Copyright (C) 2026 OTS Signs + * + * About page for OTS Signs. + */ +#} +{% extends "non-authed.twig" %} + +{% block title %}{{ "About"|trans }} | {% endblock %} + +{% block style %} + +{% endblock %} + +{% block header %}{% endblock %} +{% block contentClass %}{% endblock %} + +{% block content %} + +
+

+ {% trans "About" %} + OTS Signs +

+

+ {% trans "An" %} + Oribi Technology Services + {% trans "product." %} +

+

{% trans "OTS Signs provides a compact, focused admin UI and proxy for Xibo CMS" %}

+ + {% set appVersion = version|default("dev") %} + {% set appEnvironment = appEnvironment|default(environment|default("local")) %} + {% set commitSha = revision|default("") %} + +
+
{% trans "Version" %}: {{ appVersion }}
+
{% trans "Environment" %}: {{ appEnvironment }}
+ {% if commitSha %} +
{% trans "Commit" %}: {{ commitSha|slice(0, 7) }}
+ {% endif %} +
+ + + +
+ {% trans "Disclaimer:" %} + {% trans "OTS Signs is an independent product developed by Oribi Technology Services. It is not affiliated with or endorsed by the Xibo project or its maintainers. Xibo is a trademark of Xibo Digital Signage Ltd. Use of Xibo APIs is subject to their terms and conditions." %} + +
+
+{% endblock %} diff --git a/custom/otssignange/views/about-text.twig b/custom/otssignange/views/about-text.twig new file mode 100644 index 0000000..6caaf0a --- /dev/null +++ b/custom/otssignange/views/about-text.twig @@ -0,0 +1,55 @@ +{# +/** + * Copyright (C) 2026 OTS Signs + * + * About dialog content for OTS Signs. + */ +#} +{% extends "form-base.twig" %} + +{% block formTitle %}{% trans "About" %}{% endblock %} + +{% block formButtons %} + {% trans "Close" %}, XiboDialogClose() +{% endblock %} + +{% block formHtml %} +
+

+ {% trans "About" %} + OTS Signs +

+

+ {% trans "An" %} + Oribi Technology Services + {% trans "product." %} +

+

{% trans "OTS Signs provides a compact, focused interface and hosting for Xibo CMS" %}

+ + {% set appVersion = version|default("dev") %} + {% set appEnvironment = appEnvironment|default(environment|default("local")) %} + {% set commitSha = revision|default("") %} + +
+
{% trans "Version" %}: {{ appVersion }}
+
{% trans "Environment" %}: {{ appEnvironment }}
+ {% if commitSha %} +
{% trans "Commit" %}: {{ commitSha|slice(0, 7) }}
+ {% endif %} +
+ + + +
+ {% trans "Disclaimer:" %} + {% trans "OTS Signs is an independent product developed by Oribi Technology Services. It is not affiliated with or endorsed by the Xibo project or its maintainers. Xibo is a trademark of Xibo Digital Signage Ltd. Use of Xibo APIs is subject to their terms and conditions." %} + +
+
+{% endblock %} diff --git a/custom/otssignange/views/authed-sidebar.twig b/custom/otssignange/views/authed-sidebar.twig index b351ddf..1df8291 100644 --- a/custom/otssignange/views/authed-sidebar.twig +++ b/custom/otssignange/views/authed-sidebar.twig @@ -1,166 +1,220 @@ - + + diff --git a/custom/otssignange/views/authed.twig b/custom/otssignange/views/authed.twig new file mode 100644 index 0000000..9fd9bf5 --- /dev/null +++ b/custom/otssignange/views/authed.twig @@ -0,0 +1,135 @@ +{# +/** + * Copyright (C) 2020-2025 Xibo Signage Ltd + * + * Xibo - Digital Signage - https://xibosignage.com + * + * This file is part of Xibo. + * + * Xibo is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * Xibo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Xibo. If not, see . + */ +#} +{% extends "base.twig" %} + +{% block content %} + {% set horizontalNav = currentUser.getOptionValue("navigationMenuPosition", theme.getSetting("NAVIGATION_MENU_POSITION", "vertical")) == "horizontal" %} + + {% if not hideNavigation %} + {% set hideNavigation = currentUser.getOptionValue("hideNavigation", "0") %} + {% endif %} + +
+ + {% if hideNavigation == "0" and not forceHide %} + {% if horizontalNav %} + + {% else %} + + {% endif %} + {% endif %} + +
+
+ {% if not horizontalNav or hideNavigation == "1" or forceHide %} +
+
+
+
+
+ {% if not forceHide %} + {% if not hideNavigation == "1" %} + + {% endif %} +
+ {% include "authed-user-menu.twig" %} +
+ {% if currentUser.featureEnabled("drawer") %} +
+ {% include "authed-notification-drawer.twig" %} +
+ {% endif %} + {% include "authed-theme-topbar.twig" ignore missing %} + {% endif %} +
+
+ {% endif %} +
+
+ {% block actionMenu %}{% endblock %} + + {% if settings.INSTANCE_SUSPENDED == "partial" %} +
{{ "CMS suspended. Displays will show cached content. Please contact your administrator."|trans }}
+ {% endif %} + + {% block pageContent %}{% endblock %} +
+
+
+
+ {% block pageFooter %}{% endblock %} +
+
+
+
+
+ + {% set helpLinks = helpService.getLinksForPage(route) %} + {% set faultViewEnabled = currentUser.featureEnabled("fault.view") %} + + {# Hide in mobile view (sm/<768px) #} +
+ +
+ +
+
+{% endblock %} + +{% block javaScriptTemplates %} + {# File upload templates and scripts #} + {% include "include-file-upload.twig" %} +{% endblock %} \ No newline at end of file diff --git a/custom/otssignange/views/campaign-page.twig b/custom/otssignange/views/campaign-page.twig new file mode 100644 index 0000000..5a901ed --- /dev/null +++ b/custom/otssignange/views/campaign-page.twig @@ -0,0 +1,186 @@ +{# +/** + * Copyright (C) 2020 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 . + */ +#} +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} + +{% block title %}{{ "Campaigns"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("campaign.add") %} + + {% endif %} + +
+{% endblock %} + +{% block pageContent %} +
+ + +
+
+
+
+
+

{% trans "Filter Campaigns" %}

+ +
+
+
+
+ {% set title %}{% trans "Name" %}{% endset %} + {{ inline.inputNameGrid('name', title) }} + + {% 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 %} + + {% set title %}{% trans "Layouts" %}{% endset %} + {% set values = [{id: 0, value: ""}, {id: 2, value: "Yes"}, {id: 1, value: "No"}] %} + {{ inline.dropdown("hasLayouts", "single", title, 0, values, "id", "value") }} + + {{ inline.hidden("folderId") }} + + {% set title %}{% trans "Layout ID" %}{% endset %} + {{ inline.number("layoutId", title, layoutId) }} + + {% if currentUser.featureEnabled('ad.campaign') %} + {% set title %}{% trans "Type" %}{% endset %} + {% set options = [ + { id: null, name: "" }, + { id: "list", name: "Layout list"|trans }, + { id: "ad", name: "Ad Campaign"|trans } + ] %} + {{ inline.dropdown("type", "single", title, "both", options, "id", "name", helpText) }} + {% endif %} + + {% set title %}{% trans "Cycle Based Playback" %}{% endset %} + {% set enabled %}{% trans "Enabled" %}{% endset %} + {% set disabled %}{% trans "Disabled" %}{% endset %} + {% set options = [ + { optionid: "", option: "" }, + { optionid: 0, option: disabled}, + { optionid: 1, option: enabled} + ] %} + {{ inline.dropdown("cyclePlaybackEnabled", "single", title, "", options, "optionid", "option") }} +
+
+
+
+ +
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
+
+
+ + +
+
+
+ + + + + {% if currentUser.featureEnabled('ad.campaign') %} + + + + {% endif %} + + {% if currentUser.featureEnabled("tag.tagging") %}{% endif %} + + + + {% if currentUser.featureEnabled('ad.campaign') %} + + + + + + {% endif %} + + + + + + + + + + + + + + +
{% trans "Name" %}{% trans "Type" %}{% trans "Start Date" %}{% trans "End Date" %}{% trans "# Layouts" %}{% trans "Tags" %}{% trans "Duration" %}{% trans "Cycle based Playback" %}{% trans "Play Count" %}{% trans "Target Type" %}{% trans "Target" %}{% trans "Plays" %}{% trans "Spend" %}{% trans "Impressions" %}{% trans "Ref 1" %}{% trans "Ref 2" %}{% trans "Ref 3" %}{% trans "Ref 4" %}{% trans "Ref 5" %}{% trans "Created At" %}{% trans "Modified At" %}{% trans "Modified By" %}
+
+
+
+
+
+
+{% endblock %} + +{% block javaScript %} + {# Initialise JS variables and translations #} + + + {# Add page source code bundle #} + +{% endblock %} diff --git a/custom/otssignange/views/command-page.twig b/custom/otssignange/views/command-page.twig new file mode 100644 index 0000000..8735979 --- /dev/null +++ b/custom/otssignange/views/command-page.twig @@ -0,0 +1,162 @@ +{# +/** + * Copyright (C) 2020-2024 Xibo Signage Ltd + * + * Xibo - Digital Signage - https://xibosignage.com + * + * This file is part of Xibo. + * + * Xibo is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * Xibo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Xibo. If not, see . + */ +#} +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} + +{% block title %}{{ "Commands"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("command.add") %} + + {% endif %} + +
+{% endblock %} + + +{% block pageContent %} +
+ + +
+
+
+
+
+

{% trans "Filter Commands" %}

+ +
+
+
+
+ {% set title %}{% trans "Name" %}{% endset %} + {{ inline.inputNameGrid('command', title) }} + + {% set title %}{% trans "Code" %}{% endset %} + {{ inline.inputNameGrid('code', title, null, 'useRegexForCode', 'logicalOperatorCode') }} +
+
+
+
+
+ + + + + + + + + + + + + + +
{% trans "Name" %}{% trans "Code" %}{% trans "Available On" %}{% trans "Description" %}{% trans "Sharing" %}
+
+
+
+
+
+{% endblock %} + +{% block javaScript %} + +{% endblock %} diff --git a/custom/otssignange/views/dashboard-status-page.twig b/custom/otssignange/views/dashboard-status-page.twig index 4f07d7d..d393a21 100644 --- a/custom/otssignange/views/dashboard-status-page.twig +++ b/custom/otssignange/views/dashboard-status-page.twig @@ -32,6 +32,32 @@

{% trans "Overview of your digital signage network" %}

+
+

{% trans "Quick Actions" %}

+
+ {% if currentUser.featureEnabled("schedule.view") %} + +
+
{% trans "Create Schedule" %}
+
+ {% endif %} + + {% if currentUser.featureEnabled("displays.view") %} + +
+
{% trans "Manage Displays" %}
+
+ {% endif %} + + {% if currentUser.featureEnabled("users.view") and (currentUser.isGroupAdmin() or currentUser.isSuperAdmin()) %} + +
+
{% trans "Add User" %}
+
+ {% endif %} +
+
+
@@ -100,10 +126,10 @@
-
-
- -
+
+
+
+
{% if xmdsLimit != "" %} {% trans %}Bandwidth Usage{% endtrans %} @@ -120,10 +146,15 @@
- {% if currentUser.featureEnabled("displays.reporting") %} - {% trans "More Statistics" %} - {% endif %} -
+
+ {% if currentUser.featureEnabled("displays.reporting") %} + {% trans "More Statistics" %} + {% endif %} +
+ + +
+
@@ -133,10 +164,10 @@
-
-
- -
+
+
+
+
{% trans "Library Usage" %}
@@ -149,7 +180,13 @@
-
+
+
+ + + +
+
@@ -161,8 +198,13 @@
-
-

{% trans "Display Activity" %}

+
+
+
+
+
{% trans "Display Activity" %}
+
+
@@ -181,8 +223,13 @@
-
-

{% trans "Latest News" %}

+
+
+
+
+
{% trans "Latest News" %}
+
+
{% if latestNews|length > 0 %} @@ -202,51 +249,97 @@
-
-
-

{% trans "Display Status" %}

+
+
+
+
+
+
{% trans "Display Status" %}
+
{% trans "Click on the chart for a breakdown" %}
+
+
+
+
+ + +
+
-
-
{% trans "Click on the chart for a breakdown" %}
-
- +
+
+
-
-
-

{% trans "Display Content Status" %}

+
+
+
+
+
+
{% trans "Display Content Status" %}
+
{% trans "Click on the chart for a breakdown" %}
+
+
+
+
+ + +
+
-
-
{% trans "Click on the chart for a breakdown" %}
-
- +
+
+
-
-
-

{% trans "Display Groups Status" %}

+
+
+
+
+
+
{% trans "Display Groups Status" %}
+
{% trans "Grouped by status" %}
+
+
+
+
+ + + +
+
-
-
{% trans "Click on the chart to view Display information" %}
-
+
+
-
-
-

{% trans "Display Groups Content Status" %}

+
+
+
+
+
+
{% trans "Display Groups Content Status" %}
+
{% trans "Grouped by content status" %}
+
+
+
+
+ + + +
+
-
-
{% trans "Click on the chart to view Display information" %}
-
+
+
@@ -322,32 +415,6 @@
- -
-

{% trans "Quick Actions" %}

-
- {% if currentUser.featureEnabled("schedule.view") %} - -
-
{% trans "Create Schedule" %}
-
- {% endif %} - - {% if currentUser.featureEnabled("displays.view") %} - -
-
{% trans "Manage Displays" %}
-
- {% endif %} - - {% if currentUser.featureEnabled("users.view") and (currentUser.isGroupAdmin() or currentUser.isSuperAdmin()) %} - -
-
{% trans "Add User" %}
-
- {% endif %} -
-
{% endblock %} @@ -377,50 +444,173 @@ var displayGroupIdsStatus = []; var displayGridTable = null - // Create our chart - var bandwidthChart = new Chart($("#bandwidthChart"), { - type: "bar", - data: {{ bandwidthWidget|raw }}, - options: { - scales: { - xAxes: [{ - stacked: {% if xmdsLimit %}true{% else %}false{% endif %} - }], - yAxes: [{ - scaleLabel: { - display: true, - labelString: "{{ bandwidthSuffix }}", - }, - stacked: {% if xmdsLimit %}true{% else %}false{% endif %} - }] - }, - legend: { - display: false - }, - maintainAspectRatio: false, - } - }); + // Create our charts + const bandwidthStacked = {% if xmdsLimit %}true{% else %}false{% endif %}; - var libraryData = {{ libraryWidgetData|raw }}; - const libraryLabels = {{ libraryWidgetLabels|raw }}; - var colours = new Array(); - for (var i = 0; i < libraryData.length; i++) { - colours.push(stringToColour(libraryLabels[i])); - } - var libraryChart = new Chart($("#libraryChart"), { - type: 'pie', - data: { - datasets: [{ - data: libraryData, - backgroundColor: colours - }], + function pickColor(value, fallback) { + if (Array.isArray(value)) return value[0] || fallback; + return value || fallback; + } - labels: {{ libraryWidgetLabels|raw }} - }, - options: { - maintainAspectRatio: false - } - }); + function cacheDatasetStyles(dataset) { + if (!dataset._ots) { + dataset._ots = { + backgroundColor: dataset.backgroundColor, + borderColor: dataset.borderColor, + fill: dataset.fill + }; + } + } + + function applyDatasetType(dataset, type, fallbackColor) { + cacheDatasetStyles(dataset); + dataset.type = type; + + if (type === 'line') { + const color = pickColor(dataset._ots.borderColor || dataset._ots.backgroundColor, fallbackColor); + dataset.borderColor = color; + dataset.backgroundColor = 'rgba(0, 0, 0, 0)'; + dataset.fill = false; + dataset.tension = 0.35; + dataset.pointRadius = 2; + dataset.pointHoverRadius = 3; + dataset.pointBackgroundColor = color; + } else { + dataset.backgroundColor = dataset._ots.backgroundColor || dataset.backgroundColor || fallbackColor; + dataset.borderColor = dataset._ots.borderColor || dataset.borderColor; + dataset.fill = dataset._ots.fill; + dataset.tension = 0; + dataset.pointRadius = 0; + } + } + + function setBandwidthScaleOptions(chart, type) { + if (!chart.options || !chart.options.scales) return; + const stacked = type === 'bar' ? bandwidthStacked : false; + chart.options.scales.xAxes[0].stacked = stacked; + chart.options.scales.yAxes[0].stacked = stacked; + } + + function setChartType(chart, type, isBandwidth) { + chart.config.type = type; + chart.data.datasets.forEach(function(dataset) { + applyDatasetType(dataset, type, 'rgba(96, 165, 250, 0.9)'); + }); + if (isBandwidth) { + setBandwidthScaleOptions(chart, type); + } + chart.update(); + } + + function setLibraryChartType(chart, type) { + if (type === 'pie' || type === 'doughnut') { + chart.config.type = type; + chart.update(); + } else if (type === 'bar') { + // Convert pie data to bar format + const labels = chart.data.labels; + const data = chart.data.datasets[0].data; + const colors = chart.data.datasets[0].backgroundColor; + + chart.config.type = 'bar'; + chart.data.datasets[0].type = 'bar'; + chart.data.datasets[0].backgroundColor = colors; + chart.data.datasets[0].borderColor = colors; + chart.options.scales = { + xAxes: [{ stacked: false }], + yAxes: [{ stacked: false }] + }; + chart.update(); + } + } + + var bandwidthChart = new Chart($("#bandwidthChart"), { + type: "line", + data: {{ bandwidthWidget|raw }}, + options: { + scales: { + xAxes: [{ + stacked: false + }], + yAxes: [{ + scaleLabel: { + display: true, + labelString: "{{ bandwidthSuffix }}", + }, + stacked: false + }] + }, + legend: { + display: false + }, + maintainAspectRatio: false, + } + }); + + var libraryData = {{ libraryWidgetData|raw }}; + const libraryLabels = {{ libraryWidgetLabels|raw }}; + var colours = new Array(); + for (var i = 0; i < libraryData.length; i++) { + colours.push(stringToColour(libraryLabels[i])); + } + var libraryChart = new Chart($("#libraryChart"), { + type: 'pie', + data: { + datasets: [{ + data: libraryData, + backgroundColor: colours + }], + labels: {{ libraryWidgetLabels|raw }} + }, + options: { + maintainAspectRatio: false, + plugins: { + legend: { + position: 'bottom' + } + } + } + }); + + setChartType(libraryChart, 'pie', false); + + $('.dashboard-chart-toggle').each(function() { + const toggle = $(this); + const chartId = toggle.data('chart'); + let chart = null; + + if (chartId === 'bandwidthChart') { + chart = bandwidthChart; + } else if (chartId === 'libraryChart') { + chart = libraryChart; + } else if (chartId === 'displayStatusChart') { + chart = displayStatusChart; + } else if (chartId === 'displayContentChart') { + chart = displayContentChart; + } else if (chartId === 'displayGroupStatusChart') { + chart = displayGroupStatusChart; + } else if (chartId === 'displayGroupContentStatusChart') { + chart = displayGroupContentStatusChart; + } + + if (!chart) return; + + toggle.find('.dashboard-chart-toggle-button').on('click', function(e) { + e.preventDefault(); + const type = $(this).data('chart-type'); + + // Update active state + toggle.find('.dashboard-chart-toggle-button').removeClass('is-active'); + $(this).addClass('is-active'); + + // Update chart type + if (chartId === 'libraryChart') { + setLibraryChartType(chart, type); + } else { + setChartType(chart, type, chartId === 'bandwidthChart'); + } + }); + }); $('.article_date').each(function(index, element) { // Replace the ISO date with a nice formatted date "for humans" diff --git a/custom/otssignange/views/dataset-page.twig b/custom/otssignange/views/dataset-page.twig new file mode 100644 index 0000000..7beea78 --- /dev/null +++ b/custom/otssignange/views/dataset-page.twig @@ -0,0 +1,599 @@ +{# +/** + * Copyright (C) 2020 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 . + */ +#} +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} +{% import "forms.twig" as forms %} + +{% block title %}{{ "DataSets"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("dataset.add") %} + + {% endif %} + +
+{% endblock %} + +{% block pageContent %} +
+ + +
+
+
+
+
+

{% trans "Filter DataSets" %}

+ +
+
+
+
+ {% set title %}{% trans "Name" %}{% endset %} + {{ inline.inputNameGrid('dataSet', title) }} + + {% set title %}{% trans "Code" %}{% endset %} + {% set helpText %}{% trans "Show items which match the provided code" %}{% endset %} + {{ inline.input("code", title, "", helpText) }} + + {% set title %}{% trans "Owner" %}{% endset %} + {% set helpText %}{% trans "Show items owned by the selected User." %}{% endset %} + {% set attributes = [ + { name: "data-width", value: "200px" }, + { name: "data-allow-clear", value: "true" }, + { name: "data-placeholder--id", value: null }, + { name: "data-placeholder--value", value: "" }, + { name: "data-search-url", value: url_for("user.search") }, + { name: "data-search-term", value: "userName" }, + { name: "data-search-term-tags", value: "tags" }, + { name: "data-id-property", value: "userId" }, + { name: "data-text-property", value: "userName" }, + { name: "data-initial-key", value: "userId" }, + ] %} + {{ inline.dropdown("userId", "single", title, "", null, "userId", "userName", helpText, "pagedSelect", "", "", "", attributes) }} + + {{ inline.hidden("folderId") }} +
+
+
+ +
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
+
+
+ + +
+
+
+ + + + + + + + + + + + + + + + + + + +
{% trans "ID" %}{% trans "Name" %}{% trans "Description" %}{% trans "Code" %}{% trans "Remote?" %}{% trans "Real time?" %}{% trans "Owner" %}{% trans "Sharing" %}{% trans "Last Sync" %}{% trans "Data Last Modified" %}
+
+
+
+
+
+
+{% endblock %} + +{% block javaScript %} + +{% endblock %} + +{% block javaScriptTemplates %} + {{ parent() }} + + {% verbatim %} + + + + + + + + + {% endverbatim %} +
+
+
+{% endblock %} \ No newline at end of file diff --git a/custom/otssignange/views/daypart-page.twig b/custom/otssignange/views/daypart-page.twig new file mode 100644 index 0000000..cdd1f80 --- /dev/null +++ b/custom/otssignange/views/daypart-page.twig @@ -0,0 +1,261 @@ +{# +/** + * Copyright (C) 2020 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 . + */ +#} +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} + +{% block title %}{{ "Dayparting"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("daypart.add") %} + + {% endif %} + +
+{% endblock %} + +{% block pageContent %} +
+ + +
+
+
+
+
+

{% trans "Filter Dayparts" %}

+ +
+
+
+
+ {% set title %}{% trans "Name" %}{% endset %} + {{ inline.inputNameGrid('name', title) }} + + {% set title %}{% trans "Retired" %}{% endset %} + {% set option1 = "Yes"|trans %} + {% set option2 = "No"|trans %} + {% set values = [{id: 1, value: option1}, {id: 0, value: option2}] %} + {{ inline.dropdown("isRetired", "single", title, 0, values, "id", "value") }} +
+
+
+
+
+ + + + + + + + + + + + + +
{% trans "Name" %}{% trans "Description" %}{% trans "Start Time" %}{% trans "End Time" %}
+
+
+
+
+{% endblock %} + +{% block javaScript %} + + {% verbatim %} + + {% endverbatim %} +{% endblock %} diff --git a/custom/otssignange/views/display-page.twig b/custom/otssignange/views/display-page.twig index 0ceb6ad..022bb36 100644 --- a/custom/otssignange/views/display-page.twig +++ b/custom/otssignange/views/display-page.twig @@ -28,9 +28,9 @@ {% block actionMenu %}
{% if currentUser.featureEnabled("displays.add") %} - + {% endif %} - +
{% endblock %} @@ -47,7 +47,6 @@
-
{% trans "Displays" %}
@@ -237,10 +236,10 @@
- +
- +
diff --git a/custom/otssignange/views/displaygroup-page.twig b/custom/otssignange/views/displaygroup-page.twig new file mode 100644 index 0000000..7c55c9f --- /dev/null +++ b/custom/otssignange/views/displaygroup-page.twig @@ -0,0 +1,381 @@ +{# +/** + * Copyright (C) 2020-2023 Xibo Signage Ltd + * + * Xibo - Digital Signage - https://xibosignage.com + * + * This file is part of Xibo. + * + * Xibo is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * Xibo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Xibo. If not, see . + */ +#} +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} + +{% block title %}{{ "Display Groups"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("displaygroup.add") %} + + {% endif %} + +
+{% endblock %} + +{% block pageContent %} +
+ + +
+
+
+
+
+

{% trans "Filter Display Groups" %}

+ +
+
+
+
+ {% set title %}{% trans "ID" %}{% endset %} + {{ inline.input("displayGroupId", title) }} + + {% set title %}{% trans "Name" %}{% endset %} + {{ inline.inputNameGrid('displayGroup', title) }} + + {% set title %}{% trans "Display" %}{% endset %} + {% set attributes = [ + { name: "data-width", value: "200px" }, + { name: "data-allow-clear", value: "true" }, + { name: "data-placeholder--id", value: null }, + { name: "data-placeholder--value", value: "" }, + { name: "data-search-url", value: url_for("display.search") }, + { name: "data-search-term", value: "display" }, + { name: "data-search-term-tags", value: "tags" }, + { name: "data-id-property", value: "displayId" }, + { name: "data-text-property", value: "display" }, + { name: "data-initial-key", value: "displayId" }, + ] %} + {% set helpText %}{% trans "Return Display Groups that directly contain the selected Display." %}{% endset %} + {{ inline.dropdown("displayId", "single", title, "", null, "displayId", "display", helpText, "pagedSelect", "", "", "", attributes) }} + + {% set title %}{% trans "Nested Display" %}{% endset %} + {% set helpText %}{% trans "Return Display Groups that contain the selected Display somewhere in the nested Display Group relationship tree." %}{% endset %} + {{ inline.dropdown("nestedDisplayId", "single", title, "", null, "displayId", "display", helpText, "pagedSelect", "", "", "", attributes) }} + + {% set title %}{% trans "Dynamic Criteria" %}{% endset %} + {{ inline.input("dynamicCriteria", title) }} + + {% 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 %} + + {{ inline.hidden("folderId") }} +
+
+
+
+ +
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
+
+
+ + +
+ +
+
+ + + + + + + + + {% if currentUser.featureEnabled("tag.tagging") %} + + + {% endif %} + + + + + + + + + + + + + + +
{% trans "ID" %}{% trans "Name" %}{% trans "Description" %}{% trans "Is Dynamic?" %}{% trans "Criteria" %}{% trans "Criteria Tags" %}{% trans "Tags" %}{% trans "Sharing" %}{% trans "Reference 1" %}{% trans "Reference 2" %}{% trans "Reference 3" %}{% trans "Reference 4" %}{% trans "Reference 5" %}{% trans "Created Date" %}{% trans "Modified Date" %}
+
+
+
+
+
+
+
+{% endblock %} + +{% block javaScript %} + +{% endblock %} + +{% block javaScriptTemplates %} + {{ parent() }} + + {% verbatim %} + + {% endverbatim %} +{% endblock %} diff --git a/custom/otssignange/views/displayprofile-page.twig b/custom/otssignange/views/displayprofile-page.twig new file mode 100644 index 0000000..8ba41ac --- /dev/null +++ b/custom/otssignange/views/displayprofile-page.twig @@ -0,0 +1,168 @@ +{# +/** + * Copyright (C) 2020 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 . + */ +#} +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} + +{% block title %}{{ "Display Setting Profiles"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("displayprofile.add") %} + + {% endif %} + +
+{% endblock %} + +{% block pageContent %} +
+ + +
+
+
+
+
+

{% trans "Filter Display Settings" %}

+ +
+
+
+
+ + {% set title %}{% trans "Name" %}{% endset %} + {{ inline.inputNameGrid('displayProfile', title) }} + + {% set title %}{% trans "Type" %}{% endset %} + {{ inline.dropdown("type", "single", title, "", [{typeId:null, type:""}]|merge(types), "typeId","type") }} +
+
+
+
+
+ + + + + + + + + + + + +
{% trans "Name" %}{% trans "Type" %}{% trans "Default" %}
+
+
+
+
+
+{% endblock %} + +{% block javaScript %} + +{% endblock %} diff --git a/custom/otssignange/views/inline.twig b/custom/otssignange/views/inline.twig new file mode 100644 index 0000000..49476f6 --- /dev/null +++ b/custom/otssignange/views/inline.twig @@ -0,0 +1,327 @@ + +{% macro disabled(name, title, value, helpText, groupClass) %} +
+ + +
+{% endmacro %} + +{% macro hidden(name, value) %} + +{% endmacro %} + +{% macro raw(text, groupClass) %} +
+ {{ text|raw }} +
+{% endmacro %} + +{% macro message(message, groupClass, messageStyleClass) %} +
+ {{ message }} +
+{% endmacro %} + +{% macro alert(message, alertType, groupClass) %} +
+ +
+{% endmacro %} + +{% macro button(title, type, link, groupClass) %} +
+ {% if type == "link" %} + {{ title }} + {% else %} + + {% endif %} +
+{% endmacro %} + +{% macro input(name, title, value, helpText, groupClass, validation, accessKey) %} +
+ + +
+{% endmacro %} + +{% macro inputWithTags(name, title, value, helpText, groupClass, validation, accessKey, exactTag, exactTagTitle, logicalOperatorTitle, autoCompleteEnabled = 1) %} +
+ + {% if exactTag %} +
+ +
+
+ +
+ +
+
+ {% else %} + + {% endif %} +
+{% endmacro %} + +{% macro number(name, title, value, helpText, groupClass, validation, accessKey, maxNumber, minNumber) %} +
+ + +
+{% endmacro %} + +{% macro email(name, title, value, helpText, groupClass, validation, accessKey) %} +
+ + +
+{% endmacro %} + +{% macro password(name, title, value, helpText, groupClass, validation, accessKey) %} +
+ + +
+{% endmacro %} + +{% macro checkbox(name, title, value, groupClass, accessKey) %} +
+
+ + +
+
+{% endmacro %} + +{% macro radio(name, id, title, value, helpText, groupClass, accessKey, setValue) %} +
+
+ + +
+
+{% endmacro %} + +{% macro dropdown(name, type, title, value, options, optionId, optionValue, helpText, groupClass, validation, accessKey, callBack, dataAttributes, optionGroups) %} +
+ + +
+{% endmacro %} + +{% macro permissions(name, options) %} + + + + + + + + {% for item in options %} + + + + + + + {% endfor %} +
{% trans "Group" %}{% trans "View" %}{% trans "Edit" %}{% trans "Delete" %}
{{ name }}
+{% endmacro %} + +{% macro date(name, title, value, helpText, groupClass, validation, accessKey) %} +
+ +
+
+ + +
+
+{% endmacro %} + +{% macro dateMonth(name, title, value, helpText, groupClass, validation, accessKey) %} +
+ +
+ + + +
+
+{% endmacro %} + +{% macro dateTime(name, title, value, helpText, groupClass, validation, accessKey) %} +
+ +
+ + + +
+
+{% endmacro %} + +{% macro time(name, title, value, helpText, groupClass, validation, accessKey) %} +
+ +
+ + + +
+
+{% endmacro %} + +{% macro switch(name, title, value, labelWidth, switchSize, onText, offText, groupClass, accessKey, disabled) %} +
+
+ +
+
+{% endmacro %} + +{% macro color(name, title, value, helpText, groupClass, validation, accessKey) %} +
+ + +
+{% endmacro %} + +{% macro inputNameGrid(name, title, groupClass, useRegexName, logicalOperatorName) %} +
+ +
+
+ +
+
+ +
+ +
+
+
+
+{% endmacro %} + +{% macro dateRangeFilter(name, title, value, helpText, groupClass, validation, accessKey) %} +
+ {% set today = now | date_modify('today') | date("Y-m-d H:i:s") %} +
+ +
+ +
+
+ + +
+{% endmacro %} \ No newline at end of file diff --git a/custom/otssignange/views/layout-page.twig b/custom/otssignange/views/layout-page.twig new file mode 100644 index 0000000..e249635 --- /dev/null +++ b/custom/otssignange/views/layout-page.twig @@ -0,0 +1,536 @@ +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} + +{% block title %}{{ "Layouts"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("layout.add") %} + + + {% endif %} + +
+{% endblock %} + +{% block pageContent %} +
+ + +
+
+
+
+
+

{% trans "Filter Layouts" %}

+ +
+
+
+ +
+
+
+ {% set title %}{% trans "ID" %}{% endset %} + {{ inline.number("campaignId", title) }} + + {% set title %}{% trans "Name" %}{% endset %} + {{ inline.inputNameGrid('layout', title) }} + + {% 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 %} + + {% set title %}{% trans "Code" %}{% endset %} + {{ inline.input('codeLike', title) }} + + {% if currentUser.featureEnabled("displaygroup.view") %} + {% set title %}{% trans "Display Group" %}{% endset %} + {% set helpText %}{% trans "Show Layouts active on the selected Display / Display Group" %}{% endset %} + {% set attributes = [ + { name: "data-width", value: "200px" }, + { 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":-1}' }, + { 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("activeDisplayGroupId", "single", title, "", null, "displayGroupId", "displayGroup", helpText, "pagedSelect", "", "", "", attributes) }} + {% endif %} + + {% set title %}{% trans "Owner" %}{% endset %} + {% set helpText %}{% trans "Show items owned by the selected User." %}{% endset %} + {% set attributes = [ + { name: "data-width", value: "200px" }, + { name: "data-allow-clear", value: "true" }, + { name: "data-placeholder--id", value: null }, + { name: "data-placeholder--value", value: "" }, + { name: "data-search-url", value: url_for("user.search") }, + { name: "data-search-term", value: "userName" }, + { name: "data-search-term-tags", value: "tags" }, + { name: "data-id-property", value: "userId" }, + { name: "data-text-property", value: "userName" }, + { name: "data-initial-key", value: "userId" }, + ] %} + {{ inline.dropdown("userId", "single", title, "", null, "userId", "userName", helpText, "pagedSelect", "", "", "", attributes) }} + + {% set title %}{% trans "Owner User Group" %}{% endset %} + {% set helpText %}{% trans "Show items owned by users in the selected User Group." %}{% endset %} + {% set attributes = [ + { name: "data-width", value: "200px" }, + { name: "data-allow-clear", value: "true" }, + { name: "data-placeholder--id", value: null }, + { name: "data-placeholder--value", value: "" }, + { name: "data-search-url", value: url_for("group.search") }, + { name: "data-search-term", value: "group" }, + { name: "data-id-property", value: "groupId" }, + { name: "data-text-property", value: "group" }, + { name: "data-initial-key", value: "userGroupId" }, + ] %} + {{ inline.dropdown("ownerUserGroupId", "single", title, "", null, "groupId", "group", helpText, "pagedSelect", "", "", "", attributes) }} + + {% set title %}{% trans "Orientation" %}{% endset %} + {% set option1 = "All"|trans %} + {% set option2 = "Landscape"|trans %} + {% set option3 = "Portrait"|trans %} + {% set values = [{id: '', value: option1}, {id: 'landscape', value: option2}, {id: 'portrait', value: option3}] %} + {{ inline.dropdown("orientation", "single", title, '', values, "id", "value") }} + + {{ inline.hidden("folderId") }} +
+
+ {% set title %}{% trans "Retired" %}{% endset %} + {% set option1 = "No"|trans %} + {% set option2 = "Yes"|trans %} + {% set values = [{id: 0, value: option1}, {id: 1, value: option2}] %} + {{ inline.dropdown("retired", "single", title, 0, values, "id", "value") }} + + {% set title %}{% trans "Show" %}{% endset %} + {% set option1 = "All"|trans %} + {% set option2 = "Only Used"|trans %} + {% set option3 = "Only Unused"|trans %} + {% set values = [{id: 1, value: option1}, {id: 2, value: option2}, {id: 3, value: option3}] %} + {{ inline.dropdown("layoutStatusId", "single", title, 1, values, "id", "value") }} + + {% set title %}{% trans "Description" %}{% endset %} + {% set option1 = "All"|trans %} + {% set option2 = "1st line"|trans %} + {% set option3 = "Widget List"|trans %} + {% set values = [{id: 1, value: option1}, {id: 2, value: option2}, {id: 3, value: option3}] %} + {{ inline.dropdown("showDescriptionId", "single", title, 2, values, "id", "value") }} + + {% if currentUser.featureEnabled("library.view") %} + {% set title %}{% trans "Media" %}{% endset %} + {{ inline.input("mediaLike", title) }} + {% endif %} + + {% set title %}{% trans "Layout ID" %}{% endset %} + {{ inline.number("layoutId", title) }} + + {% set title %}{% trans "Modified Since" %}{% endset %} + {{ inline.date("modifiedSinceDt", title) }} +
+
+
+
+
+
+ +
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
+
+ +
+ + +
+ +
+
+ + + + + + + + + {% if currentUser.featureEnabled("tag.tagging") %}{% endif %} + + + + + + + + + + + + + + + + +
{% trans "ID" %}{% trans "Name" %}{% trans "Status" %}{% trans "Description" %}{% trans "Duration" %}{% trans "Tags" %}{% trans "Orientation" %}{% trans "Thumbnail" %}{% trans "Owner" %}{% trans "Sharing" %}{% trans "Valid?" %}{% trans "Stats?" %}{% trans "Created" %}{% trans "Modified" %}{% trans "Layout ID" %}{% trans "Code" %}
+
+
+
+
+
+
+{% endblock %} + +{% block javaScript %} + +{% endblock %} diff --git a/custom/otssignange/views/library-page.twig b/custom/otssignange/views/library-page.twig new file mode 100644 index 0000000..749c090 --- /dev/null +++ b/custom/otssignange/views/library-page.twig @@ -0,0 +1,576 @@ +{# +/** + * Copyright (C) 2022 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 . + */ +#} +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} + +{% block title %}{{ "Library"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabledCount(["library.add", "library.modify"]) > 0 or settings.SETTING_LIBRARY_TIDY_ENABLED == 1 %} + {% if currentUser.featureEnabled("library.add") %} + + + {% endif %} + {% if settings.SETTING_LIBRARY_TIDY_ENABLED == 1 and currentUser.featureEnabled("library.modify") %} + + {% endif %} + {% endif %} + +
+{% endblock %} + + +{% block pageContent %} +
+ + +
+
+
+
+
+

{% trans "Filter Media" %}

+ +
+
+
+
+ {% set title %}{% trans "ID" %}{% endset %} + {{ inline.number("mediaId", title) }} + + {% set title %}{% trans "Name" %}{% endset %} + {{ inline.inputNameGrid('media', title) }} + + {% 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 %} + + {% set attributes = [ + { name: "data-allow-clear", value: "true" }, + { name: "data-placeholder--id", value: null }, + { name: "data-placeholder--value", value: "" } + ] %} + + {% set title %}{% trans "Owner" %}{% endset %} + {% set helpText %}{% trans "Show items owned by the selected User." %}{% endset %} + {% set attributes = [ + { name: "data-width", value: "200px" }, + { name: "data-allow-clear", value: "true" }, + { name: "data-placeholder--id", value: null }, + { name: "data-placeholder--value", value: "" }, + { name: "data-search-url", value: url_for("user.search") }, + { name: "data-search-term", value: "userName" }, + { name: "data-search-term-tags", value: "tags" }, + { name: "data-id-property", value: "userId" }, + { name: "data-text-property", value: "userName" }, + { name: "data-initial-key", value: "userId" }, + ] %} + {{ inline.dropdown("ownerId", "single", title, "", null, "userId", "userName", helpText, "pagedSelect", "", "", "", attributes) }} + + {% set title %}{% trans "Owner User Group" %}{% endset %} + {% set helpText %}{% trans "Show items owned by users in the selected User Group." %}{% endset %} + {% set attributes = [ + { name: "data-width", value: "200px" }, + { name: "data-allow-clear", value: "true" }, + { name: "data-placeholder--id", value: null }, + { name: "data-placeholder--value", value: "" }, + { name: "data-search-url", value: url_for("group.search") }, + { name: "data-search-term", value: "group" }, + { name: "data-id-property", value: "groupId" }, + { name: "data-text-property", value: "group" }, + { name: "data-initial-key", value: "userGroupId" }, + ] %} + {{ inline.dropdown("ownerUserGroupId", "single", title, "", null, "groupId", "group", helpText, "pagedSelect", "", "", "", attributes) }} + + {% set title %}{% trans "Type" %}{% endset %} + {{ inline.dropdown("type", "single", title, "", [{"type": none, "name": ""}]|merge(modules), "type", "name") }} + + {% set title %}{% trans "Retired" %}{% endset %} + {% set values = [{id: 0, value: "No"}, {id: 1, value: "Yes"}] %} + {{ inline.dropdown("retired", "single", title, 0, values, "id", "value") }} + + {{ inline.hidden("folderId") }} + + {% set title %}{% trans "Layout ID" %}{% endset %} + {{ inline.number("layoutId", title, layoutId) }} + + {% set title %}{% trans "Orientation" %}{% endset %} + {% set option1 = "All"|trans %} + {% set option2 = "Landscape"|trans %} + {% set option3 = "Portrait"|trans %} + {% set values = [{id: '', value: option1}, {id: 'landscape', value: option2}, {id: 'portrait', value: option3}] %} + {{ inline.dropdown("orientation", "single", title, '', values, "id", "value") }} +
+
+
+
+
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
+
+
+ + +
+
+
+ + + + + + + {% if currentUser.featureEnabled("tag.tagging") %}{% endif %} + + + + + + + + + + + + + + + + + + + + + +
{% trans "ID" %}{% trans "Name" %}{% trans "Type" %}{% trans "Tag" %}{% trans "Thumbnail" %}{% trans "Duration" %}{% trans "Duration (seconds)" %}{% trans "Size" %}{% trans "Size (bytes)" %}{% trans "Resolution" %}{% trans "Owner" %}{% trans "Sharing" %}{% trans "Revised" %}{% trans "Released" %}{% trans "File Name" %}{% trans "Stats?" %}{% trans "Created" %}{% trans "Modified" %}{% trans "Expires" %}
+
+
+
+
+
+
+
+{% endblock %} + +{% block javaScript %} + +{% endblock %} diff --git a/custom/otssignange/views/menuboard-page.twig b/custom/otssignange/views/menuboard-page.twig new file mode 100644 index 0000000..76b8d3c --- /dev/null +++ b/custom/otssignange/views/menuboard-page.twig @@ -0,0 +1,198 @@ +{# +/** + * Copyright (C) 2022 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 . + */ +#} +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} + +{% block title %}{{ "Menu Boards"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("menuBoard.add") %} + + {% endif %} + +
+{% endblock %} + +{% block pageContent %} +
+ + +
+
+
+
+
+

{% trans "Filter Menu Boards" %}

+ +
+
+
+
+ {% set title %}{% trans "ID" %}{% endset %} + {{ inline.number("menuId", title) }} + + {% set title %}{% trans "Name" %}{% endset %} + {{ inline.inputNameGrid('name', title) }} + + {% set title %}{% trans "Code" %}{% endset %} + {{ inline.input('code', title) }} + + {% set title %}{% trans "Owner" %}{% endset %} + {% set helpText %}{% trans "Show items owned by the selected User." %}{% endset %} + {% set attributes = [ + { name: "data-width", value: "200px" }, + { name: "data-allow-clear", value: "true" }, + { name: "data-placeholder--id", value: null }, + { name: "data-placeholder--value", value: "" }, + { name: "data-search-url", value: url_for("user.search") }, + { name: "data-search-term", value: "userName" }, + { name: "data-search-term-tags", value: "tags" }, + { name: "data-id-property", value: "userId" }, + { name: "data-text-property", value: "userName" }, + { name: "data-initial-key", value: "userId" }, + ] %} + {{ inline.dropdown("userId", "single", title, "", null, "userId", "userName", helpText, "pagedSelect", "", "", "", attributes) }} + + {{ inline.hidden("folderId") }} +
+
+
+
+
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
+
+
+
+ + + + + + + + + + + + + + + + + +
+
+
+
+
+
+{% endblock %} + +{% block javaScript %} + +{% endblock %} \ No newline at end of file diff --git a/custom/otssignange/views/override-styles.twig b/custom/otssignange/views/override-styles.twig index 13aa98c..3b46c89 100644 --- a/custom/otssignange/views/override-styles.twig +++ b/custom/otssignange/views/override-styles.twig @@ -161,7 +161,7 @@ body { grid-template-columns: 20px 1fr; align-items: center; column-gap: 12px; - padding: 8px 12px; + padding: 6px 10px; color: #c8d5ee; text-decoration: none; transition: all var(--transition-fast); @@ -1191,12 +1191,13 @@ body .panel .panel-heading, letter-spacing: 0.02em; } +/* Filter card - modern container */ .ots-filter-card { - background: linear-gradient(180deg, rgba(30, 41, 59, 0.95), rgba(15, 23, 42, 0.92)); - border: 1px solid rgba(148, 163, 184, 0.22); - box-shadow: 0 18px 34px rgba(8, 15, 30, 0.32); + background: linear-gradient(135deg, rgba(15, 23, 42, 0.4), rgba(15, 23, 42, 0.2)); + border: none; + box-shadow: 0 4px 20px rgba(6, 10, 20, 0.15); margin-bottom: 0; - border-radius: 12px; + border-radius: 16px; overflow: hidden; } @@ -1205,109 +1206,260 @@ body .panel .panel-heading, display: flex; align-items: center; justify-content: space-between; - padding: 14px 16px; - border-bottom: 1px solid rgba(148, 163, 184, 0.2); - background: rgba(15, 23, 42, 0.3); + gap: 12px; + padding: 12px 16px; + border: none; + background: transparent; } .ots-filter-title { - font-weight: 600; + font-weight: 700; color: var(--color-text-primary); font-size: 14px; + letter-spacing: 0.03em; + text-transform: uppercase; margin: 0; } .ots-filter-toggle { - width: 32px; - height: 32px; + width: 36px; + height: 36px; padding: 0; border: none; - background: transparent; + background: rgba(59, 130, 246, 0.08); color: var(--color-text-secondary); cursor: pointer; display: flex; align-items: center; justify-content: center; - border-radius: 6px; - transition: all var(--transition-fast); + border-radius: 10px; + transition: all 200ms ease; } .ots-filter-toggle:hover { - background: rgba(59, 130, 246, 0.1); + background: rgba(59, 130, 246, 0.16); color: var(--color-primary); } .ots-filter-content { - padding: 16px; - max-height: 600px; - overflow: hidden; + padding: 0 16px 12px 16px; + max-height: none; + min-height: auto; + overflow: visible; transition: max-height 300ms ease-out, padding 300ms ease-out; + display: block; } .ots-filter-content.collapsed { max-height: 0; + min-height: 0; padding: 0 16px; overflow: hidden; + display: none; } .ots-filter-card .nav-tabs { - border-bottom: 1px solid rgba(148, 163, 184, 0.2); - gap: 8px; - margin-bottom: 14px; + display: none; } -.ots-filter-card .nav-tabs .nav-link { - color: var(--color-text-secondary); - border: 0; - border-radius: 8px; - padding: 10px 14px; - background: transparent; - font-size: 13px; - font-weight: 500; - transition: all var(--transition-fast); +.ots-filter-card .tab-content { + display: block; } -.ots-filter-card .nav-tabs .nav-link.active, -.ots-filter-card .nav-tabs .nav-link:hover { - color: var(--color-text-primary); - background: rgba(59, 130, 246, 0.12); +.ots-filter-card .tab-pane { + display: none; +} + +.ots-filter-card .tab-pane.active, +.ots-filter-card .tab-pane.show { + display: block; +} + +.ots-filter-card .form-inline { + display: flex; + flex-wrap: nowrap; + gap: 12px; + align-items: flex-end; + overflow-x: auto; + overflow-y: hidden; + -webkit-overflow-scrolling: touch; + padding-bottom: 4px; } .ots-filter-card .form-inline .form-group, .ots-filter-card .form-inline .input-group { - margin-right: 16px; - margin-bottom: 12px; + margin-right: 0; + margin-bottom: 0; + flex: 0 0 auto; + min-width: 180px; } .ots-filter-card .form-control, .ots-filter-card select, .ots-filter-card .select2-selection, -.ots-filter-card .input-group-addon { - background: var(--color-surface) !important; - border: 1px solid var(--color-border) !important; +.ots-filter-card .input-group-addon, +.ots-filter-card .input-group-text { + background: linear-gradient(180deg, rgba(15, 23, 42, 0.85), rgba(15, 23, 42, 0.65)) !important; + border: 1px solid rgba(148, 163, 184, 0.25) !important; color: var(--color-text-primary) !important; - border-radius: 6px !important; - padding: 8px 12px !important; - font-size: 13px !important; - transition: all var(--transition-fast) !important; - height: 36px !important; + border-radius: 10px !important; + padding: 12px 14px !important; + font-size: 15px !important; + font-family: inherit !important; + transition: border 150ms ease, box-shadow 150ms ease !important; + height: 48px !important; + line-height: 1.4 !important; + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.02), 0 6px 16px rgba(6, 10, 20, 0.18) !important; + box-sizing: border-box !important; +} + +.ots-filter-card .input-group { + display: flex; + align-items: center; + gap: 6px; +} + +.ots-filter-card .input-group > .form-control, +.ots-filter-card .input-group > .custom-select, +.ots-filter-card .input-group > .select2-container { + min-width: 0; + flex: 1 1 auto; } .ots-filter-card .form-control:focus, -.ots-filter-card select:focus { - border-color: var(--color-primary) !important; - box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1) !important; - background: var(--color-surface) !important; +.ots-filter-card select:focus, +.ots-filter-card .select2-selection:focus { + border-color: rgba(96, 165, 250, 0.7) !important; + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2), 0 10px 24px rgba(6, 10, 20, 0.25) !important; + background: rgba(15, 23, 42, 0.9) !important; } .ots-filter-card label { - color: var(--color-text-secondary); - font-size: 12px; - font-weight: 500; - margin-bottom: 4px; + color: var(--color-text-tertiary); + font-size: 11px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.04em; + margin-bottom: 2px; display: block; } +.ots-filter-card .select2-selection__rendered { + color: var(--color-text-primary) !important; + line-height: 20px !important; +} + +.ots-filter-card .select2-container--default .select2-selection--single, +.ots-filter-card .select2-container--default .select2-selection--multiple { + background: linear-gradient(180deg, rgba(15, 23, 42, 0.85), rgba(15, 23, 42, 0.65)) !important; + border: 1px solid rgba(148, 163, 184, 0.25) !important; + border-radius: 10px !important; + min-height: 44px !important; + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.02), 0 6px 16px rgba(6, 10, 20, 0.18) !important; +} + +.ots-filter-card .select2-container--default .select2-selection--multiple .select2-search__field { + color: var(--color-text-primary) !important; + background: transparent !important; +} + +.ots-filter-card .select2-container--default .select2-selection--multiple .select2-selection__choice { + background: rgba(59, 130, 246, 0.2) !important; + border: 1px solid rgba(59, 130, 246, 0.4) !important; + color: var(--color-text-primary) !important; + border-radius: 999px !important; +} + +.ots-filter-card .bootstrap-tagsinput, +.ots-filter-card .tagsinput { + background: linear-gradient(180deg, rgba(15, 23, 42, 0.85), rgba(15, 23, 42, 0.65)) !important; + border: 1px solid rgba(148, 163, 184, 0.25) !important; + border-radius: 10px !important; + color: var(--color-text-primary) !important; + min-height: 44px !important; + padding: 6px 10px !important; + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.02), 0 6px 16px rgba(6, 10, 20, 0.18) !important; +} + +.ots-filter-card .bootstrap-tagsinput input, +.ots-filter-card .tagsinput input { + background: transparent !important; + color: var(--color-text-primary) !important; +} + +.ots-filter-card .select2-selection__arrow b { + border-color: var(--color-text-secondary) transparent transparent transparent !important; +} + +.ots-filter-card .input-group { + background: transparent; +} + +.ots-filter-card .input-group .form-control { + border-top-right-radius: 0 !important; + border-bottom-right-radius: 0 !important; +} + +.ots-filter-card .input-group-append .input-group-text, +.ots-filter-card .input-group-addon { + border-top-left-radius: 0 !important; + border-bottom-left-radius: 0 !important; + font-weight: 600; + height: 44px !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + padding: 0 12px !important; +} + +.ots-filter-card .input-group .input-group-prepend .input-group-text, +.ots-filter-card .input-group .input-group-append .input-group-text { + border-radius: 10px !important; +} + +.ots-filter-card .input-group .btn, +.ots-filter-card .input-group .btn.btn-secondary { + height: 44px; + padding: 0 14px; + border-radius: 999px; + border: 1px solid rgba(148, 163, 184, 0.25); + background: rgba(30, 41, 59, 0.55); + color: var(--color-text-primary); + font-weight: 600; + letter-spacing: 0.02em; +} + +.ots-filter-card input::placeholder, +.ots-filter-card textarea::placeholder { + color: rgba(148, 163, 184, 0.7) !important; +} + +.ots-filter-card select { + appearance: none; + -webkit-appearance: none; + -moz-appearance: none; + background-image: linear-gradient(45deg, transparent 50%, rgba(148, 163, 184, 0.7) 50%), + linear-gradient(135deg, rgba(148, 163, 184, 0.7) 50%, transparent 50%); + background-position: calc(100% - 16px) 17px, calc(100% - 12px) 17px; + background-size: 4px 4px, 4px 4px; + background-repeat: no-repeat; + padding-right: 28px !important; +} + +.ots-filter-card .form-check-input { + width: 18px; + height: 18px; + border-radius: 6px; + border: 1px solid rgba(148, 163, 184, 0.35); + background: rgba(15, 23, 42, 0.65); + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.02); +} + +.ots-filter-card .form-check-input:checked { + background: var(--color-primary); + border-color: rgba(96, 165, 250, 0.8); +} + .ots-grid-with-folders { display: grid; grid-template-columns: 260px 1fr; @@ -2251,17 +2403,34 @@ legend { /* Dropdowns, modals, and popovers */ .dropdown-menu, .dropdown-toggle, -.popover, -.modal, -.modal-content, -.modal-header, -.modal-body, -.modal-footer { +.popover { background-color: var(--color-surface) !important; color: var(--color-text-primary) !important; border: 1px solid var(--color-border) !important; } +.modal, +.modal-body, +.modal-footer { + background-color: transparent !important; + color: var(--color-text-primary) !important; + border: 1px solid var(--color-border) !important; +} + +.modal-content { + background-color: var(--color-surface) !important; + color: var(--color-text-primary) !important; + border: 1px solid var(--color-border) !important; +} + +.modal-backdrop, +.modal-backdrop.show, +.modal-backdrop.in { + background-color: rgba(0, 0, 0, 0.3) !important; + backdrop-filter: blur(4px) !important; + opacity: 1 !important; +} + .modal-header { background-color: var(--color-surface-elevated) !important; border-bottom: 1px solid var(--color-border) !important; @@ -3070,6 +3239,22 @@ textarea:focus { .modal-content { border-radius: var(--ots-radius-lg); + background-color: var(--ots-surface-2) !important; +} + +.modal, +.modal-header, +.modal-body, +.modal-footer { + background-color: transparent !important; +} + +.modal-backdrop, +.modal-backdrop.show, +.modal-backdrop.in { + background-color: rgba(0, 0, 0, 0.3) !important; + backdrop-filter: blur(4px) !important; + opacity: 1 !important; } .modal-footer { diff --git a/custom/otssignange/views/playersoftware-page.twig b/custom/otssignange/views/playersoftware-page.twig new file mode 100644 index 0000000..b4a02c7 --- /dev/null +++ b/custom/otssignange/views/playersoftware-page.twig @@ -0,0 +1,198 @@ +{# +/** + * Copyright (C) 2020 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 . + */ +#} + +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("playersoftware.add") %} + + {% endif %} + +
+{% endblock %} + + +{% block pageContent %} +
+ + +
+
+
+
+
+

{% trans "Filter Player Versions" %}

+ +
+
+
+
+ {% set title %}{% trans "Type" %}{% endset %} + {{ inline.dropdown("playerType", "single", title, "", [{"type": none, "typeShow": none}]|merge(types), "type", "typeShow") }} + + {% set title %}{% trans "Version" %}{% endset %} + {{ inline.dropdown("playerVersion", "single", title, "", [{"version": none, "version": none}]|merge(versions), "version", "version") }} + + {% set title %}{% trans "Code" %}{% endset %} + {{ inline.input("playerCode", title) }} +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + +
{% trans "Version ID" %}{% trans "Player Version Name" %}{% trans "Type" %}{% trans "Version" %}{% trans "Code" %}{% trans "File Name" %}{% trans "Size" %}{% trans "Created At" %}{% trans "Modified At" %}{% trans "Modified By" %}
+
+
+
+
+
+{% endblock %} + +{% block javaScript %} + +{% endblock %} diff --git a/custom/otssignange/views/playlist-page.twig b/custom/otssignange/views/playlist-page.twig new file mode 100644 index 0000000..2c42415 --- /dev/null +++ b/custom/otssignange/views/playlist-page.twig @@ -0,0 +1,554 @@ +{# + * Copyright (C) 2021 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 . +#} +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} + +{% block title %}{{ "Playlists"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("playlist.add") %} + + {% endif %} + +
+{% endblock %} + +{% block pageContent %} +
+ + +
+
+
+
+
+

{% trans "Filter Playlists" %}

+ +
+
+
+ +
+
+
+ + {% set title %}{% trans "Name" %}{% endset %} + {{ inline.inputNameGrid('name', title) }} + + {% 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 %} + + {% set attributes = [ + { name: "data-live-search", value: "true" }, + { name: "data-selected-text-format", value: "count > 4" } + ] %} + + {% set title %}{% trans "Owner" %}{% endset %} + {% set helpText %}{% trans "Show items owned by the selected User." %}{% endset %} + {% set attributes = [ + { name: "data-width", value: "200px" }, + { name: "data-allow-clear", value: "true" }, + { name: "data-placeholder--id", value: null }, + { name: "data-placeholder--value", value: "" }, + { name: "data-search-url", value: url_for("user.search") }, + { name: "data-search-term", value: "userName" }, + { name: "data-search-term-tags", value: "tags" }, + { name: "data-id-property", value: "userId" }, + { name: "data-text-property", value: "userName" }, + { name: "data-initial-key", value: "userId" }, + ] %} + {{ inline.dropdown("userId", "single", title, "", null, "userId", "userName", helpText, "pagedSelect", "", "", "", attributes) }} + + {% set title %}{% trans "Owner User Group" %}{% endset %} + {% set helpText %}{% trans "Show items owned by users in the selected User Group." %}{% endset %} + {% set attributes = [ + { name: "data-width", value: "200px" }, + { name: "data-allow-clear", value: "true" }, + { name: "data-placeholder--id", value: null }, + { name: "data-placeholder--value", value: "" }, + { name: "data-search-url", value: url_for("group.search") }, + { name: "data-search-term", value: "group" }, + { name: "data-id-property", value: "groupId" }, + { name: "data-text-property", value: "group" }, + { name: "data-initial-key", value: "userGroupId" }, + ] %} + {{ inline.dropdown("ownerUserGroupId", "single", title, "", null, "groupId", "group", helpText, "pagedSelect", "", "", "", attributes) }} + {{ inline.hidden("folderId") }} + + {% set title %}{% trans "Layout ID" %}{% endset %} + {{ inline.number("layoutId", title, layoutId) }} +
+
+ + {% set title %}{% trans "Show" %}{% endset %} + {% set values = [{id: 1, value: "All"}, {id: 2, value: "Only Used"}, {id: 3, value: "Only Unused"}] %} + {{ inline.dropdown("playlistStatusId", "single", title, 1, values, "id", "value") }} + + {% if currentUser.featureEnabled("library.view") %} + {% set title %}{% trans "Media" %}{% endset %} + {{ inline.input("mediaLike", title) }} + {% endif %} +
+
+
+
+
+
+ +
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
+
+
+ + +
+
+
+ + + + + + + {% if currentUser.featureEnabled("tag.tagging") %}{% endif %} + + + + + + + + + + + + +
{% trans "ID" %}{% trans "Name" %}{% trans "Duration" %}{% trans "Tags" %}{% trans "Dynamic?" %}{% trans "Owner" %}{% trans "Sharing" %}{% trans "Created" %}{% trans "Modified" %}{% trans "Stats?" %}
+
+
+
+
+
+
+
+ + + +
+ +
+ +
+ +{% endblock %} + +{% block javaScript %} + {# Add common files #} + {% include "editorTranslations.twig" %} + {% include "editorVars.twig" %} + + + + + + +{% endblock %} diff --git a/custom/otssignange/views/resolution-page.twig b/custom/otssignange/views/resolution-page.twig new file mode 100644 index 0000000..0cd795b --- /dev/null +++ b/custom/otssignange/views/resolution-page.twig @@ -0,0 +1,133 @@ +{# +/** + * Copyright (C) 2020 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 . + */ +#} +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} + +{% block title %}{{ "Resolutions"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("resolution.add") %} + + {% endif %} + +
+{% endblock %} + + +{% block pageContent %} +
+ + +
+
+
+
+
+

{% trans "Filter Resolutions" %}

+ +
+
+
+
+ {% set title %}{% trans "Enabled" %}{% endset %} + {% set option1 %}{% trans "Yes" %}{% endset %} + {% set option2 %}{% trans "No" %}{% endset %} + {% set values = [{id: 1, value: option1}, {id: 0, value: option2}] %} + {{ inline.dropdown("enabled", "single", title, 1, values, "id", "value") }} +
+
+
+
+
+ + + + + + + + + + + + + + +
{% trans "ID" %}{% trans "Resolution" %}{% trans "Width" %}{% trans "Height" %}{% trans "Enabled?" %}
+
+
+
+
+{% endblock %} + +{% block javaScript %} + +{% endblock %} diff --git a/custom/otssignange/views/schedule-page.twig b/custom/otssignange/views/schedule-page.twig new file mode 100644 index 0000000..2090c0b --- /dev/null +++ b/custom/otssignange/views/schedule-page.twig @@ -0,0 +1,355 @@ +{# +/** + * 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 . + */ +#} +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} +{% import "forms.twig" as forms %} + +{% block title %}{{ "Schedule"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("schedule.add") %} + + {% endif %} + +
+{% endblock %} + +{% block pageContent %} +
+ + +
+
+
+
+
+

{% trans "Filter Schedule" %}

+ +
+
+
+ +
+
+
+ {% set title %}{% trans "Range" %}{% endset %} + {% set range %}{% trans "Custom" %}{% endset %} + {% set day %}{% trans "Day" %}{% endset %} + {% set week %}{% trans "Week" %}{% endset %} + {% set month %}{% trans "Month" %}{% endset %} + {% set year %}{% trans "Year" %}{% endset %} + {% set options = [ + { name: "custom", range: range }, + { name: "day", range: day }, + { name: "week", range: week }, + { name: "month", range: month }, + { name: "year", range: year }, + ] %} + {{ inline.dropdown("range", "single", title, "month", options, "name", "range", "", "date-range-input") }} + + {% set title %}{% trans 'From Date' %}{% endset %} + {{ inline.dateTime("fromDt", title, "", "", "custom-date-range d-none", "", "") }} + + {% set title %}{% trans 'To Date' %}{% endset %} + {{ inline.dateTime("toDt", title, "", "", "custom-date-range d-none", "", "") }} + + {% set title %}{% trans "Date Controls" %}{% endset %} +
+
{{ title }}
+
+
+ + + + +
+
+ + + +
+
+
+ + {% set title %}{% trans "Name" %}{% endset %} + {{ inline.inputNameGrid('name', title) }} + + {% set title %}{% trans 'Event Type' %}{% endset %} + {{ inline.dropdown("eventTypeId", "single", title, "", [{eventTypeId: null, eventTypeName: "All"}]|merge(eventTypes), "eventTypeId", "eventTypeName") }} + + {% set title %}{% trans "Layout / Campaign" %}{% endset %} + {% set helpText %}{% trans "Please select a Layout or Campaign for this Event to show" %}{% endset %} + +
+ + +
+ + {% set title %}{% trans "Displays" %}{% endset %} +
+ + +
+ + {% set title %}{% trans "Display Groups" %}{% endset %} +
+ + +
+
+ +
+ {% set label %}{% trans "Direct Schedule?" %}{% endset %} + {% set title %}{% trans "Show only events scheduled directly on selected Displays/Groups" %}{% endset %} +
+
+ + +
+
+ + {% set title %}{% trans "Only show schedules which appear on all filtered displays/groups?" %}{% endset %} + {% set label %}{% trans "Shared Schedule?" %}{% endset %} +
+
+ + +
+
+ + {% set title %}{% trans 'Geo Aware?' %}{% endset %} + {% set options = [ + { id: null, name: "Both"|trans }, + { id: 0, name: "No"|trans }, + { id: 1, name: "Yes"|trans } + ] %} + {{ inline.dropdown("geoAware", "single", title, "both", options, "id", "name") }} + + {% set title %}{% trans 'Recurring?' %}{% endset %} + {% set options = [ + { id: null, name: "Both" }, + { id: 0, name: "No"|trans }, + { id: 1, name: "Yes"|trans } + ] %} + {{ inline.dropdown("recurring", "single", title, "both", options, "id", "name") }} +
+
+
+
+
+
+ +
+ + +
+
+
+

+
+ +
+ + +
+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{% trans 'ID' %}{% trans 'Event Type' %}{% trans 'Name' %}{% trans 'Start' %}{% trans 'End' %}{% trans 'Event' %}{% trans 'Campaign ID' %}{% trans 'Display Groups' %}{% trans 'SoV' %}{% trans 'Max Plays per Hour' %}{% trans 'Geo Aware?' %}{% trans 'Recurring?' %}{% trans 'Recurrence Description' %}{% trans 'Recurrence Type' %}{% trans 'Recurrence Interval' %}{% trans 'Recurrence Repeats On' %}{% trans 'Recurrence End' %}{% trans 'Priority?' %}{% trans 'Criteria?' %}{% trans 'Created On' %}{% trans 'Updated On' %}{% trans 'Modified By' %}
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • {% trans "Always showing" %}
  • +
  • {% trans "Single Display" %}
  • +
  • {% trans "Multi Display" %}
  • +
  • {% trans "Priority" %}
  • +
  • {% trans "Recurring" %}
  • +
  • {% trans "View Only" %}
  • +
  • {% trans "Command" %}
  • +
  • {% trans "Interrupt" %}
  • +
  • {% trans "Geo Location" %}
  • +
  • {% trans "Interactive Action" %} +
  • +
  • {% trans "Synchronised" %}
  • +
+
+
+
+
+
+
+
+
+
+{% endblock %} + +{% block javaScript %} + {# Initialise JS variables #} + + + {# Add page source code bundle ( JS ) #} + + +{% endblock %} diff --git a/custom/otssignange/views/syncgroup-page.twig b/custom/otssignange/views/syncgroup-page.twig new file mode 100644 index 0000000..5ec20bc --- /dev/null +++ b/custom/otssignange/views/syncgroup-page.twig @@ -0,0 +1,190 @@ +{# +/** + * Copyright (C) 2024 Xibo Signage Ltd + * + * Xibo - Digital Signage - https://xibosignage.com + * + * This file is part of Xibo. + * + * Xibo is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * Xibo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Xibo. If not, see . + */ +#} +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} + +{% block title %}{{ "Sync Groups"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("display.syncAdd") %} + + {% endif %} + +
+{% endblock %} + +{% block pageContent %} +
+ + +
+
+
+
+
+

{% trans "Filter Sync Groups" %}

+ +
+
+
+
+ {% set title %}{% trans "ID" %}{% endset %} + {{ inline.input("syncGroupId", title) }} + + {% set title %}{% trans "Name" %}{% endset %} + {{ inline.inputNameGrid('name', title) }} + + {% set title %}{% trans "Lead Display ID" %}{% endset %} + {{ inline.input("leadDisplayId", title) }} + + {{ inline.hidden("folderId") }} +
+
+
+
+ +
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
+
+
+ + +
+
+
+ + + + + + + + + + + + + + + + + + + +
{% trans "ID" %}{% trans "Name" %}{% trans "Created Date" %}{% trans "Modified Date" %}{% trans "Owner" %}{% trans "Modified By" %}{% trans "Publisher Port" %}{% trans "Switch Delay" %}{% trans "Video Pause Delay" %}{% trans "Lead Display" %}
+
+
+
+
+
+
+
+{% endblock %} + +{% block javaScript %} + +{% endblock %} + +{% block javaScriptTemplates %} + {{ parent() }} + + {% verbatim %} + + {% endverbatim %} +{% endblock %} diff --git a/custom/otssignange/views/template-page.twig b/custom/otssignange/views/template-page.twig new file mode 100644 index 0000000..bd36dcd --- /dev/null +++ b/custom/otssignange/views/template-page.twig @@ -0,0 +1,293 @@ +{# +/** + * Copyright (C) 2022 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 . + */ +#} +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} + +{% block title %}{{ "Templates"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("template.add") %} + + {% endif %} + +
+{% endblock %} + +{% block pageContent %} +
+ + +
+
+
+
+
+

{% trans "Filter Templates" %}

+ +
+
+
+
+ {% set title %}{% trans "Name" %}{% endset %} + {{ inline.inputNameGrid('template', title) }} + + {% 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 %} + + {{ inline.hidden("folderId") }} +
+
+
+
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
+
+
+ + +
+
+
+ + + + + + + + {% if currentUser.featureEnabled("tag.tagging") %}{% endif %} + + + + + + + + + +
{% trans "Name" %}{% trans "Status" %}{% trans "Owner" %}{% trans "Description" %}{% trans "Tags" %}{% trans "Orientation" %}{% trans "Thumbnail" %}{% trans "Sharing" %}
+
+
+
+
+
+
+{% endblock %} + +{% block javaScript %} + +
+
+
+
+{% endblock %} \ No newline at end of file diff --git a/custom/otssignange/views/theme-dashboard-message.twig b/custom/otssignange/views/theme-dashboard-message.twig index 79a5877..0d06e22 100644 --- a/custom/otssignange/views/theme-dashboard-message.twig +++ b/custom/otssignange/views/theme-dashboard-message.twig @@ -2,7 +2,4 @@ OTS Signage Theme override Optional dashboard message block included with ignore missing #} -
-
OTS Theme Active
-
This is a low-risk override for troubleshooting. Remove or restyle at any time.
-
+ diff --git a/custom/otssignange/views/theme-scripts.twig b/custom/otssignange/views/theme-scripts.twig index 1a0f74a..630b161 100644 --- a/custom/otssignange/views/theme-scripts.twig +++ b/custom/otssignange/views/theme-scripts.twig @@ -103,6 +103,7 @@ const filterContent = document.querySelector('#ots-filter-content'); if (filterCollapseBtn && filterContent) { + const storageKey = `ots-filter-collapsed:${window.location.pathname}`; let isCollapsed = false; filterCollapseBtn.addEventListener('click', function() { @@ -115,17 +116,19 @@ icon.classList.toggle('fa-chevron-down'); // Save preference to localStorage - localStorage.setItem('ots-filter-collapsed', isCollapsed); + localStorage.setItem(storageKey, isCollapsed); }); // Restore saved preference - const savedState = localStorage.getItem('ots-filter-collapsed'); + const savedState = localStorage.getItem(storageKey); if (savedState === 'true') { isCollapsed = true; filterContent.classList.add('collapsed'); const icon = filterCollapseBtn.querySelector('i'); icon.classList.remove('fa-chevron-up'); icon.classList.add('fa-chevron-down'); + } else { + filterContent.classList.remove('collapsed'); } } diff --git a/tmp/xibo-campaign-page.twig b/tmp/xibo-campaign-page.twig new file mode 100644 index 0000000..b96e2c3 --- /dev/null +++ b/tmp/xibo-campaign-page.twig @@ -0,0 +1,173 @@ +{# +/** + * Copyright (C) 2020 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 . + */ +#} +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} + +{% block title %}{{ "Campaigns"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("campaign.add") %} + + {% endif %} + +
+{% endblock %} + +{% block pageContent %} +
+
{% trans "Campaigns" %}
+
+
+
+
+
+ {% set title %}{% trans "Name" %}{% endset %} + {{ inline.inputNameGrid('name', title) }} + + {% 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 %} + + {% set title %}{% trans "Layouts" %}{% endset %} + {% set values = [{id: 0, value: ""}, {id: 2, value: "Yes"}, {id: 1, value: "No"}] %} + {{ inline.dropdown("hasLayouts", "single", title, 0, values, "id", "value") }} + + {{ inline.hidden("folderId") }} + + {% set title %}{% trans "Layout ID" %}{% endset %} + {{ inline.number("layoutId", title, layoutId) }} + + {% if currentUser.featureEnabled('ad.campaign') %} + {% set title %}{% trans "Type" %}{% endset %} + {% set options = [ + { id: null, name: "" }, + { id: "list", name: "Layout list"|trans }, + { id: "ad", name: "Ad Campaign"|trans } + ] %} + {{ inline.dropdown("type", "single", title, "both", options, "id", "name", helpText) }} + {% endif %} + + {% set title %}{% trans "Cycle Based Playback" %}{% endset %} + {% set enabled %}{% trans "Enabled" %}{% endset %} + {% set disabled %}{% trans "Disabled" %}{% endset %} + {% set options = [ + { optionid: "", option: "" }, + { optionid: 0, option: disabled}, + { optionid: 1, option: enabled} + ] %} + {{ inline.dropdown("cyclePlaybackEnabled", "single", title, "", options, "optionid", "option") }} +
+
+
+ +
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
+
+
+ + +
+
+
+ + + + + {% if currentUser.featureEnabled('ad.campaign') %} + + + + {% endif %} + + {% if currentUser.featureEnabled("tag.tagging") %}{% endif %} + + + + {% if currentUser.featureEnabled('ad.campaign') %} + + + + + + {% endif %} + + + + + + + + + + + + + + +
{% trans "Name" %}{% trans "Type" %}{% trans "Start Date" %}{% trans "End Date" %}{% trans "# Layouts" %}{% trans "Tags" %}{% trans "Duration" %}{% trans "Cycle based Playback" %}{% trans "Play Count" %}{% trans "Target Type" %}{% trans "Target" %}{% trans "Plays" %}{% trans "Spend" %}{% trans "Impressions" %}{% trans "Ref 1" %}{% trans "Ref 2" %}{% trans "Ref 3" %}{% trans "Ref 4" %}{% trans "Ref 5" %}{% trans "Created At" %}{% trans "Modified At" %}{% trans "Modified By" %}
+
+
+
+
+
+
+{% endblock %} + +{% block javaScript %} + {# Initialise JS variables and translations #} + + + {# Add page source code bundle #} + +{% endblock %} diff --git a/tmp/xibo-context-menu.twig b/tmp/xibo-context-menu.twig new file mode 100644 index 0000000..1becba2 --- /dev/null +++ b/tmp/xibo-context-menu.twig @@ -0,0 +1 @@ +404: Not Found \ No newline at end of file diff --git a/tmp/xibo-dataset-page.twig b/tmp/xibo-dataset-page.twig new file mode 100644 index 0000000..969177d --- /dev/null +++ b/tmp/xibo-dataset-page.twig @@ -0,0 +1,584 @@ +{# +/** + * Copyright (C) 2020 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 . + */ +#} +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} +{% import "forms.twig" as forms %} + +{% block title %}{{ "DataSets"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("dataset.add") %} + + {% endif %} + +
+{% endblock %} + +{% block pageContent %} +
+
{% trans "DataSets" %}
+
+
+
+
+
+ {% set title %}{% trans "Name" %}{% endset %} + {{ inline.inputNameGrid('dataSet', title) }} + + {% set title %}{% trans "Code" %}{% endset %} + {% set helpText %}{% trans "Show items which match the provided code" %}{% endset %} + {{ inline.input("code", title, "", helpText) }} + + {% set title %}{% trans "Owner" %}{% endset %} + {% set helpText %}{% trans "Show items owned by the selected User." %}{% endset %} + {% set attributes = [ + { name: "data-width", value: "200px" }, + { name: "data-allow-clear", value: "true" }, + { name: "data-placeholder--id", value: null }, + { name: "data-placeholder--value", value: "" }, + { name: "data-search-url", value: url_for("user.search") }, + { name: "data-search-term", value: "userName" }, + { name: "data-search-term-tags", value: "tags" }, + { name: "data-id-property", value: "userId" }, + { name: "data-text-property", value: "userName" }, + { name: "data-initial-key", value: "userId" }, + ] %} + {{ inline.dropdown("userId", "single", title, "", null, "userId", "userName", helpText, "pagedSelect", "", "", "", attributes) }} + + {{ inline.hidden("folderId") }} +
+
+
+ +
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
+
+
+ + +
+
+
+ + + + + + + + + + + + + + + + + + + +
{% trans "ID" %}{% trans "Name" %}{% trans "Description" %}{% trans "Code" %}{% trans "Remote?" %}{% trans "Real time?" %}{% trans "Owner" %}{% trans "Sharing" %}{% trans "Last Sync" %}{% trans "Data Last Modified" %}
+
+
+
+
+
+
+{% endblock %} + +{% block javaScript %} + +{% endblock %} + +{% block javaScriptTemplates %} + {{ parent() }} + + {% verbatim %} + + + + + + + + + {% endverbatim %} +{% endblock %} \ No newline at end of file diff --git a/tmp/xibo-daypart-page.twig b/tmp/xibo-daypart-page.twig new file mode 100644 index 0000000..874faa3 --- /dev/null +++ b/tmp/xibo-daypart-page.twig @@ -0,0 +1,248 @@ +{# +/** + * Copyright (C) 2020 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 . + */ +#} +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} + +{% block title %}{{ "Dayparting"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("daypart.add") %} + + {% endif %} + +
+{% endblock %} + +{% block pageContent %} +
+
{% trans "Dayparting" %}
+
+
+
+
+
+ {% set title %}{% trans "Name" %}{% endset %} + {{ inline.inputNameGrid('name', title) }} + + {% set title %}{% trans "Retired" %}{% endset %} + {% set option1 = "Yes"|trans %} + {% set option2 = "No"|trans %} + {% set values = [{id: 1, value: option1}, {id: 0, value: option2}] %} + {{ inline.dropdown("isRetired", "single", title, 0, values, "id", "value") }} +
+
+
+
+ + + + + + + + + + + + + +
{% trans "Name" %}{% trans "Description" %}{% trans "Start Time" %}{% trans "End Time" %}
+
+
+
+
+{% endblock %} + +{% block javaScript %} + + {% verbatim %} + + {% endverbatim %} +{% endblock %} \ No newline at end of file diff --git a/tmp/xibo-layout-page.twig b/tmp/xibo-layout-page.twig new file mode 100644 index 0000000..11c905f --- /dev/null +++ b/tmp/xibo-layout-page.twig @@ -0,0 +1,523 @@ +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} + +{% block title %}{{ "Layouts"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("layout.add") %} + + + {% endif %} + +
+{% endblock %} + +{% block pageContent %} +
+
{% trans "Layouts" %}
+
+
+
+
+ +
+
+
+ {% set title %}{% trans "ID" %}{% endset %} + {{ inline.number("campaignId", title) }} + + {% set title %}{% trans "Name" %}{% endset %} + {{ inline.inputNameGrid('layout', title) }} + + {% 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 %} + + {% set title %}{% trans "Code" %}{% endset %} + {{ inline.input('codeLike', title) }} + + {% if currentUser.featureEnabled("displaygroup.view") %} + {% set title %}{% trans "Display Group" %}{% endset %} + {% set helpText %}{% trans "Show Layouts active on the selected Display / Display Group" %}{% endset %} + {% set attributes = [ + { name: "data-width", value: "200px" }, + { 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":-1}' }, + { 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("activeDisplayGroupId", "single", title, "", null, "displayGroupId", "displayGroup", helpText, "pagedSelect", "", "", "", attributes) }} + {% endif %} + + {% set title %}{% trans "Owner" %}{% endset %} + {% set helpText %}{% trans "Show items owned by the selected User." %}{% endset %} + {% set attributes = [ + { name: "data-width", value: "200px" }, + { name: "data-allow-clear", value: "true" }, + { name: "data-placeholder--id", value: null }, + { name: "data-placeholder--value", value: "" }, + { name: "data-search-url", value: url_for("user.search") }, + { name: "data-search-term", value: "userName" }, + { name: "data-search-term-tags", value: "tags" }, + { name: "data-id-property", value: "userId" }, + { name: "data-text-property", value: "userName" }, + { name: "data-initial-key", value: "userId" }, + ] %} + {{ inline.dropdown("userId", "single", title, "", null, "userId", "userName", helpText, "pagedSelect", "", "", "", attributes) }} + + {% set title %}{% trans "Owner User Group" %}{% endset %} + {% set helpText %}{% trans "Show items owned by users in the selected User Group." %}{% endset %} + {% set attributes = [ + { name: "data-width", value: "200px" }, + { name: "data-allow-clear", value: "true" }, + { name: "data-placeholder--id", value: null }, + { name: "data-placeholder--value", value: "" }, + { name: "data-search-url", value: url_for("group.search") }, + { name: "data-search-term", value: "group" }, + { name: "data-id-property", value: "groupId" }, + { name: "data-text-property", value: "group" }, + { name: "data-initial-key", value: "userGroupId" }, + ] %} + {{ inline.dropdown("ownerUserGroupId", "single", title, "", null, "groupId", "group", helpText, "pagedSelect", "", "", "", attributes) }} + + {% set title %}{% trans "Orientation" %}{% endset %} + {% set option1 = "All"|trans %} + {% set option2 = "Landscape"|trans %} + {% set option3 = "Portrait"|trans %} + {% set values = [{id: '', value: option1}, {id: 'landscape', value: option2}, {id: 'portrait', value: option3}] %} + {{ inline.dropdown("orientation", "single", title, '', values, "id", "value") }} + + {{ inline.hidden("folderId") }} +
+
+ {% set title %}{% trans "Retired" %}{% endset %} + {% set option1 = "No"|trans %} + {% set option2 = "Yes"|trans %} + {% set values = [{id: 0, value: option1}, {id: 1, value: option2}] %} + {{ inline.dropdown("retired", "single", title, 0, values, "id", "value") }} + + {% set title %}{% trans "Show" %}{% endset %} + {% set option1 = "All"|trans %} + {% set option2 = "Only Used"|trans %} + {% set option3 = "Only Unused"|trans %} + {% set values = [{id: 1, value: option1}, {id: 2, value: option2}, {id: 3, value: option3}] %} + {{ inline.dropdown("layoutStatusId", "single", title, 1, values, "id", "value") }} + + {% set title %}{% trans "Description" %}{% endset %} + {% set option1 = "All"|trans %} + {% set option2 = "1st line"|trans %} + {% set option3 = "Widget List"|trans %} + {% set values = [{id: 1, value: option1}, {id: 2, value: option2}, {id: 3, value: option3}] %} + {{ inline.dropdown("showDescriptionId", "single", title, 2, values, "id", "value") }} + + {% if currentUser.featureEnabled("library.view") %} + {% set title %}{% trans "Media" %}{% endset %} + {{ inline.input("mediaLike", title) }} + {% endif %} + + {% set title %}{% trans "Layout ID" %}{% endset %} + {{ inline.number("layoutId", title) }} + + {% set title %}{% trans "Modified Since" %}{% endset %} + {{ inline.date("modifiedSinceDt", title) }} +
+
+
+
+
+ +
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
+
+ +
+ + +
+ +
+
+ + + + + + + + + {% if currentUser.featureEnabled("tag.tagging") %}{% endif %} + + + + + + + + + + + + + + + + +
{% trans "ID" %}{% trans "Name" %}{% trans "Status" %}{% trans "Description" %}{% trans "Duration" %}{% trans "Tags" %}{% trans "Orientation" %}{% trans "Thumbnail" %}{% trans "Owner" %}{% trans "Sharing" %}{% trans "Valid?" %}{% trans "Stats?" %}{% trans "Created" %}{% trans "Modified" %}{% trans "Layout ID" %}{% trans "Code" %}
+
+
+
+
+
+
+{% endblock %} + +{% block javaScript %} + +{% endblock %} diff --git a/tmp/xibo-menuboard-page.twig b/tmp/xibo-menuboard-page.twig new file mode 100644 index 0000000..95df3e1 --- /dev/null +++ b/tmp/xibo-menuboard-page.twig @@ -0,0 +1,194 @@ +{# +/** + * Copyright (C) 2022 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 . + */ +#} +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} + +{% block title %}{{ "Menu Boards"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("menuBoard.add") %} + + {% endif %} + +
+{% endblock %} + +{% block pageContent %} +
+
{% trans "Menu Boards" %}
+
+
+
+
+
+ {% set title %}{% trans "ID" %}{% endset %} + {{ inline.number("menuId", title) }} + + {% set title %}{% trans "Name" %}{% endset %} + {{ inline.inputNameGrid('name', title) }} + + {% set title %}{% trans "Code" %}{% endset %} + {{ inline.input('code', title) }} + + {% set title %}{% trans "Owner" %}{% endset %} + {% set helpText %}{% trans "Show items owned by the selected User." %}{% endset %} + {% set attributes = [ + { name: "data-width", value: "200px" }, + { name: "data-allow-clear", value: "true" }, + { name: "data-placeholder--id", value: null }, + { name: "data-placeholder--value", value: "" }, + { name: "data-search-url", value: url_for("user.search") }, + { name: "data-search-term", value: "userName" }, + { name: "data-search-term-tags", value: "tags" }, + { name: "data-id-property", value: "userId" }, + { name: "data-text-property", value: "userName" }, + { name: "data-initial-key", value: "userId" }, + ] %} + {{ inline.dropdown("userId", "single", title, "", null, "userId", "userName", helpText, "pagedSelect", "", "", "", attributes) }} + + {{ inline.hidden("folderId") }} +
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
+
+
+
+ + + + + + + + + + + + + + + + + +
+
+
+
+
+
+{% endblock %} + +{% block javaScript %} + +{% endblock %} \ No newline at end of file diff --git a/tmp/xibo-resolution-page.twig b/tmp/xibo-resolution-page.twig new file mode 100644 index 0000000..c2e2bfa --- /dev/null +++ b/tmp/xibo-resolution-page.twig @@ -0,0 +1,120 @@ +{# +/** + * Copyright (C) 2020 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 . + */ +#} +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} + +{% block title %}{{ "Resolutions"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("resolution.add") %} + + {% endif %} + +
+{% endblock %} + + +{% block pageContent %} +
+
{% trans "Resolution" %}
+
+
+
+
+
+ {% set title %}{% trans "Enabled" %}{% endset %} + {% set option1 %}{% trans "Yes" %}{% endset %} + {% set option2 %}{% trans "No" %}{% endset %} + {% set values = [{id: 1, value: option1}, {id: 0, value: option2}] %} + {{ inline.dropdown("enabled", "single", title, 1, values, "id", "value") }} +
+
+
+
+ + + + + + + + + + + + + + +
{% trans "ID" %}{% trans "Resolution" %}{% trans "Width" %}{% trans "Height" %}{% trans "Enabled?" %}
+
+
+
+
+{% endblock %} + +{% block javaScript %} + +{% endblock %} \ No newline at end of file diff --git a/tmp/xibo-schedule-page.twig b/tmp/xibo-schedule-page.twig new file mode 100644 index 0000000..09b466e --- /dev/null +++ b/tmp/xibo-schedule-page.twig @@ -0,0 +1,342 @@ +{# +/** + * 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 . + */ +#} +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} +{% import "forms.twig" as forms %} + +{% block title %}{{ "Schedule"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("schedule.add") %} + + {% endif %} + +
+{% endblock %} + +{% block pageContent %} +
+
{% trans "Schedule" %}
+
+
+
+
+ +
+
+
+ {% set title %}{% trans "Range" %}{% endset %} + {% set range %}{% trans "Custom" %}{% endset %} + {% set day %}{% trans "Day" %}{% endset %} + {% set week %}{% trans "Week" %}{% endset %} + {% set month %}{% trans "Month" %}{% endset %} + {% set year %}{% trans "Year" %}{% endset %} + {% set options = [ + { name: "custom", range: range }, + { name: "day", range: day }, + { name: "week", range: week }, + { name: "month", range: month }, + { name: "year", range: year }, + ] %} + {{ inline.dropdown("range", "single", title, "month", options, "name", "range", "", "date-range-input") }} + + {% set title %}{% trans 'From Date' %}{% endset %} + {{ inline.dateTime("fromDt", title, "", "", "custom-date-range d-none", "", "") }} + + {% set title %}{% trans 'To Date' %}{% endset %} + {{ inline.dateTime("toDt", title, "", "", "custom-date-range d-none", "", "") }} + + {% set title %}{% trans "Date Controls" %}{% endset %} +
+
{{ title }}
+
+
+ + + + +
+
+ + + +
+
+
+ + {% set title %}{% trans "Name" %}{% endset %} + {{ inline.inputNameGrid('name', title) }} + + {% set title %}{% trans 'Event Type' %}{% endset %} + {{ inline.dropdown("eventTypeId", "single", title, "", [{eventTypeId: null, eventTypeName: "All"}]|merge(eventTypes), "eventTypeId", "eventTypeName") }} + + {% set title %}{% trans "Layout / Campaign" %}{% endset %} + {% set helpText %}{% trans "Please select a Layout or Campaign for this Event to show" %}{% endset %} + +
+ + +
+ + {% set title %}{% trans "Displays" %}{% endset %} +
+ + +
+ + {% set title %}{% trans "Display Groups" %}{% endset %} +
+ + +
+
+ +
+ {% set label %}{% trans "Direct Schedule?" %}{% endset %} + {% set title %}{% trans "Show only events scheduled directly on selected Displays/Groups" %}{% endset %} +
+
+ + +
+
+ + {% set title %}{% trans "Only show schedules which appear on all filtered displays/groups?" %}{% endset %} + {% set label %}{% trans "Shared Schedule?" %}{% endset %} +
+
+ + +
+
+ + {% set title %}{% trans 'Geo Aware?' %}{% endset %} + {% set options = [ + { id: null, name: "Both"|trans }, + { id: 0, name: "No"|trans }, + { id: 1, name: "Yes"|trans } + ] %} + {{ inline.dropdown("geoAware", "single", title, "both", options, "id", "name") }} + + {% set title %}{% trans 'Recurring?' %}{% endset %} + {% set options = [ + { id: null, name: "Both" }, + { id: 0, name: "No"|trans }, + { id: 1, name: "Yes"|trans } + ] %} + {{ inline.dropdown("recurring", "single", title, "both", options, "id", "name") }} +
+
+
+
+
+ +
+ + +
+
+
+

+
+ +
+ + +
+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{% trans 'ID' %}{% trans 'Event Type' %}{% trans 'Name' %}{% trans 'Start' %}{% trans 'End' %}{% trans 'Event' %}{% trans 'Campaign ID' %}{% trans 'Display Groups' %}{% trans 'SoV' %}{% trans 'Max Plays per Hour' %}{% trans 'Geo Aware?' %}{% trans 'Recurring?' %}{% trans 'Recurrence Description' %}{% trans 'Recurrence Type' %}{% trans 'Recurrence Interval' %}{% trans 'Recurrence Repeats On' %}{% trans 'Recurrence End' %}{% trans 'Priority?' %}{% trans 'Criteria?' %}{% trans 'Created On' %}{% trans 'Updated On' %}{% trans 'Modified By' %}
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • {% trans "Always showing" %}
  • +
  • {% trans "Single Display" %}
  • +
  • {% trans "Multi Display" %}
  • +
  • {% trans "Priority" %}
  • +
  • {% trans "Recurring" %}
  • +
  • {% trans "View Only" %}
  • +
  • {% trans "Command" %}
  • +
  • {% trans "Interrupt" %}
  • +
  • {% trans "Geo Location" %}
  • +
  • {% trans "Interactive Action" %} +
  • +
  • {% trans "Synchronised" %}
  • +
+
+
+
+
+
+
+
+
+
+{% endblock %} + +{% block javaScript %} + {# Initialise JS variables #} + + + {# Add page source code bundle ( JS ) #} + + +{% endblock %} \ No newline at end of file diff --git a/tmp/xibo-table-context-menu.twig b/tmp/xibo-table-context-menu.twig new file mode 100644 index 0000000..1becba2 --- /dev/null +++ b/tmp/xibo-table-context-menu.twig @@ -0,0 +1 @@ +404: Not Found \ No newline at end of file diff --git a/tmp/xibo-template-page-new.twig b/tmp/xibo-template-page-new.twig new file mode 100644 index 0000000..8144c21 --- /dev/null +++ b/tmp/xibo-template-page-new.twig @@ -0,0 +1,277 @@ +{# +/** + * Copyright (C) 2022 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 . + */ +#} +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} + +{% block title %}{{ "Templates"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("template.add") %} + + {% endif %} + +
+{% endblock %} + +{% block pageContent %} +
+
{% trans "Templates" %}
+
+
+
+
+
+ {% set title %}{% trans "Name" %}{% endset %} + {{ inline.inputNameGrid('template', title) }} + + {% 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 %} + + {{ inline.hidden("folderId") }} +
+
+
+
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
+
+
+ + +
+
+
+ + + + + + + + {% if currentUser.featureEnabled("tag.tagging") %}{% endif %} + + + + + + + + + +
{% trans "Name" %}{% trans "Status" %}{% trans "Owner" %}{% trans "Description" %}{% trans "Tags" %}{% trans "Orientation" %}{% trans "Thumbnail" %}{% trans "Sharing" %}
+
+
+
+
+
+
+{% endblock %} + +{% block javaScript %} + +{% endblock %} \ No newline at end of file diff --git a/tmp/xibo-template-page.twig b/tmp/xibo-template-page.twig new file mode 100644 index 0000000..8144c21 --- /dev/null +++ b/tmp/xibo-template-page.twig @@ -0,0 +1,277 @@ +{# +/** + * Copyright (C) 2022 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 . + */ +#} +{% extends "authed.twig" %} +{% import "inline.twig" as inline %} + +{% block title %}{{ "Templates"|trans }} | {% endblock %} + +{% block actionMenu %} +
+ {% if currentUser.featureEnabled("template.add") %} + + {% endif %} + +
+{% endblock %} + +{% block pageContent %} +
+
{% trans "Templates" %}
+
+
+
+
+
+ {% set title %}{% trans "Name" %}{% endset %} + {{ inline.inputNameGrid('template', title) }} + + {% 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 %} + + {{ inline.hidden("folderId") }} +
+
+
+
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
+
+
+ + +
+
+
+ + + + + + + + {% if currentUser.featureEnabled("tag.tagging") %}{% endif %} + + + + + + + + + +
{% trans "Name" %}{% trans "Status" %}{% trans "Owner" %}{% trans "Description" %}{% trans "Tags" %}{% trans "Orientation" %}{% trans "Thumbnail" %}{% trans "Sharing" %}
+
+
+
+
+
+
+{% endblock %} + +{% block javaScript %} + +{% endblock %} \ No newline at end of file