From d3b286083df2419d0ab869af14daca9b175396cc Mon Sep 17 00:00:00 2001 From: Matthew Runyon Date: Thu, 19 Oct 2023 18:11:10 -0500 Subject: [PATCH] feat: Composite plugin loading --- .../src/components/PluginsBootstrap.tsx | 14 +++++++++++- .../app-utils/src/plugins/PluginUtils.tsx | 22 +++++++++++++------ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/packages/app-utils/src/components/PluginsBootstrap.tsx b/packages/app-utils/src/components/PluginsBootstrap.tsx index 5fdea74c82..2e02e2ffc1 100644 --- a/packages/app-utils/src/components/PluginsBootstrap.tsx +++ b/packages/app-utils/src/components/PluginsBootstrap.tsx @@ -1,7 +1,10 @@ import { type Plugin } from '@deephaven/plugin'; import React, { createContext, useEffect, useState } from 'react'; +import Log from '@deephaven/log'; import { PluginModuleMap, loadModulePlugins } from '../plugins'; +const log = Log.module('PluginsBootstrap'); + export const PluginsContext = createContext(null); export type PluginsBootstrapProps = { @@ -39,7 +42,16 @@ export function PluginsBootstrap({ const corePluginPairs = corePlugins.map( plugin => [plugin.name, plugin] as const ); - setPlugins(new Map([...corePluginPairs, ...pluginModules])); + const newPlugins: PluginModuleMap = new Map(); + [...corePluginPairs, ...pluginModules].forEach(([name, plugin]) => { + if (newPlugins.has(name)) { + log.warn( + `Plugin with name '${name}' already exists. Overriding existing with ${plugin}` + ); + } + newPlugins.set(name, plugin); + }); + setPlugins(newPlugins); } } loadPlugins(); diff --git a/packages/app-utils/src/plugins/PluginUtils.tsx b/packages/app-utils/src/plugins/PluginUtils.tsx index 8fbbfe0afa..f281be72f8 100644 --- a/packages/app-utils/src/plugins/PluginUtils.tsx +++ b/packages/app-utils/src/plugins/PluginUtils.tsx @@ -64,7 +64,7 @@ export async function loadJson(jsonUrl: string): Promise { */ export async function loadModulePlugins( modulePluginsUrl: string -): Promise { +): Promise<[string, PluginModule][]> { log.debug('Loading plugins...'); try { const manifest = await loadJson(`${modulePluginsUrl}/manifest.json`); @@ -74,7 +74,9 @@ export async function loadModulePlugins( } log.debug('Plugin manifest loaded:', manifest); - const pluginPromises: Promise[] = []; + const pluginPromises: Promise< + LegacyPlugin | { default: Plugin | Plugin[] } + >[] = []; for (let i = 0; i < manifest.plugins.length; i += 1) { const { name, main } = manifest.plugins[i]; const pluginMainUrl = `${modulePluginsUrl}/${name}/${main}`; @@ -83,7 +85,7 @@ export async function loadModulePlugins( const pluginModules = await Promise.allSettled(pluginPromises); - const pluginMap: PluginModuleMap = new Map(); + const plugins: [string, PluginModule][] = []; for (let i = 0; i < pluginModules.length; i += 1) { const module = pluginModules[i]; const { name } = manifest.plugins[i]; @@ -98,19 +100,25 @@ export async function loadModulePlugins( if (moduleValue == null) { log.error(`Plugin '${name}' is missing an exported value.`); + } else if (Array.isArray(moduleValue)) { + moduleValue.forEach(plugin => { + plugins.push([plugin.name, plugin]); + }); + } else if (isLegacyPlugin(moduleValue)) { + plugins.push([name, moduleValue]); } else { - pluginMap.set(name, moduleValue); + plugins.push([moduleValue.name, moduleValue]); } } else { log.error(`Unable to load plugin '${name}'`, module.reason); } } - log.info('Plugins loaded:', pluginMap); + log.info('Plugins loaded:', plugins); - return pluginMap; + return plugins; } catch (e) { log.error('Unable to load plugins:', e); - return new Map(); + return []; } }