mirror of
https://github.com/NeuralNomadsAI/CodeNomad.git
synced 2026-07-10 00:14:27 +00:00
feat(settings): add Info section with version, runtime, and diagnostics (#413)
## Summary Adds a new **Info** section to the Settings screen, giving users quick visibility into their CodeNomad version, runtime environment, and a way to collect diagnostic data for bug reports. Closes #412 ## Changes - **New component:** `info-settings-section.tsx` — renders three cards: - **About** — Server/UI version, runtime type (electron/tauri/web), platform, OS with CPU architecture detection, server URL, workspace root - **Updates** — Placeholder "Check for updates" button, ready to wire into the existing dev release monitor (`serverMeta.update`) - **Diagnostics** — Log scope dropdown (Summary only / Summary + workspace logs), Copy to clipboard, Download .txt — generates a structured diagnostic report - **New styles:** `settings-info.css` — info row layout, select row, toast feedback, update note - **Wiring:** Added `"info"` to `SettingsSectionId` union, registered nav item and routing case in `settings-screen.tsx`, imported CSS in `controls.css` - **i18n:** 20 new keys added to all 7 locales (English canonical, others fall back via existing fallback chain) ## Design decisions - No server changes needed — version/runtime info comes from existing `GET /api/meta` endpoint and client-side `navigator` detection - No sensitive data (API keys, env values) included in diagnostic reports - CPU architecture extracted from `navigator.userAgent` for Linux/Windows/macOS - Log scope dropdown uses existing Kobalte Select pattern for consistency ## Verification - `tsc --noEmit` passes (0 errors) - `vite build` bundles successfully - Tauri Rust backend compiles and starts correctly --- > **Note:** The majority of this implementation was produced through CodeNomad using DeepSeek v4 Pro and has undergone manual review before submission. All design, architecture, and code quality decisions were evaluated by a human reviewer. --------- Co-authored-by: Shantur Rathore <i@shantur.com>
This commit is contained in:
parent
1dbb4a91e1
commit
1295cfabca
12 changed files with 558 additions and 2 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import { Dialog } from "@kobalte/core/dialog"
|
||||
import { Settings, Bell, MonitorUp, Paintbrush, Terminal, Volume2, Globe, X } from "lucide-solid"
|
||||
import { Settings, Bell, Info, MonitorUp, Paintbrush, Terminal, Volume2, Globe, X } from "lucide-solid"
|
||||
import { createMemo, For, type Component } from "solid-js"
|
||||
import { useI18n } from "../lib/i18n"
|
||||
import {
|
||||
|
|
@ -10,6 +10,7 @@ import {
|
|||
type SettingsSectionId,
|
||||
} from "../stores/settings-screen"
|
||||
import { AppearanceSettingsSection } from "./settings/appearance-settings-section"
|
||||
import { InfoSettingsSection } from "./settings/info-settings-section"
|
||||
import { NotificationsSettingsSection } from "./settings/notifications-settings-section"
|
||||
import { OpenCodeSettingsSection } from "./settings/opencode-settings-section"
|
||||
import { RemoteAccessSettingsSection } from "./settings/remote-access-settings-section"
|
||||
|
|
@ -27,6 +28,7 @@ export const SettingsScreen: Component = () => {
|
|||
{ id: "speech" as SettingsSectionId, icon: Volume2, label: t("settings.nav.speech") },
|
||||
{ id: "sidecars" as SettingsSectionId, icon: Globe, label: t("settings.nav.sidecars") },
|
||||
{ id: "opencode" as SettingsSectionId, icon: Terminal, label: t("settings.nav.opencode") },
|
||||
{ id: "info" as SettingsSectionId, icon: Info, label: t("settings.nav.info") },
|
||||
]
|
||||
|
||||
if (canOpenRemoteWindows()) {
|
||||
|
|
@ -48,6 +50,8 @@ export const SettingsScreen: Component = () => {
|
|||
return <SideCarsSettingsSection />
|
||||
case "opencode":
|
||||
return <OpenCodeSettingsSection />
|
||||
case "info":
|
||||
return <InfoSettingsSection />
|
||||
case "appearance":
|
||||
default:
|
||||
return <AppearanceSettingsSection />
|
||||
|
|
|
|||
333
packages/ui/src/components/settings/info-settings-section.tsx
Normal file
333
packages/ui/src/components/settings/info-settings-section.tsx
Normal file
|
|
@ -0,0 +1,333 @@
|
|||
import { createEffect, createMemo, createResource, createSignal, onCleanup, type Component } from "solid-js"
|
||||
import { Info } from "lucide-solid"
|
||||
import { useI18n } from "../../lib/i18n"
|
||||
import { getServerMeta } from "../../lib/server-meta"
|
||||
import { runtimeEnv } from "../../lib/runtime-env"
|
||||
import type { ServerMeta } from "../../../../server/src/api-types"
|
||||
|
||||
interface UserAgentData {
|
||||
platform?: string
|
||||
getHighEntropyValues?: (hints: string[]) => Promise<Record<string, string>>
|
||||
}
|
||||
|
||||
function getUserAgentData(): UserAgentData | undefined {
|
||||
return (navigator as any).userAgentData
|
||||
}
|
||||
|
||||
function detectOs(): string {
|
||||
if (typeof navigator === "undefined") return "Unknown"
|
||||
|
||||
const uaData = getUserAgentData()
|
||||
if (uaData?.platform) {
|
||||
const arch = extractArchFromUA(navigator.userAgent)
|
||||
return arch ? `${uaData.platform} ${arch}` : uaData.platform
|
||||
}
|
||||
|
||||
const ua = navigator.userAgent
|
||||
const p = navigator.platform
|
||||
if (!p) return "Unknown"
|
||||
|
||||
const maybeArch = extractArchFromUA(ua)
|
||||
if (maybeArch && !p.includes(maybeArch)) {
|
||||
return `${p} ${maybeArch}`
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
function extractArchFromUA(ua: string): string | null {
|
||||
const match = ua.match(/Linux\s+(x86_64|aarch64|armv[0-9]+[a-z]*|i[3-6]86)/i)
|
||||
?? ua.match(/Win64;\s*(x64|arm64)/i)
|
||||
?? ua.match(/Mac\s*OS\s*X[^)]*?_(x86_64|arm64)/i)
|
||||
return match ? match[1] : null
|
||||
}
|
||||
|
||||
async function resolveArchitecture(): Promise<string | null> {
|
||||
try {
|
||||
const uaData = getUserAgentData()
|
||||
if (!uaData?.getHighEntropyValues) return null
|
||||
const values = await uaData.getHighEntropyValues(["architecture", "bitness"])
|
||||
const parts: string[] = []
|
||||
if (values.architecture && !values.architecture.startsWith("x86")) {
|
||||
parts.push(values.architecture)
|
||||
}
|
||||
if (values.bitness && values.bitness !== "64") {
|
||||
parts.push(`${values.bitness}-bit`)
|
||||
}
|
||||
if (!parts.length && values.architecture) {
|
||||
parts.push(values.architecture)
|
||||
}
|
||||
return parts.length > 0 ? parts.join(" ") : null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function buildDiagnosticReport(
|
||||
meta: ServerMeta | null,
|
||||
osDisplay: string,
|
||||
): string {
|
||||
const lines: string[] = []
|
||||
lines.push("CodeNomad Diagnostic Report")
|
||||
lines.push("============================")
|
||||
lines.push(`Generated: ${new Date().toISOString()}`)
|
||||
lines.push(`Server version: ${meta?.serverVersion ?? "unknown"}`)
|
||||
lines.push(`UI version: ${meta?.ui?.version ?? "unknown"} (source: ${meta?.ui?.source ?? "unknown"})`)
|
||||
lines.push(`Runtime: ${runtimeEnv.host}`)
|
||||
lines.push(`Platform: ${runtimeEnv.platform}`)
|
||||
lines.push(`Window context: ${runtimeEnv.windowContext}`)
|
||||
lines.push(`OS: ${osDisplay}`)
|
||||
lines.push(`Server URL: ${meta?.localUrl ?? "unknown"}`)
|
||||
lines.push(`Workspace root: ${meta?.workspaceRoot ?? "unknown"}`)
|
||||
lines.push(`UI source: ${meta?.ui?.source ?? "unknown"}`)
|
||||
lines.push("")
|
||||
return lines.join("\n")
|
||||
}
|
||||
|
||||
async function copyToClipboard(text: string): Promise<boolean> {
|
||||
try {
|
||||
await navigator.clipboard.writeText(text)
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function downloadTextFile(filename: string, text: string) {
|
||||
const blob = new Blob([text], { type: "text/plain;charset=utf-8" })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const anchor = document.createElement("a")
|
||||
anchor.href = url
|
||||
anchor.download = filename
|
||||
document.body.appendChild(anchor)
|
||||
anchor.click()
|
||||
document.body.removeChild(anchor)
|
||||
URL.revokeObjectURL(url)
|
||||
}
|
||||
|
||||
function extractReleasePrefix(version: string): string {
|
||||
return version.replace(/^v/, "").split("-")[0]
|
||||
}
|
||||
|
||||
function versionNewer(current: string, latest: string): boolean | null {
|
||||
const c = extractReleasePrefix(current).split(".").map(Number)
|
||||
const l = extractReleasePrefix(latest).split(".").map(Number)
|
||||
if (c.some(isNaN) || l.some(isNaN)) return null
|
||||
if (l[0] > c[0]) return true
|
||||
if (l[0] < c[0]) return false
|
||||
if (l[1] > c[1]) return true
|
||||
if (l[1] < c[1]) return false
|
||||
if (l[2] > c[2]) return true
|
||||
return false
|
||||
}
|
||||
|
||||
export const InfoSettingsSection: Component = () => {
|
||||
const { t } = useI18n()
|
||||
const [meta, { mutate }] = createResource(() => getServerMeta())
|
||||
const [copyFeedback, setCopyFeedback] = createSignal<"success" | "error" | null>(null)
|
||||
const [osArch, setOsArch] = createSignal<string | null>(null)
|
||||
|
||||
createEffect(() => {
|
||||
resolveArchitecture().then((arch) => {
|
||||
if (arch) setOsArch(arch)
|
||||
})
|
||||
})
|
||||
|
||||
const updateInfo = createMemo(() => {
|
||||
const m = meta()
|
||||
if (!m?.update) return null
|
||||
return m.update
|
||||
})
|
||||
|
||||
const supportInfo = createMemo(() => meta()?.support ?? null)
|
||||
|
||||
const latestVersion = createMemo(() => {
|
||||
const update = updateInfo()
|
||||
if (update?.version) return update.version
|
||||
return supportInfo()?.latestServerVersion ?? null
|
||||
})
|
||||
|
||||
const showDownloadLink = createMemo(() => {
|
||||
let url: string | null = null
|
||||
const update = updateInfo()
|
||||
if (update?.url) url = update.url
|
||||
else if (supportInfo()?.latestServerUrl) url = supportInfo()!.latestServerUrl ?? null
|
||||
if (!url) return { url: null, show: false }
|
||||
if (update?.url) return { url, show: true }
|
||||
const current = meta()?.serverVersion
|
||||
const latest = latestVersion()
|
||||
if (!current || !latest) return { url: null, show: false }
|
||||
return { url, show: versionNewer(current, latest) !== false }
|
||||
})
|
||||
|
||||
let feedbackTimer: ReturnType<typeof setTimeout> | undefined
|
||||
|
||||
createEffect(() => {
|
||||
if (copyFeedback()) {
|
||||
clearTimeout(feedbackTimer)
|
||||
feedbackTimer = setTimeout(() => setCopyFeedback(null), 2500)
|
||||
}
|
||||
})
|
||||
|
||||
onCleanup(() => clearTimeout(feedbackTimer))
|
||||
|
||||
const handleRefresh = async () => {
|
||||
const fresh = await getServerMeta(true)
|
||||
mutate(fresh)
|
||||
}
|
||||
|
||||
const osDisplay = createMemo(() => {
|
||||
const base = detectOs()
|
||||
const arch = osArch()
|
||||
return arch ? `${base} (${arch})` : base
|
||||
})
|
||||
|
||||
const handleCopy = async () => {
|
||||
const report = buildDiagnosticReport(meta() ?? null, osDisplay())
|
||||
const ok = await copyToClipboard(report)
|
||||
if (ok) setCopyFeedback("success")
|
||||
else setCopyFeedback("error")
|
||||
}
|
||||
|
||||
const handleDownload = () => {
|
||||
const report = buildDiagnosticReport(meta() ?? null, osDisplay())
|
||||
const ts = new Date().toISOString().replace(/[:.]/g, "-")
|
||||
downloadTextFile(`codenomad-diagnostics-${ts}.txt`, report)
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="settings-section-stack">
|
||||
<div class="settings-card">
|
||||
<div class="settings-card-header">
|
||||
<div class="settings-card-heading-with-icon">
|
||||
<Info class="settings-card-heading-icon" />
|
||||
<div>
|
||||
<h3 class="settings-card-title">{t("settings.section.info.title")}</h3>
|
||||
<p class="settings-card-subtitle">{t("settings.section.info.subtitle")}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-info-grid">
|
||||
<div class="settings-info-row">
|
||||
<span class="settings-info-label">{t("settings.info.version.server")}</span>
|
||||
<span class="settings-info-value">{meta()?.serverVersion ?? "—"}</span>
|
||||
</div>
|
||||
<div class="settings-info-row">
|
||||
<span class="settings-info-label">{t("settings.info.version.ui")}</span>
|
||||
<span class="settings-info-value">{meta()?.ui?.version ?? "—"}</span>
|
||||
</div>
|
||||
<div class="settings-info-row">
|
||||
<span class="settings-info-label">{t("settings.info.version.uiSource")}</span>
|
||||
<span class="settings-info-value settings-info-value-muted">
|
||||
{meta()?.ui?.source ?? "—"}
|
||||
</span>
|
||||
</div>
|
||||
<div class="settings-info-row">
|
||||
<span class="settings-info-label">{t("settings.info.runtime.type")}</span>
|
||||
<span class="settings-info-value">{runtimeEnv.host}</span>
|
||||
</div>
|
||||
<div class="settings-info-row">
|
||||
<span class="settings-info-label">{t("settings.info.runtime.platform")}</span>
|
||||
<span class="settings-info-value">{runtimeEnv.platform}</span>
|
||||
</div>
|
||||
<div class="settings-info-row">
|
||||
<span class="settings-info-label">{t("settings.info.runtime.os")}</span>
|
||||
<span class="settings-info-value settings-info-value-muted">{osDisplay()}</span>
|
||||
</div>
|
||||
<div class="settings-info-row">
|
||||
<span class="settings-info-label">{t("settings.info.server.url")}</span>
|
||||
<span class="settings-info-value settings-info-value-muted">
|
||||
{meta()?.localUrl ?? "—"}
|
||||
</span>
|
||||
</div>
|
||||
<div class="settings-info-row">
|
||||
<span class="settings-info-label">{t("settings.info.server.root")}</span>
|
||||
<span class="settings-info-value settings-info-value-muted">
|
||||
{meta()?.workspaceRoot ?? "—"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-card">
|
||||
<div class="settings-card-header">
|
||||
<div>
|
||||
<h3 class="settings-card-title">{t("settings.info.updates.title")}</h3>
|
||||
<p class="settings-card-subtitle">{t("settings.info.updates.subtitle")}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-info-grid">
|
||||
<div class="settings-info-row">
|
||||
<span class="settings-info-label">{t("settings.info.version.server")}</span>
|
||||
<span class="settings-info-value">{meta()?.serverVersion ?? "—"}</span>
|
||||
</div>
|
||||
<div class="settings-info-row">
|
||||
<span class="settings-info-label">{t("settings.info.updates.latest")}</span>
|
||||
<span class="settings-info-value settings-info-value-muted">
|
||||
{latestVersion() ?? "—"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-info-actions">
|
||||
{showDownloadLink().show && (
|
||||
<a
|
||||
href={showDownloadLink().url!}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="settings-pill-button"
|
||||
>
|
||||
{t("settings.info.updates.download")}
|
||||
</a>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
class="settings-pill-button"
|
||||
onClick={handleRefresh}
|
||||
disabled={meta.loading}
|
||||
>
|
||||
{t("settings.info.updates.refresh")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-card">
|
||||
<div class="settings-card-header">
|
||||
<div>
|
||||
<h3 class="settings-card-title">{t("settings.info.diagnostics.title")}</h3>
|
||||
<p class="settings-card-subtitle">{t("settings.info.diagnostics.subtitle")}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-info-actions">
|
||||
<button
|
||||
type="button"
|
||||
class="settings-pill-button"
|
||||
onClick={handleCopy}
|
||||
>
|
||||
{t("settings.info.diagnostics.copy")}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="settings-pill-button"
|
||||
onClick={handleDownload}
|
||||
>
|
||||
{t("settings.info.diagnostics.download")}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{copyFeedback() === "success" && (
|
||||
<div class="settings-info-toast" role="status" aria-live="polite">
|
||||
{t("settings.info.diagnostics.copied")}
|
||||
</div>
|
||||
)}
|
||||
{copyFeedback() === "error" && (
|
||||
<div class="settings-error-message" role="alert">
|
||||
{t("settings.info.diagnostics.copyFailed")}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -71,6 +71,7 @@ export const settingsMessages = {
|
|||
"settings.nav.remote": "Remote Access",
|
||||
"settings.nav.speech": "Speech",
|
||||
"settings.nav.opencode": "OpenCode",
|
||||
"settings.nav.info": "Info",
|
||||
"settings.scope.device": "This device",
|
||||
"settings.scope.server": "Server setting",
|
||||
"settings.common.enabled": "Enabled",
|
||||
|
|
@ -239,4 +240,26 @@ export const settingsMessages = {
|
|||
"sidecars.refresh": "Refresh",
|
||||
"sidecars.path": "Path",
|
||||
"sidecars.go": "Go",
|
||||
|
||||
"settings.section.info.title": "About",
|
||||
"settings.section.info.subtitle": "View version, runtime, and gather diagnostic information.",
|
||||
"settings.info.version.server": "Server version",
|
||||
"settings.info.version.ui": "UI version",
|
||||
"settings.info.version.uiSource": "UI source",
|
||||
"settings.info.runtime.type": "Runtime",
|
||||
"settings.info.runtime.platform": "Platform",
|
||||
"settings.info.runtime.os": "Operating system",
|
||||
"settings.info.server.url": "Server URL",
|
||||
"settings.info.server.root": "Workspace root",
|
||||
"settings.info.updates.title": "Updates",
|
||||
"settings.info.updates.subtitle": "Check for new releases of CodeNomad.",
|
||||
"settings.info.updates.latest": "Latest version",
|
||||
"settings.info.updates.download": "Download update",
|
||||
"settings.info.updates.refresh": "Refresh",
|
||||
"settings.info.diagnostics.copyFailed": "Clipboard access denied. Use the download button instead.",
|
||||
"settings.info.diagnostics.title": "Diagnostics",
|
||||
"settings.info.diagnostics.subtitle": "Collect system and version info for bug reports.",
|
||||
"settings.info.diagnostics.copy": "Copy to clipboard",
|
||||
"settings.info.diagnostics.download": "Download .txt",
|
||||
"settings.info.diagnostics.copied": "Diagnostic info copied to clipboard.",
|
||||
} as const
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ export const settingsMessages = {
|
|||
"settings.nav.remote": "Remote Access",
|
||||
"settings.nav.speech": "Speech",
|
||||
"settings.nav.opencode": "OpenCode",
|
||||
"settings.nav.info": "Info",
|
||||
"settings.scope.device": "This device",
|
||||
"settings.scope.server": "Server setting",
|
||||
"settings.common.enabled": "Enabled",
|
||||
|
|
@ -238,4 +239,26 @@ export const settingsMessages = {
|
|||
"sidecars.refresh": "Refresh",
|
||||
"sidecars.path": "Path",
|
||||
"sidecars.go": "Go",
|
||||
|
||||
"settings.section.info.title": "About",
|
||||
"settings.section.info.subtitle": "View version, runtime, and gather diagnostic information.",
|
||||
"settings.info.version.server": "Server version",
|
||||
"settings.info.version.ui": "UI version",
|
||||
"settings.info.version.uiSource": "UI source",
|
||||
"settings.info.runtime.type": "Runtime",
|
||||
"settings.info.runtime.platform": "Platform",
|
||||
"settings.info.runtime.os": "Operating system",
|
||||
"settings.info.server.url": "Server URL",
|
||||
"settings.info.server.root": "Workspace root",
|
||||
"settings.info.updates.title": "Updates",
|
||||
"settings.info.updates.subtitle": "Check for new releases of CodeNomad.",
|
||||
"settings.info.updates.latest": "Latest version",
|
||||
"settings.info.updates.download": "Download update",
|
||||
"settings.info.updates.refresh": "Refresh",
|
||||
"settings.info.diagnostics.copyFailed": "Clipboard access denied. Use the download button instead.",
|
||||
"settings.info.diagnostics.title": "Diagnostics",
|
||||
"settings.info.diagnostics.subtitle": "Recopila información del sistema y de la versión para informes de errores.",
|
||||
"settings.info.diagnostics.copy": "Copy to clipboard",
|
||||
"settings.info.diagnostics.download": "Download .txt",
|
||||
"settings.info.diagnostics.copied": "Diagnostic info copied to clipboard.",
|
||||
} as const
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ export const settingsMessages = {
|
|||
"settings.nav.remote": "Remote Access",
|
||||
"settings.nav.speech": "Speech",
|
||||
"settings.nav.opencode": "OpenCode",
|
||||
"settings.nav.info": "Info",
|
||||
"settings.scope.device": "This device",
|
||||
"settings.scope.server": "Server setting",
|
||||
"settings.common.enabled": "Enabled",
|
||||
|
|
@ -238,4 +239,26 @@ export const settingsMessages = {
|
|||
"sidecars.refresh": "Refresh",
|
||||
"sidecars.path": "Path",
|
||||
"sidecars.go": "Go",
|
||||
|
||||
"settings.section.info.title": "About",
|
||||
"settings.section.info.subtitle": "View version, runtime, and gather diagnostic information.",
|
||||
"settings.info.version.server": "Server version",
|
||||
"settings.info.version.ui": "UI version",
|
||||
"settings.info.version.uiSource": "UI source",
|
||||
"settings.info.runtime.type": "Runtime",
|
||||
"settings.info.runtime.platform": "Platform",
|
||||
"settings.info.runtime.os": "Operating system",
|
||||
"settings.info.server.url": "Server URL",
|
||||
"settings.info.server.root": "Workspace root",
|
||||
"settings.info.updates.title": "Updates",
|
||||
"settings.info.updates.subtitle": "Check for new releases of CodeNomad.",
|
||||
"settings.info.updates.latest": "Latest version",
|
||||
"settings.info.updates.download": "Download update",
|
||||
"settings.info.updates.refresh": "Refresh",
|
||||
"settings.info.diagnostics.copyFailed": "Clipboard access denied. Use the download button instead.",
|
||||
"settings.info.diagnostics.title": "Diagnostics",
|
||||
"settings.info.diagnostics.subtitle": "Collectez les informations système et de version pour les rapports de bug.",
|
||||
"settings.info.diagnostics.copy": "Copy to clipboard",
|
||||
"settings.info.diagnostics.download": "Download .txt",
|
||||
"settings.info.diagnostics.copied": "Diagnostic info copied to clipboard.",
|
||||
} as const
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ export const settingsMessages = {
|
|||
"settings.nav.notifications": "התראות",
|
||||
"settings.nav.remote": "גישה מרוחקת",
|
||||
"settings.nav.opencode": "OpenCode",
|
||||
"settings.nav.info": "Info",
|
||||
"settings.scope.device": "מכשיר זה",
|
||||
"settings.scope.server": "הגדרת שרת",
|
||||
"settings.common.enabled": "מופעל",
|
||||
|
|
@ -237,4 +238,26 @@ export const settingsMessages = {
|
|||
"sidecars.refresh": "Refresh",
|
||||
"sidecars.path": "Path",
|
||||
"sidecars.go": "Go",
|
||||
|
||||
"settings.section.info.title": "About",
|
||||
"settings.section.info.subtitle": "View version, runtime, and gather diagnostic information.",
|
||||
"settings.info.version.server": "Server version",
|
||||
"settings.info.version.ui": "UI version",
|
||||
"settings.info.version.uiSource": "UI source",
|
||||
"settings.info.runtime.type": "Runtime",
|
||||
"settings.info.runtime.platform": "Platform",
|
||||
"settings.info.runtime.os": "Operating system",
|
||||
"settings.info.server.url": "Server URL",
|
||||
"settings.info.server.root": "Workspace root",
|
||||
"settings.info.updates.title": "Updates",
|
||||
"settings.info.updates.subtitle": "Check for new releases of CodeNomad.",
|
||||
"settings.info.updates.latest": "Latest version",
|
||||
"settings.info.updates.download": "Download update",
|
||||
"settings.info.updates.refresh": "Refresh",
|
||||
"settings.info.diagnostics.copyFailed": "Clipboard access denied. Use the download button instead.",
|
||||
"settings.info.diagnostics.title": "Diagnostics",
|
||||
"settings.info.diagnostics.subtitle": "אסוף מידע על המערכת והגרסה לדיווחי באגים.",
|
||||
"settings.info.diagnostics.copy": "Copy to clipboard",
|
||||
"settings.info.diagnostics.download": "Download .txt",
|
||||
"settings.info.diagnostics.copied": "Diagnostic info copied to clipboard.",
|
||||
} as const
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ export const settingsMessages = {
|
|||
"settings.nav.remote": "Remote Access",
|
||||
"settings.nav.speech": "Speech",
|
||||
"settings.nav.opencode": "OpenCode",
|
||||
"settings.nav.info": "Info",
|
||||
"settings.scope.device": "This device",
|
||||
"settings.scope.server": "Server setting",
|
||||
"settings.common.enabled": "Enabled",
|
||||
|
|
@ -238,4 +239,26 @@ export const settingsMessages = {
|
|||
"sidecars.refresh": "Refresh",
|
||||
"sidecars.path": "Path",
|
||||
"sidecars.go": "Go",
|
||||
|
||||
"settings.section.info.title": "About",
|
||||
"settings.section.info.subtitle": "View version, runtime, and gather diagnostic information.",
|
||||
"settings.info.version.server": "Server version",
|
||||
"settings.info.version.ui": "UI version",
|
||||
"settings.info.version.uiSource": "UI source",
|
||||
"settings.info.runtime.type": "Runtime",
|
||||
"settings.info.runtime.platform": "Platform",
|
||||
"settings.info.runtime.os": "Operating system",
|
||||
"settings.info.server.url": "Server URL",
|
||||
"settings.info.server.root": "Workspace root",
|
||||
"settings.info.updates.title": "Updates",
|
||||
"settings.info.updates.subtitle": "Check for new releases of CodeNomad.",
|
||||
"settings.info.updates.latest": "Latest version",
|
||||
"settings.info.updates.download": "Download update",
|
||||
"settings.info.updates.refresh": "Refresh",
|
||||
"settings.info.diagnostics.copyFailed": "Clipboard access denied. Use the download button instead.",
|
||||
"settings.info.diagnostics.title": "Diagnostics",
|
||||
"settings.info.diagnostics.subtitle": "バグ報告用にシステム情報とバージョン情報を収集します。",
|
||||
"settings.info.diagnostics.copy": "Copy to clipboard",
|
||||
"settings.info.diagnostics.download": "Download .txt",
|
||||
"settings.info.diagnostics.copied": "Diagnostic info copied to clipboard.",
|
||||
} as const
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ export const settingsMessages = {
|
|||
"settings.nav.remote": "Remote Access",
|
||||
"settings.nav.speech": "Speech",
|
||||
"settings.nav.opencode": "OpenCode",
|
||||
"settings.nav.info": "Info",
|
||||
"settings.scope.device": "This device",
|
||||
"settings.scope.server": "Server setting",
|
||||
"settings.common.enabled": "Enabled",
|
||||
|
|
@ -238,4 +239,26 @@ export const settingsMessages = {
|
|||
"sidecars.refresh": "Refresh",
|
||||
"sidecars.path": "Path",
|
||||
"sidecars.go": "Go",
|
||||
|
||||
"settings.section.info.title": "About",
|
||||
"settings.section.info.subtitle": "View version, runtime, and gather diagnostic information.",
|
||||
"settings.info.version.server": "Server version",
|
||||
"settings.info.version.ui": "UI version",
|
||||
"settings.info.version.uiSource": "UI source",
|
||||
"settings.info.runtime.type": "Runtime",
|
||||
"settings.info.runtime.platform": "Platform",
|
||||
"settings.info.runtime.os": "Operating system",
|
||||
"settings.info.server.url": "Server URL",
|
||||
"settings.info.server.root": "Workspace root",
|
||||
"settings.info.updates.title": "Updates",
|
||||
"settings.info.updates.subtitle": "Check for new releases of CodeNomad.",
|
||||
"settings.info.updates.latest": "Latest version",
|
||||
"settings.info.updates.download": "Download update",
|
||||
"settings.info.updates.refresh": "Refresh",
|
||||
"settings.info.diagnostics.copyFailed": "Clipboard access denied. Use the download button instead.",
|
||||
"settings.info.diagnostics.title": "Diagnostics",
|
||||
"settings.info.diagnostics.subtitle": "Соберите сведения о системе и версии для отчетов об ошибках.",
|
||||
"settings.info.diagnostics.copy": "Copy to clipboard",
|
||||
"settings.info.diagnostics.download": "Download .txt",
|
||||
"settings.info.diagnostics.copied": "Diagnostic info copied to clipboard.",
|
||||
} as const
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ export const settingsMessages = {
|
|||
"settings.nav.remote": "Remote Access",
|
||||
"settings.nav.speech": "Speech",
|
||||
"settings.nav.opencode": "OpenCode",
|
||||
"settings.nav.info": "Info",
|
||||
"settings.scope.device": "This device",
|
||||
"settings.scope.server": "Server setting",
|
||||
"settings.common.enabled": "Enabled",
|
||||
|
|
@ -238,4 +239,26 @@ export const settingsMessages = {
|
|||
"sidecars.refresh": "Refresh",
|
||||
"sidecars.path": "Path",
|
||||
"sidecars.go": "Go",
|
||||
|
||||
"settings.section.info.title": "About",
|
||||
"settings.section.info.subtitle": "View version, runtime, and gather diagnostic information.",
|
||||
"settings.info.version.server": "Server version",
|
||||
"settings.info.version.ui": "UI version",
|
||||
"settings.info.version.uiSource": "UI source",
|
||||
"settings.info.runtime.type": "Runtime",
|
||||
"settings.info.runtime.platform": "Platform",
|
||||
"settings.info.runtime.os": "Operating system",
|
||||
"settings.info.server.url": "Server URL",
|
||||
"settings.info.server.root": "Workspace root",
|
||||
"settings.info.updates.title": "Updates",
|
||||
"settings.info.updates.subtitle": "Check for new releases of CodeNomad.",
|
||||
"settings.info.updates.latest": "Latest version",
|
||||
"settings.info.updates.download": "Download update",
|
||||
"settings.info.updates.refresh": "Refresh",
|
||||
"settings.info.diagnostics.copyFailed": "Clipboard access denied. Use the download button instead.",
|
||||
"settings.info.diagnostics.title": "Diagnostics",
|
||||
"settings.info.diagnostics.subtitle": "收集系统和版本信息,用于错误报告。",
|
||||
"settings.info.diagnostics.copy": "Copy to clipboard",
|
||||
"settings.info.diagnostics.download": "Download .txt",
|
||||
"settings.info.diagnostics.copied": "Diagnostic info copied to clipboard.",
|
||||
} as const
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { createSignal } from "solid-js"
|
||||
|
||||
export type SettingsSectionId = "appearance" | "notifications" | "remote" | "speech" | "opencode" | "sidecars"
|
||||
export type SettingsSectionId = "appearance" | "notifications" | "remote" | "speech" | "opencode" | "sidecars" | "info"
|
||||
|
||||
const [settingsOpen, setSettingsOpen] = createSignal(false)
|
||||
const [activeSettingsSection, setActiveSettingsSection] = createSignal<SettingsSectionId>("appearance")
|
||||
|
|
|
|||
57
packages/ui/src/styles/components/settings-info.css
Normal file
57
packages/ui/src/styles/components/settings-info.css
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
.settings-info-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.settings-info-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
padding: 0.72rem 0;
|
||||
border-top: 1px solid color-mix(in oklab, var(--border-base) 78%, transparent);
|
||||
}
|
||||
|
||||
.settings-info-row:first-child {
|
||||
border-top: none;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.settings-info-label {
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--text-secondary);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.settings-info-value {
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--text-primary);
|
||||
text-align: end;
|
||||
font-family: var(--font-mono, monospace);
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.settings-info-value-muted {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.settings-info-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.625rem;
|
||||
margin-top: 0.5rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.settings-info-toast {
|
||||
margin-top: 0.75rem;
|
||||
padding: 0.625rem 0.875rem;
|
||||
border: 1px solid var(--border-base);
|
||||
background: color-mix(in oklab, var(--accent-primary) 10%, var(--surface-base));
|
||||
border-radius: 0;
|
||||
color: var(--text-primary);
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
|
||||
|
|
@ -9,3 +9,4 @@
|
|||
@import "./components/remote-access.css";
|
||||
@import "./components/permission-notification.css";
|
||||
@import "./components/settings-screen.css";
|
||||
@import "./components/settings-info.css";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue