feat(coding): add project identity UX

This commit is contained in:
2026-08-26 18:48:22 +08:00
parent 5ac08d509f
commit ce8e2103d9
10 changed files with 683 additions and 0 deletions

View File

@@ -20,6 +20,7 @@ import type {
CodingProjectSummary,
} from '@/types/coding-project';
import type { ProjectType } from '../../shared/project-config';
import type { ProjectIdentityChoice } from '../../shared/coding-project-contracts';
interface CodingWorkspaceDependencies {
listProjects(): Promise<CodingProjectCatalog>;
@@ -43,6 +44,7 @@ interface CodingWorkspaceDependencies {
parentPath?: string;
projectName?: string;
projectType?: ProjectType;
identity: ProjectIdentityChoice;
}): Promise<{ project: CodingProjectSummary; config: CodingProjectConfig; knowledgeFiles: string[] }>;
setActiveProject(projectId: string): Promise<CodingProjectSummary>;
removeProject(projectId: string): Promise<void>;
@@ -71,6 +73,7 @@ export interface CodingWorkspaceState {
parentPath?: string;
projectName?: string;
projectType?: ProjectType;
identity: ProjectIdentityChoice;
}): Promise<CodingProjectSummary>;
setActiveProject(projectId: string): Promise<CodingProjectSummary>;
removeProject(projectId: string): Promise<void>;

View File

@@ -1,6 +1,11 @@
import { create } from 'zustand';
import { hostApiFetch } from '@/lib/host-api';
import {
makeCodingProjectIndependentCopy,
resolveCodingProjectIdentity,
} from '@/lib/coding-projects';
import type { CodingProjectConfig, CodingProjectConfigSnapshot } from '@/types/coding-project';
import type { ProjectIdentityChoice } from '../../shared/coding-project-contracts';
type ProjectConfigResponse = {
status: 'valid' | 'missing' | 'invalid';
@@ -16,6 +21,8 @@ type ProjectConfigState = {
errorsByProjectId: Record<string, string>;
load: (projectId: string) => Promise<ProjectConfigResponse>;
save: (projectId: string, config: CodingProjectConfig) => Promise<CodingProjectConfig>;
resolveIdentity: (projectId: string, identity: ProjectIdentityChoice) => Promise<CodingProjectConfig>;
makeIndependentCopy: (projectId: string) => Promise<CodingProjectConfig>;
uploadKnowledge: (projectId: string, file: File) => Promise<void>;
remove: (projectId: string) => void;
};
@@ -64,6 +71,26 @@ export const useProjectConfigStore = create<ProjectConfigState>((set) => ({
return response.snapshot.config;
},
async resolveIdentity(projectId, identity) {
const snapshot = await resolveCodingProjectIdentity(projectId, identity);
set((state) => ({
configsByProjectId: { ...state.configsByProjectId, [projectId]: snapshot.config },
knowledgeByProjectId: { ...state.knowledgeByProjectId, [projectId]: snapshot.knowledgeFiles },
errorsByProjectId: Object.fromEntries(Object.entries(state.errorsByProjectId).filter(([id]) => id !== projectId)),
}));
return snapshot.config;
},
async makeIndependentCopy(projectId) {
const snapshot = await makeCodingProjectIndependentCopy(projectId);
set((state) => ({
configsByProjectId: { ...state.configsByProjectId, [projectId]: snapshot.config },
knowledgeByProjectId: { ...state.knowledgeByProjectId, [projectId]: snapshot.knowledgeFiles },
errorsByProjectId: Object.fromEntries(Object.entries(state.errorsByProjectId).filter(([id]) => id !== projectId)),
}));
return snapshot.config;
},
async uploadKnowledge(projectId, file) {
const bytes = new Uint8Array(await file.arrayBuffer());
let binary = '';