SysOps: deploy-all — 2026-06-09 10:41 UTC
This commit is contained in:
@@ -1,4 +1,8 @@
|
||||
{% extends "base.html" %}
|
||||
{% block extra_head %}
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
|
||||
<link rel="stylesheet" href="/static/css/herman-dashboard.css?v=13" />
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div x-data="marketingHub()" x-init="init()">
|
||||
<header class="page-header">
|
||||
@@ -9,9 +13,29 @@
|
||||
<div class="retail-actions">
|
||||
<button class="btn btn-sm btn-pulse" @click="refreshAll()" :disabled="busy">↻ Alles verversen</button>
|
||||
<a class="btn btn-sm btn-pulse-green" href="/retail">Retail 360 →</a>
|
||||
<a class="btn btn-sm" href="/projects">Projecten →</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div id="viz-toolbar" class="viz-toolbar"></div>
|
||||
|
||||
<div class="hm-dash-two-col" style="margin-bottom:1rem">
|
||||
<div class="hm-chart-panel page-viz-panel viz-mode-chart">
|
||||
<div class="hm-chart-head"><h4>Marketing data</h4><small>RSS · trends · kansen</small></div>
|
||||
<div class="page-viz-body">
|
||||
<div class="hm-chart-wrap page-viz-canvas"><canvas id="chart-marketing"></canvas></div>
|
||||
<div id="viz-marketing-alt" class="viz-alt"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hm-chart-panel page-viz-panel viz-mode-chart">
|
||||
<div class="hm-chart-head"><h4>Publish jobs</h4><small>status verdeling</small></div>
|
||||
<div class="page-viz-body">
|
||||
<div class="hm-chart-wrap page-viz-canvas"><canvas id="chart-marketing-publish"></canvas></div>
|
||||
<div id="viz-marketing-publish-alt" class="viz-alt"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="live-feed-bar" x-show="dashboard.rss?.length">
|
||||
<div class="ticker-track">
|
||||
<template x-for="r in dashboard.rss" :key="r.id">
|
||||
@@ -191,6 +215,12 @@
|
||||
<textarea class="form-input" rows="5" x-model="publishForm.text" placeholder="Post tekst — UTF-8 emoji ondersteund 🥘✨" style="width:100%;margin-bottom:0.75rem"></textarea>
|
||||
|
||||
<div style="display:flex;gap:1rem;flex-wrap:wrap;align-items:center;margin-bottom:1rem">
|
||||
<select class="form-input" x-model="publishForm.project_id" style="max-width:220px">
|
||||
<option value="">Opslaan in agent-project (auto)</option>
|
||||
<template x-for="p in cockpitProjects" :key="p.id">
|
||||
<option :value="p.id" x-text="p.name"></option>
|
||||
</template>
|
||||
</select>
|
||||
<label class="btn btn-secondary btn-sm">
|
||||
📷 Foto uploaden
|
||||
<input type="file" accept="image/*" @change="uploadImage($event)" style="display:none" />
|
||||
@@ -359,6 +389,8 @@
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
<script src="/static/js/dashboard-layout.js?v=2"></script>
|
||||
<script src="/static/js/page-viz.js?v=1"></script>
|
||||
<script>
|
||||
function marketingHub() {
|
||||
return {
|
||||
@@ -369,8 +401,9 @@ function marketingHub() {
|
||||
promos: [], bookmarks: [], bookmarkIds: {},
|
||||
reclameChains: [], reclameFilter: { chain: '', q: '', folder_type: '', valid_days: '' },
|
||||
reclameStats: { chains: 0 },
|
||||
publishChannels: [], publishForm: { text: '', image_url: '', media_ids: [], channels: [] },
|
||||
publishChannels: [], publishForm: { text: '', image_url: '', media_ids: [], channels: [], project_id: '' },
|
||||
publishHistory: [], publishJobId: null, publishJobStatus: '', publishBusy: false,
|
||||
cockpitProjects: [],
|
||||
emojis: ['🥘','✨','🔥','📢','🛒','🌿','☪️','🇳🇱','👨🍳','💚','📁','🎯'],
|
||||
promoForm: { chain: '', title: '', folder_path: '', description: '' },
|
||||
_pollStop: null,
|
||||
@@ -385,11 +418,16 @@ function marketingHub() {
|
||||
async init() {
|
||||
await this.loadDashboard();
|
||||
await this.loadBookmarks();
|
||||
await this.loadPublishHistory();
|
||||
fetch('/api/projects?limit=50').then(r=>r.json()).then(d=>{ this.cockpitProjects = d.items || []; }).catch(()=>{});
|
||||
if (this.tab === 'regelgeving') await this.loadRegulations();
|
||||
if (this.tab === 'reclame') { await this.loadReclameChains(); await this.loadPromos(); }
|
||||
if (this.tab === 'publish') { await this.loadPublishChannels(); await this.loadPublishHistory(); }
|
||||
this._pollStop = CockpitLive.startPolling(() => this.refreshAll(false), 30000);
|
||||
this.$nextTick(() => this.updateTabIndicator());
|
||||
if (window.PageViz) {
|
||||
window.PageViz.init('marketing', (mode) => this.renderViz(mode));
|
||||
}
|
||||
fetch('/api/admin/recommendations/pending').then(r=>r.json()).then(d=>{
|
||||
const el=document.getElementById('reco-list');
|
||||
if(!el) return;
|
||||
@@ -510,6 +548,7 @@ function marketingHub() {
|
||||
try {
|
||||
await fetch('/api/retail/rss/refresh', { method: 'POST' });
|
||||
await this.loadDashboard();
|
||||
this.renderViz(window.__vizMode || 'neo-bars');
|
||||
if (toast !== false) Cockpit.toast('Marketing data bijgewerkt', 'success');
|
||||
} finally { this.busy = false; }
|
||||
},
|
||||
@@ -540,8 +579,42 @@ function marketingHub() {
|
||||
try {
|
||||
const r = await fetch('/api/marketing/publish/history?limit=30').then(res => res.json());
|
||||
this.publishHistory = r.items || [];
|
||||
if (window.__marketingRenderViz) window.__marketingRenderViz(window.__vizMode || 'neo-bars');
|
||||
} catch (e) { this.publishHistory = []; }
|
||||
},
|
||||
renderViz(mode) {
|
||||
window.__vizMode = mode;
|
||||
window.__marketingRenderViz = (m) => this.renderViz(m);
|
||||
if (!window.VizEngine) return;
|
||||
const d = this.dashboard || {};
|
||||
VizEngine.renderFromRows(mode,
|
||||
document.getElementById('chart-marketing'),
|
||||
document.getElementById('viz-marketing-alt'),
|
||||
'marketing-main', 'Marketing KPIs',
|
||||
[
|
||||
{ label: 'RSS', value: (d.rss || []).length, raw: (d.rss || []).length },
|
||||
{ label: 'Trends', value: (d.trends || []).length, raw: (d.trends || []).length },
|
||||
{ label: 'Kansen', value: (d.top_opportunities || []).length, raw: (d.top_opportunities || []).length },
|
||||
{ label: 'Promo', value: this.promos.length, raw: this.promos.length },
|
||||
],
|
||||
'hm-eq-purple', VizEngine.MODES ? null : null
|
||||
);
|
||||
const statusMap = {};
|
||||
(this.publishHistory || []).forEach(j => {
|
||||
const s = j.status || 'unknown';
|
||||
statusMap[s] = (statusMap[s] || 0) + 1;
|
||||
});
|
||||
const labels = Object.keys(statusMap);
|
||||
const values = labels.map(k => statusMap[k]);
|
||||
if (!labels.length) { labels.push('geen'); values.push(0); }
|
||||
VizEngine.renderFromRows(mode,
|
||||
document.getElementById('chart-marketing-publish'),
|
||||
document.getElementById('viz-marketing-publish-alt'),
|
||||
'marketing-publish', 'Publish status',
|
||||
labels.map((l, i) => ({ label: l, value: values[i], raw: values[i] })),
|
||||
'hm-eq-cyan'
|
||||
);
|
||||
},
|
||||
publishResultSummary(j) {
|
||||
const res = j.result || {};
|
||||
if (typeof res === 'string') { try { return JSON.stringify(JSON.parse(res)); } catch (e) { return res; } }
|
||||
@@ -573,6 +646,7 @@ function marketingHub() {
|
||||
image_url: this.publishForm.image_url || null,
|
||||
media_ids: this.publishForm.media_ids || [],
|
||||
channels: this.publishForm.channels,
|
||||
project_id: this.publishForm.project_id ? parseInt(this.publishForm.project_id, 10) : null,
|
||||
};
|
||||
const r = await fetch('/api/marketing/publish', {
|
||||
method: 'POST',
|
||||
|
||||
Reference in New Issue
Block a user