Skip to content

feat: workspace CRUD — control plane routes + dashboard UI#84

Merged
arek-e merged 1 commit intomainfrom
feat/workspace-ui-and-routes
Apr 4, 2026
Merged

feat: workspace CRUD — control plane routes + dashboard UI#84
arek-e merged 1 commit intomainfrom
feat/workspace-ui-and-routes

Conversation

@arek-e
Copy link
Copy Markdown
Owner

@arek-e arek-e commented Apr 4, 2026

Summary

  • Control plane: 5 workspace CRUD endpoints wired with OpenAPI (create, list, get, update, delete)
  • Dashboard: Workspace list page with type badges (monorepo/multi-repo), repo info, daemon count
  • WorkspaceForm: Slide-out form — monorepo/multi-repo selector, repo inputs, root dir, branch, project settings (language, package manager, test/build commands)
  • Navigation: Workspaces in sidebar + command palette

Test plan

  • 42/42 typecheck pass
  • 31/31 tests pass
  • CI green

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Workspace management system: create, view, edit, and delete workspaces
    • Support for monorepo and multi-repo workspace types
    • Configure workspace settings including language, package manager, and build/test commands
    • Manage repositories with role and branch assignment
    • Workspace navigation added to sidebar and command palette

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 4, 2026

Warning

Rate limit exceeded

@arek-e has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 0 minutes and 54 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 0 minutes and 54 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9586ce4d-419e-45e9-ade0-4bd4f84faa6f

📥 Commits

Reviewing files that changed from the base of the PR and between f81fbf5 and 1c00227.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • apps/control-plane/package.json
  • apps/control-plane/src/app.ts
  • apps/control-plane/tsconfig.json
  • apps/dashboard/src/api/client.ts
  • apps/dashboard/src/components/CommandPalette.tsx
  • apps/dashboard/src/components/Layout.tsx
  • apps/dashboard/src/components/WorkspaceForm.tsx
  • apps/dashboard/src/pages/Workspaces.tsx
  • apps/dashboard/src/router.tsx
📝 Walkthrough

Walkthrough

This PR introduces workspace management capabilities across the control plane and dashboard. The control plane now exposes CRUD API endpoints for workspaces backed by an in-memory store, while the dashboard provides UI components for listing, creating, updating, and deleting workspaces with form-based configuration.

Changes

Cohort / File(s) Summary
Control Plane Integration
apps/control-plane/package.json, apps/control-plane/tsconfig.json
Added workspace domain package dependency and TypeScript project reference to enable workspace store and route imports.
Control Plane Routes
apps/control-plane/src/app.ts
Registered five OpenAPI endpoints: create workspace (validates unique names, returns 409 on duplication), list workspaces, get workspace by ID, update workspace, and delete workspace; integrated with in-memory workspaceStore.
Dashboard API Client
apps/dashboard/src/api/client.ts
Added Workspace and WorkspaceRepo TypeScript interfaces and five async client functions (listWorkspaces, getWorkspace, createWorkspace, updateWorkspace, deleteWorkspace) for REST communication with the control plane.
Dashboard Navigation
apps/dashboard/src/components/CommandPalette.tsx, apps/dashboard/src/components/Layout.tsx
Added "Workspaces" navigation entries to command palette and sidebar under the "Agents" group, linking to /workspaces route.
Dashboard UI Components
apps/dashboard/src/components/WorkspaceForm.tsx, apps/dashboard/src/pages/Workspaces.tsx
Introduced WorkspaceForm component for creating and editing workspaces with dynamic multi-repo support and settings management; added Workspaces page with polling-based list, creation/editing, and deletion workflows including confirmation dialogs and toast notifications.
Dashboard Routing
apps/dashboard/src/router.tsx
Registered new /workspaces route with code-splitting and skeleton loading fallback.

Sequence Diagram

