refactor(ui): remove stream mode functionality across various components

- Eliminated stream mode related translations and CSS styles to streamline the user interface.
- Updated multiple components to remove references to stream mode, enhancing code clarity and maintainability.
- Adjusted rendering logic in views to ensure consistent behavior without stream mode.
- Improved overall readability by cleaning up unused variables and props.
This commit is contained in:
Val Alexander
2026-03-12 06:48:19 -05:00
parent ad97f33c85
commit 567df63682
17 changed files with 35 additions and 206 deletions

View File

@@ -146,10 +146,6 @@ export const en: TranslationMap = {
refreshAll: "Refresh All",
terminal: "Terminal",
},
streamMode: {
active: "Stream mode — values redacted",
disable: "Disable",
},
palette: {
placeholder: "Type a command…",
noResults: "No results",

View File

@@ -147,10 +147,6 @@ export const pt_BR: TranslationMap = {
refreshAll: "Atualizar Tudo",
terminal: "Terminal",
},
streamMode: {
active: "Modo stream — valores ocultos",
disable: "Desativar",
},
palette: {
placeholder: "Digite um comando…",
noResults: "Sem resultados",

View File

@@ -144,10 +144,6 @@ export const zh_CN: TranslationMap = {
refreshAll: "全部刷新",
terminal: "终端",
},
streamMode: {
active: "流模式 — 数据已隐藏",
disable: "禁用",
},
palette: {
placeholder: "输入命令…",
noResults: "无结果",

View File

@@ -144,10 +144,6 @@ export const zh_TW: TranslationMap = {
refreshAll: "全部刷新",
terminal: "終端",
},
streamMode: {
active: "串流模式 — 數據已隱藏",
disable: "禁用",
},
palette: {
placeholder: "輸入指令…",
noResults: "無結果",

View File

@@ -3526,11 +3526,6 @@
color: var(--text-strong);
}
.ov-card__value.redacted {
filter: blur(6px);
user-select: none;
}
.ov-card__hint {
font-size: 12px;
color: var(--muted);
@@ -3594,11 +3589,6 @@
border-color: var(--border-strong);
}
.ov-recent__row.redacted {
filter: blur(6px);
user-select: none;
}
.ov-recent__key {
font-weight: 500;
white-space: nowrap;
@@ -3637,23 +3627,10 @@
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.ov-access-grid.redacted input,
.ov-access-grid.redacted select {
filter: blur(6px);
user-select: none;
}
.ov-access-grid__full {
grid-column: 1 / -1;
}
/* Stream mode banner */
.ov-stream-banner {
display: flex;
align-items: center;
gap: 10px;
}
/* Bottom grid (event log + log tail) */
.ov-bottom-grid {
display: grid;

View File

@@ -630,7 +630,6 @@ export function renderApp(state: AppViewState) {
attentionItems: state.attentionItems,
eventLog: state.eventLog,
overviewLogLines: state.overviewLogLines,
streamMode: state.streamMode,
showGatewayToken: state.overviewShowGatewayToken,
showGatewayPassword: state.overviewShowGatewayPassword,
onSettingsChange: (next) => state.applySettings(next),
@@ -656,14 +655,6 @@ export function renderApp(state: AppViewState) {
onRefresh: () => state.loadOverview(),
onNavigate: (tab) => state.setTab(tab as import("./navigation.ts").Tab),
onRefreshLogs: () => state.loadOverview(),
onToggleStreamMode: () => {
state.streamMode = !state.streamMode;
try {
localStorage.setItem("openclaw:stream-mode", String(state.streamMode));
} catch {
/* */
}
},
})
: nothing
}
@@ -717,7 +708,6 @@ export function renderApp(state: AppViewState) {
entries: state.presenceEntries,
lastError: state.presenceError,
statusMessage: state.presenceStatus,
streamMode: state.streamMode,
onRefresh: () => loadPresence(state),
}),
)
@@ -1222,6 +1212,7 @@ export function renderApp(state: AppViewState) {
state.tab === "skills"
? lazyRender(lazySkills, (m) =>
m.renderSkills({
connected: state.connected,
loading: state.skillsLoading,
report: state.skillsReport,
error: state.skillsError,
@@ -1503,7 +1494,6 @@ export function renderApp(state: AppViewState) {
))
? null
: state.configActiveSubsection,
streamMode: state.streamMode,
onRawChange: (next) => {
state.configRaw = next;
},
@@ -1574,7 +1564,6 @@ export function renderApp(state: AppViewState) {
)
? null
: state.communicationsActiveSubsection,
streamMode: state.streamMode,
onRawChange: (next) => {
state.configRaw = next;
},
@@ -1639,7 +1628,6 @@ export function renderApp(state: AppViewState) {
)
? null
: state.appearanceActiveSubsection,
streamMode: state.streamMode,
onRawChange: (next) => {
state.configRaw = next;
},
@@ -1704,7 +1692,6 @@ export function renderApp(state: AppViewState) {
)
? null
: state.automationActiveSubsection,
streamMode: state.streamMode,
onRawChange: (next) => {
state.configRaw = next;
},
@@ -1769,7 +1756,6 @@ export function renderApp(state: AppViewState) {
)
? null
: state.infrastructureActiveSubsection,
streamMode: state.streamMode,
onRawChange: (next) => {
state.configRaw = next;
},
@@ -1834,7 +1820,6 @@ export function renderApp(state: AppViewState) {
)
? null
: state.aiAgentsActiveSubsection,
streamMode: state.streamMode,
onRawChange: (next) => {
state.configRaw = next;
},

View File

@@ -295,7 +295,6 @@ export type AppViewState = {
paletteOpen: boolean;
paletteQuery: string;
paletteActiveIndex: number;
streamMode: boolean;
overviewShowGatewayToken: boolean;
overviewShowGatewayPassword: boolean;
overviewLogLines: string[];

View File

@@ -384,15 +384,6 @@ export class OpenClawApp extends LitElement {
@state() paletteOpen = false;
@state() paletteQuery = "";
@state() paletteActiveIndex = 0;
@state() streamMode = (() => {
try {
const stored = localStorage.getItem("openclaw:stream-mode");
// Default to true (redacted) unless explicitly disabled
return stored === null ? true : stored === "true";
} catch {
return true;
}
})();
@state() overviewShowGatewayToken = false;
@state() overviewShowGatewayPassword = false;
@state() overviewLogLines: string[] = [];

View File

@@ -107,7 +107,6 @@ type SensitiveRenderParams = {
path: Array<string | number>;
value: unknown;
hints: ConfigUiHints;
streamMode: boolean;
revealSensitive: boolean;
isSensitivePathRevealed?: (path: Array<string | number>) => boolean;
};
@@ -128,13 +127,12 @@ function getSensitiveRenderState(params: SensitiveRenderParams): SensitiveRender
const isSensitive = hasSensitiveConfigData(params.value, params.path, params.hints);
const isRevealed =
isSensitive &&
!params.streamMode &&
(params.revealSensitive || (params.isSensitivePathRevealed?.(params.path) ?? false));
return {
isSensitive,
isRedacted: isSensitive && !isRevealed,
isRevealed,
canReveal: isSensitive && !params.streamMode,
canReveal: isSensitive,
};
}
@@ -402,7 +400,6 @@ export function renderNode(params: {
disabled: boolean;
showLabel?: boolean;
searchCriteria?: ConfigSearchCriteria;
streamMode?: boolean;
revealSensitive?: boolean;
isSensitivePathRevealed?: (path: Array<string | number>) => boolean;
onToggleSensitivePath?: (path: Array<string | number>) => void;
@@ -524,7 +521,6 @@ export function renderNode(params: {
hints,
disabled,
showLabel,
streamMode: params.streamMode ?? false,
revealSensitive: params.revealSensitive ?? false,
isSensitivePathRevealed: params.isSensitivePathRevealed,
onToggleSensitivePath: params.onToggleSensitivePath,
@@ -627,7 +623,6 @@ function renderTextInput(params: {
disabled: boolean;
showLabel?: boolean;
searchCriteria?: ConfigSearchCriteria;
streamMode?: boolean;
revealSensitive?: boolean;
isSensitivePathRevealed?: (path: Array<string | number>) => boolean;
onToggleSensitivePath?: (path: Array<string | number>) => void;
@@ -642,7 +637,6 @@ function renderTextInput(params: {
path,
value,
hints,
streamMode: params.streamMode ?? false,
revealSensitive: params.revealSensitive ?? false,
isSensitivePathRevealed: params.isSensitivePathRevealed,
});
@@ -819,7 +813,6 @@ function renderJsonTextarea(params: {
hints: ConfigUiHints;
disabled: boolean;
showLabel?: boolean;
streamMode?: boolean;
revealSensitive?: boolean;
isSensitivePathRevealed?: (path: Array<string | number>) => boolean;
onToggleSensitivePath?: (path: Array<string | number>) => void;
@@ -833,7 +826,6 @@ function renderJsonTextarea(params: {
path,
value,
hints,
streamMode: params.streamMode ?? false,
revealSensitive: params.revealSensitive ?? false,
isSensitivePathRevealed: params.isSensitivePathRevealed,
});
@@ -890,7 +882,6 @@ function renderObject(params: {
disabled: boolean;
showLabel?: boolean;
searchCriteria?: ConfigSearchCriteria;
streamMode?: boolean;
revealSensitive?: boolean;
isSensitivePathRevealed?: (path: Array<string | number>) => boolean;
onToggleSensitivePath?: (path: Array<string | number>) => void;
@@ -905,7 +896,6 @@ function renderObject(params: {
disabled,
onPatch,
searchCriteria,
streamMode,
revealSensitive,
isSensitivePathRevealed,
onToggleSensitivePath,
@@ -950,7 +940,6 @@ function renderObject(params: {
unsupported,
disabled,
searchCriteria: childSearchCriteria,
streamMode,
revealSensitive,
isSensitivePathRevealed,
onToggleSensitivePath,
@@ -968,7 +957,6 @@ function renderObject(params: {
disabled,
reservedKeys: reserved,
searchCriteria: childSearchCriteria,
streamMode,
revealSensitive,
isSensitivePathRevealed,
onToggleSensitivePath,
@@ -1022,7 +1010,6 @@ function renderArray(params: {
disabled: boolean;
showLabel?: boolean;
searchCriteria?: ConfigSearchCriteria;
streamMode?: boolean;
revealSensitive?: boolean;
isSensitivePathRevealed?: (path: Array<string | number>) => boolean;
onToggleSensitivePath?: (path: Array<string | number>) => void;
@@ -1037,7 +1024,6 @@ function renderArray(params: {
disabled,
onPatch,
searchCriteria,
streamMode,
revealSensitive,
isSensitivePathRevealed,
onToggleSensitivePath,
@@ -1121,7 +1107,6 @@ function renderArray(params: {
disabled,
searchCriteria: childSearchCriteria,
showLabel: false,
streamMode,
revealSensitive,
isSensitivePathRevealed,
onToggleSensitivePath,
@@ -1147,7 +1132,6 @@ function renderMapField(params: {
disabled: boolean;
reservedKeys: Set<string>;
searchCriteria?: ConfigSearchCriteria;
streamMode?: boolean;
revealSensitive?: boolean;
isSensitivePathRevealed?: (path: Array<string | number>) => boolean;
onToggleSensitivePath?: (path: Array<string | number>) => void;
@@ -1163,7 +1147,6 @@ function renderMapField(params: {
reservedKeys,
onPatch,
searchCriteria,
streamMode,
revealSensitive,
isSensitivePathRevealed,
onToggleSensitivePath,
@@ -1222,7 +1205,6 @@ function renderMapField(params: {
path: valuePath,
value: entryValue,
hints,
streamMode: streamMode ?? false,
revealSensitive: revealSensitive ?? false,
isSensitivePathRevealed,
});
@@ -1313,7 +1295,6 @@ function renderMapField(params: {
disabled,
searchCriteria,
showLabel: false,
streamMode,
revealSensitive,
isSensitivePathRevealed,
onToggleSensitivePath,

View File

@@ -13,7 +13,6 @@ export type ConfigFormProps = {
searchQuery?: string;
activeSection?: string | null;
activeSubsection?: string | null;
streamMode?: boolean;
revealSensitive?: boolean;
isSensitivePathRevealed?: (path: Array<string | number>) => boolean;
onToggleSensitivePath?: (path: Array<string | number>) => void;
@@ -435,7 +434,6 @@ export function renderConfigForm(props: ConfigFormProps) {
disabled: props.disabled ?? false,
showLabel: false,
searchCriteria,
streamMode: props.streamMode ?? false,
revealSensitive: props.revealSensitive ?? false,
isSensitivePathRevealed: props.isSensitivePathRevealed,
onToggleSensitivePath: props.onToggleSensitivePath,
@@ -474,7 +472,6 @@ export function renderConfigForm(props: ConfigFormProps) {
disabled: props.disabled ?? false,
showLabel: false,
searchCriteria,
streamMode: props.streamMode ?? false,
revealSensitive: props.revealSensitive ?? false,
isSensitivePathRevealed: props.isSensitivePathRevealed,
onToggleSensitivePath: props.onToggleSensitivePath,

View File

@@ -6,7 +6,6 @@ import type { ConfigUiHints } from "../types.ts";
import {
countSensitiveConfigValues,
humanize,
isSensitiveConfigPath,
pathKey,
REDACTED_PLACEHOLDER,
schemaType,
@@ -34,7 +33,6 @@ export type ConfigProps = {
searchQuery: string;
activeSection: string | null;
activeSubsection: string | null;
streamMode: boolean;
onRawChange: (next: string) => void;
onFormModeChange: (mode: "form" | "raw") => void;
onFormPatch: (path: Array<string | number>, value: unknown) => void;
@@ -504,40 +502,10 @@ function truncateValue(value: unknown, maxLen = 40): string {
return str.slice(0, maxLen - 3) + "...";
}
/**
* Render diff value with redaction when in stream mode or path is sensitive.
* Prevents secrets from appearing in diff panel during screen sharing.
*/
function renderDiffValue(
path: string,
value: unknown,
streamMode: boolean,
uiHints: ConfigUiHints,
): string {
const hint = uiHints[path];
const sensitive = hint?.sensitive ?? isSensitiveConfigPath(path);
if (streamMode && sensitive) {
return REDACTED_PLACEHOLDER;
}
function renderDiffValue(path: string, value: unknown, _uiHints: ConfigUiHints): string {
return truncateValue(value);
}
/**
* Lightweight scan for sensitive keywords in raw config text.
* Used when stream mode is on and formValue hasn't been parsed yet.
*/
function containsSensitiveKeywords(raw: string): boolean {
// Match key patterns from SENSITIVE_PATTERNS in config-form.shared.ts
return (
/["']?\w*token["']?\s*:/i.test(raw) ||
/["']?\w*password["']?\s*:/i.test(raw) ||
/["']?\w*secret["']?\s*:/i.test(raw) ||
/["']?\w*api.?key["']?\s*:/i.test(raw)
);
}
type ThemeOption = { id: ThemeName; label: string; description: string; icon: TemplateResult };
const THEME_OPTIONS: ThemeOption[] = [
{ id: "claw", label: "Claw", description: "Chroma family", icon: icons.zap },
@@ -702,12 +670,8 @@ export function renderConfig(props: ConfigProps) {
unsupportedPaths: scopeUnsupportedPaths(rawAnalysis.unsupportedPaths, { include, exclude }),
};
const formUnsafe = analysis.schema ? analysis.unsupportedPaths.length > 0 : false;
// Force raw mode when form can't safely represent all config fields
const formMode = formUnsafe ? "raw" : showModeToggle ? props.formMode : "form";
if (formUnsafe && props.formMode === "form") {
props.onFormModeChange("raw");
}
const envSensitiveVisible = !props.streamMode && cvs.envRevealed;
const formMode = showModeToggle ? props.formMode : "form";
const envSensitiveVisible = cvs.envRevealed;
// Build categorised nav from schema - only include sections that exist in the schema
const schemaProps = analysis.schema?.properties ?? {};
@@ -906,7 +870,7 @@ export function renderConfig(props: ConfigProps) {
<div class="config-mode-toggle">
<button
class="config-mode-toggle__btn ${formMode === "form" ? "active" : ""}"
?disabled=${formUnsafe || props.schemaLoading || !props.schema}
?disabled=${props.schemaLoading || !props.schema}
title=${formUnsafe ? "Form view can't safely edit some fields" : ""}
@click=${() => props.onFormModeChange("form")}
>
@@ -974,11 +938,11 @@ export function renderConfig(props: ConfigProps) {
<div class="config-diff__path">${change.path}</div>
<div class="config-diff__values">
<span class="config-diff__from"
>${renderDiffValue(change.path, change.from, props.streamMode, props.uiHints)}</span
>${renderDiffValue(change.path, change.from, props.uiHints)}</span
>
<span class="config-diff__arrow">→</span>
<span class="config-diff__to"
>${renderDiffValue(change.path, change.to, props.streamMode, props.uiHints)}</span
>${renderDiffValue(change.path, change.to, props.uiHints)}</span
>
</div>
</div>
@@ -1013,18 +977,8 @@ export function renderConfig(props: ConfigProps) {
? html`
<button
class="config-env-peek-btn ${envSensitiveVisible ? "config-env-peek-btn--active" : ""}"
title=${
props.streamMode
? "Disable stream mode to reveal env values"
: envSensitiveVisible
? "Hide env values"
: "Reveal env values"
}
?disabled=${props.streamMode}
title=${envSensitiveVisible ? "Hide env values" : "Reveal env values"}
@click=${() => {
if (props.streamMode) {
return;
}
cvs.envRevealed = !cvs.envRevealed;
props.onRawChange(props.raw);
}}
@@ -1070,7 +1024,6 @@ export function renderConfig(props: ConfigProps) {
searchQuery: props.searchQuery,
activeSection: props.activeSection,
activeSubsection: effectiveSubsection,
streamMode: props.streamMode,
revealSensitive:
props.activeSection === "env" ? envSensitiveVisible : false,
isSensitivePathRevealed,
@@ -1087,22 +1040,14 @@ export function renderConfig(props: ConfigProps) {
[],
props.uiHints,
);
// In stream mode, also check raw content for sensitive keywords
// to prevent newly-entered secrets from being visible before parse
const rawHasSensitiveKeywords =
props.streamMode && containsSensitiveKeywords(props.raw);
const blurred =
(sensitiveCount > 0 || rawHasSensitiveKeywords) &&
(props.streamMode || !cvs.rawRevealed);
const canReveal =
(sensitiveCount > 0 || rawHasSensitiveKeywords) && !props.streamMode;
const blurred = sensitiveCount > 0 && !cvs.rawRevealed;
return html`
${
formUnsafe
? html`
<div class="callout info" style="margin-bottom: 12px">
Form view is disabled because your config contains fields the form editor can't safely represent.
Edit in Raw to avoid losing entries.
Your config contains fields the form editor can't safely represent. Use Raw mode to edit those
entries.
</div>
`
: nothing
@@ -1118,19 +1063,11 @@ export function renderConfig(props: ConfigProps) {
class="btn btn--icon ${blurred ? "" : "active"}"
style="width:28px;height:28px;padding:0;"
title=${
canReveal
? blurred
? "Reveal sensitive values"
: "Hide sensitive values"
: "Disable stream mode to reveal sensitive values"
blurred ? "Reveal sensitive values" : "Hide sensitive values"
}
aria-label="Toggle raw config redaction"
aria-pressed=${!blurred}
?disabled=${!canReveal}
@click=${() => {
if (!canReveal) {
return;
}
cvs.rawRevealed = !cvs.rawRevealed;
props.onRawChange(props.raw);
}}

View File

@@ -8,14 +8,13 @@ export type InstancesProps = {
entries: PresenceEntry[];
lastError: string | null;
statusMessage: string | null;
streamMode: boolean;
onRefresh: () => void;
};
let hostsRevealed = false;
export function renderInstances(props: InstancesProps) {
const masked = props.streamMode || !hostsRevealed;
const masked = !hostsRevealed;
return html`
<section class="card">

View File

@@ -18,14 +18,9 @@ export type OverviewCardsProps = {
cronJobs: CronJob[];
cronStatus: CronStatus | null;
presenceCount: number;
redacted: boolean;
onNavigate: (tab: string) => void;
};
function redact(value: string, redacted: boolean) {
return redacted ? "••••••" : value;
}
const DIGIT_RUN = /\d{3,}/g;
function blurDigits(value: string): TemplateResult {
@@ -40,14 +35,13 @@ type StatCard = {
label: string;
value: string | TemplateResult;
hint: string | TemplateResult;
redacted?: boolean;
};
function renderStatCard(card: StatCard, onNavigate: (tab: string) => void) {
return html`
<button class="ov-card" data-kind=${card.kind} @click=${() => onNavigate(card.tab)}>
<span class="ov-card__label">${card.label}</span>
<span class="ov-card__value ${card.redacted ? "redacted" : ""}">${card.value}</span>
<span class="ov-card__value">${card.value}</span>
<span class="ov-card__hint">${card.hint}</span>
</button>
`;
@@ -111,9 +105,8 @@ export function renderOverviewCards(props: OverviewCardsProps) {
kind: "cost",
tab: "usage",
label: t("overview.cards.cost"),
value: redact(totalCost, props.redacted),
hint: redact(`${totalTokens} tokens · ${totalMessages} msgs`, props.redacted),
redacted: props.redacted,
value: totalCost,
hint: `${totalTokens} tokens · ${totalMessages} msgs`,
},
{
kind: "sessions",
@@ -153,8 +146,8 @@ export function renderOverviewCards(props: OverviewCardsProps) {
<ul class="ov-recent__list">
${sessions.map(
(s) => html`
<li class="ov-recent__row ${props.redacted ? "redacted" : ""}">
<span class="ov-recent__key">${props.redacted ? redact(s.displayName || s.label || s.key, true) : blurDigits(s.displayName || s.label || s.key)}</span>
<li class="ov-recent__row">
<span class="ov-recent__key">${blurDigits(s.displayName || s.label || s.key)}</span>
<span class="ov-recent__model">${s.model ?? ""}</span>
<span class="ov-recent__time">${s.updatedAt ? formatRelativeTimestamp(s.updatedAt) : ""}</span>
</li>

View File

@@ -6,7 +6,6 @@ import { formatEventPayload } from "../presenter.ts";
export type OverviewEventLogProps = {
events: EventLogEntry[];
redacted: boolean;
};
export function renderOverviewEventLog(props: OverviewEventLogProps) {
@@ -23,7 +22,7 @@ export function renderOverviewEventLog(props: OverviewEventLogProps) {
${t("overview.eventLog.title")}
<span class="ov-count-badge">${props.events.length}</span>
</summary>
<div class="ov-event-log-list ${props.redacted ? "redacted" : ""}">
<div class="ov-event-log-list">
${visible.map(
(entry) => html`
<div class="ov-event-log-entry">

View File

@@ -10,7 +10,6 @@ function stripAnsi(text: string): string {
export type OverviewLogTailProps = {
lines: string[];
redacted: boolean;
onRefreshLogs: () => void;
};
@@ -19,12 +18,10 @@ export function renderOverviewLogTail(props: OverviewLogTailProps) {
return nothing;
}
const displayLines = props.redacted
? "[log hidden]"
: props.lines
.slice(-50)
.map((line) => stripAnsi(line))
.join("\n");
const displayLines = props.lines
.slice(-50)
.map((line) => stripAnsi(line))
.join("\n");
return html`
<details class="card ov-log-tail">
@@ -41,7 +38,7 @@ export function renderOverviewLogTail(props: OverviewLogTailProps) {
}}
>${icons.loader}</span>
</summary>
<pre class="ov-log-tail-content ${props.redacted ? "redacted" : ""}">${displayLines}</pre>
<pre class="ov-log-tail-content">${displayLines}</pre>
</details>
`;
}

View File

@@ -46,7 +46,6 @@ export type OverviewProps = {
attentionItems: AttentionItem[];
eventLog: EventLogEntry[];
overviewLogLines: string[];
streamMode: boolean;
showGatewayToken: boolean;
showGatewayPassword: boolean;
onSettingsChange: (next: UiSettings) => void;
@@ -58,7 +57,6 @@ export type OverviewProps = {
onRefresh: () => void;
onNavigate: (tab: string) => void;
onRefreshLogs: () => void;
onToggleStreamMode: () => void;
};
export function renderOverview(props: OverviewProps) {
@@ -198,7 +196,7 @@ export function renderOverview(props: OverviewProps) {
<div class="card">
<div class="card-title">${t("overview.access.title")}</div>
<div class="card-sub">${t("overview.access.subtitle")}</div>
<div class="ov-access-grid ${props.streamMode ? "redacted" : ""}" style="margin-top: 16px;">
<div class="ov-access-grid" style="margin-top: 16px;">
<label class="field ov-access-grid__full">
<span>${t("overview.access.wsUrl")}</span>
<input
@@ -376,18 +374,6 @@ export function renderOverview(props: OverviewProps) {
</div>
</section>
${
props.streamMode
? html`<div class="callout ov-stream-banner" style="margin-top: 18px;">
<span class="nav-item__icon">${icons.radio}</span>
${t("overview.streamMode.active")}
<button class="btn btn--sm" style="margin-left: auto;" @click=${() => props.onToggleStreamMode()}>
${t("overview.streamMode.disable")}
</button>
</div>`
: nothing
}
<div class="ov-section-divider"></div>
${renderOverviewCards({
@@ -397,7 +383,6 @@ export function renderOverview(props: OverviewProps) {
cronJobs: props.cronJobs,
cronStatus: props.cronStatus,
presenceCount: props.presenceCount,
redacted: props.streamMode,
onNavigate: props.onNavigate,
})}
@@ -408,12 +393,10 @@ export function renderOverview(props: OverviewProps) {
<div class="ov-bottom-grid" style="margin-top: 18px;">
${renderOverviewEventLog({
events: props.eventLog,
redacted: props.streamMode,
})}
${renderOverviewLogTail({
lines: props.overviewLogLines,
redacted: props.streamMode,
onRefreshLogs: props.onRefreshLogs,
})}
</div>

View File

@@ -10,6 +10,7 @@ import {
} from "./skills-shared.ts";
export type SkillsProps = {
connected: boolean;
loading: boolean;
report: SkillStatusReport | null;
error: string | null;
@@ -42,7 +43,7 @@ export function renderSkills(props: SkillsProps) {
<div class="card-title">Skills</div>
<div class="card-sub">Installed skills and their status.</div>
</div>
<button class="btn" ?disabled=${props.loading} @click=${props.onRefresh}>
<button class="btn" ?disabled=${props.loading || !props.connected} @click=${props.onRefresh}>
${props.loading ? "Loading…" : "Refresh"}
</button>
</div>
@@ -74,7 +75,13 @@ export function renderSkills(props: SkillsProps) {
${
filtered.length === 0
? html`
<div class="muted" style="margin-top: 16px">No skills found.</div>
<div class="muted" style="margin-top: 16px">
${
!props.connected && !props.report
? "Not connected to gateway."
: "No skills found."
}
</div>
`
: html`
<div class="agent-skills-groups" style="margin-top: 16px;">