mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-05 04:50:23 +00:00
fix(ui): localize control ui strings
This commit is contained in:
@@ -699,7 +699,9 @@ export function renderApp(state: AppViewState) {
|
||||
?disabled=${dreamingLoading || state.dreamDiaryLoading}
|
||||
@click=${refreshDreaming}
|
||||
>
|
||||
${dreamingRefreshLoading ? "Refreshing…" : "Refresh"}
|
||||
${dreamingRefreshLoading
|
||||
? t("dreaming.header.refreshing")
|
||||
: t("dreaming.header.refresh")}
|
||||
</button>
|
||||
<button
|
||||
class="dreams__phase-toggle ${dreamingOn
|
||||
@@ -709,9 +711,9 @@ export function renderApp(state: AppViewState) {
|
||||
@click=${() => applyDreamingEnabled(!dreamingOn)}
|
||||
>
|
||||
<span class="dreams__phase-toggle-dot"></span>
|
||||
<span class="dreams__phase-toggle-label"
|
||||
>${dreamingOn ? "Dreaming On" : "Dreaming Off"}</span
|
||||
>
|
||||
<span class="dreams__phase-toggle-label">
|
||||
${dreamingOn ? t("dreaming.header.on") : t("dreaming.header.off")}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
`
|
||||
@@ -1859,7 +1861,7 @@ export function renderApp(state: AppViewState) {
|
||||
assistantName: state.assistantName,
|
||||
configPath: state.configSnapshot?.path ?? null,
|
||||
rawAvailable: typeof state.configSnapshot?.raw === "string",
|
||||
navRootLabel: "Appearance",
|
||||
navRootLabel: t("tabs.appearance"),
|
||||
includeSections: [...APPEARANCE_SECTION_KEYS],
|
||||
includeVirtualSections: true,
|
||||
})
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { formatDurationHuman } from "../../../src/infra/format-time/format-duration.ts";
|
||||
import { formatRelativeTimestamp } from "../../../src/infra/format-time/format-relative.ts";
|
||||
import { stripAssistantInternalScaffolding } from "../../../src/shared/text/assistant-visible-text.js";
|
||||
import { t } from "../i18n/index.ts";
|
||||
|
||||
export { formatRelativeTimestamp, formatDurationHuman };
|
||||
|
||||
export function formatMs(ms?: number | null): string {
|
||||
if (!ms && ms !== 0) {
|
||||
return "n/a";
|
||||
return t("common.na");
|
||||
}
|
||||
return new Date(ms).toLocaleString();
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { t } from "../i18n/index.ts";
|
||||
import { formatRelativeTimestamp, formatDurationHuman, formatMs } from "./format.ts";
|
||||
import type { CronJob, GatewaySessionRow, PresenceEntry } from "./types.ts";
|
||||
|
||||
@@ -11,12 +12,12 @@ export function formatPresenceSummary(entry: PresenceEntry): string {
|
||||
|
||||
export function formatPresenceAge(entry: PresenceEntry): string {
|
||||
const ts = entry.ts ?? null;
|
||||
return ts ? formatRelativeTimestamp(ts) : "n/a";
|
||||
return ts ? formatRelativeTimestamp(ts) : t("common.na");
|
||||
}
|
||||
|
||||
export function formatNextRun(ms?: number | null) {
|
||||
if (!ms) {
|
||||
return "n/a";
|
||||
return t("common.na");
|
||||
}
|
||||
const weekday = new Date(ms).toLocaleDateString(undefined, { weekday: "short" });
|
||||
return `${weekday}, ${formatMs(ms)} (${formatRelativeTimestamp(ms)})`;
|
||||
@@ -24,7 +25,7 @@ export function formatNextRun(ms?: number | null) {
|
||||
|
||||
export function formatSessionTokens(row: GatewaySessionRow) {
|
||||
if (row.totalTokens == null) {
|
||||
return "n/a";
|
||||
return t("common.na");
|
||||
}
|
||||
const total = row.totalTokens ?? 0;
|
||||
const ctx = row.contextTokens ?? 0;
|
||||
@@ -45,9 +46,9 @@ export function formatEventPayload(payload: unknown): string {
|
||||
|
||||
export function formatCronState(job: CronJob) {
|
||||
const state = job.state ?? {};
|
||||
const next = state.nextRunAtMs ? formatMs(state.nextRunAtMs) : "n/a";
|
||||
const last = state.lastRunAtMs ? formatMs(state.lastRunAtMs) : "n/a";
|
||||
const status = state.lastStatus ?? "n/a";
|
||||
const next = state.nextRunAtMs ? formatMs(state.nextRunAtMs) : t("common.na");
|
||||
const last = state.lastRunAtMs ? formatMs(state.lastRunAtMs) : t("common.na");
|
||||
const status = state.lastStatus ?? t("common.na");
|
||||
return `${status} · next ${next} · last ${last}`;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { html, nothing } from "lit";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import type {
|
||||
AgentIdentityResult,
|
||||
AgentsFilesListResult,
|
||||
@@ -205,7 +206,7 @@ export function renderAgentOverview(params: {
|
||||
?disabled=${configLoading}
|
||||
@click=${onConfigReload}
|
||||
>
|
||||
Reload Config
|
||||
${t("common.reloadConfig")}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -3,6 +3,7 @@ import DOMPurify from "dompurify";
|
||||
import { html, nothing } from "lit";
|
||||
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
||||
import { marked } from "marked";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import { formatRelativeTimestamp } from "../format.ts";
|
||||
import { icons } from "../icons.ts";
|
||||
import {
|
||||
@@ -175,7 +176,7 @@ export function renderAgentChannels(params: {
|
||||
<div class="card-sub">Gateway-wide channel status snapshot.</div>
|
||||
</div>
|
||||
<button class="btn btn--sm" ?disabled=${params.loading} @click=${params.onRefresh}>
|
||||
${params.loading ? "Refreshing…" : "Refresh"}
|
||||
${params.loading ? t("common.refreshing") : t("common.refresh")}
|
||||
</button>
|
||||
</div>
|
||||
<div class="muted" style="margin-top: 8px;">Last refresh: ${lastSuccessLabel}</div>
|
||||
@@ -270,7 +271,7 @@ export function renderAgentCron(params: {
|
||||
<div class="card-sub">Gateway cron status.</div>
|
||||
</div>
|
||||
<button class="btn btn--sm" ?disabled=${params.loading} @click=${params.onRefresh}>
|
||||
${params.loading ? "Refreshing…" : "Refresh"}
|
||||
${params.loading ? t("common.refreshing") : t("common.refresh")}
|
||||
</button>
|
||||
</div>
|
||||
<div class="stat-grid" style="margin-top: 16px;">
|
||||
@@ -373,7 +374,7 @@ export function renderAgentFiles(params: {
|
||||
?disabled=${params.agentFilesLoading}
|
||||
@click=${() => params.onLoadFiles(params.agentId)}
|
||||
>
|
||||
${params.agentFilesLoading ? "Loading…" : "Refresh"}
|
||||
${params.agentFilesLoading ? t("common.loading") : t("common.refresh")}
|
||||
</button>
|
||||
</div>
|
||||
${list
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { html, nothing } from "lit";
|
||||
import { normalizeToolName } from "../../../../src/agents/tool-policy-shared.js";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import type {
|
||||
SkillStatusEntry,
|
||||
SkillStatusReport,
|
||||
@@ -188,7 +189,7 @@ export function renderAgentTools(params: {
|
||||
?disabled=${params.configLoading}
|
||||
@click=${params.onConfigReload}
|
||||
>
|
||||
Reload Config
|
||||
${t("common.reloadConfig")}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn--sm primary"
|
||||
@@ -468,10 +469,10 @@ export function renderAgentSkills(params: {
|
||||
?disabled=${params.configLoading}
|
||||
@click=${params.onConfigReload}
|
||||
>
|
||||
Reload Config
|
||||
${t("common.reloadConfig")}
|
||||
</button>
|
||||
<button class="btn btn--sm" ?disabled=${params.loading} @click=${params.onRefresh}>
|
||||
${params.loading ? "Loading…" : "Refresh"}
|
||||
${params.loading ? t("common.loading") : t("common.refresh")}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn--sm primary"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { html, nothing } from "lit";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import type {
|
||||
AgentIdentityResult,
|
||||
AgentsFilesListResult,
|
||||
@@ -196,7 +197,7 @@ export function renderAgents(props: AgentsProps) {
|
||||
?disabled=${props.loading}
|
||||
@click=${props.onRefresh}
|
||||
>
|
||||
${props.loading ? "Loading…" : "Refresh"}
|
||||
${props.loading ? t("common.loading") : t("common.refresh")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { html } from "lit";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import type { ConfigUiHints } from "../types.ts";
|
||||
import { formatChannelExtraValue, resolveChannelConfigValue } from "./channel-config-extras.ts";
|
||||
import type { ChannelsProps } from "./channels.types.ts";
|
||||
@@ -135,7 +136,7 @@ export function renderChannelConfigSection(params: { channelId: string; props: C
|
||||
${props.configSaving ? "Saving…" : "Save"}
|
||||
</button>
|
||||
<button class="btn" ?disabled=${disabled} @click=${() => props.onConfigReload()}>
|
||||
Reload
|
||||
${t("common.reload")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { html, nothing } from "lit";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import { formatRelativeTimestamp } from "../format.ts";
|
||||
import type { DiscordStatus } from "../types.ts";
|
||||
import { renderChannelConfigSection } from "./channels.config.ts";
|
||||
@@ -22,27 +23,27 @@ export function renderDiscordCard(params: {
|
||||
subtitle: "Bot status and channel configuration.",
|
||||
accountCountLabel,
|
||||
statusRows: [
|
||||
{ label: "Configured", value: formatNullableBoolean(configured) },
|
||||
{ label: "Running", value: discord?.running ? "Yes" : "No" },
|
||||
{ label: t("common.configured"), value: formatNullableBoolean(configured) },
|
||||
{ label: t("common.running"), value: discord?.running ? t("common.yes") : t("common.no") },
|
||||
{
|
||||
label: "Last start",
|
||||
value: discord?.lastStartAt ? formatRelativeTimestamp(discord.lastStartAt) : "n/a",
|
||||
label: t("common.lastStart"),
|
||||
value: discord?.lastStartAt ? formatRelativeTimestamp(discord.lastStartAt) : t("common.na"),
|
||||
},
|
||||
{
|
||||
label: "Last probe",
|
||||
value: discord?.lastProbeAt ? formatRelativeTimestamp(discord.lastProbeAt) : "n/a",
|
||||
label: t("common.lastProbe"),
|
||||
value: discord?.lastProbeAt ? formatRelativeTimestamp(discord.lastProbeAt) : t("common.na"),
|
||||
},
|
||||
],
|
||||
lastError: discord?.lastError,
|
||||
secondaryCallout: discord?.probe
|
||||
? html`<div class="callout" style="margin-top: 12px;">
|
||||
Probe ${discord.probe.ok ? "ok" : "failed"} · ${discord.probe.status ?? ""}
|
||||
${discord.probe.error ?? ""}
|
||||
${discord.probe.ok ? t("common.probeOk") : t("common.probeFailed")} ·
|
||||
${discord.probe.status ?? ""} ${discord.probe.error ?? ""}
|
||||
</div>`
|
||||
: nothing,
|
||||
configSection: renderChannelConfigSection({ channelId: "discord", props }),
|
||||
footer: html`<div class="row" style="margin-top: 12px;">
|
||||
<button class="btn" @click=${() => props.onRefresh(true)}>Probe</button>
|
||||
<button class="btn" @click=${() => props.onRefresh(true)}>${t("common.probe")}</button>
|
||||
</div>`,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { html, nothing } from "lit";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import { formatRelativeTimestamp } from "../format.ts";
|
||||
import type { GoogleChatStatus } from "../types.ts";
|
||||
import { renderChannelConfigSection } from "./channels.config.ts";
|
||||
@@ -22,37 +23,45 @@ export function renderGoogleChatCard(params: {
|
||||
subtitle: "Chat API webhook status and channel configuration.",
|
||||
accountCountLabel,
|
||||
statusRows: [
|
||||
{ label: "Configured", value: formatNullableBoolean(configured) },
|
||||
{ label: t("common.configured"), value: formatNullableBoolean(configured) },
|
||||
{
|
||||
label: "Running",
|
||||
value: googleChat ? (googleChat.running ? "Yes" : "No") : "n/a",
|
||||
label: t("common.running"),
|
||||
value: googleChat
|
||||
? googleChat.running
|
||||
? t("common.yes")
|
||||
: t("common.no")
|
||||
: t("common.na"),
|
||||
},
|
||||
{ label: "Credential", value: googleChat?.credentialSource ?? "n/a" },
|
||||
{ label: t("common.credential"), value: googleChat?.credentialSource ?? t("common.na") },
|
||||
{
|
||||
label: "Audience",
|
||||
label: t("common.audience"),
|
||||
value: googleChat?.audienceType
|
||||
? `${googleChat.audienceType}${googleChat.audience ? ` · ${googleChat.audience}` : ""}`
|
||||
: "n/a",
|
||||
: t("common.na"),
|
||||
},
|
||||
{
|
||||
label: "Last start",
|
||||
value: googleChat?.lastStartAt ? formatRelativeTimestamp(googleChat.lastStartAt) : "n/a",
|
||||
label: t("common.lastStart"),
|
||||
value: googleChat?.lastStartAt
|
||||
? formatRelativeTimestamp(googleChat.lastStartAt)
|
||||
: t("common.na"),
|
||||
},
|
||||
{
|
||||
label: "Last probe",
|
||||
value: googleChat?.lastProbeAt ? formatRelativeTimestamp(googleChat.lastProbeAt) : "n/a",
|
||||
label: t("common.lastProbe"),
|
||||
value: googleChat?.lastProbeAt
|
||||
? formatRelativeTimestamp(googleChat.lastProbeAt)
|
||||
: t("common.na"),
|
||||
},
|
||||
],
|
||||
lastError: googleChat?.lastError,
|
||||
secondaryCallout: googleChat?.probe
|
||||
? html`<div class="callout" style="margin-top: 12px;">
|
||||
Probe ${googleChat.probe.ok ? "ok" : "failed"} · ${googleChat.probe.status ?? ""}
|
||||
${googleChat.probe.error ?? ""}
|
||||
${googleChat.probe.ok ? t("common.probeOk") : t("common.probeFailed")} ·
|
||||
${googleChat.probe.status ?? ""} ${googleChat.probe.error ?? ""}
|
||||
</div>`
|
||||
: nothing,
|
||||
configSection: renderChannelConfigSection({ channelId: "googlechat", props }),
|
||||
footer: html`<div class="row" style="margin-top: 12px;">
|
||||
<button class="btn" @click=${() => props.onRefresh(true)}>Probe</button>
|
||||
<button class="btn" @click=${() => props.onRefresh(true)}>${t("common.probe")}</button>
|
||||
</div>`,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { html, nothing } from "lit";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import { formatRelativeTimestamp } from "../format.ts";
|
||||
import type { IMessageStatus } from "../types.ts";
|
||||
import { renderChannelConfigSection } from "./channels.config.ts";
|
||||
@@ -22,26 +23,31 @@ export function renderIMessageCard(params: {
|
||||
subtitle: "macOS bridge status and channel configuration.",
|
||||
accountCountLabel,
|
||||
statusRows: [
|
||||
{ label: "Configured", value: formatNullableBoolean(configured) },
|
||||
{ label: "Running", value: imessage?.running ? "Yes" : "No" },
|
||||
{ label: t("common.configured"), value: formatNullableBoolean(configured) },
|
||||
{ label: t("common.running"), value: imessage?.running ? t("common.yes") : t("common.no") },
|
||||
{
|
||||
label: "Last start",
|
||||
value: imessage?.lastStartAt ? formatRelativeTimestamp(imessage.lastStartAt) : "n/a",
|
||||
label: t("common.lastStart"),
|
||||
value: imessage?.lastStartAt
|
||||
? formatRelativeTimestamp(imessage.lastStartAt)
|
||||
: t("common.na"),
|
||||
},
|
||||
{
|
||||
label: "Last probe",
|
||||
value: imessage?.lastProbeAt ? formatRelativeTimestamp(imessage.lastProbeAt) : "n/a",
|
||||
label: t("common.lastProbe"),
|
||||
value: imessage?.lastProbeAt
|
||||
? formatRelativeTimestamp(imessage.lastProbeAt)
|
||||
: t("common.na"),
|
||||
},
|
||||
],
|
||||
lastError: imessage?.lastError,
|
||||
secondaryCallout: imessage?.probe
|
||||
? html`<div class="callout" style="margin-top: 12px;">
|
||||
Probe ${imessage.probe.ok ? "ok" : "failed"} · ${imessage.probe.error ?? ""}
|
||||
${imessage.probe.ok ? t("common.probeOk") : t("common.probeFailed")} ·
|
||||
${imessage.probe.error ?? ""}
|
||||
</div>`
|
||||
: nothing,
|
||||
configSection: renderChannelConfigSection({ channelId: "imessage", props }),
|
||||
footer: html`<div class="row" style="margin-top: 12px;">
|
||||
<button class="btn" @click=${() => props.onRefresh(true)}>Probe</button>
|
||||
<button class="btn" @click=${() => props.onRefresh(true)}>${t("common.probe")}</button>
|
||||
</div>`,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { html, nothing } from "lit";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import { formatRelativeTimestamp } from "../format.ts";
|
||||
import type { ChannelAccountSnapshot, NostrStatus } from "../types.ts";
|
||||
import { renderChannelConfigSection } from "./channels.config.ts";
|
||||
@@ -209,16 +210,18 @@ export function renderNostrCard(params: {
|
||||
<span>${summaryRunning ? "Yes" : "No"}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="label">Public Key</span>
|
||||
<span class="label">${t("common.publicKey")}</span>
|
||||
<span class="monospace" title="${summaryPublicKey ?? ""}"
|
||||
>${truncatePubkey(summaryPublicKey)}</span
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<span class="label">Last start</span>
|
||||
<span
|
||||
>${summaryLastStartAt ? formatRelativeTimestamp(summaryLastStartAt) : "n/a"}</span
|
||||
>
|
||||
<span class="label">${t("common.lastStart")}</span>
|
||||
<span>
|
||||
${summaryLastStartAt
|
||||
? formatRelativeTimestamp(summaryLastStartAt)
|
||||
: t("common.na")}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`}
|
||||
@@ -228,7 +231,7 @@ export function renderNostrCard(params: {
|
||||
${renderProfileSection()} ${renderChannelConfigSection({ channelId: "nostr", props })}
|
||||
|
||||
<div class="row" style="margin-top: 12px;">
|
||||
<button class="btn" @click=${() => props.onRefresh(false)}>Refresh</button>
|
||||
<button class="btn" @click=${() => props.onRefresh(false)}>${t("common.refresh")}</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { html, nothing } from "lit";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import type { ChannelAccountSnapshot } from "../types.ts";
|
||||
import type { ChannelKey, ChannelsProps } from "./channels.types.ts";
|
||||
|
||||
@@ -87,9 +88,9 @@ export function resolveChannelConfigured(key: ChannelKey, props: ChannelsProps):
|
||||
|
||||
export function formatNullableBoolean(value: boolean | null): string {
|
||||
if (value == null) {
|
||||
return "n/a";
|
||||
return t("common.na");
|
||||
}
|
||||
return value ? "Yes" : "No";
|
||||
return value ? t("common.yes") : t("common.no");
|
||||
}
|
||||
|
||||
export function renderSingleAccountChannelCard(params: {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { html, nothing } from "lit";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import { formatRelativeTimestamp } from "../format.ts";
|
||||
import type { SignalStatus } from "../types.ts";
|
||||
import { renderChannelConfigSection } from "./channels.config.ts";
|
||||
@@ -22,28 +23,28 @@ export function renderSignalCard(params: {
|
||||
subtitle: "signal-cli status and channel configuration.",
|
||||
accountCountLabel,
|
||||
statusRows: [
|
||||
{ label: "Configured", value: formatNullableBoolean(configured) },
|
||||
{ label: "Running", value: signal?.running ? "Yes" : "No" },
|
||||
{ label: "Base URL", value: signal?.baseUrl ?? "n/a" },
|
||||
{ label: t("common.configured"), value: formatNullableBoolean(configured) },
|
||||
{ label: t("common.running"), value: signal?.running ? t("common.yes") : t("common.no") },
|
||||
{ label: t("common.baseUrl"), value: signal?.baseUrl ?? t("common.na") },
|
||||
{
|
||||
label: "Last start",
|
||||
value: signal?.lastStartAt ? formatRelativeTimestamp(signal.lastStartAt) : "n/a",
|
||||
label: t("common.lastStart"),
|
||||
value: signal?.lastStartAt ? formatRelativeTimestamp(signal.lastStartAt) : t("common.na"),
|
||||
},
|
||||
{
|
||||
label: "Last probe",
|
||||
value: signal?.lastProbeAt ? formatRelativeTimestamp(signal.lastProbeAt) : "n/a",
|
||||
label: t("common.lastProbe"),
|
||||
value: signal?.lastProbeAt ? formatRelativeTimestamp(signal.lastProbeAt) : t("common.na"),
|
||||
},
|
||||
],
|
||||
lastError: signal?.lastError,
|
||||
secondaryCallout: signal?.probe
|
||||
? html`<div class="callout" style="margin-top: 12px;">
|
||||
Probe ${signal.probe.ok ? "ok" : "failed"} · ${signal.probe.status ?? ""}
|
||||
${signal.probe.error ?? ""}
|
||||
${signal.probe.ok ? t("common.probeOk") : t("common.probeFailed")} ·
|
||||
${signal.probe.status ?? ""} ${signal.probe.error ?? ""}
|
||||
</div>`
|
||||
: nothing,
|
||||
configSection: renderChannelConfigSection({ channelId: "signal", props }),
|
||||
footer: html`<div class="row" style="margin-top: 12px;">
|
||||
<button class="btn" @click=${() => props.onRefresh(true)}>Probe</button>
|
||||
<button class="btn" @click=${() => props.onRefresh(true)}>${t("common.probe")}</button>
|
||||
</div>`,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { html, nothing } from "lit";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import { formatRelativeTimestamp } from "../format.ts";
|
||||
import type { SlackStatus } from "../types.ts";
|
||||
import { renderChannelConfigSection } from "./channels.config.ts";
|
||||
@@ -22,27 +23,27 @@ export function renderSlackCard(params: {
|
||||
subtitle: "Socket mode status and channel configuration.",
|
||||
accountCountLabel,
|
||||
statusRows: [
|
||||
{ label: "Configured", value: formatNullableBoolean(configured) },
|
||||
{ label: "Running", value: slack?.running ? "Yes" : "No" },
|
||||
{ label: t("common.configured"), value: formatNullableBoolean(configured) },
|
||||
{ label: t("common.running"), value: slack?.running ? t("common.yes") : t("common.no") },
|
||||
{
|
||||
label: "Last start",
|
||||
value: slack?.lastStartAt ? formatRelativeTimestamp(slack.lastStartAt) : "n/a",
|
||||
label: t("common.lastStart"),
|
||||
value: slack?.lastStartAt ? formatRelativeTimestamp(slack.lastStartAt) : t("common.na"),
|
||||
},
|
||||
{
|
||||
label: "Last probe",
|
||||
value: slack?.lastProbeAt ? formatRelativeTimestamp(slack.lastProbeAt) : "n/a",
|
||||
label: t("common.lastProbe"),
|
||||
value: slack?.lastProbeAt ? formatRelativeTimestamp(slack.lastProbeAt) : t("common.na"),
|
||||
},
|
||||
],
|
||||
lastError: slack?.lastError,
|
||||
secondaryCallout: slack?.probe
|
||||
? html`<div class="callout" style="margin-top: 12px;">
|
||||
Probe ${slack.probe.ok ? "ok" : "failed"} · ${slack.probe.status ?? ""}
|
||||
${slack.probe.error ?? ""}
|
||||
${slack.probe.ok ? t("common.probeOk") : t("common.probeFailed")} ·
|
||||
${slack.probe.status ?? ""} ${slack.probe.error ?? ""}
|
||||
</div>`
|
||||
: nothing,
|
||||
configSection: renderChannelConfigSection({ channelId: "slack", props }),
|
||||
footer: html`<div class="row" style="margin-top: 12px;">
|
||||
<button class="btn" @click=${() => props.onRefresh(true)}>Probe</button>
|
||||
<button class="btn" @click=${() => props.onRefresh(true)}>${t("common.probe")}</button>
|
||||
</div>`,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { html, nothing } from "lit";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import { formatRelativeTimestamp } from "../format.ts";
|
||||
import type { ChannelAccountSnapshot, TelegramStatus } from "../types.ts";
|
||||
import { renderChannelConfigSection } from "./channels.config.ts";
|
||||
@@ -31,19 +32,19 @@ export function renderTelegramCard(params: {
|
||||
</div>
|
||||
<div class="status-list account-card-status">
|
||||
<div>
|
||||
<span class="label">Running</span>
|
||||
<span>${account.running ? "Yes" : "No"}</span>
|
||||
<span class="label">${t("common.running")}</span>
|
||||
<span>${account.running ? t("common.yes") : t("common.no")}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="label">Configured</span>
|
||||
<span>${account.configured ? "Yes" : "No"}</span>
|
||||
<span class="label">${t("common.configured")}</span>
|
||||
<span>${account.configured ? t("common.yes") : t("common.no")}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="label">Last inbound</span>
|
||||
<span class="label">${t("common.lastInbound")}</span>
|
||||
<span
|
||||
>${account.lastInboundAt
|
||||
? formatRelativeTimestamp(account.lastInboundAt)
|
||||
: "n/a"}</span
|
||||
: t("common.na")}</span
|
||||
>
|
||||
</div>
|
||||
${account.lastError
|
||||
@@ -70,14 +71,14 @@ export function renderTelegramCard(params: {
|
||||
: nothing}
|
||||
${telegram?.probe
|
||||
? html`<div class="callout" style="margin-top: 12px;">
|
||||
Probe ${telegram.probe.ok ? "ok" : "failed"} · ${telegram.probe.status ?? ""}
|
||||
${telegram.probe.error ?? ""}
|
||||
${telegram.probe.ok ? t("common.probeOk") : t("common.probeFailed")} ·
|
||||
${telegram.probe.status ?? ""} ${telegram.probe.error ?? ""}
|
||||
</div>`
|
||||
: nothing}
|
||||
${renderChannelConfigSection({ channelId: "telegram", props })}
|
||||
|
||||
<div class="row" style="margin-top: 12px;">
|
||||
<button class="btn" @click=${() => props.onRefresh(true)}>Probe</button>
|
||||
<button class="btn" @click=${() => props.onRefresh(true)}>${t("common.probe")}</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -88,28 +89,32 @@ export function renderTelegramCard(params: {
|
||||
subtitle: "Bot status and channel configuration.",
|
||||
accountCountLabel,
|
||||
statusRows: [
|
||||
{ label: "Configured", value: formatNullableBoolean(configured) },
|
||||
{ label: "Running", value: telegram?.running ? "Yes" : "No" },
|
||||
{ label: "Mode", value: telegram?.mode ?? "n/a" },
|
||||
{ label: t("common.configured"), value: formatNullableBoolean(configured) },
|
||||
{ label: t("common.running"), value: telegram?.running ? t("common.yes") : t("common.no") },
|
||||
{ label: t("common.mode"), value: telegram?.mode ?? t("common.na") },
|
||||
{
|
||||
label: "Last start",
|
||||
value: telegram?.lastStartAt ? formatRelativeTimestamp(telegram.lastStartAt) : "n/a",
|
||||
label: t("common.lastStart"),
|
||||
value: telegram?.lastStartAt
|
||||
? formatRelativeTimestamp(telegram.lastStartAt)
|
||||
: t("common.na"),
|
||||
},
|
||||
{
|
||||
label: "Last probe",
|
||||
value: telegram?.lastProbeAt ? formatRelativeTimestamp(telegram.lastProbeAt) : "n/a",
|
||||
label: t("common.lastProbe"),
|
||||
value: telegram?.lastProbeAt
|
||||
? formatRelativeTimestamp(telegram.lastProbeAt)
|
||||
: t("common.na"),
|
||||
},
|
||||
],
|
||||
lastError: telegram?.lastError,
|
||||
secondaryCallout: telegram?.probe
|
||||
? html`<div class="callout" style="margin-top: 12px;">
|
||||
Probe ${telegram.probe.ok ? "ok" : "failed"} · ${telegram.probe.status ?? ""}
|
||||
${telegram.probe.error ?? ""}
|
||||
${telegram.probe.ok ? t("common.probeOk") : t("common.probeFailed")} ·
|
||||
${telegram.probe.status ?? ""} ${telegram.probe.error ?? ""}
|
||||
</div>`
|
||||
: nothing,
|
||||
configSection: renderChannelConfigSection({ channelId: "telegram", props }),
|
||||
footer: html`<div class="row" style="margin-top: 12px;">
|
||||
<button class="btn" @click=${() => props.onRefresh(true)}>Probe</button>
|
||||
<button class="btn" @click=${() => props.onRefresh(true)}>${t("common.probe")}</button>
|
||||
</div>`,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { html, nothing } from "lit";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import { formatRelativeTimestamp, formatDurationHuman } from "../format.ts";
|
||||
import type { WhatsAppStatus } from "../types.ts";
|
||||
import { renderChannelConfigSection } from "./channels.config.ts";
|
||||
@@ -78,7 +79,7 @@ export function renderWhatsAppCard(params: {
|
||||
>
|
||||
Logout
|
||||
</button>
|
||||
<button class="btn" @click=${() => props.onRefresh(true)}>Refresh</button>
|
||||
<button class="btn" @click=${() => props.onRefresh(true)}>${t("common.refresh")}</button>
|
||||
</div>`,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { html, nothing, type TemplateResult } from "lit";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import { icons } from "../icons.ts";
|
||||
import { BORDER_RADIUS_STOPS, type BorderRadiusStop } from "../storage.ts";
|
||||
import type { ThemeTransitionContext } from "../theme-transition.ts";
|
||||
@@ -421,7 +422,7 @@ const SECTION_CATEGORIES: SectionCategory[] = [
|
||||
},
|
||||
{
|
||||
id: "appearance",
|
||||
label: "Appearance",
|
||||
label: t("tabs.appearance"),
|
||||
sections: [
|
||||
{ key: "__appearance__", label: "Theme" },
|
||||
{ key: "ui", label: "UI" },
|
||||
@@ -842,7 +843,7 @@ export function renderConfig(props: ConfigProps) {
|
||||
`
|
||||
: nothing}
|
||||
<button class="btn btn--sm" ?disabled=${props.loading} @click=${props.onReload}>
|
||||
${props.loading ? "Loading…" : "Reload"}
|
||||
${props.loading ? t("common.loading") : t("common.reload")}
|
||||
</button>
|
||||
<button class="btn btn--sm primary" ?disabled=${!canSave} @click=${props.onSave}>
|
||||
${props.saving ? "Saving…" : "Save"}
|
||||
@@ -896,7 +897,11 @@ export function renderConfig(props: ConfigProps) {
|
||||
`
|
||||
: nothing}
|
||||
|
||||
<div class="config-top-tabs__scroller" role="tablist" aria-label="Settings sections">
|
||||
<div
|
||||
class="config-top-tabs__scroller"
|
||||
role="tablist"
|
||||
aria-label="${t("common.settingsSections")}"
|
||||
>
|
||||
${topTabs.map(
|
||||
(tab) => html`
|
||||
<button
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { html, nothing } from "lit";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import type { EventLogEntry } from "../app-events.ts";
|
||||
import { formatEventPayload } from "../presenter.ts";
|
||||
|
||||
@@ -42,7 +43,7 @@ export function renderDebug(props: DebugProps) {
|
||||
<div class="card-sub">Status, health, and heartbeat data.</div>
|
||||
</div>
|
||||
<button class="btn" ?disabled=${props.loading} @click=${props.onRefresh}>
|
||||
${props.loading ? "Refreshing…" : "Refresh"}
|
||||
${props.loading ? t("common.refreshing") : t("common.refresh")}
|
||||
</button>
|
||||
</div>
|
||||
<div class="stack" style="margin-top: 12px;">
|
||||
@@ -95,7 +96,7 @@ export function renderDebug(props: DebugProps) {
|
||||
</label>
|
||||
</div>
|
||||
<div class="row" style="margin-top: 12px;">
|
||||
<button class="btn primary" @click=${props.onCall}>Call</button>
|
||||
<button class="btn primary" @click=${props.onCall}>${t("common.call")}</button>
|
||||
</div>
|
||||
${props.callError
|
||||
? html`<div class="callout danger" style="margin-top: 12px;">${props.callError}</div>`
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { html, nothing } from "lit";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
|
||||
// ── Diary entry parser ─────────────────────────────────────────────────
|
||||
|
||||
@@ -74,27 +75,27 @@ export type DreamingProps = {
|
||||
onRequestUpdate?: () => void;
|
||||
};
|
||||
|
||||
const DREAM_PHRASES = [
|
||||
"consolidating memories\u2026",
|
||||
"tidying the knowledge graph\u2026",
|
||||
"replaying today's conversations\u2026",
|
||||
"weaving short-term into long-term\u2026",
|
||||
"defragmenting the mind palace\u2026",
|
||||
"filing away loose thoughts\u2026",
|
||||
"connecting distant dots\u2026",
|
||||
"composting old context windows\u2026",
|
||||
"alphabetizing the subconscious\u2026",
|
||||
"promoting promising hunches\u2026",
|
||||
"forgetting what doesn't matter\u2026",
|
||||
"dreaming in embeddings\u2026",
|
||||
"reorganizing the memory attic\u2026",
|
||||
"softly indexing the day\u2026",
|
||||
"nurturing fledgling insights\u2026",
|
||||
"simmering half-formed ideas\u2026",
|
||||
"whispering to the vector store\u2026",
|
||||
];
|
||||
const DREAM_PHRASE_KEYS = [
|
||||
"dreaming.phrases.consolidatingMemories",
|
||||
"dreaming.phrases.tidyingKnowledgeGraph",
|
||||
"dreaming.phrases.replayingConversations",
|
||||
"dreaming.phrases.weavingShortTerm",
|
||||
"dreaming.phrases.defragmentingMindPalace",
|
||||
"dreaming.phrases.filingLooseThoughts",
|
||||
"dreaming.phrases.connectingDots",
|
||||
"dreaming.phrases.compostingContext",
|
||||
"dreaming.phrases.alphabetizingSubconscious",
|
||||
"dreaming.phrases.promotingHunches",
|
||||
"dreaming.phrases.forgettingNoise",
|
||||
"dreaming.phrases.dreamingEmbeddings",
|
||||
"dreaming.phrases.reorganizingAttic",
|
||||
"dreaming.phrases.indexingDay",
|
||||
"dreaming.phrases.nurturingInsights",
|
||||
"dreaming.phrases.simmeringIdeas",
|
||||
"dreaming.phrases.whisperingVectorStore",
|
||||
] as const;
|
||||
|
||||
let _dreamIndex = Math.floor(Math.random() * DREAM_PHRASES.length);
|
||||
let _dreamIndex = Math.floor(Math.random() * DREAM_PHRASE_KEYS.length);
|
||||
let _dreamLastSwap = 0;
|
||||
const DREAM_SWAP_MS = 6_000;
|
||||
|
||||
@@ -121,9 +122,9 @@ function currentDreamPhrase(): string {
|
||||
const now = Date.now();
|
||||
if (now - _dreamLastSwap > DREAM_SWAP_MS) {
|
||||
_dreamLastSwap = now;
|
||||
_dreamIndex = (_dreamIndex + 1) % DREAM_PHRASES.length;
|
||||
_dreamIndex = (_dreamIndex + 1) % DREAM_PHRASE_KEYS.length;
|
||||
}
|
||||
return DREAM_PHRASES[_dreamIndex];
|
||||
return t(DREAM_PHRASE_KEYS[_dreamIndex] ?? DREAM_PHRASE_KEYS[0]);
|
||||
}
|
||||
|
||||
const STARS: {
|
||||
@@ -198,7 +199,7 @@ export function renderDreaming(props: DreamingProps) {
|
||||
props.onRequestUpdate?.();
|
||||
}}
|
||||
>
|
||||
Scene
|
||||
${t("dreaming.tabs.scene")}
|
||||
</button>
|
||||
<button
|
||||
class="dreams__tab ${_subTab === "diary" ? "dreams__tab--active" : ""}"
|
||||
@@ -207,7 +208,7 @@ export function renderDreaming(props: DreamingProps) {
|
||||
props.onRequestUpdate?.();
|
||||
}}
|
||||
>
|
||||
Diary
|
||||
${t("dreaming.tabs.diary")}
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
@@ -263,13 +264,15 @@ function renderScene(props: DreamingProps, idle: boolean, dreamText: string) {
|
||||
|
||||
<div class="dreams__status">
|
||||
<span class="dreams__status-label"
|
||||
>${props.active ? "Dreaming Active" : "Dreaming Idle"}</span
|
||||
>${props.active ? t("dreaming.status.active") : t("dreaming.status.idle")}</span
|
||||
>
|
||||
<div class="dreams__status-detail">
|
||||
<div class="dreams__status-dot"></div>
|
||||
<span>
|
||||
${props.promotedCount} promoted
|
||||
${props.nextCycle ? html`· next sweep ${props.nextCycle}` : nothing}
|
||||
${props.promotedCount} ${t("dreaming.status.promotedSuffix")}
|
||||
${props.nextCycle
|
||||
? html`· ${t("dreaming.status.nextSweepPrefix")} ${props.nextCycle}`
|
||||
: nothing}
|
||||
${props.timezone ? html`· ${props.timezone}` : nothing}
|
||||
</span>
|
||||
</div>
|
||||
@@ -280,21 +283,21 @@ function renderScene(props: DreamingProps, idle: boolean, dreamText: string) {
|
||||
<span class="dreams__stat-value" style="color: var(--text-strong);"
|
||||
>${props.shortTermCount}</span
|
||||
>
|
||||
<span class="dreams__stat-label">Short-term</span>
|
||||
<span class="dreams__stat-label">${t("dreaming.stats.shortTerm")}</span>
|
||||
</div>
|
||||
<div class="dreams__stat-divider"></div>
|
||||
<div class="dreams__stat">
|
||||
<span class="dreams__stat-value" style="color: var(--accent);"
|
||||
>${props.totalSignalCount}</span
|
||||
>
|
||||
<span class="dreams__stat-label">Signals</span>
|
||||
<span class="dreams__stat-label">${t("dreaming.stats.signals")}</span>
|
||||
</div>
|
||||
<div class="dreams__stat-divider"></div>
|
||||
<div class="dreams__stat">
|
||||
<span class="dreams__stat-value" style="color: var(--accent-2);"
|
||||
>${props.phaseSignalCount}</span
|
||||
>
|
||||
<span class="dreams__stat-label">Phase Hits</span>
|
||||
<span class="dreams__stat-label">${t("dreaming.stats.phaseHits")}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -337,10 +340,8 @@ function renderDiarySection(props: DreamingProps) {
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="dreams-diary__empty-text">No dreams yet</div>
|
||||
<div class="dreams-diary__empty-hint">
|
||||
Dreams will appear here after the first dreaming cycle runs.
|
||||
</div>
|
||||
<div class="dreams-diary__empty-text">${t("dreaming.diary.noDreamsYet")}</div>
|
||||
<div class="dreams-diary__empty-hint">${t("dreaming.diary.noDreamsHint")}</div>
|
||||
</div>
|
||||
</section>
|
||||
`;
|
||||
@@ -353,10 +354,8 @@ function renderDiarySection(props: DreamingProps) {
|
||||
return html`
|
||||
<section class="dreams-diary">
|
||||
<div class="dreams-diary__empty">
|
||||
<div class="dreams-diary__empty-text">The diary is waiting</div>
|
||||
<div class="dreams-diary__empty-hint">
|
||||
Narrative entries will appear after the next dreaming cycle.
|
||||
</div>
|
||||
<div class="dreams-diary__empty-text">${t("dreaming.diary.waitingTitle")}</div>
|
||||
<div class="dreams-diary__empty-hint">${t("dreaming.diary.waitingHint")}</div>
|
||||
</div>
|
||||
</section>
|
||||
`;
|
||||
@@ -373,7 +372,7 @@ function renderDiarySection(props: DreamingProps) {
|
||||
return html`
|
||||
<section class="dreams-diary">
|
||||
<div class="dreams-diary__header">
|
||||
<span class="dreams-diary__title">Dream Diary</span>
|
||||
<span class="dreams-diary__title">${t("dreaming.diary.title")}</span>
|
||||
<div class="dreams-diary__nav">
|
||||
<button
|
||||
class="dreams-diary__nav-btn"
|
||||
@@ -382,7 +381,7 @@ function renderDiarySection(props: DreamingProps) {
|
||||
setDiaryPage(page + 1);
|
||||
props.onRequestUpdate?.();
|
||||
}}
|
||||
title="Older"
|
||||
title=${t("dreaming.diary.older")}
|
||||
>
|
||||
‹
|
||||
</button>
|
||||
@@ -394,7 +393,7 @@ function renderDiarySection(props: DreamingProps) {
|
||||
setDiaryPage(page - 1);
|
||||
props.onRequestUpdate?.();
|
||||
}}
|
||||
title="Newer"
|
||||
title=${t("dreaming.diary.newer")}
|
||||
>
|
||||
›
|
||||
</button>
|
||||
@@ -407,7 +406,7 @@ function renderDiarySection(props: DreamingProps) {
|
||||
props.onRefreshDiary();
|
||||
}}
|
||||
>
|
||||
${props.dreamDiaryLoading ? "\u2026" : "Reload"}
|
||||
${props.dreamDiaryLoading ? t("dreaming.diary.reloading") : t("dreaming.diary.reload")}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { html, nothing } from "lit";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import { icons } from "../icons.ts";
|
||||
import { formatPresenceAge } from "../presenter.ts";
|
||||
import type { PresenceEntry } from "../types.ts";
|
||||
@@ -38,7 +39,7 @@ export function renderInstances(props: InstancesProps) {
|
||||
${masked ? icons.eyeOff : icons.eye}
|
||||
</button>
|
||||
<button class="btn" ?disabled=${props.loading} @click=${props.onRefresh}>
|
||||
${props.loading ? "Loading…" : "Refresh"}
|
||||
${props.loading ? t("common.loading") : t("common.refresh")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { html, nothing } from "lit";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import type { LogEntry, LogLevel } from "../types.ts";
|
||||
|
||||
const LEVELS: LogLevel[] = ["trace", "debug", "info", "warn", "error", "fatal"];
|
||||
@@ -62,7 +63,7 @@ export function renderLogs(props: LogsProps) {
|
||||
</div>
|
||||
<div class="row" style="gap: 8px;">
|
||||
<button class="btn" ?disabled=${props.loading} @click=${props.onRefresh}>
|
||||
${props.loading ? "Loading…" : "Refresh"}
|
||||
${props.loading ? t("common.loading") : t("common.refresh")}
|
||||
</button>
|
||||
<button
|
||||
class="btn"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { html, nothing } from "lit";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import type {
|
||||
ExecApprovalsAllowlistEntry,
|
||||
ExecApprovalsFile,
|
||||
@@ -215,7 +216,7 @@ export function renderExecApprovals(state: ExecApprovalsState) {
|
||||
? html`<div class="row" style="margin-top: 12px; gap: 12px;">
|
||||
<div class="muted">Load exec approvals to edit allowlists.</div>
|
||||
<button class="btn" ?disabled=${state.loading || !targetReady} @click=${state.onLoad}>
|
||||
${state.loading ? "Loading…" : "Load approvals"}
|
||||
${state.loading ? t("common.loading") : t("common.loadApprovals")}
|
||||
</button>
|
||||
</div>`
|
||||
: html`
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { html, nothing } from "lit";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import type {
|
||||
DevicePairingList,
|
||||
DeviceTokenSummary,
|
||||
@@ -58,7 +59,7 @@ export function renderNodes(props: NodesProps) {
|
||||
<div class="card-sub">Paired devices and live links.</div>
|
||||
</div>
|
||||
<button class="btn" ?disabled=${props.loading} @click=${props.onRefresh}>
|
||||
${props.loading ? "Loading…" : "Refresh"}
|
||||
${props.loading ? t("common.loading") : t("common.refresh")}
|
||||
</button>
|
||||
</div>
|
||||
<div class="list" style="margin-top: 16px;">
|
||||
@@ -82,7 +83,7 @@ function renderDevices(props: NodesProps) {
|
||||
<div class="card-sub">Pairing requests + role tokens.</div>
|
||||
</div>
|
||||
<button class="btn" ?disabled=${props.devicesLoading} @click=${props.onDevicesRefresh}>
|
||||
${props.devicesLoading ? "Loading…" : "Refresh"}
|
||||
${props.devicesLoading ? t("common.loading") : t("common.refresh")}
|
||||
</button>
|
||||
</div>
|
||||
${props.devicesError
|
||||
@@ -276,7 +277,7 @@ function renderBindings(state: BindingState) {
|
||||
? html`<div class="row" style="margin-top: 12px; gap: 12px;">
|
||||
<div class="muted">Load config to edit bindings.</div>
|
||||
<button class="btn" ?disabled=${state.configLoading} @click=${state.onLoadConfig}>
|
||||
${state.configLoading ? "Loading…" : "Load config"}
|
||||
${state.configLoading ? t("common.loading") : t("common.loadConfig")}
|
||||
</button>
|
||||
</div>`
|
||||
: html`
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { html, nothing } from "lit";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import { formatRelativeTimestamp } from "../format.ts";
|
||||
import { icons } from "../icons.ts";
|
||||
import { pathForTab } from "../navigation.ts";
|
||||
@@ -222,7 +223,7 @@ export function renderSessions(props: SessionsProps) {
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn" ?disabled=${props.loading} @click=${props.onRefresh}>
|
||||
${props.loading ? "Loading…" : "Refresh"}
|
||||
${props.loading ? t("common.loading") : t("common.refresh")}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -306,7 +307,9 @@ export function renderSessions(props: SessionsProps) {
|
||||
? html`
|
||||
<div class="data-table-bulk-bar">
|
||||
<span>${props.selectedKeys.size} selected</span>
|
||||
<button class="btn btn--sm" @click=${props.onDeselectAll}>Unselect</button>
|
||||
<button class="btn btn--sm" @click=${props.onDeselectAll}>
|
||||
${t("common.unselect")}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn--sm danger"
|
||||
?disabled=${props.loading}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { html, nothing } from "lit";
|
||||
import { ref } from "lit/directives/ref.js";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import type {
|
||||
ClawHubSearchResult,
|
||||
ClawHubSkillDetail,
|
||||
@@ -137,7 +138,7 @@ export function renderSkills(props: SkillsProps) {
|
||||
?disabled=${props.loading || !props.connected}
|
||||
@click=${props.onRefresh}
|
||||
>
|
||||
${props.loading ? "Loading\u2026" : "Refresh"}
|
||||
${props.loading ? t("common.loading") : t("common.refresh")}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -320,7 +321,7 @@ function renderClawHubDetailDialog(props: SkillsProps) {
|
||||
</div>
|
||||
<div class="md-preview-dialog__body" style="display: grid; gap: 16px;">
|
||||
${props.clawhubDetailLoading
|
||||
? html`<div class="muted">Loading…</div>`
|
||||
? html`<div class="muted">${t("common.loading")}</div>`
|
||||
: props.clawhubDetailError
|
||||
? html`<div class="callout danger">${props.clawhubDetailError}</div>`
|
||||
: detail?.skill
|
||||
|
||||
Reference in New Issue
Block a user