sequenceDiagram
    participant User as User (Dashboard)
    participant Form as WorkspaceForm
    participant API as Dashboard API Client
    participant Server as Control Plane API
    participant Store as Workspace Store
    
    User->>Form: Click "Create Workspace"
    Form->>Form: Populate form state
    User->>Form: Submit workspace data
    Form->>API: POST /v1/workspaces (create) or PATCH /v1/workspaces/:id (update)
    API->>Server: Send HTTP request with workspace payload
    Server->>Store: Check if workspace exists (update) or name is unique (create)
    alt Create - Duplicate Name
        Store-->>Server: Name already exists
        Server-->>API: 409 WORKSPACE_ALREADY_EXISTS
    else Valid Request
        Store->>Store: Create or update workspace with UUID and timestamps
        Store-->>Server: Workspace object
        Server-->>API: 200 OK with workspace
    end
    API-->>Form: Response (success or error)
    Form->>Form: Show toast notification
    Form->>User: Close form, refresh list
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 A workspace awaits, oh what delight!
Create, edit, delete—all working right!
Repos in rows, settings aligned,
A form so graceful, a mind at ease,
Your workspaces managed with woodland-bred ease! 🌲✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description provided does not follow the required template structure and is missing required sections like 'What' and 'Why' with proper headings, along with the checklist. Restructure description to match the template: add 'What' and 'Why' sections with proper headings, include the complete checklist with all items, and link to any related issues.
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: implementing workspace CRUD functionality with control plane routes and dashboard UI.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/workspace-ui-and-routes

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Apr 4, 2026

Deploying getpaws with  Cloudflare Pages  Cloudflare Pages

Latest commit: 1c00227
Status: ✅  Deploy successful!
Preview URL: https://ee806777.getpaws-6m4.pages.dev
Branch Preview URL: https://feat-workspace-ui-and-routes.getpaws-6m4.pages.dev

View logs

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (2)
apps/control-plane/src/app.ts (1)

988-996: Consider adding audit logging for workspace operations.

Daemon CRUD operations emit audit events (e.g., daemon.created, daemon.updated, daemon.deleted), but workspace operations do not. For consistency and operational visibility, consider adding similar audit entries.

📝 Example audit logging for create
     const workspace = workspaceStore.create({
       id: randomUUID(),
       ...body,
       repos: body.repos,
       settings: body.settings ?? {},
       createdAt: new Date().toISOString(),
       updatedAt: new Date().toISOString(),
     });
