UNPKG

@o3r/configuration

Version:

This module contains configuration-related features such as CMS compatibility, Configuration override, store and debugging. It enables your application runtime configuration and comes with an integrated ng builder to help you generate configurations suppo

1 lines • 70.7 kB
{"version":3,"file":"o3r-configuration.mjs","sources":["../../src/core/configuration.ts","../../src/stores/config-override/config-override.actions.ts","../../src/stores/config-override/config-override.reducer.ts","../../src/stores/config-override/config-override.state.ts","../../src/stores/config-override/config-override.module.ts","../../src/stores/config-override/config-override.selectors.ts","../../src/stores/config-override/config-override.sync.ts","../../src/stores/configuration/configuration.actions.ts","../../src/stores/configuration/configuration.helpers.ts","../../src/stores/configuration/configuration.reducer.ts","../../src/stores/configuration/configuration.state.ts","../../src/stores/configuration/configuration.module.ts","../../src/stores/configuration/configuration.selectors.ts","../../src/stores/configuration/configuration.sync.ts","../../src/devkit/configuration-devtools.token.ts","../../src/devkit/configuration-devtools.service.ts","../../src/devkit/configuration-devtools.console.service.ts","../../src/devkit/configuration-devtools.interface.ts","../../src/devkit/configuration-devtools.message.service.ts","../../src/devkit/configuration-devtools.module.ts","../../src/services/configuration/configuration.base.module.ts","../../src/services/configuration/configuration.base.service.ts","../../src/tools/configuration.decorators.ts","../../src/tools/configuration.observer.ts","../../src/tools/configuration.signal.ts","../../src/o3r-configuration.ts"],"sourcesContent":["import {\n deepFill,\n} from '@o3r/core';\nimport {\n Observable,\n} from 'rxjs';\nimport {\n distinctUntilChanged,\n map,\n shareReplay,\n} from 'rxjs/operators';\n\n/**\n * Interface to define the error messages into component configuration\n */\nexport interface ErrorMessages {\n /**\n * Error message map\n */\n errorMessages: { [key: string]: string };\n}\n\n/**\n * Interface to specify that the component has an ID\n */\nexport interface Identifiable {\n /**\n * Identifier\n */\n id: string;\n}\n\n/**\n * Get the component and library's names based on the configuration name\n * @param configurationName Name of the component as found in the store\n * @returns Object containing library and component name.\n */\nexport function parseConfigurationName(configurationName: string): { library?: string; libraryName?: string; componentName: string } | undefined {\n const parsedConfigurationName = configurationName.match(/^([^#]*)#(.*)$/i);\n if (parsedConfigurationName) {\n return {\n library: parsedConfigurationName.length > 2 ? parsedConfigurationName[1] : undefined,\n componentName: parsedConfigurationName.length > 2 ? parsedConfigurationName[2] : parsedConfigurationName[0]\n };\n }\n}\n\n/**\n * Operator to get the configuration from store for a given component and merge it with the global config\n * @param defaultValue Default value of the configuration\n */\nexport function getConfiguration<T extends Record<string, unknown>>(defaultValue: T) {\n return <C extends Partial<T>>(source: Observable<C | undefined>): Observable<T> =>\n source.pipe(\n map((configOverride) => {\n return deepFill(defaultValue, configOverride);\n }),\n distinctUntilChanged((prev, current) => JSON.stringify(prev) === JSON.stringify(current)),\n shareReplay({ refCount: true, bufferSize: 1 })\n );\n}\n","import {\n createAction,\n props,\n} from '@ngrx/store';\nimport {\n SetStateActionPayload,\n} from '@o3r/core';\nimport {\n ConfigOverrideState,\n} from './config-override.state';\n\n/** Actions */\nconst ACTION_SET = '[ConfigOverride] set';\n\n/**\n * Clear all overrides and fill the store with the payload\n */\nexport const setConfigOverride = createAction(ACTION_SET, props<SetStateActionPayload<ConfigOverrideState>>());\n","import {\n ActionCreator,\n createReducer,\n on,\n ReducerTypes,\n} from '@ngrx/store';\nimport * as actions from './config-override.actions';\nimport {\n ConfigOverrideState,\n} from './config-override.state';\n\n/**\n * ConfigOverride Store initial value\n */\nexport const configOverrideInitialState: ConfigOverrideState = { configOverrides: {} };\n\n/**\n * List of basic actions for ConfigOverride Store\n */\nexport const configOverrideReducerFeatures: ReducerTypes<ConfigOverrideState, ActionCreator[]>[] = [\n on(actions.setConfigOverride, (_state, payload) => ({ ...payload.state }))\n];\n\n/**\n * ConfigOverride Store reducer\n */\nexport const configOverrideReducer = createReducer(\n configOverrideInitialState,\n ...configOverrideReducerFeatures\n);\n","/**\n * Property override model\n */\nexport interface PropertyOverride {\n [property: string]: any;\n}\n\n/**\n * ConfigOverride store state\n */\nexport interface ConfigOverrideState {\n /** Map of PropertyOverride indexed on component + config name */\n configOverrides: Record<string, PropertyOverride>;\n}\n\n/**\n * Name of the ConfigOverride Store\n */\nexport const CONFIG_OVERRIDE_STORE_NAME = 'configOverride';\n\n/**\n * ConfigOverride Store Interface\n */\nexport interface ConfigOverrideStore {\n /** ConfigOverride state */\n [CONFIG_OVERRIDE_STORE_NAME]: ConfigOverrideState;\n}\n","import {\n InjectionToken,\n ModuleWithProviders,\n NgModule,\n} from '@angular/core';\nimport {\n Action,\n ActionReducer,\n StoreModule,\n} from '@ngrx/store';\nimport {\n configOverrideReducer,\n} from './config-override.reducer';\nimport {\n CONFIG_OVERRIDE_STORE_NAME,\n ConfigOverrideState,\n} from './config-override.state';\n\n/** Token of the ConfigOverride reducer */\nexport const CONFIG_OVERRIDE_REDUCER_TOKEN = new InjectionToken<ActionReducer<ConfigOverrideState, Action>>('Feature ConfigOverride Reducer');\n\n/** Provide default reducer for ConfigOverride store */\nexport function getDefaultConfigOverrideReducer() {\n return configOverrideReducer;\n}\n\n@NgModule({\n imports: [\n StoreModule.forFeature(CONFIG_OVERRIDE_STORE_NAME, CONFIG_OVERRIDE_REDUCER_TOKEN)\n ],\n providers: [\n { provide: CONFIG_OVERRIDE_REDUCER_TOKEN, useFactory: getDefaultConfigOverrideReducer }\n ]\n})\nexport class ConfigOverrideStoreModule {\n public static forRoot<T extends ConfigOverrideState>(reducerFactory: () => ActionReducer<T, Action>): ModuleWithProviders<ConfigOverrideStoreModule> {\n return {\n ngModule: ConfigOverrideStoreModule,\n providers: [\n { provide: CONFIG_OVERRIDE_REDUCER_TOKEN, useFactory: reducerFactory }\n ]\n };\n }\n}\n","import {\n createFeatureSelector,\n createSelector,\n} from '@ngrx/store';\nimport {\n CONFIG_OVERRIDE_STORE_NAME,\n ConfigOverrideState,\n} from './config-override.state';\n\n/** Select ConfigOverride State */\nexport const selectConfigOverrideState = createFeatureSelector<ConfigOverrideState>(CONFIG_OVERRIDE_STORE_NAME);\n\n/** Select the array of ConfigOverride */\nexport const selectConfigOverride = createSelector(selectConfigOverrideState, (state) => state?.configOverrides || {});\n\n/**\n * Get the override for given component identifier\n * @param componentId\n */\nexport const selectComponentOverrideConfig = (componentId: string) => createSelector(selectConfigOverride, (configOverrides) => configOverrides[componentId] || {});\n","import {\n Serializer,\n} from '@o3r/core';\nimport {\n configOverrideInitialState,\n} from './config-override.reducer';\nimport {\n ConfigOverrideState,\n} from './config-override.state';\n\n/**\n * Deserializer\n * @param rawObject\n */\nexport const configOverrideStorageDeserializer = (rawObject: any) => {\n if (!rawObject) {\n return configOverrideInitialState;\n }\n return rawObject;\n};\n\nexport const configOverrideStorageSync: Serializer<ConfigOverrideState> = {\n deserialize: configOverrideStorageDeserializer\n};\n","import {\n createAction,\n props,\n} from '@ngrx/store';\nimport {\n Configuration,\n} from '@o3r/core';\n\nexport interface SetConfigurationEntitiesPayload {\n /** Map of configurations to update/insert, this is now Partial due the change of Configuration interface */\n entities: { [id: string]: Partial<Configuration> };\n}\n\nexport interface UpsertConfigurationEntityPayload {\n /** ID of the item */\n id: string;\n /** Updated/New configuration object */\n configuration: Partial<Configuration>;\n}\n\nexport interface UpdateConfigurationEntityPayload {\n /** ID of the item */\n id: string;\n /** Updated/New configuration partial object */\n configuration: Partial<Configuration>;\n}\n\n/** Entity Actions */\nconst ACTION_CLEAR_ENTITIES = '[Configuration] clear entities';\nconst ACTION_UPDATE_ENTITIES = '[Configuration] update entities';\nconst ACTION_UPSERT_ENTITIES = '[Configuration] upsert entities';\nconst ACTION_SET_ENTITIES = '[Configuration] set entities';\nconst ACTION_UPDATE_CONFIGURATION_ENTITY = '[Configuration] update configuration entity';\nconst ACTION_UPSERT_CONFIGURATION_ENTITY = '[Configuration] set configuration entity';\n\n/**\n * Upsert one configuration entity\n */\nexport const upsertConfigurationEntity = createAction(ACTION_UPSERT_CONFIGURATION_ENTITY, props<UpsertConfigurationEntityPayload>());\n\n/**\n * Update one configuration entity\n */\nexport const updateConfigurationEntity = createAction(ACTION_UPDATE_CONFIGURATION_ENTITY, props<UpdateConfigurationEntityPayload>());\n\n/**\n * Clear all configuration and fill the store with the payload\n */\nexport const setConfigurationEntities = createAction(ACTION_SET_ENTITIES, props<SetConfigurationEntitiesPayload>());\n\n/**\n * Update configuration with known IDs, ignore the new ones\n */\nexport const updateConfigurationEntities = createAction(ACTION_UPDATE_ENTITIES, props<SetConfigurationEntitiesPayload>());\n\n/**\n * Update configuration with known IDs, insert the new ones\n */\nexport const upsertConfigurationEntities = createAction(ACTION_UPSERT_ENTITIES, props<SetConfigurationEntitiesPayload>());\n\n/**\n * Clear only the entities, keeps the other attributes in the state\n */\nexport const clearConfigurationEntities = createAction(ACTION_CLEAR_ENTITIES);\n","import type {\n Configuration,\n CustomConfig,\n} from '@o3r/core';\nimport {\n computeItemIdentifier,\n} from '@o3r/core';\nimport {\n SetConfigurationEntitiesPayload,\n} from './configuration.actions';\n\n/**\n * compute the configuration into SetEntitiesPayload\n * @param customConfigObject array of configurations\n */\nexport function computeConfiguration<T extends Configuration>(customConfigObject: CustomConfig<T>[]): SetConfigurationEntitiesPayload {\n const entities = customConfigObject.reduce<{ [k: string]: Partial<T> & { id: string } }>((acc, conf) => {\n const id = computeItemIdentifier(conf.name, conf.library);\n acc[id] = { ...conf.config, id };\n return acc;\n }, {});\n return { entities };\n}\n","import {\n createEntityAdapter,\n EntityAdapter,\n} from '@ngrx/entity';\nimport {\n ActionCreator,\n createReducer,\n on,\n ReducerTypes,\n} from '@ngrx/store';\nimport * as actions from './configuration.actions';\nimport {\n ConfigurationModel,\n ConfigurationState,\n} from './configuration.state';\n\n/**\n * Configuration Store adapter\n */\nexport const configurationAdapter: EntityAdapter<ConfigurationModel> = createEntityAdapter<ConfigurationModel>({\n selectId: (model) => model.id\n});\n\n/**\n * Configuration Store initial value\n */\nexport const configurationInitialState: ConfigurationState = configurationAdapter.getInitialState({});\n\n/**\n * List of basic actions for Configuration Store\n */\nexport const configurationReducerFeatures: ReducerTypes<ConfigurationState, ActionCreator[]>[] = [\n\n on(actions.setConfigurationEntities, (state, payload) => configurationAdapter.addMany((Object.keys(payload) as (keyof typeof payload)[]).map((id) =>\n ({ ...(payload[id] as any), id })), configurationAdapter.removeAll(state))),\n\n on(actions.updateConfigurationEntities, (state, payload) =>\n configurationAdapter.updateMany(Object.keys(payload.entities).map((id) => ({ id: id, changes: payload.entities[id] })), state)),\n\n on(actions.upsertConfigurationEntities, (state, payload) => configurationAdapter.upsertMany(Object.keys(payload.entities).map((id) => ({ ...payload.entities[id], id })), state)),\n\n on(actions.clearConfigurationEntities, (state) => configurationAdapter.removeAll(state)),\n\n on(actions.updateConfigurationEntity, (state, payload) => configurationAdapter.updateOne({ id: payload.id, changes: payload.configuration }, state)),\n\n on(actions.upsertConfigurationEntity, (state, payload) => configurationAdapter.upsertOne({ id: payload.id, ...payload.configuration }, state))\n];\n\n/**\n * Configuration Store reducer\n */\nexport const configurationReducer = createReducer(\n configurationInitialState,\n ...configurationReducerFeatures\n);\n","import type {\n EntityState,\n} from '@ngrx/entity';\nimport type {\n Configuration,\n} from '@o3r/core';\n\n/**\n * Configuration model\n */\nexport interface ConfigurationModel extends Configuration {\n id: string;\n}\n\n/**\n * Configuration store state\n */\nexport interface ConfigurationState extends EntityState<ConfigurationModel> {\n}\n\n/**\n * Name of the Configuration Store\n */\nexport const CONFIGURATION_STORE_NAME = 'configuration';\n\n/**\n * Configuration Store Interface\n */\nexport interface ConfigurationStore {\n /** Configuration state */\n [CONFIGURATION_STORE_NAME]: ConfigurationState;\n}\n\n/**\n * ID of the global configuration\n */\nexport const globalConfigurationId = 'global';\n","import {\n InjectionToken,\n ModuleWithProviders,\n NgModule,\n} from '@angular/core';\nimport {\n Action,\n ActionReducer,\n StoreModule,\n} from '@ngrx/store';\nimport {\n configurationReducer,\n} from './configuration.reducer';\nimport {\n CONFIGURATION_STORE_NAME,\n ConfigurationState,\n} from './configuration.state';\n\n/** Token of the Configuration reducer */\nexport const CONFIGURATION_REDUCER_TOKEN = new InjectionToken<ActionReducer<ConfigurationState, Action>>('Feature Configuration Reducer');\n\n/** Provide default reducer for Configuration store */\nexport function getDefaultConfigurationReducer() {\n return configurationReducer;\n}\n\n@NgModule({\n imports: [\n StoreModule.forFeature(CONFIGURATION_STORE_NAME, CONFIGURATION_REDUCER_TOKEN)\n ],\n providers: [\n { provide: CONFIGURATION_REDUCER_TOKEN, useFactory: getDefaultConfigurationReducer }\n ]\n})\nexport class ConfigurationStoreModule {\n public static forRoot<T extends ConfigurationState>(reducerFactory: () => ActionReducer<T, Action>): ModuleWithProviders<ConfigurationStoreModule> {\n return {\n ngModule: ConfigurationStoreModule,\n providers: [\n { provide: CONFIGURATION_REDUCER_TOKEN, useFactory: reducerFactory }\n ]\n };\n }\n}\n","import {\n createSelector,\n} from '@ngrx/store';\nimport {\n Configuration,\n} from '@o3r/core';\nimport {\n configurationAdapter,\n} from './configuration.reducer';\nimport {\n CONFIGURATION_STORE_NAME,\n ConfigurationState,\n globalConfigurationId,\n} from './configuration.state';\n\nconst { selectIds, selectEntities, selectAll, selectTotal } = configurationAdapter.getSelectors();\n\n/**\n * Select Configuration State\n * Note: the usage of createSelector is to avoid warning printing because of potentially undefined feature store\n */\nexport const selectConfigurationState = createSelector<{ [CONFIGURATION_STORE_NAME]: ConfigurationState }, [state: ConfigurationState | undefined], ConfigurationState | undefined>(\n (state) => state[CONFIGURATION_STORE_NAME],\n (state) => state\n);\n\n/** Select the array of Configuration ids */\nexport const selectConfigurationIds = createSelector(selectConfigurationState, (state) => state ? selectIds(state) : []);\n\n/** Select the array of Configuration */\nexport const selectAllConfiguration = createSelector(selectConfigurationState, (state) => state ? selectAll(state) : []);\n\n/** Select the dictionary of Configuration entities */\nexport const selectConfigurationEntities = createSelector(selectConfigurationState, (state) => state ? selectEntities(state) : {});\n\n/** Select the total Configuration count */\nexport const selectConfigurationTotal = createSelector(selectConfigurationState, (state) => state ? selectTotal(state) : 0);\n\n/**\n * Select the configuration for component with id\n * @param props property of the selector\n * @param props.id id of the component\n */\nexport const selectConfigurationForComponent = <T extends Configuration>(props: { id: string }) =>\n createSelector(selectConfigurationEntities, (entities) => (entities?.[props.id] || {}) as Configuration as T);\n\n/**\n * Select the global configuration\n */\nexport const selectGlobalConfiguration = createSelector(selectConfigurationForComponent({ id: globalConfigurationId }), (config) => config);\n","import {\n configurationAdapter,\n configurationInitialState,\n} from './configuration.reducer';\nimport {\n ConfigurationState,\n} from './configuration.state';\n\nexport const configurationStorageSync = {\n deserialize: (rawObject: any) => {\n if (!rawObject || !rawObject.ids) {\n return configurationInitialState;\n }\n const storeObject = configurationAdapter.getInitialState<ConfigurationState>(rawObject);\n return storeObject as ConfigurationState;\n }\n};\n","import {\n InjectionToken,\n} from '@angular/core';\nimport {\n ConfigurationDevtoolsServiceOptions,\n} from './configuration-devtools.interface';\n\nexport const OTTER_CONFIGURATION_DEVTOOLS_DEFAULT_OPTIONS: Readonly<ConfigurationDevtoolsServiceOptions> = {\n defaultLibraryName: '@o3r/components',\n defaultJsonFilename: 'partial-static-config.json',\n isActivatedOnBootstrap: false,\n isActivatedOnBootstrapWhenCMSContext: true\n} as const;\n\nexport const OTTER_CONFIGURATION_DEVTOOLS_OPTIONS = new InjectionToken<ConfigurationDevtoolsServiceOptions>('Otter Configuration Devtools options');\n","import {\n ApplicationRef,\n Inject,\n Injectable,\n Optional,\n} from '@angular/core';\nimport {\n select,\n Store,\n} from '@ngrx/store';\nimport {\n computeItemIdentifier,\n Configuration,\n CustomConfig,\n} from '@o3r/core';\nimport {\n firstValueFrom,\n Observable,\n} from 'rxjs';\nimport {\n filter,\n map,\n shareReplay,\n} from 'rxjs/operators';\nimport {\n parseConfigurationName,\n} from '../core';\nimport {\n computeConfiguration,\n ConfigurationModel,\n ConfigurationStore,\n selectConfigurationEntities,\n selectConfigurationIds,\n upsertConfigurationEntities,\n upsertConfigurationEntity,\n} from '../stores';\nimport {\n ConfigurationDevtoolsServiceOptions,\n} from './configuration-devtools.interface';\nimport {\n OTTER_CONFIGURATION_DEVTOOLS_DEFAULT_OPTIONS,\n OTTER_CONFIGURATION_DEVTOOLS_OPTIONS,\n} from './configuration-devtools.token';\n\n@Injectable({ providedIn: 'root' })\nexport class OtterConfigurationDevtools {\n /** Stream of configurations */\n public readonly configurationEntities$: Observable<CustomConfig[]>;\n\n constructor(\n protected store: Store<ConfigurationStore>,\n private readonly appRef: ApplicationRef,\n @Optional() @Inject(OTTER_CONFIGURATION_DEVTOOLS_OPTIONS) private readonly options: ConfigurationDevtoolsServiceOptions) {\n this.options = { ...OTTER_CONFIGURATION_DEVTOOLS_DEFAULT_OPTIONS, ...options };\n\n /** Full configuration store */\n this.configurationEntities$ = this.store.pipe(\n select(selectConfigurationEntities),\n map((entities) =>\n Object.values(entities)\n .filter((entity): entity is ConfigurationModel => !!entity)\n .map((entity) => {\n const { id, ...config } = entity;\n const { library = this.options.defaultLibraryName, componentName: name = id } = parseConfigurationName(id) || {};\n return { name, config, library } satisfies CustomConfig;\n })\n ),\n shareReplay(1)\n );\n }\n\n /**\n * Get configuration name based on input information\n * @param selector Selector for a component configuration. It can be a string in the form library#componentName (i.e: @my-lib/shared-components#HeaderContComponent)\n * or an object with the component and library names (i.e: {library:\"@my-lib/shared-components\", componentName:'HeaderContComponent'})\n * @param isFallbackName Determine if the name requested is a fallback name\n * @returns string in the format library#componentName (i.e: \"@my-lib/shared-components#HeaderContComponent\")\n */\n public getComponentConfigName(selector: string | { library?: string; componentName: string }, isFallbackName = false) {\n if (!isFallbackName) {\n return typeof selector === 'string' ? selector : computeItemIdentifier(selector.componentName, selector.library || this.options.defaultLibraryName);\n }\n\n return typeof selector === 'string'\n ? computeItemIdentifier(selector, this.options.defaultLibraryName || 'global')\n : computeItemIdentifier(selector.componentName, this.options.defaultLibraryName || 'global');\n }\n\n /**\n * Get the list of components which have a configuration loaded in the store\n */\n public getComponentsWithConfiguration(): Promise<string[]> {\n return firstValueFrom(\n this.store\n .pipe(\n select(selectConfigurationIds),\n map((ids) => ids\n .map((configName) => parseConfigurationName(configName.toString()))\n .filter((parsedName): parsedName is { library?: string; componentName: string } => !!parsedName)\n .map((parsedName) => parsedName.componentName + (parsedName.library ? ' from ' + parsedName.library : ''))\n )\n )\n );\n }\n\n /**\n * Set a specified value of a component configuration\n * @param selector Selector for a component configuration\n * @param configProperty Name of the configuration property to set\n * @param configValue Value of the configuration property to set\n */\n public setDynamicConfig(selector: string | { library?: string; componentName: string }, configProperty: string, configValue: any): void {\n this.store.dispatch(\n upsertConfigurationEntity({\n id: this.getComponentConfigName(selector),\n configuration: { [configProperty]: configValue }\n })\n );\n this.appRef.tick();\n }\n\n /**\n * Get the configuration for a specific component\n * @param selector Selector for a component configuration. It can be a string in the form library#configurationName (i.e: @my-lib/shared-components#HeaderPresConfig)\n * or an object with the configuration and library names (i.e: {library:\"@my-lib/shared-components\", componentName:'HeaderPresConfig'})\n */\n public getCurrentConfigurationFor(selector: string | { library?: string; componentName: string }): Promise<Configuration> {\n return firstValueFrom(\n this.store.pipe(\n select(selectConfigurationEntities),\n map((entities) => entities[this.getComponentConfigName(selector)] || entities[this.getComponentConfigName(selector, true)]),\n filter((entity): entity is ConfigurationModel => !!entity),\n map((entity) => {\n const { id, ...configuration } = entity;\n return configuration as Configuration;\n })\n )\n );\n }\n\n /**\n * Get the whole configuration of the application\n */\n public getConfiguration() {\n return firstValueFrom(this.configurationEntities$);\n }\n\n /**\n * Load a json configuration\n * @param configurations configurations to load\n */\n public loadConfiguration(configurations: string | CustomConfig<Configuration>[]): void {\n this.store.dispatch(upsertConfigurationEntities(computeConfiguration(typeof configurations === 'string' ? JSON.parse(configurations) : configurations)));\n this.appRef.tick();\n }\n}\n","/* eslint-disable no-console -- service to log message in the console */\nimport {\n Inject,\n Injectable,\n Optional,\n} from '@angular/core';\nimport type {\n Configuration,\n ContextualizationDataset,\n CustomConfig,\n DevtoolsServiceInterface,\n WindowWithDevtools,\n} from '@o3r/core';\nimport {\n firstValueFrom,\n} from 'rxjs';\nimport {\n ConfigurationContextualizationDevtools,\n ConfigurationDevtoolsServiceOptions,\n} from './configuration-devtools.interface';\nimport {\n OtterConfigurationDevtools,\n} from './configuration-devtools.service';\nimport {\n OTTER_CONFIGURATION_DEVTOOLS_DEFAULT_OPTIONS,\n OTTER_CONFIGURATION_DEVTOOLS_OPTIONS,\n} from './configuration-devtools.token';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class ConfigurationDevtoolsConsoleService implements DevtoolsServiceInterface, ConfigurationContextualizationDevtools {\n /** Name of the Window property to access to the devtools */\n public static readonly windowModuleName = 'configuration';\n\n constructor(\n private readonly configurationDevtools: OtterConfigurationDevtools,\n @Optional() @Inject(OTTER_CONFIGURATION_DEVTOOLS_OPTIONS) private readonly options: ConfigurationDevtoolsServiceOptions\n ) {\n this.options = { ...OTTER_CONFIGURATION_DEVTOOLS_DEFAULT_OPTIONS, ...options };\n\n if (\n this.options.isActivatedOnBootstrap\n || (\n this.options.isActivatedOnBootstrapWhenCMSContext\n && (document.body.dataset as ContextualizationDataset).cmscontext === 'true'\n )\n ) {\n this.activate();\n }\n }\n\n private downloadJSON(content: string, fileName: string = this.options.defaultJsonFilename): void {\n const a = document.createElement('a');\n const file = new Blob([content], { type: 'text/plain' });\n a.href = URL.createObjectURL(file);\n a.download = fileName;\n a.click();\n }\n\n private copyElementToClipboard(content: string): void {\n const input = document.createElement('textarea');\n input.value = content;\n document.body.append(input);\n input.select();\n document.execCommand('copy');\n input.remove();\n }\n\n /**\n * Set a specified value of a component configuration\n * @param selector Selector for a component configuration\n * @param configProperty Name of the configuration property to set\n * @param configValue Value of the configuration property to set\n */\n public setDynamicConfig(selector: string | { library?: string; componentName: string }, configProperty: string, configValue: any): void {\n this.configurationDevtools.setDynamicConfig(selector, configProperty, configValue);\n }\n\n /** @inheritDoc */\n public activate() {\n const windowWithDevtools: WindowWithDevtools = window;\n windowWithDevtools._OTTER_DEVTOOLS_ ||= {};\n windowWithDevtools._OTTER_DEVTOOLS_[ConfigurationDevtoolsConsoleService.windowModuleName] = this;\n\n console.info(`Otter Configuration Devtools is now accessible via the _OTTER_DEVTOOLS_.${ConfigurationDevtoolsConsoleService.windowModuleName} variable`);\n }\n\n /**\n * Display the list of configurations loaded in the store and the library they originate from\n * @returns array with the configurations and libraries for example: [\"LibComponentsCommonRuntimeConfig from @my-lib/shared-common\"]\n */\n public async displayComponentsWithConfiguration() {\n const selectors = await this.configurationDevtools.getComponentsWithConfiguration();\n console.log(selectors);\n }\n\n /**\n * Display the configuration for a specific component\n * @param selector Selector for a component configuration. It can be a string in the form library#configurationName (i.e: '@my-lib/shared-components#HeaderContConfig')\n * or an object with the configuration and library names (i.e: {library:\"@my-lib/shared-components\", componentName:'HeaderContConfig'}).\n * Note the object input componentName expects a configuration name not a component name.\n * @returns Configuration object (i.e: {airlineLogoPath: \"img/airlines/icon-BH.svg\", displayLanguageSelector: false})\n */\n public async displayCurrentConfigurationFor(selector: string | { library?: string; componentName: string }) {\n const configuration = await this.configurationDevtools.getCurrentConfigurationFor(selector);\n console.log(configuration);\n }\n\n /**\n * Download the JSON file of the whole configuration\n * @param fileName Name of the file to download\n */\n public async saveConfiguration(fileName: string = this.options.defaultJsonFilename) {\n const configs = await firstValueFrom(this.configurationDevtools.configurationEntities$);\n this.downloadJSON(JSON.stringify(configs), fileName);\n }\n\n /**\n * Display the whole configuration of the application\n */\n public async displayConfiguration() {\n const configs = await this.configurationDevtools.getConfiguration();\n console.log(configs);\n }\n\n /**\n * Display a bookmark to generate the current configuration\n */\n public async displayConfigurationBookmark() {\n const content = await this.configurationDevtools.getConfiguration();\n\n console.log('BOOKMARK');\n console.log(`javascript:window._OTTER_DEVTOOLS_.updateConfigurations('${JSON.stringify(content).replace(/'/g, '\\\\\\'')}')`);\n }\n\n /**\n * Copy the whole configuration to the clipboard\n */\n public async copyConfigurationToClipboard() {\n const configs = await firstValueFrom(this.configurationDevtools.configurationEntities$);\n this.copyElementToClipboard(JSON.stringify(configs));\n }\n\n /**\n * Replace N configurations in one shot\n * @param configurations array of configurations to update\n */\n public updateConfigurations(configurations: string | CustomConfig<Configuration>[]): void {\n this.configurationDevtools.loadConfiguration(configurations);\n }\n}\n","import type {\n Dictionary,\n} from '@ngrx/entity';\nimport type {\n Configuration,\n ConnectContentMessage,\n ContextualizationDevtoolsCommonOptions,\n CustomConfig,\n DevtoolsCommonOptions,\n MessageDataTypes,\n OtterMessageContent,\n RequestMessagesContentMessage,\n} from '@o3r/core';\nimport type {\n ConfigurationModel,\n} from '../stores/index';\n\n/** Option for Configuration devtools service */\nexport interface ConfigurationDevtoolsServiceOptions extends DevtoolsCommonOptions, ContextualizationDevtoolsCommonOptions {\n /**\n * Default library name to use if not specified in the function call\n * @default `@o3r/components`\n */\n defaultLibraryName: string;\n /**\n * Default JSON file name if not specified in the function\n * @default partial-static-config.json\n */\n defaultJsonFilename: string;\n}\n\nexport interface ConfigurationsMessage extends OtterMessageContent<'configurations'> {\n /** Configurations */\n configurations: Dictionary<ConfigurationModel>;\n}\n\nexport interface UpdateConfigMessage extends OtterMessageContent<'updateConfig'> {\n /** Configuration ID */\n id: string;\n /** Configuration value */\n configValue: any;\n}\n\ntype ConfigurationMessageContents =\n | ConfigurationsMessage\n | UpdateConfigMessage;\n\n/** List of possible DataTypes for Configuration messages */\nexport type ConfigurationMessageDataTypes = MessageDataTypes<ConfigurationMessageContents>;\n\n/** List of all messages for configuration purpose */\nexport type AvailableConfigurationMessageContents =\n | ConfigurationMessageContents\n | ConnectContentMessage\n | RequestMessagesContentMessage<ConfigurationMessageDataTypes>;\n\n/**\n * Determine if the given message is a Configuration message\n * @param message message to check\n */\nexport const isConfigurationMessage = (message: any): message is AvailableConfigurationMessageContents => {\n return message && (\n message.dataType === 'configurations'\n || message.dataType === 'updateConfig'\n || message.dataType === 'requestMessages'\n || message.dataType === 'connect');\n};\n\n/**\n * Contextualization devtools exposed for configuration in CMS integration\n */\nexport interface ConfigurationContextualizationDevtools {\n /**\n * Replace N configurations in one shot\n * @param configs array of configurations to update\n */\n updateConfigurations: (configurations: CustomConfig<Configuration>[]) => void;\n}\n","import {\n DestroyRef,\n inject,\n Inject,\n Injectable,\n Optional,\n} from '@angular/core';\nimport {\n takeUntilDestroyed,\n} from '@angular/core/rxjs-interop';\nimport {\n select,\n Store,\n} from '@ngrx/store';\nimport {\n DevtoolsServiceInterface,\n filterMessageContent,\n sendOtterMessage,\n} from '@o3r/core';\nimport {\n LoggerService,\n} from '@o3r/logger';\nimport {\n firstValueFrom,\n fromEvent,\n} from 'rxjs';\nimport {\n ConfigurationStore,\n selectConfigurationEntities,\n} from '../stores';\nimport {\n AvailableConfigurationMessageContents,\n ConfigurationDevtoolsServiceOptions,\n ConfigurationMessageDataTypes,\n isConfigurationMessage,\n} from './configuration-devtools.interface';\nimport {\n OtterConfigurationDevtools,\n} from './configuration-devtools.service';\nimport {\n OTTER_CONFIGURATION_DEVTOOLS_DEFAULT_OPTIONS,\n OTTER_CONFIGURATION_DEVTOOLS_OPTIONS,\n} from './configuration-devtools.token';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class ConfigurationDevtoolsMessageService implements DevtoolsServiceInterface {\n private readonly sendMessage = sendOtterMessage<AvailableConfigurationMessageContents>;\n private readonly destroyRef = inject(DestroyRef);\n\n constructor(\n private readonly store: Store<ConfigurationStore>,\n private readonly logger: LoggerService,\n private readonly configurationDevtools: OtterConfigurationDevtools,\n @Optional() @Inject(OTTER_CONFIGURATION_DEVTOOLS_OPTIONS) private readonly options: ConfigurationDevtoolsServiceOptions) {\n this.options = { ...OTTER_CONFIGURATION_DEVTOOLS_DEFAULT_OPTIONS, ...options };\n\n if (this.options.isActivatedOnBootstrap) {\n this.activate();\n }\n }\n\n private async sendCurrentConfigurationState() {\n const configurations = await firstValueFrom(this.store.pipe(\n select(selectConfigurationEntities)\n ));\n this.sendMessage('configurations', { configurations });\n }\n\n /**\n * Function to trigger a re-send a requested messages to the Otter Chrome DevTools extension\n * @param only restricted list of messages to re-send\n */\n private handleReEmitRequest(only?: ConfigurationMessageDataTypes[]) {\n if (!only || only.includes('configurations')) {\n return this.sendCurrentConfigurationState();\n }\n }\n\n /**\n * Function to handle the incoming messages from Otter Chrome DevTools extension\n * @param message message coming from the Otter Chrome DevTools extension\n */\n private async handleEvents(message: AvailableConfigurationMessageContents) {\n this.logger.debug('Message handling by the configuration service', message);\n\n switch (message.dataType) {\n case 'connect': {\n await this.connectPlugin();\n break;\n }\n case 'requestMessages': {\n await this.handleReEmitRequest(message.only);\n break;\n }\n case 'updateConfig': {\n this.configurationDevtools.loadConfiguration([{\n name: message.id,\n config: message.configValue\n }]);\n break;\n }\n default: {\n this.logger.warn('Message ignored by the configuration service', message);\n }\n }\n }\n\n /**\n * Function to connect the plugin to the Otter DevTools extension\n */\n private connectPlugin() {\n this.logger.debug('Otter DevTools is plugged to configuration service of the application');\n return this.sendCurrentConfigurationState();\n }\n\n /** @inheritDoc */\n public activate() {\n fromEvent(window, 'message').pipe(\n takeUntilDestroyed(this.destroyRef),\n filterMessageContent(isConfigurationMessage)\n ).subscribe((e) => this.handleEvents(e));\n\n this.store.pipe(\n select(selectConfigurationEntities),\n takeUntilDestroyed(this.destroyRef)\n ).subscribe((configurations) => this.sendMessage('configurations', { configurations }));\n }\n}\n","import {\n ModuleWithProviders,\n NgModule,\n} from '@angular/core';\nimport {\n StoreModule,\n} from '@ngrx/store';\nimport {\n ConfigurationStoreModule,\n} from '../stores/index';\nimport {\n ConfigurationDevtoolsConsoleService,\n} from './configuration-devtools.console.service';\nimport type {\n ConfigurationDevtoolsServiceOptions,\n} from './configuration-devtools.interface';\nimport {\n ConfigurationDevtoolsMessageService,\n} from './configuration-devtools.message.service';\nimport {\n OtterConfigurationDevtools,\n} from './configuration-devtools.service';\nimport {\n OTTER_CONFIGURATION_DEVTOOLS_DEFAULT_OPTIONS,\n OTTER_CONFIGURATION_DEVTOOLS_OPTIONS,\n} from './configuration-devtools.token';\n\n@NgModule({\n imports: [\n StoreModule,\n ConfigurationStoreModule\n ],\n providers: [\n { provide: OTTER_CONFIGURATION_DEVTOOLS_OPTIONS, useValue: OTTER_CONFIGURATION_DEVTOOLS_DEFAULT_OPTIONS },\n ConfigurationDevtoolsMessageService,\n ConfigurationDevtoolsConsoleService,\n OtterConfigurationDevtools\n ]\n})\nexport class ConfigurationDevtoolsModule {\n /**\n * Initialize Otter Devtools\n * @param options\n */\n public static instrument(options: Partial<ConfigurationDevtoolsServiceOptions>): ModuleWithProviders<ConfigurationDevtoolsModule> {\n return {\n ngModule: ConfigurationDevtoolsModule,\n providers: [\n { provide: OTTER_CONFIGURATION_DEVTOOLS_OPTIONS, useValue: { ...OTTER_CONFIGURATION_DEVTOOLS_DEFAULT_OPTIONS, ...options }, multi: false },\n ConfigurationDevtoolsMessageService,\n ConfigurationDevtoolsConsoleService,\n OtterConfigurationDevtools\n ]\n };\n }\n}\n","import {\n NgModule,\n} from '@angular/core';\nimport {\n LoggerModule,\n} from '@o3r/logger';\nimport {\n ConfigurationStoreModule,\n} from '../../stores/index';\n\n@NgModule({\n imports: [ConfigurationStoreModule, LoggerModule]\n})\nexport class ConfigurationBaseServiceModule {}\n","import {\n Injectable,\n} from '@angular/core';\nimport {\n select,\n Store,\n} from '@ngrx/store';\nimport {\n Configuration,\n CustomConfig,\n deepFill,\n} from '@o3r/core';\nimport {\n combineLatest,\n Observable,\n of,\n} from 'rxjs';\nimport {\n distinctUntilChanged,\n map,\n switchMap,\n take,\n} from 'rxjs/operators';\nimport {\n ConfigOverrideStore,\n selectComponentOverrideConfig,\n} from '../../stores/config-override/index';\nimport {\n computeConfiguration,\n ConfigurationStore,\n globalConfigurationId,\n selectConfigurationEntities,\n selectConfigurationForComponent,\n selectGlobalConfiguration,\n updateConfigurationEntity,\n upsertConfigurationEntities,\n upsertConfigurationEntity,\n} from '../../stores/index';\nimport {\n ConfigurationBaseServiceModule,\n} from './configuration.base.module';\n\nconst jsonStringifyDiff = (obj1: any, obj2: any) => JSON.stringify(obj1) === JSON.stringify(obj2);\n\n/**\n * Configuration service\n */\n@Injectable({\n providedIn: ConfigurationBaseServiceModule\n})\nexport class ConfigurationBaseService {\n private readonly extendedConfiguration: { [key: string]: boolean } = {};\n\n constructor(private readonly store: Store<ConfigurationStore & ConfigOverrideStore>) {}\n\n /**\n * Update a specific component config or add it to the store if does not exist\n * @param configuration to edit/add\n * @param configurationId Configuration ID\n */\n public upsertConfiguration<T extends Configuration>(configuration: T, configurationId = globalConfigurationId) {\n this.store.dispatch(upsertConfigurationEntity({ id: configurationId, configuration }));\n }\n\n /**\n * Update a specific component config\n * @param configuration Partial config to edit\n * @param configurationId Configuration ID\n */\n public updateConfiguration<T extends Partial<Configuration>>(configuration: T, configurationId = globalConfigurationId) {\n this.store.dispatch(updateConfigurationEntity({ id: configurationId, configuration }));\n }\n\n /**\n * This function will get the configuration stored in the data attribute of the html's body tag\n * @param configTagName Value used to identify the data attribute where the config is pushed in the index.html\n */\n public getConfigFromBodyTag<T extends Configuration>(configTagName = 'staticconfig') {\n const bootstrapConfigString = document.body.dataset[configTagName];\n const customConfigObject: CustomConfig<T>[] = bootstrapConfigString ? JSON.parse(bootstrapConfigString) : [];\n if (customConfigObject.length > 0) {\n this.computeConfiguration(customConfigObject);\n }\n }\n\n /**\n * Transform the custom configuration in store configuration model\n * @param customConfigObject Configuration object (extracted from body tag for static config or downloaded in case of dynamic config)\n */\n public computeConfiguration<T extends Configuration>(customConfigObject: CustomConfig<T>[]) {\n this.store.dispatch(upsertConfigurationEntities(computeConfiguration(customConfigObject)));\n }\n\n /**\n * Complete a stored configuration by adding the missing fields\n * @param extension Configuration extension to be included in the store\n * @param configurationId Configuration ID to extend\n * @param forceUpdate Force update the configuration in the store\n */\n public extendConfiguration<T extends Configuration>(extension: T, configurationId = globalConfigurationId, forceUpdate = false) {\n if (this.extendedConfiguration[configurationId] && !forceUpdate) {\n return;\n }\n this.extendedConfiguration[configurationId] = true;\n this.store.pipe(\n select(selectConfigurationEntities),\n take(1),\n map((storedConfigs) => configurationId in storedConfigs ? deepFill(extension, storedConfigs[configurationId]) : extension)\n ).subscribe((extendedConfig) => this.upsertConfiguration(extendedConfig, configurationId));\n }\n\n /**\n * Operator to get the configuration from store for a given component and merge it with the global config\n * @param id Id of the component\n * @param defaultValue Default value of the configuration\n */\n public getComponentConfig<T extends Configuration>(id: string, defaultValue: T) {\n return (source: Observable<Partial<T> | undefined>): Observable<T> => {\n const componentConfigurationFromStore$ = this.getConfig<T>(id);\n\n return source.pipe(\n switchMap((overrideConfig) => componentConfigurationFromStore$.pipe(\n map((componentConfigurationFromStore) => {\n const config = componentConfigurationFromStore ? deepFill(defaultValue, componentConfigurationFromStore) : defaultValue;\n return overrideConfig ? deepFill(config, overrideConfig) : config;\n })\n ))\n );\n };\n }\n\n /**\n * Get an observable of the configuration from store for a given component and merge it with the global config + the config overrides from the rules engine\n * @param id Id of the component\n */\n public getConfig<T extends Configuration>(id: string): Observable<T> {\n const globalConfig$ = this.store.pipe(select(selectGlobalConfiguration));\n const componentConfig$ = id === globalConfigurationId ? of({}) : this.store.pipe(select(selectConfigurationForComponent({ id })));\n const overrideConfig$ = this.store.pipe(select(selectComponentOverrideConfig(id)));\n\n return combineLatest([globalConfig$, componentConfig$, overrideConfig$]).pipe(\n map(([globalConfig, componentConfig, overrideConfig]) => ({ ...globalConfig, ...componentConfig, ...overrideConfig })),\n distinctUntilChanged(jsonStringifyDiff)\n );\n }\n}\n","import {\n Configuration,\n otterComponentInfoPropertyName,\n} from '@o3r/core';\nimport {\n ConfigurationObserver,\n} from './configuration.observer';\nimport type {\n ConfigurationSignal,\n} from './configuration.signal';\n\nconst decorator = (target: any, key: string) => {\n const privateField = `_${key}`;\n\n if (delete target[key]) {\n Object.defineProperty(target, key, {\n get: function (this: any) {\n return this[privateField];\n },\n set: function (this: any, value: ConfigurationObserver<Configuration> | ConfigurationSignal<Configuration>) {\n this[privateField] = value;\n if (this[otterComponentInfoPropertyName]) {\n this[otterComponentInfoPropertyName].configId = this[privateField].configId;\n }\n },\n enumerable: true,\n configurable: true\n });\n }\n};\n\n/**\n * Decorator to identify the component's configuration\n */\n// eslint-disable-next-line @typescript-eslint/naming-convention -- decorator should be PascalCase\nexport function O3rConfig() {\n return decorator;\n}\n","import type {\n Configuration,\n} from '@o3r/core';\nimport {\n BehaviorSubject,\n type Observable,\n type Observer,\n type Subject,\n} from 'rxjs';\nimport {\n shareReplay,\n} from 'rxjs/operators';\nimport {\n getConfiguration,\n} from '../core';\nimport {\n ConfigurationBaseService,\n} from '../services/configuration/configuration.base.service';\n\nexport class ConfigurationObserver<T extends Configuration> implements Observer<Partial<T> | undefined>, Pick<Subject<T>, 'asObservable'> {\n /** Inner observable */\n private readonly observable: Observable<T>;\n\n /** Inner subscriber */\n private readonly subscriber: BehaviorSubject<Partial<T>> = new BehaviorSubject<Partial<T>>({});\n\n /** @inheritdoc */\n public closed?: boolean;\n\n constructor(\n /** Configuration ID */\n public configId: string,\n defaultConfig: T,\n configurationService?: ConfigurationBaseService\n ) {\n if (configurationService) {\n configurationService.extendConfiguration(defaultConfig, configId);\n }\n\n this.observable = this.subscriber\n .pipe(\n configurationService ? configurationService.getComponentConfig(configId, defaultConfig) : getConfiguration(defaultConfig),\n shareReplay({ refCount: true, bufferSize: 1 })\n );\n }\n\n /** @inheritdoc */\n public next(value?: Partial<T>): void {\n this.subscriber.next(value || {});\n }\n\n /** @inheritdoc */\n public error(err: any): void {\n this.subscriber.error(err);\n this.closed = true;\n }\n\n /** @inheritdoc */\n public complete(): void {\n this.subscriber.complete();\n this.closed = true;\n }\n\n /**\n * @inheritdoc\n */\n public asObservable(): Observable<T> {\n return this.observable;\n }\n}\n","import {\n inject,\n type InputSignal,\n type Signal,\n} from '@angular/core';\nimport {\n toObservable,\n toSignal,\n} from '@angular/core/rxjs-interop';\nimport type {\n Configuration,\n} from '@o3r/core';\nimport {\n shareReplay,\n} from 'rxjs';\nimport {\n getConfiguration,\n} from '../core';\nimport {\n ConfigurationBaseService,\n} from '../services';\n\n/** Configuration signal */\nexport type ConfigurationSignal<T> = Signal<T> & { configId: string };\n\n/**\n * Get a configuration signal\n * @param configInput\n * @param configId\n * @param defaultConfig\n */\nexport function configSignal<T extends Configuration>(\n configInput: InputSignal<Partial<T> | undefined>,\n configId: string,\n defaultConfig: T\n): ConfigurationSignal<T> {\n const configurationService = inject(ConfigurationBaseService, { optional: true });\n if (configurationService) {\n configurationService.extendConfiguration(defaultConfig, configId);\n }\n\n const signal: ConfigurationSignal<T> = toSignal(\n toObservable(configInput).pipe(\n configurationService ? configurationService.getComponentConfig(configId, defaultConfig) : getConfiguration(defaultConfig),\n shareReplay({ bufferSize: 1, refCount: true })\n ),\n { initialValue: defaultConfig }\n ) as ConfigurationSignal<T>;\n signal.configId = configId;\n return signal;\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":["actions.setConfigOverride","actions.setConfigurationEntities","actions.updateConfigurationEntities","actions.upsertConfigurationEntities","actions.clearConfigurationEntities","actions.updateConfigurationEntity","actions.upsertConfigurationEntity","shareReplay"],"mappings":";;;;;;;;;;;;AAgCA;;;;AAIG;AACG,SAAU,sBAAsB,CAAC,iBAAyB,EAAA;IAC9D,MAAM,uBAAuB,GAAG,iBAAiB,CAAC,KAAK,CAAC,iBAAiB,CAAC;IAC1E,IAAI,uBAAuB,EAAE;QAC3B,OAAO;AACL,YAAA,OAAO,EAAE,uBAAuB,CAAC,MAAM,GAAG,CAAC,GAAG,uBAAuB,CAAC,CAAC,CAAC,GAAG,SAAS;AACpF,YAAA,aAAa,EAAE,uBAAuB,CAAC,MAAM,GAAG,CAAC,GAAG,uBAAuB,CAAC,CAAC,CAAC,GAAG,uBAAuB,CAAC,CAAC;SAC3G;;AAEL;AAEA;;;AAGG;AACG,SAAU,gBAAgB,CAAoC,YAAe,EAAA;AACjF,IAAA,OAAO,CAAuB,MAAiC,KAC7D,MAAM,CAAC,IAAI,CACT,GAAG,CAAC,CAAC,cAAc,KAAI;AACrB,QAAA,OAAO,QAAQ,CAAC,YAAY,EAAE,cAAc,CAAC;AAC/C,KAAC,CAAC,EACF,oBAAoB,CAAC,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,EACzF,WAAW,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAC/C;AACL;;ACjDA;AACA,MAAM,UAAU,GAAG,sBAAsB;AAEzC;;AAEG;AACU,MAAA,iBAAiB,GAAG,YAAY,CAAC,UAAU,EAAE,KAAK,EAA8C;;ACN7G;;AAEG;MACU,0BAA0B,GAAwB,EAAE,eAAe,EAAE,EAAE;AAEpF;;AAEG;AACU,MAAA,6BAA6B,GAAyD;IACjG,EAAE,CAACA,iBAAyB,EAAE,CAAC,MAAM,EAAE,OAAO,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;;AAG3E;;AAEG;AACU,MAAA,qBAAqB,GAAG,aAAa,CAChD,0BAA0B,EAC1B,GAAG,6BAA6B;;ACblC;;AAEG;AACI,MAAM,0BAA0B,GAAG;;ACA1C;MACa,6BAA6B,GAAG,IAAI,cAAc,CAA6C,gCAAgC;AAE5I;SACgB,+BAA+B,GAAA;AAC7C,IAAA,OAAO,qBAAqB;AAC9B;MAUa,yBAAyB,CAAA;IAC7B,OAAO,OAAO,CAAgC,cAA8C,EAAA;QACjG,OAAO;AACL,YAAA,QAAQ,EAAE,yBAAyB;AACnC,YAAA,SAAS,EAAE;AACT,gBAAA,EAAE,OAAO,EAAE,6BAA6B,EAAE,UAAU,EAAE,cAAc;AACrE;SACF;;iIAPQ,yBAAyB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,QAAA,EAAA,CAAA,CAAA;kIAAzB,yBAAyB,EAAA,OAAA,EAAA,CAAA,EAAA,CAAA,kBAAA,CAAA,EAAA,CAAA,CAAA;AAAzB,uBAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,mBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EA