secubox-openwrt/package/secubox/luci-app-hexojs/htdocs/luci-static/resources/view/hexojs/overview.js
CyberMind-FR 1bbd345cee refactor(luci): Mass KissTheme UI rework across all LuCI apps
Convert 90+ LuCI view files from legacy cbi-button-* classes to
KissTheme kiss-btn-* classes for consistent dark theme styling.

Pattern conversions applied:
- cbi-button-positive → kiss-btn-green
- cbi-button-negative/remove → kiss-btn-red
- cbi-button-apply → kiss-btn-cyan
- cbi-button-action → kiss-btn-blue
- cbi-button (plain) → kiss-btn

Also replaced hardcoded colors (#080, #c00, #888, etc.) with
CSS variables (--kiss-green, --kiss-red, --kiss-muted, etc.)
for proper dark theme compatibility.

Apps updated include: ai-gateway, auth-guardian, bandwidth-manager,
cloner, config-advisor, crowdsec-dashboard, dns-provider, exposure,
glances, haproxy, hexojs, iot-guard, jellyfin, ksm-manager,
mac-guardian, magicmirror2, master-link, meshname-dns, metablogizer,
metabolizer, mqtt-bridge, netdata-dashboard, picobrew, routes-status,
secubox-admin, secubox-mirror, secubox-p2p, secubox-security-threats,
service-registry, simplex, streamlit, system-hub, tor-shield,
traffic-shaper, vhost-manager, vortex-dns, vortex-firewall,
webradio, wireguard-dashboard, zigbee2mqtt, zkp, and more.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-12 11:09:34 +01:00

188 lines
8.4 KiB
JavaScript

'use strict';
'require view';
'require ui';
'require rpc';
'require hexojs/api as api';
return view.extend({
load: function() {
return Promise.all([
L.require('secubox/kiss-theme'),
api.listInstances(),
api.getStatus(),
api.getSiteStats(),
api.listBackups()
]).then(function(r) {
return { instances: r[1] || [], status: r[2] || {}, stats: r[3] || {}, backups: r[4] || [] };
});
},
render: function(d) {
var self = this;
var K = window.KissTheme;
K.apply();
return K.wrap([
// Header
K.E('div', { style: 'display:flex;justify-content:space-between;align-items:center;margin-bottom:20px' }, [
K.E('h2', { style: 'margin:0;font-size:24px' }, '📰 HexoJS'),
K.badge(d.status.running ? 'RUNNING' : 'STOPPED', d.status.running ? 'green' : 'red')
]),
// Stats
K.E('div', { class: 'kiss-grid kiss-grid-4' }, [
K.stat(d.instances.length, 'Instances', K.colors.cyan),
K.stat(d.stats.posts || 0, 'Posts', K.colors.green),
K.stat(d.stats.drafts || 0, 'Drafts', K.colors.yellow),
K.stat(d.backups.length, 'Backups', K.colors.purple)
]),
// Quick Actions
K.card('⚡ Actions', K.E('div', { style: 'display:flex;gap:8px;flex-wrap:wrap' }, [
K.btn('+ Instance', function() { self.createInstance(); }, 'green'),
K.btn('🐙 GitHub', function() { self.gitClone('github'); }),
K.btn('🍵 Gitea', function() { self.gitClone('gitea'); }),
K.E('a', { class: 'kiss-btn', href: L.url('admin', 'services', 'hexojs', 'editor') }, '✏ Post'),
K.E('a', { class: 'kiss-btn', href: L.url('admin', 'services', 'hexojs', 'settings') }, '⚙ Settings')
])),
// Instances
K.card('📦 Instances', d.instances.length ? K.E('div', {}, d.instances.map(function(i) {
return K.E('div', { style: 'display:flex;justify-content:space-between;align-items:center;padding:12px;background:var(--kiss-bg2);border-radius:8px;margin-bottom:8px' }, [
K.E('div', {}, [
K.E('strong', {}, i.title || i.name),
K.badge(i.running ? 'ON' : 'OFF', i.running ? 'green' : 'red'),
K.E('div', { style: 'font-size:12px;color:var(--kiss-muted);margin-top:4px' }, 'Port: ' + i.port)
]),
K.E('div', { style: 'display:flex;gap:4px' }, [
K.E('button', { class: 'kiss-btn', onClick: function() { self.toggle(i); } }, i.running ? '⏹' : '▶'),
K.E('button', { class: 'kiss-btn', onClick: function() { self.publish(i.name); } }, '🚀'),
K.E('button', { class: 'kiss-btn', onClick: function() { self.backup(i.name); } }, '💾'),
i.running ? K.E('a', { class: 'kiss-btn', href: 'http://' + location.hostname + ':' + i.port, target: '_blank' }, '👁') : null,
K.E('button', { class: 'kiss-btn kiss-btn-red', onClick: function() { self.deleteInst(i.name); } }, '✕')
])
]);
})) : K.E('div', { style: 'text-align:center;color:var(--kiss-muted);padding:20px' }, 'No instances')),
// Backups
K.card('💾 Backups', d.backups.length ? K.E('table', { class: 'kiss-table' }, [
K.E('thead', {}, K.E('tr', {}, [K.E('th', {}, 'Name'), K.E('th', {}, 'Size'), K.E('th', {}, 'Date'), K.E('th', {}, '')])),
K.E('tbody', {}, d.backups.map(function(b) {
return K.E('tr', {}, [
K.E('td', {}, b.name),
K.E('td', {}, b.size || '-'),
K.E('td', {}, b.timestamp ? new Date(b.timestamp * 1000).toLocaleDateString() : '-'),
K.E('td', { style: 'text-align:right' }, [
K.E('button', { class: 'kiss-btn', onClick: function() { self.restore(b.name); } }, '↩'),
K.E('button', { class: 'kiss-btn kiss-btn-red', style: 'margin-left:4px', onClick: function() { self.delBackup(b.name); } }, '✕')
])
]);
}))
]) : K.E('div', { style: 'text-align:center;color:var(--kiss-muted);padding:20px' }, 'No backups'))
], 'admin/services/hexojs');
},
createInstance: function() {
var name, title, port;
ui.showModal('New Instance', [
E('div', { style: 'margin-bottom:12px' }, [
E('label', { style: 'display:block;font-size:12px;color:#94a3b8;margin-bottom:4px' }, 'Name'),
name = E('input', { type: 'text', style: 'width:100%;padding:8px;background:#111827;border:1px solid #1e293b;border-radius:4px;color:#e2e8f0' })
]),
E('div', { style: 'margin-bottom:12px' }, [
E('label', { style: 'display:block;font-size:12px;color:#94a3b8;margin-bottom:4px' }, 'Title'),
title = E('input', { type: 'text', style: 'width:100%;padding:8px;background:#111827;border:1px solid #1e293b;border-radius:4px;color:#e2e8f0' })
]),
E('div', { style: 'margin-bottom:16px' }, [
E('label', { style: 'display:block;font-size:12px;color:#94a3b8;margin-bottom:4px' }, 'Port'),
port = E('input', { type: 'number', placeholder: '4000', style: 'width:100%;padding:8px;background:#111827;border:1px solid #1e293b;border-radius:4px;color:#e2e8f0' })
]),
E('div', { style: 'display:flex;gap:8px;justify-content:flex-end' }, [
E('button', { class: 'kiss-btn', click: ui.hideModal }, 'Cancel'),
E('button', { class: 'kiss-btn kiss-btn-green', click: function() {
if (!name.value) return;
ui.showModal('Creating...', [E('p', { class: 'spinning' }, 'Please wait...')]);
api.createInstance(name.value, title.value, port.value ? +port.value : null).then(function(r) {
ui.hideModal();
r.success ? location.reload() : ui.addNotification(null, E('p', r.error || 'Failed'));
});
}}, 'Create')
])
]);
},
gitClone: function(src) {
var repo, inst, branch;
ui.showModal('Clone from ' + src, [
E('div', { style: 'margin-bottom:12px' }, [
E('label', { style: 'display:block;font-size:12px;color:#94a3b8;margin-bottom:4px' }, 'Repository URL'),
repo = E('input', { type: 'text', style: 'width:100%;padding:8px;background:#111827;border:1px solid #1e293b;border-radius:4px;color:#e2e8f0' })
]),
E('div', { style: 'margin-bottom:12px' }, [
E('label', { style: 'display:block;font-size:12px;color:#94a3b8;margin-bottom:4px' }, 'Instance'),
inst = E('input', { type: 'text', value: 'default', style: 'width:100%;padding:8px;background:#111827;border:1px solid #1e293b;border-radius:4px;color:#e2e8f0' })
]),
E('div', { style: 'margin-bottom:16px' }, [
E('label', { style: 'display:block;font-size:12px;color:#94a3b8;margin-bottom:4px' }, 'Branch'),
branch = E('input', { type: 'text', value: 'main', style: 'width:100%;padding:8px;background:#111827;border:1px solid #1e293b;border-radius:4px;color:#e2e8f0' })
]),
E('div', { style: 'display:flex;gap:8px;justify-content:flex-end' }, [
E('button', { class: 'kiss-btn', click: ui.hideModal }, 'Cancel'),
E('button', { class: 'kiss-btn kiss-btn-green', click: function() {
if (!repo.value) return;
ui.showModal('Cloning...', [E('p', { class: 'spinning' }, 'Please wait...')]);
(src === 'github' ? api.gitHubClone : api.gitClone)(repo.value, inst.value, branch.value).then(function(r) {
ui.hideModal();
r.success ? location.reload() : ui.addNotification(null, E('p', r.error || 'Failed'));
});
}}, 'Clone')
])
]);
},
toggle: function(i) {
var fn = i.running ? api.stopInstance : api.startInstance;
ui.showModal('...', [E('p', { class: 'spinning' }, 'Please wait...')]);
fn(i.name).then(function() { ui.hideModal(); setTimeout(location.reload.bind(location), 1500); });
},
publish: function(n) {
ui.showModal('Publishing...', [E('p', { class: 'spinning' }, 'Building site...')]);
api.quickPublish(n).then(function(r) {
ui.hideModal();
ui.addNotification(null, E('p', r.success ? 'Published!' : (r.error || 'Failed')));
});
},
backup: function(n) {
ui.showModal('Backup...', [E('p', { class: 'spinning' }, 'Creating backup...')]);
api.createBackup(n, null).then(function(r) {
ui.hideModal();
r.success ? location.reload() : ui.addNotification(null, E('p', r.error || 'Failed'));
});
},
restore: function(n) {
if (!confirm('Restore backup "' + n + '"? This will overwrite current data.')) return;
ui.showModal('Restoring...', [E('p', { class: 'spinning' }, 'Please wait...')]);
api.restoreBackup(n, 'default').then(function(r) {
ui.hideModal();
ui.addNotification(null, E('p', r.success ? 'Restored' : (r.error || 'Failed')));
});
},
delBackup: function(n) {
if (!confirm('Delete backup "' + n + '"?')) return;
api.deleteBackup(n).then(function() { location.reload(); });
},
deleteInst: function(n) {
if (!confirm('Delete instance "' + n + '"?')) return;
api.deleteInstance(n, false).then(function() { location.reload(); });
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});