Major rebranding, i18n, dashboard, shared folders, role capabilities
- Rebrand: new app/agent icons, SKALD.md, warm "paper" CSS palette (terracotta accent, --radius tokens, WCAG contrast, reduced-motion), updated favicon, tray icon, skaldkonur asset - i18n: backend crate (i18n.rs, locale column, ui_locale config), frontend library (web/lib/i18n.js, I18nMixin, t(key)), translation files (web/i18n/), every component wired - Dashboard: <dashboard-page> replaces old home-page content; <app-copilot> becomes the landing page (full/dock layout modes) - Shared folders: API endpoints (shared_folders.rs), frontend page, can_write membership, container mount topology, user_fs routing - Role capabilities: new db table & authorization seam (data not enums), roles.attrs JSON for ui_mode / interface select - Setup: skald-setup prompts for language + password, sets ui_locale - General: components migrated to CSS variables, Lit conventions cleanup, connectors/catalog/marketplace/approval refactoring
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { html, nothing } from 'lit';
|
||||
import { LightElement } from '../lib/base.js';
|
||||
import { t } from '../lib/i18n.js';
|
||||
|
||||
export class ConfigPage extends LightElement {
|
||||
static properties = {
|
||||
@@ -9,6 +10,8 @@ export class ConfigPage extends LightElement {
|
||||
_saving: { state: true }, // Set<key>
|
||||
_saved: { state: true }, // Set<key> (brief flash)
|
||||
_error: { state: true },
|
||||
_debugMode: { state: true },
|
||||
_debugLoading: { state: true },
|
||||
};
|
||||
|
||||
constructor() {
|
||||
@@ -19,17 +22,55 @@ export class ConfigPage extends LightElement {
|
||||
this._saving = new Set();
|
||||
this._saved = new Set();
|
||||
this._error = null;
|
||||
this._debugMode = false;
|
||||
this._debugLoading = true;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this.__onLocaleChanged = () => this.requestUpdate();
|
||||
window.addEventListener('locale-changed', this.__onLocaleChanged);
|
||||
window.addEventListener('llm-page-change', (e) => {
|
||||
this._open = e.detail.page === 'config';
|
||||
this.style.display = this._open ? 'flex' : 'none';
|
||||
if (this._open) this._load();
|
||||
if (this._open) { this._load(); this._loadDebugMode(); }
|
||||
});
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
window.removeEventListener('locale-changed', this.__onLocaleChanged);
|
||||
super.disconnectedCallback();
|
||||
}
|
||||
|
||||
async _loadDebugMode() {
|
||||
try {
|
||||
const res = await fetch('/api/dev/debug_mode');
|
||||
if (!res.ok) throw new Error();
|
||||
const data = await res.json();
|
||||
this._debugMode = data.enabled;
|
||||
} catch {
|
||||
// ignore, keep current value
|
||||
} finally {
|
||||
this._debugLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
async _toggleDebugMode() {
|
||||
const next = !this._debugMode;
|
||||
this._debugMode = next;
|
||||
try {
|
||||
const res = await fetch('/api/dev/debug_mode', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ enabled: next }),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
window.dispatchEvent(new CustomEvent('debug-mode-change', { detail: { enabled: next } }));
|
||||
} catch {
|
||||
this._debugMode = !next;
|
||||
}
|
||||
}
|
||||
|
||||
async _load() {
|
||||
this._error = null;
|
||||
try {
|
||||
@@ -70,7 +111,7 @@ export class ConfigPage extends LightElement {
|
||||
this._saved = new Set([...this._saved].filter(k => k !== key));
|
||||
}, 1500);
|
||||
} catch (e) {
|
||||
alert(`Error saving ${prop.name}: ${e.message}`);
|
||||
alert(t('config.error_save', { name: prop.name, msg: e.message }));
|
||||
} finally {
|
||||
this._saving = new Set([...this._saving].filter(k => k !== key));
|
||||
}
|
||||
@@ -164,18 +205,45 @@ export class ConfigPage extends LightElement {
|
||||
return html`
|
||||
<div class="config-page">
|
||||
<div class="config-page-header">
|
||||
<h2 class="llm-page-title">Config</h2>
|
||||
<h2 class="llm-page-title">${t('config.title')}</h2>
|
||||
</div>
|
||||
|
||||
${this._error ? html`
|
||||
<div class="alert alert-danger">${this._error}</div>` : nothing}
|
||||
|
||||
${this._properties.length === 0 && !this._error ? html`
|
||||
<p class="text-muted mt-2">Loading…</p>` : nothing}
|
||||
<p class="text-muted mt-2">${t('config.loading')}</p>` : nothing}
|
||||
|
||||
<div class="config-sets">
|
||||
${this._properties.map(s => this._renderSet(s))}
|
||||
</div>
|
||||
|
||||
<div class="config-set">
|
||||
<div class="config-set-header">
|
||||
<div class="config-set-name">${t('config.developer')}</div>
|
||||
<div class="config-set-desc"></div>
|
||||
</div>
|
||||
<div class="config-rows">
|
||||
<div class="config-row">
|
||||
<div class="config-row-meta">
|
||||
<div class="config-row-name">${t('config.debug')}</div>
|
||||
<div class="config-row-desc">${t('config.debug.desc')}</div>
|
||||
</div>
|
||||
<div class="config-row-control">
|
||||
<div class="form-check form-switch config-bool-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch"
|
||||
id="cfg-debug-mode"
|
||||
.checked=${this._debugMode}
|
||||
?disabled=${this._debugLoading}
|
||||
@change=${() => this._toggleDebugMode()} />
|
||||
<label class="form-check-label" for="cfg-debug-mode">
|
||||
${this._debugMode ? 'Enabled' : 'Disabled'}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user