+    auditStore.append({
+      category: 'workspace',
+      action: 'workspace.created',
+      severity: 'info',
+      resourceType: 'workspace',
+      resourceId: workspace.id,
+    });
     return c.json(workspace, 201);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/control-plane/src/app.ts` around lines 988 - 996, Add an audit event
emission when a workspace is created: after calling workspaceStore.create(...)
and before returning c.json(...), call the existing audit/event logging utility
used for daemon events (emitAuditEvent or similar) to publish an event like
"workspace.created" with the workspace id, name/payload (workspace),
actor/context (e.g., request user or c.get('user') if available) and timestamps;
update the same pattern in the handler that performs workspaceStore.update and
workspaceStore.delete to emit "workspace.updated" and "workspace.deleted"
respectively so workspace operations mirror daemon.* audit entries.
apps/dashboard/src/api/client.ts (1)

578-635: Consider a workspace API factory that injects the request function.

These new methods call global fetch directly, which makes isolated testing harder. A small createWorkspaceApi(request = fetch) factory keeps behavior identical and improves testability.

As per coding guidelines, "Use dependency injection for testability. Inject request, exec, and other dependencies rather than relying on globals."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/dashboard/src/api/client.ts` around lines 578 - 635, Refactor the
workspace API to accept a request function via a small factory (e.g., export a
createWorkspaceApi(request = fetch) that returns the methods listWorkspaces,
getWorkspace, createWorkspace, updateWorkspace, and deleteWorkspace) so tests
can inject a mock request; each method should use the injected request instead
of the global fetch and preserve current behavior (including encodeURIComponent
for id, apiKeyHeaders() usage, error parsing logic in
createWorkspace/updateWorkspace, and returned shapes). Update any existing
callers/tests to call createWorkspaceApi() or pass a mocked request when needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/control-plane/src/app.ts`:
- Around line 972-973: The workspace CRUD endpoints under /v1/workspaces are
missing the auth middleware registration; update the auth middleware
registration block (the same place where daemons, sessions, and snapshots are
protected around the existing middleware setup) to attach the same
authentication middleware (e.g., ensureAuthenticated / authMiddleware used for
daemons/sessions/snapshots) to the workspace routes (the router or handler that
registers the workspace CRUD endpoints, such as the workspacesRoutes or router
handling /v1/workspaces) so all create/read/update/delete workspace endpoints
are protected.

In `@apps/dashboard/src/api/client.ts`:
- Line 580: Replace the generic throws (e.g., "throw new Error(`Failed to fetch
workspaces: ${res.status}`)" and the other throw sites at the indicated
locations) with a typed workspace error that carries an error code so callers
can handle them programmatically; instantiate and throw the project-specific
error class (e.g., DaemonsError or WorkspaceError) with a distinct code like
WORKSPACE_FETCH_FAILED or WORKSPACE_NOT_FOUND and include the original
message/status as context. Locate the throw sites in
apps/dashboard/src/api/client.ts that use the local res variable and the
fetch/parse branches and replace each "new Error(...)" with "new
DaemonsError('WORKSPACE_<SPECIFIC_CODE>', `<descriptive message including
${res.status} or details>`)" (or the established WorkspaceError class used
across the codebase), preserving original message text as the error detail.
Ensure import of the error class is added if missing and use unique error codes
per failure case (e.g., WORKSPACE_FETCH_FAILED, WORKSPACE_PARSE_FAILED,
WORKSPACE_DELETE_FAILED) to match coding guidelines.
- Around line 578-582: The API functions listWorkspaces, getWorkspace,
createWorkspace, and updateWorkspace currently send/receive raw JSON, so add Zod
schemas for the Workspace shape and for list/individual responses and use them
to validate: parse and validate response bodies with schema.parse(resJson) and
throw a descriptive error on parse failures; for createWorkspace and
updateWorkspace validate the request payload with the corresponding Zod input
schema before calling fetch and send the validated object as the body; derive
TypeScript types via z.infer<> and replace direct returns with the parsed/typed
results to ensure runtime safety and clear error messages (reference the
functions listWorkspaces, getWorkspace, createWorkspace, updateWorkspace and the
central Workspace schema you add).

In `@apps/dashboard/src/pages/Workspaces.tsx`:
- Around line 24-32: The file defines a local Workspace interface that diverges
from the API client’s canonical type (missing rootDir, settings, updatedAt and
using a loose role type); replace the local interface declaration with an import
of the API client's Workspace type and update any usages (e.g., the local
Workspace interface and the repos.role annotation) to use the imported Workspace
to ensure type parity and stricter role union types.

---

Nitpick comments:
In `@apps/control-plane/src/app.ts`:
- Around line 988-996: Add an audit event emission when a workspace is created:
after calling workspaceStore.create(...) and before returning c.json(...), call
the existing audit/event logging utility used for daemon events (emitAuditEvent
or similar) to publish an event like "workspace.created" with the workspace id,
name/payload (workspace), actor/context (e.g., request user or c.get('user') if
available) and timestamps; update the same pattern in the handler that performs
workspaceStore.update and workspaceStore.delete to emit "workspace.updated" and
"workspace.deleted" respectively so workspace operations mirror daemon.* audit
entries.

In `@apps/dashboard/src/api/client.ts`:
- Around line 578-635: Refactor the workspace API to accept a request function
via a small factory (e.g., export a createWorkspaceApi(request = fetch) that
returns the methods listWorkspaces, getWorkspace, createWorkspace,
updateWorkspace, and deleteWorkspace) so tests can inject a mock request; each
method should use the injected request instead of the global fetch and preserve
current behavior (including encodeURIComponent for id, apiKeyHeaders() usage,
error parsing logic in createWorkspace/updateWorkspace, and returned shapes).
Update any existing callers/tests to call createWorkspaceApi() or pass a mocked
request when needed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e4445733-fe57-4586-935a-cc4aaf1ac90c

📥 Commits

Reviewing files that changed from the base of the PR and between f11746a and f81fbf5.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • apps/control-plane/package.json
  • apps/control-plane/src/app.ts
  • apps/control-plane/tsconfig.json
  • apps/dashboard/src/api/client.ts
  • apps/dashboard/src/components/CommandPalette.tsx
  • apps/dashboard/src/components/Layout.tsx
  • apps/dashboard/src/components/WorkspaceForm.tsx
  • apps/dashboard/src/pages/Workspaces.tsx
  • apps/dashboard/src/router.tsx

Comment on lines +972 to +973
// --- Workspaces ---

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing auth middleware for workspace routes.

The workspace CRUD endpoints lack auth middleware registration. Other /v1/* domain routes (e.g., daemons, sessions, snapshots) have explicit auth middleware applied in lines 551-573. Without this, workspace routes are unprotected.

🔒 Proposed fix to add auth middleware for workspace routes

Add these lines in the auth middleware registration section (around line 573):

 app.use('/v1/mcp/*', authMiddleware(authConfig));
 app.use('/v1/mcp', authMiddleware(authConfig));
 app.use('/v1/settings', authMiddleware(authConfig));
 app.use('/v1/settings/*', authMiddleware(authConfig));
+app.use('/v1/workspaces', authMiddleware(authConfig));
+app.use('/v1/workspaces/*', authMiddleware(authConfig));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/control-plane/src/app.ts` around lines 972 - 973, The workspace CRUD
endpoints under /v1/workspaces are missing the auth middleware registration;
update the auth middleware registration block (the same place where daemons,
sessions, and snapshots are protected around the existing middleware setup) to
attach the same authentication middleware (e.g., ensureAuthenticated /
authMiddleware used for daemons/sessions/snapshots) to the workspace routes (the
router or handler that registers the workspace CRUD endpoints, such as the
workspacesRoutes or router handling /v1/workspaces) so all
create/read/update/delete workspace endpoints are protected.

