From 2e8630e1ebcd395b9d3417cae94acdfabb5627e3 Mon Sep 17 00:00:00 2001 From: Ruben Thoms Date: Mon, 18 Nov 2024 16:33:01 +0100 Subject: [PATCH] Revert "New 2d viewer component" This reverts commit 62f0df3361b1afd955d2b20514ea432b171a0ffe. --- frontend/src/modules/2DViewer/interfaces.ts | 23 - .../src/modules/2DViewer/layers/ColorScale.ts | 59 --- .../modules/2DViewer/layers/DeltaSurface.ts | 85 ---- .../src/modules/2DViewer/layers/Dependency.ts | 210 --------- .../2DViewer/layers/DeserializationFactory.ts | 70 --- .../modules/2DViewer/layers/LayerManager.ts | 209 -------- .../modules/2DViewer/layers/LayerRegistry.ts | 18 - .../2DViewer/layers/SettingRegistry.ts | 13 - .../modules/2DViewer/layers/SettingsGroup.ts | 36 -- .../modules/2DViewer/layers/SharedSetting.ts | 118 ----- frontend/src/modules/2DViewer/layers/View.ts | 38 -- .../layers/components/ColorScaleComponent.tsx | 73 --- .../components/DeltaSurfaceComponent.tsx | 78 --- .../2DViewer/layers/components/EditName.tsx | 67 --- .../layers/components/EmptyContent.tsx | 9 - .../components/ExpandCollapseAllButton.tsx | 37 -- .../layers/components/LayerComponent.tsx | 167 ------- .../layers/components/LayersActions.tsx | 83 ---- .../layers/components/RemoveButton.tsx | 30 -- .../layers/components/SettingComponent.tsx | 113 ----- .../components/SettingsGroupComponent.tsx | 73 --- .../components/SharedSettingComponent.tsx | 89 ---- .../layers/components/ViewComponent.tsx | 77 --- .../layers/components/VisibilityToggle.tsx | 24 - .../2DViewer/layers/components/utils.tsx | 93 ---- .../layers/delegates/GroupDelegate.ts | 249 ---------- .../2DViewer/layers/delegates/ItemDelegate.ts | 153 ------ .../layers/delegates/LayerDelegate.ts | 330 ------------- .../delegates/PublishSubscribeDelegate.ts | 46 -- .../layers/delegates/SettingDelegate.ts | 341 -------------- .../delegates/SettingsContextDelegate.ts | 379 --------------- .../delegates/UnsubscribeHandlerDelegate.ts | 30 -- .../DrilledWellTrajectoriesContext.ts | 86 ---- .../DrilledWellTrajectoriesLayer.ts | 125 ----- .../DrilledWellTrajectoriesLayer/types.ts | 8 - .../DrilledWellborePicksContext.ts | 137 ------ .../DrilledWellborePicksLayer.ts | 126 ----- .../layers/DrilledWellborePicksLayer/types.ts | 9 - .../ObservedSurfaceContext.ts | 144 ------ .../ObservedSurfaceLayer.ts | 124 ----- .../layers/ObservedSurfaceLayer/types.ts | 9 - .../RealizationGridContext.ts | 180 ------- .../RealizationGridLayer.ts | 204 -------- .../layers/RealizationGridLayer/types.ts | 12 - .../RealizationPolygonsContext.ts | 126 ----- .../RealizationPolygonsLayer.ts | 124 ----- .../layers/RealizationPolygonsLayer/types.ts | 10 - .../RealizationSurfaceContext.ts | 159 ------- .../RealizationSurfaceLayer.ts | 129 ----- .../layers/RealizationSurfaceLayer/types.ts | 11 - .../StatisticalSurfaceContext.ts | 173 ------- .../StatisticalSurfaceLayer.ts | 155 ------ .../layers/StatisticalSurfaceLayer/types.ts | 14 - .../settings/DrilledWellbores.tsx | 135 ------ .../implementations/settings/Ensemble.tsx | 67 --- .../settings/GridAttribute.tsx | 54 --- .../implementations/settings/GridLayer.tsx | 102 ---- .../implementations/settings/GridName.tsx | 54 --- .../settings/PolygonsAttribute.tsx | 54 --- .../implementations/settings/PolygonsName.tsx | 54 --- .../implementations/settings/Realization.tsx | 56 --- .../implementations/settings/Sensitivity.tsx | 139 ------ .../settings/ShowGridLines.tsx | 47 -- .../settings/StatisticFunction.tsx | 60 --- .../settings/SurfaceAttribute.tsx | 54 --- .../implementations/settings/SurfaceName.tsx | 54 --- .../settings/TimeOrInterval.tsx | 84 ---- .../implementations/settings/settingsTypes.ts | 16 - .../src/modules/2DViewer/layers/interfaces.ts | 204 -------- .../modules/2DViewer/layers/queryConstants.ts | 2 - frontend/src/modules/2DViewer/layers/utils.ts | 22 - frontend/src/modules/2DViewer/loadModule.tsx | 13 - frontend/src/modules/2DViewer/preview.tsx | 8 - frontend/src/modules/2DViewer/preview.webp | Bin 38828 -> 0 bytes .../src/modules/2DViewer/registerModule.ts | 24 - .../2DViewer/settings/atoms/baseAtoms.ts | 8 - .../2DViewer/settings/atoms/derivedAtoms.ts | 31 -- .../components/layerManagerComponent.tsx | 445 ------------------ .../modules/2DViewer/settings/settings.tsx | 146 ------ frontend/src/modules/2DViewer/types.ts | 38 -- .../view/components/LayersWrapper.tsx | 154 ------ .../view/components/ReadoutBoxWrapper.tsx | 117 ----- .../view/components/ReadoutWrapper.tsx | 76 --- .../2DViewer/view/components/Toolbar.tsx | 21 - .../customDeckGlLayers/AdvancedWellsLayer.ts | 67 --- .../customDeckGlLayers/PlaceholderLayer.ts | 21 - .../customDeckGlLayers/WellborePicksLayer.ts | 136 ------ .../2DViewer/view/utils/layerFactory.ts | 363 -------------- .../2DViewer/view/utils/makeViewsAndLayers.ts | 179 ------- frontend/src/modules/2DViewer/view/view.tsx | 24 - .../_shared/components/Toolbar/index.ts | 3 - .../_shared/components/Toolbar/toolbar.tsx | 16 - .../components/Toolbar/toolbarDivider.tsx | 3 - frontend/src/modules/registerAllModules.ts | 4 +- 94 files changed, 2 insertions(+), 8638 deletions(-) delete mode 100644 frontend/src/modules/2DViewer/interfaces.ts delete mode 100644 frontend/src/modules/2DViewer/layers/ColorScale.ts delete mode 100644 frontend/src/modules/2DViewer/layers/DeltaSurface.ts delete mode 100644 frontend/src/modules/2DViewer/layers/Dependency.ts delete mode 100644 frontend/src/modules/2DViewer/layers/DeserializationFactory.ts delete mode 100644 frontend/src/modules/2DViewer/layers/LayerManager.ts delete mode 100644 frontend/src/modules/2DViewer/layers/LayerRegistry.ts delete mode 100644 frontend/src/modules/2DViewer/layers/SettingRegistry.ts delete mode 100644 frontend/src/modules/2DViewer/layers/SettingsGroup.ts delete mode 100644 frontend/src/modules/2DViewer/layers/SharedSetting.ts delete mode 100644 frontend/src/modules/2DViewer/layers/View.ts delete mode 100644 frontend/src/modules/2DViewer/layers/components/ColorScaleComponent.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/components/DeltaSurfaceComponent.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/components/EditName.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/components/EmptyContent.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/components/ExpandCollapseAllButton.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/components/LayerComponent.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/components/LayersActions.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/components/RemoveButton.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/components/SettingComponent.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/components/SettingsGroupComponent.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/components/SharedSettingComponent.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/components/ViewComponent.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/components/VisibilityToggle.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/components/utils.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/delegates/GroupDelegate.ts delete mode 100644 frontend/src/modules/2DViewer/layers/delegates/ItemDelegate.ts delete mode 100644 frontend/src/modules/2DViewer/layers/delegates/LayerDelegate.ts delete mode 100644 frontend/src/modules/2DViewer/layers/delegates/PublishSubscribeDelegate.ts delete mode 100644 frontend/src/modules/2DViewer/layers/delegates/SettingDelegate.ts delete mode 100644 frontend/src/modules/2DViewer/layers/delegates/SettingsContextDelegate.ts delete mode 100644 frontend/src/modules/2DViewer/layers/delegates/UnsubscribeHandlerDelegate.ts delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellTrajectoriesLayer/DrilledWellTrajectoriesContext.ts delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellTrajectoriesLayer/DrilledWellTrajectoriesLayer.ts delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellTrajectoriesLayer/types.ts delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellborePicksLayer/DrilledWellborePicksContext.ts delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellborePicksLayer/DrilledWellborePicksLayer.ts delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellborePicksLayer/types.ts delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/layers/ObservedSurfaceLayer/ObservedSurfaceContext.ts delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/layers/ObservedSurfaceLayer/ObservedSurfaceLayer.ts delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/layers/ObservedSurfaceLayer/types.ts delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/layers/RealizationGridLayer/RealizationGridContext.ts delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/layers/RealizationGridLayer/RealizationGridLayer.ts delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/layers/RealizationGridLayer/types.ts delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/layers/RealizationPolygonsLayer/RealizationPolygonsContext.ts delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/layers/RealizationPolygonsLayer/RealizationPolygonsLayer.ts delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/layers/RealizationPolygonsLayer/types.ts delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/layers/RealizationSurfaceLayer/RealizationSurfaceContext.ts delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/layers/RealizationSurfaceLayer/RealizationSurfaceLayer.ts delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/layers/RealizationSurfaceLayer/types.ts delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/layers/StatisticalSurfaceLayer/StatisticalSurfaceContext.ts delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/layers/StatisticalSurfaceLayer/StatisticalSurfaceLayer.ts delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/layers/StatisticalSurfaceLayer/types.ts delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/settings/DrilledWellbores.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/settings/Ensemble.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/settings/GridAttribute.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/settings/GridLayer.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/settings/GridName.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/settings/PolygonsAttribute.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/settings/PolygonsName.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/settings/Realization.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/settings/Sensitivity.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/settings/ShowGridLines.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/settings/StatisticFunction.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/settings/SurfaceAttribute.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/settings/SurfaceName.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/settings/TimeOrInterval.tsx delete mode 100644 frontend/src/modules/2DViewer/layers/implementations/settings/settingsTypes.ts delete mode 100644 frontend/src/modules/2DViewer/layers/interfaces.ts delete mode 100644 frontend/src/modules/2DViewer/layers/queryConstants.ts delete mode 100644 frontend/src/modules/2DViewer/layers/utils.ts delete mode 100644 frontend/src/modules/2DViewer/loadModule.tsx delete mode 100644 frontend/src/modules/2DViewer/preview.tsx delete mode 100644 frontend/src/modules/2DViewer/preview.webp delete mode 100644 frontend/src/modules/2DViewer/registerModule.ts delete mode 100644 frontend/src/modules/2DViewer/settings/atoms/baseAtoms.ts delete mode 100644 frontend/src/modules/2DViewer/settings/atoms/derivedAtoms.ts delete mode 100644 frontend/src/modules/2DViewer/settings/components/layerManagerComponent.tsx delete mode 100644 frontend/src/modules/2DViewer/settings/settings.tsx delete mode 100644 frontend/src/modules/2DViewer/types.ts delete mode 100644 frontend/src/modules/2DViewer/view/components/LayersWrapper.tsx delete mode 100644 frontend/src/modules/2DViewer/view/components/ReadoutBoxWrapper.tsx delete mode 100644 frontend/src/modules/2DViewer/view/components/ReadoutWrapper.tsx delete mode 100644 frontend/src/modules/2DViewer/view/components/Toolbar.tsx delete mode 100644 frontend/src/modules/2DViewer/view/customDeckGlLayers/AdvancedWellsLayer.ts delete mode 100644 frontend/src/modules/2DViewer/view/customDeckGlLayers/PlaceholderLayer.ts delete mode 100644 frontend/src/modules/2DViewer/view/customDeckGlLayers/WellborePicksLayer.ts delete mode 100644 frontend/src/modules/2DViewer/view/utils/layerFactory.ts delete mode 100644 frontend/src/modules/2DViewer/view/utils/makeViewsAndLayers.ts delete mode 100644 frontend/src/modules/2DViewer/view/view.tsx delete mode 100644 frontend/src/modules/_shared/components/Toolbar/index.ts delete mode 100644 frontend/src/modules/_shared/components/Toolbar/toolbar.tsx delete mode 100644 frontend/src/modules/_shared/components/Toolbar/toolbarDivider.tsx diff --git a/frontend/src/modules/2DViewer/interfaces.ts b/frontend/src/modules/2DViewer/interfaces.ts deleted file mode 100644 index 1c42c5ce3..000000000 --- a/frontend/src/modules/2DViewer/interfaces.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { InterfaceInitialization } from "@framework/UniDirectionalModuleComponentsInterface"; - -import { LayerManager } from "./layers/LayerManager"; -import { layerManagerAtom, preferredViewLayoutAtom } from "./settings/atoms/baseAtoms"; -import { PreferredViewLayout } from "./types"; - -export type SettingsToViewInterface = { - layerManager: LayerManager | null; - preferredViewLayout: PreferredViewLayout; -}; - -export type Interfaces = { - settingsToView: SettingsToViewInterface; -}; - -export const settingsToViewInterfaceInitialization: InterfaceInitialization = { - layerManager: (get) => { - return get(layerManagerAtom); - }, - preferredViewLayout: (get) => { - return get(preferredViewLayoutAtom); - }, -}; diff --git a/frontend/src/modules/2DViewer/layers/ColorScale.ts b/frontend/src/modules/2DViewer/layers/ColorScale.ts deleted file mode 100644 index 6463ac651..000000000 --- a/frontend/src/modules/2DViewer/layers/ColorScale.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { defaultContinuousSequentialColorPalettes } from "@framework/utils/colorPalettes"; -import { ColorScaleGradientType, ColorScaleType } from "@lib/utils/ColorScale"; -import { ColorScale as ColorScaleImpl } from "@lib/utils/ColorScale"; - -import { LayerManager, LayerManagerTopic } from "./LayerManager"; -import { ItemDelegate } from "./delegates/ItemDelegate"; -import { Item, SerializedColorScale } from "./interfaces"; - -export class ColorScale implements Item { - private _itemDelegate: ItemDelegate; - private _colorScale: ColorScaleImpl = new ColorScaleImpl({ - colorPalette: defaultContinuousSequentialColorPalettes[0], - gradientType: ColorScaleGradientType.Sequential, - type: ColorScaleType.Continuous, - steps: 10, - }); - private _areBoundariesUserDefined: boolean = false; - - constructor(name: string, layerManager: LayerManager) { - this._itemDelegate = new ItemDelegate(name, layerManager); - } - - getItemDelegate(): ItemDelegate { - return this._itemDelegate; - } - - getColorScale(): ColorScaleImpl { - return this._colorScale; - } - - setColorScale(colorScale: ColorScaleImpl): void { - this._colorScale = colorScale; - this.getItemDelegate().getLayerManager()?.publishTopic(LayerManagerTopic.LAYER_DATA_REVISION); - } - - getAreBoundariesUserDefined(): boolean { - return this._areBoundariesUserDefined; - } - - setAreBoundariesUserDefined(areBoundariesUserDefined: boolean): void { - this._areBoundariesUserDefined = areBoundariesUserDefined; - this.getItemDelegate().getLayerManager()?.publishTopic(LayerManagerTopic.LAYER_DATA_REVISION); - } - - serializeState(): SerializedColorScale { - return { - ...this._itemDelegate.serializeState(), - type: "color-scale", - colorScale: this._colorScale.serialize(), - userDefinedBoundaries: this._areBoundariesUserDefined, - }; - } - - deserializeState(serialized: SerializedColorScale): void { - this._itemDelegate.deserializeState(serialized); - this._colorScale = ColorScaleImpl.fromSerialized(serialized.colorScale); - this._areBoundariesUserDefined = serialized.userDefinedBoundaries; - } -} diff --git a/frontend/src/modules/2DViewer/layers/DeltaSurface.ts b/frontend/src/modules/2DViewer/layers/DeltaSurface.ts deleted file mode 100644 index e7a9d5f8e..000000000 --- a/frontend/src/modules/2DViewer/layers/DeltaSurface.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { LayerManager } from "./LayerManager"; -import { GroupDelegate, GroupDelegateTopic } from "./delegates/GroupDelegate"; -import { ItemDelegate } from "./delegates/ItemDelegate"; -import { LayerDelegate } from "./delegates/LayerDelegate"; -import { SettingsContextDelegateTopic } from "./delegates/SettingsContextDelegate"; -import { UnsubscribeHandlerDelegate } from "./delegates/UnsubscribeHandlerDelegate"; -import { Group, SerializedDeltaSurface, instanceofLayer } from "./interfaces"; - -export class DeltaSurface implements Group { - private _itemDelegate: ItemDelegate; - private _groupDelegate: GroupDelegate; - private _unsubscribeHandler: UnsubscribeHandlerDelegate = new UnsubscribeHandlerDelegate(); - private _childrenLayerDelegateSet: Set> = new Set(); - - constructor(name: string, layerManager: LayerManager) { - this._groupDelegate = new GroupDelegate(this); - - this._unsubscribeHandler.registerUnsubscribeFunction( - "children", - this._groupDelegate.getPublishSubscribeDelegate().makeSubscriberFunction(GroupDelegateTopic.CHILDREN)( - () => { - this.handleChildrenChange(); - } - ) - ); - - this._groupDelegate.setColor("rgb(220, 210, 180)"); - this._itemDelegate = new ItemDelegate(name, layerManager); - } - - private handleChildrenChange(): void { - this._unsubscribeHandler.unsubscribe("layer-delegates"); - - for (const layerDelegate of this._childrenLayerDelegateSet) { - layerDelegate.setIsSubordinated(false); - } - - this._childrenLayerDelegateSet.clear(); - - for (const child of this._groupDelegate.getChildren()) { - if (instanceofLayer(child)) { - child.getLayerDelegate().setIsSubordinated(true); - const layerDelegate = child.getLayerDelegate(); - this._childrenLayerDelegateSet.add(layerDelegate); - - this._unsubscribeHandler.registerUnsubscribeFunction( - "layer-delegates", - layerDelegate - .getSettingsContext() - .getDelegate() - .getPublishSubscribeDelegate() - .makeSubscriberFunction(SettingsContextDelegateTopic.SETTINGS_CHANGED)(() => { - this.handleSettingsChange(); - }) - ); - } - } - } - - private handleSettingsChange(): void { - console.debug("Settings changed - would refetch data"); - // Fetch data - } - - getItemDelegate(): ItemDelegate { - return this._itemDelegate; - } - - getGroupDelegate(): GroupDelegate { - return this._groupDelegate; - } - - deserializeState(serialized: SerializedDeltaSurface): void { - this._itemDelegate.deserializeState(serialized); - this._groupDelegate.deserializeChildren(serialized.children); - } - - serializeState(): SerializedDeltaSurface { - return { - ...this._itemDelegate.serializeState(), - type: "delta-surface", - children: this.getGroupDelegate().serializeChildren(), - }; - } -} diff --git a/frontend/src/modules/2DViewer/layers/Dependency.ts b/frontend/src/modules/2DViewer/layers/Dependency.ts deleted file mode 100644 index af2904299..000000000 --- a/frontend/src/modules/2DViewer/layers/Dependency.ts +++ /dev/null @@ -1,210 +0,0 @@ -import { isCancelledError } from "@tanstack/react-query"; - -import { isEqual } from "lodash"; - -import { GlobalSettings } from "./LayerManager"; -import { SettingsContextDelegate } from "./delegates/SettingsContextDelegate"; -import { Settings, UpdateFunc } from "./interfaces"; - -export class Dependency { - private _updateFunc: UpdateFunc; - private _dependencies: Set<(value: Awaited | null) => void> = new Set(); - private _loadingDependencies: Set<(loading: boolean, hasDependencies: boolean) => void> = new Set(); - - private _contextDelegate: SettingsContextDelegate; - - private _makeSettingGetter: (key: K, handler: (value: TSettings[K]) => void) => void; - private _makeGlobalSettingGetter: ( - key: K, - handler: (value: GlobalSettings[K]) => void - ) => void; - private _cachedSettingsMap: Map = new Map(); - private _cachedGlobalSettingsMap: Map = new Map(); - private _cachedDependenciesMap: Map, any> = new Map(); - private _cachedValue: Awaited | null = null; - private _abortController: AbortController | null = null; - private _isInitialized = false; - private _numParentDependencies = 0; - private _numChildDependencies = 0; - - constructor( - contextDelegate: SettingsContextDelegate, - updateFunc: UpdateFunc, - makeSettingGetter: (key: K, handler: (value: TSettings[K]) => void) => void, - makeGlobalSettingGetter: ( - key: K, - handler: (value: GlobalSettings[K]) => void - ) => void - ) { - this._contextDelegate = contextDelegate; - this._updateFunc = updateFunc; - this._makeSettingGetter = makeSettingGetter; - this._makeGlobalSettingGetter = makeGlobalSettingGetter; - - this.getGlobalSetting = this.getGlobalSetting.bind(this); - this.getLocalSetting = this.getLocalSetting.bind(this); - this.getHelperDependency = this.getHelperDependency.bind(this); - } - - hasChildDependencies(): boolean { - return this._numChildDependencies > 0; - } - - getValue(): Awaited | null { - return this._cachedValue; - } - - subscribe(callback: (value: Awaited | null) => void, childDependency: boolean = false): () => void { - this._dependencies.add(callback); - - if (childDependency) { - this._numChildDependencies++; - } - - return () => { - this._dependencies.delete(callback); - if (childDependency) { - this._numChildDependencies--; - } - }; - } - - subscribeLoading(callback: (loading: boolean, hasDependencies: boolean) => void): () => void { - this._loadingDependencies.add(callback); - - return () => { - this._loadingDependencies.delete(callback); - }; - } - - private getLocalSetting(settingName: K): TSettings[K] { - if (!this._isInitialized) { - this._numParentDependencies++; - } - - if (this._cachedSettingsMap.has(settingName as string)) { - return this._cachedSettingsMap.get(settingName as string); - } - - this._makeSettingGetter(settingName, (value) => { - this._cachedSettingsMap.set(settingName as string, value); - this.callUpdateFunc(); - }); - - this._cachedSettingsMap.set( - settingName as string, - this._contextDelegate.getSettings()[settingName].getDelegate().getValue() - ); - return this._cachedSettingsMap.get(settingName as string); - } - - private setLoadingState(loading: boolean) { - for (const callback of this._loadingDependencies) { - callback(loading, this.hasChildDependencies()); - } - } - - private getGlobalSetting(settingName: K): GlobalSettings[K] { - if (this._cachedGlobalSettingsMap.has(settingName as string)) { - return this._cachedGlobalSettingsMap.get(settingName as string); - } - - this._makeGlobalSettingGetter(settingName, (value) => { - this._cachedGlobalSettingsMap.set(settingName as string, value); - this.callUpdateFunc(); - }); - - this._cachedGlobalSettingsMap.set( - settingName as string, - this._contextDelegate.getLayerManager().getGlobalSetting(settingName) - ); - return this._cachedGlobalSettingsMap.get(settingName as string); - } - - private getHelperDependency(dep: Dependency): Awaited | null { - if (!this._isInitialized) { - this._numParentDependencies++; - } - - if (this._cachedDependenciesMap.has(dep)) { - return this._cachedDependenciesMap.get(dep); - } - - const value = dep.getValue(); - this._cachedDependenciesMap.set(dep, value); - - dep.subscribe((newValue) => { - this._cachedDependenciesMap.set(dep, newValue); - this.callUpdateFunc(); - }, true); - - dep.subscribeLoading((loading) => { - if (loading) { - this.setLoadingState(true); - } - // Not subscribing to loading state false as it will - // be set when this dependency is updated - // #Waterfall - }); - - return value; - } - - async initialize() { - this._abortController = new AbortController(); - - // Establishing subscriptions - await this._updateFunc({ - getLocalSetting: this.getLocalSetting, - getGlobalSetting: this.getGlobalSetting, - getHelperDependency: this.getHelperDependency, - abortSignal: this._abortController.signal, - }); - - // If there are no dependencies, we can call the update function - if (this._numParentDependencies === 0) { - await this.callUpdateFunc(); - } - - this._isInitialized = true; - } - - async callUpdateFunc() { - if (this._abortController) { - this._abortController.abort(); - this._abortController = null; - } - - this._abortController = new AbortController(); - - this.setLoadingState(true); - - let newValue: Awaited | null = null; - try { - newValue = await this._updateFunc({ - getLocalSetting: this.getLocalSetting, - getGlobalSetting: this.getGlobalSetting, - getHelperDependency: this.getHelperDependency, - abortSignal: this._abortController.signal, - }); - } catch (e: any) { - if (!isCancelledError(e)) { - this.applyNewValue(null); - return; - } - return; - } - - this.applyNewValue(newValue); - } - - applyNewValue(newValue: Awaited | null) { - this.setLoadingState(false); - if (!isEqual(newValue, this._cachedValue) || newValue === null) { - this._cachedValue = newValue; - for (const callback of this._dependencies) { - callback(newValue); - } - } - } -} diff --git a/frontend/src/modules/2DViewer/layers/DeserializationFactory.ts b/frontend/src/modules/2DViewer/layers/DeserializationFactory.ts deleted file mode 100644 index 4f14b1477..000000000 --- a/frontend/src/modules/2DViewer/layers/DeserializationFactory.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { ColorScale } from "./ColorScale"; -import { LayerManager } from "./LayerManager"; -import { LayerRegistry } from "./LayerRegistry"; -import { SettingRegistry } from "./SettingRegistry"; -import { SettingsGroup } from "./SettingsGroup"; -import { SharedSetting } from "./SharedSetting"; -import { View } from "./View"; -import { - Item, - SerializedColorScale, - SerializedItem, - SerializedLayer, - SerializedSettingsGroup, - SerializedSharedSetting, - SerializedView, -} from "./interfaces"; - -export class DeserializationFactory { - private _layerManager: LayerManager; - - constructor(layerManager: LayerManager) { - this._layerManager = layerManager; - } - - makeItem(serialized: SerializedItem): Item { - if (serialized.type === "layer") { - const serializedLayer = serialized as SerializedLayer; - const layer = LayerRegistry.makeLayer(serializedLayer.layerClass, this._layerManager); - layer.getLayerDelegate().deserializeState(serializedLayer); - layer.getItemDelegate().setId(serializedLayer.id); - layer.getItemDelegate().setName(serializedLayer.name); - return layer; - } - - if (serialized.type === "view") { - const serializedView = serialized as SerializedView; - const view = new View(serializedView.name, this._layerManager, serializedView.color); - view.deserializeState(serializedView); - return view; - } - - if (serialized.type === "settings-group") { - const serializedSettingsGroup = serialized as SerializedSettingsGroup; - const settingsGroup = new SettingsGroup(serializedSettingsGroup.name, this._layerManager); - settingsGroup.deserializeState(serializedSettingsGroup); - return settingsGroup; - } - - if (serialized.type === "color-scale") { - const serializedColorScale = serialized as SerializedColorScale; - const colorScale = new ColorScale(serializedColorScale.name, this._layerManager); - colorScale.deserializeState(serializedColorScale); - return colorScale; - } - - if (serialized.type === "delta-surface") { - throw new Error("DeltaSurface deserialization not implemented"); - } - - if (serialized.type === "shared-setting") { - const serializedSharedSetting = serialized as SerializedSharedSetting; - const wrappedSetting = SettingRegistry.makeSetting(serializedSharedSetting.wrappedSettingClass); - const setting = new SharedSetting(wrappedSetting, this._layerManager); - setting.deserializeState(serializedSharedSetting); - return setting; - } - - throw new Error(`Unknown serialized item type: ${serialized.type}`); - } -} diff --git a/frontend/src/modules/2DViewer/layers/LayerManager.ts b/frontend/src/modules/2DViewer/layers/LayerManager.ts deleted file mode 100644 index dc9c7cfab..000000000 --- a/frontend/src/modules/2DViewer/layers/LayerManager.ts +++ /dev/null @@ -1,209 +0,0 @@ -import { Ensemble } from "@framework/Ensemble"; -import { - EnsembleRealizationFilterFunction, - WorkbenchSession, - WorkbenchSessionEvent, - createEnsembleRealizationFilterFuncForWorkbenchSession, -} from "@framework/WorkbenchSession"; -import { WorkbenchSettings } from "@framework/WorkbenchSettings"; -import { QueryClient } from "@tanstack/react-query"; - -import { isEqual } from "lodash"; - -import { GroupDelegate, GroupDelegateTopic } from "./delegates/GroupDelegate"; -import { ItemDelegate } from "./delegates/ItemDelegate"; -import { PublishSubscribe, PublishSubscribeDelegate } from "./delegates/PublishSubscribeDelegate"; -import { UnsubscribeHandlerDelegate } from "./delegates/UnsubscribeHandlerDelegate"; -import { Group, Item, SerializedLayerManager } from "./interfaces"; - -export enum LayerManagerTopic { - ITEMS_CHANGED = "ITEMS_CHANGED", - SETTINGS_CHANGED = "SETTINGS_CHANGED", - AVAILABLE_SETTINGS_CHANGED = "AVAILABLE_SETTINGS_CHANGED", - LAYER_DATA_REVISION = "LAYER_DATA_REVISION", - GLOBAL_SETTINGS_CHANGED = "GLOBAL_SETTINGS_CHANGED", - SHARED_SETTINGS_CHANGED = "SHARED_SETTINGS_CHANGED", -} - -export type LayerManagerTopicPayload = { - [LayerManagerTopic.ITEMS_CHANGED]: Item[]; - [LayerManagerTopic.SETTINGS_CHANGED]: void; - [LayerManagerTopic.AVAILABLE_SETTINGS_CHANGED]: void; - [LayerManagerTopic.LAYER_DATA_REVISION]: number; - [LayerManagerTopic.GLOBAL_SETTINGS_CHANGED]: void; - [LayerManagerTopic.SHARED_SETTINGS_CHANGED]: void; -}; - -export type GlobalSettings = { - fieldId: string | null; - ensembles: readonly Ensemble[]; - realizationFilterFunction: EnsembleRealizationFilterFunction; -}; - -export class LayerManager implements Group, PublishSubscribe { - private _workbenchSession: WorkbenchSession; - private _workbenchSettings: WorkbenchSettings; - private _groupDelegate: GroupDelegate; - private _queryClient: QueryClient; - private _publishSubscribeDelegate = new PublishSubscribeDelegate(); - private _itemDelegate: ItemDelegate; - private _layerDataRevision: number = 0; - private _globalSettings: GlobalSettings; - private _subscriptionsHandler = new UnsubscribeHandlerDelegate(); - private _deserializing = false; - - constructor(workbenchSession: WorkbenchSession, workbenchSettings: WorkbenchSettings, queryClient: QueryClient) { - this._workbenchSession = workbenchSession; - this._workbenchSettings = workbenchSettings; - this._queryClient = queryClient; - this._itemDelegate = new ItemDelegate("LayerManager", this); - this._groupDelegate = new GroupDelegate(this); - - this._globalSettings = this.initializeGlobalSettings(); - - this._subscriptionsHandler.registerUnsubscribeFunction( - "workbenchSession", - this._workbenchSession.subscribe( - WorkbenchSessionEvent.EnsembleSetChanged, - this.handleEnsembleSetChanged.bind(this) - ) - ); - this._subscriptionsHandler.registerUnsubscribeFunction( - "workbenchSession", - this._workbenchSession.subscribe( - WorkbenchSessionEvent.RealizationFilterSetChanged, - this.handleRealizationFilterSetChanged.bind(this) - ) - ); - this._subscriptionsHandler.registerUnsubscribeFunction( - "groupDelegate", - this._groupDelegate - .getPublishSubscribeDelegate() - .makeSubscriberFunction(GroupDelegateTopic.TREE_REVISION_NUMBER)(() => { - this.publishTopic(LayerManagerTopic.LAYER_DATA_REVISION); - this.publishTopic(LayerManagerTopic.ITEMS_CHANGED); - }) - ); - } - - getItemDelegate(): ItemDelegate { - return this._itemDelegate; - } - - getGroupDelegate(): GroupDelegate { - return this._groupDelegate; - } - - updateGlobalSetting(key: T, value: GlobalSettings[T]): void { - if (isEqual(this._globalSettings[key], value)) { - return; - } - - this._globalSettings[key] = value; - this.publishTopic(LayerManagerTopic.GLOBAL_SETTINGS_CHANGED); - } - - getGlobalSetting(key: T): GlobalSettings[T] { - return this._globalSettings[key]; - } - - publishTopic(topic: LayerManagerTopic): void { - if (this._deserializing) { - return; - } - - if (topic === LayerManagerTopic.LAYER_DATA_REVISION) { - this._layerDataRevision++; - } - - this._publishSubscribeDelegate.notifySubscribers(topic); - } - - getWorkbenchSession(): WorkbenchSession { - return this._workbenchSession; - } - - getQueryClient(): QueryClient { - return this._queryClient; - } - - getWorkbenchSettings(): WorkbenchSettings { - return this._workbenchSettings; - } - - makeSnapshotGetter(topic: T): () => LayerManagerTopicPayload[T] { - const snapshotGetter = (): any => { - if (topic === LayerManagerTopic.ITEMS_CHANGED) { - return this._groupDelegate.getChildren(); - } - if (topic === LayerManagerTopic.SETTINGS_CHANGED) { - return; - } - if (topic === LayerManagerTopic.AVAILABLE_SETTINGS_CHANGED) { - return; - } - if (topic === LayerManagerTopic.LAYER_DATA_REVISION) { - return this._layerDataRevision; - } - if (topic === LayerManagerTopic.GLOBAL_SETTINGS_CHANGED) { - return this._globalSettings; - } - if (topic === LayerManagerTopic.SHARED_SETTINGS_CHANGED) { - return; - } - }; - - return snapshotGetter; - } - - getPublishSubscribeDelegate(): PublishSubscribeDelegate { - return this._publishSubscribeDelegate; - } - - beforeDestroy() { - this._subscriptionsHandler.unsubscribeAll(); - } - - serializeState(): SerializedLayerManager { - const itemState = this._itemDelegate.serializeState(); - return { - ...itemState, - type: "layer-manager", - children: this._groupDelegate.serializeChildren(), - }; - } - - deserializeState(serializedState: SerializedLayerManager): void { - this._deserializing = true; - this._itemDelegate.deserializeState(serializedState); - this._groupDelegate.deserializeChildren(serializedState.children); - this._deserializing = false; - - this.publishTopic(LayerManagerTopic.ITEMS_CHANGED); - this.publishTopic(LayerManagerTopic.GLOBAL_SETTINGS_CHANGED); - } - - private initializeGlobalSettings(): GlobalSettings { - const ensembles = this._workbenchSession.getEnsembleSet().getEnsembleArr(); - return { - fieldId: null, - ensembles, - realizationFilterFunction: createEnsembleRealizationFilterFuncForWorkbenchSession(this._workbenchSession), - }; - } - - private handleRealizationFilterSetChanged() { - this._globalSettings.realizationFilterFunction = createEnsembleRealizationFilterFuncForWorkbenchSession( - this._workbenchSession - ); - - this.publishTopic(LayerManagerTopic.GLOBAL_SETTINGS_CHANGED); - } - - private handleEnsembleSetChanged() { - const ensembles = this._workbenchSession.getEnsembleSet().getEnsembleArr(); - this._globalSettings.ensembles = ensembles; - - this.publishTopic(LayerManagerTopic.GLOBAL_SETTINGS_CHANGED); - } -} diff --git a/frontend/src/modules/2DViewer/layers/LayerRegistry.ts b/frontend/src/modules/2DViewer/layers/LayerRegistry.ts deleted file mode 100644 index cb1455e94..000000000 --- a/frontend/src/modules/2DViewer/layers/LayerRegistry.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { LayerManager } from "./LayerManager"; -import { Layer } from "./interfaces"; - -export class LayerRegistry { - private static _registeredLayers: Map }> = new Map(); - - static registerLayer(ctor: { new (layerManager: LayerManager): Layer }): void { - this._registeredLayers.set(ctor.name, ctor); - } - - static makeLayer(layerName: string, layerManager: LayerManager): Layer { - const Layer = this._registeredLayers.get(layerName); - if (!Layer) { - throw new Error(`Layer ${layerName} not found`); - } - return new Layer(layerManager); - } -} diff --git a/frontend/src/modules/2DViewer/layers/SettingRegistry.ts b/frontend/src/modules/2DViewer/layers/SettingRegistry.ts deleted file mode 100644 index b8e8b8a76..000000000 --- a/frontend/src/modules/2DViewer/layers/SettingRegistry.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Setting } from "./interfaces"; - -export class SettingRegistry { - private static _registeredSettings: Record }> = {}; - - static registerSetting(ctor: { new (): Setting }): void { - this._registeredSettings[ctor.name] = ctor; - } - - static makeSetting(settingName: string): Setting { - return new this._registeredSettings[settingName](); - } -} diff --git a/frontend/src/modules/2DViewer/layers/SettingsGroup.ts b/frontend/src/modules/2DViewer/layers/SettingsGroup.ts deleted file mode 100644 index 7ff819b2c..000000000 --- a/frontend/src/modules/2DViewer/layers/SettingsGroup.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { LayerManager } from "./LayerManager"; -import { GroupDelegate } from "./delegates/GroupDelegate"; -import { ItemDelegate } from "./delegates/ItemDelegate"; -import { Group, SerializedSettingsGroup } from "./interfaces"; - -export class SettingsGroup implements Group { - private _itemDelegate: ItemDelegate; - private _groupDelegate: GroupDelegate; - - constructor(name: string, layerManager: LayerManager) { - this._groupDelegate = new GroupDelegate(this); - this._groupDelegate.setColor("rgb(196 181 253)"); - this._itemDelegate = new ItemDelegate(name, layerManager); - } - - getItemDelegate(): ItemDelegate { - return this._itemDelegate; - } - - getGroupDelegate(): GroupDelegate { - return this._groupDelegate; - } - - serializeState(): SerializedSettingsGroup { - return { - ...this._itemDelegate.serializeState(), - type: "settings-group", - children: this._groupDelegate.serializeChildren(), - }; - } - - deserializeState(serialized: SerializedSettingsGroup) { - this._itemDelegate.deserializeState(serialized); - this._groupDelegate.deserializeChildren(serialized.children); - } -} diff --git a/frontend/src/modules/2DViewer/layers/SharedSetting.ts b/frontend/src/modules/2DViewer/layers/SharedSetting.ts deleted file mode 100644 index 7446c0c42..000000000 --- a/frontend/src/modules/2DViewer/layers/SharedSetting.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { LayerManager, LayerManagerTopic } from "./LayerManager"; -import { ItemDelegate } from "./delegates/ItemDelegate"; -import { SettingTopic } from "./delegates/SettingDelegate"; -import { UnsubscribeHandlerDelegate } from "./delegates/UnsubscribeHandlerDelegate"; -import { Item, Layer, SerializedSharedSetting, Setting, instanceofLayer } from "./interfaces"; - -export class SharedSetting implements Item { - private _wrappedSetting: Setting; - private _unsubscribeHandler: UnsubscribeHandlerDelegate = new UnsubscribeHandlerDelegate(); - private _itemDelegate: ItemDelegate; - - constructor(wrappedSetting: Setting, layerManager: LayerManager) { - this._wrappedSetting = wrappedSetting; - - this._unsubscribeHandler.registerUnsubscribeFunction( - "setting", - this._wrappedSetting - .getDelegate() - .getPublishSubscribeDelegate() - .makeSubscriberFunction(SettingTopic.VALUE_CHANGED)(() => { - this.publishValueChange(); - }) - ); - this._itemDelegate = new ItemDelegate(wrappedSetting.getLabel(), layerManager); - - this._unsubscribeHandler.registerUnsubscribeFunction( - "layer-manager", - layerManager.getPublishSubscribeDelegate().makeSubscriberFunction(LayerManagerTopic.ITEMS_CHANGED)(() => { - this.makeIntersectionOfAvailableValues(); - }) - ); - this._unsubscribeHandler.registerUnsubscribeFunction( - "layer-manager", - layerManager.getPublishSubscribeDelegate().makeSubscriberFunction(LayerManagerTopic.SETTINGS_CHANGED)( - () => { - this.makeIntersectionOfAvailableValues(); - } - ) - ); - this._unsubscribeHandler.registerUnsubscribeFunction( - "layer-manager", - layerManager - .getPublishSubscribeDelegate() - .makeSubscriberFunction(LayerManagerTopic.AVAILABLE_SETTINGS_CHANGED)(() => { - this.makeIntersectionOfAvailableValues(); - }) - ); - } - - getItemDelegate(): ItemDelegate { - return this._itemDelegate; - } - - publishValueChange(): void { - const layerManager = this._itemDelegate.getLayerManager(); - if (layerManager) { - layerManager.publishTopic(LayerManagerTopic.SHARED_SETTINGS_CHANGED); - } - } - - getWrappedSetting(): Setting { - return this._wrappedSetting; - } - - private makeIntersectionOfAvailableValues(): void { - const parentGroup = this._itemDelegate.getParentGroup(); - if (!parentGroup) { - return; - } - - const layers = parentGroup.getDescendantItems((item) => instanceofLayer(item)) as Layer[]; - let index = 0; - let availableValues: any[] = []; - for (const item of layers) { - const setting = item.getLayerDelegate().getSettingsContext().getDelegate().getSettings()[ - this._wrappedSetting.getType() - ]; - if (setting) { - if (setting.getDelegate().isLoading()) { - this._wrappedSetting.getDelegate().setLoading(true); - return; - } - if (index === 0) { - availableValues.push(...setting.getDelegate().getAvailableValues()); - } else { - availableValues = availableValues.filter((value) => - setting.getDelegate().getAvailableValues().includes(value) - ); - } - index++; - } - } - - this._wrappedSetting.getDelegate().setLoading(false); - - this._wrappedSetting.getDelegate().setAvailableValues(availableValues); - this.publishValueChange(); - } - - serializeState(): SerializedSharedSetting { - return { - ...this._itemDelegate.serializeState(), - type: "shared-setting", - wrappedSettingClass: this._wrappedSetting.constructor.name, - settingType: this._wrappedSetting.getType(), - value: this._wrappedSetting.getDelegate().serializeValue(), - }; - } - - deserializeState(serialized: SerializedSharedSetting): void { - this._itemDelegate.deserializeState(serialized); - this._wrappedSetting.getDelegate().deserializeValue(serialized.value); - } - - beforeDestroy(): void { - this._unsubscribeHandler.unsubscribeAll(); - } -} diff --git a/frontend/src/modules/2DViewer/layers/View.ts b/frontend/src/modules/2DViewer/layers/View.ts deleted file mode 100644 index f39c308fa..000000000 --- a/frontend/src/modules/2DViewer/layers/View.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { LayerManager } from "./LayerManager"; -import { GroupDelegate } from "./delegates/GroupDelegate"; -import { ItemDelegate } from "./delegates/ItemDelegate"; -import { Group, SerializedView } from "./interfaces"; - -export class View implements Group { - private _itemDelegate: ItemDelegate; - private _groupDelegate: GroupDelegate; - - constructor(name: string, layerManager: LayerManager, color: string | null = null) { - this._groupDelegate = new GroupDelegate(this); - this._groupDelegate.setColor(color); - this._itemDelegate = new ItemDelegate(name, layerManager); - } - - getItemDelegate(): ItemDelegate { - return this._itemDelegate; - } - - getGroupDelegate(): GroupDelegate { - return this._groupDelegate; - } - - serializeState(): SerializedView { - return { - ...this._itemDelegate.serializeState(), - type: "view", - color: this._groupDelegate.getColor() ?? "", - children: this._groupDelegate.serializeChildren(), - }; - } - - deserializeState(serialized: SerializedView) { - this._itemDelegate.deserializeState(serialized); - this._groupDelegate.setColor(serialized.color); - this._groupDelegate.deserializeChildren(serialized.children); - } -} diff --git a/frontend/src/modules/2DViewer/layers/components/ColorScaleComponent.tsx b/frontend/src/modules/2DViewer/layers/components/ColorScaleComponent.tsx deleted file mode 100644 index 91836a135..000000000 --- a/frontend/src/modules/2DViewer/layers/components/ColorScaleComponent.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import React from "react"; - -import { Icon } from "@equinor/eds-core-react"; -import { color_palette } from "@equinor/eds-icons"; -import { DenseIconButton } from "@lib/components/DenseIconButton"; -import { SortableListItem } from "@lib/components/SortableList"; -import { ColorScale as ColorScaleImpl } from "@lib/utils/ColorScale"; -import { resolveClassNames } from "@lib/utils/resolveClassNames"; -import { ColorScaleSelector } from "@modules/_shared/components/ColorScaleSelector/colorScaleSelector"; -import { ExpandLess, ExpandMore } from "@mui/icons-material"; - -import { RemoveButton } from "./RemoveButton"; - -import { ColorScale } from "../ColorScale"; -import { ItemDelegateTopic } from "../delegates/ItemDelegate"; -import { usePublishSubscribeTopicValue } from "../delegates/PublishSubscribeDelegate"; - -export type ColorScaleComponentProps = { - colorScale: ColorScale; -}; - -export function ColorScaleComponent(props: ColorScaleComponentProps): React.ReactNode { - const workbenchSettings = props.colorScale.getItemDelegate().getLayerManager()?.getWorkbenchSettings(); - const isExpanded = usePublishSubscribeTopicValue(props.colorScale.getItemDelegate(), ItemDelegateTopic.EXPANDED); - - function handleColorScaleChange(newColorScale: ColorScaleImpl, areBoundariesUserDefined: boolean): void { - props.colorScale.setColorScale(newColorScale); - props.colorScale.setAreBoundariesUserDefined(areBoundariesUserDefined); - } - - function makeColorScaleSelector(): React.ReactNode { - if (!workbenchSettings) { - return "No layer manager set."; - } - - return ( - - ); - } - - function handleToggleExpanded(): void { - props.colorScale.getItemDelegate().setExpanded(!isExpanded); - } - - return ( - Color scale} - startAdornment={ -
- - {isExpanded ? : } - - -
- } - endAdornment={} - > -
- {makeColorScaleSelector()} -
-
- ); -} diff --git a/frontend/src/modules/2DViewer/layers/components/DeltaSurfaceComponent.tsx b/frontend/src/modules/2DViewer/layers/components/DeltaSurfaceComponent.tsx deleted file mode 100644 index 0dfa0eb61..000000000 --- a/frontend/src/modules/2DViewer/layers/components/DeltaSurfaceComponent.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import { SortableListGroup } from "@lib/components/SortableList"; - -import { EditName } from "./EditName"; -import { EmptyContent } from "./EmptyContent"; -import { ExpandCollapseAllButton } from "./ExpandCollapseAllButton"; -import { LayersActionGroup, LayersActions } from "./LayersActions"; -import { RemoveButton } from "./RemoveButton"; -import { VisibilityToggle } from "./VisibilityToggle"; -import { makeComponent } from "./utils"; - -import { DeltaSurface } from "../DeltaSurface"; -import { GroupDelegateTopic } from "../delegates/GroupDelegate"; -import { ItemDelegateTopic } from "../delegates/ItemDelegate"; -import { usePublishSubscribeTopicValue } from "../delegates/PublishSubscribeDelegate"; -import { Group, Item, instanceofLayer } from "../interfaces"; - -export type DeltaSurfaceComponentProps = { - deltaSurface: DeltaSurface; - actions?: LayersActionGroup[]; - onActionClick?: (actionIdentifier: string, group: Group) => void; -}; - -export function DeltaSurfaceComponent(props: DeltaSurfaceComponentProps): React.ReactNode { - const children = usePublishSubscribeTopicValue(props.deltaSurface.getGroupDelegate(), GroupDelegateTopic.CHILDREN); - const isExpanded = usePublishSubscribeTopicValue(props.deltaSurface.getItemDelegate(), ItemDelegateTopic.EXPANDED); - const color = props.deltaSurface.getGroupDelegate().getColor(); - - function handleActionClick(actionIdentifier: string) { - if (props.onActionClick) { - props.onActionClick(actionIdentifier, props.deltaSurface); - } - } - - function makeEndAdornment() { - const adornment: React.ReactNode[] = []; - if ( - props.actions && - props.deltaSurface.getGroupDelegate().findChildren((item) => instanceofLayer(item)).length < 2 - ) { - adornment.push( - - ); - } - adornment.push(); - adornment.push(); - return adornment; - } - - return ( - } - contentStyle={{ - backgroundColor: color ?? undefined, - }} - headerStyle={{ - backgroundColor: color ?? undefined, - }} - startAdornment={ -
- -
- } - endAdornment={<>{makeEndAdornment()}} - contentWhenEmpty={ - Drag two surface layers inside to calculate the difference between them. - } - expanded={isExpanded} - > - {children.map((child: Item) => makeComponent(child, props.actions, props.onActionClick))} -
- ); -} diff --git a/frontend/src/modules/2DViewer/layers/components/EditName.tsx b/frontend/src/modules/2DViewer/layers/components/EditName.tsx deleted file mode 100644 index b4ec032ee..000000000 --- a/frontend/src/modules/2DViewer/layers/components/EditName.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import React from "react"; - -import { Edit } from "@mui/icons-material"; - -import { ItemDelegateTopic } from "../delegates/ItemDelegate"; -import { usePublishSubscribeTopicValue } from "../delegates/PublishSubscribeDelegate"; -import { Item } from "../interfaces"; - -type EditItemNameProps = { - item: Item; -}; - -export function EditName(props: EditItemNameProps): React.ReactNode { - const itemName = usePublishSubscribeTopicValue(props.item.getItemDelegate(), ItemDelegateTopic.NAME); - - const [editingName, setEditingName] = React.useState(false); - const [currentName, setCurrentName] = React.useState(itemName); - - function handleNameDoubleClick() { - setEditingName(true); - } - - function handleNameChange(e: React.ChangeEvent) { - setCurrentName(e.target.value); - } - - function handleBlur() { - setEditingName(false); - props.item.getItemDelegate().setName(currentName); - } - - function handleKeyDown(e: React.KeyboardEvent) { - if (e.key === "Enter") { - setEditingName(false); - props.item.getItemDelegate().setName(currentName); - } - } - - return ( -
- {editingName ? ( - - ) : ( - <> -
{itemName}
- - - )} -
- ); -} diff --git a/frontend/src/modules/2DViewer/layers/components/EmptyContent.tsx b/frontend/src/modules/2DViewer/layers/components/EmptyContent.tsx deleted file mode 100644 index ab8a3db27..000000000 --- a/frontend/src/modules/2DViewer/layers/components/EmptyContent.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import React from "react"; - -export type EmptyContentProps = { - children?: React.ReactNode; -}; - -export function EmptyContent(props: EmptyContentProps): React.ReactNode { - return
{props.children}
; -} diff --git a/frontend/src/modules/2DViewer/layers/components/ExpandCollapseAllButton.tsx b/frontend/src/modules/2DViewer/layers/components/ExpandCollapseAllButton.tsx deleted file mode 100644 index 49ecbfb5f..000000000 --- a/frontend/src/modules/2DViewer/layers/components/ExpandCollapseAllButton.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React from "react"; - -import { DenseIconButton } from "@lib/components/DenseIconButton"; -import { UnfoldLessDouble, UnfoldMoreDouble } from "@mui/icons-material"; - -import { Group } from "../interfaces"; - -export type ExpandCollapseAllButtonProps = { - group: Group; -}; - -export function ExpandCollapseAllButton(props: ExpandCollapseAllButtonProps): React.ReactNode { - function expandAllChildren() { - const descendants = props.group.getGroupDelegate().getDescendantItems(() => true); - for (const child of descendants) { - child.getItemDelegate().setExpanded(true); - } - } - - function collapseAllChildren() { - const descendants = props.group.getGroupDelegate().getDescendantItems(() => true); - for (const child of descendants) { - child.getItemDelegate().setExpanded(false); - } - } - - return ( - <> - - - - - - - - ); -} diff --git a/frontend/src/modules/2DViewer/layers/components/LayerComponent.tsx b/frontend/src/modules/2DViewer/layers/components/LayerComponent.tsx deleted file mode 100644 index 05e3d3fdc..000000000 --- a/frontend/src/modules/2DViewer/layers/components/LayerComponent.tsx +++ /dev/null @@ -1,167 +0,0 @@ -import React from "react"; - -import { StatusMessage } from "@framework/ModuleInstanceStatusController"; -import { CircularProgress } from "@lib/components/CircularProgress"; -import { DenseIconButton } from "@lib/components/DenseIconButton"; -import { SortableListItem } from "@lib/components/SortableList"; -import { resolveClassNames } from "@lib/utils/resolveClassNames"; -import { Block, CheckCircle, Difference, Error, ExpandLess, ExpandMore } from "@mui/icons-material"; - -import { EditName } from "./EditName"; -import { RemoveButton } from "./RemoveButton"; -import { SettingComponent } from "./SettingComponent"; -import { VisibilityToggle } from "./VisibilityToggle"; - -import { ItemDelegateTopic } from "../delegates/ItemDelegate"; -import { LayerDelegateTopic, LayerStatus } from "../delegates/LayerDelegate"; -import { usePublishSubscribeTopicValue } from "../delegates/PublishSubscribeDelegate"; -import { SettingsContextDelegateTopic, SettingsContextLoadingState } from "../delegates/SettingsContextDelegate"; -import { Layer, Setting } from "../interfaces"; - -export type LayerComponentProps = { - layer: Layer; -}; - -export function LayerComponent(props: LayerComponentProps): React.ReactNode { - const isExpanded = usePublishSubscribeTopicValue(props.layer.getItemDelegate(), ItemDelegateTopic.EXPANDED); - - function makeSetting(setting: Setting) { - const manager = props.layer.getItemDelegate().getLayerManager(); - if (!manager) { - return null; - } - return ( - - ); - } - - function makeSettings(settings: Record>): React.ReactNode[] { - const settingNodes: React.ReactNode[] = []; - for (const key of Object.keys(settings)) { - settingNodes.push(makeSetting(settings[key])); - } - return settingNodes; - } - - return ( - } - startAdornment={} - endAdornment={} - > -
- {makeSettings(props.layer.getLayerDelegate().getSettingsContext().getDelegate().getSettings())} -
-
- ); -} - -type StartActionProps = { - layer: Layer; -}; - -function StartActions(props: StartActionProps): React.ReactNode { - const isExpanded = usePublishSubscribeTopicValue(props.layer.getItemDelegate(), ItemDelegateTopic.EXPANDED); - - function handleToggleExpanded() { - props.layer.getItemDelegate().setExpanded(!isExpanded); - } - return ( -
- - {isExpanded ? : } - - -
- ); -} - -type EndActionProps = { - layer: Layer; -}; - -function EndActions(props: EndActionProps): React.ReactNode { - const status = usePublishSubscribeTopicValue(props.layer.getLayerDelegate(), LayerDelegateTopic.STATUS); - const settingsStatus = usePublishSubscribeTopicValue( - props.layer.getLayerDelegate().getSettingsContext().getDelegate(), - SettingsContextDelegateTopic.LOADING_STATE_CHANGED - ); - const isSubordinated = usePublishSubscribeTopicValue( - props.layer.getLayerDelegate(), - LayerDelegateTopic.SUBORDINATED - ); - - function makeStatus(): React.ReactNode { - if (isSubordinated) { - return ( -
- -
- ); - } - if (status === LayerStatus.LOADING) { - return ( -
- -
- ); - } - if (status === LayerStatus.ERROR) { - const error = props.layer.getLayerDelegate().getError(); - if (typeof error === "string") { - return ( -
- -
- ); - } else { - const statusMessage = error as StatusMessage; - return ( -
- -
- ); - } - } - if (status === LayerStatus.SUCCESS) { - return ( -
- -
- ); - } - if (settingsStatus === SettingsContextLoadingState.FAILED) { - return ( -
- -
- ); - } - return null; - } - - return ( - <> - {makeStatus()} - - - ); -} diff --git a/frontend/src/modules/2DViewer/layers/components/LayersActions.tsx b/frontend/src/modules/2DViewer/layers/components/LayersActions.tsx deleted file mode 100644 index f063c0a9a..000000000 --- a/frontend/src/modules/2DViewer/layers/components/LayersActions.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import React from "react"; - -import { Menu } from "@lib/components/Menu"; -import { MenuButton } from "@lib/components/MenuButton/menuButton"; -import { MenuDivider } from "@lib/components/MenuDivider"; -import { MenuHeading } from "@lib/components/MenuHeading"; -import { MenuItem } from "@lib/components/MenuItem"; -import { Dropdown } from "@mui/base"; -import { Add, ArrowDropDown } from "@mui/icons-material"; - -export type LayersAction = { - identifier: string; - icon?: React.ReactNode; - label: string; -}; - -export type LayersActionGroup = { - icon?: React.ReactNode; - label: string; - children: (LayersAction | LayersActionGroup)[]; -}; - -function isLayersActionGroup(action: LayersAction | LayersActionGroup): action is LayersActionGroup { - return (action as LayersActionGroup).children !== undefined; -} - -export type LayersActionsProps = { - layersActionGroups: LayersActionGroup[]; - onActionClick: (actionIdentifier: string) => void; -}; - -export function LayersActions(props: LayersActionsProps): React.ReactNode { - function makeContent( - layersActionGroups: (LayersActionGroup | LayersAction)[], - indentLevel: number = 0 - ): React.ReactNode[] { - const content: React.ReactNode[] = []; - for (const [index, item] of layersActionGroups.entries()) { - if (isLayersActionGroup(item)) { - if (index > 0) { - content.push(); - } - content.push( - - {item.icon} - {item.label} - - ); - content.push(makeContent(item.children, indentLevel + 1)); - } else { - content.push( - props.onActionClick(item.identifier)} - > - {item.icon} - {item.label} - - ); - } - } - return content; - } - - return ( - - - - Add - - - - {makeContent(props.layersActionGroups)} - - - ); -} diff --git a/frontend/src/modules/2DViewer/layers/components/RemoveButton.tsx b/frontend/src/modules/2DViewer/layers/components/RemoveButton.tsx deleted file mode 100644 index 10a5a0caf..000000000 --- a/frontend/src/modules/2DViewer/layers/components/RemoveButton.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { DenseIconButton } from "@lib/components/DenseIconButton"; -import { DenseIconButtonColorScheme } from "@lib/components/DenseIconButton/denseIconButton"; -import { Delete } from "@mui/icons-material"; - -import { Item, instanceofLayer } from "../interfaces"; - -export type RemoveButtonProps = { - item: Item; -}; - -export function RemoveButton(props: RemoveButtonProps): React.ReactNode { - function handleRemove() { - const parentGroup = props.item.getItemDelegate().getParentGroup(); - if (parentGroup) { - parentGroup.removeChild(props.item); - } - - if (instanceofLayer(props.item)) { - props.item.getLayerDelegate().beforeDestroy(); - } - } - - return ( - <> - - - - - ); -} diff --git a/frontend/src/modules/2DViewer/layers/components/SettingComponent.tsx b/frontend/src/modules/2DViewer/layers/components/SettingComponent.tsx deleted file mode 100644 index 122fad595..000000000 --- a/frontend/src/modules/2DViewer/layers/components/SettingComponent.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import React from "react"; - -import { PendingWrapper } from "@lib/components/PendingWrapper"; -import { resolveClassNames } from "@lib/utils/resolveClassNames"; -import { Link, Warning } from "@mui/icons-material"; - -import { LayerManager, LayerManagerTopic } from "../LayerManager"; -import { usePublishSubscribeTopicValue } from "../delegates/PublishSubscribeDelegate"; -import { SettingTopic } from "../delegates/SettingDelegate"; -import { Setting, SettingComponentProps as SettingComponentPropsInterface } from "../interfaces"; - -export type SettingComponentProps = { - setting: Setting; - manager: LayerManager; - sharedSetting: boolean; -}; - -export function SettingComponent(props: SettingComponentProps): React.ReactNode { - const componentRef = React.useRef<(props: SettingComponentPropsInterface) => React.ReactNode>( - props.setting.makeComponent() - ); - const value = usePublishSubscribeTopicValue(props.setting.getDelegate(), SettingTopic.VALUE_CHANGED); - const isValid = usePublishSubscribeTopicValue(props.setting.getDelegate(), SettingTopic.VALIDITY_CHANGED); - const isPersisted = usePublishSubscribeTopicValue( - props.setting.getDelegate(), - SettingTopic.PERSISTED_STATE_CHANGED - ); - const availableValues = usePublishSubscribeTopicValue( - props.setting.getDelegate(), - SettingTopic.AVAILABLE_VALUES_CHANGED - ); - const overriddenValue = usePublishSubscribeTopicValue(props.setting.getDelegate(), SettingTopic.OVERRIDDEN_CHANGED); - const isLoading = usePublishSubscribeTopicValue(props.setting.getDelegate(), SettingTopic.LOADING_STATE_CHANGED); - const isInitialized = usePublishSubscribeTopicValue(props.setting.getDelegate(), SettingTopic.INIT_STATE_CHANGED); - const globalSettings = usePublishSubscribeTopicValue(props.manager, LayerManagerTopic.GLOBAL_SETTINGS_CHANGED); - - let actuallyLoading = isLoading || !isInitialized; - if (!isLoading && isPersisted && !isValid) { - actuallyLoading = false; - } - - function handleValueChanged(newValue: TValue) { - props.setting.getDelegate().setValue(newValue); - } - - if (props.sharedSetting && availableValues.length === 0 && isInitialized) { - return ( - -
{props.setting.getLabel()}
-
Empty intersection
-
- ); - } - - if (overriddenValue !== undefined) { - const valueAsString = props.setting - .getDelegate() - .valueToString(overriddenValue, props.manager.getWorkbenchSession(), props.manager.getWorkbenchSettings()); - return ( - -
- {props.setting.getLabel()} - - - -
-
- {isValid ? valueAsString : No valid shared setting value} -
-
- ); - } - - return ( - -
{props.setting.getLabel()}
-
- -
-
- -
- {isPersisted && !isLoading && isInitialized && ( - - - - Persisted value not valid. - - - )} -
-
-
-
- ); -} diff --git a/frontend/src/modules/2DViewer/layers/components/SettingsGroupComponent.tsx b/frontend/src/modules/2DViewer/layers/components/SettingsGroupComponent.tsx deleted file mode 100644 index 313ed2305..000000000 --- a/frontend/src/modules/2DViewer/layers/components/SettingsGroupComponent.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import { SortableListGroup } from "@lib/components/SortableList"; -import { SettingsApplications } from "@mui/icons-material"; - -import { EmptyContent } from "./EmptyContent"; -import { ExpandCollapseAllButton } from "./ExpandCollapseAllButton"; -import { LayersActionGroup, LayersActions } from "./LayersActions"; -import { RemoveButton } from "./RemoveButton"; -import { makeComponent } from "./utils"; - -import { GroupDelegateTopic } from "../delegates/GroupDelegate"; -import { ItemDelegateTopic } from "../delegates/ItemDelegate"; -import { usePublishSubscribeTopicValue } from "../delegates/PublishSubscribeDelegate"; -import { Group, Item } from "../interfaces"; - -export type SettingsGroupComponentProps = { - group: Group; - actions?: LayersActionGroup[]; - onActionClick?: (actionIdentifier: string, group: Group) => void; -}; - -export function SettingsGroupComponent(props: SettingsGroupComponentProps): React.ReactNode { - const children = usePublishSubscribeTopicValue(props.group.getGroupDelegate(), GroupDelegateTopic.CHILDREN); - const isExpanded = usePublishSubscribeTopicValue(props.group.getItemDelegate(), ItemDelegateTopic.EXPANDED); - const color = props.group.getGroupDelegate().getColor(); - - function handleActionClick(actionIdentifier: string) { - if (props.onActionClick) { - props.onActionClick(actionIdentifier, props.group); - } - } - - function makeEndAdornment() { - const adornment: React.ReactNode[] = []; - if (props.actions) { - adornment.push( - - ); - } - adornment.push(); - adornment.push(); - return adornment; - } - - return ( - - {props.group.getItemDelegate().getName()} - - } - contentStyle={{ - backgroundColor: color ?? undefined, - }} - headerStyle={{ - backgroundColor: "rgb(196 181 253)", - }} - startAdornment={} - endAdornment={<>{makeEndAdornment()}} - contentWhenEmpty={ - Drag a layer or setting inside to add it to this settings group. - } - expanded={isExpanded} - > - {children.map((child: Item) => makeComponent(child, props.actions, props.onActionClick))} - - ); -} diff --git a/frontend/src/modules/2DViewer/layers/components/SharedSettingComponent.tsx b/frontend/src/modules/2DViewer/layers/components/SharedSettingComponent.tsx deleted file mode 100644 index 27523b6d5..000000000 --- a/frontend/src/modules/2DViewer/layers/components/SharedSettingComponent.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import React from "react"; - -import { DenseIconButton } from "@lib/components/DenseIconButton"; -import { DenseIconButtonColorScheme } from "@lib/components/DenseIconButton/denseIconButton"; -import { SortableListItem } from "@lib/components/SortableList"; -import { resolveClassNames } from "@lib/utils/resolveClassNames"; -import { Delete, ExpandLess, ExpandMore, Link } from "@mui/icons-material"; - -import { SettingComponent } from "./SettingComponent"; - -import { SharedSetting } from "../SharedSetting"; -import { ItemDelegateTopic } from "../delegates/ItemDelegate"; -import { usePublishSubscribeTopicValue } from "../delegates/PublishSubscribeDelegate"; - -export type SharedSettingComponentProps = { - sharedSetting: SharedSetting; -}; - -export function SharedSettingComponent(props: SharedSettingComponentProps): React.ReactNode { - const isExpanded = usePublishSubscribeTopicValue(props.sharedSetting.getItemDelegate(), ItemDelegateTopic.EXPANDED); - - const manager = props.sharedSetting.getItemDelegate().getLayerManager(); - if (!manager) { - return null; - } - - function handleToggleExpanded() { - props.sharedSetting.getItemDelegate().setExpanded(!isExpanded); - } - - return ( - - {props.sharedSetting.getItemDelegate().getName()} - - } - startAdornment={ -
- - {isExpanded ? : } - - -
- } - endAdornment={} - headerClassNames="!bg-teal-200" - > -
- -
-
- ); -} - -type ActionProps = { - sharedSetting: SharedSetting; -}; - -function Actions(props: ActionProps): React.ReactNode { - function handleRemove() { - props.sharedSetting.beforeDestroy(); - const parentGroup = props.sharedSetting.getItemDelegate().getParentGroup(); - if (parentGroup) { - parentGroup.removeChild(props.sharedSetting); - } - } - - return ( - <> - - - - - ); -} diff --git a/frontend/src/modules/2DViewer/layers/components/ViewComponent.tsx b/frontend/src/modules/2DViewer/layers/components/ViewComponent.tsx deleted file mode 100644 index d91ae8ec8..000000000 --- a/frontend/src/modules/2DViewer/layers/components/ViewComponent.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { SortableListGroup } from "@lib/components/SortableList"; - -import { EditName } from "./EditName"; -import { EmptyContent } from "./EmptyContent"; -import { ExpandCollapseAllButton } from "./ExpandCollapseAllButton"; -import { LayersActionGroup, LayersActions } from "./LayersActions"; -import { RemoveButton } from "./RemoveButton"; -import { VisibilityToggle } from "./VisibilityToggle"; -import { makeComponent } from "./utils"; - -import { GroupDelegateTopic } from "../delegates/GroupDelegate"; -import { ItemDelegateTopic } from "../delegates/ItemDelegate"; -import { usePublishSubscribeTopicValue } from "../delegates/PublishSubscribeDelegate"; -import { Group, Item } from "../interfaces"; - -export type ViewComponentProps = { - group: Group; - actions?: LayersActionGroup[]; - onActionClick?: (actionIdentifier: string, group: Group) => void; -}; - -export function ViewComponent(props: ViewComponentProps): React.ReactNode { - const children = usePublishSubscribeTopicValue(props.group.getGroupDelegate(), GroupDelegateTopic.CHILDREN); - const isExpanded = usePublishSubscribeTopicValue(props.group.getItemDelegate(), ItemDelegateTopic.EXPANDED); - const color = props.group.getGroupDelegate().getColor(); - - function handleActionClick(actionIdentifier: string) { - if (props.onActionClick) { - props.onActionClick(actionIdentifier, props.group); - } - } - - function makeEndAdornment() { - const adornments: React.ReactNode[] = []; - if (props.actions) { - adornments.push( - - ); - } - adornments.push(); - adornments.push(); - return adornments; - } - - return ( - -
-
- -
-
- } - contentStyle={{ - backgroundColor: color ?? undefined, - }} - expanded={isExpanded} - startAdornment={} - endAdornment={<>{makeEndAdornment()}} - contentWhenEmpty={Drag a layer inside to add it to this view.} - > - {children.map((child: Item) => makeComponent(child, props.actions, props.onActionClick))} -
- ); -} diff --git a/frontend/src/modules/2DViewer/layers/components/VisibilityToggle.tsx b/frontend/src/modules/2DViewer/layers/components/VisibilityToggle.tsx deleted file mode 100644 index 366c17874..000000000 --- a/frontend/src/modules/2DViewer/layers/components/VisibilityToggle.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { DenseIconButton } from "@lib/components/DenseIconButton"; -import { Visibility, VisibilityOff } from "@mui/icons-material"; - -import { ItemDelegateTopic } from "../delegates/ItemDelegate"; -import { usePublishSubscribeTopicValue } from "../delegates/PublishSubscribeDelegate"; -import { Item } from "../interfaces"; - -export type VisibilityToggleProps = { - item: Item; -}; - -export function VisibilityToggle(props: VisibilityToggleProps): React.ReactNode { - const isVisible = usePublishSubscribeTopicValue(props.item.getItemDelegate(), ItemDelegateTopic.VISIBILITY); - - function handleToggleLayerVisibility() { - props.item.getItemDelegate().setVisible(!isVisible); - } - - return ( - - {isVisible ? : } - - ); -} diff --git a/frontend/src/modules/2DViewer/layers/components/utils.tsx b/frontend/src/modules/2DViewer/layers/components/utils.tsx deleted file mode 100644 index 0f1f3f31b..000000000 --- a/frontend/src/modules/2DViewer/layers/components/utils.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { SortableListItemProps } from "@lib/components/SortableList"; - -import { ColorScaleComponent } from "./ColorScaleComponent"; -import { DeltaSurfaceComponent } from "./DeltaSurfaceComponent"; -import { LayerComponent } from "./LayerComponent"; -import { LayersActionGroup } from "./LayersActions"; -import { SettingsGroupComponent } from "./SettingsGroupComponent"; -import { SharedSettingComponent } from "./SharedSettingComponent"; -import { ViewComponent } from "./ViewComponent"; - -import { ColorScale } from "../ColorScale"; -import { DeltaSurface } from "../DeltaSurface"; -import { SettingsGroup } from "../SettingsGroup"; -import { SharedSetting } from "../SharedSetting"; -import { View } from "../View"; -import { Group, Item, instanceofGroup, instanceofLayer } from "../interfaces"; - -export function makeComponent( - item: Item, - layerActions?: LayersActionGroup[], - onActionClick?: (identifier: string, group: Group) => void -): React.ReactElement { - if (instanceofLayer(item)) { - return ; - } - if (instanceofGroup(item)) { - if (item instanceof SettingsGroup) { - return ( - - ); - } else if (item instanceof View) { - return ( - - ); - } else if (item instanceof DeltaSurface) { - return ( - - ); - } - } - if (item instanceof SharedSetting) { - return ; - } - if (item instanceof ColorScale) { - return ; - } - throw new Error("Not implemented"); -} - -function filterAwayViewActions(actions: LayersActionGroup[]): LayersActionGroup[] { - return actions.map((group) => ({ - ...group, - children: group.children.filter((child) => child.label !== "View"), - })); -} - -function filterAwayNonSurfaceActions(actions: LayersActionGroup[]): LayersActionGroup[] { - const result: LayersActionGroup[] = []; - - for (const group of actions) { - if (group.label === "Shared Settings") { - result.push(group); - continue; - } - if (group.label !== "Layers") { - continue; - } - const children = group.children.filter((child) => child.label.includes("Surface")); - if (children.length > 0) { - result.push({ - ...group, - children, - }); - } - } - - return result; -} diff --git a/frontend/src/modules/2DViewer/layers/delegates/GroupDelegate.ts b/frontend/src/modules/2DViewer/layers/delegates/GroupDelegate.ts deleted file mode 100644 index 613be3e8b..000000000 --- a/frontend/src/modules/2DViewer/layers/delegates/GroupDelegate.ts +++ /dev/null @@ -1,249 +0,0 @@ -import { ItemDelegateTopic } from "./ItemDelegate"; -import { PublishSubscribe, PublishSubscribeDelegate } from "./PublishSubscribeDelegate"; -import { UnsubscribeHandlerDelegate } from "./UnsubscribeHandlerDelegate"; - -import { DeserializationFactory } from "../DeserializationFactory"; -import { LayerManagerTopic } from "../LayerManager"; -import { SharedSetting } from "../SharedSetting"; -import { Item, SerializedItem, instanceofGroup, instanceofLayer } from "../interfaces"; - -export enum GroupDelegateTopic { - CHILDREN = "CHILDREN", - TREE_REVISION_NUMBER = "TREE_REVISION_NUMBER", - CHILDREN_EXPANSION_STATES = "CHILDREN_EXPANSION_STATES", -} - -export type GroupDelegateTopicPayloads = { - [GroupDelegateTopic.CHILDREN]: Item[]; - [GroupDelegateTopic.TREE_REVISION_NUMBER]: number; - [GroupDelegateTopic.CHILDREN_EXPANSION_STATES]: { [id: string]: boolean }; -}; - -export class GroupDelegate implements PublishSubscribe { - private _owner: Item | null; - private _color: string | null = null; - private _children: Item[] = []; - private _publishSubscribeDelegate = new PublishSubscribeDelegate(); - private _unsubscribeHandlerDelegate = new UnsubscribeHandlerDelegate(); - private _treeRevisionNumber: number = 0; - private _deserializing = false; - - constructor(owner: Item | null) { - this._owner = owner; - } - - getColor(): string | null { - return this._color; - } - - setColor(color: string | null) { - this._color = color; - } - - prependChild(child: Item) { - this._children = [child, ...this._children]; - this.takeOwnershipOfChild(child); - } - - appendChild(child: Item) { - this._children = [...this._children, child]; - this.takeOwnershipOfChild(child); - } - - insertChild(child: Item, index: number) { - this._children = [...this._children.slice(0, index), child, ...this._children.slice(index)]; - this.takeOwnershipOfChild(child); - } - - removeChild(child: Item) { - this._children = this._children.filter((c) => c !== child); - this.disposeOwnershipOfChild(child); - this.incrementTreeRevisionNumber(); - } - - clearChildren() { - for (const child of this._children) { - this.disposeOwnershipOfChild(child); - } - this._children = []; - this.publishTopic(GroupDelegateTopic.CHILDREN); - this.incrementTreeRevisionNumber(); - } - - moveChild(child: Item, index: number) { - const currentIndex = this._children.indexOf(child); - if (currentIndex === -1) { - throw new Error("Child not found"); - } - - this._children = [...this._children.slice(0, currentIndex), ...this._children.slice(currentIndex + 1)]; - - this._children = [...this._children.slice(0, index), child, ...this._children.slice(index)]; - this.publishTopic(GroupDelegateTopic.CHILDREN); - this.incrementTreeRevisionNumber(); - } - - getChildren() { - return this._children; - } - - findChildren(predicate: (item: Item) => boolean): Item[] { - return this._children.filter(predicate); - } - - findDescendantById(id: string): Item | undefined { - for (const child of this._children) { - if (child.getItemDelegate().getId() === id) { - return child; - } - - if (instanceofGroup(child)) { - const descendant = child.getGroupDelegate().findDescendantById(id); - if (descendant) { - return descendant; - } - } - } - - return undefined; - } - - getAncestorAndSiblingItems(predicate: (item: Item) => boolean): Item[] { - const items: Item[] = []; - for (const child of this._children) { - if (predicate(child)) { - items.push(child); - } - } - const parentGroup = this._owner?.getItemDelegate().getParentGroup(); - if (parentGroup) { - items.push(...parentGroup.getAncestorAndSiblingItems(predicate)); - } - - return items; - } - - getDescendantItems(predicate: (item: Item) => boolean): Item[] { - const items: Item[] = []; - for (const child of this._children) { - if (predicate(child)) { - items.push(child); - } - - if (instanceofGroup(child)) { - items.push(...child.getGroupDelegate().getDescendantItems(predicate)); - } - } - - return items; - } - - makeSnapshotGetter(topic: T): () => GroupDelegateTopicPayloads[T] { - const snapshotGetter = (): any => { - if (topic === GroupDelegateTopic.CHILDREN) { - return this._children; - } - if (topic === GroupDelegateTopic.TREE_REVISION_NUMBER) { - return this._treeRevisionNumber; - } - if (topic === GroupDelegateTopic.CHILDREN_EXPANSION_STATES) { - const expansionState: { [id: string]: boolean } = {}; - for (const child of this._children) { - if (instanceofGroup(child)) { - expansionState[child.getItemDelegate().getId()] = child.getItemDelegate().isExpanded(); - } - } - return expansionState; - } - }; - - return snapshotGetter; - } - - getPublishSubscribeDelegate(): PublishSubscribeDelegate { - return this._publishSubscribeDelegate; - } - - serializeChildren(): SerializedItem[] { - return this._children.map((child) => child.serializeState()); - } - - deserializeChildren(children: SerializedItem[]) { - if (!this._owner) { - throw new Error("Owner not set"); - } - - this._deserializing = true; - const factory = new DeserializationFactory(this._owner.getItemDelegate().getLayerManager()); - for (const child of children) { - const item = factory.makeItem(child); - this.appendChild(item); - } - this._deserializing = false; - } - - private incrementTreeRevisionNumber() { - this._treeRevisionNumber++; - this.publishTopic(GroupDelegateTopic.TREE_REVISION_NUMBER); - } - - private takeOwnershipOfChild(child: Item) { - child.getItemDelegate().setParentGroup(this); - - this._unsubscribeHandlerDelegate.unsubscribe(child.getItemDelegate().getId()); - - if (instanceofLayer(child)) { - this._unsubscribeHandlerDelegate.registerUnsubscribeFunction( - child.getItemDelegate().getId(), - child - .getItemDelegate() - .getPublishSubscribeDelegate() - .makeSubscriberFunction(ItemDelegateTopic.EXPANDED)(() => { - this.publishTopic(GroupDelegateTopic.CHILDREN_EXPANSION_STATES); - }) - ); - } - - if (instanceofGroup(child)) { - this._unsubscribeHandlerDelegate.registerUnsubscribeFunction( - child.getItemDelegate().getId(), - child - .getGroupDelegate() - .getPublishSubscribeDelegate() - .makeSubscriberFunction(GroupDelegateTopic.TREE_REVISION_NUMBER)(() => { - this.incrementTreeRevisionNumber(); - }) - ); - this._unsubscribeHandlerDelegate.registerUnsubscribeFunction( - child.getItemDelegate().getId(), - child - .getGroupDelegate() - .getPublishSubscribeDelegate() - .makeSubscriberFunction(GroupDelegateTopic.CHILDREN_EXPANSION_STATES)(() => { - this.publishTopic(GroupDelegateTopic.CHILDREN_EXPANSION_STATES); - }) - ); - } - - this.publishTopic(GroupDelegateTopic.CHILDREN); - this.incrementTreeRevisionNumber(); - } - - private publishTopic(topic: GroupDelegateTopic) { - if (this._deserializing) { - return; - } - this._publishSubscribeDelegate.notifySubscribers(topic); - } - - private disposeOwnershipOfChild(child: Item) { - this._unsubscribeHandlerDelegate.unsubscribe(child.getItemDelegate().getId()); - child.getItemDelegate().setParentGroup(null); - - if (child instanceof SharedSetting) { - this._owner?.getItemDelegate().getLayerManager().publishTopic(LayerManagerTopic.SETTINGS_CHANGED); - } - - this.publishTopic(GroupDelegateTopic.CHILDREN); - } -} diff --git a/frontend/src/modules/2DViewer/layers/delegates/ItemDelegate.ts b/frontend/src/modules/2DViewer/layers/delegates/ItemDelegate.ts deleted file mode 100644 index 0967d611e..000000000 --- a/frontend/src/modules/2DViewer/layers/delegates/ItemDelegate.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { isEqual } from "lodash"; -import { v4 } from "uuid"; - -import { GroupDelegate } from "./GroupDelegate"; -import { PublishSubscribe, PublishSubscribeDelegate } from "./PublishSubscribeDelegate"; - -import { LayerManager, LayerManagerTopic } from "../LayerManager"; -import { SerializedItem } from "../interfaces"; - -export enum ItemDelegateTopic { - NAME = "NAME", - VISIBILITY = "VISIBILITY", - EXPANDED = "EXPANDED", -} - -export type ItemDelegatePayloads = { - [ItemDelegateTopic.NAME]: string; - [ItemDelegateTopic.VISIBILITY]: boolean; - [ItemDelegateTopic.EXPANDED]: boolean; -}; - -export class ItemDelegate implements PublishSubscribe { - private _id: string; - private _name: string; - private _visible: boolean = true; - private _expanded: boolean = true; - private _parentGroup: GroupDelegate | null = null; - private _layerManager: LayerManager; - private _publishSubscribeDelegate = new PublishSubscribeDelegate(); - - constructor(name: string, layerManager: LayerManager) { - this._id = v4(); - this._layerManager = layerManager; - this._name = this.makeUniqueName(name); - } - - setId(id: string): void { - this._id = id; - } - - getId(): string { - return this._id; - } - - getName(): string { - return this._name; - } - - setName(name: string): void { - if (isEqual(this._name, name)) { - return; - } - - this._name = name; - this._publishSubscribeDelegate.notifySubscribers(ItemDelegateTopic.NAME); - if (this._layerManager) { - this._layerManager.publishTopic(LayerManagerTopic.LAYER_DATA_REVISION); - } - } - - getParentGroup(): GroupDelegate | null { - return this._parentGroup; - } - - setParentGroup(parentGroup: GroupDelegate | null): void { - this._parentGroup = parentGroup; - } - - getLayerManager(): LayerManager { - return this._layerManager; - } - - isVisible(): boolean { - return this._visible; - } - - setVisible(visible: boolean): void { - if (isEqual(this._visible, visible)) { - return; - } - - this._visible = visible; - this._publishSubscribeDelegate.notifySubscribers(ItemDelegateTopic.VISIBILITY); - if (this._layerManager) { - this._layerManager.publishTopic(LayerManagerTopic.LAYER_DATA_REVISION); - } - } - - isExpanded(): boolean { - return this._expanded; - } - - setExpanded(expanded: boolean): void { - if (isEqual(this._expanded, expanded)) { - return; - } - - this._expanded = expanded; - this._publishSubscribeDelegate.notifySubscribers(ItemDelegateTopic.EXPANDED); - } - - makeSnapshotGetter(topic: T): () => ItemDelegatePayloads[T] { - const snapshotGetter = (): any => { - if (topic === ItemDelegateTopic.NAME) { - return this._name; - } - if (topic === ItemDelegateTopic.VISIBILITY) { - return this._visible; - } - if (topic === ItemDelegateTopic.EXPANDED) { - return this._expanded; - } - }; - return snapshotGetter; - } - - getPublishSubscribeDelegate(): PublishSubscribeDelegate { - return this._publishSubscribeDelegate; - } - - serializeState(): Omit { - return { - id: this._id, - name: this._name, - visible: this._visible, - expanded: this._expanded, - }; - } - - deserializeState(state: Omit): void { - this._id = state.id; - this._name = state.name; - this._visible = state.visible; - this._expanded = state.expanded; - } - - private makeUniqueName(candidate: string): string { - const groupDelegate = this._layerManager?.getGroupDelegate(); - if (!groupDelegate) { - return candidate; - } - const existingNames = groupDelegate - .getDescendantItems(() => true) - .map((item) => item.getItemDelegate().getName()); - let uniqueName = candidate; - let counter = 1; - while (existingNames.includes(uniqueName)) { - uniqueName = `${candidate} (${counter})`; - counter++; - } - return uniqueName; - } -} diff --git a/frontend/src/modules/2DViewer/layers/delegates/LayerDelegate.ts b/frontend/src/modules/2DViewer/layers/delegates/LayerDelegate.ts deleted file mode 100644 index 3d9dde990..000000000 --- a/frontend/src/modules/2DViewer/layers/delegates/LayerDelegate.ts +++ /dev/null @@ -1,330 +0,0 @@ -import { StatusMessage } from "@framework/ModuleInstanceStatusController"; -import { ApiErrorHelper } from "@framework/utils/ApiErrorHelper"; -import { isDevMode } from "@lib/utils/devMode"; -import { QueryClient, isCancelledError } from "@tanstack/react-query"; - -import { PublishSubscribe, PublishSubscribeDelegate } from "./PublishSubscribeDelegate"; -import { SettingsContextDelegateTopic } from "./SettingsContextDelegate"; -import { UnsubscribeHandlerDelegate } from "./UnsubscribeHandlerDelegate"; - -import { LayerManager, LayerManagerTopic } from "../LayerManager"; -import { SharedSetting } from "../SharedSetting"; -import { BoundingBox, Layer, SerializedLayer, Settings, SettingsContext } from "../interfaces"; - -export enum LayerDelegateTopic { - STATUS = "STATUS", - DATA = "DATA", - SUBORDINATED = "SUBORDINATED", -} - -export enum LayerColoringType { - NONE = "NONE", - COLORSCALE = "COLORSCALE", - COLORSET = "COLORSET", -} - -export enum LayerStatus { - IDLE = "IDLE", - LOADING = "LOADING", - ERROR = "ERROR", - SUCCESS = "SUCCESS", -} - -export type LayerDelegatePayloads = { - [LayerDelegateTopic.STATUS]: LayerStatus; - [LayerDelegateTopic.DATA]: TData; - [LayerDelegateTopic.SUBORDINATED]: boolean; -}; -export class LayerDelegate - implements PublishSubscribe> -{ - private _owner: Layer; - private _settingsContext: SettingsContext; - private _layerManager: LayerManager; - private _unsubscribeHandler: UnsubscribeHandlerDelegate = new UnsubscribeHandlerDelegate(); - private _cancellationPending: boolean = false; - private _publishSubscribeDelegate = new PublishSubscribeDelegate(); - private _queryKeys: unknown[][] = []; - private _status: LayerStatus = LayerStatus.IDLE; - private _data: TData | null = null; - private _error: StatusMessage | string | null = null; - private _boundingBox: BoundingBox | null = null; - private _valueRange: [number, number] | null = null; - private _coloringType: LayerColoringType; - private _isSubordinated: boolean = false; - - constructor( - owner: Layer, - layerManager: LayerManager, - settingsContext: SettingsContext, - coloringType: LayerColoringType - ) { - this._owner = owner; - this._layerManager = layerManager; - this._settingsContext = settingsContext; - this._coloringType = coloringType; - - this._unsubscribeHandler.registerUnsubscribeFunction( - "settings-context", - this._settingsContext - .getDelegate() - .getPublishSubscribeDelegate() - .makeSubscriberFunction(SettingsContextDelegateTopic.SETTINGS_CHANGED)(() => { - this.handleSettingsChange(); - }) - ); - - this._unsubscribeHandler.registerUnsubscribeFunction( - "layer-manager", - layerManager - .getPublishSubscribeDelegate() - .makeSubscriberFunction(LayerManagerTopic.SHARED_SETTINGS_CHANGED)(() => { - this.handleSharedSettingsChanged(); - }) - ); - - this._unsubscribeHandler.registerUnsubscribeFunction( - "layer-manager", - layerManager.getPublishSubscribeDelegate().makeSubscriberFunction(LayerManagerTopic.ITEMS_CHANGED)(() => { - this.handleSharedSettingsChanged(); - }) - ); - } - - handleSettingsChange(): void { - this._cancellationPending = true; - this.maybeCancelQuery().then(() => { - this.maybeRefetchData(); - }); - } - - registerQueryKey(queryKey: unknown[]): void { - this._queryKeys.push(queryKey); - } - - getStatus(): LayerStatus { - return this._status; - } - - getData(): TData | null { - return this._data; - } - - getSettingsContext(): SettingsContext { - return this._settingsContext; - } - - getBoundingBox(): BoundingBox | null { - return this._boundingBox; - } - - getColoringType(): LayerColoringType { - return this._coloringType; - } - - isSubordinated(): boolean { - return this._isSubordinated; - } - - setIsSubordinated(isSubordinated: boolean): void { - if (this._isSubordinated === isSubordinated) { - return; - } - this._isSubordinated = isSubordinated; - this._publishSubscribeDelegate.notifySubscribers(LayerDelegateTopic.SUBORDINATED); - } - - getValueRange(): [number, number] | null { - return this._valueRange; - } - - handleSharedSettingsChanged(): void { - const parentGroup = this._owner.getItemDelegate().getParentGroup(); - if (parentGroup) { - const sharedSettings: SharedSetting[] = parentGroup.getAncestorAndSiblingItems( - (item) => item instanceof SharedSetting - ) as SharedSetting[]; - const overriddenSettings: { [K in keyof TSettings]: TSettings[K] } = {} as { - [K in keyof TSettings]: TSettings[K]; - }; - for (const sharedSetting of sharedSettings) { - const type = sharedSetting.getWrappedSetting().getType(); - const setting = this._settingsContext.getDelegate().getSettings()[type]; - if (setting && overriddenSettings[type] === undefined) { - if ( - sharedSetting.getWrappedSetting().getDelegate().isInitialized() && - sharedSetting.getWrappedSetting().getDelegate().isValueValid() - ) { - overriddenSettings[type] = sharedSetting.getWrappedSetting().getDelegate().getValue(); - } else { - overriddenSettings[type] = null; - } - } - } - this._settingsContext.getDelegate().setOverriddenSettings(overriddenSettings); - } - } - - getLayerManager(): LayerManager { - return this._layerManager; - } - - makeSnapshotGetter(topic: T): () => LayerDelegatePayloads[T] { - const snapshotGetter = (): any => { - if (topic === LayerDelegateTopic.STATUS) { - return this._status; - } - if (topic === LayerDelegateTopic.DATA) { - return this._data; - } - if (topic === LayerDelegateTopic.SUBORDINATED) { - return this._isSubordinated; - } - }; - - return snapshotGetter; - } - - getPublishSubscribeDelegate(): PublishSubscribeDelegate { - return this._publishSubscribeDelegate; - } - - getError(): StatusMessage | string | null { - if (!this._error) { - return null; - } - - const name = this._owner.getItemDelegate().getName(); - - if (typeof this._error === "string") { - return `${name}: ${this._error}`; - } - - return { - ...this._error, - message: `${name}: ${this._error.message}`, - }; - } - - async maybeRefetchData(): Promise { - const queryClient = this.getQueryClient(); - - if (!queryClient) { - return; - } - - if (this._cancellationPending) { - return; - } - - if (this._isSubordinated) { - return; - } - - this.setStatus(LayerStatus.LOADING); - this.invalidateBoundingBox(); - this.invalidateValueRange(); - - try { - this._data = await this._owner.fechData(queryClient); - if (this._owner.makeBoundingBox) { - this._boundingBox = this._owner.makeBoundingBox(); - } - if (this._owner.makeValueRange) { - this._valueRange = this._owner.makeValueRange(); - } - if (this._queryKeys.length === null && isDevMode()) { - console.warn( - "Did you forget to use 'setQueryKeys' in your layer implementation of 'fetchData'? This will cause the queries to not be cancelled when settings change and might lead to undesired behaviour." - ); - } - this._queryKeys = []; - this._publishSubscribeDelegate.notifySubscribers(LayerDelegateTopic.DATA); - this._layerManager.publishTopic(LayerManagerTopic.LAYER_DATA_REVISION); - this.setStatus(LayerStatus.SUCCESS); - } catch (error: any) { - if (isCancelledError(error)) { - return; - } - const apiError = ApiErrorHelper.fromError(error); - if (apiError) { - this._error = apiError.makeStatusMessage(); - } else { - this._error = "An error occurred"; - } - this.setStatus(LayerStatus.ERROR); - } - } - - serializeState(): SerializedLayer { - const itemState = this._owner.getItemDelegate().serializeState(); - return { - ...itemState, - type: "layer", - layerClass: this._owner.constructor.name, - settings: this._settingsContext.getDelegate().serializeSettings(), - }; - } - - deserializeState(serializedLayer: SerializedLayer): void { - this._owner.getItemDelegate().deserializeState(serializedLayer); - this._settingsContext.getDelegate().deserializeSettings(serializedLayer.settings); - } - - beforeDestroy(): void { - this._settingsContext.getDelegate().beforeDestroy(); - this._unsubscribeHandler.unsubscribeAll(); - } - - private setStatus(status: LayerStatus): void { - if (this._status === status) { - return; - } - - this._status = status; - this._layerManager.publishTopic(LayerManagerTopic.LAYER_DATA_REVISION); - this._publishSubscribeDelegate.notifySubscribers(LayerDelegateTopic.STATUS); - } - - private getQueryClient(): QueryClient | null { - return this._layerManager?.getQueryClient() ?? null; - } - - private invalidateBoundingBox(): void { - this._boundingBox = null; - } - - private invalidateValueRange(): void { - this._valueRange = null; - } - - private async maybeCancelQuery(): Promise { - const queryClient = this.getQueryClient(); - - if (!queryClient) { - return; - } - - if (this._queryKeys.length > 0) { - for (const queryKey of this._queryKeys) { - await queryClient.cancelQueries( - { - queryKey, - exact: true, - fetchStatus: "fetching", - type: "active", - }, - { - silent: true, - revert: true, - } - ); - await queryClient.invalidateQueries({ queryKey }); - queryClient.removeQueries({ queryKey }); - } - this._queryKeys = []; - } - - this._cancellationPending = false; - } -} diff --git a/frontend/src/modules/2DViewer/layers/delegates/PublishSubscribeDelegate.ts b/frontend/src/modules/2DViewer/layers/delegates/PublishSubscribeDelegate.ts deleted file mode 100644 index 567fd3bfc..000000000 --- a/frontend/src/modules/2DViewer/layers/delegates/PublishSubscribeDelegate.ts +++ /dev/null @@ -1,46 +0,0 @@ -import React from "react"; - -export type TopicPayloads = Record; - -export interface PublishSubscribe> { - makeSnapshotGetter(topic: T): () => TTopicPayloads[T]; - getPublishSubscribeDelegate(): PublishSubscribeDelegate; -} - -export class PublishSubscribeDelegate { - private _subscribers = new Map void>>(); - - notifySubscribers(topic: TTopic): void { - const subscribers = this._subscribers.get(topic); - if (subscribers) { - subscribers.forEach((subscriber) => subscriber()); - } - } - - makeSubscriberFunction(topic: TTopic): (onStoreChangeCallback: () => void) => () => void { - // Using arrow function in order to keep "this" in context - const subscriber = (onStoreChangeCallback: () => void): (() => void) => { - const subscribers = this._subscribers.get(topic) || new Set(); - subscribers.add(onStoreChangeCallback); - this._subscribers.set(topic, subscribers); - - return () => { - subscribers.delete(onStoreChangeCallback); - }; - }; - - return subscriber; - } -} - -export function usePublishSubscribeTopicValue>( - publishSubscribe: PublishSubscribe, - topic: TTopic -): TTopicPayloads[TTopic] { - const value = React.useSyncExternalStore( - publishSubscribe.getPublishSubscribeDelegate().makeSubscriberFunction(topic), - publishSubscribe.makeSnapshotGetter(topic) - ); - - return value; -} diff --git a/frontend/src/modules/2DViewer/layers/delegates/SettingDelegate.ts b/frontend/src/modules/2DViewer/layers/delegates/SettingDelegate.ts deleted file mode 100644 index e20285b14..000000000 --- a/frontend/src/modules/2DViewer/layers/delegates/SettingDelegate.ts +++ /dev/null @@ -1,341 +0,0 @@ -import { WorkbenchSession } from "@framework/WorkbenchSession"; -import { WorkbenchSettings } from "@framework/WorkbenchSettings"; - -import { isArray, isEqual } from "lodash"; -import { v4 } from "uuid"; - -import { PublishSubscribe, PublishSubscribeDelegate } from "./PublishSubscribeDelegate"; - -import { AvailableValuesType, Setting } from "../interfaces"; - -export enum SettingTopic { - VALUE_CHANGED = "VALUE_CHANGED", - VALIDITY_CHANGED = "VALIDITY_CHANGED", - AVAILABLE_VALUES_CHANGED = "AVAILABLE_VALUES_CHANGED", - OVERRIDDEN_CHANGED = "OVERRIDDEN_CHANGED", - LOADING_STATE_CHANGED = "LOADING_STATE_CHANGED", - INIT_STATE_CHANGED = "INIT_STATE_CHANGED", - PERSISTED_STATE_CHANGED = "PERSISTED_STATE_CHANGED", -} - -export type SettingTopicPayloads = { - [SettingTopic.VALUE_CHANGED]: TValue; - [SettingTopic.VALIDITY_CHANGED]: boolean; - [SettingTopic.AVAILABLE_VALUES_CHANGED]: Exclude[]; - [SettingTopic.OVERRIDDEN_CHANGED]: TValue | undefined; - [SettingTopic.LOADING_STATE_CHANGED]: boolean; - [SettingTopic.INIT_STATE_CHANGED]: boolean; - [SettingTopic.PERSISTED_STATE_CHANGED]: boolean; -}; - -export class SettingDelegate implements PublishSubscribe> { - private _id: string; - private _owner: Setting; - private _value: TValue; - private _isValueValid: boolean = false; - private _publishSubscribeDelegate = new PublishSubscribeDelegate(); - private _availableValues: AvailableValuesType = [] as unknown as AvailableValuesType; - private _overriddenValue: TValue | undefined = undefined; - private _loading: boolean = false; - private _initialized: boolean = false; - private _currentValueFromPersistence: TValue | null = null; - private _isStatic: boolean; - - constructor(value: TValue, owner: Setting, isStatic: boolean = false) { - this._id = v4(); - this._owner = owner; - this._value = value; - if (typeof value === "boolean") { - this._isValueValid = true; - } - this._isStatic = isStatic; - if (isStatic) { - this.setInitialized(); - } - } - - getId(): string { - return this._id; - } - - getValue(): TValue { - if (this._overriddenValue !== undefined) { - return this._overriddenValue; - } - - if (this._currentValueFromPersistence !== null) { - return this._currentValueFromPersistence; - } - - return this._value; - } - - isStatic(): boolean { - return this._isStatic; - } - - serializeValue(): string { - if (this._owner.serializeValue) { - return this._owner.serializeValue(this.getValue()); - } - - return JSON.stringify(this.getValue()); - } - - deserializeValue(serializedValue: string): void { - if (this._owner.deserializeValue) { - this._currentValueFromPersistence = this._owner.deserializeValue(serializedValue); - return; - } - - this._currentValueFromPersistence = JSON.parse(serializedValue); - } - - isValueValid(): boolean { - return this._isValueValid; - } - - isPersistedValue(): boolean { - return this._currentValueFromPersistence !== null; - } - - /* - * This method is used to set the value of the setting. - * It should only be called when a user is changing a setting. - */ - setValue(value: TValue): void { - if (isEqual(this._value, value)) { - return; - } - this._currentValueFromPersistence = null; - this._value = value; - - this.setValueValid(this.checkIfValueIsValid(this._value)); - - this._publishSubscribeDelegate.notifySubscribers(SettingTopic.VALUE_CHANGED); - } - - setValueValid(isValueValid: boolean): void { - if (this._isValueValid === isValueValid) { - return; - } - this._isValueValid = isValueValid; - this._publishSubscribeDelegate.notifySubscribers(SettingTopic.VALIDITY_CHANGED); - } - - setLoading(loading: boolean): void { - if (this._loading === loading) { - return; - } - this._loading = loading; - this._publishSubscribeDelegate.notifySubscribers(SettingTopic.LOADING_STATE_CHANGED); - } - - setInitialized(): void { - if (this._initialized) { - return; - } - this._initialized = true; - this._publishSubscribeDelegate.notifySubscribers(SettingTopic.INIT_STATE_CHANGED); - } - - isInitialized(): boolean { - return this._initialized; - } - - isLoading(): boolean { - return this._loading; - } - - valueToString(value: TValue, workbenchSession: WorkbenchSession, workbenchSettings: WorkbenchSettings): string { - if (this._owner.valueToString) { - return this._owner.valueToString({ value, workbenchSession, workbenchSettings }); - } - - if (typeof value === "boolean") { - return value ? "true" : "false"; - } - - if (typeof value === "string") { - return value; - } - - if (typeof value === "number") { - return value.toString(); - } - - return "Value has no string representation"; - } - - setOverriddenValue(overriddenValue: TValue | undefined): void { - if (isEqual(this._overriddenValue, overriddenValue)) { - return; - } - - const prevValue = this._overriddenValue; - this._overriddenValue = overriddenValue; - this._publishSubscribeDelegate.notifySubscribers(SettingTopic.OVERRIDDEN_CHANGED); - - if (overriddenValue === undefined) { - // Keep overridden value, if invalid fix it - if (prevValue !== undefined) { - this._value = prevValue; - } - this.maybeFixupValue(); - } - - this.setValueValid(this.checkIfValueIsValid(this.getValue())); - - if (prevValue === undefined && overriddenValue !== undefined && isEqual(this._value, overriddenValue)) { - return; - } - - if (prevValue !== undefined && overriddenValue === undefined && isEqual(this._value, prevValue)) { - return; - } - - this._publishSubscribeDelegate.notifySubscribers(SettingTopic.VALUE_CHANGED); - } - - makeSnapshotGetter(topic: T): () => SettingTopicPayloads[T] { - const snapshotGetter = (): any => { - if (topic === SettingTopic.VALUE_CHANGED) { - return this._value; - } - if (topic === SettingTopic.VALIDITY_CHANGED) { - return this._isValueValid; - } - if (topic === SettingTopic.AVAILABLE_VALUES_CHANGED) { - return this._availableValues; - } - if (topic === SettingTopic.OVERRIDDEN_CHANGED) { - return this._overriddenValue; - } - if (topic === SettingTopic.LOADING_STATE_CHANGED) { - return this._loading; - } - if (topic === SettingTopic.PERSISTED_STATE_CHANGED) { - return this.isPersistedValue(); - } - if (topic === SettingTopic.INIT_STATE_CHANGED) { - return this._initialized; - } - }; - - return snapshotGetter; - } - - getPublishSubscribeDelegate(): PublishSubscribeDelegate { - return this._publishSubscribeDelegate; - } - - getAvailableValues(): AvailableValuesType { - return this._availableValues; - } - - maybeResetPersistedValue(): boolean { - if (this._currentValueFromPersistence === null) { - return false; - } - - if (this._owner.isValueValid) { - if (this._owner.isValueValid(this._availableValues, this._currentValueFromPersistence)) { - this._value = this._currentValueFromPersistence; - this._currentValueFromPersistence = null; - return true; - } - return false; - } - - if (Array.isArray(this._currentValueFromPersistence)) { - const currentValueFromPersistence = this._currentValueFromPersistence as TValue[]; - if (currentValueFromPersistence.every((value) => this._availableValues.some((el) => isEqual(el, value)))) { - this._value = this._currentValueFromPersistence; - this._currentValueFromPersistence = null; - return true; - } - return false; - } - - if (this._availableValues.some((el) => isEqual(this._currentValueFromPersistence as TValue, el))) { - this._value = this._currentValueFromPersistence; - this._currentValueFromPersistence = null; - return true; - } - - return false; - } - - setAvailableValues(availableValues: AvailableValuesType): void { - if (isEqual(this._availableValues, availableValues) && this._initialized) { - return; - } - - this._availableValues = availableValues; - let valueChanged = false; - if ((!this.checkIfValueIsValid(this.getValue()) && this.maybeFixupValue()) || this.maybeResetPersistedValue()) { - valueChanged = true; - } - this.setValueValid(this.checkIfValueIsValid(this.getValue())); - this.setInitialized(); - const prevIsValid = this._isValueValid; - if (valueChanged || this._isValueValid !== prevIsValid) { - this._publishSubscribeDelegate.notifySubscribers(SettingTopic.VALUE_CHANGED); - } - this._publishSubscribeDelegate.notifySubscribers(SettingTopic.AVAILABLE_VALUES_CHANGED); - } - - private maybeFixupValue(): boolean { - if (this.checkIfValueIsValid(this._value)) { - return false; - } - - if (this.isPersistedValue()) { - return false; - } - - if (this._availableValues.length === 0) { - return false; - } - - if (this._availableValues.some((el) => isEqual(el, this._value))) { - return false; - } - - let candidate = this._value; - - if (this._owner.fixupValue) { - candidate = this._owner.fixupValue(this._availableValues, this._value); - } else if (Array.isArray(this._value)) { - candidate = [this._availableValues[0]] as TValue; - } else { - candidate = this._availableValues[0] as TValue; - } - - if (isEqual(candidate, this._value)) { - return false; - } - - this._value = candidate; - return true; - } - - private checkIfValueIsValid(value: TValue): boolean { - if (this._owner.isValueValid) { - return this._owner.isValueValid(this._availableValues, value); - } - if (typeof value === "boolean") { - return true; - } - if (this._availableValues.length === 0) { - return false; - } - if (this._availableValues.some((el) => isEqual(el, value))) { - return true; - } - if (isArray(value) && value.every((value) => this._availableValues.some((el) => isEqual(value, el)))) { - return true; - } - return false; - } -} diff --git a/frontend/src/modules/2DViewer/layers/delegates/SettingsContextDelegate.ts b/frontend/src/modules/2DViewer/layers/delegates/SettingsContextDelegate.ts deleted file mode 100644 index 5a0f21b15..000000000 --- a/frontend/src/modules/2DViewer/layers/delegates/SettingsContextDelegate.ts +++ /dev/null @@ -1,379 +0,0 @@ -import { PublishSubscribe, PublishSubscribeDelegate } from "./PublishSubscribeDelegate"; -import { SettingTopic } from "./SettingDelegate"; -import { UnsubscribeHandlerDelegate } from "./UnsubscribeHandlerDelegate"; - -import { Dependency } from "../Dependency"; -import { GlobalSettings, LayerManager, LayerManagerTopic } from "../LayerManager"; -import { - AvailableValuesType, - EachAvailableValuesType, - SerializedSettingsState, - Setting, - Settings, - SettingsContext, - UpdateFunc, -} from "../interfaces"; - -export enum SettingsContextLoadingState { - LOADING = "LOADING", - LOADED = "LOADED", - FAILED = "FAILED", -} - -export enum SettingsContextDelegateTopic { - SETTINGS_CHANGED = "SETTINGS_CHANGED", - LAYER_MANAGER_CHANGED = "LAYER_MANAGER_CHANGED", - LOADING_STATE_CHANGED = "LOADING_STATE_CHANGED", -} - -export type SettingsContextDelegatePayloads = { - [SettingsContextDelegateTopic.SETTINGS_CHANGED]: void; - [SettingsContextDelegateTopic.LAYER_MANAGER_CHANGED]: void; - [SettingsContextDelegateTopic.LOADING_STATE_CHANGED]: SettingsContextLoadingState; -}; - -export interface FetchDataFunction { - (oldValues: { [K in TKey]: TSettings[K] }, newValues: { [K in TKey]: TSettings[K] }): void; -} - -export type SettingsContextDelegateState = { - values: { [K in TKey]: TSettings[K] }; -}; - -export class SettingsContextDelegate - implements PublishSubscribe -{ - private _parentContext: SettingsContext; - private _layerManager: LayerManager; - private _settings: { [K in TKey]: Setting } = {} as { [K in TKey]: Setting }; - private _overriddenSettings: { [K in TKey]: TSettings[K] } = {} as { [K in TKey]: TSettings[K] }; - private _publishSubscribeDelegate = new PublishSubscribeDelegate(); - private _unsubscribeHandler: UnsubscribeHandlerDelegate = new UnsubscribeHandlerDelegate(); - private _loadingState: SettingsContextLoadingState = SettingsContextLoadingState.LOADING; - - constructor( - context: SettingsContext, - layerManager: LayerManager, - settings: { [K in TKey]: Setting } - ) { - this._parentContext = context; - this._layerManager = layerManager; - - for (const key in settings) { - this._unsubscribeHandler.registerUnsubscribeFunction( - "settings", - settings[key] - .getDelegate() - .getPublishSubscribeDelegate() - .makeSubscriberFunction(SettingTopic.VALUE_CHANGED)(() => { - this.handleSettingChanged(); - }) - ); - this._unsubscribeHandler.registerUnsubscribeFunction( - "settings", - settings[key] - .getDelegate() - .getPublishSubscribeDelegate() - .makeSubscriberFunction(SettingTopic.LOADING_STATE_CHANGED)(() => { - this.handleSettingsLoadingStateChanged(); - }) - ); - } - - this._settings = settings; - - this.createDependencies(); - } - - getLayerManager(): LayerManager { - return this._layerManager; - } - - getValues(): { [K in TKey]?: TSettings[K] } { - const settings: { [K in TKey]?: TSettings[K] } = {} as { [K in TKey]?: TSettings[K] }; - for (const key in this._settings) { - if (this._settings[key].getDelegate().isPersistedValue()) { - settings[key] = undefined; - continue; - } - settings[key] = this._settings[key].getDelegate().getValue(); - } - - return settings; - } - - setOverriddenSettings(overriddenSettings: { [K in TKey]: TSettings[K] }): void { - this._overriddenSettings = overriddenSettings; - for (const key in this._settings) { - if (Object.keys(this._overriddenSettings).includes(key)) { - this._settings[key].getDelegate().setOverriddenValue(this._overriddenSettings[key]); - } else { - this._settings[key].getDelegate().setOverriddenValue(undefined); - } - } - } - - areCurrentSettingsValid(): boolean { - for (const key in this._settings) { - if (!this._settings[key].getDelegate().isValueValid()) { - return false; - } - } - - if (!this._parentContext.areCurrentSettingsValid) { - return true; - } - - const settings: TSettings = {} as TSettings; - for (const key in this._settings) { - settings[key] = this._settings[key].getDelegate().getValue(); - } - - return this._parentContext.areCurrentSettingsValid(settings); - } - - areAllSettingsLoaded(): boolean { - for (const key in this._settings) { - if (this._settings[key].getDelegate().isLoading()) { - return false; - } - } - - return true; - } - - areAllSettingsInitialized(): boolean { - for (const key in this._settings) { - if ( - !this._settings[key].getDelegate().isInitialized() || - this._settings[key].getDelegate().isPersistedValue() - ) { - return false; - } - } - - return true; - } - - isSomePersistedSettingNotValid(): boolean { - for (const key in this._settings) { - if ( - !this._settings[key].getDelegate().isLoading() && - this._settings[key].getDelegate().isPersistedValue() && - !this._settings[key].getDelegate().isValueValid() && - this._settings[key].getDelegate().isInitialized() - ) { - return true; - } - } - - return false; - } - - getInvalidSettings(): string[] { - const invalidSettings: string[] = []; - for (const key in this._settings) { - if (!this._settings[key].getDelegate().isValueValid()) { - invalidSettings.push(this._settings[key].getLabel()); - } - } - - return invalidSettings; - } - - setAvailableValues(key: K, availableValues: AvailableValuesType): void { - const settingDelegate = this._settings[key].getDelegate(); - settingDelegate.setAvailableValues(availableValues); - - this.getLayerManager().publishTopic(LayerManagerTopic.AVAILABLE_SETTINGS_CHANGED); - } - - getSettings() { - return this._settings; - } - - makeSnapshotGetter(topic: T): () => SettingsContextDelegatePayloads[T] { - const snapshotGetter = (): any => { - if (topic === SettingsContextDelegateTopic.SETTINGS_CHANGED) { - return; - } - if (topic === SettingsContextDelegateTopic.LAYER_MANAGER_CHANGED) { - return; - } - if (topic === SettingsContextDelegateTopic.LOADING_STATE_CHANGED) { - return this._loadingState; - } - }; - - return snapshotGetter; - } - - getPublishSubscribeDelegate(): PublishSubscribeDelegate { - return this._publishSubscribeDelegate; - } - - serializeSettings(): SerializedSettingsState { - const serializedSettings: SerializedSettingsState = {} as SerializedSettingsState; - for (const key in this._settings) { - serializedSettings[key] = this._settings[key].getDelegate().serializeValue(); - } - return serializedSettings; - } - - deserializeSettings(serializedSettings: SerializedSettingsState): void { - for (const [key, value] of Object.entries(serializedSettings)) { - const settingDelegate = this._settings[key as TKey].getDelegate(); - settingDelegate.deserializeValue(value); - if (settingDelegate.isStatic()) { - settingDelegate.maybeResetPersistedValue(); - } - } - } - - createDependencies(): void { - this._unsubscribeHandler.unsubscribe("dependencies"); - - const makeSettingGetter = (key: K, handler: (value: TSettings[K]) => void) => { - const handleChange = (): void => { - handler(this._settings[key].getDelegate().getValue()); - }; - this._unsubscribeHandler.registerUnsubscribeFunction( - "dependencies", - this._settings[key] - .getDelegate() - .getPublishSubscribeDelegate() - .makeSubscriberFunction(SettingTopic.VALUE_CHANGED)(handleChange) - ); - - this._unsubscribeHandler.registerUnsubscribeFunction( - "dependencies", - this._settings[key] - .getDelegate() - .getPublishSubscribeDelegate() - .makeSubscriberFunction(SettingTopic.PERSISTED_STATE_CHANGED)(handleChange) - ); - - return handleChange; - }; - - const makeGlobalSettingGetter = ( - key: K, - handler: (value: GlobalSettings[K]) => void - ) => { - const handleChange = (): void => { - handler(this.getLayerManager.bind(this)().getGlobalSetting(key)); - }; - this._unsubscribeHandler.registerUnsubscribeFunction( - "dependencies", - this.getLayerManager() - .getPublishSubscribeDelegate() - .makeSubscriberFunction(LayerManagerTopic.GLOBAL_SETTINGS_CHANGED)(handleChange) - ); - - return handleChange; - }; - - const availableSettingsUpdater = ( - settingKey: K, - updateFunc: UpdateFunc, TSettings, K> - ): Dependency, TSettings, K> => { - const dependency = new Dependency, TSettings, K>( - this as unknown as SettingsContextDelegate, - updateFunc, - makeSettingGetter, - makeGlobalSettingGetter - ); - - dependency.subscribe((availableValues: AvailableValuesType | null) => { - if (availableValues === null) { - this.setAvailableValues(settingKey, [] as unknown as AvailableValuesType); - return; - } - this.setAvailableValues(settingKey, availableValues); - }); - - dependency.subscribeLoading((loading: boolean, hasDependencies: boolean) => { - this._settings[settingKey].getDelegate().setLoading(loading); - - if (!hasDependencies) { - this.handleSettingChanged(); - } - }); - - dependency.initialize(); - - return dependency; - }; - - const helperDependency = ( - update: (args: { - getLocalSetting: (settingName: T) => TSettings[T]; - getGlobalSetting: (settingName: T) => GlobalSettings[T]; - getHelperDependency: (dep: Dependency) => TDep | null; - abortSignal: AbortSignal; - }) => T - ) => { - const dependency = new Dependency( - this as unknown as SettingsContextDelegate, - update, - makeSettingGetter, - makeGlobalSettingGetter - ); - - dependency.initialize(); - - return dependency; - }; - - if (this._parentContext.defineDependencies) { - this._parentContext.defineDependencies({ - availableSettingsUpdater, - helperDependency, - workbenchSession: this.getLayerManager().getWorkbenchSession(), - workbenchSettings: this.getLayerManager().getWorkbenchSettings(), - queryClient: this.getLayerManager().getQueryClient(), - }); - } - } - - beforeDestroy(): void { - this._unsubscribeHandler.unsubscribeAll(); - } - - private setLoadingState(loadingState: SettingsContextLoadingState) { - if (this._loadingState === loadingState) { - return; - } - - this._loadingState = loadingState; - this._publishSubscribeDelegate.notifySubscribers(SettingsContextDelegateTopic.LOADING_STATE_CHANGED); - } - - private handleSettingChanged() { - // this.getLayerManager().publishTopic(LayerManagerTopic.SETTINGS_CHANGED); - - if (!this.areAllSettingsLoaded() || !this.areAllSettingsInitialized()) { - this.setLoadingState(SettingsContextLoadingState.LOADING); - return; - } - - if (this.isSomePersistedSettingNotValid() || !this.areCurrentSettingsValid()) { - this.setLoadingState(SettingsContextLoadingState.FAILED); - return; - } - - this.setLoadingState(SettingsContextLoadingState.LOADED); - this._publishSubscribeDelegate.notifySubscribers(SettingsContextDelegateTopic.SETTINGS_CHANGED); - } - - private handleSettingsLoadingStateChanged() { - for (const key in this._settings) { - if (this._settings[key].getDelegate().isLoading()) { - this.setLoadingState(SettingsContextLoadingState.LOADING); - return; - } - } - - this.setLoadingState(SettingsContextLoadingState.LOADED); - } -} diff --git a/frontend/src/modules/2DViewer/layers/delegates/UnsubscribeHandlerDelegate.ts b/frontend/src/modules/2DViewer/layers/delegates/UnsubscribeHandlerDelegate.ts deleted file mode 100644 index 067c8d830..000000000 --- a/frontend/src/modules/2DViewer/layers/delegates/UnsubscribeHandlerDelegate.ts +++ /dev/null @@ -1,30 +0,0 @@ -export class UnsubscribeHandlerDelegate { - private _subscriptions: Map void>> = new Map(); - - registerUnsubscribeFunction(topic: string, callback: () => void): void { - let subscriptionsSet = this._subscriptions.get(topic); - if (!subscriptionsSet) { - subscriptionsSet = new Set(); - this._subscriptions.set(topic, subscriptionsSet); - } - subscriptionsSet.add(callback); - } - - unsubscribe(topic: string): void { - const subscriptionsSet = this._subscriptions.get(topic); - if (subscriptionsSet) { - for (const unsubscribeFunc of subscriptionsSet) { - unsubscribeFunc(); - } - this._subscriptions.delete(topic); - } - } - - unsubscribeAll(): void { - for (const subscriptionsSet of this._subscriptions.values()) { - for (const unsubscribeFunc of subscriptionsSet) { - unsubscribeFunc(); - } - } - } -} diff --git a/frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellTrajectoriesLayer/DrilledWellTrajectoriesContext.ts b/frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellTrajectoriesLayer/DrilledWellTrajectoriesContext.ts deleted file mode 100644 index 4b9e466de..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellTrajectoriesLayer/DrilledWellTrajectoriesContext.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { apiService } from "@framework/ApiService"; -import { LayerManager } from "@modules/2DViewer/layers/LayerManager"; -import { SettingsContextDelegate } from "@modules/2DViewer/layers/delegates/SettingsContextDelegate"; -import { SettingType } from "@modules/2DViewer/layers/implementations/settings/settingsTypes"; -import { CACHE_TIME, STALE_TIME } from "@modules/2DViewer/layers/queryConstants"; -import { cancelPromiseOnAbort } from "@modules/2DViewer/layers/utils"; - -import { DrilledWellTrajectoriesSettings } from "./types"; - -import { DefineDependenciesArgs, SettingsContext } from "../../../interfaces"; -import { DrilledWellbores } from "../../settings/DrilledWellbores"; -import { Ensemble } from "../../settings/Ensemble"; - -export class DrilledWellTrajectoriesContext implements SettingsContext { - private _contextDelegate: SettingsContextDelegate; - - constructor(layerManager: LayerManager) { - this._contextDelegate = new SettingsContextDelegate< - DrilledWellTrajectoriesSettings, - keyof DrilledWellTrajectoriesSettings - >(this, layerManager, { - [SettingType.ENSEMBLE]: new Ensemble(), - [SettingType.SMDA_WELLBORE_HEADERS]: new DrilledWellbores(), - }); - } - - getDelegate(): SettingsContextDelegate { - return this._contextDelegate; - } - - getSettings() { - return this._contextDelegate.getSettings(); - } - - defineDependencies({ - helperDependency, - availableSettingsUpdater, - workbenchSession, - queryClient, - }: DefineDependenciesArgs) { - availableSettingsUpdater(SettingType.ENSEMBLE, ({ getGlobalSetting }) => { - const fieldIdentifier = getGlobalSetting("fieldId"); - const ensembles = getGlobalSetting("ensembles"); - - const ensembleIdents = ensembles - .filter((ensemble) => ensemble.getFieldIdentifier() === fieldIdentifier) - .map((ensemble) => ensemble.getIdent()); - - return ensembleIdents; - }); - - const wellboreHeadersDep = helperDependency(async function fetchData({ getLocalSetting, abortSignal }) { - const ensembleIdent = getLocalSetting(SettingType.ENSEMBLE); - - if (!ensembleIdent) { - return null; - } - - const ensembleSet = workbenchSession.getEnsembleSet(); - const ensemble = ensembleSet.findEnsemble(ensembleIdent); - - if (!ensemble) { - return null; - } - - const fieldIdentifier = ensemble.getFieldIdentifier(); - - return await queryClient.fetchQuery({ - queryKey: ["getDrilledWellboreHeaders", fieldIdentifier], - queryFn: () => - cancelPromiseOnAbort(apiService.well.getDrilledWellboreHeaders(fieldIdentifier), abortSignal), - staleTime: STALE_TIME, - gcTime: CACHE_TIME, - }); - }); - availableSettingsUpdater(SettingType.SMDA_WELLBORE_HEADERS, ({ getHelperDependency }) => { - const wellboreHeaders = getHelperDependency(wellboreHeadersDep); - - if (!wellboreHeaders) { - return []; - } - - return wellboreHeaders; - }); - } -} diff --git a/frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellTrajectoriesLayer/DrilledWellTrajectoriesLayer.ts b/frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellTrajectoriesLayer/DrilledWellTrajectoriesLayer.ts deleted file mode 100644 index 961b1f4e1..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellTrajectoriesLayer/DrilledWellTrajectoriesLayer.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { WellboreTrajectory_api } from "@api"; -import { apiService } from "@framework/ApiService"; -import { LayerManager } from "@modules/2DViewer/layers/LayerManager"; -import { LayerRegistry } from "@modules/2DViewer/layers/LayerRegistry"; -import { ItemDelegate } from "@modules/2DViewer/layers/delegates/ItemDelegate"; -import { SettingType } from "@modules/2DViewer/layers/implementations/settings/settingsTypes"; -import { QueryClient } from "@tanstack/react-query"; - -import { isEqual } from "lodash"; - -import { DrilledWellTrajectoriesContext } from "./DrilledWellTrajectoriesContext"; -import { DrilledWellTrajectoriesSettings } from "./types"; - -import { LayerColoringType, LayerDelegate } from "../../../delegates/LayerDelegate"; -import { BoundingBox, Layer, SerializedLayer } from "../../../interfaces"; - -export class DrilledWellTrajectoriesLayer implements Layer { - private _layerDelegate: LayerDelegate; - private _itemDelegate: ItemDelegate; - - constructor(layerManager: LayerManager) { - this._itemDelegate = new ItemDelegate("Drilled Wellbore trajectories", layerManager); - this._layerDelegate = new LayerDelegate( - this, - layerManager, - new DrilledWellTrajectoriesContext(layerManager), - LayerColoringType.NONE - ); - } - - getSettingsContext() { - return this._layerDelegate.getSettingsContext(); - } - - getItemDelegate(): ItemDelegate { - return this._itemDelegate; - } - - getLayerDelegate(): LayerDelegate { - return this._layerDelegate; - } - - doSettingsChangesRequireDataRefetch( - prevSettings: DrilledWellTrajectoriesSettings, - newSettings: DrilledWellTrajectoriesSettings - ): boolean { - return !isEqual(prevSettings, newSettings); - } - - makeBoundingBox(): BoundingBox | null { - const data = this._layerDelegate.getData(); - if (!data) { - return null; - } - - const bbox: BoundingBox = { - x: [Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER], - y: [Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER], - z: [Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER], - }; - - for (const trajectory of data) { - for (const point of trajectory.eastingArr) { - bbox.x[0] = Math.min(bbox.x[0], point); - bbox.x[1] = Math.max(bbox.x[1], point); - } - for (const point of trajectory.northingArr) { - bbox.y[0] = Math.min(bbox.y[0], point); - bbox.y[1] = Math.max(bbox.y[1], point); - } - for (const point of trajectory.tvdMslArr) { - bbox.z[0] = Math.min(bbox.z[0], point); - bbox.z[1] = Math.max(bbox.z[1], point); - } - } - - return bbox; - } - - fechData(queryClient: QueryClient): Promise { - const workbenchSession = this.getSettingsContext().getDelegate().getLayerManager().getWorkbenchSession(); - const ensembleSet = workbenchSession.getEnsembleSet(); - const settings = this.getSettingsContext().getDelegate().getSettings(); - const ensembleIdent = settings[SettingType.ENSEMBLE].getDelegate().getValue(); - const selectedWellboreHeaders = settings[SettingType.SMDA_WELLBORE_HEADERS].getDelegate().getValue(); - let selectedWellboreUuids: string[] = []; - if (selectedWellboreHeaders) { - selectedWellboreUuids = selectedWellboreHeaders.map((header) => header.wellboreUuid); - } - - let fieldIdentifier: string | null = null; - if (ensembleIdent) { - const ensemble = ensembleSet.findEnsemble(ensembleIdent); - if (ensemble) { - fieldIdentifier = ensemble.getFieldIdentifier(); - } - } - - const queryKey = ["getWellTrajectories", fieldIdentifier]; - this._layerDelegate.registerQueryKey(queryKey); - - const promise = queryClient - .fetchQuery({ - queryKey, - queryFn: () => apiService.well.getWellTrajectories(fieldIdentifier ?? ""), - staleTime: 1800000, // TODO - gcTime: 1800000, - }) - .then((response: WellboreTrajectory_api[]) => { - return response.filter((trajectory) => selectedWellboreUuids.includes(trajectory.wellboreUuid)); - }); - - return promise; - } - - serializeState(): SerializedLayer { - return this._layerDelegate.serializeState(); - } - - deserializeState(serializedState: SerializedLayer): void { - this._layerDelegate.deserializeState(serializedState); - } -} - -LayerRegistry.registerLayer(DrilledWellTrajectoriesLayer); diff --git a/frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellTrajectoriesLayer/types.ts b/frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellTrajectoriesLayer/types.ts deleted file mode 100644 index f4877d5b6..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellTrajectoriesLayer/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { WellboreHeader_api } from "@api"; -import { EnsembleIdent } from "@framework/EnsembleIdent"; -import { SettingType } from "@modules/2DViewer/layers/implementations/settings/settingsTypes"; - -export type DrilledWellTrajectoriesSettings = { - [SettingType.ENSEMBLE]: EnsembleIdent | null; - [SettingType.SMDA_WELLBORE_HEADERS]: WellboreHeader_api[] | null; -}; diff --git a/frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellborePicksLayer/DrilledWellborePicksContext.ts b/frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellborePicksLayer/DrilledWellborePicksContext.ts deleted file mode 100644 index e2e7fb5ff..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellborePicksLayer/DrilledWellborePicksContext.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { apiService } from "@framework/ApiService"; -import { LayerManager } from "@modules/2DViewer/layers/LayerManager"; -import { SettingsContextDelegate } from "@modules/2DViewer/layers/delegates/SettingsContextDelegate"; -import { SettingType } from "@modules/2DViewer/layers/implementations/settings/settingsTypes"; -import { CACHE_TIME, STALE_TIME } from "@modules/2DViewer/layers/queryConstants"; -import { cancelPromiseOnAbort } from "@modules/2DViewer/layers/utils"; - -import { DrilledWellborePicksSettings } from "./types"; - -import { DefineDependenciesArgs, SettingsContext } from "../../../interfaces"; -import { DrilledWellbores } from "../../settings/DrilledWellbores"; -import { Ensemble } from "../../settings/Ensemble"; -import { SurfaceName } from "../../settings/SurfaceName"; - -export class DrilledWellborePicksContext implements SettingsContext { - private _contextDelegate: SettingsContextDelegate; - - constructor(layerManager: LayerManager) { - this._contextDelegate = new SettingsContextDelegate< - DrilledWellborePicksSettings, - keyof DrilledWellborePicksSettings - >(this, layerManager, { - [SettingType.ENSEMBLE]: new Ensemble(), - [SettingType.SMDA_WELLBORE_HEADERS]: new DrilledWellbores(), - [SettingType.SURFACE_NAME]: new SurfaceName(), - }); - } - - getDelegate(): SettingsContextDelegate { - return this._contextDelegate; - } - - getSettings() { - return this._contextDelegate.getSettings(); - } - - areCurrentSettingsValid(settings: DrilledWellborePicksSettings): boolean { - return ( - settings[SettingType.ENSEMBLE] !== null && - settings[SettingType.SMDA_WELLBORE_HEADERS] !== null && - settings[SettingType.SMDA_WELLBORE_HEADERS].length > 0 && - settings[SettingType.SURFACE_NAME] !== null - ); - } - - defineDependencies({ - helperDependency, - availableSettingsUpdater, - workbenchSession, - queryClient, - }: DefineDependenciesArgs) { - availableSettingsUpdater(SettingType.ENSEMBLE, ({ getGlobalSetting }) => { - const fieldIdentifier = getGlobalSetting("fieldId"); - const ensembles = getGlobalSetting("ensembles"); - - const ensembleIdents = ensembles - .filter((ensemble) => ensemble.getFieldIdentifier() === fieldIdentifier) - .map((ensemble) => ensemble.getIdent()); - - return ensembleIdents; - }); - - const wellboreHeadersDep = helperDependency(async function fetchData({ getLocalSetting, abortSignal }) { - const ensembleIdent = getLocalSetting(SettingType.ENSEMBLE); - - if (!ensembleIdent) { - return null; - } - - const ensembleSet = workbenchSession.getEnsembleSet(); - const ensemble = ensembleSet.findEnsemble(ensembleIdent); - - if (!ensemble) { - return null; - } - - const fieldIdentifier = ensemble.getFieldIdentifier(); - - return await queryClient.fetchQuery({ - queryKey: ["getDrilledWellboreHeaders", fieldIdentifier], - queryFn: () => - cancelPromiseOnAbort(apiService.well.getDrilledWellboreHeaders(fieldIdentifier), abortSignal), - staleTime: STALE_TIME, - gcTime: CACHE_TIME, - }); - }); - - const pickIdentifiersDep = helperDependency(async function fetchData({ getLocalSetting, abortSignal }) { - const ensembleIdent = getLocalSetting(SettingType.ENSEMBLE); - - if (!ensembleIdent) { - return null; - } - - const ensembleSet = workbenchSession.getEnsembleSet(); - const ensemble = ensembleSet.findEnsemble(ensembleIdent); - - if (!ensemble) { - return null; - } - - const fieldIdentifier = ensemble.getFieldIdentifier(); - const stratColumnIdentifier = ensemble.getStratigraphicColumnIdentifier(); - - return await queryClient.fetchQuery({ - queryKey: ["getPickStratigraphy", fieldIdentifier, stratColumnIdentifier], - queryFn: () => - cancelPromiseOnAbort( - apiService.well.getWellborePickIdentifiers(fieldIdentifier, stratColumnIdentifier), - abortSignal - ), - staleTime: STALE_TIME, - gcTime: CACHE_TIME, - }); - }); - - availableSettingsUpdater(SettingType.SMDA_WELLBORE_HEADERS, ({ getHelperDependency }) => { - const wellboreHeaders = getHelperDependency(wellboreHeadersDep); - - if (!wellboreHeaders) { - return []; - } - - return wellboreHeaders; - }); - - availableSettingsUpdater(SettingType.SURFACE_NAME, ({ getHelperDependency }) => { - const pickIdentifiers = getHelperDependency(pickIdentifiersDep); - - if (!pickIdentifiers) { - return []; - } - - return pickIdentifiers; - }); - } -} diff --git a/frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellborePicksLayer/DrilledWellborePicksLayer.ts b/frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellborePicksLayer/DrilledWellborePicksLayer.ts deleted file mode 100644 index 27fb63e4a..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellborePicksLayer/DrilledWellborePicksLayer.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { WellborePick_api } from "@api"; -import { apiService } from "@framework/ApiService"; -import { LayerManager } from "@modules/2DViewer/layers/LayerManager"; -import { LayerRegistry } from "@modules/2DViewer/layers/LayerRegistry"; -import { ItemDelegate } from "@modules/2DViewer/layers/delegates/ItemDelegate"; -import { SettingType } from "@modules/2DViewer/layers/implementations/settings/settingsTypes"; -import { CACHE_TIME, STALE_TIME } from "@modules/2DViewer/layers/queryConstants"; -import { QueryClient } from "@tanstack/react-query"; - -import { isEqual } from "lodash"; - -import { DrilledWellborePicksContext } from "./DrilledWellborePicksContext"; -import { DrilledWellborePicksSettings } from "./types"; - -import { LayerColoringType, LayerDelegate } from "../../../delegates/LayerDelegate"; -import { BoundingBox, Layer, SerializedLayer } from "../../../interfaces"; - -export class DrilledWellborePicksLayer implements Layer { - private _layerDelegate: LayerDelegate; - private _itemDelegate: ItemDelegate; - - constructor(layerManager: LayerManager) { - this._itemDelegate = new ItemDelegate("Drilled Wellbore picks", layerManager); - this._layerDelegate = new LayerDelegate( - this, - layerManager, - new DrilledWellborePicksContext(layerManager), - LayerColoringType.NONE - ); - } - - getSettingsContext() { - return this._layerDelegate.getSettingsContext(); - } - - getItemDelegate(): ItemDelegate { - return this._itemDelegate; - } - - getLayerDelegate(): LayerDelegate { - return this._layerDelegate; - } - - doSettingsChangesRequireDataRefetch( - prevSettings: DrilledWellborePicksSettings, - newSettings: DrilledWellborePicksSettings - ): boolean { - return !isEqual(prevSettings, newSettings); - } - - makeBoundingBox(): BoundingBox | null { - const data = this._layerDelegate.getData(); - if (!data) { - return null; - } - - const bbox: BoundingBox = { - x: [Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER], - y: [Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER], - z: [Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER], - }; - - for (const trajectory of data) { - bbox.x[0] = Math.min(bbox.x[0], trajectory.easting); - bbox.x[1] = Math.max(bbox.x[1], trajectory.easting); - - bbox.y[0] = Math.min(bbox.y[0], trajectory.northing); - bbox.y[1] = Math.max(bbox.y[1], trajectory.northing); - - bbox.z[0] = Math.min(bbox.z[0], trajectory.tvdMsl); - bbox.z[1] = Math.max(bbox.z[1], trajectory.tvdMsl); - } - - return bbox; - } - - fechData(queryClient: QueryClient): Promise { - const workbenchSession = this.getSettingsContext().getDelegate().getLayerManager().getWorkbenchSession(); - const ensembleSet = workbenchSession.getEnsembleSet(); - const settings = this.getSettingsContext().getDelegate().getSettings(); - const ensembleIdent = settings[SettingType.ENSEMBLE].getDelegate().getValue(); - const selectedWellboreHeaders = settings[SettingType.SMDA_WELLBORE_HEADERS].getDelegate().getValue(); - let selectedWellboreUuids: string[] = []; - if (selectedWellboreHeaders) { - selectedWellboreUuids = selectedWellboreHeaders.map((header) => header.wellboreUuid); - } - const selectedPickIdentifier = settings[SettingType.SURFACE_NAME].getDelegate().getValue(); - let fieldIdentifier: string | null = null; - if (ensembleIdent) { - const ensemble = ensembleSet.findEnsemble(ensembleIdent); - if (ensemble) { - fieldIdentifier = ensemble.getFieldIdentifier(); - } - } - - const queryKey = ["getWellborePicksForPickIdentifier", fieldIdentifier, selectedPickIdentifier]; - this._layerDelegate.registerQueryKey(queryKey); - - const promise = queryClient - .fetchQuery({ - queryKey, - queryFn: () => - apiService.well.getWellborePicksForPickIdentifier( - fieldIdentifier ?? "", - selectedPickIdentifier ?? "" - ), - staleTime: STALE_TIME, - gcTime: CACHE_TIME, - }) - .then((response: WellborePick_api[]) => { - return response.filter((trajectory) => selectedWellboreUuids.includes(trajectory.wellboreUuid)); - }); - - return promise; - } - - serializeState(): SerializedLayer { - return this._layerDelegate.serializeState(); - } - - deserializeState(state: SerializedLayer): void { - this._layerDelegate.deserializeState(state); - } -} - -LayerRegistry.registerLayer(DrilledWellborePicksLayer); diff --git a/frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellborePicksLayer/types.ts b/frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellborePicksLayer/types.ts deleted file mode 100644 index ace87b9b8..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/layers/DrilledWellborePicksLayer/types.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { WellboreHeader_api } from "@api"; -import { EnsembleIdent } from "@framework/EnsembleIdent"; -import { SettingType } from "@modules/2DViewer/layers/implementations/settings/settingsTypes"; - -export type DrilledWellborePicksSettings = { - [SettingType.ENSEMBLE]: EnsembleIdent | null; - [SettingType.SMDA_WELLBORE_HEADERS]: WellboreHeader_api[] | null; - [SettingType.SURFACE_NAME]: string | null; -}; diff --git a/frontend/src/modules/2DViewer/layers/implementations/layers/ObservedSurfaceLayer/ObservedSurfaceContext.ts b/frontend/src/modules/2DViewer/layers/implementations/layers/ObservedSurfaceLayer/ObservedSurfaceContext.ts deleted file mode 100644 index 8888954eb..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/layers/ObservedSurfaceLayer/ObservedSurfaceContext.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { SurfaceMetaSet_api, SurfaceTimeType_api } from "@api"; -import { apiService } from "@framework/ApiService"; -import { LayerManager } from "@modules/2DViewer/layers/LayerManager"; -import { SettingsContextDelegate } from "@modules/2DViewer/layers/delegates/SettingsContextDelegate"; -import { SettingType } from "@modules/2DViewer/layers/implementations/settings/settingsTypes"; -import { CACHE_TIME, STALE_TIME } from "@modules/2DViewer/layers/queryConstants"; -import { cancelPromiseOnAbort } from "@modules/2DViewer/layers/utils"; - -import { ObservedSurfaceSettings } from "./types"; - -import { DefineDependenciesArgs, SettingsContext } from "../../../interfaces"; -import { Ensemble } from "../../settings/Ensemble"; -import { SurfaceAttribute } from "../../settings/SurfaceAttribute"; -import { SurfaceName } from "../../settings/SurfaceName"; -import { TimeOrInterval } from "../../settings/TimeOrInterval"; - -export class ObservedSurfaceContext implements SettingsContext { - private _contextDelegate: SettingsContextDelegate; - private _fetchDataCache: SurfaceMetaSet_api | null = null; - - constructor(layerManager: LayerManager) { - this._contextDelegate = new SettingsContextDelegate( - this, - layerManager, - { - [SettingType.ENSEMBLE]: new Ensemble(), - [SettingType.SURFACE_ATTRIBUTE]: new SurfaceAttribute(), - [SettingType.SURFACE_NAME]: new SurfaceName(), - [SettingType.TIME_OR_INTERVAL]: new TimeOrInterval(), - } - ); - } - - getDelegate(): SettingsContextDelegate { - return this._contextDelegate; - } - - getSettings() { - return this._contextDelegate.getSettings(); - } - defineDependencies({ - helperDependency, - availableSettingsUpdater, - workbenchSession, - queryClient, - }: DefineDependenciesArgs) { - availableSettingsUpdater(SettingType.ENSEMBLE, ({ getGlobalSetting }) => { - const fieldIdentifier = getGlobalSetting("fieldId"); - const ensembleSet = workbenchSession.getEnsembleSet(); - - const ensembleIdents = ensembleSet - .getEnsembleArr() - .filter((ensemble) => ensemble.getFieldIdentifier() === fieldIdentifier) - .map((ensemble) => ensemble.getIdent()); - - return ensembleIdents; - }); - - const observedSurfaceMetadataDep = helperDependency(async ({ getLocalSetting, abortSignal }) => { - const ensembleIdent = getLocalSetting(SettingType.ENSEMBLE); - - if (!ensembleIdent) { - return null; - } - - return await queryClient.fetchQuery({ - queryKey: ["getObservedSurfacesMetadata", ensembleIdent.getCaseUuid()], - queryFn: () => - cancelPromiseOnAbort( - apiService.surface.getObservedSurfacesMetadata(ensembleIdent.getCaseUuid()), - abortSignal - ), - staleTime: STALE_TIME, - gcTime: CACHE_TIME, - }); - }); - - availableSettingsUpdater(SettingType.SURFACE_ATTRIBUTE, ({ getHelperDependency }) => { - const data = getHelperDependency(observedSurfaceMetadataDep); - - if (!data) { - return []; - } - - const availableAttributes = [ - ...Array.from(new Set(data.surfaces.map((surface) => surface.attribute_name))), - ]; - - return availableAttributes; - }); - - availableSettingsUpdater(SettingType.SURFACE_NAME, ({ getHelperDependency, getLocalSetting }) => { - const attribute = getLocalSetting(SettingType.SURFACE_ATTRIBUTE); - const data = getHelperDependency(observedSurfaceMetadataDep); - - if (!attribute || !data) { - return []; - } - - const availableSurfaceNames = [ - ...Array.from( - new Set( - data.surfaces.filter((surface) => surface.attribute_name === attribute).map((el) => el.name) - ) - ), - ]; - - return availableSurfaceNames; - }); - - availableSettingsUpdater(SettingType.TIME_OR_INTERVAL, ({ getLocalSetting, getHelperDependency }) => { - const attribute = getLocalSetting(SettingType.SURFACE_ATTRIBUTE); - const surfaceName = getLocalSetting(SettingType.SURFACE_NAME); - const data = getHelperDependency(observedSurfaceMetadataDep); - - if (!attribute || !surfaceName || !data) { - return []; - } - - const availableTimeOrIntervals: string[] = []; - const availableTimeTypes = [ - ...Array.from( - new Set( - data.surfaces - .filter((surface) => surface.attribute_name === attribute && surface.name === surfaceName) - .map((el) => el.time_type) - ) - ), - ]; - - if (availableTimeTypes.includes(SurfaceTimeType_api.NO_TIME)) { - availableTimeOrIntervals.push(SurfaceTimeType_api.NO_TIME); - } - if (availableTimeTypes.includes(SurfaceTimeType_api.TIME_POINT)) { - availableTimeOrIntervals.push(...data.time_points_iso_str); - } - if (availableTimeTypes.includes(SurfaceTimeType_api.INTERVAL)) { - availableTimeOrIntervals.push(...data.time_intervals_iso_str); - } - - return availableTimeOrIntervals; - }); - } -} diff --git a/frontend/src/modules/2DViewer/layers/implementations/layers/ObservedSurfaceLayer/ObservedSurfaceLayer.ts b/frontend/src/modules/2DViewer/layers/implementations/layers/ObservedSurfaceLayer/ObservedSurfaceLayer.ts deleted file mode 100644 index 67ef98914..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/layers/ObservedSurfaceLayer/ObservedSurfaceLayer.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { SurfaceDataPng_api } from "@api"; -import { apiService } from "@framework/ApiService"; -import { LayerManager } from "@modules/2DViewer/layers/LayerManager"; -import { LayerRegistry } from "@modules/2DViewer/layers/LayerRegistry"; -import { ItemDelegate } from "@modules/2DViewer/layers/delegates/ItemDelegate"; -import { SettingType } from "@modules/2DViewer/layers/implementations/settings/settingsTypes"; -import { CACHE_TIME, STALE_TIME } from "@modules/2DViewer/layers/queryConstants"; -import { FullSurfaceAddress, SurfaceAddressBuilder } from "@modules/_shared/Surface"; -import { SurfaceDataFloat_trans, transformSurfaceData } from "@modules/_shared/Surface/queryDataTransforms"; -import { encodeSurfAddrStr } from "@modules/_shared/Surface/surfaceAddress"; -import { QueryClient } from "@tanstack/react-query"; - -import { isEqual } from "lodash"; - -import { ObservedSurfaceContext } from "./ObservedSurfaceContext"; -import { ObservedSurfaceSettings } from "./types"; - -import { LayerColoringType, LayerDelegate } from "../../../delegates/LayerDelegate"; -import { BoundingBox, Layer, SerializedLayer } from "../../../interfaces"; - -export class ObservedSurfaceLayer - implements Layer -{ - private _layerDelegate: LayerDelegate; - private _itemDelegate: ItemDelegate; - - constructor(layerManager: LayerManager) { - this._itemDelegate = new ItemDelegate("Observed Surface", layerManager); - this._layerDelegate = new LayerDelegate( - this, - layerManager, - new ObservedSurfaceContext(layerManager), - LayerColoringType.COLORSCALE - ); - } - - getSettingsContext() { - return this._layerDelegate.getSettingsContext(); - } - - getItemDelegate(): ItemDelegate { - return this._itemDelegate; - } - - getLayerDelegate(): LayerDelegate { - return this._layerDelegate; - } - - doSettingsChangesRequireDataRefetch( - prevSettings: ObservedSurfaceSettings, - newSettings: ObservedSurfaceSettings - ): boolean { - return !isEqual(prevSettings, newSettings); - } - - makeBoundingBox(): BoundingBox | null { - const data = this._layerDelegate.getData(); - if (!data) { - return null; - } - - return { - x: [data.transformed_bbox_utm.min_x, data.transformed_bbox_utm.max_x], - y: [data.transformed_bbox_utm.min_y, data.transformed_bbox_utm.max_y], - z: [0, 0], - }; - } - - makeValueRange(): [number, number] | null { - const data = this._layerDelegate.getData(); - if (!data) { - return null; - } - - return [data.value_min, data.value_max]; - } - - fechData(queryClient: QueryClient): Promise { - let surfaceAddress: FullSurfaceAddress | null = null; - const addrBuilder = new SurfaceAddressBuilder(); - - const settings = this.getSettingsContext().getDelegate().getSettings(); - const ensembleIdent = settings[SettingType.ENSEMBLE].getDelegate().getValue(); - const surfaceName = settings[SettingType.SURFACE_NAME].getDelegate().getValue(); - const attribute = settings[SettingType.SURFACE_ATTRIBUTE].getDelegate().getValue(); - const timeOrInterval = settings[SettingType.TIME_OR_INTERVAL].getDelegate().getValue(); - - if (ensembleIdent && surfaceName && attribute && timeOrInterval) { - addrBuilder.withEnsembleIdent(ensembleIdent); - addrBuilder.withName(surfaceName); - addrBuilder.withAttribute(attribute); - addrBuilder.withTimeOrInterval(timeOrInterval); - - surfaceAddress = addrBuilder.buildObservedAddress(); - } - - const surfAddrStr = surfaceAddress ? encodeSurfAddrStr(surfaceAddress) : null; - - const queryKey = ["getSurfaceData", surfAddrStr, null, "png"]; - - this._layerDelegate.registerQueryKey(queryKey); - - const promise = queryClient - .fetchQuery({ - queryKey, - queryFn: () => apiService.surface.getSurfaceData(surfAddrStr ?? "", "png", null), - staleTime: STALE_TIME, - gcTime: CACHE_TIME, - }) - .then((data) => transformSurfaceData(data)); - - return promise; - } - - serializeState(): SerializedLayer { - return this._layerDelegate.serializeState(); - } - - deserializeState(serializedState: SerializedLayer): void { - this._layerDelegate.deserializeState(serializedState); - } -} - -LayerRegistry.registerLayer(ObservedSurfaceLayer); diff --git a/frontend/src/modules/2DViewer/layers/implementations/layers/ObservedSurfaceLayer/types.ts b/frontend/src/modules/2DViewer/layers/implementations/layers/ObservedSurfaceLayer/types.ts deleted file mode 100644 index 26d641e44..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/layers/ObservedSurfaceLayer/types.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { EnsembleIdent } from "@framework/EnsembleIdent"; -import { SettingType } from "@modules/2DViewer/layers/implementations/settings/settingsTypes"; - -export type ObservedSurfaceSettings = { - [SettingType.ENSEMBLE]: EnsembleIdent | null; - [SettingType.SURFACE_ATTRIBUTE]: string | null; - [SettingType.SURFACE_NAME]: string | null; - [SettingType.TIME_OR_INTERVAL]: string | null; -}; diff --git a/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationGridLayer/RealizationGridContext.ts b/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationGridLayer/RealizationGridContext.ts deleted file mode 100644 index e768409b5..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationGridLayer/RealizationGridContext.ts +++ /dev/null @@ -1,180 +0,0 @@ -import { apiService } from "@framework/ApiService"; -import { LayerManager } from "@modules/2DViewer/layers/LayerManager"; -import { SettingsContextDelegate } from "@modules/2DViewer/layers/delegates/SettingsContextDelegate"; -import { SettingType } from "@modules/2DViewer/layers/implementations/settings/settingsTypes"; -import { CACHE_TIME, STALE_TIME } from "@modules/2DViewer/layers/queryConstants"; -import { cancelQueryOnAbort } from "@modules/2DViewer/layers/utils"; - -import { RealizationGridSettings } from "./types"; - -import { DefineDependenciesArgs, SettingsContext } from "../../../interfaces"; -import { Ensemble } from "../../settings/Ensemble"; -import { GridAttribute } from "../../settings/GridAttribute"; -import { GridLayer } from "../../settings/GridLayer"; -import { GridName } from "../../settings/GridName"; -import { Realization } from "../../settings/Realization"; -import { ShowGridLines } from "../../settings/ShowGridLines"; -import { TimeOrInterval } from "../../settings/TimeOrInterval"; - -export class RealizationGridContext implements SettingsContext { - private _contextDelegate: SettingsContextDelegate; - - constructor(layerManager: LayerManager) { - this._contextDelegate = new SettingsContextDelegate( - this, - layerManager, - { - [SettingType.ENSEMBLE]: new Ensemble(), - [SettingType.REALIZATION]: new Realization(), - [SettingType.GRID_NAME]: new GridName(), - [SettingType.GRID_ATTRIBUTE]: new GridAttribute(), - [SettingType.GRID_LAYER]: new GridLayer(), - [SettingType.TIME_OR_INTERVAL]: new TimeOrInterval(), - [SettingType.SHOW_GRID_LINES]: new ShowGridLines(), - } - ); - } - - areCurrentSettingsValid(settings: RealizationGridSettings): boolean { - return ( - settings[SettingType.ENSEMBLE] !== null && - settings[SettingType.REALIZATION] !== null && - settings[SettingType.GRID_NAME] !== null && - settings[SettingType.GRID_ATTRIBUTE] !== null && - settings[SettingType.GRID_LAYER] !== null && - settings[SettingType.TIME_OR_INTERVAL] !== null - ); - } - - getDelegate(): SettingsContextDelegate { - return this._contextDelegate; - } - - getSettings() { - return this._contextDelegate.getSettings(); - } - defineDependencies({ - helperDependency, - availableSettingsUpdater, - workbenchSession, - queryClient, - }: DefineDependenciesArgs) { - availableSettingsUpdater(SettingType.ENSEMBLE, ({ getGlobalSetting }) => { - const fieldIdentifier = getGlobalSetting("fieldId"); - const ensembles = getGlobalSetting("ensembles"); - - const ensembleIdents = ensembles - .filter((ensemble) => ensemble.getFieldIdentifier() === fieldIdentifier) - .map((ensemble) => ensemble.getIdent()); - - return ensembleIdents; - }); - - availableSettingsUpdater(SettingType.REALIZATION, ({ getLocalSetting, getGlobalSetting }) => { - const ensembleIdent = getLocalSetting(SettingType.ENSEMBLE); - const realizationFilterFunc = getGlobalSetting("realizationFilterFunction"); - - if (!ensembleIdent) { - return []; - } - - const realizations = realizationFilterFunc(ensembleIdent); - - return [...realizations]; - }); - const realizationGridDataDep = helperDependency(async ({ getLocalSetting, abortSignal }) => { - const ensembleIdent = getLocalSetting(SettingType.ENSEMBLE); - const realization = getLocalSetting(SettingType.REALIZATION); - - if (!ensembleIdent || realization === null) { - return null; - } - - return await cancelQueryOnAbort(queryClient, abortSignal, { - queryKey: ["getRealizationGridMetadata", ensembleIdent, realization], - queryFn: () => - apiService.grid3D.getGridModelsInfo( - ensembleIdent.getCaseUuid(), - ensembleIdent.getEnsembleName(), - realization - ), - staleTime: STALE_TIME, - gcTime: CACHE_TIME, - }); - }); - - availableSettingsUpdater(SettingType.GRID_NAME, ({ getHelperDependency }) => { - const data = getHelperDependency(realizationGridDataDep); - - if (!data) { - return []; - } - - const availableGridNames = [...Array.from(new Set(data.map((gridModelInfo) => gridModelInfo.grid_name)))]; - - return availableGridNames; - }); - - availableSettingsUpdater(SettingType.GRID_ATTRIBUTE, ({ getLocalSetting, getHelperDependency }) => { - const gridName = getLocalSetting(SettingType.GRID_NAME); - const data = getHelperDependency(realizationGridDataDep); - - if (!gridName || !data) { - return []; - } - - const gridAttributeArr = - data.find((gridModel) => gridModel.grid_name === gridName)?.property_info_arr ?? []; - - const availableGridAttributes = [ - ...Array.from(new Set(gridAttributeArr.map((gridAttribute) => gridAttribute.property_name))), - ]; - - return availableGridAttributes; - }); - - availableSettingsUpdater(SettingType.GRID_LAYER, ({ getLocalSetting, getHelperDependency }) => { - const gridName = getLocalSetting(SettingType.GRID_NAME); - const data = getHelperDependency(realizationGridDataDep); - - if (!gridName || !data) { - return []; - } - - const gridDimensions = data.find((gridModel) => gridModel.grid_name === gridName)?.dimensions ?? null; - const availableGridLayers: number[] = []; - if (gridDimensions) { - availableGridLayers.push(gridDimensions.i_count); - availableGridLayers.push(gridDimensions.j_count); - availableGridLayers.push(gridDimensions.k_count); - } - - return availableGridLayers; - }); - - availableSettingsUpdater(SettingType.TIME_OR_INTERVAL, ({ getLocalSetting, getHelperDependency }) => { - const gridName = getLocalSetting(SettingType.GRID_NAME); - const gridAttribute = getLocalSetting(SettingType.GRID_ATTRIBUTE); - const data = getHelperDependency(realizationGridDataDep); - - if (!gridName || !gridAttribute || !data) { - return []; - } - - const gridAttributeArr = - data.find((gridModel) => gridModel.grid_name === gridName)?.property_info_arr ?? []; - - const availableTimeOrIntervals = [ - ...Array.from( - new Set( - gridAttributeArr - .filter((attr) => attr.property_name === gridAttribute) - .map((gridAttribute) => gridAttribute.iso_date_or_interval ?? "NO_TIME") - ) - ), - ]; - - return availableTimeOrIntervals; - }); - } -} diff --git a/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationGridLayer/RealizationGridLayer.ts b/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationGridLayer/RealizationGridLayer.ts deleted file mode 100644 index 4ff662e3e..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationGridLayer/RealizationGridLayer.ts +++ /dev/null @@ -1,204 +0,0 @@ -import { apiService } from "@framework/ApiService"; -import { LayerManager } from "@modules/2DViewer/layers/LayerManager"; -import { LayerRegistry } from "@modules/2DViewer/layers/LayerRegistry"; -import { ItemDelegate } from "@modules/2DViewer/layers/delegates/ItemDelegate"; -import { SettingType } from "@modules/2DViewer/layers/implementations/settings/settingsTypes"; -import { CACHE_TIME, STALE_TIME } from "@modules/2DViewer/layers/queryConstants"; -import { - GridMappedProperty_trans, - GridSurface_trans, - transformGridMappedProperty, - transformGridSurface, -} from "@modules/3DViewer/view/queries/queryDataTransforms"; -import { QueryClient } from "@tanstack/react-query"; - -import { isEqual } from "lodash"; - -import { RealizationGridContext } from "./RealizationGridContext"; -import { RealizationGridSettings } from "./types"; - -import { LayerColoringType, LayerDelegate } from "../../../delegates/LayerDelegate"; -import { BoundingBox, Layer, SerializedLayer } from "../../../interfaces"; - -export class RealizationGridLayer - implements - Layer< - RealizationGridSettings, - { - gridSurfaceData: GridSurface_trans; - gridParameterData: GridMappedProperty_trans; - } - > -{ - private _layerDelegate: LayerDelegate< - RealizationGridSettings, - { - gridSurfaceData: GridSurface_trans; - gridParameterData: GridMappedProperty_trans; - } - >; - private _itemDelegate: ItemDelegate; - - constructor(layerManager: LayerManager) { - this._itemDelegate = new ItemDelegate("Realization Grid layer", layerManager); - this._layerDelegate = new LayerDelegate( - this, - layerManager, - new RealizationGridContext(layerManager), - LayerColoringType.COLORSCALE - ); - } - - getSettingsContext() { - return this._layerDelegate.getSettingsContext(); - } - - getItemDelegate(): ItemDelegate { - return this._itemDelegate; - } - - getLayerDelegate(): LayerDelegate< - RealizationGridSettings, - { - gridSurfaceData: GridSurface_trans; - gridParameterData: GridMappedProperty_trans; - } - > { - return this._layerDelegate; - } - - doSettingsChangesRequireDataRefetch( - prevSettings: RealizationGridSettings, - newSettings: RealizationGridSettings - ): boolean { - return !isEqual(prevSettings, newSettings); - } - - makeBoundingBox(): BoundingBox | null { - const data = this._layerDelegate.getData(); - if (!data) { - return null; - } - - return { - x: [ - data.gridSurfaceData.origin_utm_x + data.gridSurfaceData.xmin, - data.gridSurfaceData.origin_utm_x + data.gridSurfaceData.xmax, - ], - y: [ - data.gridSurfaceData.origin_utm_y + data.gridSurfaceData.ymin, - data.gridSurfaceData.origin_utm_y + data.gridSurfaceData.ymax, - ], - z: [data.gridSurfaceData.zmin, data.gridSurfaceData.zmax], - }; - } - - makeValueRange(): [number, number] | null { - const data = this._layerDelegate.getData(); - if (!data) { - return null; - } - - return [data.gridParameterData.min_grid_prop_value, data.gridParameterData.max_grid_prop_value]; - } - - fechData(queryClient: QueryClient): Promise<{ - gridSurfaceData: GridSurface_trans; - gridParameterData: GridMappedProperty_trans; - }> { - const settings = this.getSettingsContext().getDelegate().getSettings(); - const ensembleIdent = settings[SettingType.ENSEMBLE].getDelegate().getValue(); - const realizationNum = settings[SettingType.REALIZATION].getDelegate().getValue(); - const gridName = settings[SettingType.GRID_NAME].getDelegate().getValue(); - const attribute = settings[SettingType.GRID_ATTRIBUTE].getDelegate().getValue(); - let timeOrInterval = settings[SettingType.TIME_OR_INTERVAL].getDelegate().getValue(); - if (timeOrInterval === "NO_TIME") { - timeOrInterval = null; - } - let availableDimensions = settings[SettingType.GRID_LAYER].getDelegate().getAvailableValues(); - if (!availableDimensions.length || availableDimensions[0] === null) { - availableDimensions = [0, 0, 0]; - } - const layerIndex = settings[SettingType.GRID_LAYER].getDelegate().getValue(); - const iMin = 0; - const iMax = availableDimensions[0] || 0; - const jMin = 0; - const jMax = availableDimensions[1] || 0; - const kMin = layerIndex || 0; - const kMax = layerIndex || 0; - const queryKey = [ - "gridParameter", - ensembleIdent, - gridName, - attribute, - timeOrInterval, - realizationNum, - iMin, - iMax, - jMin, - jMax, - kMin, - kMax, - ]; - this._layerDelegate.registerQueryKey(queryKey); - - const gridParameterPromise = queryClient - .fetchQuery({ - queryKey, - queryFn: () => - apiService.grid3D.gridParameter( - ensembleIdent?.getCaseUuid() ?? "", - ensembleIdent?.getEnsembleName() ?? "", - gridName ?? "", - attribute ?? "", - realizationNum ?? 0, - timeOrInterval, - iMin, - iMax - 1, - jMin, - jMax - 1, - kMin, - kMax - ), - staleTime: STALE_TIME, - gcTime: CACHE_TIME, - }) - .then(transformGridMappedProperty); - - const gridSurfacePromise = queryClient - .fetchQuery({ - queryKey: ["getGridData", ensembleIdent, gridName, realizationNum, iMin, iMax, jMin, jMax, kMin, kMax], - queryFn: () => - apiService.grid3D.gridSurface( - ensembleIdent?.getCaseUuid() ?? "", - ensembleIdent?.getEnsembleName() ?? "", - gridName ?? "", - realizationNum ?? 0, - iMin, - iMax - 1, - jMin, - jMax - 1, - kMin, - kMax - ), - staleTime: STALE_TIME, - gcTime: CACHE_TIME, - }) - .then(transformGridSurface); - - return Promise.all([gridSurfacePromise, gridParameterPromise]).then(([gridSurfaceData, gridParameterData]) => ({ - gridSurfaceData, - gridParameterData, - })); - } - - serializeState(): SerializedLayer { - return this._layerDelegate.serializeState(); - } - - deserializeState(serializedState: SerializedLayer): void { - this._layerDelegate.deserializeState(serializedState); - } -} - -LayerRegistry.registerLayer(RealizationGridLayer); diff --git a/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationGridLayer/types.ts b/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationGridLayer/types.ts deleted file mode 100644 index 8dbbeb749..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationGridLayer/types.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { EnsembleIdent } from "@framework/EnsembleIdent"; -import { SettingType } from "@modules/2DViewer/layers/implementations/settings/settingsTypes"; - -export type RealizationGridSettings = { - [SettingType.ENSEMBLE]: EnsembleIdent | null; - [SettingType.REALIZATION]: number | null; - [SettingType.GRID_ATTRIBUTE]: string | null; - [SettingType.GRID_NAME]: string | null; - [SettingType.GRID_LAYER]: number | null; - [SettingType.TIME_OR_INTERVAL]: string | null; - [SettingType.SHOW_GRID_LINES]: boolean; -}; diff --git a/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationPolygonsLayer/RealizationPolygonsContext.ts b/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationPolygonsLayer/RealizationPolygonsContext.ts deleted file mode 100644 index d1a5c73ed..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationPolygonsLayer/RealizationPolygonsContext.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { PolygonsMeta_api } from "@api"; -import { apiService } from "@framework/ApiService"; -import { LayerManager } from "@modules/2DViewer/layers/LayerManager"; -import { SettingsContextDelegate } from "@modules/2DViewer/layers/delegates/SettingsContextDelegate"; -import { SettingType } from "@modules/2DViewer/layers/implementations/settings/settingsTypes"; -import { CACHE_TIME, STALE_TIME } from "@modules/2DViewer/layers/queryConstants"; -import { cancelPromiseOnAbort } from "@modules/2DViewer/layers/utils"; - -import { RealizationPolygonsSettings } from "./types"; - -import { DefineDependenciesArgs, SettingsContext } from "../../../interfaces"; -import { Ensemble } from "../../settings/Ensemble"; -import { PolygonsAttribute } from "../../settings/PolygonsAttribute"; -import { PolygonsName } from "../../settings/PolygonsName"; -import { Realization } from "../../settings/Realization"; - -export class RealizationPolygonsContext implements SettingsContext { - private _contextDelegate: SettingsContextDelegate; - private _fetchDataCache: PolygonsMeta_api[] | null = null; - - constructor(layerManager: LayerManager) { - this._contextDelegate = new SettingsContextDelegate< - RealizationPolygonsSettings, - keyof RealizationPolygonsSettings - >(this, layerManager, { - [SettingType.ENSEMBLE]: new Ensemble(), - [SettingType.REALIZATION]: new Realization(), - [SettingType.POLYGONS_ATTRIBUTE]: new PolygonsAttribute(), - [SettingType.POLYGONS_NAME]: new PolygonsName(), - }); - } - - getDelegate(): SettingsContextDelegate { - return this._contextDelegate; - } - - getSettings() { - return this._contextDelegate.getSettings(); - } - - defineDependencies({ - helperDependency, - availableSettingsUpdater, - workbenchSession, - queryClient, - }: DefineDependenciesArgs) { - availableSettingsUpdater(SettingType.ENSEMBLE, ({ getGlobalSetting }) => { - const fieldIdentifier = getGlobalSetting("fieldId"); - const ensembles = getGlobalSetting("ensembles"); - - const ensembleIdents = ensembles - .filter((ensemble) => ensemble.getFieldIdentifier() === fieldIdentifier) - .map((ensemble) => ensemble.getIdent()); - - return ensembleIdents; - }); - - availableSettingsUpdater(SettingType.REALIZATION, ({ getLocalSetting, getGlobalSetting }) => { - const ensembleIdent = getLocalSetting(SettingType.ENSEMBLE); - const realizationFilterFunc = getGlobalSetting("realizationFilterFunction"); - - if (!ensembleIdent) { - return []; - } - - const realizations = realizationFilterFunc(ensembleIdent); - - return [...realizations]; - }); - - const realizationPolygonsMetadataDep = helperDependency(async ({ getLocalSetting, abortSignal }) => { - const ensembleIdent = getLocalSetting(SettingType.ENSEMBLE); - - if (!ensembleIdent) { - return null; - } - - return await queryClient.fetchQuery({ - queryKey: ["getRealizationPolygonsMetadata", ensembleIdent], - queryFn: () => - cancelPromiseOnAbort( - apiService.polygons.getPolygonsDirectory( - ensembleIdent.getCaseUuid(), - ensembleIdent.getEnsembleName() - ), - abortSignal - ), - staleTime: STALE_TIME, - gcTime: CACHE_TIME, - }); - }); - - availableSettingsUpdater(SettingType.POLYGONS_ATTRIBUTE, ({ getHelperDependency }) => { - const data = getHelperDependency(realizationPolygonsMetadataDep); - - if (!data) { - return []; - } - - const availableAttributes = [ - ...Array.from(new Set(data.map((polygonsMeta) => polygonsMeta.attribute_name))), - ]; - - return availableAttributes; - }); - - availableSettingsUpdater(SettingType.POLYGONS_NAME, ({ getHelperDependency, getLocalSetting }) => { - const attribute = getLocalSetting(SettingType.POLYGONS_ATTRIBUTE); - const data = getHelperDependency(realizationPolygonsMetadataDep); - - if (!attribute || !data) { - return []; - } - - const availableSurfaceNames = [ - ...Array.from( - new Set( - data.filter((polygonsMeta) => polygonsMeta.attribute_name === attribute).map((el) => el.name) - ) - ), - ]; - - return availableSurfaceNames; - }); - } -} diff --git a/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationPolygonsLayer/RealizationPolygonsLayer.ts b/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationPolygonsLayer/RealizationPolygonsLayer.ts deleted file mode 100644 index 7cf7e6753..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationPolygonsLayer/RealizationPolygonsLayer.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { PolygonData_api } from "@api"; -import { apiService } from "@framework/ApiService"; -import { LayerManager } from "@modules/2DViewer/layers/LayerManager"; -import { LayerRegistry } from "@modules/2DViewer/layers/LayerRegistry"; -import { ItemDelegate } from "@modules/2DViewer/layers/delegates/ItemDelegate"; -import { LayerColoringType, LayerDelegate } from "@modules/2DViewer/layers/delegates/LayerDelegate"; -import { SettingType } from "@modules/2DViewer/layers/implementations/settings/settingsTypes"; -import { CACHE_TIME, STALE_TIME } from "@modules/2DViewer/layers/queryConstants"; -import { QueryClient } from "@tanstack/react-query"; - -import { isEqual } from "lodash"; - -import { RealizationPolygonsContext } from "./RealizationPolygonsContext"; -import { RealizationPolygonsSettings } from "./types"; - -import { BoundingBox, Layer, SerializedLayer } from "../../../interfaces"; - -export class RealizationPolygonsLayer implements Layer { - private _layerDelegate: LayerDelegate; - private _itemDelegate: ItemDelegate; - - constructor(layerManager: LayerManager) { - this._itemDelegate = new ItemDelegate("Realization Polygons", layerManager); - this._layerDelegate = new LayerDelegate( - this, - layerManager, - new RealizationPolygonsContext(layerManager), - LayerColoringType.NONE - ); - } - - getSettingsContext() { - return this._layerDelegate.getSettingsContext(); - } - - getItemDelegate(): ItemDelegate { - return this._itemDelegate; - } - - getLayerDelegate(): LayerDelegate { - return this._layerDelegate; - } - - doSettingsChangesRequireDataRefetch( - prevSettings: RealizationPolygonsSettings, - newSettings: RealizationPolygonsSettings - ): boolean { - return !isEqual(prevSettings, newSettings); - } - - makeBoundingBox(): BoundingBox | null { - const data = this._layerDelegate.getData(); - if (!data) { - return null; - } - - const bbox: BoundingBox = { - x: [Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY], - y: [Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY], - z: [Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY], - }; - - for (const polygon of data) { - for (const point of polygon.x_arr) { - bbox.x[0] = Math.min(bbox.x[0], point); - bbox.x[1] = Math.max(bbox.x[1], point); - } - for (const point of polygon.y_arr) { - bbox.y[0] = Math.min(bbox.y[0], point); - bbox.y[1] = Math.max(bbox.y[1], point); - } - for (const point of polygon.z_arr) { - bbox.z[0] = Math.min(bbox.z[0], point); - bbox.z[1] = Math.max(bbox.z[1], point); - } - } - - return bbox; - } - - fechData(queryClient: QueryClient): Promise { - const settings = this.getSettingsContext().getDelegate().getSettings(); - const ensembleIdent = settings[SettingType.ENSEMBLE].getDelegate().getValue(); - const realizationNum = settings[SettingType.REALIZATION].getDelegate().getValue(); - const polygonsName = settings[SettingType.POLYGONS_NAME].getDelegate().getValue(); - const polygonsAttribute = settings[SettingType.POLYGONS_ATTRIBUTE].getDelegate().getValue(); - - const queryKey = [ - "getPolygonsData", - ensembleIdent?.getCaseUuid() ?? "", - ensembleIdent?.getEnsembleName() ?? "", - realizationNum ?? 0, - polygonsName ?? "", - polygonsAttribute ?? "", - ]; - this._layerDelegate.registerQueryKey(queryKey); - - const promise = queryClient.fetchQuery({ - queryKey, - queryFn: () => - apiService.polygons.getPolygonsData( - ensembleIdent?.getCaseUuid() ?? "", - ensembleIdent?.getEnsembleName() ?? "", - realizationNum ?? 0, - polygonsName ?? "", - polygonsAttribute ?? "" - ), - staleTime: STALE_TIME, - gcTime: CACHE_TIME, - }); - - return promise; - } - - serializeState(): SerializedLayer { - return this._layerDelegate.serializeState(); - } - - deserializeState(serializedState: SerializedLayer): void { - this._layerDelegate.deserializeState(serializedState); - } -} - -LayerRegistry.registerLayer(RealizationPolygonsLayer); diff --git a/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationPolygonsLayer/types.ts b/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationPolygonsLayer/types.ts deleted file mode 100644 index cc5807a1e..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationPolygonsLayer/types.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { EnsembleIdent } from "@framework/EnsembleIdent"; - -import { SettingType } from "../../settings/settingsTypes"; - -export type RealizationPolygonsSettings = { - [SettingType.ENSEMBLE]: EnsembleIdent | null; - [SettingType.REALIZATION]: number | null; - [SettingType.POLYGONS_ATTRIBUTE]: string | null; - [SettingType.POLYGONS_NAME]: string | null; -}; diff --git a/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationSurfaceLayer/RealizationSurfaceContext.ts b/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationSurfaceLayer/RealizationSurfaceContext.ts deleted file mode 100644 index 19cbdc478..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationSurfaceLayer/RealizationSurfaceContext.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { SurfaceTimeType_api } from "@api"; -import { apiService } from "@framework/ApiService"; -import { LayerManager } from "@modules/2DViewer/layers/LayerManager"; -import { SettingsContextDelegate } from "@modules/2DViewer/layers/delegates/SettingsContextDelegate"; -import { SettingType } from "@modules/2DViewer/layers/implementations/settings/settingsTypes"; -import { CACHE_TIME, STALE_TIME } from "@modules/2DViewer/layers/queryConstants"; -import { cancelPromiseOnAbort } from "@modules/2DViewer/layers/utils"; - -import { RealizationSurfaceSettings } from "./types"; - -import { DefineDependenciesArgs, SettingsContext } from "../../../interfaces"; -import { Ensemble } from "../../settings/Ensemble"; -import { Realization } from "../../settings/Realization"; -import { SurfaceAttribute } from "../../settings/SurfaceAttribute"; -import { SurfaceName } from "../../settings/SurfaceName"; -import { TimeOrInterval } from "../../settings/TimeOrInterval"; - -export class RealizationSurfaceContext implements SettingsContext { - private _contextDelegate: SettingsContextDelegate; - - constructor(layerManager: LayerManager) { - this._contextDelegate = new SettingsContextDelegate< - RealizationSurfaceSettings, - keyof RealizationSurfaceSettings - >(this, layerManager, { - [SettingType.ENSEMBLE]: new Ensemble(), - [SettingType.REALIZATION]: new Realization(), - [SettingType.SURFACE_ATTRIBUTE]: new SurfaceAttribute(), - [SettingType.SURFACE_NAME]: new SurfaceName(), - [SettingType.TIME_OR_INTERVAL]: new TimeOrInterval(), - }); - } - - getDelegate(): SettingsContextDelegate { - return this._contextDelegate; - } - - getSettings() { - return this._contextDelegate.getSettings(); - } - - defineDependencies({ - helperDependency, - availableSettingsUpdater, - queryClient, - }: DefineDependenciesArgs) { - availableSettingsUpdater(SettingType.ENSEMBLE, ({ getGlobalSetting }) => { - const fieldIdentifier = getGlobalSetting("fieldId"); - const ensembles = getGlobalSetting("ensembles"); - - const ensembleIdents = ensembles - .filter((ensemble) => ensemble.getFieldIdentifier() === fieldIdentifier) - .map((ensemble) => ensemble.getIdent()); - - return ensembleIdents; - }); - - availableSettingsUpdater(SettingType.REALIZATION, ({ getLocalSetting, getGlobalSetting }) => { - const ensembleIdent = getLocalSetting(SettingType.ENSEMBLE); - const realizationFilterFunc = getGlobalSetting("realizationFilterFunction"); - - if (!ensembleIdent) { - return []; - } - - const realizations = realizationFilterFunc(ensembleIdent); - - return [...realizations]; - }); - - const realizationSurfaceMetadataDep = helperDependency(async ({ getLocalSetting, abortSignal }) => { - const ensembleIdent = getLocalSetting(SettingType.ENSEMBLE); - - if (!ensembleIdent) { - return null; - } - - return await queryClient.fetchQuery({ - queryKey: ["getRealizationSurfacesMetadata", ensembleIdent], - queryFn: () => - cancelPromiseOnAbort( - apiService.surface.getRealizationSurfacesMetadata( - ensembleIdent.getCaseUuid(), - ensembleIdent.getEnsembleName() - ), - abortSignal - ), - staleTime: STALE_TIME, - gcTime: CACHE_TIME, - }); - }); - - availableSettingsUpdater(SettingType.SURFACE_ATTRIBUTE, ({ getHelperDependency }) => { - const data = getHelperDependency(realizationSurfaceMetadataDep); - - if (!data) { - return []; - } - - const availableAttributes = [ - ...Array.from(new Set(data.surfaces.map((surface) => surface.attribute_name))), - ]; - - return availableAttributes; - }); - - availableSettingsUpdater(SettingType.SURFACE_NAME, ({ getHelperDependency, getLocalSetting }) => { - const attribute = getLocalSetting(SettingType.SURFACE_ATTRIBUTE); - const data = getHelperDependency(realizationSurfaceMetadataDep); - - if (!attribute || !data) { - return []; - } - - const availableSurfaceNames = [ - ...Array.from( - new Set( - data.surfaces.filter((surface) => surface.attribute_name === attribute).map((el) => el.name) - ) - ), - ]; - - return availableSurfaceNames; - }); - - availableSettingsUpdater(SettingType.TIME_OR_INTERVAL, ({ getLocalSetting, getHelperDependency }) => { - const attribute = getLocalSetting(SettingType.SURFACE_ATTRIBUTE); - const surfaceName = getLocalSetting(SettingType.SURFACE_NAME); - const data = getHelperDependency(realizationSurfaceMetadataDep); - - if (!attribute || !surfaceName || !data) { - return []; - } - - const availableTimeOrIntervals: string[] = []; - const availableTimeTypes = [ - ...Array.from( - new Set( - data.surfaces - .filter((surface) => surface.attribute_name === attribute && surface.name === surfaceName) - .map((el) => el.time_type) - ) - ), - ]; - - if (availableTimeTypes.includes(SurfaceTimeType_api.NO_TIME)) { - availableTimeOrIntervals.push(SurfaceTimeType_api.NO_TIME); - } - if (availableTimeTypes.includes(SurfaceTimeType_api.TIME_POINT)) { - availableTimeOrIntervals.push(...data.time_points_iso_str); - } - if (availableTimeTypes.includes(SurfaceTimeType_api.INTERVAL)) { - availableTimeOrIntervals.push(...data.time_intervals_iso_str); - } - - return availableTimeOrIntervals; - }); - } -} diff --git a/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationSurfaceLayer/RealizationSurfaceLayer.ts b/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationSurfaceLayer/RealizationSurfaceLayer.ts deleted file mode 100644 index 3dec51ed0..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationSurfaceLayer/RealizationSurfaceLayer.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { SurfaceDataPng_api, SurfaceTimeType_api } from "@api"; -import { apiService } from "@framework/ApiService"; -import { LayerManager } from "@modules/2DViewer/layers/LayerManager"; -import { LayerRegistry } from "@modules/2DViewer/layers/LayerRegistry"; -import { ItemDelegate } from "@modules/2DViewer/layers/delegates/ItemDelegate"; -import { LayerColoringType, LayerDelegate } from "@modules/2DViewer/layers/delegates/LayerDelegate"; -import { SettingType } from "@modules/2DViewer/layers/implementations/settings/settingsTypes"; -import { CACHE_TIME, STALE_TIME } from "@modules/2DViewer/layers/queryConstants"; -import { FullSurfaceAddress, SurfaceAddressBuilder } from "@modules/_shared/Surface"; -import { SurfaceDataFloat_trans, transformSurfaceData } from "@modules/_shared/Surface/queryDataTransforms"; -import { encodeSurfAddrStr } from "@modules/_shared/Surface/surfaceAddress"; -import { QueryClient } from "@tanstack/react-query"; - -import { isEqual } from "lodash"; - -import { RealizationSurfaceContext } from "./RealizationSurfaceContext"; -import { RealizationSurfaceSettings } from "./types"; - -import { BoundingBox, Layer, SerializedLayer } from "../../../interfaces"; - -export class RealizationSurfaceLayer - implements Layer -{ - private _layerDelegate: LayerDelegate; - private _itemDelegate: ItemDelegate; - - constructor(layerManager: LayerManager) { - this._itemDelegate = new ItemDelegate("Realization Surface", layerManager); - this._layerDelegate = new LayerDelegate( - this, - layerManager, - new RealizationSurfaceContext(layerManager), - LayerColoringType.COLORSCALE - ); - } - - getSettingsContext() { - return this._layerDelegate.getSettingsContext(); - } - - getItemDelegate(): ItemDelegate { - return this._itemDelegate; - } - - getLayerDelegate(): LayerDelegate { - return this._layerDelegate; - } - - doSettingsChangesRequireDataRefetch( - prevSettings: RealizationSurfaceSettings, - newSettings: RealizationSurfaceSettings - ): boolean { - return !isEqual(prevSettings, newSettings); - } - - makeBoundingBox(): BoundingBox | null { - const data = this._layerDelegate.getData(); - if (!data) { - return null; - } - - return { - x: [data.transformed_bbox_utm.min_x, data.transformed_bbox_utm.max_x], - y: [data.transformed_bbox_utm.min_y, data.transformed_bbox_utm.max_y], - z: [0, 0], - }; - } - - makeValueRange(): [number, number] | null { - const data = this._layerDelegate.getData(); - if (!data) { - return null; - } - - return [data.value_min, data.value_max]; - } - - fechData(queryClient: QueryClient): Promise { - let surfaceAddress: FullSurfaceAddress | null = null; - const addrBuilder = new SurfaceAddressBuilder(); - - const settings = this.getSettingsContext().getDelegate().getSettings(); - const ensembleIdent = settings[SettingType.ENSEMBLE].getDelegate().getValue(); - const realizationNum = settings[SettingType.REALIZATION].getDelegate().getValue(); - const surfaceName = settings[SettingType.SURFACE_NAME].getDelegate().getValue(); - const attribute = settings[SettingType.SURFACE_ATTRIBUTE].getDelegate().getValue(); - const timeOrInterval = settings[SettingType.TIME_OR_INTERVAL].getDelegate().getValue(); - - if (ensembleIdent && surfaceName && attribute && realizationNum !== null) { - addrBuilder.withEnsembleIdent(ensembleIdent); - addrBuilder.withName(surfaceName); - addrBuilder.withAttribute(attribute); - addrBuilder.withRealization(realizationNum); - - if (timeOrInterval !== SurfaceTimeType_api.NO_TIME) { - addrBuilder.withTimeOrInterval(timeOrInterval); - } - - surfaceAddress = addrBuilder.buildRealizationAddress(); - } - - const surfAddrStr = surfaceAddress ? encodeSurfAddrStr(surfaceAddress) : null; - - const queryKey = ["getSurfaceData", surfAddrStr, null, "png"]; - - this._layerDelegate.registerQueryKey(queryKey); - - const promise = queryClient - .fetchQuery({ - queryKey, - queryFn: () => apiService.surface.getSurfaceData(surfAddrStr ?? "", "png", null), - staleTime: STALE_TIME, - gcTime: CACHE_TIME, - }) - .then((data) => transformSurfaceData(data)); - - return promise; - } - - serializeState(): SerializedLayer { - return this._layerDelegate.serializeState(); - } - - deserializeState(serializedState: SerializedLayer): void { - this._layerDelegate.deserializeState(serializedState); - } -} - -LayerRegistry.registerLayer(RealizationSurfaceLayer); diff --git a/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationSurfaceLayer/types.ts b/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationSurfaceLayer/types.ts deleted file mode 100644 index 4eb3e2c98..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/layers/RealizationSurfaceLayer/types.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { EnsembleIdent } from "@framework/EnsembleIdent"; - -import { SettingType } from "../../settings/settingsTypes"; - -export type RealizationSurfaceSettings = { - [SettingType.ENSEMBLE]: EnsembleIdent | null; - [SettingType.REALIZATION]: number | null; - [SettingType.SURFACE_ATTRIBUTE]: string | null; - [SettingType.SURFACE_NAME]: string | null; - [SettingType.TIME_OR_INTERVAL]: string | null; -}; diff --git a/frontend/src/modules/2DViewer/layers/implementations/layers/StatisticalSurfaceLayer/StatisticalSurfaceContext.ts b/frontend/src/modules/2DViewer/layers/implementations/layers/StatisticalSurfaceLayer/StatisticalSurfaceContext.ts deleted file mode 100644 index 22832de4b..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/layers/StatisticalSurfaceLayer/StatisticalSurfaceContext.ts +++ /dev/null @@ -1,173 +0,0 @@ -import { SurfaceStatisticFunction_api, SurfaceTimeType_api } from "@api"; -import { apiService } from "@framework/ApiService"; -import { LayerManager } from "@modules/2DViewer/layers/LayerManager"; -import { CACHE_TIME, STALE_TIME } from "@modules/2DViewer/layers/queryConstants"; -import { cancelPromiseOnAbort } from "@modules/2DViewer/layers/utils"; - -import { StatisticalSurfaceSettings } from "./types"; - -import { SettingsContextDelegate } from "../../../delegates/SettingsContextDelegate"; -import { DefineDependenciesArgs, SettingsContext } from "../../../interfaces"; -import { Ensemble } from "../../settings/Ensemble"; -import { Sensitivity, SensitivityNameCasePair } from "../../settings/Sensitivity"; -import { StatisticFunction } from "../../settings/StatisticFunction"; -import { SurfaceAttribute } from "../../settings/SurfaceAttribute"; -import { SurfaceName } from "../../settings/SurfaceName"; -import { TimeOrInterval } from "../../settings/TimeOrInterval"; -import { SettingType } from "../../settings/settingsTypes"; - -export class StatisticalSurfaceContext implements SettingsContext { - private _contextDelegate: SettingsContextDelegate; - - constructor(layerManager: LayerManager) { - this._contextDelegate = new SettingsContextDelegate< - StatisticalSurfaceSettings, - keyof StatisticalSurfaceSettings - >(this, layerManager, { - [SettingType.ENSEMBLE]: new Ensemble(), - [SettingType.STATISTIC_FUNCTION]: new StatisticFunction(), - [SettingType.SENSITIVITY]: new Sensitivity(), - [SettingType.SURFACE_ATTRIBUTE]: new SurfaceAttribute(), - [SettingType.SURFACE_NAME]: new SurfaceName(), - [SettingType.TIME_OR_INTERVAL]: new TimeOrInterval(), - }); - } - - getDelegate(): SettingsContextDelegate { - return this._contextDelegate; - } - - getSettings() { - return this._contextDelegate.getSettings(); - } - - defineDependencies({ - helperDependency, - availableSettingsUpdater, - workbenchSession, - queryClient, - }: DefineDependenciesArgs) { - availableSettingsUpdater(SettingType.STATISTIC_FUNCTION, () => Object.values(SurfaceStatisticFunction_api)); - availableSettingsUpdater(SettingType.ENSEMBLE, ({ getGlobalSetting }) => { - const fieldIdentifier = getGlobalSetting("fieldId"); - const ensembles = getGlobalSetting("ensembles"); - - const ensembleIdents = ensembles - .filter((ensemble) => ensemble.getFieldIdentifier() === fieldIdentifier) - .map((ensemble) => ensemble.getIdent()); - - return ensembleIdents; - }); - availableSettingsUpdater(SettingType.SENSITIVITY, ({ getLocalSetting }) => { - const ensembleIdent = getLocalSetting(SettingType.ENSEMBLE); - - if (!ensembleIdent) { - return []; - } - - const ensembleSet = workbenchSession.getEnsembleSet(); - const currentEnsemble = ensembleSet.findEnsemble(ensembleIdent); - const sensitivities = currentEnsemble?.getSensitivities()?.getSensitivityArr() ?? []; - if (sensitivities.length === 0) { - return []; - } - const availableSensitivityPairs: SensitivityNameCasePair[] = []; - sensitivities.map((sensitivity) => - sensitivity.cases.map((sensitivityCase) => { - availableSensitivityPairs.push({ - sensitivityName: sensitivity.name, - sensitivityCase: sensitivityCase.name, - }); - }) - ); - return availableSensitivityPairs; - }); - - const surfaceMetadataDep = helperDependency(async ({ getLocalSetting, abortSignal }) => { - const ensembleIdent = getLocalSetting(SettingType.ENSEMBLE); - - if (!ensembleIdent) { - return null; - } - - return await queryClient.fetchQuery({ - queryKey: ["getRealizationSurfacesMetadata", ensembleIdent], - queryFn: () => - cancelPromiseOnAbort( - apiService.surface.getRealizationSurfacesMetadata( - ensembleIdent.getCaseUuid(), - ensembleIdent.getEnsembleName() - ), - abortSignal - ), - staleTime: STALE_TIME, - gcTime: CACHE_TIME, - }); - }); - - availableSettingsUpdater(SettingType.SURFACE_ATTRIBUTE, ({ getHelperDependency }) => { - const data = getHelperDependency(surfaceMetadataDep); - - if (!data) { - return []; - } - - const availableAttributes = [ - ...Array.from(new Set(data.surfaces.map((surface) => surface.attribute_name))), - ]; - - return availableAttributes; - }); - availableSettingsUpdater(SettingType.SURFACE_NAME, ({ getHelperDependency, getLocalSetting }) => { - const attribute = getLocalSetting(SettingType.SURFACE_ATTRIBUTE); - const data = getHelperDependency(surfaceMetadataDep); - - if (!attribute || !data) { - return []; - } - - const availableSurfaceNames = [ - ...Array.from( - new Set( - data.surfaces.filter((surface) => surface.attribute_name === attribute).map((el) => el.name) - ) - ), - ]; - - return availableSurfaceNames; - }); - - availableSettingsUpdater(SettingType.TIME_OR_INTERVAL, ({ getLocalSetting, getHelperDependency }) => { - const attribute = getLocalSetting(SettingType.SURFACE_ATTRIBUTE); - const surfaceName = getLocalSetting(SettingType.SURFACE_NAME); - const data = getHelperDependency(surfaceMetadataDep); - - if (!attribute || !surfaceName || !data) { - return []; - } - - const availableTimeOrIntervals: string[] = []; - const availableTimeTypes = [ - ...Array.from( - new Set( - data.surfaces - .filter((surface) => surface.attribute_name === attribute && surface.name === surfaceName) - .map((el) => el.time_type) - ) - ), - ]; - - if (availableTimeTypes.includes(SurfaceTimeType_api.NO_TIME)) { - availableTimeOrIntervals.push(SurfaceTimeType_api.NO_TIME); - } - if (availableTimeTypes.includes(SurfaceTimeType_api.TIME_POINT)) { - availableTimeOrIntervals.push(...data.time_points_iso_str); - } - if (availableTimeTypes.includes(SurfaceTimeType_api.INTERVAL)) { - availableTimeOrIntervals.push(...data.time_intervals_iso_str); - } - - return availableTimeOrIntervals; - }); - } -} diff --git a/frontend/src/modules/2DViewer/layers/implementations/layers/StatisticalSurfaceLayer/StatisticalSurfaceLayer.ts b/frontend/src/modules/2DViewer/layers/implementations/layers/StatisticalSurfaceLayer/StatisticalSurfaceLayer.ts deleted file mode 100644 index a06c7d16a..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/layers/StatisticalSurfaceLayer/StatisticalSurfaceLayer.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { SurfaceDataPng_api, SurfaceTimeType_api } from "@api"; -import { apiService } from "@framework/ApiService"; -import { LayerManager } from "@modules/2DViewer/layers/LayerManager"; -import { LayerRegistry } from "@modules/2DViewer/layers/LayerRegistry"; -import { ItemDelegate } from "@modules/2DViewer/layers/delegates/ItemDelegate"; -import { LayerColoringType, LayerDelegate } from "@modules/2DViewer/layers/delegates/LayerDelegate"; -import { SettingType } from "@modules/2DViewer/layers/implementations/settings/settingsTypes"; -import { CACHE_TIME, STALE_TIME } from "@modules/2DViewer/layers/queryConstants"; -import { FullSurfaceAddress, SurfaceAddressBuilder } from "@modules/_shared/Surface"; -import { SurfaceDataFloat_trans, transformSurfaceData } from "@modules/_shared/Surface/queryDataTransforms"; -import { encodeSurfAddrStr } from "@modules/_shared/Surface/surfaceAddress"; -import { QueryClient } from "@tanstack/react-query"; - -import { isEqual } from "lodash"; - -import { StatisticalSurfaceContext } from "./StatisticalSurfaceContext"; -import { StatisticalSurfaceSettings } from "./types"; - -import { BoundingBox, Layer, SerializedLayer } from "../../../interfaces"; - -export class StatisticalSurfaceLayer - implements Layer -{ - private _itemDelegate: ItemDelegate; - private _layerDelegate: LayerDelegate; - - constructor(layerManager: LayerManager) { - this._itemDelegate = new ItemDelegate("Statistical Surface", layerManager); - this._layerDelegate = new LayerDelegate( - this, - layerManager, - new StatisticalSurfaceContext(layerManager), - LayerColoringType.COLORSCALE - ); - } - - getSettingsContext() { - return this._layerDelegate.getSettingsContext(); - } - - getItemDelegate(): ItemDelegate { - return this._itemDelegate; - } - - getLayerDelegate(): LayerDelegate { - return this._layerDelegate; - } - - doSettingsChangesRequireDataRefetch( - prevSettings: StatisticalSurfaceSettings, - newSettings: StatisticalSurfaceSettings - ): boolean { - return !isEqual(prevSettings, newSettings); - } - - makeBoundingBox(): BoundingBox | null { - const data = this._layerDelegate.getData(); - if (!data) { - return null; - } - - return { - x: [data.transformed_bbox_utm.min_x, data.transformed_bbox_utm.max_x], - y: [data.transformed_bbox_utm.min_y, data.transformed_bbox_utm.max_y], - z: [0, 0], - }; - } - - makeValueRange(): [number, number] | null { - const data = this._layerDelegate.getData(); - if (!data) { - return null; - } - - return [data.value_min, data.value_max]; - } - - fechData(queryClient: QueryClient): Promise { - let surfaceAddress: FullSurfaceAddress | null = null; - const addrBuilder = new SurfaceAddressBuilder(); - const workbenchSession = this.getLayerDelegate().getLayerManager().getWorkbenchSession(); - const settings = this.getSettingsContext().getDelegate().getSettings(); - const ensembleIdent = settings[SettingType.ENSEMBLE].getDelegate().getValue(); - const surfaceName = settings[SettingType.SURFACE_NAME].getDelegate().getValue(); - const attribute = settings[SettingType.SURFACE_ATTRIBUTE].getDelegate().getValue(); - const timeOrInterval = settings[SettingType.TIME_OR_INTERVAL].getDelegate().getValue(); - const statisticFunction = settings[SettingType.STATISTIC_FUNCTION].getDelegate().getValue(); - const sensitivityNameCasePair = settings[SettingType.SENSITIVITY].getDelegate().getValue(); - - if (ensembleIdent && surfaceName && attribute) { - addrBuilder.withEnsembleIdent(ensembleIdent); - addrBuilder.withName(surfaceName); - addrBuilder.withAttribute(attribute); - - // Get filtered realizations from workbench - let filteredRealizations = workbenchSession - .getRealizationFilterSet() - .getRealizationFilterForEnsembleIdent(ensembleIdent) - .getFilteredRealizations(); - const currentEnsemble = workbenchSession.getEnsembleSet().findEnsemble(ensembleIdent); - - // If sensitivity is set, filter realizations further to only include the realizations that are in the sensitivity - if (sensitivityNameCasePair) { - const sensitivity = currentEnsemble - ?.getSensitivities() - ?.getCaseByName(sensitivityNameCasePair.sensitivityName, sensitivityNameCasePair.sensitivityCase); - - const sensitivityRealizations = sensitivity?.realizations ?? []; - - filteredRealizations = filteredRealizations.filter((realization) => - sensitivityRealizations.includes(realization) - ); - } - - // If realizations are filtered, update the address - const allRealizations = currentEnsemble?.getRealizations() ?? []; - if (!isEqual([...allRealizations], [...filteredRealizations])) { - addrBuilder.withStatisticRealizations([...filteredRealizations]); - } - - if (timeOrInterval !== SurfaceTimeType_api.NO_TIME) { - addrBuilder.withTimeOrInterval(timeOrInterval); - } - addrBuilder.withStatisticFunction(statisticFunction); - surfaceAddress = addrBuilder.buildStatisticalAddress(); - } - - const surfAddrStr = surfaceAddress ? encodeSurfAddrStr(surfaceAddress) : null; - - const queryKey = ["getSurfaceData", surfAddrStr, null, "png"]; - - this._layerDelegate.registerQueryKey(queryKey); - - const promise = queryClient - .fetchQuery({ - queryKey, - queryFn: () => apiService.surface.getSurfaceData(surfAddrStr ?? "", "png", null), - staleTime: STALE_TIME, - gcTime: CACHE_TIME, - }) - .then((data) => transformSurfaceData(data)); - - return promise; - } - - serializeState(): SerializedLayer { - return this._layerDelegate.serializeState(); - } - - deserializeState(serializedState: SerializedLayer): void { - this._layerDelegate.deserializeState(serializedState); - } -} - -LayerRegistry.registerLayer(StatisticalSurfaceLayer); diff --git a/frontend/src/modules/2DViewer/layers/implementations/layers/StatisticalSurfaceLayer/types.ts b/frontend/src/modules/2DViewer/layers/implementations/layers/StatisticalSurfaceLayer/types.ts deleted file mode 100644 index 22bb5154f..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/layers/StatisticalSurfaceLayer/types.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { SurfaceStatisticFunction_api } from "@api"; -import { EnsembleIdent } from "@framework/EnsembleIdent"; -import { SettingType } from "@modules/2DViewer/layers/implementations/settings/settingsTypes"; - -import { SensitivityNameCasePair } from "../../settings/Sensitivity"; - -export type StatisticalSurfaceSettings = { - [SettingType.ENSEMBLE]: EnsembleIdent | null; - [SettingType.STATISTIC_FUNCTION]: SurfaceStatisticFunction_api; - [SettingType.SENSITIVITY]: SensitivityNameCasePair | null; - [SettingType.SURFACE_ATTRIBUTE]: string | null; - [SettingType.SURFACE_NAME]: string | null; - [SettingType.TIME_OR_INTERVAL]: string | null; -}; diff --git a/frontend/src/modules/2DViewer/layers/implementations/settings/DrilledWellbores.tsx b/frontend/src/modules/2DViewer/layers/implementations/settings/DrilledWellbores.tsx deleted file mode 100644 index 2f69789f5..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/settings/DrilledWellbores.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import React from "react"; - -import { WellboreHeader_api } from "@api"; -import { DenseIconButton } from "@lib/components/DenseIconButton"; -import { Select, SelectOption } from "@lib/components/Select"; -import { Deselect, SelectAll } from "@mui/icons-material"; - -import { SettingType } from "./settingsTypes"; - -import { SettingRegistry } from "../../SettingRegistry"; -import { SettingDelegate } from "../../delegates/SettingDelegate"; -import { AvailableValuesType, Setting, SettingComponentProps } from "../../interfaces"; - -type ValueType = WellboreHeader_api[] | null; - -export class DrilledWellbores implements Setting { - private _delegate: SettingDelegate; - - constructor() { - this._delegate = new SettingDelegate(null, this); - } - - getType(): SettingType { - return SettingType.SMDA_WELLBORE_HEADERS; - } - - getLabel(): string { - return "Drilled wellbores"; - } - - getDelegate(): SettingDelegate { - return this._delegate; - } - - fixupValue(availableValues: AvailableValuesType, currentValue: ValueType): ValueType { - if (!currentValue) { - return availableValues; - } - - const matchingValues = currentValue.filter((value) => - availableValues.some((availableValue) => availableValue.wellboreUuid === value.wellboreUuid) - ); - if (matchingValues.length === 0) { - return availableValues; - } - return matchingValues; - } - - makeComponent(): (props: SettingComponentProps) => React.ReactNode { - return function DrilledWellbores(props: SettingComponentProps) { - const options: SelectOption[] = React.useMemo( - () => - props.availableValues.map((ident) => ({ - value: ident.wellboreUuid, - label: ident.uniqueWellboreIdentifier, - })), - [props.availableValues] - ); - - function handleChange(selectedUuids: string[]) { - const selectedWellbores = props.availableValues.filter((ident) => - selectedUuids.includes(ident.wellboreUuid) - ); - props.onValueChange(selectedWellbores); - } - - function selectAll() { - const allUuids = props.availableValues.map((ident) => ident.wellboreUuid); - handleChange(allUuids); - } - - function selectNone() { - handleChange([]); - } - - const selectedValues = React.useMemo( - () => props.value?.map((ident) => ident.wellboreUuid) ?? [], - [props.value] - ); - - return ( -
-
- - - Select all - - - - Clear selection - -
- - ); -} - -SettingRegistry.registerSetting(DrilledWellbores); diff --git a/frontend/src/modules/2DViewer/layers/implementations/settings/Ensemble.tsx b/frontend/src/modules/2DViewer/layers/implementations/settings/Ensemble.tsx deleted file mode 100644 index 404033a6c..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/settings/Ensemble.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import React from "react"; - -import { EnsembleIdent } from "@framework/EnsembleIdent"; -import { EnsembleDropdown } from "@framework/components/EnsembleDropdown"; - -import { SettingType } from "./settingsTypes"; - -import { SettingRegistry } from "../../SettingRegistry"; -import { SettingDelegate } from "../../delegates/SettingDelegate"; -import { Setting, SettingComponentProps, ValueToStringArgs } from "../../interfaces"; - -export class Ensemble implements Setting { - private _delegate: SettingDelegate; - - constructor() { - this._delegate = new SettingDelegate(null, this); - } - - getType(): SettingType { - return SettingType.ENSEMBLE; - } - - getLabel(): string { - return "Ensemble"; - } - - getDelegate(): SettingDelegate { - return this._delegate; - } - - serializeValue(value: EnsembleIdent | null): string { - return value?.toString() ?? ""; - } - - deserializeValue(serializedValue: string): EnsembleIdent | null { - return serializedValue !== "" ? EnsembleIdent.fromString(serializedValue) : null; - } - - makeComponent(): (props: SettingComponentProps) => React.ReactNode { - return function Ensemble(props: SettingComponentProps) { - const ensembles = props.globalSettings.ensembles.filter((ensemble) => - props.availableValues.includes(ensemble.getIdent()) - ); - - return ( - - ); - }; - } - - valueToString(args: ValueToStringArgs): string { - const { value, workbenchSession } = args; - if (value === null) { - return "-"; - } - - return workbenchSession.getEnsembleSet().findEnsemble(value)?.getDisplayName() ?? "-"; - } -} - -SettingRegistry.registerSetting(Ensemble); diff --git a/frontend/src/modules/2DViewer/layers/implementations/settings/GridAttribute.tsx b/frontend/src/modules/2DViewer/layers/implementations/settings/GridAttribute.tsx deleted file mode 100644 index 9be760c67..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/settings/GridAttribute.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import React from "react"; - -import { Dropdown, DropdownOption } from "@lib/components/Dropdown"; - -import { SettingType } from "./settingsTypes"; - -import { SettingRegistry } from "../../SettingRegistry"; -import { SettingDelegate } from "../../delegates/SettingDelegate"; -import { Setting, SettingComponentProps } from "../../interfaces"; - -type ValueType = string | null; - -export class GridAttribute implements Setting { - private _delegate: SettingDelegate; - - constructor() { - this._delegate = new SettingDelegate(null, this); - } - - getType(): SettingType { - return SettingType.GRID_ATTRIBUTE; - } - - getLabel(): string { - return "Grid attribute"; - } - - getDelegate(): SettingDelegate { - return this._delegate; - } - - makeComponent(): (props: SettingComponentProps) => React.ReactNode { - return function Ensemble(props: SettingComponentProps) { - const options: DropdownOption[] = props.availableValues.map((value) => { - return { - value: value.toString(), - label: value === null ? "None" : value.toString(), - }; - }); - - return ( - - ); - }; - } -} - -SettingRegistry.registerSetting(GridAttribute); diff --git a/frontend/src/modules/2DViewer/layers/implementations/settings/GridLayer.tsx b/frontend/src/modules/2DViewer/layers/implementations/settings/GridLayer.tsx deleted file mode 100644 index 7c05849d2..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/settings/GridLayer.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import React from "react"; - -import { Dropdown, DropdownOption } from "@lib/components/Dropdown"; - -import { SettingType } from "./settingsTypes"; - -import { SettingRegistry } from "../../SettingRegistry"; -import { SettingDelegate } from "../../delegates/SettingDelegate"; -import { AvailableValuesType, Setting, SettingComponentProps } from "../../interfaces"; - -type ValueType = number | null; - -export class GridLayer implements Setting { - private _delegate: SettingDelegate; - - constructor() { - this._delegate = new SettingDelegate(null, this); - } - - getType(): SettingType { - return SettingType.GRID_LAYER; - } - - getLabel(): string { - return "Grid layer"; - } - - getDelegate(): SettingDelegate { - return this._delegate; - } - - isValueValid(availableValues: AvailableValuesType, value: ValueType): boolean { - if (value === null) { - return false; - } - - if (availableValues.length < 3) { - return false; - } - - const min = 0; - const max = availableValues[2]; - - if (max === null) { - return false; - } - - return value >= min && value <= max; - } - - fixupValue(availableValues: AvailableValuesType, currentValue: ValueType): ValueType { - if (availableValues.length < 3) { - return null; - } - - const min = 0; - const max = availableValues[2]; - - if (max === null) { - return null; - } - - if (currentValue === null) { - return min; - } - - if (currentValue < min) { - return min; - } - - if (currentValue > max) { - return max; - } - - return currentValue; - } - - makeComponent(): (props: SettingComponentProps) => React.ReactNode { - return function Ensemble(props: SettingComponentProps) { - const kRange = props.availableValues ? Array.from({ length: props.availableValues[2] }, (_, i) => i) : []; - - const options: DropdownOption[] = kRange.map((value) => { - return { - value: value.toString(), - label: value === null ? "None" : value.toString(), - }; - }); - - return ( - props.onValueChange(parseInt(val))} - disabled={props.isOverridden} - showArrows - /> - ); - }; - } -} - -SettingRegistry.registerSetting(GridLayer); diff --git a/frontend/src/modules/2DViewer/layers/implementations/settings/GridName.tsx b/frontend/src/modules/2DViewer/layers/implementations/settings/GridName.tsx deleted file mode 100644 index 160da8a10..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/settings/GridName.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import React from "react"; - -import { Dropdown, DropdownOption } from "@lib/components/Dropdown"; - -import { SettingType } from "./settingsTypes"; - -import { SettingRegistry } from "../../SettingRegistry"; -import { SettingDelegate } from "../../delegates/SettingDelegate"; -import { Setting, SettingComponentProps } from "../../interfaces"; - -type ValueType = string | null; - -export class GridName implements Setting { - private _delegate: SettingDelegate; - - constructor() { - this._delegate = new SettingDelegate(null, this); - } - - getType(): SettingType { - return SettingType.GRID_NAME; - } - - getLabel(): string { - return "Grid name"; - } - - getDelegate(): SettingDelegate { - return this._delegate; - } - - makeComponent(): (props: SettingComponentProps) => React.ReactNode { - return function Ensemble(props: SettingComponentProps) { - const options: DropdownOption[] = props.availableValues.map((value) => { - return { - value: value.toString(), - label: value === null ? "None" : value.toString(), - }; - }); - - return ( - - ); - }; - } -} - -SettingRegistry.registerSetting(GridName); diff --git a/frontend/src/modules/2DViewer/layers/implementations/settings/PolygonsAttribute.tsx b/frontend/src/modules/2DViewer/layers/implementations/settings/PolygonsAttribute.tsx deleted file mode 100644 index 43c6617c6..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/settings/PolygonsAttribute.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import React from "react"; - -import { Dropdown, DropdownOption } from "@lib/components/Dropdown"; - -import { SettingType } from "./settingsTypes"; - -import { SettingRegistry } from "../../SettingRegistry"; -import { SettingDelegate } from "../../delegates/SettingDelegate"; -import { Setting, SettingComponentProps } from "../../interfaces"; - -type ValueType = string | null; - -export class PolygonsAttribute implements Setting { - private _delegate: SettingDelegate; - - constructor() { - this._delegate = new SettingDelegate(null, this); - } - - getType(): SettingType { - return SettingType.POLYGONS_ATTRIBUTE; - } - - getLabel(): string { - return "Polygons attribute"; - } - - getDelegate(): SettingDelegate { - return this._delegate; - } - - makeComponent(): (props: SettingComponentProps) => React.ReactNode { - return function Ensemble(props: SettingComponentProps) { - const options: DropdownOption[] = props.availableValues.map((value) => { - return { - value: value.toString(), - label: value === null ? "None" : value.toString(), - }; - }); - - return ( - - ); - }; - } -} - -SettingRegistry.registerSetting(PolygonsAttribute); diff --git a/frontend/src/modules/2DViewer/layers/implementations/settings/PolygonsName.tsx b/frontend/src/modules/2DViewer/layers/implementations/settings/PolygonsName.tsx deleted file mode 100644 index 9bd3f6ff6..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/settings/PolygonsName.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import React from "react"; - -import { Dropdown, DropdownOption } from "@lib/components/Dropdown"; - -import { SettingType } from "./settingsTypes"; - -import { SettingRegistry } from "../../SettingRegistry"; -import { SettingDelegate } from "../../delegates/SettingDelegate"; -import { Setting, SettingComponentProps } from "../../interfaces"; - -type ValueType = string | null; - -export class PolygonsName implements Setting { - private _delegate: SettingDelegate; - - constructor() { - this._delegate = new SettingDelegate(null, this); - } - - getType(): SettingType { - return SettingType.POLYGONS_NAME; - } - - getLabel(): string { - return "Polygons name"; - } - - getDelegate(): SettingDelegate { - return this._delegate; - } - - makeComponent(): (props: SettingComponentProps) => React.ReactNode { - return function FaultPolygons(props: SettingComponentProps) { - const options: DropdownOption[] = props.availableValues.map((value) => { - return { - value: value.toString(), - label: value === null ? "None" : value.toString(), - }; - }); - - return ( - - ); - }; - } -} - -SettingRegistry.registerSetting(PolygonsName); diff --git a/frontend/src/modules/2DViewer/layers/implementations/settings/Realization.tsx b/frontend/src/modules/2DViewer/layers/implementations/settings/Realization.tsx deleted file mode 100644 index 1decc851d..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/settings/Realization.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import React from "react"; - -import { Dropdown, DropdownOption } from "@lib/components/Dropdown"; - -import { SettingType } from "./settingsTypes"; - -import { SettingRegistry } from "../../SettingRegistry"; -import { SettingDelegate } from "../../delegates/SettingDelegate"; -import { Setting, SettingComponentProps } from "../../interfaces"; - -export class Realization implements Setting { - private _delegate: SettingDelegate; - - constructor() { - this._delegate = new SettingDelegate(null, this); - } - - getType(): SettingType { - return SettingType.REALIZATION; - } - - getLabel(): string { - return "Realization"; - } - - getDelegate(): SettingDelegate { - return this._delegate; - } - - makeComponent(): (props: SettingComponentProps) => React.ReactNode { - return function Realization(props: SettingComponentProps) { - function handleSelectionChange(selectedValue: string) { - const newValue = parseInt(selectedValue); - props.onValueChange(newValue); - } - - const options: DropdownOption[] = props.availableValues.map((value) => { - return { - value: value.toString(), - label: value === null ? "None" : value.toString(), - }; - }); - return ( - - ); - }; - } -} - -SettingRegistry.registerSetting(Realization); diff --git a/frontend/src/modules/2DViewer/layers/implementations/settings/Sensitivity.tsx b/frontend/src/modules/2DViewer/layers/implementations/settings/Sensitivity.tsx deleted file mode 100644 index c45071bac..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/settings/Sensitivity.tsx +++ /dev/null @@ -1,139 +0,0 @@ -import React from "react"; - -import { Dropdown } from "@lib/components/Dropdown"; - -import { SettingType } from "./settingsTypes"; - -import { SettingRegistry } from "../../SettingRegistry"; -import { SettingDelegate } from "../../delegates/SettingDelegate"; -import { AvailableValuesType, Setting, SettingComponentProps } from "../../interfaces"; - -export type SensitivityNameCasePair = { - sensitivityName: string; - sensitivityCase: string; -}; - -export class Sensitivity implements Setting { - private _delegate: SettingDelegate; - - constructor() { - this._delegate = new SettingDelegate(null, this); - } - - getType(): SettingType { - return SettingType.STATISTIC_FUNCTION; - } - - getLabel(): string { - return "Sensitivity"; - } - - getDelegate(): SettingDelegate { - return this._delegate; - } - - isValueValid( - availableValues: AvailableValuesType, - value: SensitivityNameCasePair | null - ): boolean { - if (availableValues.length === 0) { - return true; - } - if (!value) { - return false; - } - return availableValues - .filter((el) => el !== null) - .some( - (sensitivity) => - sensitivity?.sensitivityName === value.sensitivityName && - sensitivity?.sensitivityCase === value.sensitivityCase - ); - } - - makeComponent(): (props: SettingComponentProps) => React.ReactNode { - return function Sensitivity(props: SettingComponentProps) { - const availableSensitivityNames: string[] = [ - ...Array.from(new Set(props.availableValues.map((sensitivity) => sensitivity.sensitivityName))), - ]; - - const currentSensitivityName = props.value?.sensitivityName; - const availableSensitiveCases = props.availableValues - .filter((sensitivity) => sensitivity.sensitivityName === currentSensitivityName) - .map((sensitivity) => sensitivity.sensitivityCase); - - const currentSensitivityCase = fixupSensitivityCase( - props.value?.sensitivityCase || null, - availableSensitiveCases - ); - - const sensitivityNameOptions = availableSensitivityNames.map((sensitivityName) => ({ - value: sensitivityName, - label: sensitivityName, - })); - - const sensitivityCaseOptions = availableSensitiveCases.map((sensitivityCase) => ({ - value: sensitivityCase, - label: sensitivityCase, - })); - - if (!currentSensitivityName || !currentSensitivityCase) { - props.onValueChange(null); - } else if (currentSensitivityCase !== props.value?.sensitivityCase) { - props.onValueChange({ - sensitivityName: currentSensitivityName, - sensitivityCase: currentSensitivityCase, - }); - } - - function handleSensitivityNameChange(selectedValue: string) { - const availableSensitiveCases = props.availableValues - .filter((sensitivity) => sensitivity.sensitivityName === selectedValue) - .map((sensitivity) => sensitivity.sensitivityCase); - - const currentSensitivityCase = fixupSensitivityCase(null, availableSensitiveCases); - if (!currentSensitivityCase) { - props.onValueChange(null); - } else { - props.onValueChange({ - sensitivityName: selectedValue, - sensitivityCase: currentSensitivityCase, - }); - } - } - function handleSensitivityCaseChange(selectedValue: string) { - props.onValueChange({ - sensitivityName: props.value?.sensitivityName ?? "", - sensitivityCase: selectedValue, - }); - } - if (props.availableValues.length === 0) { - return "No sensitivities available"; - } - return ( -
- - -
- ); - }; - } -} - -function fixupSensitivityCase(currentSensitivityCase: string | null, availableSensitiveCases: string[]): string | null { - if (!currentSensitivityCase || !availableSensitiveCases.includes(currentSensitivityCase)) { - return availableSensitiveCases[0] ?? null; - } - - return currentSensitivityCase; -} - -SettingRegistry.registerSetting(Sensitivity as unknown as new () => Setting); diff --git a/frontend/src/modules/2DViewer/layers/implementations/settings/ShowGridLines.tsx b/frontend/src/modules/2DViewer/layers/implementations/settings/ShowGridLines.tsx deleted file mode 100644 index 17a9456f3..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/settings/ShowGridLines.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import React, { ChangeEvent } from "react"; - -import { Switch } from "@lib/components/Switch"; - -import { SettingType } from "./settingsTypes"; - -import { SettingRegistry } from "../../SettingRegistry"; -import { SettingDelegate } from "../../delegates/SettingDelegate"; -import { Setting, SettingComponentProps } from "../../interfaces"; - -type ValueType = boolean; - -export class ShowGridLines implements Setting { - private _delegate: SettingDelegate; - - constructor() { - this._delegate = new SettingDelegate(false, this, true); - } - - getType(): SettingType { - return SettingType.ENSEMBLE; - } - - getLabel(): string { - return "Show grid lines"; - } - - isValueValid(): boolean { - return true; - } - - getDelegate(): SettingDelegate { - return this._delegate; - } - - makeComponent(): (props: SettingComponentProps) => React.ReactNode { - return function ShowGridLines(props: SettingComponentProps) { - function handleChange(e: ChangeEvent) { - props.onValueChange(e.target.checked); - } - - return ; - }; - } -} - -SettingRegistry.registerSetting(ShowGridLines); diff --git a/frontend/src/modules/2DViewer/layers/implementations/settings/StatisticFunction.tsx b/frontend/src/modules/2DViewer/layers/implementations/settings/StatisticFunction.tsx deleted file mode 100644 index 029e7544e..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/settings/StatisticFunction.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import React from "react"; - -import { SurfaceStatisticFunction_api } from "@api"; -import { Dropdown, DropdownOption } from "@lib/components/Dropdown"; - -import { SettingType } from "./settingsTypes"; - -import { SettingRegistry } from "../../SettingRegistry"; -import { SettingDelegate } from "../../delegates/SettingDelegate"; -import { Setting, SettingComponentProps } from "../../interfaces"; - -export class StatisticFunction implements Setting { - private _delegate: SettingDelegate; - - constructor() { - this._delegate = new SettingDelegate(SurfaceStatisticFunction_api.MEAN, this); - } - - getType(): SettingType { - return SettingType.STATISTIC_FUNCTION; - } - - getLabel(): string { - return "Statistic function"; - } - - getDelegate(): SettingDelegate { - return this._delegate; - } - - isValueValid(): boolean { - return true; - } - - makeComponent(): (props: SettingComponentProps) => React.ReactNode { - const itemArr: DropdownOption[] = [ - { value: SurfaceStatisticFunction_api.MEAN, label: "Mean" }, - { value: SurfaceStatisticFunction_api.STD, label: "Std" }, - { value: SurfaceStatisticFunction_api.MIN, label: "Min" }, - { value: SurfaceStatisticFunction_api.MAX, label: "Max" }, - { value: SurfaceStatisticFunction_api.P10, label: "P10" }, - { value: SurfaceStatisticFunction_api.P90, label: "P90" }, - { value: SurfaceStatisticFunction_api.P50, label: "P50" }, - ]; - - return function StatisticFunction(props: SettingComponentProps) { - return ( - props.onValueChange(newVal as SurfaceStatisticFunction_api)} - disabled={props.isOverridden} - showArrows - /> - ); - }; - } -} - -SettingRegistry.registerSetting(StatisticFunction); diff --git a/frontend/src/modules/2DViewer/layers/implementations/settings/SurfaceAttribute.tsx b/frontend/src/modules/2DViewer/layers/implementations/settings/SurfaceAttribute.tsx deleted file mode 100644 index 2220606fd..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/settings/SurfaceAttribute.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import React from "react"; - -import { Dropdown, DropdownOption } from "@lib/components/Dropdown"; - -import { SettingType } from "./settingsTypes"; - -import { SettingRegistry } from "../../SettingRegistry"; -import { SettingDelegate } from "../../delegates/SettingDelegate"; -import { Setting, SettingComponentProps } from "../../interfaces"; - -type ValueType = string | null; - -export class SurfaceAttribute implements Setting { - private _delegate: SettingDelegate; - - constructor() { - this._delegate = new SettingDelegate(null, this); - } - - getType(): SettingType { - return SettingType.SURFACE_ATTRIBUTE; - } - - getLabel(): string { - return "Surface attribute"; - } - - getDelegate(): SettingDelegate { - return this._delegate; - } - - makeComponent(): (props: SettingComponentProps) => React.ReactNode { - return function Ensemble(props: SettingComponentProps) { - const options: DropdownOption[] = props.availableValues.map((value) => { - return { - value: value.toString(), - label: value === null ? "None" : value.toString(), - }; - }); - - return ( - - ); - }; - } -} - -SettingRegistry.registerSetting(SurfaceAttribute); diff --git a/frontend/src/modules/2DViewer/layers/implementations/settings/SurfaceName.tsx b/frontend/src/modules/2DViewer/layers/implementations/settings/SurfaceName.tsx deleted file mode 100644 index 63e714a0e..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/settings/SurfaceName.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import React from "react"; - -import { Dropdown, DropdownOption } from "@lib/components/Dropdown"; - -import { SettingType } from "./settingsTypes"; - -import { SettingRegistry } from "../../SettingRegistry"; -import { SettingDelegate } from "../../delegates/SettingDelegate"; -import { Setting, SettingComponentProps } from "../../interfaces"; - -type ValueType = string | null; - -export class SurfaceName implements Setting { - private _delegate: SettingDelegate; - - constructor() { - this._delegate = new SettingDelegate(null, this); - } - - getType(): SettingType { - return SettingType.SURFACE_NAME; - } - - getLabel(): string { - return "Surface name"; - } - - getDelegate(): SettingDelegate { - return this._delegate; - } - - makeComponent(): (props: SettingComponentProps) => React.ReactNode { - return function Ensemble(props: SettingComponentProps) { - const options: DropdownOption[] = props.availableValues.map((value) => { - return { - value: value.toString(), - label: value === null ? "None" : value.toString(), - }; - }); - - return ( - - ); - }; - } -} - -SettingRegistry.registerSetting(SurfaceName); diff --git a/frontend/src/modules/2DViewer/layers/implementations/settings/TimeOrInterval.tsx b/frontend/src/modules/2DViewer/layers/implementations/settings/TimeOrInterval.tsx deleted file mode 100644 index 5096481b2..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/settings/TimeOrInterval.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import React from "react"; - -import { SurfaceTimeType_api } from "@api"; -import { Dropdown, DropdownOption } from "@lib/components/Dropdown"; - -import { SettingType } from "./settingsTypes"; - -import { SettingRegistry } from "../../SettingRegistry"; -import { SettingDelegate } from "../../delegates/SettingDelegate"; -import { Setting, SettingComponentProps, ValueToStringArgs } from "../../interfaces"; - -type ValueType = string | null; - -export class TimeOrInterval implements Setting { - private _delegate: SettingDelegate; - - constructor() { - this._delegate = new SettingDelegate(null, this); - } - - getType(): SettingType { - return SettingType.TIME_OR_INTERVAL; - } - - getLabel(): string { - return "Date"; - } - - getDelegate(): SettingDelegate { - return this._delegate; - } - - makeComponent(): (props: SettingComponentProps) => React.ReactNode { - return function Ensemble(props: SettingComponentProps) { - const options: DropdownOption[] = props.availableValues.map((value) => { - return { - value: value.toString(), - label: timeTypeToLabel(value), - }; - }); - - return ( - - ); - }; - } - - valueToString(args: ValueToStringArgs): string { - const { value } = args; - if (value === null) { - return "-"; - } - return timeTypeToLabel(value); - } -} - -function timeTypeToLabel(input: string): string { - if (input === SurfaceTimeType_api.NO_TIME) { - return "Initial / No date"; - } - const [start, end] = input.split("/"); - if (end) { - return isoIntervalStringToDateLabel(start, end); - } - return isoStringToDateLabel(start); -} -function isoStringToDateLabel(isoDatestring: string): string { - const date = isoDatestring.split("T")[0]; - return `${date}`; -} - -function isoIntervalStringToDateLabel(startIsoDateString: string, endIsoDateString: string): string { - const startDate = startIsoDateString.split("T")[0]; - const endDate = endIsoDateString.split("T")[0]; - return `${startDate}/${endDate}`; -} - -SettingRegistry.registerSetting(TimeOrInterval); diff --git a/frontend/src/modules/2DViewer/layers/implementations/settings/settingsTypes.ts b/frontend/src/modules/2DViewer/layers/implementations/settings/settingsTypes.ts deleted file mode 100644 index f7430c181..000000000 --- a/frontend/src/modules/2DViewer/layers/implementations/settings/settingsTypes.ts +++ /dev/null @@ -1,16 +0,0 @@ -export enum SettingType { - ENSEMBLE = "ensemble", - REALIZATION = "realization", - STATISTIC_FUNCTION = "statisticFunction", - SENSITIVITY = "sensitivity", - SURFACE_NAME = "surfaceName", - SURFACE_ATTRIBUTE = "surfaceAttribute", - TIME_OR_INTERVAL = "timeOrInterval", - POLYGONS_ATTRIBUTE = "polygonsAttribute", - POLYGONS_NAME = "polygonsName", - SMDA_WELLBORE_HEADERS = "smdaWellboreHeaders", - GRID_NAME = "gridName", - GRID_ATTRIBUTE = "gridAttribute", - GRID_LAYER = "gridLayer", - SHOW_GRID_LINES = "showGridLines", -} diff --git a/frontend/src/modules/2DViewer/layers/interfaces.ts b/frontend/src/modules/2DViewer/layers/interfaces.ts deleted file mode 100644 index 1020cea33..000000000 --- a/frontend/src/modules/2DViewer/layers/interfaces.ts +++ /dev/null @@ -1,204 +0,0 @@ -import { WorkbenchSession } from "@framework/WorkbenchSession"; -import { WorkbenchSettings } from "@framework/WorkbenchSettings"; -import { ColorScaleSerialization } from "@lib/utils/ColorScale"; -import { QueryClient } from "@tanstack/react-query"; - -import { Dependency } from "./Dependency"; -import { GlobalSettings } from "./LayerManager"; -import { GroupDelegate } from "./delegates/GroupDelegate"; -import { ItemDelegate } from "./delegates/ItemDelegate"; -import { LayerDelegate } from "./delegates/LayerDelegate"; -import { SettingDelegate } from "./delegates/SettingDelegate"; -import { SettingsContextDelegate } from "./delegates/SettingsContextDelegate"; -import { SettingType } from "./implementations/settings/settingsTypes"; - -export type SerializedType = - | "layer-manager" - | "view" - | "layer" - | "settings-group" - | "color-scale" - | "delta-surface" - | "shared-setting"; - -export interface SerializedItem { - id: string; - type: SerializedType; - name: string; - expanded: boolean; - visible: boolean; -} - -export type SerializedSettingsState = Record; - -export interface SerializedLayer extends SerializedItem { - type: "layer"; - layerClass: string; - settings: SerializedSettingsState; -} - -export interface SerializedView extends SerializedItem { - type: "view"; - color: string; - children: SerializedItem[]; -} - -export interface SerializedSettingsGroup extends SerializedItem { - type: "settings-group"; - children: SerializedItem[]; -} - -export interface SerializedColorScale extends SerializedItem { - type: "color-scale"; - colorScale: ColorScaleSerialization; - userDefinedBoundaries: boolean; -} - -export interface SerializedSharedSetting extends SerializedItem { - type: "shared-setting"; - settingType: SettingType; - wrappedSettingClass: string; - value: string; -} - -export interface SerializedLayerManager extends SerializedItem { - type: "layer-manager"; - children: SerializedItem[]; -} - -export interface SerializedDeltaSurface extends SerializedItem { - type: "delta-surface"; - children: SerializedItem[]; -} - -export interface Item { - getItemDelegate(): ItemDelegate; - serializeState(): SerializedItem; - deserializeState(serialized: SerializedItem): void; -} - -export function instanceofItem(item: any): item is Item { - return (item as Item).getItemDelegate !== undefined; -} - -export interface Group extends Item { - getGroupDelegate(): GroupDelegate; -} - -export function instanceofGroup(item: Item): item is Group { - return (item as Group).getItemDelegate !== undefined && (item as Group).getGroupDelegate !== undefined; -} - -export type BoundingBox = { - x: [number, number]; - y: [number, number]; - z: [number, number]; -}; - -export enum FetchDataFunctionResult { - SUCCESS = "SUCCESS", - IN_PROGRESS = "IN_PROGRESS", - ERROR = "ERROR", - NO_CHANGE = "NO_CHANGE", -} -export interface FetchDataFunction { - ( - oldValues: { [K in TKey]?: TSettings[K] }, - newValues: { [K in TKey]?: TSettings[K] } - ): Promise; -} - -export interface Layer extends Item { - getLayerDelegate(): LayerDelegate; - doSettingsChangesRequireDataRefetch(prevSettings: TSettings, newSettings: TSettings): boolean; - fechData(queryClient: QueryClient): Promise; - makeBoundingBox?(): BoundingBox | null; - makeValueRange?(): [number, number] | null; -} - -export function instanceofLayer(item: Item): item is Layer { - return ( - (item as Layer).getItemDelegate !== undefined && - (item as Layer).doSettingsChangesRequireDataRefetch !== undefined && - (item as Layer).fechData !== undefined - ); -} - -export interface GetHelperDependency { - (dep: Dependency): Awaited | null; -} - -export interface UpdateFunc { - (args: { - getLocalSetting: (settingName: K) => TSettings[K]; - getGlobalSetting: (settingName: T) => GlobalSettings[T]; - getHelperDependency: GetHelperDependency; - abortSignal: AbortSignal; - }): TReturnValue; -} - -export interface DefineDependenciesArgs { - availableSettingsUpdater: ( - settingName: TKey, - update: UpdateFunc, TSettings, TKey> - ) => Dependency, TSettings, TKey>; - helperDependency: ( - update: (args: { - getLocalSetting: (settingName: T) => TSettings[T]; - getGlobalSetting: (settingName: T) => GlobalSettings[T]; - getHelperDependency: (helperDependency: Dependency) => TDep | null; - abortSignal: AbortSignal; - }) => T - ) => Dependency; - workbenchSession: WorkbenchSession; - workbenchSettings: WorkbenchSettings; - queryClient: QueryClient; -} - -export interface SettingsContext { - getDelegate(): SettingsContextDelegate; - areCurrentSettingsValid?: (settings: TSettings) => boolean; - defineDependencies(args: DefineDependenciesArgs): void; -} - -// Required when making "AvailableValuesType" for all settings in an object ("TSettings") -export type EachAvailableValuesType = T extends any ? AvailableValuesType : never; - -// Returns an array of "TValue" if the "TValue" itself is not already an array -export type AvailableValuesType = RemoveUnknownFromArray>; - -// "MakeArrayIfNotArray" yields "unknown[] | any[]" for "T = any" - we don't want "unknown[]" -type RemoveUnknownFromArray = T extends unknown[] | any[] ? any[] : T; -type MakeArrayIfNotArray = Exclude extends Array ? Array : Array>; - -export type SettingComponentProps = { - onValueChange: (newValue: TValue) => void; - value: TValue; - isValueValid: boolean; - overriddenValue: TValue | null; - isOverridden: boolean; - availableValues: AvailableValuesType; - workbenchSession: WorkbenchSession; - workbenchSettings: WorkbenchSettings; - globalSettings: GlobalSettings; -}; - -export type ValueToStringArgs = { - value: TValue; - workbenchSession: WorkbenchSession; - workbenchSettings: WorkbenchSettings; -}; - -export interface Setting { - getType(): SettingType; - getLabel(): string; - makeComponent(): (props: SettingComponentProps) => React.ReactNode; - getDelegate(): SettingDelegate; - fixupValue?: (availableValues: AvailableValuesType, currentValue: TValue) => TValue; - isValueValid?: (availableValues: AvailableValuesType, value: TValue) => boolean; - serializeValue?: (value: TValue) => string; - deserializeValue?: (serializedValue: string) => TValue; - valueToString?: (args: ValueToStringArgs) => string; -} - -export type Settings = { [key in SettingType]?: any }; diff --git a/frontend/src/modules/2DViewer/layers/queryConstants.ts b/frontend/src/modules/2DViewer/layers/queryConstants.ts deleted file mode 100644 index 3acac7d69..000000000 --- a/frontend/src/modules/2DViewer/layers/queryConstants.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const STALE_TIME = 60 * 1000; -export const CACHE_TIME = 60 * 1000; diff --git a/frontend/src/modules/2DViewer/layers/utils.ts b/frontend/src/modules/2DViewer/layers/utils.ts deleted file mode 100644 index d9ea853b6..000000000 --- a/frontend/src/modules/2DViewer/layers/utils.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { CancelablePromise } from "@api"; -import { FetchQueryOptions, QueryClient } from "@tanstack/react-query"; - -export function cancelPromiseOnAbort(promise: CancelablePromise, abortSignal: AbortSignal): Promise { - abortSignal.addEventListener("abort", () => { - console.debug("Promise aborted"); - promise.cancel(); - }); - return promise; -} - -export async function cancelQueryOnAbort( - queryClient: QueryClient, - abortSignal: AbortSignal, - options: FetchQueryOptions -) { - abortSignal.addEventListener("abort", () => { - queryClient.cancelQueries({ queryKey: options.queryKey }); - }); - - return await queryClient.fetchQuery(options); -} diff --git a/frontend/src/modules/2DViewer/loadModule.tsx b/frontend/src/modules/2DViewer/loadModule.tsx deleted file mode 100644 index dfcfa27de..000000000 --- a/frontend/src/modules/2DViewer/loadModule.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { ModuleRegistry } from "@framework/ModuleRegistry"; - -import { Interfaces, settingsToViewInterfaceInitialization } from "./interfaces"; -import { MODULE_NAME } from "./registerModule"; -import { Settings } from "./settings/settings"; -import { View } from "./view/view"; - -const module = ModuleRegistry.initModule(MODULE_NAME, { - settingsToViewInterfaceInitialization, -}); - -module.settingsFC = Settings; -module.viewFC = View; diff --git a/frontend/src/modules/2DViewer/preview.tsx b/frontend/src/modules/2DViewer/preview.tsx deleted file mode 100644 index 2a9746ab7..000000000 --- a/frontend/src/modules/2DViewer/preview.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import { DrawPreviewFunc } from "@framework/Preview"; -import previewImg from "./preview.webp"; - -export const preview: DrawPreviewFunc = function (width: number, height: number) { - return ( - - ); -}; diff --git a/frontend/src/modules/2DViewer/preview.webp b/frontend/src/modules/2DViewer/preview.webp deleted file mode 100644 index 0b82963c8d6bbacf99350d170c51036c1c0e84ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38828 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 Xp{Yv8e@maqfBgIV-~aQc|MUL={RDJ4 diff --git a/frontend/src/modules/2DViewer/registerModule.ts b/frontend/src/modules/2DViewer/registerModule.ts deleted file mode 100644 index 2e29217a9..000000000 --- a/frontend/src/modules/2DViewer/registerModule.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ModuleCategory, ModuleDevState } from "@framework/Module"; -import { ModuleDataTagId } from "@framework/ModuleDataTags"; -import { ModuleRegistry } from "@framework/ModuleRegistry"; - -import { Interfaces } from "./interfaces"; -import { preview } from "./preview"; - -export const MODULE_NAME: string = "2DViewer"; - -ModuleRegistry.registerModule({ - moduleName: MODULE_NAME, - category: ModuleCategory.MAIN, - devState: ModuleDevState.DEV, - defaultTitle: "2D Viewer", - preview, - description: "Generic 2D viewer for co-visualization of spatial data.", - dataTagIds: [ - ModuleDataTagId.SURFACE, - ModuleDataTagId.DRILLED_WELLS, - ModuleDataTagId.SEISMIC, - ModuleDataTagId.GRID3D, - ModuleDataTagId.POLYGONS, - ], -}); diff --git a/frontend/src/modules/2DViewer/settings/atoms/baseAtoms.ts b/frontend/src/modules/2DViewer/settings/atoms/baseAtoms.ts deleted file mode 100644 index c67693fd1..000000000 --- a/frontend/src/modules/2DViewer/settings/atoms/baseAtoms.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { LayerManager } from "@modules/2DViewer/layers/LayerManager"; -import { PreferredViewLayout } from "@modules/2DViewer/types"; - -import { atom } from "jotai"; - -export const userSelectedFieldIdentifierAtom = atom(null); -export const layerManagerAtom = atom(null); -export const preferredViewLayoutAtom = atom(PreferredViewLayout.VERTICAL); diff --git a/frontend/src/modules/2DViewer/settings/atoms/derivedAtoms.ts b/frontend/src/modules/2DViewer/settings/atoms/derivedAtoms.ts deleted file mode 100644 index 7d4115816..000000000 --- a/frontend/src/modules/2DViewer/settings/atoms/derivedAtoms.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { EnsembleSet } from "@framework/EnsembleSet"; -import { EnsembleSetAtom } from "@framework/GlobalAtoms"; - -import { atom } from "jotai"; - -import { userSelectedFieldIdentifierAtom } from "./baseAtoms"; - -export const selectedFieldIdentifierAtom = atom((get) => { - const ensembleSet = get(EnsembleSetAtom); - const userSelectedField = get(userSelectedFieldIdentifierAtom); - - if ( - !userSelectedField || - !ensembleSet.getEnsembleArr().some((ens) => ens.getFieldIdentifier() === userSelectedField) - ) { - return ensembleSet.getEnsembleArr().at(0)?.getFieldIdentifier() ?? null; - } - - return userSelectedField; -}); - -export const filteredEnsembleSetAtom = atom((get) => { - const ensembleSet = get(EnsembleSetAtom); - const fieldIdentifier = get(userSelectedFieldIdentifierAtom); - - if (fieldIdentifier === null) { - return ensembleSet; - } - - return new EnsembleSet(ensembleSet.getEnsembleArr().filter((el) => el.getFieldIdentifier() === fieldIdentifier)); -}); diff --git a/frontend/src/modules/2DViewer/settings/components/layerManagerComponent.tsx b/frontend/src/modules/2DViewer/settings/components/layerManagerComponent.tsx deleted file mode 100644 index 559bb309f..000000000 --- a/frontend/src/modules/2DViewer/settings/components/layerManagerComponent.tsx +++ /dev/null @@ -1,445 +0,0 @@ -import React from "react"; - -import { Icon } from "@equinor/eds-core-react"; -import { color_palette, fault, grid_layer, settings, surface_layer, wellbore } from "@equinor/eds-icons"; -import { WorkbenchSession } from "@framework/WorkbenchSession"; -import { WorkbenchSettings } from "@framework/WorkbenchSettings"; -import { Menu } from "@lib/components/Menu"; -import { MenuButton } from "@lib/components/MenuButton"; -import { MenuHeading } from "@lib/components/MenuHeading"; -import { MenuItem } from "@lib/components/MenuItem"; -import { IsMoveAllowedArgs, SortableList } from "@lib/components/SortableList"; -import { useElementSize } from "@lib/hooks/useElementSize"; -import { convertRemToPixels } from "@lib/utils/screenUnitConversions"; -import { ColorScale } from "@modules/2DViewer/layers/ColorScale"; -import { DeltaSurface } from "@modules/2DViewer/layers/DeltaSurface"; -import { LayerManager } from "@modules/2DViewer/layers/LayerManager"; -import { SettingsGroup } from "@modules/2DViewer/layers/SettingsGroup"; -import { SharedSetting } from "@modules/2DViewer/layers/SharedSetting"; -import { View } from "@modules/2DViewer/layers/View"; -import { ExpandCollapseAllButton } from "@modules/2DViewer/layers/components/ExpandCollapseAllButton"; -import { LayersActionGroup, LayersActions } from "@modules/2DViewer/layers/components/LayersActions"; -import { makeComponent } from "@modules/2DViewer/layers/components/utils"; -import { GroupDelegateTopic } from "@modules/2DViewer/layers/delegates/GroupDelegate"; -import { usePublishSubscribeTopicValue } from "@modules/2DViewer/layers/delegates/PublishSubscribeDelegate"; -import { DrilledWellTrajectoriesLayer } from "@modules/2DViewer/layers/implementations/layers/DrilledWellTrajectoriesLayer/DrilledWellTrajectoriesLayer"; -import { DrilledWellborePicksLayer } from "@modules/2DViewer/layers/implementations/layers/DrilledWellborePicksLayer/DrilledWellborePicksLayer"; -import { ObservedSurfaceLayer } from "@modules/2DViewer/layers/implementations/layers/ObservedSurfaceLayer/ObservedSurfaceLayer"; -import { RealizationGridLayer } from "@modules/2DViewer/layers/implementations/layers/RealizationGridLayer/RealizationGridLayer"; -import { RealizationPolygonsLayer } from "@modules/2DViewer/layers/implementations/layers/RealizationPolygonsLayer/RealizationPolygonsLayer"; -import { RealizationSurfaceLayer } from "@modules/2DViewer/layers/implementations/layers/RealizationSurfaceLayer/RealizationSurfaceLayer"; -import { StatisticalSurfaceLayer } from "@modules/2DViewer/layers/implementations/layers/StatisticalSurfaceLayer/StatisticalSurfaceLayer"; -import { Ensemble } from "@modules/2DViewer/layers/implementations/settings/Ensemble"; -import { Realization } from "@modules/2DViewer/layers/implementations/settings/Realization"; -import { SurfaceAttribute } from "@modules/2DViewer/layers/implementations/settings/SurfaceAttribute"; -import { SurfaceName } from "@modules/2DViewer/layers/implementations/settings/SurfaceName"; -import { TimeOrInterval } from "@modules/2DViewer/layers/implementations/settings/TimeOrInterval"; -import { Group, Item, instanceofGroup, instanceofLayer } from "@modules/2DViewer/layers/interfaces"; -import { PreferredViewLayout } from "@modules/2DViewer/types"; -import { Dropdown } from "@mui/base"; -import { - Add, - Check, - Panorama, - SettingsApplications, - Settings as SettingsIcon, - TableRowsOutlined, - ViewColumnOutlined, -} from "@mui/icons-material"; - -import { useAtom } from "jotai"; - -import { preferredViewLayoutAtom } from "../atoms/baseAtoms"; - -export type LayerManagerComponentProps = { - layerManager: LayerManager; - workbenchSession: WorkbenchSession; - workbenchSettings: WorkbenchSettings; -}; - -export function LayerManagerComponent(props: LayerManagerComponentProps): React.ReactNode { - const layerListRef = React.useRef(null); - const colorSet = props.workbenchSettings.useColorSet(); - const layerListSize = useElementSize(layerListRef); - - const [preferredViewLayout, setPreferredViewLayout] = useAtom(preferredViewLayoutAtom); - - const groupDelegate = props.layerManager.getGroupDelegate(); - const items = usePublishSubscribeTopicValue(groupDelegate, GroupDelegateTopic.CHILDREN); - - function handleLayerAction(identifier: string, group?: Group) { - let groupDelegate = props.layerManager.getGroupDelegate(); - if (group) { - groupDelegate = group.getGroupDelegate(); - } - - const numSharedSettings = groupDelegate.findChildren((item) => { - return item instanceof SharedSetting; - }).length; - - const numViews = groupDelegate.getDescendantItems((item) => item instanceof View).length; - - switch (identifier) { - case "view": - groupDelegate.appendChild( - new View(numViews > 0 ? `View (${numViews})` : "View", props.layerManager, colorSet.getNextColor()) - ); - return; - case "delta-surface": - groupDelegate.insertChild(new DeltaSurface("Delta surface", props.layerManager), numSharedSettings); - return; - case "settings-group": - groupDelegate.insertChild(new SettingsGroup("Settings group", props.layerManager), numSharedSettings); - return; - case "color-scale": - groupDelegate.prependChild(new ColorScale("Color scale", props.layerManager)); - return; - case "observed-surface": - groupDelegate.insertChild(new ObservedSurfaceLayer(props.layerManager), numSharedSettings); - return; - case "statistical-surface": - groupDelegate.insertChild(new StatisticalSurfaceLayer(props.layerManager), numSharedSettings); - return; - case "realization-surface": - groupDelegate.insertChild(new RealizationSurfaceLayer(props.layerManager), numSharedSettings); - return; - case "realization-polygons": - groupDelegate.insertChild(new RealizationPolygonsLayer(props.layerManager), numSharedSettings); - return; - case "drilled-wellbore-trajectories": - groupDelegate.insertChild(new DrilledWellTrajectoriesLayer(props.layerManager), numSharedSettings); - return; - case "drilled-wellbore-picks": - groupDelegate.insertChild(new DrilledWellborePicksLayer(props.layerManager), numSharedSettings); - return; - case "realization-grid": - groupDelegate.insertChild(new RealizationGridLayer(props.layerManager), numSharedSettings); - return; - case "ensemble": - groupDelegate.prependChild(new SharedSetting(new Ensemble(), props.layerManager)); - return; - case "realization": - groupDelegate.prependChild(new SharedSetting(new Realization(), props.layerManager)); - return; - case "surface-name": - groupDelegate.prependChild(new SharedSetting(new SurfaceName(), props.layerManager)); - return; - case "surface-attribute": - groupDelegate.prependChild(new SharedSetting(new SurfaceAttribute(), props.layerManager)); - return; - case "Date": - groupDelegate.prependChild(new SharedSetting(new TimeOrInterval(), props.layerManager)); - return; - } - } - - function checkIfItemMoveAllowed(args: IsMoveAllowedArgs): boolean { - const movedItem = groupDelegate.findDescendantById(args.movedItemId); - if (!movedItem) { - return false; - } - - const destinationItem = args.destinationId - ? groupDelegate.findDescendantById(args.destinationId) - : props.layerManager; - - if (!destinationItem || !instanceofGroup(destinationItem)) { - return false; - } - - if (movedItem instanceof View && destinationItem instanceof View) { - return false; - } - - if (destinationItem instanceof DeltaSurface) { - if ( - instanceofLayer(movedItem) && - !( - movedItem instanceof RealizationSurfaceLayer || - movedItem instanceof StatisticalSurfaceLayer || - movedItem instanceof ObservedSurfaceLayer - ) - ) { - return false; - } - - if (instanceofGroup(movedItem)) { - return false; - } - - if (destinationItem.getGroupDelegate().findChildren((item) => instanceofLayer(item)).length >= 2) { - return false; - } - } - - const numSharedSettingsAndColorScales = - destinationItem.getGroupDelegate().findChildren((item) => { - return item instanceof SharedSetting || item instanceof ColorScale; - }).length ?? 0; - - if (!(movedItem instanceof SharedSetting || movedItem instanceof ColorScale)) { - if (args.position < numSharedSettingsAndColorScales) { - return false; - } - } else { - if (args.originId === args.destinationId) { - if (args.position >= numSharedSettingsAndColorScales) { - return false; - } - } else { - if (args.position > numSharedSettingsAndColorScales) { - return false; - } - } - } - - return true; - } - - function handleItemMoved( - movedItemId: string, - originId: string | null, - destinationId: string | null, - position: number - ) { - const movedItem = groupDelegate.findDescendantById(movedItemId); - if (!movedItem) { - return; - } - - let origin = props.layerManager.getGroupDelegate(); - if (originId) { - const candidate = groupDelegate.findDescendantById(originId); - if (candidate && instanceofGroup(candidate)) { - origin = candidate.getGroupDelegate(); - } - } - - let destination = props.layerManager.getGroupDelegate(); - if (destinationId) { - const candidate = groupDelegate.findDescendantById(destinationId); - if (candidate && instanceofGroup(candidate)) { - destination = candidate.getGroupDelegate(); - } - } - - if (origin === destination) { - origin.moveChild(movedItem, position); - return; - } - - origin.removeChild(movedItem); - destination.insertChild(movedItem, position); - } - - const hasView = groupDelegate.getDescendantItems((item) => item instanceof View).length > 0; - const adjustedLayerActions = hasView ? LAYER_ACTIONS : INITIAL_LAYER_ACTIONS; - - return ( -
-
-
-
Layers
- - - - - - - - Preferred view layout - setPreferredViewLayout(PreferredViewLayout.HORIZONTAL)} - > - Horizontal - - setPreferredViewLayout(PreferredViewLayout.VERTICAL)} - > - Vertical - - - -
-
- - Click on to add a layer. -
- } - > - {items.map((item: Item) => makeComponent(item, LAYER_ACTIONS, handleLayerAction))} - -
-
-
- ); -} - -type ViewLayoutMenuItemProps = { - checked: boolean; - onClick: () => void; - children: React.ReactNode; -}; - -function ViewLayoutMenuItem(props: ViewLayoutMenuItemProps): React.ReactNode { - return ( - -
-
{props.checked && }
-
{props.children}
-
-
- ); -} - -const INITIAL_LAYER_ACTIONS: LayersActionGroup[] = [ - { - label: "Groups", - children: [ - { - identifier: "view", - icon: , - label: "View", - }, - { - identifier: "settings-group", - icon: , - label: "Settings group", - }, - ], - }, -]; - -const LAYER_ACTIONS: LayersActionGroup[] = [ - { - label: "Groups", - children: [ - { - identifier: "view", - icon: , - label: "View", - }, - { - identifier: "settings-group", - icon: , - label: "Settings group", - }, - /* - { - identifier: "delta-surface", - icon: , - label: "Delta Surface", - }, - */ - ], - }, - { - label: "Layers", - children: [ - { - label: "Surfaces", - children: [ - { - identifier: "observed-surface", - icon: , - label: "Observed Surface", - }, - { - identifier: "statistical-surface", - icon: , - label: "Statistical Surface", - }, - { - identifier: "realization-surface", - icon: , - label: "Realization Surface", - }, - ], - }, - { - label: "Wells", - children: [ - { - identifier: "drilled-wellbore-trajectories", - icon: , - label: "Drilled Wellbore Trajectories", - }, - { - identifier: "drilled-wellbore-picks", - icon: , - label: "Drilled Wellbore Picks", - }, - ], - }, - { - label: "Polygons", - children: [ - { - identifier: "realization-polygons", - icon: , - label: "Realization Polygons", - }, - ], - }, - { - label: "Others", - children: [ - { - identifier: "realization-grid", - icon: , - label: "Realization Grid", - }, - ], - }, - ], - }, - { - label: "Shared Settings", - children: [ - { - identifier: "ensemble", - icon: , - label: "Ensemble", - }, - { - identifier: "realization", - icon: , - label: "Realization", - }, - { - identifier: "surface-name", - icon: , - label: "Surface Name", - }, - { - identifier: "surface-attribute", - icon: , - label: "Surface Attribute", - }, - { - identifier: "Date", - icon: , - label: "Date", - }, - ], - }, - { - label: "Utilities", - children: [ - { - identifier: "color-scale", - icon: , - label: "Color scale", - }, - ], - }, -]; diff --git a/frontend/src/modules/2DViewer/settings/settings.tsx b/frontend/src/modules/2DViewer/settings/settings.tsx deleted file mode 100644 index b2c17d128..000000000 --- a/frontend/src/modules/2DViewer/settings/settings.tsx +++ /dev/null @@ -1,146 +0,0 @@ -import React from "react"; - -import { ModuleSettingsProps } from "@framework/Module"; -import { useEnsembleSet } from "@framework/WorkbenchSession"; -import { FieldDropdown } from "@framework/components/FieldDropdown"; -import { CollapsibleGroup } from "@lib/components/CollapsibleGroup"; -import { useQueryClient } from "@tanstack/react-query"; - -import { useAtom, useAtomValue, useSetAtom } from "jotai"; - -import { layerManagerAtom, preferredViewLayoutAtom, userSelectedFieldIdentifierAtom } from "./atoms/baseAtoms"; -import { selectedFieldIdentifierAtom } from "./atoms/derivedAtoms"; -import { LayerManagerComponent } from "./components/layerManagerComponent"; - -import { LayerManager, LayerManagerTopic } from "../layers/LayerManager"; -import { GroupDelegateTopic } from "../layers/delegates/GroupDelegate"; - -export function Settings(props: ModuleSettingsProps): React.ReactNode { - const ensembleSet = useEnsembleSet(props.workbenchSession); - const queryClient = useQueryClient(); - - const [layerManager, setLayerManager] = useAtom(layerManagerAtom); - - const fieldIdentifier = useAtomValue(selectedFieldIdentifierAtom); - const setFieldIdentifier = useSetAtom(userSelectedFieldIdentifierAtom); - const [preferredViewLayout, setPreferredViewLayout] = useAtom(preferredViewLayoutAtom); - - const persistState = React.useCallback( - function persistLayerManagerState() { - if (!layerManager) { - return; - } - - const serializedState = { - layerManager: layerManager.serializeState(), - fieldIdentifier, - preferredViewLayout, - }; - window.localStorage.setItem( - `${props.settingsContext.getInstanceIdString()}-settings`, - JSON.stringify(serializedState) - ); - }, - [layerManager, fieldIdentifier, preferredViewLayout, props.settingsContext] - ); - - const applyPersistedState = React.useCallback( - function applyPersistedState(layerManager: LayerManager) { - const serializedState = window.localStorage.getItem( - `${props.settingsContext.getInstanceIdString()}-settings` - ); - if (!serializedState) { - return; - } - - const parsedState = JSON.parse(serializedState); - if (parsedState.fieldIdentifier) { - setFieldIdentifier(parsedState.fieldIdentifier); - } - if (parsedState.preferredViewLayout) { - setPreferredViewLayout(parsedState.preferredViewLayout); - } - - if (parsedState.layerManager) { - if (!layerManager) { - return; - } - layerManager.deserializeState(parsedState.layerManager); - } - }, - [setFieldIdentifier, setPreferredViewLayout, props.settingsContext] - ); - - React.useEffect( - function onMountEffect() { - const newLayerManager = new LayerManager(props.workbenchSession, props.workbenchSettings, queryClient); - setLayerManager(newLayerManager); - - applyPersistedState(newLayerManager); - - return function onUnmountEffect() { - newLayerManager.beforeDestroy(); - }; - }, - [setLayerManager, props.workbenchSession, props.workbenchSettings, queryClient, applyPersistedState] - ); - - React.useEffect( - function onLayerManagerChangeEffect() { - if (!layerManager) { - return; - } - - persistState(); - - const unsubscribeDataRev = layerManager - .getPublishSubscribeDelegate() - .makeSubscriberFunction(LayerManagerTopic.LAYER_DATA_REVISION)(persistState); - - const unsubscribeExpands = layerManager - .getGroupDelegate() - .getPublishSubscribeDelegate() - .makeSubscriberFunction(GroupDelegateTopic.CHILDREN_EXPANSION_STATES)(persistState); - - return function onUnmountEffect() { - layerManager.beforeDestroy(); - unsubscribeDataRev(); - unsubscribeExpands(); - }; - }, - [layerManager, props.workbenchSession, props.workbenchSettings, persistState] - ); - - React.useEffect( - function onFieldIdentifierChangedEffect() { - if (!layerManager) { - return; - } - layerManager.updateGlobalSetting("fieldId", fieldIdentifier); - }, - [fieldIdentifier, layerManager] - ); - - function handleFieldChange(fieldId: string | null) { - setFieldIdentifier(fieldId); - if (!layerManager) { - return; - } - layerManager.updateGlobalSetting("fieldId", fieldId); - } - - return ( -
- - - - {layerManager && ( - - )} -
- ); -} diff --git a/frontend/src/modules/2DViewer/types.ts b/frontend/src/modules/2DViewer/types.ts deleted file mode 100644 index 4a9b727f7..000000000 --- a/frontend/src/modules/2DViewer/types.ts +++ /dev/null @@ -1,38 +0,0 @@ -export enum LayerType { - OBSERVED_SURFACE = "observedSurface", - STATISTICAL_SURFACE = "statisticalSurface", - REALIZATION_SURFACE = "realizationSurface", - REALIZATION_GRID = "realizationGrid", - REALIZATION_POLYGONS = "realizationPolygons", - DRILLED_WELLBORE_TRAJECTORIES = "drilledWellTrajectories", - DRILLED_WELLBORE_PICKS = "drilledWellPicks", -} - -export const LAYER_TYPE_TO_STRING_MAPPING: Record = { - [LayerType.OBSERVED_SURFACE]: "Observed Surface", - [LayerType.STATISTICAL_SURFACE]: "Statistical Surface", - [LayerType.REALIZATION_SURFACE]: "Realization Surface", - [LayerType.REALIZATION_GRID]: "Realization Grid Layer", - [LayerType.REALIZATION_POLYGONS]: "Realization Polygons", - [LayerType.DRILLED_WELLBORE_TRAJECTORIES]: "Drilled Well Trajectories", - [LayerType.DRILLED_WELLBORE_PICKS]: "Drilled Well Picks", -}; - -export enum SharedSettingType { - ENSEMBLE = "ensemble", - REALIZATION = "realization", - SURFACE_ATTRIBUTE = "surfaceAttribute", - SURFACE_NAME = "surfaceName", -} - -export const SHARED_SETTING_TYPE_TO_STRING_MAPPING: Record = { - [SharedSettingType.ENSEMBLE]: "Ensemble", - [SharedSettingType.REALIZATION]: "Realization", - [SharedSettingType.SURFACE_ATTRIBUTE]: "Surface Attribute", - [SharedSettingType.SURFACE_NAME]: "Surface Name", -}; - -export enum PreferredViewLayout { - HORIZONTAL = "horizontal", - VERTICAL = "vertical", -} diff --git a/frontend/src/modules/2DViewer/view/components/LayersWrapper.tsx b/frontend/src/modules/2DViewer/view/components/LayersWrapper.tsx deleted file mode 100644 index ce4a63968..000000000 --- a/frontend/src/modules/2DViewer/view/components/LayersWrapper.tsx +++ /dev/null @@ -1,154 +0,0 @@ -import React from "react"; - -import { View as DeckGlView } from "@deck.gl/core"; -import { ViewContext } from "@framework/ModuleContext"; -import { useViewStatusWriter } from "@framework/StatusWriter"; -import { PendingWrapper } from "@lib/components/PendingWrapper"; -import { useElementSize } from "@lib/hooks/useElementSize"; -import { Rect2D, outerRectContainsInnerRect } from "@lib/utils/geometry"; -import { Interfaces } from "@modules/2DViewer/interfaces"; -import { LayerManager, LayerManagerTopic } from "@modules/2DViewer/layers/LayerManager"; -import { usePublishSubscribeTopicValue } from "@modules/2DViewer/layers/delegates/PublishSubscribeDelegate"; -import { BoundingBox } from "@modules/2DViewer/layers/interfaces"; -import { PreferredViewLayout } from "@modules/2DViewer/types"; -import { ColorLegendsContainer } from "@modules/_shared/components/ColorLegendsContainer"; -import { ColorScaleWithId } from "@modules/_shared/components/ColorLegendsContainer/colorLegendsContainer"; -import { ViewportType } from "@webviz/subsurface-viewer"; -import { ViewsType } from "@webviz/subsurface-viewer/dist/SubsurfaceViewer"; - -import { ReadoutWrapper } from "./ReadoutWrapper"; - -import { PlaceholderLayer } from "../customDeckGlLayers/PlaceholderLayer"; -import { DeckGlLayerWithPosition, recursivelyMakeViewsAndLayers } from "../utils/makeViewsAndLayers"; - -export type LayersWrapperProps = { - layerManager: LayerManager; - preferredViewLayout: PreferredViewLayout; - viewContext: ViewContext; -}; - -export function LayersWrapper(props: LayersWrapperProps): React.ReactNode { - const [prevBoundingBox, setPrevBoundingBox] = React.useState(null); - - const mainDivRef = React.useRef(null); - const mainDivSize = useElementSize(mainDivRef); - const statusWriter = useViewStatusWriter(props.viewContext); - - usePublishSubscribeTopicValue(props.layerManager, LayerManagerTopic.LAYER_DATA_REVISION); - - const viewports: ViewportType[] = []; - const viewerLayers: DeckGlLayerWithPosition[] = []; - const viewportAnnotations: React.ReactNode[] = []; - const globalColorScales: ColorScaleWithId[] = []; - - const views: ViewsType = { - layout: [1, 1], - viewports: viewports, - showLabel: false, - }; - - let numCols = 0; - let numRows = 0; - - let numLoadingLayers = 0; - - const viewsAndLayers = recursivelyMakeViewsAndLayers(props.layerManager); - - numCols = Math.ceil(Math.sqrt(viewsAndLayers.views.length)); - numRows = Math.ceil(viewsAndLayers.views.length / numCols); - - if (props.preferredViewLayout === PreferredViewLayout.HORIZONTAL) { - [numCols, numRows] = [numRows, numCols]; - } - - views.layout = [numCols, numRows]; - - viewerLayers.push(...viewsAndLayers.layers); - globalColorScales.push(...viewsAndLayers.colorScales); - const globalLayerIds = viewsAndLayers.layers.map((layer) => layer.layer.id); - - for (const view of viewsAndLayers.views) { - viewports.push({ - id: view.id, - name: view.name, - isSync: true, - layerIds: [...globalLayerIds, ...view.layers.map((layer) => layer.layer.id), "placeholder"], - }); - viewerLayers.push(...view.layers); - - viewportAnnotations.push( - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - /* @ts-expect-error */ - - -
-
-
-
{view.name}
-
-
- - ); - } - - if (viewsAndLayers.boundingBox !== null) { - if (prevBoundingBox !== null) { - const oldBoundingRect: Rect2D | null = { - x: prevBoundingBox.x[0], - y: prevBoundingBox.y[0], - width: prevBoundingBox.x[1] - prevBoundingBox.x[0], - height: prevBoundingBox.y[1] - prevBoundingBox.y[0], - }; - - const newBoundingRect: Rect2D = { - x: viewsAndLayers.boundingBox.x[0], - y: viewsAndLayers.boundingBox.y[0], - width: viewsAndLayers.boundingBox.x[1] - viewsAndLayers.boundingBox.x[0], - height: viewsAndLayers.boundingBox.y[1] - viewsAndLayers.boundingBox.y[0], - }; - - if (!outerRectContainsInnerRect(oldBoundingRect, newBoundingRect)) { - setPrevBoundingBox(viewsAndLayers.boundingBox); - } - } else { - setPrevBoundingBox(viewsAndLayers.boundingBox); - } - } - - numLoadingLayers = viewsAndLayers.numLoadingLayers; - statusWriter.setLoading(viewsAndLayers.numLoadingLayers > 0); - - for (const message of viewsAndLayers.errorMessages) { - statusWriter.addError(message); - } - - let bounds: [number, number, number, number] | undefined = undefined; - if (prevBoundingBox) { - bounds = [prevBoundingBox.x[0], prevBoundingBox.y[0], prevBoundingBox.x[1], prevBoundingBox.y[1]]; - } - - const layers = viewerLayers.toSorted((a, b) => b.position - a.position).map((layer) => layer.layer); - layers.push(new PlaceholderLayer({ id: "placeholder" })); - - return ( -
- 0}> -
- -
-
-
- ); -} diff --git a/frontend/src/modules/2DViewer/view/components/ReadoutBoxWrapper.tsx b/frontend/src/modules/2DViewer/view/components/ReadoutBoxWrapper.tsx deleted file mode 100644 index 70a488c0b..000000000 --- a/frontend/src/modules/2DViewer/view/components/ReadoutBoxWrapper.tsx +++ /dev/null @@ -1,117 +0,0 @@ -import React from "react"; - -import { ReadoutBox, ReadoutItem } from "@modules/_shared/components/ReadoutBox"; -import { ExtendedLayerProps, LayerPickInfo } from "@webviz/subsurface-viewer"; - -import { isEqual } from "lodash"; - -// Needs extra distance for the left side; this avoids overlapping with legend elements -const READOUT_EDGE_DISTANCE_REM = { left: 6 }; - -function makePositionReadout(layerPickInfo: LayerPickInfo): ReadoutItem | null { - if (layerPickInfo.coordinate === undefined || layerPickInfo.coordinate.length < 2) { - return null; - } - return { - label: "Position", - info: [ - { - name: "x", - value: layerPickInfo.coordinate[0], - unit: "m", - }, - { - name: "y", - value: layerPickInfo.coordinate[1], - unit: "m", - }, - ], - }; -} - -export type ReadoutBoxWrapperProps = { - layerPickInfo: LayerPickInfo[]; - maxNumItems?: number; - visible?: boolean; -}; - -export function ReadoutBoxWrapper(props: ReadoutBoxWrapperProps): React.ReactNode { - const [infoData, setInfoData] = React.useState([]); - const [prevLayerPickInfo, setPrevLayerPickInfo] = React.useState([]); - - if (!isEqual(props.layerPickInfo, prevLayerPickInfo)) { - setPrevLayerPickInfo(props.layerPickInfo); - const newReadoutItems: ReadoutItem[] = []; - - if (props.layerPickInfo.length === 0) { - setInfoData([]); - return; - } - - const positionReadout = makePositionReadout(props.layerPickInfo[0]); - if (!positionReadout) { - return; - } - newReadoutItems.push(positionReadout); - - for (const layerPickInfo of props.layerPickInfo) { - const layerName = (layerPickInfo.layer?.props as unknown as ExtendedLayerProps)?.name; - const layerProps = layerPickInfo.properties; - - // pick info can have 2 types of properties that can be displayed on the info card - // 1. defined as propertyValue, used for general layer info (now using for positional data) - // 2. Another defined as array of property object described by type PropertyDataType - - const layerReadout = newReadoutItems.find((item) => item.label === layerName); - - // collecting card data for 1st type - const zValue = (layerPickInfo as LayerPickInfo).propertyValue; - if (zValue !== undefined) { - if (layerReadout) { - layerReadout.info.push({ - name: "Property value", - value: zValue, - }); - } else { - newReadoutItems.push({ - label: layerName ?? "Unknown layer", - info: [ - { - name: "Property value", - value: zValue, - }, - ], - }); - } - } - - // collecting card data for 2nd type - if (!layerProps || layerProps.length === 0) { - continue; - } - if (layerReadout) { - layerProps?.forEach((prop) => { - const property = layerReadout.info?.find((item) => item.name === prop.name); - if (property) { - property.value = prop.value; - } else { - layerReadout.info.push(prop); - } - }); - } else { - newReadoutItems.push({ - label: layerName ?? "Unknown layer", - info: layerProps, - }); - } - } - - setInfoData(newReadoutItems); - } - - if (!props.visible) { - return null; - } - - return ; -} diff --git a/frontend/src/modules/2DViewer/view/components/ReadoutWrapper.tsx b/frontend/src/modules/2DViewer/view/components/ReadoutWrapper.tsx deleted file mode 100644 index 042573389..000000000 --- a/frontend/src/modules/2DViewer/view/components/ReadoutWrapper.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import React from "react"; - -import { Layer as DeckGlLayer } from "@deck.gl/core"; -import { SubsurfaceViewerWithCameraState } from "@modules/_shared/components/SubsurfaceViewerWithCameraState"; -import { LayerPickInfo, MapMouseEvent, ViewStateType, ViewsType } from "@webviz/subsurface-viewer"; - -import { ReadoutBoxWrapper } from "./ReadoutBoxWrapper"; -import { Toolbar } from "./Toolbar"; - -export type ReadooutWrapperProps = { - views: ViewsType; - viewportAnnotations: React.ReactNode[]; - layers: DeckGlLayer[]; - bounds?: [number, number, number, number]; -}; - -export function ReadoutWrapper(props: ReadooutWrapperProps): React.ReactNode { - const id = React.useId(); - - const [cameraPositionSetByAction, setCameraPositionSetByAction] = React.useState(null); - const [triggerHomeCounter, setTriggerHomeCounter] = React.useState(0); - const [layerPickingInfo, setLayerPickingInfo] = React.useState([]); - - function handleFitInViewClick() { - setTriggerHomeCounter((prev) => prev + 1); - } - - function handleMouseHover(event: MapMouseEvent): void { - setLayerPickingInfo(event.infos); - } - - function handleMouseEvent(event: MapMouseEvent): void { - if (event.type === "hover") { - handleMouseHover(event); - } - } - - return ( - <> - - - setCameraPositionSetByAction(null)} - onMouseEvent={handleMouseEvent} - layers={props.layers} - scale={{ - visible: true, - incrementValue: 100, - widthPerUnit: 100, - cssStyle: { - right: 10, - top: 10, - }, - }} - coords={{ - visible: false, - multiPicking: true, - pickDepth: 2, - }} - triggerHome={triggerHomeCounter} - pickingRadius={5} - > - {props.viewportAnnotations} - - {props.views.viewports.length === 0 && ( -
- Please add views and layers in the settings panel. -
- )} - - ); -} diff --git a/frontend/src/modules/2DViewer/view/components/Toolbar.tsx b/frontend/src/modules/2DViewer/view/components/Toolbar.tsx deleted file mode 100644 index 08527e27d..000000000 --- a/frontend/src/modules/2DViewer/view/components/Toolbar.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Button } from "@lib/components/Button"; -import { Toolbar as GenericToolbar } from "@modules/_shared/components/Toolbar"; -import { FilterCenterFocus } from "@mui/icons-material"; - -export type ToolbarProps = { - onFitInView: () => void; -}; - -export function Toolbar(props: ToolbarProps): React.ReactNode { - function handleFitInViewClick() { - props.onFitInView(); - } - - return ( - - - - ); -} diff --git a/frontend/src/modules/2DViewer/view/customDeckGlLayers/AdvancedWellsLayer.ts b/frontend/src/modules/2DViewer/view/customDeckGlLayers/AdvancedWellsLayer.ts deleted file mode 100644 index 112c3363b..000000000 --- a/frontend/src/modules/2DViewer/view/customDeckGlLayers/AdvancedWellsLayer.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { FilterContext, Layer, LayersList } from "@deck.gl/core"; -import { GeoJsonLayer } from "@deck.gl/layers"; -import { WellsLayer } from "@webviz/subsurface-viewer/dist/layers"; - -export class AdvancedWellsLayer extends WellsLayer { - static layerName: string = "WellsLayer"; - - constructor(props: any) { - super(props); - } - - filterSubLayer(context: FilterContext): boolean { - if (context.layer.id.includes("names")) { - return context.viewport.zoom > -2; - } - - return true; - } - - renderLayers(): LayersList { - const layers = super.renderLayers(); - - if (!Array.isArray(layers)) { - return layers; - } - - const colorsLayer = layers.find((layer) => { - if (!(layer instanceof Layer)) { - return false; - } - - return layer.id.includes("colors"); - }); - - if (!(colorsLayer instanceof GeoJsonLayer)) { - return layers; - } - - const newColorsLayer = new GeoJsonLayer({ - data: colorsLayer.props.data, - pickable: true, - stroked: false, - positionFormat: colorsLayer.props.positionFormat, - pointRadiusUnits: "meters", - lineWidthUnits: "meters", - pointRadiusScale: this.props.pointRadiusScale, - lineWidthScale: this.props.lineWidthScale, - getLineWidth: colorsLayer.props.getLineWidth, - getPointRadius: colorsLayer.props.getPointRadius, - lineBillboard: true, - pointBillboard: true, - parameters: colorsLayer.props.parameters, - visible: colorsLayer.props.visible, - id: "colors", - lineWidthMinPixels: 1, - lineWidthMaxPixels: 5, - extensions: colorsLayer.props.extensions, - getDashArray: colorsLayer.props.getDashArray, - getLineColor: colorsLayer.props.getLineColor, - getFillColor: colorsLayer.props.getFillColor, - autoHighlight: true, - onHover: () => {}, - }); - - return [newColorsLayer, ...layers.filter((layer) => layer !== colorsLayer)]; - } -} diff --git a/frontend/src/modules/2DViewer/view/customDeckGlLayers/PlaceholderLayer.ts b/frontend/src/modules/2DViewer/view/customDeckGlLayers/PlaceholderLayer.ts deleted file mode 100644 index b146c9fea..000000000 --- a/frontend/src/modules/2DViewer/view/customDeckGlLayers/PlaceholderLayer.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Layer } from "@deck.gl/core"; - -type PlaceholderLayerProps = { - id: string; -}; - -export class PlaceholderLayer extends Layer { - static layerName: string = "PlaceholderLayer"; - - constructor(props: PlaceholderLayerProps) { - super(props); - } - - initializeState(): void { - return; - } - - render() { - return null; - } -} diff --git a/frontend/src/modules/2DViewer/view/customDeckGlLayers/WellborePicksLayer.ts b/frontend/src/modules/2DViewer/view/customDeckGlLayers/WellborePicksLayer.ts deleted file mode 100644 index c58047a25..000000000 --- a/frontend/src/modules/2DViewer/view/customDeckGlLayers/WellborePicksLayer.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { CompositeLayer, CompositeLayerProps, FilterContext, Layer, UpdateParameters } from "@deck.gl/core"; -import { GeoJsonLayer, TextLayer } from "@deck.gl/layers"; - -import type { Feature, FeatureCollection } from "geojson"; - -export type WellBorePickLayerData = { - easting: number; - northing: number; - wellBoreUwi: string; - tvdMsl: number; - md: number; - slotName: string; -}; - -type TextLayerData = { - coordinates: [number, number, number]; - name: string; -}; - -export type WellBorePicksLayerProps = { - id: string; - data: WellBorePickLayerData[]; -}; - -export class WellborePicksLayer extends CompositeLayer { - static layerName: string = "WellborePicksLayer"; - private _textData: TextLayerData[] = []; - private _pointsData: FeatureCollection | null = null; - - filterSubLayer(context: FilterContext): boolean { - if (context.layer.id.includes("text")) { - return context.viewport.zoom > -4; - } - - return true; - } - - updateState(params: UpdateParameters>>): void { - const features: Feature[] = params.props.data.map((wellPick) => { - return { - type: "Feature", - geometry: { - type: "Point", - coordinates: [wellPick.easting, wellPick.northing], - }, - properties: { - name: `${wellPick.wellBoreUwi}, TVD_MSL: ${wellPick.tvdMsl}, MD: ${wellPick.md}`, - color: [100, 100, 100, 100], - }, - }; - }); - - const pointsData: FeatureCollection = { - type: "FeatureCollection", - features: features, - }; - - const textData: TextLayerData[] = this.props.data.map((wellPick) => { - return { - coordinates: [wellPick.easting, wellPick.northing, wellPick.tvdMsl], - name: wellPick.wellBoreUwi, - }; - }); - - this._pointsData = pointsData; - this._textData = textData; - } - - renderLayers() { - const fontSize = 16; - const sizeMinPixels = 16; - const sizeMaxPixels = 16; - - return [ - new GeoJsonLayer( - this.getSubLayerProps({ - id: "points", - data: this._pointsData ?? undefined, - // pointType: 'circle+text', - filled: true, - lineWidthMinPixels: 5, - lineWidthMaxPixels: 5, - lineWidthUnits: "meters", - parameters: { - depthTest: false, - }, - getLineWidth: 1, - depthTest: false, - pickable: true, - getText: (d: Feature) => d.properties?.wellBoreUwi, - getLineColor: [50, 50, 50], - // extensions: [new CollisionFilterExtension()], - // collisionGroup: "wellbore-picks", - }) - ), - - new TextLayer( - this.getSubLayerProps({ - id: "text", - data: this._textData, - // depthTest: true, - pickable: true, - getColor: [255, 255, 255], - fontWeight: 800, - fontSettings: { - fontSize: fontSize * 2, - sdf: true, - }, - outlineColor: [0, 0, 0], - outlineWidth: 2, - getSize: 12, - sdf: true, - sizeScale: fontSize, - sizeUnits: "meters", - sizeMinPixels: sizeMinPixels, - sizeMaxPixels: sizeMaxPixels, - getAlignmentBaseline: "top", - getTextAnchor: "middle", - getPosition: (d: TextLayerData) => d.coordinates, - getText: (d: TextLayerData) => d.name, - // maxWidth: 64 * 12, - /* - // extensions: [new CollisionFilterExtension()], - collisionGroup: "wellbore-picks", - - collisionTestProps: { - sizeScale: fontSize, - sizeMaxPixels: sizeMaxPixels * 2, - sizeMinPixels: sizeMinPixels * 2, - }, - */ - }) - ), - ]; - } -} diff --git a/frontend/src/modules/2DViewer/view/utils/layerFactory.ts b/frontend/src/modules/2DViewer/view/utils/layerFactory.ts deleted file mode 100644 index fc03f2de5..000000000 --- a/frontend/src/modules/2DViewer/view/utils/layerFactory.ts +++ /dev/null @@ -1,363 +0,0 @@ -import { PolygonData_api, SurfaceDataPng_api, SurfaceDef_api, WellborePick_api, WellboreTrajectory_api } from "@api"; -import { Layer } from "@deck.gl/core"; -import { GeoJsonLayer } from "@deck.gl/layers"; -import { defaultColorPalettes } from "@framework/utils/colorPalettes"; -import { ColorScaleGradientType, ColorScaleType } from "@lib/utils/ColorScale"; -import { Vec2, rotatePoint2Around } from "@lib/utils/vec2"; -import { GridMappedProperty_trans, GridSurface_trans } from "@modules/3DViewer/view/queries/queryDataTransforms"; -import { ColorScaleWithName } from "@modules/_shared/utils/ColorScaleWithName"; -import { ColormapLayer, Grid3DLayer, WellsLayer } from "@webviz/subsurface-viewer/dist/layers"; - -import { Rgb, parse } from "culori"; -import { Feature, FeatureCollection, GeoJsonProperties, Geometry } from "geojson"; - -import { DrilledWellTrajectoriesLayer } from "../../layers/implementations/layers/DrilledWellTrajectoriesLayer/DrilledWellTrajectoriesLayer"; -import { DrilledWellborePicksLayer } from "../../layers/implementations/layers/DrilledWellborePicksLayer/DrilledWellborePicksLayer"; -import { ObservedSurfaceLayer } from "../../layers/implementations/layers/ObservedSurfaceLayer/ObservedSurfaceLayer"; -import { RealizationGridLayer } from "../../layers/implementations/layers/RealizationGridLayer/RealizationGridLayer"; -import { RealizationPolygonsLayer } from "../../layers/implementations/layers/RealizationPolygonsLayer/RealizationPolygonsLayer"; -import { RealizationSurfaceLayer } from "../../layers/implementations/layers/RealizationSurfaceLayer/RealizationSurfaceLayer"; -import { StatisticalSurfaceLayer } from "../../layers/implementations/layers/StatisticalSurfaceLayer/StatisticalSurfaceLayer"; -import { Layer as LayerInterface } from "../../layers/interfaces"; -import { AdvancedWellsLayer } from "../customDeckGlLayers/AdvancedWellsLayer"; -import { WellBorePickLayerData, WellborePicksLayer } from "../customDeckGlLayers/WellborePicksLayer"; - -export function makeLayer(layer: LayerInterface, colorScale?: ColorScaleWithName): Layer | null { - const data = layer.getLayerDelegate().getData(); - - if (colorScale === undefined) { - colorScale = new ColorScaleWithName({ - colorPalette: defaultColorPalettes[0], - gradientType: ColorScaleGradientType.Sequential, - name: "Default", - type: ColorScaleType.Continuous, - steps: 10, - }); - } - - if (!data) { - return null; - } - if (layer instanceof ObservedSurfaceLayer) { - return createMapImageLayer( - data, - layer.getItemDelegate().getId(), - layer.getItemDelegate().getName(), - colorScale - ); - } - if (layer instanceof RealizationSurfaceLayer) { - return createMapImageLayer( - data, - layer.getItemDelegate().getId(), - layer.getItemDelegate().getName(), - colorScale - ); - } - if (layer instanceof StatisticalSurfaceLayer) { - return createMapImageLayer( - data, - layer.getItemDelegate().getId(), - layer.getItemDelegate().getName(), - colorScale - ); - } - if (layer instanceof RealizationPolygonsLayer) { - return createPolygonsLayer(data, layer.getItemDelegate().getId()); - } - if (layer instanceof DrilledWellTrajectoriesLayer) { - return makeWellsLayer(data, layer.getItemDelegate().getId(), null); - } - if (layer instanceof DrilledWellborePicksLayer) { - return createWellPicksLayer(data, layer.getItemDelegate().getId()); - } - if (layer instanceof RealizationGridLayer) { - return makeGrid3DLayer( - layer.getItemDelegate().getId(), - data.gridSurfaceData, - data.gridParameterData, - layer.getSettingsContext().getDelegate().getSettings().showGridLines.getDelegate().getValue(), - colorScale - ); - } - return null; -} -function createWellPicksLayer(wellPicksDataApi: WellborePick_api[], id: string): WellborePicksLayer { - const wellPicksData: WellBorePickLayerData[] = wellPicksDataApi.map((wellPick) => { - return { - easting: wellPick.easting, - northing: wellPick.northing, - wellBoreUwi: wellPick.uniqueWellboreIdentifier, - tvdMsl: wellPick.tvdMsl, - md: wellPick.md, - pickable: true, - slotName: "", - }; - }); - return new WellborePicksLayer({ - id: id, - data: wellPicksData, - pickable: true, - }); -} - -/* -function createMapFloatLayer(layerData: SurfaceDataFloat_trans, id: string): MapLayer { - return new MapLayer({ - id: id, - meshData: layerData.valuesFloat32Arr, - typedArraySupport: true, - frame: { - origin: [layerData.surface_def.origin_utm_x, layerData.surface_def.origin_utm_y], - count: [layerData.surface_def.npoints_x, layerData.surface_def.npoints_y], - increment: [layerData.surface_def.inc_x, layerData.surface_def.inc_y], - rotDeg: layerData.surface_def.rot_deg, - }, - contours: [0, 100], - isContoursDepth: true, - gridLines: false, - material: true, - smoothShading: true, - colorMapName: "Physics", - parameters: { - depthTest: false, - }, - depthTest: false, - }); -} -*/ - -function createMapImageLayer( - layerData: SurfaceDataPng_api, - id: string, - name: string, - colorScale?: ColorScaleWithName -): ColormapLayer { - return new ColormapLayer({ - id: id, - name: name, - image: `data:image/png;base64,${layerData.png_image_base64}`, - bounds: _calcBoundsForRotationAroundUpperLeftCorner(layerData.surface_def), - rotDeg: layerData.surface_def.rot_deg, - valueRange: [layerData.value_min, layerData.value_max], - colorMapRange: [layerData.value_min, layerData.value_max], - colorMapName: "Physics", - parameters: { - depthWriteEnabled: false, - }, - colorMapFunction: makeColorMapFunction(colorScale, layerData.value_min, layerData.value_max), - }); -} - -function _calcBoundsForRotationAroundUpperLeftCorner(surfDef: SurfaceDef_api): [number, number, number, number] { - const width = (surfDef.npoints_x - 1) * surfDef.inc_x; - const height = (surfDef.npoints_y - 1) * surfDef.inc_y; - const orgRotPoint: Vec2 = { x: surfDef.origin_utm_x, y: surfDef.origin_utm_y }; - const orgTopLeft: Vec2 = { x: surfDef.origin_utm_x, y: surfDef.origin_utm_y + height }; - - const transTopLeft: Vec2 = rotatePoint2Around(orgTopLeft, orgRotPoint, (surfDef.rot_deg * Math.PI) / 180); - const tLeft = transTopLeft.x; - const tBottom = transTopLeft.y - height; - const tRight = transTopLeft.x + width; - const tTop = transTopLeft.y; - - const bounds: [number, number, number, number] = [tLeft, tBottom, tRight, tTop]; - - return bounds; -} - -function createPolygonsLayer(polygonsData: PolygonData_api[], id: string): GeoJsonLayer { - const features: Feature[] = polygonsData.map((polygon) => { - return polygonsToGeojson(polygon); - }); - const data: FeatureCollection = { - type: "FeatureCollection", - features: features, - }; - return new GeoJsonLayer({ - id: id, - data: data, - // opacity: 0.5, - filled: false, - lineWidthMinPixels: 2, - parameters: { - depthTest: false, - }, - - pickable: true, - }); -} -function polygonsToGeojson(polygons: PolygonData_api): Feature { - const data: Feature = { - type: "Feature", - geometry: { - type: "Polygon", - coordinates: [zipCoords(polygons.x_arr, polygons.y_arr, polygons.z_arr)], - }, - properties: { name: polygons.poly_id, color: [0, 0, 0, 255] }, - }; - return data; -} - -export function makeWellsLayer( - fieldWellboreTrajectoriesData: WellboreTrajectory_api[], - id: string, - selectedWellboreUuid: string | null -): WellsLayer { - const tempWorkingWellsData = fieldWellboreTrajectoriesData.filter( - (el) => el.uniqueWellboreIdentifier !== "NO 34/4-K-3 AH" - ); - const wellLayerDataFeatures = tempWorkingWellsData.map((well) => - wellTrajectoryToGeojson(well, selectedWellboreUuid) - ); - - function getLineStyleWidth(object: Feature): number { - if (object.properties && "lineWidth" in object.properties) { - return object.properties.lineWidth as number; - } - return 2; - } - - function getWellHeadStyleWidth(object: Feature): number { - if (object.properties && "wellHeadSize" in object.properties) { - return object.properties.wellHeadSize as number; - } - return 1; - } - - function getColor(object: Feature): [number, number, number, number] { - if (object.properties && "color" in object.properties) { - return object.properties.color as [number, number, number, number]; - } - return [50, 50, 50, 100]; - } - - const wellsLayer = new AdvancedWellsLayer({ - id: id, - data: { - type: "FeatureCollection", - unit: "m", - features: wellLayerDataFeatures, - }, - refine: false, - lineStyle: { width: getLineStyleWidth, color: getColor }, - wellHeadStyle: { size: getWellHeadStyleWidth, color: getColor }, - wellNameVisible: true, - pickable: true, - ZIncreasingDownwards: false, - outline: false, - lineWidthScale: 2, - }); - - return wellsLayer; -} - -export function wellTrajectoryToGeojson( - wellTrajectory: WellboreTrajectory_api, - selectedWellboreUuid: string | null -): Record { - const point: Record = { - type: "Point", - coordinates: [wellTrajectory.eastingArr[0], wellTrajectory.northingArr[0], -wellTrajectory.tvdMslArr[0]], - }; - const coordinates: Record = { - type: "LineString", - coordinates: zipCoords(wellTrajectory.eastingArr, wellTrajectory.northingArr, wellTrajectory.tvdMslArr), - }; - - let color = [100, 100, 100]; - let lineWidth = 2; - let wellHeadSize = 1; - if (wellTrajectory.wellboreUuid === selectedWellboreUuid) { - color = [255, 0, 0]; - lineWidth = 5; - wellHeadSize = 10; - } - - const geometryCollection: Record = { - type: "Feature", - geometry: { - type: "GeometryCollection", - geometries: [point, coordinates], - }, - properties: { - uuid: wellTrajectory.wellboreUuid, - name: wellTrajectory.uniqueWellboreIdentifier, - uwi: wellTrajectory.uniqueWellboreIdentifier, - color, - md: [wellTrajectory.mdArr], - lineWidth, - wellHeadSize, - }, - }; - - return geometryCollection; -} - -function zipCoords(x_arr: number[], y_arr: number[], z_arr: number[]): number[][] { - const coords: number[][] = []; - for (let i = 0; i < x_arr.length; i++) { - coords.push([x_arr[i], y_arr[i], -z_arr[i]]); - } - - return coords; -} -type WorkingGrid3dLayer = { - pointsData: Float32Array; - polysData: Uint32Array; - propertiesData: Float32Array; - colorMapName: string; - ZIncreasingDownwards: boolean; -} & Layer; - -export function makeGrid3DLayer( - id: string, - gridSurfaceData: GridSurface_trans, - gridParameterData: GridMappedProperty_trans, - showGridLines: boolean, - colorScale?: ColorScaleWithName - // colorScale: ColorScale -): WorkingGrid3dLayer { - const offsetXyz = [gridSurfaceData.origin_utm_x, gridSurfaceData.origin_utm_y, 0]; - const pointsNumberArray = gridSurfaceData.pointsFloat32Arr.map((val, i) => val + offsetXyz[i % 3]); - const polysNumberArray = gridSurfaceData.polysUint32Arr; - const grid3dLayer = new Grid3DLayer({ - id: id, - pointsData: pointsNumberArray, - polysData: polysNumberArray, - propertiesData: gridParameterData.polyPropsFloat32Arr, - ZIncreasingDownwards: false, - gridLines: showGridLines, - material: { ambient: 0.4, diffuse: 0.7, shininess: 8, specularColor: [25, 25, 25] }, - pickable: true, - colorMapName: "Physics", - colorMapClampColor: true, - colorMapRange: [gridParameterData.min_grid_prop_value, gridParameterData.max_grid_prop_value], - colorMapFunction: makeColorMapFunction( - colorScale, - gridParameterData.min_grid_prop_value, - gridParameterData.max_grid_prop_value - ), - }); - return grid3dLayer as unknown as WorkingGrid3dLayer; -} - -function makeColorMapFunction( - colorScale: ColorScaleWithName | undefined, - valueMin: number, - valueMax: number -): ((value: number) => [number, number, number]) | undefined { - if (!colorScale) { - return undefined; - } - - return (value: number) => { - const nonNormalizedValue = value * (valueMax - valueMin) + valueMin; - const interpolatedColor = colorScale.getColorForValue(nonNormalizedValue); - const color = parse(interpolatedColor) as Rgb; - if (color === undefined) { - return [0, 0, 0]; - } - return [color.r * 255, color.g * 255, color.b * 255]; - }; -} diff --git a/frontend/src/modules/2DViewer/view/utils/makeViewsAndLayers.ts b/frontend/src/modules/2DViewer/view/utils/makeViewsAndLayers.ts deleted file mode 100644 index d0e69341e..000000000 --- a/frontend/src/modules/2DViewer/view/utils/makeViewsAndLayers.ts +++ /dev/null @@ -1,179 +0,0 @@ -import { Layer as DeckGlLayer } from "@deck.gl/core"; -import { StatusMessage } from "@framework/ModuleInstanceStatusController"; -import { defaultContinuousSequentialColorPalettes } from "@framework/utils/colorPalettes"; -import { ColorScaleGradientType, ColorScaleType } from "@lib/utils/ColorScale"; -import { ColorScale } from "@modules/2DViewer/layers/ColorScale"; -import { DeltaSurface } from "@modules/2DViewer/layers/DeltaSurface"; -import { View } from "@modules/2DViewer/layers/View"; -import { LayerStatus } from "@modules/2DViewer/layers/delegates/LayerDelegate"; -import { BoundingBox, Group, Layer, instanceofGroup, instanceofLayer } from "@modules/2DViewer/layers/interfaces"; -import { ColorScaleWithId } from "@modules/_shared/components/ColorLegendsContainer/colorLegendsContainer"; -import { ColorScaleWithName } from "@modules/_shared/utils/ColorScaleWithName"; - -import { makeLayer } from "./layerFactory"; - -export type DeckGlLayerWithPosition = { - layer: DeckGlLayer; - position: number; -}; - -export type DeckGlView = { - id: string; - color: string | null; - name: string; - layers: DeckGlLayerWithPosition[]; - colorScales: ColorScaleWithId[]; -}; - -export type DeckGlViewsAndLayers = { - views: DeckGlView[]; - layers: DeckGlLayerWithPosition[]; - errorMessages: (StatusMessage | string)[]; - boundingBox: BoundingBox | null; - colorScales: ColorScaleWithId[]; - numLoadingLayers: number; -}; - -export function recursivelyMakeViewsAndLayers(group: Group, numCollectedLayers: number = 0): DeckGlViewsAndLayers { - const collectedViews: DeckGlView[] = []; - const collectedLayers: DeckGlLayerWithPosition[] = []; - const collectedColorScales: ColorScaleWithId[] = []; - const collectedErrorMessages: (StatusMessage | string)[] = []; - let collectedNumLoadingLayers = 0; - let globalBoundingBox: BoundingBox | null = null; - - const children = group.getGroupDelegate().getChildren(); - - const maybeApplyBoundingBox = (boundingBox: BoundingBox | null) => { - if (boundingBox) { - globalBoundingBox = - globalBoundingBox === null ? boundingBox : makeNewBoundingBox(boundingBox, globalBoundingBox); - } - }; - - for (const child of children) { - if (!child.getItemDelegate().isVisible()) { - continue; - } - - if (instanceofGroup(child) && !(child instanceof DeltaSurface)) { - const { views, layers, boundingBox, colorScales, numLoadingLayers, errorMessages } = - recursivelyMakeViewsAndLayers(child, numCollectedLayers + collectedLayers.length); - - collectedErrorMessages.push(...errorMessages); - collectedNumLoadingLayers += numLoadingLayers; - maybeApplyBoundingBox(boundingBox); - - if (child instanceof View) { - const view: DeckGlView = { - id: child.getItemDelegate().getId(), - color: child.getGroupDelegate().getColor(), - name: child.getItemDelegate().getName(), - layers: layers, - colorScales, - }; - - collectedViews.push(view); - continue; - } - - collectedLayers.push(...layers); - collectedViews.push(...views); - } - - if (instanceofLayer(child)) { - if (child.getLayerDelegate().getStatus() === LayerStatus.LOADING) { - collectedNumLoadingLayers++; - } - - if (child.getLayerDelegate().getStatus() !== LayerStatus.SUCCESS) { - if (child.getLayerDelegate().getStatus() === LayerStatus.ERROR) { - const error = child.getLayerDelegate().getError(); - if (error) { - collectedErrorMessages.push(error); - } - } - continue; - } - - const colorScale = findColorScale(child); - - const layer = makeLayer(child, colorScale?.colorScale ?? undefined); - - if (!layer) { - continue; - } - - if (colorScale) { - collectedColorScales.push(colorScale); - } - - const boundingBox = child.getLayerDelegate().getBoundingBox(); - maybeApplyBoundingBox(boundingBox); - collectedLayers.push({ layer, position: numCollectedLayers + collectedLayers.length }); - } - } - - return { - views: collectedViews, - layers: collectedLayers, - errorMessages: collectedErrorMessages, - boundingBox: globalBoundingBox, - colorScales: collectedColorScales, - numLoadingLayers: collectedNumLoadingLayers, - }; -} - -function findColorScale(layer: Layer): { id: string; colorScale: ColorScaleWithName } | null { - if (layer.getLayerDelegate().getColoringType() !== "COLORSCALE") { - return null; - } - - let colorScaleWithName = new ColorScaleWithName({ - colorPalette: defaultContinuousSequentialColorPalettes[0], - gradientType: ColorScaleGradientType.Sequential, - name: layer.getItemDelegate().getName(), - type: ColorScaleType.Continuous, - steps: 10, - }); - - const range = layer.getLayerDelegate().getValueRange(); - if (range) { - colorScaleWithName.setRangeAndMidPoint(range[0], range[1], (range[0] + range[1]) / 2); - } - - const colorScaleItemArr = layer - .getItemDelegate() - .getParentGroup() - ?.getAncestorAndSiblingItems((item) => item instanceof ColorScale); - - if (colorScaleItemArr && colorScaleItemArr.length > 0) { - const colorScaleItem = colorScaleItemArr[0]; - if (colorScaleItem instanceof ColorScale) { - colorScaleWithName = ColorScaleWithName.fromColorScale( - colorScaleItem.getColorScale(), - layer.getItemDelegate().getName() - ); - - if (!colorScaleItem.getAreBoundariesUserDefined()) { - const range = layer.getLayerDelegate().getValueRange(); - if (range) { - colorScaleWithName.setRangeAndMidPoint(range[0], range[1], (range[0] + range[1]) / 2); - } - } - } - } - - return { - id: layer.getItemDelegate().getId(), - colorScale: colorScaleWithName, - }; -} - -function makeNewBoundingBox(newBoundingBox: BoundingBox, oldBoundingBox: BoundingBox): BoundingBox { - return { - x: [Math.min(newBoundingBox.x[0], oldBoundingBox.x[0]), Math.max(newBoundingBox.x[1], oldBoundingBox.x[1])], - y: [Math.min(newBoundingBox.y[0], oldBoundingBox.y[0]), Math.max(newBoundingBox.y[1], oldBoundingBox.y[1])], - z: [Math.min(newBoundingBox.z[0], oldBoundingBox.z[0]), Math.max(newBoundingBox.z[1], oldBoundingBox.z[1])], - }; -} diff --git a/frontend/src/modules/2DViewer/view/view.tsx b/frontend/src/modules/2DViewer/view/view.tsx deleted file mode 100644 index bc4022d72..000000000 --- a/frontend/src/modules/2DViewer/view/view.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from "react"; - -import { ModuleViewProps } from "@framework/Module"; - -import { LayersWrapper } from "./components/LayersWrapper"; - -import { Interfaces } from "../interfaces"; - -export function View(props: ModuleViewProps): React.ReactNode { - const preferredViewLayout = props.viewContext.useSettingsToViewInterfaceValue("preferredViewLayout"); - const layerManager = props.viewContext.useSettingsToViewInterfaceValue("layerManager"); - - if (!layerManager) { - return null; - } - - return ( - - ); -} diff --git a/frontend/src/modules/_shared/components/Toolbar/index.ts b/frontend/src/modules/_shared/components/Toolbar/index.ts deleted file mode 100644 index 92e32c985..000000000 --- a/frontend/src/modules/_shared/components/Toolbar/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { Toolbar } from "./toolbar"; -export { ToolBarDivider } from "./toolbarDivider"; -export type { ToolbarProps } from "./toolbar"; diff --git a/frontend/src/modules/_shared/components/Toolbar/toolbar.tsx b/frontend/src/modules/_shared/components/Toolbar/toolbar.tsx deleted file mode 100644 index 3ca04a388..000000000 --- a/frontend/src/modules/_shared/components/Toolbar/toolbar.tsx +++ /dev/null @@ -1,16 +0,0 @@ -export type ToolbarProps = { - hidden?: boolean; - children: React.ReactNode; -}; - -export function Toolbar(props: ToolbarProps): React.ReactNode { - if (props.hidden) { - return null; - } - - return ( -
- {props.children} -
- ); -} diff --git a/frontend/src/modules/_shared/components/Toolbar/toolbarDivider.tsx b/frontend/src/modules/_shared/components/Toolbar/toolbarDivider.tsx deleted file mode 100644 index c3c141c7f..000000000 --- a/frontend/src/modules/_shared/components/Toolbar/toolbarDivider.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export function ToolBarDivider(): React.ReactNode { - return
; -} diff --git a/frontend/src/modules/registerAllModules.ts b/frontend/src/modules/registerAllModules.ts index e4609ba35..f16f380d4 100644 --- a/frontend/src/modules/registerAllModules.ts +++ b/frontend/src/modules/registerAllModules.ts @@ -1,6 +1,5 @@ import { isDevMode } from "@lib/utils/devMode"; -import "./2DViewer/registerModule"; import "./3DViewer/registerModule"; import "./DistributionPlot/registerModule"; import "./FlowNetwork/registerModule"; @@ -15,8 +14,9 @@ import "./SimulationTimeSeries/registerModule"; import "./SimulationTimeSeriesSensitivity/registerModule"; import "./SubsurfaceMap/registerModule"; import "./TornadoChart/registerModule"; -import "./Vfp/registerModule"; import "./WellCompletions/registerModule"; +import "./Vfp/registerModule"; + if (isDevMode()) { await import("./MyModule/registerModule");