feat: Implement comprehensive project management with new API client, backend routes, and frontend pages for projects and settings.
This commit is contained in:
@@ -13,9 +13,15 @@ export interface Project {
|
||||
description: string;
|
||||
status: string;
|
||||
workflow_type: string;
|
||||
project_type: string;
|
||||
test_mode: boolean;
|
||||
install_path?: string;
|
||||
gitea_repo?: string;
|
||||
deployment_target?: string;
|
||||
deploy_server_id?: number;
|
||||
git_server_id?: number;
|
||||
deploy_server_name?: string;
|
||||
git_server_name?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
tasks: Task[];
|
||||
@@ -29,9 +35,13 @@ export interface ProjectSummary {
|
||||
slug: string;
|
||||
status: string;
|
||||
workflow_type: string;
|
||||
project_type: string;
|
||||
test_mode: boolean;
|
||||
install_path?: string;
|
||||
task_count: number;
|
||||
tasks_done: number;
|
||||
deploy_server_name?: string;
|
||||
git_server_name?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
@@ -89,6 +99,7 @@ export interface AgentStatus {
|
||||
export interface WorkflowDef {
|
||||
type: string;
|
||||
label: string;
|
||||
path: string;
|
||||
steps: {
|
||||
agent: string;
|
||||
label: string;
|
||||
@@ -98,6 +109,32 @@ export interface WorkflowDef {
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface ProjectTypeInfo {
|
||||
value: string;
|
||||
emoji: string;
|
||||
label: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export interface DeployServer {
|
||||
id: number;
|
||||
name: string;
|
||||
host: string;
|
||||
user: string;
|
||||
ssh_port: number;
|
||||
description: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface GitServer {
|
||||
id: number;
|
||||
name: string;
|
||||
url: string;
|
||||
org: string;
|
||||
description: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface AppConfig {
|
||||
OPENCLAW_WORKSPACE: string;
|
||||
GITEA_SERVER: string;
|
||||
@@ -127,7 +164,7 @@ async function request<T>(path: string, options?: RequestInit): Promise<T> {
|
||||
return res.json();
|
||||
}
|
||||
|
||||
// ─── Projects ───────────────────────────────────────────────────────────────
|
||||
// ─── API ────────────────────────────────────────────────────────────────────
|
||||
|
||||
export const api = {
|
||||
// Projects
|
||||
@@ -136,7 +173,16 @@ export const api = {
|
||||
return request<ProjectSummary[]>(`/api/projects${qs}`);
|
||||
},
|
||||
getProject: (id: number) => request<Project>(`/api/projects/${id}`),
|
||||
createProject: (data: { name: string; description: string; workflow_type: string; test_mode?: boolean }) =>
|
||||
createProject: (data: {
|
||||
name: string;
|
||||
description: string;
|
||||
workflow_type: string;
|
||||
project_type: string;
|
||||
test_mode?: boolean;
|
||||
install_path?: string;
|
||||
deploy_server_id?: number | null;
|
||||
git_server_id?: number | null;
|
||||
}) =>
|
||||
request<Project>('/api/projects', { method: 'POST', body: JSON.stringify(data) }),
|
||||
startProject: (id: number) => request<{ status: string }>(`/api/projects/${id}/start`, { method: 'POST' }),
|
||||
pauseProject: (id: number) => request<{ status: string }>(`/api/projects/${id}/pause`, { method: 'POST' }),
|
||||
@@ -145,6 +191,9 @@ export const api = {
|
||||
deleteProject: (id: number) => request<{ message: string }>(`/api/projects/${id}`, { method: 'DELETE' }),
|
||||
getProgress: (id: number) => request<{ current_step: number; total_steps: number; percentage: number }>(`/api/projects/${id}/progress`),
|
||||
|
||||
// Project Types
|
||||
listProjectTypes: () => request<ProjectTypeInfo[]>('/api/projects/types'),
|
||||
|
||||
// Agents
|
||||
listAgents: () => request<AgentStatus[]>('/api/agents'),
|
||||
getAgentHistory: (name: string) => request<AgentExecution[]>(`/api/agents/${name}/history`),
|
||||
@@ -163,6 +212,18 @@ export const api = {
|
||||
updateConfig: (data: Record<string, string>) =>
|
||||
request<{ message: string }>('/api/config', { method: 'PUT', body: JSON.stringify(data) }),
|
||||
|
||||
// Deploy Servers
|
||||
listDeployServers: () => request<DeployServer[]>('/api/config/deploy-servers'),
|
||||
createDeployServer: (data: { name: string; host: string; user?: string; password?: string; ssh_port?: number; description?: string }) =>
|
||||
request<DeployServer>('/api/config/deploy-servers', { method: 'POST', body: JSON.stringify(data) }),
|
||||
deleteDeployServer: (id: number) => request<{ message: string }>(`/api/config/deploy-servers/${id}`, { method: 'DELETE' }),
|
||||
|
||||
// Git Servers
|
||||
listGitServers: () => request<GitServer[]>('/api/config/git-servers'),
|
||||
createGitServer: (data: { name: string; url: string; token?: string; org?: string; description?: string }) =>
|
||||
request<GitServer>('/api/config/git-servers', { method: 'POST', body: JSON.stringify(data) }),
|
||||
deleteGitServer: (id: number) => request<{ message: string }>(`/api/config/git-servers/${id}`, { method: 'DELETE' }),
|
||||
|
||||
// Health
|
||||
health: () => request<{ status: string; version: string }>('/api/health'),
|
||||
};
|
||||
|
||||
@@ -14,7 +14,7 @@ type WSCallback = (msg: WSMessage) => void;
|
||||
export function useWebSocket(onMessage: WSCallback) {
|
||||
const wsRef = useRef<WebSocket | null>(null);
|
||||
const [connected, setConnected] = useState(false);
|
||||
const reconnectTimer = useRef<ReturnType<typeof setTimeout>>();
|
||||
const reconnectTimer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
|
||||
|
||||
const connect = useCallback(() => {
|
||||
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
|
||||
Reference in New Issue
Block a user