Comment on lines +578 to +582
export async function listWorkspaces(): Promise<{ workspaces: Workspace[] }> {
const res = await fetch('/v1/workspaces', { headers: apiKeyHeaders() });
if (!res.ok) throw new Error(`Failed to fetch workspaces: ${res.status}`);
return res.json();
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, locate and examine the file
find . -type f -name "client.ts" | grep -E "apps/dashboard.*api"

Repository: arek-e/paws

Length of output: 89


🏁 Script executed:

# Get file size to understand how much to read
wc -l apps/dashboard/src/api/client.ts

Repository: arek-e/paws

Length of output: 91


🏁 Script executed:

# Read the relevant section of the file (around lines 578-627)
sed -n '570,635p' apps/dashboard/src/api/client.ts

Repository: arek-e/paws

Length of output: 2076


🏁 Script executed:

# Check if Zod is already imported in the file
grep -n "zod\|Zod" apps/dashboard/src/api/client.ts | head -20

Repository: arek-e/paws

Length of output: 37


🏁 Script executed:

# Check for the Workspace type definition
grep -n "type Workspace\|interface Workspace" apps/dashboard/src/api/client.ts

Repository: arek-e/paws

Length of output: 124


🏁 Script executed:

# Get the full Workspace and WorkspaceRepo type definitions
sed -n '554,575p' apps/dashboard/src/api/client.ts

Repository: arek-e/paws

Length of output: 515


🏁 Script executed:

# Check if Zod is used elsewhere in the dashboard project
find apps/dashboard -type f \( -name "*.ts" -o -name "*.tsx" \) -exec grep -l "from 'zod'\|from \"zod\"" {} \;

Repository: arek-e/paws

Length of output: 37


🏁 Script executed:

# Look at the imports at the top of the client.ts file to understand dependencies
head -30 apps/dashboard/src/api/client.ts

Repository: arek-e/paws

Length of output: 950


Add Zod validation for workspace API request/response payloads.

The listWorkspaces(), getWorkspace(), createWorkspace(), and updateWorkspace() functions return unvalidated JSON responses, and createWorkspace() and updateWorkspace() submit request bodies without validation. This creates runtime brittleness if the API schema drifts from the TypeScript interface definitions.

Proposed fix
+import { z } from 'zod';
+
+const WorkspaceRepoSchema = z.object({
+  name: z.string(),
+  role: z.enum(['primary', 'reference']).optional(),
+  branch: z.string().optional(),
+});
+
+const WorkspaceSchema = z.object({
+  id: z.string(),
+  name: z.string(),
+  description: z.string().optional(),
+  type: z.enum(['monorepo', 'multi-repo']),
+  repos: z.array(WorkspaceRepoSchema),
+  rootDir: z.string().optional(),
+  settings: z
+    .object({
+      language: z.string().optional(),
+      packageManager: z.string().optional(),
+      testCommand: z.string().optional(),
+      buildCommand: z.string().optional(),
+    })
+    .optional(),
+  daemonCount: z.number().optional(),
+  createdAt: z.string(),
+  updatedAt: z.string().optional(),
+});
+
+const WorkspaceListSchema = z.object({
+  workspaces: z.array(WorkspaceSchema),
+});
+
 export async function listWorkspaces(): Promise<{ workspaces: Workspace[] }> {
   const res = await fetch('/v1/workspaces', { headers: apiKeyHeaders() });
   if (!res.ok) throw new Error(`Failed to fetch workspaces: ${res.status}`);
-  return res.json();
+  return WorkspaceListSchema.parse(await res.json());
 }

Per coding guidelines: "Use Zod for all external data validation: API requests, config files, and environment variables."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/dashboard/src/api/client.ts` around lines 578 - 582, The API functions
listWorkspaces, getWorkspace, createWorkspace, and updateWorkspace currently
send/receive raw JSON, so add Zod schemas for the Workspace shape and for
list/individual responses and use them to validate: parse and validate response
bodies with schema.parse(resJson) and throw a descriptive error on parse
failures; for createWorkspace and updateWorkspace validate the request payload
with the corresponding Zod input schema before calling fetch and send the
validated object as the body; derive TypeScript types via z.infer<> and replace
direct returns with the parsed/typed results to ensure runtime safety and clear
error messages (reference the functions listWorkspaces, getWorkspace,
createWorkspace, updateWorkspace and the central Workspace schema you add).


export async function listWorkspaces(): Promise<{ workspaces: Workspace[] }> {
const res = await fetch('/v1/workspaces', { headers: apiKeyHeaders() });
if (!res.ok) throw new Error(`Failed to fetch workspaces: ${res.status}`);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Replace generic Error throws with typed workspace error codes.

Line 580, Line 588, Line 602-605, Line 621-624, and Line 634 throw generic Error, which removes machine-readable error semantics for callers.

Proposed fix
+type WorkspaceErrorCode =
+  | 'WORKSPACE_LIST_FAILED'
+  | 'WORKSPACE_GET_FAILED'
+  | 'WORKSPACE_CREATE_FAILED'
+  | 'WORKSPACE_UPDATE_FAILED'
+  | 'WORKSPACE_DELETE_FAILED';
+
+type WorkspaceApiError = Error & {
+  code: WorkspaceErrorCode;
+  status: number;
+};
+
+function createWorkspaceApiError(
+  code: WorkspaceErrorCode,
+  status: number,
+  message: string,
+): WorkspaceApiError {
+  return Object.assign(new Error(message), { code, status });
+}
...
-  if (!res.ok) throw new Error(`Failed to fetch workspaces: ${res.status}`);
+  if (!res.ok) {
+    throw createWorkspaceApiError('WORKSPACE_LIST_FAILED', res.status, `Failed to fetch workspaces: ${res.status}`);
+  }

As per coding guidelines, "Use typed errors with error codes (e.g., DaemonsError), not generic Error."

Also applies to: 588-588, 602-605, 621-624, 634-634

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/dashboard/src/api/client.ts` at line 580, Replace the generic throws
(e.g., "throw new Error(`Failed to fetch workspaces: ${res.status}`)" and the
other throw sites at the indicated locations) with a typed workspace error that
carries an error code so callers can handle them programmatically; instantiate
and throw the project-specific error class (e.g., DaemonsError or
WorkspaceError) with a distinct code like WORKSPACE_FETCH_FAILED or
WORKSPACE_NOT_FOUND and include the original message/status as context. Locate
the throw sites in apps/dashboard/src/api/client.ts that use the local res
variable and the fetch/parse branches and replace each "new Error(...)" with
"new DaemonsError('WORKSPACE_<SPECIFIC_CODE>', `<descriptive message including
${res.status} or details>`)" (or the established WorkspaceError class used
across the codebase), preserving original message text as the error detail.
Ensure import of the error class is added if missing and use unique error codes
per failure case (e.g., WORKSPACE_FETCH_FAILED, WORKSPACE_PARSE_FAILED,
WORKSPACE_DELETE_FAILED) to match coding guidelines.

Comment on lines +24 to +32
interface Workspace {
id: string;
name: string;
description?: string;
type: 'monorepo' | 'multi-repo';
repos: Array<{ name: string; role?: string; branch?: string }>;
daemonCount?: number;
createdAt: string;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Import Workspace type from the API client instead of redefining locally.

The local interface is missing fields (rootDir, settings, updatedAt) and uses a weaker type for role (string vs 'primary' | 'reference'). The API client already exports a complete Workspace interface that should be used for type consistency.

♻️ Proposed fix
-import { deleteWorkspace, listWorkspaces } from '../api/client.js';
+import { deleteWorkspace, listWorkspaces, type Workspace } from '../api/client.js';
 import { WorkspaceForm } from '../components/WorkspaceForm.js';
 import { RelativeTime } from '../components/RelativeTime.js';
 // ... other imports

-interface Workspace {
-  id: string;
-  name: string;
-  description?: string;
-  type: 'monorepo' | 'multi-repo';
-  repos: Array<{ name: string; role?: string; branch?: string }>;
-  daemonCount?: number;
-  createdAt: string;
-}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/dashboard/src/pages/Workspaces.tsx` around lines 24 - 32, The file
defines a local Workspace interface that diverges from the API client’s
canonical type (missing rootDir, settings, updatedAt and using a loose role
type); replace the local interface declaration with an import of the API
client's Workspace type and update any usages (e.g., the local Workspace
interface and the repos.role annotation) to use the imported Workspace to ensure
type parity and stricter role union types.

- Wire workspace domain into control plane: 5 OpenAPI endpoints
  (create, list, get, update, delete) with in-memory store
- Dashboard workspace page: list view with type badges, repo info,
  create/edit/delete actions
- WorkspaceForm: slide-out form with monorepo/multi-repo type selector,
  repo picker, root directory, branch, and project settings
- Workspace added to sidebar nav and command palette

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@arek-e arek-e force-pushed the feat/workspace-ui-and-routes branch from f81fbf5 to 1c00227 Compare April 4, 2026 11:04
@arek-e arek-e merged commit c7404ac into main Apr 4, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant