feat: add main features
Agents for developpement added + frontend add + backend added. Git viewer created + agent and template creator + layout and project creator
This commit is contained in:
149
frontend/src/features/templates/useTemplates.ts
Normal file
149
frontend/src/features/templates/useTemplates.ts
Normal file
@ -0,0 +1,149 @@
|
||||
/**
|
||||
* `useTemplates` — view-model hook for the templates feature (L7).
|
||||
*
|
||||
* Owns the templates list and CRUD actions. Consumes {@link TemplateGateway}
|
||||
* exclusively; never touches `invoke()` or `@tauri-apps/api`, keeping the
|
||||
* component layer testable with mock gateways (ARCHITECTURE §1.3).
|
||||
*/
|
||||
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
import type { GatewayError, Template } from "@/domain";
|
||||
import type { CreateTemplateInput } from "@/ports";
|
||||
import { useGateways } from "@/app/di";
|
||||
|
||||
/** What the templates UI needs from this hook. */
|
||||
export interface TemplatesViewModel {
|
||||
/** All templates. */
|
||||
templates: Template[];
|
||||
/** Last error message, or `null`. */
|
||||
error: string | null;
|
||||
/** Whether a request is in flight. */
|
||||
busy: boolean;
|
||||
/** Reloads the template list. */
|
||||
refresh: () => Promise<void>;
|
||||
/** Creates a new template and refreshes the list. */
|
||||
createTemplate: (input: CreateTemplateInput) => Promise<void>;
|
||||
/** Updates the content of an existing template. */
|
||||
updateTemplate: (templateId: string, content: string) => Promise<void>;
|
||||
/** Deletes a template by id. */
|
||||
deleteTemplate: (templateId: string) => Promise<void>;
|
||||
/** Creates an agent from a template in the given project. */
|
||||
createAgentFromTemplate: (
|
||||
projectId: string,
|
||||
templateId: string,
|
||||
opts?: { name?: string; synchronized?: boolean },
|
||||
) => Promise<void>;
|
||||
}
|
||||
|
||||
function describe(e: unknown): string {
|
||||
if (e && typeof e === "object" && "message" in e) {
|
||||
return String((e as GatewayError).message);
|
||||
}
|
||||
return String(e);
|
||||
}
|
||||
|
||||
export function useTemplates(): TemplatesViewModel {
|
||||
const { template } = useGateways();
|
||||
|
||||
const [templates, setTemplates] = useState<Template[]>([]);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [busy, setBusy] = useState(false);
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
setBusy(true);
|
||||
setError(null);
|
||||
try {
|
||||
const list = await template.listTemplates();
|
||||
setTemplates(list);
|
||||
} catch (e) {
|
||||
setError(describe(e));
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
}, [template]);
|
||||
|
||||
useEffect(() => {
|
||||
void refresh();
|
||||
}, [refresh]);
|
||||
|
||||
const createTemplate = useCallback(
|
||||
async (input: CreateTemplateInput) => {
|
||||
setBusy(true);
|
||||
setError(null);
|
||||
try {
|
||||
const created = await template.createTemplate(input);
|
||||
setTemplates((prev) => [...prev, created]);
|
||||
} catch (e) {
|
||||
setError(describe(e));
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
},
|
||||
[template],
|
||||
);
|
||||
|
||||
const updateTemplate = useCallback(
|
||||
async (templateId: string, content: string) => {
|
||||
setBusy(true);
|
||||
setError(null);
|
||||
try {
|
||||
const updated = await template.updateTemplate(templateId, content);
|
||||
setTemplates((prev) =>
|
||||
prev.map((t) => (t.id === templateId ? updated : t)),
|
||||
);
|
||||
} catch (e) {
|
||||
setError(describe(e));
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
},
|
||||
[template],
|
||||
);
|
||||
|
||||
const deleteTemplate = useCallback(
|
||||
async (templateId: string) => {
|
||||
setBusy(true);
|
||||
setError(null);
|
||||
try {
|
||||
await template.deleteTemplate(templateId);
|
||||
setTemplates((prev) => prev.filter((t) => t.id !== templateId));
|
||||
} catch (e) {
|
||||
setError(describe(e));
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
},
|
||||
[template],
|
||||
);
|
||||
|
||||
const createAgentFromTemplate = useCallback(
|
||||
async (
|
||||
projectId: string,
|
||||
templateId: string,
|
||||
opts?: { name?: string; synchronized?: boolean },
|
||||
) => {
|
||||
setBusy(true);
|
||||
setError(null);
|
||||
try {
|
||||
await template.createAgentFromTemplate(projectId, templateId, opts);
|
||||
} catch (e) {
|
||||
setError(describe(e));
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
},
|
||||
[template],
|
||||
);
|
||||
|
||||
return {
|
||||
templates,
|
||||
error,
|
||||
busy,
|
||||
refresh,
|
||||
createTemplate,
|
||||
updateTemplate,
|
||||
deleteTemplate,
|
||||
createAgentFromTemplate,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user