diff --git a/web/workspace/src/lib/workspace-sidebar/ObjectivesNavSection.svelte b/web/workspace/src/lib/workspace-sidebar/ObjectivesNavSection.svelte new file mode 100644 index 00000000..e448e99e --- /dev/null +++ b/web/workspace/src/lib/workspace-sidebar/ObjectivesNavSection.svelte @@ -0,0 +1,157 @@ + + + + + diff --git a/web/workspace/src/lib/workspace-sidebar/RepositoriesNavSection.svelte b/web/workspace/src/lib/workspace-sidebar/RepositoriesNavSection.svelte new file mode 100644 index 00000000..759e8899 --- /dev/null +++ b/web/workspace/src/lib/workspace-sidebar/RepositoriesNavSection.svelte @@ -0,0 +1,106 @@ + + + + + diff --git a/web/workspace/src/lib/workspace-sidebar/WorkersNavSection.svelte b/web/workspace/src/lib/workspace-sidebar/WorkersNavSection.svelte new file mode 100644 index 00000000..0b81f0b6 --- /dev/null +++ b/web/workspace/src/lib/workspace-sidebar/WorkersNavSection.svelte @@ -0,0 +1,157 @@ + + + + + diff --git a/web/workspace/src/lib/workspace-sidebar/WorkspaceSidebar.svelte b/web/workspace/src/lib/workspace-sidebar/WorkspaceSidebar.svelte new file mode 100644 index 00000000..ecc85e69 --- /dev/null +++ b/web/workspace/src/lib/workspace-sidebar/WorkspaceSidebar.svelte @@ -0,0 +1,124 @@ + + + + + diff --git a/web/workspace/src/lib/workspace-sidebar/types.ts b/web/workspace/src/lib/workspace-sidebar/types.ts new file mode 100644 index 00000000..8dc8286b --- /dev/null +++ b/web/workspace/src/lib/workspace-sidebar/types.ts @@ -0,0 +1,82 @@ +export type ExtensionPoint = { + status: string; + note: string; +}; + +export type WorkspaceResponse = { + workspace_id: string; + display_name: string; + record_authority: string; + extension_points: { + event_stream: ExtensionPoint; + host_worker_bridge: ExtensionPoint; + }; +}; + +export type Diagnostic = { + code: string; + severity: string; + message: string; +}; + +export type Host = { + host_id: string; + label: string; + kind: string; + status: string; + observed_at: string; + last_seen_at: string; + capabilities: { + local_pod_inspection: string; + workspace_root: string; + os: string; + arch: string; + max_workers: number; + }; + diagnostics: Diagnostic[]; +}; + +export type Worker = { + worker_id: string; + host_id: string; + label: string; + pod_name: string; + role?: string; + profile?: string; + workspace_root?: string; + state: string; + status: string; + last_seen_at?: string; + implementation: { kind: string; pod_name: string }; + diagnostics: Diagnostic[]; +}; + +export type ListResponse = { + workspace_id: string; + limit: number; + items: T[]; + source: string; + diagnostics: Diagnostic[]; +}; + +export type ObjectiveSummary = { + id: string; + title: string; + state: string; + updated_at?: string | null; + linked_tickets?: string[]; + record_source?: string; +}; + +export type InvalidProjectRecord = { + label: string; + reason: string; +}; + +export type ObjectiveListResponse = { + workspace_id: string; + limit: number; + items: ObjectiveSummary[]; + invalid_records: InvalidProjectRecord[]; + record_authority: string; +}; diff --git a/web/workspace/src/routes/+page.svelte b/web/workspace/src/routes/+page.svelte index 9b1c1a4a..a7d8477a 100644 --- a/web/workspace/src/routes/+page.svelte +++ b/web/workspace/src/routes/+page.svelte @@ -1,59 +1,6 @@ @@ -110,174 +75,182 @@ /> -
-
-

Local / single-workspace bootstrap

-

Yoi Workspace Control Plane

-

- Static SPA shell for reading canonical .yoi project records - and the local Host / Worker execution view through bounded backend APIs. - Ticket and Objective lifecycle authority stays in the existing local record - workflow. -

-
+
+ -
-

Workspace

