Files
govoplan-projects/webui/src/api/projects.ts
T

108 lines
2.8 KiB
TypeScript

import {
apiFetch,
apiPath,
type ApiSettings
} from "@govoplan/core-webui";
export type ProjectObjectKind = "portfolio" | "project" | "milestone";
export type ProjectSubjectRef = {
kind: string;
id: string;
label?: string | null;
};
export type ProjectRecord = {
tenant_id: string;
object_kind: ProjectObjectKind;
object_id: string;
object_key: string;
revision: number;
title: string;
state: string;
description?: string | null;
visibility: "tenant" | "restricted";
parent_kind?: ProjectObjectKind | null;
parent_id?: string | null;
starts_at?: string | null;
due_at?: string | null;
recorded_at: string;
change_reason: string;
owner?: ProjectSubjectRef | null;
memberships: Array<Record<string, unknown>>;
outcomes: Array<{ key: string; title: string; description?: string | null }>;
benefits: Array<{ key: string; title: string; target?: string | null }>;
dependencies: Array<Record<string, unknown>>;
capacity_assumptions: Array<Record<string, unknown>>;
change_impacts: Array<Record<string, unknown>>;
benefit_reviews: Array<Record<string, unknown>>;
resource_links: Array<Record<string, unknown>>;
external_references: Array<Record<string, unknown>>;
metadata: Record<string, unknown>;
};
export type ProjectListResponse = {
objects: ProjectRecord[];
total: number;
offset: number;
limit: number;
};
export function listProjectObjects(
settings: ApiSettings,
options: {
objectKinds?: ProjectObjectKind[];
states?: string[];
parentKind?: ProjectObjectKind;
parentId?: string;
query?: string;
offset?: number;
limit?: number;
},
signal?: AbortSignal
): Promise<ProjectListResponse> {
return apiFetch(settings, apiPath("/api/v1/projects/objects", {
object_kind: options.objectKinds,
state: options.states,
parent_kind: options.parentKind,
parent_id: options.parentId,
query: options.query,
offset: options.offset,
limit: options.limit
}), { signal });
}
export function createProjectObject(
settings: ApiSettings,
record: ProjectRecord,
idempotencyKey: string
): Promise<ProjectRecord> {
return apiFetch(settings, "/api/v1/projects/objects", {
method: "POST",
body: JSON.stringify({ record, idempotency_key: idempotencyKey })
});
}
export function updateProjectObject(
settings: ApiSettings,
record: ProjectRecord,
changes: Record<string, unknown>,
changeReason: string
): Promise<ProjectRecord> {
return apiFetch(
settings,
`/api/v1/projects/objects/${encodeURIComponent(record.object_kind)}/${encodeURIComponent(record.object_id)}`,
{
method: "PATCH",
body: JSON.stringify({
expected_revision: record.revision,
recorded_at: new Date().toISOString(),
change_reason: changeReason,
idempotency_key: crypto.randomUUID(),
changes
})
}
);
}