/* * Copyright 2025 coze-dev Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { inject, injectable, type interfaces, named } from 'inversify'; import { type AsClass, ContributionProvider, type MaybePromise, } from '@flowgram-adapter/common'; import { ContainerFactory, type URI } from '@coze-project-ide/core'; import { WidgetFactory } from './widget/widget-factory'; import { CustomRenderWidgetFactory } from './widget/react-widgets/custom-render-widget-factory'; import { type ReactWidget } from './widget/react-widget'; import { type Widget } from './lumino/widgets'; // import { ViewRendererRegistry } from './view-render-registry'; export interface FlowWidget extends Widget { init?: (opt?: any) => void; } @injectable() export class WidgetManager { protected readonly widgets = new Map(); protected widgetFactories: WidgetFactory[] = []; @inject(CustomRenderWidgetFactory) protected customRenderWidgetFactory: CustomRenderWidgetFactory; @inject(ContributionProvider) @named(WidgetFactory) protected readonly factoryProvider: ContributionProvider; @inject(ContainerFactory) containerFactory: ContainerFactory; init(widgetFactories?: WidgetFactory[]) { this.widgetFactories = widgetFactories || []; for (const factory of this.factoryProvider.getContributions()) { this.widgetFactories.push(factory); } } getFactoryFromURI(uri: URI): WidgetFactory | undefined { for (const factory of this.widgetFactories) { if (factory.match && factory.match.test(uri.toString())) { return factory; } if (factory.canHandle && factory.canHandle(uri)) { return factory; } } } // @inject(ViewRendererRegistry) readonly rendererRegistry: ViewRendererRegistry; protected readonly pendingWidgetPromises = new Map< string, MaybePromise >(); getWidget(id: string): Widget | undefined { for (const [key, widget] of this.widgets.entries()) { if (id === key) { return widget; } } return undefined; } getWidgetFromURI(uri: URI, factory?: WidgetFactory): Widget | undefined { const id = this.uriToWidgetID(uri, factory); return this.getWidget(id); } uriToWidgetID(uri: URI, factory?: WidgetFactory): string { factory = factory || this.getFactoryFromURI(uri); return factory?.getId?.(uri) || uri.withoutQuery().toString(); } getAllWidgets(): Widget[] { const result: Widget[] = []; for (const [_, widget] of this.widgets.entries()) { result.push(widget); } return result; } setWidget(id: string, widget: ReactWidget | Widget) { this.widgets.set(id, widget); widget.disposed.connect(() => this.widgets.delete(id)); } protected doGetWidget( id: string, ): MaybePromise | undefined { const pendingWidget = this.widgets.get(id) ?? this.pendingWidgetPromises.get(id); if (pendingWidget) { return pendingWidget as MaybePromise; } return undefined; } async createSubWidget( uri: URI, widget: AsClass, ): Promise { const widgetId = this.uriToWidgetID(uri); const currentWidget = this.getWidget(widgetId); if (currentWidget) { return currentWidget as T; } const childContainer = this.containerFactory.createChild(); childContainer.bind(widget).toSelf().inSingletonScope(); const createWidget = childContainer.get(widget); createWidget.id = widgetId; createWidget.init(uri, childContainer); this.setWidget(widgetId, createWidget); return createWidget as T; } /** * 使用工厂模式注册 */ async getOrCreateWidgetFromURI( uri: URI, factory?: WidgetFactory, ): Promise { factory = factory || this.getFactoryFromURI(uri); if (!factory) { throw Error(`No widget factory '${uri.toString()}' has been registered.`); } const widgetId = this.uriToWidgetID(uri, factory); const existingWidget = this.doGetWidget(widgetId); if (existingWidget) { return existingWidget; } try { let widgetPromise = factory.createWidget?.(uri); let childContainer: interfaces.Container | undefined; if (!widgetPromise && factory.widget) { childContainer = this.containerFactory.createChild(); childContainer.bind(factory.widget).toSelf().inSingletonScope(); widgetPromise = childContainer.get(factory.widget); } if (!widgetPromise && factory.render) { childContainer = this.containerFactory.createChild(); widgetPromise = this.customRenderWidgetFactory(childContainer); } if (!widgetPromise) { throw Error('No widget createWidget'); } this.pendingWidgetPromises.set(widgetId, widgetPromise); const widget = await widgetPromise; if (factory.render) { widget.render = factory.render; } widget.id = widgetId; widget.init(uri, childContainer); this.setWidget(widgetId, widget); return widget as T; } finally { this.pendingWidgetPromises.delete(widgetId); } } }