Files
PaperClipAI/ui/src/api/projects.ts
T
DottaandPaperclip b315580640 feat: add private task creation and sharing controls (#14718)
Add private task creation and sharing controls, effective access explanations, private project management, and locked task references.

Constrain the mobile composer plus menu to the viewport and explain named inherited privacy on hover, focus, or tap. Include 125 production-component Storybook stories and thirteen interactive user journeys.

Final head passes all CI checks and Greptile Apex 5/5 with no findings.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-07 07:27:52 -05:00

82 lines
4.0 KiB
TypeScript

import type {
Project,
ProjectAccessMember,
ProjectRepositoryOptions,
ProjectWorkspace,
WorkspaceOperation,
WorkspaceRuntimeControlTarget,
} from "@paperclipai/shared";
import { api } from "./client";
import { sanitizeWorkspaceRuntimeControlTarget } from "./workspace-runtime-control";
function withCompanyScope(path: string, companyId?: string) {
if (!companyId) return path;
const separator = path.includes("?") ? "&" : "?";
return `${path}${separator}companyId=${encodeURIComponent(companyId)}`;
}
function projectPath(id: string, companyId?: string, suffix = "") {
return withCompanyScope(`/projects/${encodeURIComponent(id)}${suffix}`, companyId);
}
export const projectsApi = {
repositoryOptions: (companyId: string) => api.get<ProjectRepositoryOptions>(`/companies/${companyId}/project-repositories`),
setRepositories: (id: string, repositoryIds: string[]) => api.put<Project>(projectPath(id, undefined, "/repositories"), { repositoryIds }),
list: (companyId: string, opts: { includeArchived?: boolean } = {}) => {
const params = new URLSearchParams();
if (opts.includeArchived) params.set("includeArchived", "true");
const query = params.toString();
return api.get<Project[]>("/companies/" + encodeURIComponent(companyId) + "/projects" + (query ? "?" + query : ""));
},
get: (id: string, companyId?: string) => api.get<Project>(projectPath(id, companyId)),
create: (companyId: string, data: Record<string, unknown>) =>
api.post<Project>(`/companies/${companyId}/projects`, data),
update: (id: string, data: Record<string, unknown>, companyId?: string) =>
api.patch<Project>(projectPath(id, companyId), data),
listAccessMembers: (id: string, companyId?: string) =>
api.get<ProjectAccessMember[]>(projectPath(id, companyId, "/access-members")),
addAccessMember: (
id: string,
data: { subjectType: "user" | "agent"; subjectId: string },
companyId?: string,
) => api.post<ProjectAccessMember>(projectPath(id, companyId, "/access-members"), data),
removeAccessMember: (id: string, memberId: string, companyId?: string) =>
api.delete<ProjectAccessMember>(
projectPath(id, companyId, `/access-members/${encodeURIComponent(memberId)}`),
),
listWorkspaces: (projectId: string, companyId?: string) =>
api.get<ProjectWorkspace[]>(projectPath(projectId, companyId, "/workspaces")),
createWorkspace: (projectId: string, data: Record<string, unknown>, companyId?: string) =>
api.post<ProjectWorkspace>(projectPath(projectId, companyId, "/workspaces"), data),
updateWorkspace: (projectId: string, workspaceId: string, data: Record<string, unknown>, companyId?: string) =>
api.patch<ProjectWorkspace>(
projectPath(projectId, companyId, `/workspaces/${encodeURIComponent(workspaceId)}`),
data,
),
controlWorkspaceRuntimeServices: (
projectId: string,
workspaceId: string,
action: "start" | "stop" | "restart",
companyId?: string,
target: WorkspaceRuntimeControlTarget = {},
) =>
api.post<{ workspace: ProjectWorkspace; operation: WorkspaceOperation }>(
projectPath(projectId, companyId, `/workspaces/${encodeURIComponent(workspaceId)}/runtime-services/${action}`),
sanitizeWorkspaceRuntimeControlTarget(target),
),
controlWorkspaceCommands: (
projectId: string,
workspaceId: string,
action: "start" | "stop" | "restart" | "run",
companyId?: string,
target: WorkspaceRuntimeControlTarget = {},
) =>
api.post<{ workspace: ProjectWorkspace; operation: WorkspaceOperation }>(
projectPath(projectId, companyId, `/workspaces/${encodeURIComponent(workspaceId)}/runtime-commands/${action}`),
sanitizeWorkspaceRuntimeControlTarget(target),
),
removeWorkspace: (projectId: string, workspaceId: string, companyId?: string) =>
api.delete<ProjectWorkspace>(projectPath(projectId, companyId, `/workspaces/${encodeURIComponent(workspaceId)}`)),
remove: (id: string, companyId?: string) => api.delete<Project>(projectPath(id, companyId)),
};