import { WidgetBuilder, WidgetDataProps, WidgetProps, WidgetState, } from "widgets/BaseWidget"; import React from "react"; import { PropertyPaneConfig } from "constants/PropertyControlConstants"; import { WidgetConfigProps } from "reducers/entityReducers/widgetConfigReducer"; import { RenderMode } from "constants/WidgetConstants"; import * as log from "loglevel"; import { WidgetFeatures } from "./WidgetFeatures"; import { addPropertyConfigIds, convertFunctionsToString, enhancePropertyPaneConfig, } from "./WidgetFactoryHelpers"; type WidgetDerivedPropertyType = any; export type DerivedPropertiesMap = Record; export type WidgetType = typeof WidgetFactory.widgetTypes[number]; class WidgetFactory { static widgetTypes: Record = {}; static widgetMap: Map< WidgetType, WidgetBuilder > = new Map(); static widgetDerivedPropertiesGetterMap: Map< WidgetType, WidgetDerivedPropertyType > = new Map(); static derivedPropertiesMap: Map< WidgetType, DerivedPropertiesMap > = new Map(); static defaultPropertiesMap: Map< WidgetType, Record > = new Map(); static metaPropertiesMap: Map> = new Map(); static propertyPaneConfigsMap: Map< WidgetType, readonly PropertyPaneConfig[] > = new Map(); static widgetConfigMap: Map< WidgetType, Partial & WidgetConfigProps & { type: string } > = new Map(); static registerWidgetBuilder( widgetType: string, widgetBuilder: WidgetBuilder, derivedPropertiesMap: DerivedPropertiesMap, defaultPropertiesMap: Record, metaPropertiesMap: Record, propertyPaneConfig?: PropertyPaneConfig[], features?: WidgetFeatures, ) { if (!this.widgetTypes[widgetType]) { this.widgetTypes[widgetType] = widgetType; this.widgetMap.set(widgetType, widgetBuilder); this.derivedPropertiesMap.set(widgetType, derivedPropertiesMap); this.defaultPropertiesMap.set(widgetType, defaultPropertiesMap); this.metaPropertiesMap.set(widgetType, metaPropertiesMap); if (propertyPaneConfig) { const enhancedPropertyPaneConfig = enhancePropertyPaneConfig( propertyPaneConfig, features, ); const serializablePropertyPaneConfig = convertFunctionsToString( enhancedPropertyPaneConfig, ); const finalPropertyPaneConfig = addPropertyConfigIds( serializablePropertyPaneConfig, ); this.propertyPaneConfigsMap.set( widgetType, Object.freeze(finalPropertyPaneConfig), ); } } } static storeWidgetConfig( widgetType: string, config: Partial & WidgetConfigProps & { type: string }, ) { this.widgetConfigMap.set(widgetType, Object.freeze(config)); } static createWidget( widgetData: WidgetDataProps, renderMode: RenderMode, ): React.ReactNode { const widgetProps: WidgetProps = { key: widgetData.widgetId, isVisible: true, ...widgetData, renderMode, }; const widgetBuilder = this.widgetMap.get(widgetData.type); if (widgetBuilder) { // TODO validate props here const widget = widgetBuilder.buildWidget(widgetProps); return widget; } else { const ex: WidgetCreationException = { message: "Widget Builder not registered for widget type" + widgetData.type, }; log.error(ex); return null; } } static getWidgetTypes(): WidgetType[] { return Array.from(this.widgetMap.keys()); } static getWidgetDerivedPropertiesMap( widgetType: WidgetType, ): DerivedPropertiesMap { const map = this.derivedPropertiesMap.get(widgetType); if (!map) { log.error("Widget type validation is not defined"); return {}; } return map; } static getWidgetDefaultPropertiesMap( widgetType: WidgetType, ): Record { const map = this.defaultPropertiesMap.get(widgetType); if (!map) { log.error("Widget default properties not defined", widgetType); return {}; } return map; } static getWidgetMetaPropertiesMap( widgetType: WidgetType, ): Record { const map = this.metaPropertiesMap.get(widgetType); if (!map) { log.error("Widget meta properties not defined: ", widgetType); return {}; } return map; } static getWidgetPropertyPaneConfig( type: WidgetType, ): readonly PropertyPaneConfig[] { const map = this.propertyPaneConfigsMap.get(type); if (!map) { log.error("Widget property pane configs not defined", type); return []; } return map; } static getWidgetTypeConfigMap(): WidgetTypeConfigMap { const typeConfigMap: WidgetTypeConfigMap = {}; WidgetFactory.getWidgetTypes().forEach((type) => { typeConfigMap[type] = { defaultProperties: WidgetFactory.getWidgetDefaultPropertiesMap(type), derivedProperties: WidgetFactory.getWidgetDerivedPropertiesMap(type), metaProperties: WidgetFactory.getWidgetMetaPropertiesMap(type), }; }); return typeConfigMap; } } export type WidgetTypeConfigMap = Record< string, { defaultProperties: Record; metaProperties: Record; derivedProperties: WidgetDerivedPropertyType; } >; export interface WidgetCreationException { message: string; } export default WidgetFactory;