{pattern.title}
-{pattern.body}
-diff --git a/.yoi/profiles.toml b/.yoi/profiles.toml index 7fde639f..de011901 100644 --- a/.yoi/profiles.toml +++ b/.yoi/profiles.toml @@ -1 +1,3 @@ default = "builtin:companion" + +[profile] diff --git a/web/workspace/src/app.css b/web/workspace/src/app.css index 9d9bd050..e11f749b 100644 --- a/web/workspace/src/app.css +++ b/web/workspace/src/app.css @@ -1446,3 +1446,212 @@ display: block; } } + +@layer components { + .settings-page { + display: grid; + gap: var(--space-5); + } + + .settings-nav { + display: flex; + flex-wrap: wrap; + gap: var(--space-3); + } + + .settings-nav a, + .settings-section-card, + .button-link { + color: inherit; + text-decoration: none; + } + + .settings-nav a, + .settings-section-card { + display: grid; + gap: var(--space-1); + min-width: min(16rem, 100%); + padding: var(--space-3) var(--space-4); + border: 1px solid var(--line); + border-radius: var(--radius-panel); + background: var(--bg-raised); + } + + .settings-nav a:hover, + .settings-nav a:focus-visible, + .settings-nav a.active, + .settings-section-card:hover, + .settings-section-card:focus-visible { + background: var(--interactive-hover); + } + + .settings-nav span, + .settings-section-card h3 { + color: var(--text-strong); + font-weight: 800; + } + + .settings-section-grid, + .settings-profile-grid, + .settings-pattern-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr)); + gap: var(--space-4); + } + + .settings-card { + display: grid; + gap: var(--space-4); + } + + .settings-card-header, + .settings-section-header { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: var(--space-4); + } + + .settings-form, + .settings-registry-editor { + display: grid; + gap: var(--space-3); + } + + .settings-form label, + .settings-registry-editor label { + display: grid; + gap: var(--space-1); + color: var(--text-muted); + font-size: 0.82rem; + } + + .settings-form input, + .settings-form select, + .settings-form textarea, + .settings-registry-editor input, + .settings-registry-editor select, + .settings-runtime-form input { + width: 100%; + border: 1px solid var(--line); + border-radius: 0.55rem; + background: var(--bg-raised); + color: var(--text-strong); + padding: 0.45rem 0.55rem; + font: inherit; + } + + .settings-form textarea { + min-height: 18rem; + resize: vertical; + font-family: var(--font-mono); + } + + .settings-form button, + .button-link { + width: fit-content; + border: 0; + border-radius: 0.6rem; + background: var(--accent); + color: var(--bg); + font-weight: 700; + padding: 0.5rem 0.75rem; + cursor: pointer; + } + + .settings-form button:disabled { + cursor: not-allowed; + opacity: 0.55; + } + + .settings-form button.danger { + background: var(--danger); + } + + .settings-note { + margin: 0; + color: var(--text-muted); + } + + .settings-profile-list { + display: grid; + gap: var(--space-3); + margin: 0; + padding: 0; + list-style: none; + } + + .settings-profile-list li, + .settings-registry-editor fieldset, + .settings-pattern-grid article { + display: grid; + gap: var(--space-2); + padding: var(--space-3); + border: 1px solid var(--line); + border-radius: var(--radius-panel); + background: var(--bg-raised); + } + + .settings-profile-list strong, + .settings-profile-list span, + .settings-profile-list small { + display: block; + } + + .settings-profile-list strong { + color: var(--text-strong); + } + + .settings-profile-list span, + .settings-profile-list small, + .settings-profile-list p { + margin: 0; + color: var(--text-muted); + } + + .settings-registry-editor fieldset { + margin: 0; + } + + .settings-registry-editor legend { + color: var(--text-strong); + font-weight: 750; + } + + .settings-identity-list { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr)); + gap: var(--space-3); + margin: 0; + } + + .settings-identity-list div { + display: grid; + gap: var(--space-1); + } + + .settings-identity-list dt { + color: var(--text-muted); + font-size: 0.78rem; + } + + .settings-identity-list dd { + margin: 0; + color: var(--text-strong); + } + + .section-status-pill { + width: fit-content; + border-radius: 999px; + padding: 0.25rem 0.55rem; + background: var(--bg-subtle); + color: var(--text-muted); + font-size: 0.72rem; + font-weight: 800; + text-transform: uppercase; + } + + .status-message.error { + color: var(--danger); + } +} diff --git a/web/workspace/src/lib/workspace-settings/DiagnosticsList.svelte b/web/workspace/src/lib/workspace-settings/DiagnosticsList.svelte new file mode 100644 index 00000000..475ea6b4 --- /dev/null +++ b/web/workspace/src/lib/workspace-settings/DiagnosticsList.svelte @@ -0,0 +1,20 @@ + + +{#if diagnostics.length > 0} +
Settings / Admin
++ Configure workspace metadata, runtime connections, and Decodal profile sources through the Backend. +
+Workspace Browser
-- Local administration surfaces for the Workspace backend. Runtime Connections v0 is editable through typed APIs; broader admin controls remain bounded placeholders. -
-Authority boundary
-{SETTINGS_PERMISSION_NOTICE}
-editable
-{SETTINGS_SECTIONS.find((section) => section.id === "runtime-connections")?.summary}
- - {#if runtimeLoading} - - {:else if runtimeError} - - {:else if runtimeSettings} -| Runtime | -Source | -Connection | -Status | -Actions | -
|---|---|---|---|---|
- {runtimeSettings.embedded.display_name}
- {runtimeSettings.embedded.runtime_id}
- |
- - embedded - Workspace backend process - | -Local Backend runtime | -- {runtimeSettings.embedded.status} - {#if runtimeSettings.embedded.restart_required} - restart required - {/if} - | -Managed by backend | -
| {@render DiagnosticsList({ diagnostics: runtimeSettings.embedded.diagnostics })} | -||||
- {remote.display_name}
- {remote.runtime_id}
- |
- - remote - Configured Runtime endpoint - | -- Endpoint: {remote.endpoint_configured ? "configured" : "not configured"} - {#if remote.endpoint_configured}hidden{/if} - Token: {remote.token_ref_configured ? "configured" : "not configured"} - | -- {remote.status} - {#if remote.restart_required} - restart required - {/if} - | -
-
-
-
-
- |
-
| {@render DiagnosticsList({ diagnostics: remote.diagnostics })} | -||||
|
-
- Test: {test.state}
- {test.health_result} · {test.checked_at}
-
- {test.compatibility_basis} - {#if available.length > 0} -Verified areas: {available.join(', ')} - {/if} - {#if unchecked.length > 0} -Unchecked warning areas: {unchecked.join(', ')} - {/if} - {@render DiagnosticsList({ diagnostics: test.diagnostics })} - |
- ||||
editable
-- Workspace profile settings are surfaced as source-qualified selectors and Decodal source summaries. The browser never receives raw host paths, runtime endpoints, tokens, resource handles, archive content, or archive digests. -
- - {#if profileLoading} - - {:else} -| Selector | Label | Source | Status | Action |
|---|---|---|---|---|
{profile.selector} |
- {profile.label} | -{profile.source_kind} | -{profile.diagnostics.length === 0 ? "ok" : `${profile.diagnostics.length} diagnostics`} | -- {#if profile.profile_source_id} - - {:else} - builtin - {/if} - | -
Open a project source from the discovered profile table to edit it.
-{section.status}
-{section.summary}
-{workspace?.workspace_id ?? "loading"}Overview
+{section.summary}
+ + {/each} +Implementation patterns
-{pattern.body}
-Backend pattern
++ Workspace metadata and Decodal profile sources are edited through Backend APIs, not direct frontend filesystem access. +
++ Runtime execution receives explicit resources and WorkingDirectory handles; raw workspace paths stay out of Browser-facing payloads. +
++ Settings mutations return typed diagnostics so validation issues are visible without exposing internal paths or credentials. +
+read-only
++ Backend-owned config is exposed through typed settings APIs. Additional Backend config surfaces will be added as they become editable product settings. +
+read-only
++ Review the effective launch profiles and their source files. Editing is intentionally deferred until the Decodal profile source model is settled. +
+ + {#if loading} + + {:else if profileSettings} +Profiles that can be selected when launching a Worker.
+{profile.description}
{/if} +Decodal source files that define or contribute to launch profiles.
+editable
+Manage remote Runtime connection records stored in the workspace-local Backend config. The embedded Runtime is built in and shown separately.
+ + {#if runtimeLoading} + + {:else if runtimeError} + + {:else if runtimeSettings} +| Runtime | +Source | +Connection | +Status | +Actions | +
|---|---|---|---|---|
+ {runtimeSettings.embedded.display_name}
+ {runtimeSettings.embedded.runtime_id}
+ |
+ + embedded + Workspace backend process + | +Local Backend runtime | ++ {runtimeSettings.embedded.status} + {#if runtimeSettings.embedded.restart_required} + restart required + {/if} + | +Managed by backend | +
+ {remote.display_name}
+ {remote.runtime_id}
+ |
+ + remote + Configured Runtime endpoint + | ++ Endpoint: {remote.endpoint_configured ? 'configured' : 'not configured'} + {#if remote.endpoint_configured}hidden{/if} + Token: {remote.token_ref_configured ? 'configured' : 'not configured'} + | ++ {remote.status} + {#if remote.restart_required} + restart required + {/if} + | +
+
+
+
+
+ |
+
|
+
+ Test: {test.state}
+ {test.health_result} · {test.checked_at}
+
+ {test.compatibility_basis} + {#if available.length > 0} +Verified areas: {available.join(', ')} + {/if} + {#if unchecked.length > 0} +Unchecked warning areas: {unchecked.join(', ')} + {/if} + |
+ ||||
editable
+{workspaceMetadata?.revision ?? 'unknown'}