Lumi/plugins/throne_wishlist/views/admin.ejs
2026-06-16 08:30:40 +02:00

227 lines
10 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<%- include("../../../src/web/views/partials/layout-top", { title }) %>
<link rel="stylesheet" href="/plugins/throne_wishlist/assets/admin.css?v=<%= assetVersion %>" />
<% const destinationMap = new Map(destinations.map((item) => [item.platform, item])); %>
<% const templateMap = new Map(templates.map((item) => [item.event_type + ":" + item.platform, item])); %>
<% const statusMap = new Map(platformStatus.map((item) => [item.id, item])); %>
<header class="throne-header">
<div>
<h1>Throne Wishlist</h1>
<p>Verified wishlist events and cross-platform notifications.</p>
</div>
<button type="button" class="button subtle" data-debug-open>Debug</button>
</header>
<section class="card">
<div class="section-header">
<div>
<h2>Diagnostics</h2>
<p class="hint">Core availability and public delivery readiness.</p>
</div>
</div>
<div class="diagnostic-grid">
<div><span>Webhook framework</span><strong><%= webhookAvailable ? "Available" : "Unavailable" %></strong></div>
<div><span>Public base URL</span><strong><%= publicBaseUrl %></strong></div>
<% platformStatus.forEach((platform) => { %>
<div><span><%= platform.label %></span><strong><%= platform.sendAvailable ? "Ready" : "Unavailable" %></strong><small><%= platform.diagnostic %></small></div>
<% }) %>
</div>
<% if (publicBaseUrlWarning) { %>
<div class="callout"><%= publicBaseUrlWarning %></div>
<% } %>
<% if (!webhookAvailable) { %>
<div class="callout">Install and restart with the core webhook framework patch before creating endpoints.</div>
<% } %>
</section>
<section class="card">
<div class="section-header">
<div>
<h2>Endpoints</h2>
<p class="hint">Create multiple subscriber URLs and paste them into Throne.</p>
</div>
</div>
<form method="post" action="/plugins/throne_wishlist/endpoints/create" class="inline-form">
<div class="field">
<label for="throne-identifier">Identifier</label>
<input id="throne-identifier" name="identifier" required placeholder="cozy-carnage" />
</div>
<button type="submit" class="button" <%= webhookAvailable ? "" : "disabled" %>>Create endpoint</button>
</form>
<% if (!endpoints.length) { %>
<p>No Throne endpoints configured.</p>
<% } else { %>
<div class="table-wrap">
<table class="table throne-table">
<thead>
<tr>
<th>Identifier</th>
<th>UUID</th>
<th>Link</th>
<th>Last payload</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% endpoints.forEach((endpoint) => { %>
<tr>
<td><strong><%= endpoint.identifier %></strong></td>
<td><code><%= endpoint.uuid %></code></td>
<td>
<div class="copy-row">
<input value="<%= endpoint.publicUrl %>" readonly data-copy-source="<%= endpoint.id %>" aria-label="Webhook URL for <%= endpoint.identifier %>" />
<button type="button" class="icon-button" data-copy-button="<%= endpoint.id %>" title="Copy webhook URL" aria-label="Copy webhook URL">
<span aria-hidden="true">⧉</span>
</button>
</div>
<small class="copy-status" data-copy-status="<%= endpoint.id %>" aria-live="polite"></small>
</td>
<td>
<% if (endpoint.last_payload_preview) { %>
<% let preview = {}; try { preview = JSON.parse(endpoint.last_payload_preview); } catch {} %>
<strong><%= preview.event_type || "unknown" %></strong>
<small><%= preview.event_id || "No event id" %></small>
<small><%= preview.authentic ? "Authentic" : "Rejected" %> · <%= formatTimestamp(endpoint.last_payload_at) %></small>
<% } else { %>
<span>Never</span>
<% } %>
</td>
<td>
<div class="action-row">
<button type="button" class="button subtle" data-confirm-open data-confirm-title="Renew endpoint?" data-confirm-text="The current Throne URL will stop working immediately." data-confirm-action="/plugins/throne_wishlist/endpoints/<%= endpoint.id %>/renew">Renew</button>
<button type="button" class="button subtle danger" data-confirm-open data-confirm-title="Remove endpoint?" data-confirm-text="This endpoint will stop accepting Throne payloads." data-confirm-action="/plugins/throne_wishlist/endpoints/<%= endpoint.id %>/remove">Remove</button>
</div>
</td>
</tr>
<% }) %>
</tbody>
</table>
</div>
<% } %>
</section>
<section class="card">
<div class="section-header">
<div>
<h2>Platform Destinations</h2>
<p class="hint">Only destinations with a working Lumi send capability can be enabled.</p>
</div>
</div>
<form method="post" action="/plugins/throne_wishlist/destinations" class="destination-grid">
<% const availablePlatforms = platformStatus.filter((platform) => platform.sendAvailable); %>
<% if (!availablePlatforms.length) { %>
<p>No active platform sender is currently available.</p>
<% } %>
<% availablePlatforms.forEach((platform) => { const destination = destinationMap.get(platform.id); %>
<fieldset class="destination-panel">
<legend><%= platform.label %></legend>
<label class="switch">
<input type="checkbox" class="switch-input" name="enabled_platforms" value="<%= platform.id %>" <%= destination?.enabled ? "checked" : "" %> />
<span class="switch-track" aria-hidden="true"></span>
<span class="switch-text"><%= destination?.enabled ? "Enabled" : "Disabled" %></span>
</label>
<% if (platform.id === "discord") { %>
<div class="field">
<label for="discord-destination">Text channel</label>
<select id="discord-destination" name="discord_destination_id">
<option value="">Select a regular text channel</option>
<% discordChannels.forEach((channel) => { %>
<option value="<%= channel.id %>" <%= destination?.destination_id === channel.id ? "selected" : "" %>><%= channel.label %></option>
<% }) %>
</select>
</div>
<% } %>
<small><%= platform.diagnostic %></small>
</fieldset>
<% }) %>
<div class="field full">
<button type="submit" class="button">Save destinations</button>
</div>
</form>
</section>
<section class="card">
<div class="section-header">
<div>
<h2>Event Messages</h2>
<p class="hint">One message per event and platform. Unknown placeholders remain unchanged.</p>
</div>
</div>
<details class="placeholder-list">
<summary>Available placeholders</summary>
<div>
<% placeholders.forEach((placeholder) => { %><code>{<%= placeholder %>}</code> <% }) %>
</div>
</details>
<div class="event-sections">
<% eventTypes.forEach((eventType) => { %>
<section class="event-section">
<h3><%= eventType %></h3>
<div class="template-grid">
<% if (!activePlatforms.length) { %>
<p>No active platform templates are available.</p>
<% } %>
<% activePlatforms.forEach((platform) => { const template = templateMap.get(eventType + ":" + platform); const status = statusMap.get(platform); %>
<details class="template-panel lumi-expandable-settings" data-lumi-expandable-settings>
<summary>
<span>
<strong><%= status?.label || platform %></strong>
<span class="lumi-preview-line" data-placeholder-preview="#template-<%= eventType %>-<%= platform %>" data-fallback="<%= template?.template || "" %>"></span>
</span>
<label class="switch" onclick="event.stopPropagation()">
<input type="checkbox" class="switch-input" disabled <%= template?.enabled ? "checked" : "" %> />
<span class="switch-track" aria-hidden="true"></span>
<span class="switch-text"><%= template?.enabled ? "On" : "Off" %></span>
</label>
</summary>
<form method="post" action="/plugins/throne_wishlist/templates" class="lumi-expandable-body form-grid" data-lumi-settings-form>
<input type="hidden" name="event_type" value="<%= eventType %>" />
<input type="hidden" name="platform" value="<%= platform %>" />
<div class="template-heading field full">
<strong><%= status?.label || platform %></strong>
<label class="switch">
<input type="checkbox" class="switch-input" name="enabled" <%= template?.enabled ? "checked" : "" %> />
<span class="switch-track" aria-hidden="true"></span>
<span class="switch-text"><%= template?.enabled ? "On" : "Off" %></span>
</label>
</div>
<div class="field full">
<label for="template-<%= eventType %>-<%= platform %>">Message</label>
<textarea id="template-<%= eventType %>-<%= platform %>" name="template" rows="4"><%= template?.template || "" %></textarea>
</div>
<button type="submit" class="button subtle">Save <%= status?.label || platform %></button>
</form>
</details>
<% }) %>
</div>
</section>
<% }) %>
</div>
</section>
<div class="modal-backdrop" data-debug-modal aria-hidden="true">
<div class="modal debug-modal" role="dialog" aria-modal="true" aria-labelledby="debug-title">
<div class="modal-header">
<div>
<h3 id="debug-title">Live Throne Payloads</h3>
<p class="hint" data-debug-status>Starting debug session…</p>
</div>
<button type="button" class="icon-button" data-debug-close aria-label="Close debug viewer">×</button>
</div>
<div class="debug-toolbar">
<button type="button" class="icon-button" data-debug-prev aria-label="Previous payload">←</button>
<span data-debug-page>0 / 0</span>
<input type="range" min="1" max="1" value="1" data-debug-slider aria-label="Payload page" />
<button type="button" class="icon-button" data-debug-next aria-label="Next payload">→</button>
</div>
<div class="debug-summary" data-debug-summary>No payloads received during this session.</div>
<pre class="debug-json" data-debug-json>{}</pre>
</div>
</div>
<script src="/plugins/throne_wishlist/assets/admin.js?v=<%= assetVersion %>"></script>
<script src="/plugins/throne_wishlist/assets/debug-modal.js?v=<%= assetVersion %>"></script>
<%- include("../../../src/web/views/partials/layout-bottom") %>