mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-18 04:31:10 +00:00
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:
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -144,10 +144,6 @@ export const zh_CN: TranslationMap = {
|
||||
refreshAll: "全部刷新",
|
||||
terminal: "终端",
|
||||
},
|
||||
streamMode: {
|
||||
active: "流模式 — 数据已隐藏",
|
||||
disable: "禁用",
|
||||
},
|
||||
palette: {
|
||||
placeholder: "输入命令…",
|
||||
noResults: "无结果",
|
||||
|
||||
@@ -144,10 +144,6 @@ export const zh_TW: TranslationMap = {
|
||||
refreshAll: "全部刷新",
|
||||
terminal: "終端",
|
||||
},
|
||||
streamMode: {
|
||||
active: "串流模式 — 數據已隱藏",
|
||||
disable: "禁用",
|
||||
},
|
||||
palette: {
|
||||
placeholder: "輸入指令…",
|
||||
noResults: "無結果",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
|
||||
@@ -295,7 +295,6 @@ export type AppViewState = {
|
||||
paletteOpen: boolean;
|
||||
paletteQuery: string;
|
||||
paletteActiveIndex: number;
|
||||
streamMode: boolean;
|
||||
overviewShowGatewayToken: boolean;
|
||||
overviewShowGatewayPassword: boolean;
|
||||
overviewLogLines: string[];
|
||||
|
||||
@@ -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[] = [];
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}}
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;">
|
||||
|
||||
Reference in New Issue
Block a user