diff --git a/edge-apps/puzzel-dashboard/README.md b/edge-apps/puzzel-dashboard/README.md new file mode 100644 index 000000000..5c3cebb60 --- /dev/null +++ b/edge-apps/puzzel-dashboard/README.md @@ -0,0 +1,37 @@ +# Puzzel Dashboard + +A Screenly Edge App that embeds the [Puzzel](https://www.puzzel.com/) admin dashboard in a full-screen iframe and automatically logs in using injected credentials. + +## How it works + +1. The player loads `index.html`, which renders a full-screen iframe pointing at the configured `dashboard_url`. +2. On each load the player injects `screenly_inject.js` into the dashboard page and supplies the configured credentials via `screenly_settings`. +3. The inject script detects the Puzzel login pages by their input field IDs and fills them automatically — no manual login required on the screen. + +## Settings + +| Key | Type | Description | +| --------------- | ------------ | -------------------------------------------------------------------------------------------------- | +| `dashboard_url` | string (URL) | The URL of the Puzzel dashboard to display (default: `https://app.puzzel.com/admin/app/dashboard`) | +| `username` | string | Puzzel account email (Puzzel ID) | +| `password` | secret | Puzzel account password (stored encrypted) | + +## Login page selectors + +The inject script handles Puzzel's two-step login at `https://app.puzzel.com/id/Account/Login`: + +| Step | Field | Selector | +| ------------ | ----------------- | -------------------------------------------------- | +| 1 – Username | Puzzel ID (email) | `#Input_Username` | +| 1 – Submit | Next button | `button.submit-button[type="submit"]:not(.hidden)` | +| 2 – Password | Password | `#Input_Password` | +| 2 – Submit | Sign-in button | `button.submit-button[type="submit"]:not(.hidden)` | + +The script detects which step is active by checking for the presence of `#Input_Username` or `#Input_Password` — no path matching required. + +## Deploying + +```shell +screenly edge-app create --name puzzel-dashboard --in-place +screenly edge-app deploy +``` diff --git a/edge-apps/puzzel-dashboard/index.html b/edge-apps/puzzel-dashboard/index.html new file mode 100644 index 000000000..da5e7b555 --- /dev/null +++ b/edge-apps/puzzel-dashboard/index.html @@ -0,0 +1,21 @@ + + + + + + Puzzel Dashboard - Screenly Edge App + + + + + + + + + + diff --git a/edge-apps/puzzel-dashboard/screenly.yml b/edge-apps/puzzel-dashboard/screenly.yml new file mode 100644 index 000000000..978cdd10b --- /dev/null +++ b/edge-apps/puzzel-dashboard/screenly.yml @@ -0,0 +1,40 @@ +--- +syntax: manifest_v1 +id: +description: Puzzel Dashboard +icon: https://playground.srly.io/edge-apps/puzzel-dashboard/static/img/icon.svg +author: Screenly, Inc. +categories: + - Dashboards +ready_signal: true +settings: + dashboard_url: + type: string + title: Dashboard URL + optional: false + default_value: 'https://app.puzzel.com/admin/app/dashboard' + help_text: + schema_version: 1 + properties: + help_text: The URL of the dashboard to display. + type: url + password: + type: secret + title: Password + optional: false + default_value: '' + help_text: + schema_version: 1 + properties: + help_text: The password used to log in to the dashboard. + type: string + username: + type: string + title: Puzzel ID + optional: false + default_value: '' + help_text: + schema_version: 1 + properties: + help_text: The username used to log in to the dashboard. + type: string diff --git a/edge-apps/puzzel-dashboard/screenly_inject.js b/edge-apps/puzzel-dashboard/screenly_inject.js new file mode 100644 index 000000000..74f225d7e --- /dev/null +++ b/edge-apps/puzzel-dashboard/screenly_inject.js @@ -0,0 +1,51 @@ +// Injected by the player into the dashboard page on every load. +// `screenly_settings` is provided by the player — no import needed. +// This script runs AFTER the page has fully loaded; DOMContentLoaded has +// already fired. Manipulate the DOM directly. + +/* global screenly_settings, Event */ + +// Set an input's value and notify change listeners. +function setValue(selector, value) { + const el = document.querySelector(selector) + if (!el) return false + el.value = value + el.dispatchEvent(new Event('change', { bubbles: true })) + return true +} + +// ---- Puzzel (app.puzzel.com) ------------------------------------------------ +// Selectors confirmed against https://app.puzzel.com/id/Account/Login +// Two-step login: username first, then password on the next page load. + +// Step 1 — username/Puzzel ID field +if (document.querySelector('#Input_Username')) { + if (!setValue('#Input_Username', screenly_settings.username)) { + console.log('[screenly_inject] Username field not found.') + } else { + const submitBtn = document.querySelector( + 'button.submit-button[type="submit"]:not(.hidden)', + ) + if (submitBtn) { + submitBtn.click() + } else { + console.log('[screenly_inject] Submit button not found.') + } + } +} + +// Step 2 — password field +if (document.querySelector('#Input_Password')) { + if (!setValue('#Input_Password', screenly_settings.password)) { + console.log('[screenly_inject] Password field not found.') + } else { + const submitBtn = document.querySelector( + 'button.submit-button[type="submit"]:not(.hidden)', + ) + if (submitBtn) { + submitBtn.click() + } else { + console.log('[screenly_inject] Submit button not found.') + } + } +} diff --git a/edge-apps/puzzel-dashboard/screenly_qc.yml b/edge-apps/puzzel-dashboard/screenly_qc.yml new file mode 100644 index 000000000..978cdd10b --- /dev/null +++ b/edge-apps/puzzel-dashboard/screenly_qc.yml @@ -0,0 +1,40 @@ +--- +syntax: manifest_v1 +id: +description: Puzzel Dashboard +icon: https://playground.srly.io/edge-apps/puzzel-dashboard/static/img/icon.svg +author: Screenly, Inc. +categories: + - Dashboards +ready_signal: true +settings: + dashboard_url: + type: string + title: Dashboard URL + optional: false + default_value: 'https://app.puzzel.com/admin/app/dashboard' + help_text: + schema_version: 1 + properties: + help_text: The URL of the dashboard to display. + type: url + password: + type: secret + title: Password + optional: false + default_value: '' + help_text: + schema_version: 1 + properties: + help_text: The password used to log in to the dashboard. + type: string + username: + type: string + title: Puzzel ID + optional: false + default_value: '' + help_text: + schema_version: 1 + properties: + help_text: The username used to log in to the dashboard. + type: string diff --git a/edge-apps/puzzel-dashboard/static/css/style.css b/edge-apps/puzzel-dashboard/static/css/style.css new file mode 100644 index 000000000..918bb9f51 --- /dev/null +++ b/edge-apps/puzzel-dashboard/static/css/style.css @@ -0,0 +1,21 @@ +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html, +body { + width: 100%; + height: 100%; + overflow: hidden; +} + +iframe { + display: block; + width: 100%; + height: 100%; + border: none; +} diff --git a/edge-apps/puzzel-dashboard/static/img/icon.svg b/edge-apps/puzzel-dashboard/static/img/icon.svg new file mode 100644 index 000000000..0cc6879f4 --- /dev/null +++ b/edge-apps/puzzel-dashboard/static/img/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/edge-apps/puzzel-dashboard/static/js/main.js b/edge-apps/puzzel-dashboard/static/js/main.js new file mode 100644 index 000000000..8a0ff5827 --- /dev/null +++ b/edge-apps/puzzel-dashboard/static/js/main.js @@ -0,0 +1,14 @@ +/* global screenly */ + +document.addEventListener('DOMContentLoaded', async () => { + const settings = screenly.settings + const url = settings.dashboard_url + + if (!url) { + console.error('Please specify a dashboard URL') + return + } + + document.getElementById('dashboard').src = url + screenly.signalReadyForRendering() +})