5d60d33db1
Volledige Foodlinkk Command Center uitbreiding met social automatisering, reclamefolder filters, Proxmox monitoring en documentatie.
311 lines
13 KiB
HTML
311 lines
13 KiB
HTML
{% extends "base.html" %}
|
|
{% block content %}
|
|
<div x-data="settingsPage()" x-init="load()">
|
|
<header class="page-header settings-header">
|
|
<div>
|
|
<h1>Settings</h1>
|
|
<p class="subtitle page-tip">Configure integrations — Herman reads active settings from PostgreSQL.</p>
|
|
</div>
|
|
</header>
|
|
|
|
<nav class="settings-tabs">
|
|
<a href="/settings?tab=email" class="settings-tab {% if active_tab == 'email' %}active{% endif %}">Email</a>
|
|
<a href="/settings?tab=permissions" class="settings-tab {% if active_tab == 'permissions' %}active{% endif %}">Rechten Herman</a>
|
|
<a href="/settings?tab=general" class="settings-tab {% if active_tab == 'general' %}active{% endif %}">General</a>
|
|
</nav>
|
|
|
|
{% if active_tab == 'email' %}
|
|
<section class="panel settings-panel">
|
|
<div class="settings-panel-head">
|
|
<div>
|
|
<h2>Email accounts</h2>
|
|
<p class="page-tip">Kies welk mailbox Herman gebruikt om te versturen. IMAP velden zijn voor latere inbox-sync.</p>
|
|
</div>
|
|
<button type="button" class="btn btn-primary" @click="openForm()">+ Nieuw account</button>
|
|
</div>
|
|
|
|
<div class="settings-active-banner" x-show="activeAccount" x-cloak>
|
|
<span class="badge badge-positive">Actief</span>
|
|
<span x-text="activeAccount ? activeAccount.label + ' · ' + activeAccount.email_address : ''"></span>
|
|
</div>
|
|
|
|
<div class="email-account-list">
|
|
<template x-for="acc in accounts" :key="acc.id">
|
|
<article class="email-account-card" :class="{ 'is-active': acc.is_active }">
|
|
<div class="email-account-card-head">
|
|
<div>
|
|
<strong x-text="acc.label"></strong>
|
|
<span class="muted" x-text="acc.email_address"></span>
|
|
</div>
|
|
<span class="badge" :class="acc.is_active ? 'badge-positive' : 'badge-neutral'" x-text="acc.is_active ? 'Actief' : acc.provider"></span>
|
|
</div>
|
|
<div class="email-account-meta">
|
|
<span x-text="'SMTP: ' + (acc.smtp_host || '—') + ':' + (acc.smtp_port || '')"></span>
|
|
<span x-text="acc.smtp_password_set ? '🔒 wachtwoord opgeslagen' : '⚠️ geen SMTP wachtwoord'"></span>
|
|
<span x-show="acc.last_test_status" x-text="'Test: ' + acc.last_test_status"></span>
|
|
</div>
|
|
<div class="btn-group">
|
|
<button type="button" class="btn btn-secondary btn-sm" @click="edit(acc)">Bewerken</button>
|
|
<button type="button" class="btn btn-primary btn-sm" @click="activate(acc.id)" x-show="!acc.is_active">Maak actief</button>
|
|
<button type="button" class="btn btn-secondary btn-sm" @click="testAccount(acc.id)">Test SMTP</button>
|
|
<button type="button" class="btn btn-reject btn-sm" @click="remove(acc.id)">Verwijder</button>
|
|
</div>
|
|
</article>
|
|
</template>
|
|
<p class="empty-state" x-show="!accounts.length && !loading">Nog geen email account — voeg er een toe om Herman mail te laten versturen.</p>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="modal" :class="{ open: formOpen }" @click.self="formOpen=false">
|
|
<div class="modal-card settings-modal">
|
|
<h3 x-text="form.id ? 'Email account bewerken' : 'Nieuw email account'"></h3>
|
|
|
|
<label class="form-label">Label
|
|
<input class="form-input" x-model="form.label" placeholder="bv. Foodlinkk sales" />
|
|
</label>
|
|
|
|
<label class="form-label">Email adres
|
|
<input class="form-input" type="email" x-model="form.email_address" placeholder="info@foodlinkk.nl" />
|
|
</label>
|
|
|
|
<label class="form-label">Provider (vult SMTP/IMAP automatisch in)
|
|
<select class="form-input" x-model="form.provider" @change="applyProvider()">
|
|
<option value="custom">Custom / eigen server</option>
|
|
<option value="gmail">Gmail</option>
|
|
<option value="outlook">Outlook / Microsoft 365</option>
|
|
<option value="zoho">Zoho Mail</option>
|
|
</select>
|
|
</label>
|
|
|
|
<div class="settings-form-grid">
|
|
<label class="form-label">SMTP host<input class="form-input" x-model="form.smtp_host" /></label>
|
|
<label class="form-label">SMTP port<input class="form-input" type="number" x-model.number="form.smtp_port" /></label>
|
|
<label class="form-label">SMTP user<input class="form-input" x-model="form.smtp_user" /></label>
|
|
<label class="form-label">SMTP wachtwoord
|
|
<input class="form-input" type="password" x-model="form.smtp_password" :placeholder="form.smtp_password_set ? '•••••••• (laat leeg om te behouden)' : 'App-wachtwoord'" />
|
|
</label>
|
|
</div>
|
|
|
|
<details class="settings-details">
|
|
<summary>IMAP (inbox sync — later)</summary>
|
|
<div class="settings-form-grid">
|
|
<label class="form-label">IMAP host<input class="form-input" x-model="form.imap_host" /></label>
|
|
<label class="form-label">IMAP port<input class="form-input" type="number" x-model.number="form.imap_port" /></label>
|
|
<label class="form-label">IMAP user<input class="form-input" x-model="form.imap_user" /></label>
|
|
<label class="form-label">IMAP wachtwoord
|
|
<input class="form-input" type="password" x-model="form.imap_password" :placeholder="form.imap_password_set ? '••••••••' : 'App-wachtwoord'" />
|
|
</label>
|
|
</div>
|
|
<label class="form-check">
|
|
<input type="checkbox" x-model="form.sync_enabled" /> Inbox sync inschakelen (wanneer beschikbaar)
|
|
</label>
|
|
</details>
|
|
|
|
<label class="form-check">
|
|
<input type="checkbox" x-model="form.is_active" /> Direct als actief account instellen
|
|
</label>
|
|
|
|
<div class="btn-group">
|
|
<button type="button" class="btn btn-primary" @click="save()" :disabled="saving">Opslaan</button>
|
|
<button type="button" class="btn btn-secondary" @click="testForm()" :disabled="saving">Test SMTP</button>
|
|
<button type="button" class="btn btn-secondary" @click="formOpen=false">Annuleren</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% elif active_tab == 'permissions' %}
|
|
<section class="panel settings-panel hm-neo" x-data="permissionsPage()" x-init="loadPerms()">
|
|
<div class="settings-panel-head">
|
|
<div>
|
|
<h2>Herman — Module rechten</h2>
|
|
<p class="page-tip">Bepaal welke bedrijfsprocessen Herman mag benaderen. Grant all = volledige toegang.</p>
|
|
</div>
|
|
<button type="button" class="btn btn-pulse-green" @click="grantAll()">👑 Alles aan Herman</button>
|
|
</div>
|
|
<p><span class="live-badge">Live</span> <span x-text="grantedCount + ' / ' + total + ' modules actief'"></span></p>
|
|
<div class="perm-grid">
|
|
<template x-for="p in perms" :key="p.module_key">
|
|
<div class="perm-card" :class="p.granted ? 'granted' : ''">
|
|
<div>
|
|
<strong x-text="p.module_label"></strong>
|
|
<p style="font-size:0.8rem;margin:0.25rem 0;color:#94a3b8" x-text="p.description"></p>
|
|
<small x-text="p.category"></small>
|
|
</div>
|
|
<label class="form-check">
|
|
<input type="checkbox" :checked="p.granted" @change="toggle(p.module_key, $event.target.checked)"> Toegang
|
|
</label>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
</section>
|
|
{% elif active_tab == 'general' %}
|
|
<section class="panel settings-panel">
|
|
<h2>General</h2>
|
|
<p class="page-tip">Dashboard: <a href="http://10.4.7.18:8600">http://10.4.7.18:8600</a> · Telegram: @klaploper_bot · Ochtend briefing: 07:00</p>
|
|
<p class="page-tip">Meer instellingen (Telegram tijd, timezone) komen hier later.</p>
|
|
</section>
|
|
{% endif %}
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
function permissionsPage() {
|
|
return {
|
|
perms: [], grantedCount: 0, total: 0,
|
|
async loadPerms() {
|
|
const r = await Cockpit.api('/api/settings/permissions');
|
|
this.perms = r.items || [];
|
|
this.grantedCount = r.granted_count || 0;
|
|
this.total = r.total || 0;
|
|
},
|
|
async toggle(key, granted) {
|
|
await Cockpit.api('/api/settings/permissions/' + key, { method: 'PUT', body: JSON.stringify({ granted }) });
|
|
await this.loadPerms();
|
|
},
|
|
async grantAll() {
|
|
const r = await Cockpit.api('/api/settings/permissions/grant-all', { method: 'POST' });
|
|
Cockpit.toast(r.message || 'Alle rechten toegekend', 'success');
|
|
await this.loadPerms();
|
|
}
|
|
};
|
|
}
|
|
</script>
|
|
{% if active_tab == 'email' %}
|
|
<script>
|
|
const PROVIDERS = {
|
|
gmail: { smtp_host: 'smtp.gmail.com', smtp_port: 587, imap_host: 'imap.gmail.com', imap_port: 993 },
|
|
outlook: { smtp_host: 'smtp.office365.com', smtp_port: 587, imap_host: 'outlook.office365.com', imap_port: 993 },
|
|
zoho: { smtp_host: 'smtp.zoho.eu', smtp_port: 587, imap_host: 'imap.zoho.eu', imap_port: 993 },
|
|
custom: { smtp_host: '', smtp_port: 587, imap_host: '', imap_port: 993 },
|
|
};
|
|
|
|
function settingsPage() {
|
|
return {
|
|
accounts: [],
|
|
activeAccount: null,
|
|
loading: true,
|
|
formOpen: false,
|
|
saving: false,
|
|
form: defaultForm(),
|
|
|
|
async load() {
|
|
this.loading = true;
|
|
try {
|
|
const r = await Cockpit.api('/api/settings/email');
|
|
this.accounts = r.accounts || [];
|
|
this.activeAccount = this.accounts.find(a => a.is_active) || null;
|
|
} catch (e) { Cockpit.toast(e.message, 'error'); }
|
|
this.loading = false;
|
|
},
|
|
|
|
defaultForm() { return defaultForm(); },
|
|
|
|
openForm() {
|
|
this.form = defaultForm();
|
|
this.formOpen = true;
|
|
},
|
|
|
|
edit(acc) {
|
|
this.form = Object.assign(defaultForm(), acc, { smtp_password: '', imap_password: '' });
|
|
this.formOpen = true;
|
|
},
|
|
|
|
applyProvider() {
|
|
const p = PROVIDERS[this.form.provider] || PROVIDERS.custom;
|
|
this.form.smtp_host = p.smtp_host;
|
|
this.form.smtp_port = p.smtp_port;
|
|
this.form.imap_host = p.imap_host;
|
|
this.form.imap_port = p.imap_port;
|
|
if (this.form.email_address && !this.form.smtp_user) {
|
|
this.form.smtp_user = this.form.email_address;
|
|
this.form.imap_user = this.form.email_address;
|
|
}
|
|
},
|
|
|
|
bodyFromForm() {
|
|
const b = {
|
|
label: this.form.label,
|
|
email_address: this.form.email_address,
|
|
provider: this.form.provider,
|
|
is_active: this.form.is_active,
|
|
smtp_host: this.form.smtp_host,
|
|
smtp_port: this.form.smtp_port,
|
|
smtp_user: this.form.smtp_user,
|
|
imap_host: this.form.imap_host,
|
|
imap_port: this.form.imap_port,
|
|
imap_user: this.form.imap_user,
|
|
sync_enabled: this.form.sync_enabled,
|
|
};
|
|
if (this.form.smtp_password) b.smtp_password = this.form.smtp_password;
|
|
if (this.form.imap_password) b.imap_password = this.form.imap_password;
|
|
return b;
|
|
},
|
|
|
|
async save() {
|
|
this.saving = true;
|
|
try {
|
|
const body = this.bodyFromForm();
|
|
if (this.form.id) {
|
|
await Cockpit.api('/api/settings/email/' + this.form.id, { method: 'PUT', body: JSON.stringify(body) });
|
|
} else {
|
|
await Cockpit.api('/api/settings/email', { method: 'POST', body: JSON.stringify(body) });
|
|
}
|
|
Cockpit.toast('Opgeslagen', 'success');
|
|
this.formOpen = false;
|
|
await this.load();
|
|
} catch (e) { Cockpit.toast(e.message, 'error'); }
|
|
this.saving = false;
|
|
},
|
|
|
|
async activate(id) {
|
|
try {
|
|
await Cockpit.api('/api/settings/email/' + id + '/activate', { method: 'POST' });
|
|
Cockpit.toast('Actief account gewijzigd', 'success');
|
|
await this.load();
|
|
} catch (e) { Cockpit.toast(e.message, 'error'); }
|
|
},
|
|
|
|
async testAccount(id) {
|
|
try {
|
|
Cockpit.toast('SMTP test…', 'info');
|
|
const r = await Cockpit.api('/api/settings/email/' + id + '/test', { method: 'POST' });
|
|
Cockpit.toast(r.message || 'SMTP OK', r.ok ? 'success' : 'error');
|
|
await this.load();
|
|
} catch (e) { Cockpit.toast(e.message, 'error'); }
|
|
},
|
|
|
|
async testForm() {
|
|
this.saving = true;
|
|
try {
|
|
const r = await Cockpit.api('/api/settings/email/test', {
|
|
method: 'POST',
|
|
body: JSON.stringify(this.bodyFromForm()),
|
|
});
|
|
Cockpit.toast(r.message || 'SMTP OK', r.ok ? 'success' : 'error');
|
|
} catch (e) { Cockpit.toast(e.message, 'error'); }
|
|
this.saving = false;
|
|
},
|
|
|
|
async remove(id) {
|
|
if (!confirm('Email account verwijderen?')) return;
|
|
try {
|
|
await Cockpit.api('/api/settings/email/' + id, { method: 'DELETE' });
|
|
Cockpit.toast('Verwijderd', 'success');
|
|
await this.load();
|
|
} catch (e) { Cockpit.toast(e.message, 'error'); }
|
|
},
|
|
};
|
|
}
|
|
|
|
function defaultForm() {
|
|
return {
|
|
id: null, label: '', email_address: '', provider: 'gmail', is_active: true,
|
|
smtp_host: 'smtp.gmail.com', smtp_port: 587, smtp_user: '', smtp_password: '', smtp_password_set: false,
|
|
imap_host: 'imap.gmail.com', imap_port: 993, imap_user: '', imap_password: '', imap_password_set: false,
|
|
sync_enabled: false,
|
|
};
|
|
}
|
|
</script>
|
|
{% endif %}
|
|
{% endblock %}
|