Implement execution workspaces and work products

This commit is contained in:
Dotta
2026-03-13 17:12:25 -05:00
parent 9da5358bb3
commit 920bc4c70f
45 changed files with 9157 additions and 140 deletions

View File

@@ -0,0 +1,39 @@
import { useEffect, useState } from "react";
const WORKSPACES_KEY = "paperclip:experimental:workspaces";
export function loadExperimentalWorkspacesEnabled(): boolean {
if (typeof window === "undefined") return false;
return window.localStorage.getItem(WORKSPACES_KEY) === "true";
}
export function saveExperimentalWorkspacesEnabled(enabled: boolean) {
if (typeof window === "undefined") return;
window.localStorage.setItem(WORKSPACES_KEY, enabled ? "true" : "false");
window.dispatchEvent(new CustomEvent("paperclip:experimental:workspaces", { detail: enabled }));
}
export function useExperimentalWorkspacesEnabled() {
const [enabled, setEnabled] = useState(loadExperimentalWorkspacesEnabled);
useEffect(() => {
const handleStorage = (event: StorageEvent) => {
if (event.key && event.key !== WORKSPACES_KEY) return;
setEnabled(loadExperimentalWorkspacesEnabled());
};
const handleCustom = () => setEnabled(loadExperimentalWorkspacesEnabled());
window.addEventListener("storage", handleStorage);
window.addEventListener("paperclip:experimental:workspaces", handleCustom as EventListener);
return () => {
window.removeEventListener("storage", handleStorage);
window.removeEventListener("paperclip:experimental:workspaces", handleCustom as EventListener);
};
}, []);
const update = (next: boolean) => {
saveExperimentalWorkspacesEnabled(next);
setEnabled(next);
};
return { enabled, setEnabled: update };
}

View File

@@ -110,6 +110,7 @@ function makeIssue(id: string, isUnreadForMe: boolean): Issue {
id,
companyId: "company-1",
projectId: null,
projectWorkspaceId: null,
goalId: null,
parentId: null,
title: `Issue ${id}`,
@@ -125,6 +126,8 @@ function makeIssue(id: string, isUnreadForMe: boolean): Issue {
requestDepth: 0,
billingCode: null,
assigneeAdapterOverrides: null,
executionWorkspaceId: null,
executionWorkspacePreference: null,
executionWorkspaceSettings: null,
checkoutRunId: null,
executionRunId: null,

View File

@@ -32,6 +32,12 @@ export const queryKeys = {
approvals: (issueId: string) => ["issues", "approvals", issueId] as const,
liveRuns: (issueId: string) => ["issues", "live-runs", issueId] as const,
activeRun: (issueId: string) => ["issues", "active-run", issueId] as const,
workProducts: (issueId: string) => ["issues", "work-products", issueId] as const,
},
executionWorkspaces: {
list: (companyId: string, filters?: Record<string, string | boolean | undefined>) =>
["execution-workspaces", companyId, filters ?? {}] as const,
detail: (id: string) => ["execution-workspaces", "detail", id] as const,
},
projects: {
list: (companyId: string) => ["projects", companyId] as const,