Files
Agent-System/web/src/api/projectMembers.ts
T
weichenandCursor 17f430b267 fix(web): reuse projectSettingsError envelope across API clients
Prefer error_code when present and route projectMembers/freeformDoc/
taskRuns/chatSessions failures through the shared structured parser.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 03:02:06 +00:00

87 lines
2.6 KiB
TypeScript

import { getBearerAuthHeaders } from './authHeaders';
import { projectSettingsErrorFromResponse } from './projectSettingsError';
export type ApiProjectMemberRole = 'owner' | 'member' | 'viewer';
export type ApiProjectMemberStatus = 'active' | 'exited';
export type ApiDocumentDuty = 'author' | 'reviewer' | 'approver' | '';
export interface ApiProjectMemberRecord {
id?: number;
project_id?: number;
user_id: number;
username?: string;
name?: string;
project_role: ApiProjectMemberRole;
document_duty?: ApiDocumentDuty;
status: ApiProjectMemberStatus;
joined_at?: string;
}
export interface ListProjectMembersResponse {
members: ApiProjectMemberRecord[];
}
export interface UpsertProjectMemberPayload {
user_id: number;
project_role: ApiProjectMemberRole;
document_duty?: ApiDocumentDuty;
status?: ApiProjectMemberStatus;
}
async function memberApiError(res: Response, fallback: string) {
const text = await res.text();
return projectSettingsErrorFromResponse(res.status, text, fallback);
}
export async function listProjectMembers(projectId: number): Promise<ApiProjectMemberRecord[]> {
const res = await fetch(`/api/v1/projects/${projectId}/members`, {
headers: getBearerAuthHeaders(),
});
if (!res.ok) {
throw await memberApiError(res, `获取项目成员失败: ${res.status}`);
}
const data: ListProjectMembersResponse = await res.json();
return data.members ?? [];
}
export async function addProjectMember(
projectId: number,
payload: UpsertProjectMemberPayload
): Promise<void> {
const res = await fetch(`/api/v1/projects/${projectId}/members`, {
method: 'POST',
headers: getBearerAuthHeaders('application/json'),
body: JSON.stringify(payload),
});
if (!res.ok) {
throw await memberApiError(res, `添加项目成员失败: ${res.status}`);
}
}
export async function updateProjectMember(
projectId: number,
payload: UpsertProjectMemberPayload
): Promise<void> {
const res = await fetch(`/api/v1/projects/${projectId}/members`, {
method: 'PUT',
headers: getBearerAuthHeaders('application/json'),
body: JSON.stringify(payload),
});
if (!res.ok) {
throw await memberApiError(res, `更新项目成员失败: ${res.status}`);
}
}
export async function removeProjectMember(projectId: number, userId: number): Promise<void> {
const res = await fetch(
`/api/v1/projects/${projectId}/members?user_id=${encodeURIComponent(String(userId))}`,
{
method: 'DELETE',
headers: getBearerAuthHeaders(),
}
);
if (!res.ok) {
throw await memberApiError(res, `移出项目成员失败: ${res.status}`);
}
}