181 lines
5.6 KiB
TypeScript
181 lines
5.6 KiB
TypeScript
/*
|
|
* 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<string, Widget>();
|
|
|
|
protected widgetFactories: WidgetFactory[] = [];
|
|
|
|
@inject(CustomRenderWidgetFactory)
|
|
protected customRenderWidgetFactory: CustomRenderWidgetFactory;
|
|
|
|
@inject(ContributionProvider)
|
|
@named(WidgetFactory)
|
|
protected readonly factoryProvider: ContributionProvider<WidgetFactory>;
|
|
|
|
@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<Widget>
|
|
>();
|
|
|
|
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<T extends Widget>(
|
|
id: string,
|
|
): MaybePromise<T> | undefined {
|
|
const pendingWidget =
|
|
this.widgets.get(id) ?? this.pendingWidgetPromises.get(id);
|
|
if (pendingWidget) {
|
|
return pendingWidget as MaybePromise<T>;
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
async createSubWidget<T extends ReactWidget>(
|
|
uri: URI,
|
|
widget: AsClass<ReactWidget>,
|
|
): Promise<T> {
|
|
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<ReactWidget>(widget);
|
|
createWidget.id = widgetId;
|
|
createWidget.init(uri, childContainer);
|
|
this.setWidget(widgetId, createWidget);
|
|
return createWidget as T;
|
|
}
|
|
|
|
/**
|
|
* 使用工厂模式注册
|
|
*/
|
|
async getOrCreateWidgetFromURI<T extends ReactWidget>(
|
|
uri: URI,
|
|
factory?: WidgetFactory,
|
|
): Promise<T> {
|
|
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<T>(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<ReactWidget>(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);
|
|
}
|
|
}
|
|
}
|