Files
pikasTech-HWLAB/web/hwlab-cloud-web/src/api/projectManagement.ts
T

286 lines
12 KiB
TypeScript

// SPEC: PJ2026-010404 项目管理 draft-2026-06-25-p0-project-management-mdtodo; draft-2026-06-26-p1-mdtodo-web-operable.
// Responsibility: Cloud Web client for the public project-management same-origin API.
import { fetchJson } from "./client";
import type { ApiResult } from "@/types";
export interface ProjectManagementEnvelope {
contractVersion?: string;
serviceId?: string;
ok?: boolean;
valuesRedacted?: boolean;
}
export interface ProjectNavigationItem {
id: string;
label: string;
apiRoute?: string;
}
export interface ProjectNavigationCapabilities {
mdtodoProjection?: boolean;
workbenchLaunch?: boolean;
workbenchLinks?: boolean;
sourceOfTruth?: string;
[key: string]: unknown;
}
export interface ProjectNavigation {
id: string;
label: string;
actor?: { id?: string | null; role?: string | null; authMethod?: string | null } | null;
items?: ProjectNavigationItem[];
capabilities?: ProjectNavigationCapabilities;
}
export interface ProjectProjectionSummary {
sourceId?: string;
documentCount?: number;
taskCount?: number;
projectedAt?: string;
startedAt?: string;
}
export interface ProjectNavigationResponse extends ProjectManagementEnvelope {
navigation?: ProjectNavigation;
projection?: ProjectProjectionSummary | null;
}
export interface ProjectRecord {
projectId: string;
name?: string;
title?: string;
sourceIds?: string[];
sourceOfTruth?: string;
status?: string;
}
export interface ProjectSource {
sourceId: string;
kind?: string;
sourceKind?: string;
displayName?: string;
projectId?: string;
status?: string;
hwpodId?: string | null;
nodeId?: string | null;
workspaceRootRef?: string | null;
mdtodoRootRef?: string | null;
maxFiles?: number;
updatedAt?: string;
valuesRedacted?: boolean;
}
export interface ProjectSourceInput {
sourceId?: string;
sourceKind?: string;
displayName?: string;
projectId?: string;
hwpodId?: string;
nodeId?: string;
workspaceRootRef?: string;
mdtodoRootRef?: string;
maxFiles?: number;
}
export interface MdtodoFileRecord {
sourceId: string;
fileRef: string;
projectId?: string;
relativePath?: string;
title?: string;
fingerprint?: string;
taskCount?: number;
parseError?: string | null;
revision?: number;
lastIndexedAt?: string;
updatedAt?: string;
}
export interface MdtodoTaskRecord {
taskRef: string;
projectId?: string;
sourceId?: string;
fileRef?: string;
taskId?: string;
rxxId?: string;
title?: string;
status?: string;
parentTaskRef?: string | null;
depth?: number;
lineNumber?: number;
ordinal?: number;
linkCount?: number;
sourceFingerprint?: string;
bodyPreview?: string;
parserMode?: string;
links?: MdtodoTaskLinkRecord[];
task?: {
bodyPreview?: string | null;
links?: MdtodoTaskLinkRecord[];
linkCount?: number | null;
title?: string | null;
[key: string]: unknown;
};
updatedAt?: string;
}
export interface MdtodoTaskLinkRecord {
linkId: string;
label?: string;
href?: string;
kind?: string;
relativePath?: string | null;
ordinal?: number;
availability?: string;
message?: string;
valuesRedacted?: boolean;
}
export interface MdtodoTaskDetailRecord {
taskRef: string;
taskId?: string;
rxxId?: string;
projectId?: string;
sourceId?: string;
fileRef?: string;
relativePath?: string;
title?: string;
status?: string;
lineNumber?: number;
headingLevel?: number;
statusMarker?: string | null;
body?: string;
bodyPreview?: string;
links?: MdtodoTaskLinkRecord[];
valuesRedacted?: boolean;
}
export interface MdtodoExecutionContext {
sourceId?: string | null;
sourceKind?: string | null;
projectId?: string | null;
taskRef?: string | null;
fileRef?: string | null;
relativePath?: string | null;
taskId?: string | null;
hwpodId?: string | null;
nodeId?: string | null;
workspaceRootRef?: string | null;
workspaceRootHash?: string | null;
workspaceRootLabel?: string | null;
mdtodoRootRef?: string | null;
hwpodWorkspaceArgs?: string | null;
contextFingerprint?: string | null;
capabilities?: Record<string, unknown>;
valuesRedacted?: boolean;
}
export interface MdtodoReportPreviewRecord {
sourceId?: string;
relativePath?: string;
content?: string;
fingerprint?: string;
revision?: string;
byteCount?: number;
render?: string;
linkId?: string;
label?: string;
href?: string;
valuesRedacted?: boolean;
}
export interface ProjectWorkbenchLinkRecord {
linkId: string;
projectId?: string;
taskRef?: string | null;
sessionId?: string | null;
traceId?: string | null;
createdBy?: string | null;
role?: string;
createdAt?: string;
updatedAt?: string;
}
export interface ProjectListResponse extends ProjectManagementEnvelope { projects?: ProjectRecord[] }
export interface ProjectSourceListResponse extends ProjectManagementEnvelope { sources?: ProjectSource[] }
export interface ProjectSourceMutationResponse extends ProjectManagementEnvelope { source?: ProjectSource }
export interface ProjectSourceProbeResponse extends ProjectManagementEnvelope { probe?: { ok?: boolean; status?: string; sourceId?: string; sourceKind?: string; entries?: number; valuesRedacted?: boolean } }
export interface ProjectSourceReindexResponse extends ProjectManagementEnvelope { projection?: ProjectProjectionSummary & { sourceKind?: string; rootRef?: string; valuesRedacted?: boolean } }
export interface MdtodoFileListResponse extends ProjectManagementEnvelope { files?: MdtodoFileRecord[] }
export interface MdtodoTaskPage {
offset?: number;
limit?: number;
maxLimit?: number;
total?: number;
hasMore?: boolean;
}
export interface MdtodoTaskListResponse extends ProjectManagementEnvelope { tasks?: MdtodoTaskRecord[]; page?: MdtodoTaskPage }
export interface MdtodoTaskDetailResponse extends ProjectManagementEnvelope { task?: MdtodoTaskRecord; detail?: MdtodoTaskDetailRecord; file?: MdtodoFileRecord }
export interface MdtodoLaunchContextResponse extends ProjectManagementEnvelope { task?: MdtodoTaskRecord; source?: Partial<ProjectSource>; executionContext?: MdtodoExecutionContext; launchContext?: Record<string, unknown> }
export interface MdtodoReportPreviewResponse extends ProjectManagementEnvelope { task?: MdtodoTaskRecord; link?: MdtodoTaskLinkRecord; report?: MdtodoReportPreviewRecord; file?: MdtodoFileRecord }
export interface MdtodoTaskMutationInput {
sourceId?: string;
fileRef?: string;
parentTaskRef?: string;
afterTaskRef?: string;
expectedFingerprint?: string;
revision?: string;
title?: string;
status?: string;
body?: string;
}
export interface MdtodoTaskMutationResponse extends ProjectManagementEnvelope {
task?: MdtodoTaskRecord | null;
changedTaskId?: string | null;
affectedTaskIds?: string[];
file?: MdtodoFileRecord & { parserMode?: string; valuesRedacted?: boolean };
projection?: ProjectProjectionSummary;
}
export interface ProjectWorkbenchLinkListResponse extends ProjectManagementEnvelope { links?: ProjectWorkbenchLinkRecord[] }
export interface MdtodoTaskQuery {
sourceId?: string | null;
fileRef?: string | null;
projectId?: string | null;
parentTaskRef?: string | null;
status?: string | null;
search?: string | null;
limit?: number | null;
offset?: number | null;
}
export interface ProjectWorkbenchLinkQuery {
taskRef?: string | null;
projectId?: string | null;
sessionId?: string | null;
}
export const projectManagementAPI = {
navigation: (): Promise<ApiResult<ProjectNavigationResponse>> => fetchJson("/v1/project-management/navigation", { timeoutMs: 12000, timeoutName: "project navigation" }),
projects: (): Promise<ApiResult<ProjectListResponse>> => fetchJson("/v1/project-management/projects", { timeoutMs: 12000, timeoutName: "project list" }),
sources: (): Promise<ApiResult<ProjectSourceListResponse>> => fetchJson("/v1/project-management/mdtodo/sources", { timeoutMs: 12000, timeoutName: "project mdtodo sources" }),
createSource: (input: ProjectSourceInput): Promise<ApiResult<ProjectSourceMutationResponse>> => fetchJson("/v1/project-management/mdtodo/sources", { method: "POST", body: JSON.stringify(input), timeoutMs: 12000, timeoutName: "project mdtodo source create" }),
updateSource: (sourceId: string, input: ProjectSourceInput): Promise<ApiResult<ProjectSourceMutationResponse>> => fetchJson(`/v1/project-management/mdtodo/sources/${encodeURIComponent(sourceId)}`, { method: "PATCH", body: JSON.stringify(input), timeoutMs: 12000, timeoutName: "project mdtodo source update" }),
probeSource: (sourceId: string): Promise<ApiResult<ProjectSourceProbeResponse>> => fetchJson(`/v1/project-management/mdtodo/sources/${encodeURIComponent(sourceId)}/probe`, { method: "POST", body: JSON.stringify({}), timeoutMs: 12000, timeoutName: "project mdtodo source probe" }),
reindexSource: (sourceId: string): Promise<ApiResult<ProjectSourceReindexResponse>> => fetchJson(`/v1/project-management/mdtodo/sources/${encodeURIComponent(sourceId)}/reindex`, { method: "POST", body: JSON.stringify({}), timeoutMs: 12000, timeoutName: "project mdtodo source reindex" }),
files: (sourceId?: string | null): Promise<ApiResult<MdtodoFileListResponse>> => fetchJson(`/v1/project-management/mdtodo/files${queryString({ sourceId })}`, { timeoutMs: 12000, timeoutName: "project mdtodo files" }),
tasks: (query: MdtodoTaskQuery = {}): Promise<ApiResult<MdtodoTaskListResponse>> => fetchJson(`/v1/project-management/mdtodo/tasks${queryString({ sourceId: query.sourceId, fileRef: query.fileRef, projectId: query.projectId, parentTaskRef: query.parentTaskRef, status: query.status, search: query.search, limit: query.limit, offset: query.offset })}`, { timeoutMs: 12000, timeoutName: "project mdtodo tasks" }),
taskDetail: (taskRef: string): Promise<ApiResult<MdtodoTaskDetailResponse>> => fetchJson(`/v1/project-management/mdtodo/task-detail${queryString({ taskRef })}`, { timeoutMs: 12000, timeoutName: "project mdtodo task detail" }),
launchContext: (taskRef: string): Promise<ApiResult<MdtodoLaunchContextResponse>> => fetchJson(`/v1/project-management/mdtodo/launch-context${queryString({ taskRef })}`, { timeoutMs: 12000, timeoutName: "project mdtodo launch context" }),
reportPreview: (taskRef: string, linkId: string): Promise<ApiResult<MdtodoReportPreviewResponse>> => fetchJson(`/v1/project-management/mdtodo/report-preview${queryString({ taskRef, linkId })}`, { timeoutMs: 12000, timeoutName: "project mdtodo report preview" }),
updateTask: (taskRef: string, input: MdtodoTaskMutationInput): Promise<ApiResult<MdtodoTaskMutationResponse>> => fetchJson(`/v1/project-management/mdtodo/tasks/${encodeURIComponent(taskRef)}`, { method: "PATCH", body: JSON.stringify(input), timeoutMs: 12000, timeoutName: "project mdtodo task update" }),
createTask: (input: MdtodoTaskMutationInput): Promise<ApiResult<MdtodoTaskMutationResponse>> => fetchJson("/v1/project-management/mdtodo/tasks", { method: "POST", body: JSON.stringify(input), timeoutMs: 12000, timeoutName: "project mdtodo task create" }),
deleteTask: (taskRef: string, input: MdtodoTaskMutationInput): Promise<ApiResult<MdtodoTaskMutationResponse>> => fetchJson(`/v1/project-management/mdtodo/tasks/${encodeURIComponent(taskRef)}`, { method: "DELETE", body: JSON.stringify(input), timeoutMs: 12000, timeoutName: "project mdtodo task delete" }),
workbenchLinks: (query: ProjectWorkbenchLinkQuery = {}): Promise<ApiResult<ProjectWorkbenchLinkListResponse>> => fetchJson(`/v1/project-management/workbench-links${queryString({ taskRef: query.taskRef, projectId: query.projectId, sessionId: query.sessionId })}`, { timeoutMs: 12000, timeoutName: "project workbench links" })
};
function queryString(values: Record<string, string | number | null | undefined>): string {
const params = new URLSearchParams();
for (const [key, value] of Object.entries(values)) {
if (value !== null && value !== undefined && value !== "") params.set(key, String(value));
}
const text = params.toString();
return text ? `?${text}` : "";
}