diff --git a/package.json b/package.json index e85cd73760..e87e3ca644 100644 --- a/package.json +++ b/package.json @@ -199,6 +199,7 @@ "electron-updater": "^4.6.0", "electron-window-state": "^5.0.3", "fs-extra": "^9.0.1", + "glob": "^7.2.0", "glob-to-regexp": "^0.4.1", "got": "^11.8.2", "grapheme-splitter": "^1.0.4", diff --git a/src/renderer/components/dock/create-resource.store.ts b/src/renderer/components/dock/create-resource.store.ts index 715668389f..8ecc66ea60 100644 --- a/src/renderer/components/dock/create-resource.store.ts +++ b/src/renderer/components/dock/create-resource.store.ts @@ -20,8 +20,10 @@ */ import fs from "fs-extra"; +import glob from "glob"; import path from "path"; import os from "os"; +import { promisify } from "util"; import { action, makeObservable, observable } from "mobx"; import logger from "../../../common/logger"; import { DockTabStore } from "./dock-tab.store"; @@ -30,7 +32,7 @@ import { dockStore, DockTabCreateSpecific, TabKind } from "./dock.store"; export interface TemplatesGroup { label: string; templates: { - [filename: string]: string; + [filepath: string]: string; // filepath is relative to templates folder }; } @@ -76,10 +78,10 @@ export class CreateResourceStore extends DockTabStore { if (!templatesGroup) return; // exit: unknown templates source folder await fs.ensureDir(sourceFolder); - const fileNames = await fs.readdir(sourceFolder); + const files = await promisify(glob)("**/*.@(yaml|yml|json)", { cwd: sourceFolder }); templatesGroup.templates = Object.fromEntries( - fileNames.map(fileName => [fileName, "" /* empty: content not loaded yet */]) + files.map(filePath => [filePath, "" /* empty: content not loaded yet */]) ); } catch (error) { logger.error(`[CREATE-RESOURCE]: scanning template folders error: ${error}`); @@ -87,8 +89,8 @@ export class CreateResourceStore extends DockTabStore { } @action - async loadTemplate(init: { fileName: string, sourceFolder: string }): Promise { - const { fileName, sourceFolder } = init; + async loadTemplate(init: { filePath: string, sourceFolder: string }): Promise { + const { filePath, sourceFolder } = init; const templatesGroup = this.templateGroups[sourceFolder]; @@ -96,23 +98,23 @@ export class CreateResourceStore extends DockTabStore { return ""; // unknown group, exit } - const template = templatesGroup.templates[fileName]; + const template = templatesGroup.templates[filePath]; if (template) return template; // return cache, preloaded already try { - const templatePath = path.resolve(sourceFolder, fileName); + const templatePath = path.resolve(sourceFolder, filePath); const pathExists = await fs.pathExists(templatePath); if (!pathExists) return ""; // template file not exists, skip const textContent = await fs.readFile(templatePath, { encoding: "utf-8" }); - templatesGroup.templates[fileName] = textContent; // save cache + templatesGroup.templates[filePath] = textContent; // save cache return textContent; } catch (error) { - logger.error(`[CREATE-RESOURCE]: reading "${sourceFolder}/${fileName}" has failed: ${error}`); + logger.error(`[CREATE-RESOURCE]: reading "${sourceFolder}/${filePath}" has failed: ${error}`); } return ""; diff --git a/src/renderer/components/dock/create-resource.tsx b/src/renderer/components/dock/create-resource.tsx index c8902c4d2b..1c49081ada 100644 --- a/src/renderer/components/dock/create-resource.tsx +++ b/src/renderer/components/dock/create-resource.tsx @@ -39,7 +39,7 @@ type SelectOptionTemplate = SelectOption; interface SelectOptionTemplateValue { sourceFolder: string; - fileName: string; + filePath: string; // relative to `sourceFolder` content?: string; // available after loading (template selection) } @@ -113,10 +113,10 @@ export class CreateResourceInfoPanel extends React.Component { return Object.entries(createResourceStore.templateGroups).map(([sourceFolder, group]) => { return { label: group.label, - options: Object.entries(group.templates).map(([fileName]) => { + options: Object.entries(group.templates).map(([filePath]) => { return { - label: fileName, - value: { fileName, sourceFolder }, + label: filePath, + value: { filePath, sourceFolder }, }; }), }; @@ -124,8 +124,8 @@ export class CreateResourceInfoPanel extends React.Component { } onSelectTemplate = async ({ value }: SelectOptionTemplate) => { - const { fileName, sourceFolder, content } = value; - const templateContent = content ?? await createResourceStore.loadTemplate({ fileName, sourceFolder }); + const { filePath, sourceFolder, content } = value; + const templateContent = content ?? await createResourceStore.loadTemplate({ filePath, sourceFolder }); createResourceStore.setData(this.tabId, templateContent); // update draft };