jack zhang 61e9dd5cc1
feat: plugin mobile v2 (#4777)
* feat: init

* fix: mobile layout

* feat: more code

* feat: improve navigate bar

* fix: mobile title

* feat: improve code

* fix: add settings and initailzer

* fix: settings

* fix: tabbar items settings

* feat: tabbar initializer

* fix: api

* fix: styles

* feat: navbar

* feat: navigate bar tabs initializer

* feat: navigate bar tab settings

* feat: navigation bar actions

* fix: bug

* fix: bug

* fix: bug

* fix: tabbar active

* fix: bug

* fix: mobile login and layout

* fix: update version

* fix: build error

* feat: plugin settings support link

* fix: add mobile meta

* fix: desktop mode

* fix: remove old code and change collection name and mobile path

* fix: tabbar and tabs initialer layout

* fix: initializer style

* fix: adjust schema position

* fix: mobile style

* fix: delete relation resource and home page bug

* fix: support multi app

* fix: not found page

* fix: js bridge

* fix: bug

* fix: navigation bar schema flat

* fix: navigation bar action style

* fix: change version

* fix: mobile meta and real mobile test

* refactor: folder and name

* fix: navigation bar sticky and zIndex

* fix: full mobile schema

* fix: mobile readme and package.json

* fix: e2e bug

* fix: bug

* fix: tabbar style on productino

* fix: bug

* fix: rename MobileTabBar.Page

* fix: support tabbar sort

* fix: support  page tabs sort

* fix: i18n

* fix: settings utils import bug

* docs: api doc

* fix: qrcode refresh

* test: unit tests

* fix: bug

* fix: unit test

* fix: build bug

* fix: e2e test

* fix: overflow scroll

* fix: bug

* fix: scroll and overflow

* fix: bug

* fix: e2e expect await

* fix: e2e bug

* fix: bug

* fix: change name

* fix: add more e2e

* fix: page header

* fix: tab support icon

* fix: bug

* fix: bug

* fix: docs

* fix(T-4811): scroll bar too long

* fix(T-4810): desktop mode

* fix: e2e

* fix(T-4812): title empty

* fix: unit test

* feat: hide Open mode option in mobile mode

* feat: change default value of Open mode on mobile

* feat: add OpenModeProvider

* feat: support page mode

* fix: fix build

* test: update unit tests

* chore: remove pro-plugins

* fix: bug

* fix(T-4812): title is required

* fix: bug

* fix: bug

* fix: bug

* fix: bug

* refactor: remove z-index

* refactor: make better for subpages

* fix: drag bug

* fix: bug

* fix: theme bug

* fix(T-4859): create tab bar title empty

* fix(T-4857): action too long

* fix: e2e bug

* fix: remove comment

* fix: bug

* fix: theme bug

* fix: should provider modal component

* fix: bug

---------

Co-authored-by: chenos <chenlinxh@gmail.com>
Co-authored-by: Zeke Zhang <958414905@qq.com>
2024-07-22 14:06:36 +08:00

114 lines
3.2 KiB
TypeScript

/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import type { Application } from './Application';
import type { Plugin } from './Plugin';
import { getPlugins } from './utils/remotePlugins';
export type PluginOptions<T = any> = { name?: string; packageName?: string; config?: T };
export type PluginType<Opts = any> = typeof Plugin | [typeof Plugin<Opts>, PluginOptions<Opts>];
export type PluginData = {
name: string;
packageName: string;
version: string;
url: string;
type: 'local' | 'upload' | 'npm';
};
export class PluginManager {
protected pluginInstances: Map<typeof Plugin, Plugin> = new Map();
protected pluginsAliases: Record<string, Plugin> = {};
private initPlugins: Promise<void>;
constructor(
protected _plugins: PluginType[],
protected loadRemotePlugins: boolean,
protected app: Application,
) {
this.app = app;
this.initPlugins = this.init(_plugins);
}
/**
* @internal
*/
async init(_plugins: PluginType[]) {
await this.initStaticPlugins(_plugins);
if (this.loadRemotePlugins) {
await this.initRemotePlugins();
}
}
private async initStaticPlugins(_plugins: PluginType[] = []) {
for await (const plugin of _plugins) {
const pluginClass = Array.isArray(plugin) ? plugin[0] : plugin;
const opts = Array.isArray(plugin) ? plugin[1] : undefined;
await this.add(pluginClass, opts);
}
}
private async initRemotePlugins() {
const res = await this.app.apiClient.request({ url: 'pm:listEnabled' });
const pluginList: PluginData[] = res?.data?.data || [];
const plugins = await getPlugins({
requirejs: this.app.requirejs,
pluginData: pluginList,
devDynamicImport: this.app.devDynamicImport,
});
for await (const [name, pluginClass] of plugins) {
const info = pluginList.find((item) => item.name === name);
await this.add(pluginClass, info);
}
}
async add<T = any>(plugin: typeof Plugin, opts: PluginOptions<T> = {}) {
const instance = this.getInstance(plugin, opts);
this.pluginInstances.set(plugin, instance);
if (opts.name) {
this.pluginsAliases[opts.name] = instance;
}
if (opts.packageName) {
this.pluginsAliases[opts.packageName] = instance;
}
await instance.afterAdd();
}
get<T extends typeof Plugin>(PluginClass: T): InstanceType<T>;
get<T extends {}>(name: string): T;
get(nameOrPluginClass: any) {
if (typeof nameOrPluginClass === 'string') {
return this.pluginsAliases[nameOrPluginClass];
}
return this.pluginInstances.get(nameOrPluginClass.default || nameOrPluginClass);
}
private getInstance<T>(plugin: typeof Plugin, opts?: T) {
return new plugin(opts, this.app);
}
/**
* @internal
*/
async load() {
await this.initPlugins;
for (const plugin of this.pluginInstances.values()) {
await plugin.beforeLoad();
}
for (const plugin of this.pluginInstances.values()) {
await plugin.load();
}
}
}