Platform bundle: marketing publish, IT ops, packaging, agents mesh.

Volledige Foodlinkk Command Center uitbreiding met social automatisering,
reclamefolder filters, Proxmox monitoring en documentatie.
This commit is contained in:
Aissa
2026-06-09 00:41:27 +00:00
commit 5d60d33db1
212 changed files with 30044 additions and 0 deletions
+55
View File
@@ -0,0 +1,55 @@
{% extends "base.html" %}
{% block content %}
<div x-data="clientsCrud()">
<header class="page-header"><h1>Clients</h1>
<p class="subtitle page-tip">Kanban by stage — click a card for details or change stage from the dropdown.</p></header>
<button class="btn btn-primary" @click="openModal()">Add client</button>
<div class="kanban">
{% set stages = ['intake','discovery','proposal','active','churned'] %}
{% for st in stages %}
<div class="kanban-col"><h3>{{ st }}</h3>
{% for c in clients if c.stage == st %}
<div class="kanban-card clickable-row" @click="show({{ c.id }}, '{{ c.name|e }}', '{{ (c.email or '')|e }}', '{{ c.stage|e }}', '{{ (c.notes or '')|e }}')">
<strong>{{ c.name }}</strong><br/><small>{{ c.sector or '' }}</small>
<select class="form-input" @click.stop="" @change="setStage({{ c.id }}, $event.target.value, '{{ c.name|e }}', '{{ (c.email or '')|e }}', '{{ (c.notes or '')|e }}')">
{% for s in stages %}<option value="{{ s }}" {% if c.stage==s %}selected{% endif %}>{{ s }}</option>{% endfor %}
</select>
</div>
{% endfor %}
</div>
{% endfor %}
</div>
<div class="modal" :class="{ open: modal }" @click.self="modal=false">
<div class="modal-card"><h3 x-text="form.id ? 'Edit client' : 'New client'"></h3>
<input class="form-input" placeholder="Name" x-model="form.name" />
<input class="form-input" placeholder="Email" x-model="form.email" />
<select x-model="form.stage" class="form-input"><option>intake</option><option>discovery</option><option>proposal</option><option>active</option><option>churned</option></select>
<textarea class="form-input" x-model="form.notes" placeholder="Notes"></textarea>
<div class="btn-group"><button class="btn btn-primary" @click="save()">Save</button><button class="btn btn-secondary" @click="modal=false">Cancel</button></div>
</div>
</div>
<aside class="drawer" :class="{ open: drawer }"><button class="drawer-close" @click="drawer=false">×</button><p x-text="detail"></p></aside>
</div>
{% endblock %}
{% block scripts %}
<script>
function clientsCrud() {
return {
modal: false, drawer: false, detail: '',
form: { id: null, name: '', email: '', stage: 'intake', notes: '' },
openModal() { this.form = { id: null, name: '', email: '', stage: 'intake', notes: '' }; this.modal = true; },
show(id, name, email, stage, notes) { this.detail = name + ' · ' + email; this.form = { id, name, email, stage, notes }; this.drawer = true; },
async save() {
const body = { name: this.form.name, email: this.form.email, stage: this.form.stage, notes: this.form.notes };
if (this.form.id) await Cockpit.api('/clients/' + this.form.id, { method: 'PUT', body: JSON.stringify(body) });
else await Cockpit.api('/clients', { method: 'POST', body: JSON.stringify(body) });
location.reload();
},
async setStage(id, stage, name, email, notes) {
await Cockpit.api('/clients/' + id, { method: 'PUT', body: JSON.stringify({ name, email, stage, notes }) });
Cockpit.toast('Stage updated', 'success'); location.reload();
}
};
}
</script>
{% endblock %}