Yuki Takei 2 лет назад
Родитель
Сommit
5711007318

+ 7 - 2
apps/app/src/features/growi-plugin/interfaces/growi-plugin.ts

@@ -1,4 +1,5 @@
-import { GrowiPluginType, GrowiThemeMetadata, HasObjectId } from '@growi/core';
+import type { GrowiPluginType, GrowiThemeMetadata, HasObjectId } from '@growi/core';
+import type { TemplateSummary } from '@growi/pluginkit/dist/v4';
 
 export type IGrowiPluginOrigin = {
   url: string,
@@ -22,7 +23,11 @@ export type IGrowiPluginMeta = {
 }
 
 export type IGrowiThemePluginMeta = IGrowiPluginMeta & {
-  themes: GrowiThemeMetadata[]
+  themes: GrowiThemeMetadata[],
+}
+
+export type IGrowiTemplatePluginMeta = IGrowiPluginMeta & {
+  templateSummaries: TemplateSummary[],
 }
 
 export type IGrowiPluginHasId = IGrowiPlugin & HasObjectId;

+ 5 - 18
apps/app/src/features/growi-plugin/server/models/growi-plugin.ts

@@ -1,4 +1,4 @@
-import { GrowiPluginType, GrowiThemeMetadata, GrowiThemeSchemeType } from '@growi/core';
+import { GrowiPluginType } from '@growi/core';
 import {
   Schema, type Model, type Document, type Types,
 } from 'mongoose';
@@ -6,7 +6,7 @@ import {
 import { getOrCreateModel } from '~/server/util/mongoose-utils';
 
 import type {
-  IGrowiPlugin, IGrowiPluginMeta, IGrowiPluginOrigin, IGrowiThemePluginMeta,
+  IGrowiPlugin, IGrowiPluginMeta, IGrowiPluginOrigin, IGrowiTemplatePluginMeta, IGrowiThemePluginMeta,
 } from '../../interfaces';
 
 export interface IGrowiPluginDocument extends IGrowiPlugin, Document {
@@ -18,21 +18,7 @@ export interface IGrowiPluginModel extends Model<IGrowiPluginDocument> {
   deactivatePlugin(id: Types.ObjectId): Promise<string>
 }
 
-const growiThemeMetadataSchema = new Schema<GrowiThemeMetadata>({
-  name: { type: String, required: true },
-  manifestKey: { type: String, required: true },
-  schemeType: {
-    type: String,
-    enum: GrowiThemeSchemeType,
-    require: true,
-  },
-  bg: { type: String, required: true },
-  topbar: { type: String, required: true },
-  sidebar: { type: String, required: true },
-  accent: { type: String, required: true },
-});
-
-const growiPluginMetaSchema = new Schema<IGrowiPluginMeta|IGrowiThemePluginMeta>({
+const growiPluginMetaSchema = new Schema<IGrowiPluginMeta & IGrowiThemePluginMeta & IGrowiTemplatePluginMeta>({
   name: { type: String, required: true },
   types: {
     type: [String],
@@ -41,7 +27,8 @@ const growiPluginMetaSchema = new Schema<IGrowiPluginMeta|IGrowiThemePluginMeta>
   },
   desc: { type: String },
   author: { type: String },
-  themes: [growiThemeMetadataSchema],
+  themes: [Map],
+  templateSummaries: [Map],
 });
 
 const growiPluginOriginSchema = new Schema<IGrowiPluginOrigin>({

+ 11 - 0
apps/app/src/features/growi-plugin/server/services/growi-plugin/generate-template-plugin-meta.ts

@@ -0,0 +1,11 @@
+import type { GrowiPluginValidationData } from '@growi/pluginkit';
+import { scanAllTemplates } from '@growi/pluginkit/dist/v4/server';
+
+import type { IGrowiPlugin, IGrowiTemplatePluginMeta } from '../../../interfaces';
+
+export const generateTemplatePluginMeta = async(plugin: IGrowiPlugin, validationData: GrowiPluginValidationData): Promise<IGrowiTemplatePluginMeta> => {
+  return {
+    ...plugin.meta,
+    templateSummaries: await scanAllTemplates(validationData.projectDirRoot),
+  };
+};

+ 12 - 0
apps/app/src/features/growi-plugin/server/services/growi-plugin/generate-theme-plugin-meta.ts

@@ -0,0 +1,12 @@
+import type { GrowiPluginValidationData } from '@growi/pluginkit';
+
+import type { IGrowiPlugin, IGrowiThemePluginMeta } from '../../../interfaces';
+
+export const generateThemePluginMeta = async(plugin: IGrowiPlugin, validationData: GrowiPluginValidationData): Promise<IGrowiThemePluginMeta> => {
+  // TODO: validate as a theme plugin
+
+  return {
+    ...plugin.meta,
+    themes: validationData.growiPlugin.themes,
+  };
+};

+ 27 - 12
apps/app/src/features/growi-plugin/server/services/growi-plugin.ts → apps/app/src/features/growi-plugin/server/services/growi-plugin/growi-plugin.ts

@@ -15,9 +15,12 @@ import { resolveFromRoot } from '~/utils/project-dir-utils';
 
 import type {
   IGrowiPlugin, IGrowiPluginOrigin, IGrowiThemePluginMeta, IGrowiPluginMeta,
-} from '../../interfaces';
-import { GrowiPlugin } from '../models';
-import { GitHubUrl } from '../models/vo/github-url';
+} from '../../../interfaces';
+import { GrowiPlugin } from '../../models';
+import { GitHubUrl } from '../../models/vo/github-url';
+
+import { generateTemplatePluginMeta } from './generate-template-plugin-meta';
+import { generateThemePluginMeta } from './generate-theme-plugin-meta';
 
 const logger = loggerFactory('growi:plugins:plugin-utils');
 
@@ -27,8 +30,13 @@ const PLUGINS_STATIC_DIR = '/static/plugins'; // configured by express.static
 
 export type GrowiPluginResourceEntries = [installedPath: string, href: string][];
 
-function retrievePluginManifest(growiPlugin: IGrowiPlugin): ViteManifest {
+function retrievePluginManifest(growiPlugin: IGrowiPlugin): ViteManifest | undefined {
   const manifestPath = resolveFromRoot(path.join('tmp/plugins', growiPlugin.installedPath, 'dist/manifest.json'));
+
+  if (!fs.existsSync(manifestPath)) {
+    return;
+  }
+
   const manifestStr: string = readFileSync(manifestPath, 'utf-8');
   return JSON.parse(manifestStr);
 }
@@ -221,11 +229,11 @@ export class GrowiPluginService implements IGrowiPluginService {
     const packageRootPath = opts?.packageRootPath ?? path.resolve(pluginStoringPath, ghOrganizationName, ghReposName);
 
     // validate
-    const data = await validateGrowiDirective(packageRootPath);
+    const validationData = await validateGrowiDirective(packageRootPath);
 
     const packageData = opts?.parentPackageData ?? importPackageJson(packageRootPath);
 
-    const { growiPlugin } = data;
+    const { growiPlugin } = validationData;
     const {
       name: packageName, description: packageDesc, author: packageAuthor,
     } = packageData;
@@ -243,7 +251,7 @@ export class GrowiPluginService implements IGrowiPluginService {
       return plugins.flat();
     }
 
-    const plugin = {
+    const plugin: IGrowiPlugin = {
       isEnabled: true,
       installedPath: `${ghOrganizationName}/${ghReposName}`,
       organizationName: ghOrganizationName,
@@ -258,10 +266,11 @@ export class GrowiPluginService implements IGrowiPluginService {
 
     // add theme metadata
     if (growiPlugin.types.includes(GrowiPluginType.Theme)) {
-      (plugin as IGrowiPlugin<IGrowiThemePluginMeta>).meta = {
-        ...plugin.meta,
-        themes: growiPlugin.themes,
-      };
+      plugin.meta = await generateThemePluginMeta(plugin, validationData);
+    }
+    // add template metadata
+    if (growiPlugin.types.includes(GrowiPluginType.Template)) {
+      plugin.meta = await generateTemplatePluginMeta(plugin, validationData);
     }
 
     logger.info('Plugin detected => ', plugin);
@@ -338,7 +347,9 @@ export class GrowiPluginService implements IGrowiPluginService {
     let themeHref;
     try {
       const manifest = retrievePluginManifest(matchedPlugin);
-      themeHref = `${PLUGINS_STATIC_DIR}/${matchedPlugin.installedPath}/dist/${manifest[matchedThemeMetadata.manifestKey].file}`;
+      if (manifest != null) {
+        themeHref = `${PLUGINS_STATIC_DIR}/${matchedPlugin.installedPath}/dist/${manifest[matchedThemeMetadata.manifestKey].file}`;
+      }
     }
     catch (e) {
       logger.error(`Could not read manifest file for the theme '${theme}'`, e);
@@ -359,6 +370,10 @@ export class GrowiPluginService implements IGrowiPluginService {
           const { types } = growiPlugin.meta;
           const manifest = await retrievePluginManifest(growiPlugin);
 
+          if (manifest == null) {
+            return;
+          }
+
           // add script
           if (types.includes(GrowiPluginType.Script)) {
             const href = `${PLUGINS_STATIC_DIR}/${growiPlugin.installedPath}/dist/${manifest['client-entry.tsx'].file}`;

+ 1 - 0
apps/app/src/features/growi-plugin/server/services/growi-plugin/index.ts

@@ -0,0 +1 @@
+export * from './growi-plugin';