community templates (#691)
This commit is contained in:
@@ -5,7 +5,7 @@ import http from "isomorphic-git/http/node";
|
||||
import { app } from "electron";
|
||||
import { copyDirectoryRecursive } from "../utils/file_utils";
|
||||
import { readSettings } from "@/main/settings";
|
||||
import { DEFAULT_TEMPLATE_ID, getTemplateOrThrow } from "@/shared/templates";
|
||||
import { getTemplateOrThrow } from "../utils/template_utils";
|
||||
import log from "electron-log";
|
||||
|
||||
const logger = log.scope("createFromTemplate");
|
||||
@@ -16,7 +16,7 @@ export async function createFromTemplate({
|
||||
fullAppPath: string;
|
||||
}) {
|
||||
const settings = readSettings();
|
||||
const templateId = settings.selectedTemplateId ?? DEFAULT_TEMPLATE_ID;
|
||||
const templateId = settings.selectedTemplateId;
|
||||
|
||||
if (templateId === "react") {
|
||||
await copyDirectoryRecursive(
|
||||
@@ -26,7 +26,7 @@ export async function createFromTemplate({
|
||||
return;
|
||||
}
|
||||
|
||||
const template = getTemplateOrThrow(templateId);
|
||||
const template = await getTemplateOrThrow(templateId);
|
||||
if (!template.githubUrl) {
|
||||
throw new Error(`Template ${templateId} has no GitHub URL`);
|
||||
}
|
||||
|
||||
19
src/ipc/handlers/template_handlers.ts
Normal file
19
src/ipc/handlers/template_handlers.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { createLoggedHandler } from "./safe_handle";
|
||||
import log from "electron-log";
|
||||
import { getAllTemplates } from "../utils/template_utils";
|
||||
import { localTemplatesData, type Template } from "../../shared/templates";
|
||||
|
||||
const logger = log.scope("template_handlers");
|
||||
const handle = createLoggedHandler(logger);
|
||||
|
||||
export function registerTemplateHandlers() {
|
||||
handle("get-templates", async (): Promise<Template[]> => {
|
||||
try {
|
||||
const templates = await getAllTemplates();
|
||||
return templates;
|
||||
} catch (error) {
|
||||
logger.error("Error fetching templates:", error);
|
||||
return localTemplatesData;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -52,6 +52,7 @@ import type {
|
||||
UpdateChatParams,
|
||||
FileAttachment,
|
||||
} from "./ipc_types";
|
||||
import type { Template } from "../shared/templates";
|
||||
import type { AppChatContext, ProposalResult } from "@/lib/schemas";
|
||||
import { showError } from "@/lib/toast";
|
||||
|
||||
@@ -1024,4 +1025,9 @@ export class IpcClient {
|
||||
}): Promise<ProblemReport> {
|
||||
return this.ipcRenderer.invoke("check-problems", params);
|
||||
}
|
||||
|
||||
// Template methods
|
||||
public async getTemplates(): Promise<Template[]> {
|
||||
return this.ipcRenderer.invoke("get-templates");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import { registerAppUpgradeHandlers } from "./handlers/app_upgrade_handlers";
|
||||
import { registerCapacitorHandlers } from "./handlers/capacitor_handlers";
|
||||
import { registerProblemsHandlers } from "./handlers/problems_handlers";
|
||||
import { registerAppEnvVarsHandlers } from "./handlers/app_env_vars_handlers";
|
||||
import { registerTemplateHandlers } from "./handlers/template_handlers";
|
||||
|
||||
export function registerIpcHandlers() {
|
||||
// Register all IPC handlers by category
|
||||
@@ -55,4 +56,5 @@ export function registerIpcHandlers() {
|
||||
registerAppUpgradeHandlers();
|
||||
registerCapacitorHandlers();
|
||||
registerAppEnvVarsHandlers();
|
||||
registerTemplateHandlers();
|
||||
}
|
||||
|
||||
82
src/ipc/utils/template_utils.ts
Normal file
82
src/ipc/utils/template_utils.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import {
|
||||
type Template,
|
||||
type ApiTemplate,
|
||||
localTemplatesData,
|
||||
} from "../../shared/templates";
|
||||
import log from "electron-log";
|
||||
|
||||
const logger = log.scope("template_utils");
|
||||
|
||||
// In-memory cache for API templates
|
||||
let apiTemplatesCache: Template[] | null = null;
|
||||
let apiTemplatesFetchPromise: Promise<Template[]> | null = null;
|
||||
|
||||
// Convert API template to our Template interface
|
||||
function convertApiTemplate(apiTemplate: ApiTemplate): Template {
|
||||
return {
|
||||
id: `${apiTemplate.githubOrg}/${apiTemplate.githubRepo}`,
|
||||
title: apiTemplate.title,
|
||||
description: apiTemplate.description,
|
||||
imageUrl: apiTemplate.imageUrl,
|
||||
githubUrl: `https://github.com/${apiTemplate.githubOrg}/${apiTemplate.githubRepo}`,
|
||||
isOfficial: false,
|
||||
};
|
||||
}
|
||||
|
||||
// Fetch templates from API with caching
|
||||
export async function fetchApiTemplates(): Promise<Template[]> {
|
||||
// Return cached data if available
|
||||
if (apiTemplatesCache) {
|
||||
return apiTemplatesCache;
|
||||
}
|
||||
|
||||
// Return existing promise if fetch is already in progress
|
||||
if (apiTemplatesFetchPromise) {
|
||||
return apiTemplatesFetchPromise;
|
||||
}
|
||||
|
||||
// Start new fetch
|
||||
apiTemplatesFetchPromise = (async (): Promise<Template[]> => {
|
||||
try {
|
||||
const response = await fetch("https://api.dyad.sh/v1/templates");
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Failed to fetch templates: ${response.status} ${response.statusText}`,
|
||||
);
|
||||
}
|
||||
|
||||
const apiTemplates: ApiTemplate[] = await response.json();
|
||||
const convertedTemplates = apiTemplates.map(convertApiTemplate);
|
||||
|
||||
// Cache the result
|
||||
apiTemplatesCache = convertedTemplates;
|
||||
return convertedTemplates;
|
||||
} catch (error) {
|
||||
logger.error("Failed to fetch API templates:", error);
|
||||
// Reset the promise so we can retry later
|
||||
apiTemplatesFetchPromise = null;
|
||||
return []; // Return empty array on error
|
||||
}
|
||||
})();
|
||||
|
||||
return apiTemplatesFetchPromise;
|
||||
}
|
||||
|
||||
// Get all templates (local + API)
|
||||
export async function getAllTemplates(): Promise<Template[]> {
|
||||
const apiTemplates = await fetchApiTemplates();
|
||||
return [...localTemplatesData, ...apiTemplates];
|
||||
}
|
||||
|
||||
export async function getTemplateOrThrow(
|
||||
templateId: string,
|
||||
): Promise<Template> {
|
||||
const allTemplates = await getAllTemplates();
|
||||
const template = allTemplates.find((template) => template.id === templateId);
|
||||
if (!template) {
|
||||
throw new Error(
|
||||
`Template ${templateId} not found. Please select a different template.`,
|
||||
);
|
||||
}
|
||||
return template;
|
||||
}
|
||||
Reference in New Issue
Block a user