Plugin Loader: Wait for plugins to register their extensions (#106969)

* fix: mark apps as preloaded after being preloaded

* move marking as preloaded into `preload`

* add tests

* refactor: make it reuse promises of already loaded plugins

* fix: review notes

---------

Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
This commit is contained in:
Sven Grossmann
2025-06-25 08:49:25 +02:00
committed by GitHub
parent 694a58372e
commit 478c1debe0
2 changed files with 290 additions and 12 deletions

View File

@ -17,23 +17,25 @@ export type PluginPreloadResult = {
addedLinkConfigs?: PluginExtensionAddedLinkConfig[];
};
const preloadedAppPlugins = new Set<string>();
const isNotYetPreloaded = ({ id }: AppPluginConfig) => !preloadedAppPlugins.has(id);
const markAsPreloaded = (apps: AppPluginConfig[]) => apps.forEach(({ id }) => preloadedAppPlugins.add(id));
const preloadPromises = new Map<string, Promise<void>>();
export const clearPreloadedPluginsCache = () => {
preloadPromises.clear();
};
export async function preloadPlugins(apps: AppPluginConfig[] = []) {
const appPluginsToPreload = apps.filter(isNotYetPreloaded);
// Create preload promises for each app, reusing existing promises if already loading
const promises = apps.map((app) => {
if (!preloadPromises.has(app.id)) {
preloadPromises.set(app.id, preload(app));
}
return preloadPromises.get(app.id)!;
});
if (appPluginsToPreload.length === 0) {
return;
}
markAsPreloaded(apps);
await Promise.all(appPluginsToPreload.map(preload));
await Promise.all(promises);
}
async function preload(config: AppPluginConfig) {
async function preload(config: AppPluginConfig): Promise<void> {
try {
const meta = await getPluginSettings(config.id, {
showErrorAlert: contextSrv.user.orgRole !== '',