- {#if workspace} -
-
-
ID
-
{workspace.workspace_id}
-
-
-
Name
-
{workspace.display_name}
-
-
-
Record authority
-
{workspace.record_authority}
-
-
-
Host / Worker bridge
-
{workspace.extension_points.host_worker_bridge.status}
-
-
- {:else if loadError} -

{loadError}

- {:else} -

Waiting for /api/workspace

- {/if} -
- -
-
-

Read API surface

-
    - {#each endpoints as endpoint} -
  • {endpoint.path} — {endpoint.label}
  • - {/each} -
-
- -
-

Reserved seams

+
+
+

Local / single-workspace bootstrap

+

Yoi Workspace Control Plane

- Event streams remain represented as extension-point state in the backend - response. Hosts and Workers are read-only local observations; no - scheduler, lifecycle control, or hosted multi-tenant behavior is - implemented in this slice. + Static SPA shell for reading canonical .yoi project records + and the local Host / Worker execution view through bounded backend APIs. + Ticket and Objective lifecycle authority stays in the existing local record + workflow.

-
-
+ -
-
-

Hosts

- {#if hosts} - {#if hosts.items.length === 0} -

No local Hosts are visible.

- {:else} -
- {#each hosts.items as host} -
-
- {host.label} - {host.status} -
-
-
-
ID
-
{host.host_id}
-
-
-
Kind
-
{host.kind}
-
-
-
Local Pod inspection
-
{host.capabilities.local_pod_inspection}
-
-
-
Platform
-
{host.capabilities.os} / {host.capabilities.arch}
-
-
-
- {/each} +
+

Workspace

+ {#if workspace} +
+
+
ID
+
{workspace.workspace_id}
- {/if} - {:else if loadError} -

{loadError}

- {:else} -

Waiting for /api/hosts

- {/if} -
- -
-

Workers

- {#if workers} - {#if workers.items.length === 0} -

No local Workers are visible.

- {:else} -
- - - - - - - - - - - - {#each workers.items as worker} - - - - - - - - {/each} - -
WorkerHostStateWorkspaceImplementation
- {worker.label} - {#if worker.role || worker.profile} - {worker.role ?? 'role unknown'} / {worker.profile ?? 'profile unknown'} - {/if} - {worker.host_id}{worker.state} · {worker.status}{worker.workspace_root ?? 'unknown'}{worker.implementation.kind}: {worker.implementation.pod_name}
+
+
Name
+
{workspace.display_name}
- {/if} - {:else if loadError} -

{loadError}

+
+
Record authority
+
{workspace.record_authority}
+
+
+
Host / Worker bridge
+
{workspace.extension_points.host_worker_bridge.status}
+
+ + {:else if workspaceError} +

{workspaceError}

{:else} -

Waiting for /api/workers

+

Waiting for /api/workspace

{/if} -
-
+ - {#if hosts || workers} - {@const diagnostics = diagnosticsFor(hosts?.diagnostics, workers?.diagnostics)} - {#if diagnostics.length > 0} -
-

Diagnostics

+
+
+

Read API surface

    - {#each diagnostics as diagnostic} -
  • - {diagnostic.severity} - {diagnostic.code} - {diagnostic.message} -
  • + {#each endpoints as endpoint} +
  • {endpoint.path} — {endpoint.label}
  • {/each}
-
+
+ +
+

Reserved seams

+

+ Event streams remain represented as extension-point state in the backend + response. Hosts and Workers are read-only local observations; no + scheduler, lifecycle control, or hosted multi-tenant behavior is + implemented in this slice. +

+
+ + +
+
+

Hosts

+ {#if hosts} + {#if hosts.items.length === 0} +

No local Hosts are visible.

+ {:else} +
+ {#each hosts.items as host} +
+
+ {host.label} + {host.status} +
+
+
+
ID
+
{host.host_id}
+
+
+
Kind
+
{host.kind}
+
+
+
Local inspection
+
{host.capabilities.local_pod_inspection}
+
+
+
Platform
+
{host.capabilities.os} / {host.capabilities.arch}
+
+
+
+ {/each} +
+ {/if} + {:else if hostsError} +

{hostsError}

+ {:else} +

Waiting for /api/hosts

+ {/if} +
+ +
+

Workers

+ {#if workers} + {#if workers.items.length === 0} +

No local Workers are visible.

+ {:else} +
+ + + + + + + + + + + + {#each workers.items as worker} + + + + + + + + {/each} + +
WorkerHostStateWorkspaceImplementation
+ {worker.label} + {#if worker.role || worker.profile} + {worker.role ?? 'role unknown'} / {worker.profile ?? 'profile unknown'} + {/if} + {worker.host_id}{worker.state} · {worker.status}{worker.workspace_root ?? 'unknown'}{worker.implementation.kind}
+
+ {/if} + {:else if workersError} +

{workersError}

+ {:else} +

Waiting for /api/workers

+ {/if} +
+
+ + {#if hosts || workers} + {@const diagnostics = diagnosticsFor(hosts?.diagnostics, workers?.diagnostics)} + {#if diagnostics.length > 0} +
+

Diagnostics

+
    + {#each diagnostics as diagnostic} +
  • + {diagnostic.severity} + {diagnostic.code} + {diagnostic.message} +
  • + {/each} +
+
+ {/if} {/if} - {/if} -
+ +