auto-sync: 2026-05-17 06:14:58
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
// 自定义 hooks
|
||||
|
||||
import { useState, useEffect, useCallback, useRef } from 'react';
|
||||
import * as api from '../api';
|
||||
import type { Task, Project, DaemonStatus } from '../types';
|
||||
|
||||
export function useProjects() {
|
||||
const [projects, setProjects] = useState<Project[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const data = await api.listProjects();
|
||||
setProjects(data);
|
||||
setError(null);
|
||||
} catch (e) {
|
||||
setError(String(e));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => { refresh(); }, [refresh]);
|
||||
return { projects, loading, error, refresh };
|
||||
}
|
||||
|
||||
export function useTasks(projectId: string | null) {
|
||||
const [tasks, setTasks] = useState<Task[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
if (!projectId) return;
|
||||
try {
|
||||
setLoading(true);
|
||||
const data = await api.listTasks(projectId);
|
||||
setTasks(data);
|
||||
setError(null);
|
||||
} catch (e) {
|
||||
setError(String(e));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [projectId]);
|
||||
|
||||
useEffect(() => { refresh(); }, [refresh]);
|
||||
return { tasks, loading, error, refresh };
|
||||
}
|
||||
|
||||
export function useDaemonStatus() {
|
||||
const [status, setStatus] = useState<DaemonStatus | null>(null);
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
try {
|
||||
const data = await api.getDaemonStatus();
|
||||
setStatus(data);
|
||||
} catch {
|
||||
// Daemon may not be running
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
refresh();
|
||||
const interval = setInterval(refresh, 10000);
|
||||
return () => clearInterval(interval);
|
||||
}, [refresh]);
|
||||
|
||||
return { status, refresh };
|
||||
}
|
||||
|
||||
export function useSSE(onEvent: (data: unknown) => void) {
|
||||
const esRef = useRef<EventSource | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
esRef.current = api.createEventSource(onEvent, () => {
|
||||
// Auto-reconnect is handled by EventSource
|
||||
});
|
||||
return () => {
|
||||
esRef.current?.close();
|
||||
};
|
||||
}, [onEvent]);
|
||||
}
|
||||
Reference in New Issue
Block a user