feat: full channels.json UI + http_allowlist settings
Notifications page:
- NC Talk section expanded: url, bot_secret, notification_room,
nc_username, nc_app_password — all fields from channels.json now editable
- Per-channel sections use <details>/<summary> collapsibles; auto-open
when values are present
- Secrets use type=password with "leave blank to keep" semantics
- Google Chat outbound webhook in its own collapsible section
Account settings:
- HTTP POST Allowlist section added (same textarea pattern as email allowlist)
- POST /settings/http-allowlist route saves home/{user}/http_allowlist.json
- Example placeholder shows ha.dgrzone.com and n8n patterns
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -46,7 +46,7 @@
|
||||
border-radius: 12px;
|
||||
padding: 2.5rem 2rem;
|
||||
width: 100%;
|
||||
max-width: 480px;
|
||||
max-width: 520px;
|
||||
}
|
||||
|
||||
.page-nav {
|
||||
@@ -109,6 +109,7 @@
|
||||
transition: border-color 0.15s;
|
||||
}
|
||||
input:focus, select:focus { border-color: #7c3aed; }
|
||||
input[type="password"] { font-family: monospace; letter-spacing: 0.05em; }
|
||||
|
||||
.field { margin-bottom: 1rem; }
|
||||
|
||||
@@ -157,7 +158,49 @@
|
||||
}
|
||||
.test-result.ok { background: rgba(74, 222, 128, 0.1); color: #4ade80; border: 1px solid rgba(74, 222, 128, 0.25); }
|
||||
.test-result.err { background: rgba(248, 113, 113, 0.1); color: #f87171; border: 1px solid rgba(248, 113, 113, 0.25); }
|
||||
|
||||
.hint { font-size: 0.78rem; color: var(--pg-dim); margin-top: 0.35rem; line-height: 1.5; }
|
||||
|
||||
/* Channel config blocks */
|
||||
details.channel-block {
|
||||
border: 1px solid var(--pg-border);
|
||||
border-radius: 8px;
|
||||
margin-bottom: 0.75rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
details.channel-block summary {
|
||||
padding: 0.75rem 1rem;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
color: var(--pg-muted);
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
user-select: none;
|
||||
background: var(--pg-bg);
|
||||
}
|
||||
details.channel-block summary::-webkit-details-marker { display: none; }
|
||||
details.channel-block summary::before {
|
||||
content: '▶';
|
||||
font-size: 0.65rem;
|
||||
color: var(--pg-dimmer);
|
||||
transition: transform 0.15s;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
details.channel-block[open] summary::before { transform: rotate(90deg); }
|
||||
details.channel-block[open] summary { border-bottom: 1px solid var(--pg-border); }
|
||||
.channel-block-body {
|
||||
padding: 1rem 1rem 0.25rem;
|
||||
}
|
||||
.channel-hint {
|
||||
font-size: 0.75rem;
|
||||
color: var(--pg-dimmer);
|
||||
margin-top: -0.6rem;
|
||||
margin-bottom: 1rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -179,12 +222,13 @@
|
||||
<!-- SUCCESS -->
|
||||
<!-- ERROR -->
|
||||
|
||||
<!-- Channel config -->
|
||||
<div class="section">
|
||||
<h2>Channel</h2>
|
||||
<form method="POST" action="/settings/notifications">
|
||||
<form method="POST" action="/settings/notifications">
|
||||
|
||||
<!-- Channel selector -->
|
||||
<div class="section">
|
||||
<h2>Channel</h2>
|
||||
<div class="field">
|
||||
<label for="notification_channel">Notification channel</label>
|
||||
<label for="notification_channel">Default outbound channel</label>
|
||||
<select id="notification_channel" name="notification_channel"
|
||||
data-value="{{ notify_channel }}">
|
||||
<option value="">None (disabled)</option>
|
||||
@@ -193,36 +237,118 @@
|
||||
<option value="nextcloud">Nextcloud Talk</option>
|
||||
<option value="google_chat">Google Chat</option>
|
||||
</select>
|
||||
<p class="hint">Used for reminder alerts, distillation summaries, and cron job notifications.</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="notification_email">Email override
|
||||
<label for="notification_email">Email address override
|
||||
<span style="color:var(--pg-dim); font-weight:400;">(optional)</span>
|
||||
</label>
|
||||
<input type="email" id="notification_email" name="notification_email"
|
||||
value="{{ notify_email_override }}"
|
||||
placeholder="Leave blank to use login email"
|
||||
placeholder="Leave blank to use your login email"
|
||||
autocomplete="off">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="nc_notification_room">Nextcloud Talk room token</label>
|
||||
<input type="text" id="nc_notification_room" name="nc_notification_room"
|
||||
value="{{ nc_notify_room }}"
|
||||
placeholder="Token from the Talk room URL"
|
||||
autocomplete="off" spellcheck="false">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="gc_outbound_webhook">Google Chat webhook URL</label>
|
||||
<input type="url" id="gc_outbound_webhook" name="gc_outbound_webhook"
|
||||
value="{{ gc_webhook }}"
|
||||
placeholder="https://chat.googleapis.com/v1/spaces/…"
|
||||
autocomplete="off" spellcheck="false">
|
||||
</div>
|
||||
<button type="submit">Save notification settings</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Nextcloud Talk -->
|
||||
<div class="section">
|
||||
<h2>Nextcloud Talk</h2>
|
||||
<p class="hint" style="margin-bottom:1rem;">
|
||||
Configure to send and receive messages via your Nextcloud Talk bot.
|
||||
<strong>Sending</strong> requires the bot URL, secret, and notification room.
|
||||
<strong>Reading history</strong> (<code>nc_talk_history</code> tool) additionally
|
||||
requires a Nextcloud username and app password.
|
||||
</p>
|
||||
|
||||
<details class="channel-block" {{ nc_url and 'open' or '' }}>
|
||||
<summary>Bot credentials (sending)</summary>
|
||||
<div class="channel-block-body">
|
||||
<p class="channel-hint">
|
||||
Set these up in your Nextcloud Talk room → Bot settings.
|
||||
See the <a href="/help" style="color:#a78bfa;">setup guide</a> for step-by-step instructions.
|
||||
</p>
|
||||
<div class="field">
|
||||
<label for="nc_url">Nextcloud URL</label>
|
||||
<input type="url" id="nc_url" name="nc_url"
|
||||
value="{{ nc_url }}"
|
||||
placeholder="https://cloud.example.com"
|
||||
autocomplete="off" spellcheck="false">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="nc_bot_secret">Bot secret</label>
|
||||
<input type="password" id="nc_bot_secret" name="nc_bot_secret"
|
||||
value="{{ nc_bot_secret }}"
|
||||
placeholder="Leave blank to keep existing value"
|
||||
autocomplete="new-password" spellcheck="false">
|
||||
<p class="hint">Generated when you registered the bot in Nextcloud Talk.</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="nc_notification_room">Notification room token</label>
|
||||
<input type="text" id="nc_notification_room" name="nc_notification_room"
|
||||
value="{{ nc_notify_room }}"
|
||||
placeholder="Token from the Talk room URL"
|
||||
autocomplete="off" spellcheck="false">
|
||||
<p class="hint">The token at the end of the Talk room URL — e.g. <code>abc123def</code>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details class="channel-block" {{ nc_username and 'open' or '' }}>
|
||||
<summary>API credentials (reading history)</summary>
|
||||
<div class="channel-block-body">
|
||||
<p class="channel-hint">
|
||||
Required for the <code>nc_talk_history</code> orchestrator tool.
|
||||
Generate an app password in Nextcloud → Settings → Security → App passwords.
|
||||
</p>
|
||||
<div class="field">
|
||||
<label for="nc_username">Nextcloud username</label>
|
||||
<input type="text" id="nc_username" name="nc_username"
|
||||
value="{{ nc_username }}"
|
||||
placeholder="Your Nextcloud login username"
|
||||
autocomplete="off" spellcheck="false">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="nc_app_password">App password</label>
|
||||
<input type="password" id="nc_app_password" name="nc_app_password"
|
||||
value="{{ nc_app_password }}"
|
||||
placeholder="Leave blank to keep existing value"
|
||||
autocomplete="new-password" spellcheck="false">
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
<!-- Google Chat -->
|
||||
<div class="section">
|
||||
<h2>Google Chat</h2>
|
||||
<p class="hint" style="margin-bottom:1rem;">
|
||||
Outbound webhook for proactive messages to a Google Chat space.
|
||||
Incoming messages are handled separately via the Google Chat Add-on.
|
||||
</p>
|
||||
|
||||
<details class="channel-block" {{ gc_webhook and 'open' or '' }}>
|
||||
<summary>Outbound webhook</summary>
|
||||
<div class="channel-block-body">
|
||||
<p class="channel-hint">
|
||||
Create a webhook in your Google Chat space → Manage webhooks.
|
||||
Paste the full URL here.
|
||||
</p>
|
||||
<div class="field">
|
||||
<label for="gc_outbound_webhook">Webhook URL</label>
|
||||
<input type="url" id="gc_outbound_webhook" name="gc_outbound_webhook"
|
||||
value="{{ gc_webhook }}"
|
||||
placeholder="https://chat.googleapis.com/v1/spaces/…"
|
||||
autocomplete="off" spellcheck="false">
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
<button type="submit">Save notification settings</button>
|
||||
</form>
|
||||
|
||||
<!-- Test -->
|
||||
<div class="section">
|
||||
<div class="section" style="margin-top:2rem;">
|
||||
<h2>Test</h2>
|
||||
<p class="hint" style="margin-bottom:0.85rem">
|
||||
Fire a notification via your configured channel or run the reminder check
|
||||
|
||||
@@ -345,6 +345,25 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- HTTP POST Allowlist -->
|
||||
<div class="section">
|
||||
<h2>HTTP POST Allowlist</h2>
|
||||
<p style="font-size:0.8rem; color:var(--pg-muted); margin-bottom:0.85rem; line-height:1.55;">
|
||||
One URL prefix per line. The <code style="font-size:0.82rem; background:var(--pg-bg); padding:0.1rem 0.35rem; border-radius:4px;">http_post</code>
|
||||
tool will only POST to URLs that start with a listed prefix.
|
||||
Leave blank to block all outbound POST requests.
|
||||
</p>
|
||||
<form method="POST" action="/settings/http-allowlist">
|
||||
<div class="field">
|
||||
<label for="http_allowlist_ta">Allowed URL prefixes</label>
|
||||
<textarea id="http_allowlist_ta" name="prefixes" rows="5"
|
||||
placeholder="https://ha.dgrzone.com/api/webhook/ https://n8n.dgrzone.com/webhook/"
|
||||
spellcheck="false">{{ http_allowlist }}</textarea>
|
||||
</div>
|
||||
<button type="submit">Save allowlist</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Notifications -->
|
||||
<div class="section">
|
||||
<h2>Notifications</h2>
|
||||
|
||||
Reference in New Issue
Block a user