Files
IdeaSDK/frontend/src/features/templates/useTemplates.ts
Blomios 307ae71857 feat: add main features
Agents for developpement added + frontend add + backend added. Git viewer created + agent and template creator + layout and project creator
2026-06-06 01:27:01 +02:00

150 lines
3.9 KiB
TypeScript

/**
* `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,
};
}