From 976a0e234c45e3360f5601b0e6203527985d81e7 Mon Sep 17 00:00:00 2001 From: Ruben Thoms Date: Mon, 9 Sep 2024 13:54:58 +0200 Subject: [PATCH] wip --- .../src/modules/LayerSpike/layers/Broker.ts | 59 +++++++++--- .../{GroupHandler.ts => GroupDelegate.ts} | 54 ++++++++++- .../modules/LayerSpike/layers/LayerBase.ts | 27 ------ .../LayerSpike/layers/LayerDelegate.ts | 53 +++++++++++ .../modules/LayerSpike/layers/LayerManager.ts | 33 +++++++ .../src/modules/LayerSpike/layers/Message.ts | 36 +++++++ .../LayerSpike/layers/SettingsContext.ts | 53 ----------- .../layers/SettingsContextDelegate.ts | 95 +++++++++++++++++++ .../src/modules/LayerSpike/layers/View.ts | 16 +++- .../{Group.tsx => GroupComponent.tsx} | 10 +- .../LayerSpike/layers/components/Layer.tsx | 38 -------- .../layers/components/LayerComponent.tsx | 40 ++++++++ .../{Setting.tsx => SettingComponent.tsx} | 4 +- .../LayerSpike/layers/components/utils.tsx | 37 ++------ .../layers/implementations/Ensemble.tsx | 6 +- .../layers/implementations/SurfaceContext.ts | 21 ---- .../layers/implementations/SurfaceLayer.ts | 9 -- .../SurfaceLayer/SurfaceContext.ts | 30 ++++++ .../SurfaceLayer/SurfaceLayer.ts | 33 +++++++ .../implementations/SurfaceLayer/types.ts | 5 + .../LayerSpike/layers/implementations/View.ts | 14 ++- .../modules/LayerSpike/layers/interfaces.ts | 36 +++++-- .../src/modules/LayerSpike/layers/settings.ts | 1 - frontend/src/modules/LayerSpike/settings.tsx | 36 ++++--- 24 files changed, 508 insertions(+), 238 deletions(-) rename frontend/src/modules/LayerSpike/layers/{GroupHandler.ts => GroupDelegate.ts} (61%) delete mode 100644 frontend/src/modules/LayerSpike/layers/LayerBase.ts create mode 100644 frontend/src/modules/LayerSpike/layers/LayerDelegate.ts create mode 100644 frontend/src/modules/LayerSpike/layers/LayerManager.ts create mode 100644 frontend/src/modules/LayerSpike/layers/Message.ts delete mode 100644 frontend/src/modules/LayerSpike/layers/SettingsContext.ts create mode 100644 frontend/src/modules/LayerSpike/layers/SettingsContextDelegate.ts rename frontend/src/modules/LayerSpike/layers/components/{Group.tsx => GroupComponent.tsx} (60%) delete mode 100644 frontend/src/modules/LayerSpike/layers/components/Layer.tsx create mode 100644 frontend/src/modules/LayerSpike/layers/components/LayerComponent.tsx rename frontend/src/modules/LayerSpike/layers/components/{Setting.tsx => SettingComponent.tsx} (100%) delete mode 100644 frontend/src/modules/LayerSpike/layers/implementations/SurfaceContext.ts delete mode 100644 frontend/src/modules/LayerSpike/layers/implementations/SurfaceLayer.ts create mode 100644 frontend/src/modules/LayerSpike/layers/implementations/SurfaceLayer/SurfaceContext.ts create mode 100644 frontend/src/modules/LayerSpike/layers/implementations/SurfaceLayer/SurfaceLayer.ts create mode 100644 frontend/src/modules/LayerSpike/layers/implementations/SurfaceLayer/types.ts delete mode 100644 frontend/src/modules/LayerSpike/layers/settings.ts diff --git a/frontend/src/modules/LayerSpike/layers/Broker.ts b/frontend/src/modules/LayerSpike/layers/Broker.ts index 091eb8808..de77b79cb 100644 --- a/frontend/src/modules/LayerSpike/layers/Broker.ts +++ b/frontend/src/modules/LayerSpike/layers/Broker.ts @@ -1,20 +1,57 @@ -import { WorkbenchServices } from "@framework/WorkbenchServices"; -import { WorkbenchSession } from "@framework/WorkbenchSession"; +import { Message, MessageDirection } from "./Message"; export class Broker { - private _workbenchServices: WorkbenchServices; - private _workbenchSession: WorkbenchSession; + private _parentBroker: Broker | null = null; + private _childrenBrokers: Broker[] = []; + private _messageCallback: ((message: Message) => void) | null = null; - constructor(workbenchServices: WorkbenchServices, workbenchSession: WorkbenchSession) { - this._workbenchServices = workbenchServices; - this._workbenchSession = workbenchSession; + constructor(parent: Broker | null) { + this._parentBroker = parent; } - getWorkbenchServices(): WorkbenchServices { - return this._workbenchServices; + setParent(parent: Broker | null) { + this._parentBroker = parent; } - getWorkbenchSession(): WorkbenchSession { - return this._workbenchSession; + setChildren(children: Broker[]) { + this._childrenBrokers = children; + } + + addChild(child: Broker) { + this._childrenBrokers.push(child); + } + + removeChild(child: Broker) { + this._childrenBrokers = this._childrenBrokers.filter((broker) => broker !== child); + } + + emit(message: Message) { + this.callCallback(message); + + if (message.isPropagationStopped()) { + return; + } + + if (message.getDirection() === MessageDirection.UP && this._parentBroker) { + this._parentBroker.emit(message); + return; + } + + if (message.getDirection() === MessageDirection.DOWN) { + for (const child of this._childrenBrokers) { + child.emit(message); + } + } + } + + onMessage(callback: (message: Message) => void) { + this._messageCallback = callback; + } + + callCallback(message: Message): void { + const callback = this._messageCallback; + if (callback) { + callback(message); + } } } diff --git a/frontend/src/modules/LayerSpike/layers/GroupHandler.ts b/frontend/src/modules/LayerSpike/layers/GroupDelegate.ts similarity index 61% rename from frontend/src/modules/LayerSpike/layers/GroupHandler.ts rename to frontend/src/modules/LayerSpike/layers/GroupDelegate.ts index 8ffea28df..d17f22210 100644 --- a/frontend/src/modules/LayerSpike/layers/GroupHandler.ts +++ b/frontend/src/modules/LayerSpike/layers/GroupDelegate.ts @@ -2,8 +2,11 @@ import React from "react"; import { v4 } from "uuid"; +import { Broker } from "./Broker"; +import { LayerManager } from "./LayerManager"; +import { Message, MessageDirection, MessageType } from "./Message"; import { PublishSubscribe, PublishSubscribeHandler } from "./PublishSubscribeHandler"; -import { Item, instanceofGroup } from "./interfaces"; +import { Item, instanceofGroup, instanceofLayer } from "./interfaces"; export enum GroupBaseTopic { CHILDREN_CHANGED = "CHILDREN_CHANGED", @@ -13,35 +16,76 @@ export type GroupBaseTopicPayloads = { [GroupBaseTopic.CHILDREN_CHANGED]: Item[]; }; -export class GroupHandler implements Item, PublishSubscribe { +export class GroupDelegate implements Item, PublishSubscribe { private _children: Item[] = []; private _id: string; + private _manager: LayerManager; + private _broker: Broker; private _publishSubscribeHandler = new PublishSubscribeHandler(); - constructor() { + constructor(manager: LayerManager) { this._id = v4(); + this._broker = new Broker(null); + this._manager = manager; + + this._broker.onMessage(this.handleAvailableSettingsChanged.bind(this)); + } + + private handleAvailableSettingsChanged(message: Message) { + if (message.getType() === MessageType.AVAILABLE_SETTINGS_CHANGED) { + if (message.getDirection() === MessageDirection.DOWN) { + message.stopPropagation(); + return; + } + + this._broker.emit(new Message(MessageType.AVAILABLE_SETTINGS_CHANGED, MessageDirection.DOWN)); + } } getId() { return this._id; } + getBroker() { + return this._broker; + } + + private setBrokerAndManagerOfChild(child: Item) { + child.getBroker().setParent(this._broker); + this._broker.addChild(child.getBroker()); + if (instanceofLayer(child)) { + child.getLayerDelegate().setLayerManager(this._manager); + } + } + + private removeBrokerAndManagerOfChild(child: Item) { + child.getBroker().setParent(null); + this._broker.removeChild(child.getBroker()); + if (instanceofLayer(child)) { + child.getLayerDelegate().setLayerManager(null); + } + } + prependChild(child: Item) { + this.setBrokerAndManagerOfChild(child); this._children = [child, ...this._children]; this._publishSubscribeHandler.notifySubscribers(GroupBaseTopic.CHILDREN_CHANGED); } appendChild(child: Item) { + this.setBrokerAndManagerOfChild(child); this._children = [...this._children, child]; this._publishSubscribeHandler.notifySubscribers(GroupBaseTopic.CHILDREN_CHANGED); } insertChild(child: Item, index: number) { + this.setBrokerAndManagerOfChild(child); this._children = [...this._children.slice(0, index), child, ...this._children.slice(index)]; this._publishSubscribeHandler.notifySubscribers(GroupBaseTopic.CHILDREN_CHANGED); } removeChild(child: Item) { + this.removeBrokerAndManagerOfChild(child); this._children = this._children.filter((c) => c !== child); this._publishSubscribeHandler.notifySubscribers(GroupBaseTopic.CHILDREN_CHANGED); } @@ -69,7 +113,7 @@ export class GroupHandler implements Item, PublishSubscribe( - layerGroup: GroupHandler, + layerGroup: GroupDelegate, topic: T ): GroupBaseTopicPayloads[T] { const value = React.useSyncExternalStore( diff --git a/frontend/src/modules/LayerSpike/layers/LayerBase.ts b/frontend/src/modules/LayerSpike/layers/LayerBase.ts deleted file mode 100644 index 1304c927f..000000000 --- a/frontend/src/modules/LayerSpike/layers/LayerBase.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { v4 } from "uuid"; - -import { Item, SettingsContext } from "./interfaces"; - -export class LayerBase implements Item { - private _name: string; - private _id: string; - private _settingsContext: SettingsContext; - - constructor(name: string, settingsContext: SettingsContext) { - this._id = v4(); - this._name = name; - this._settingsContext = settingsContext; - } - - getId(): string { - return this._id; - } - - getName(): string { - return this._name; - } - - getSettingsContext(): SettingsContext { - return this._settingsContext; - } -} diff --git a/frontend/src/modules/LayerSpike/layers/LayerDelegate.ts b/frontend/src/modules/LayerSpike/layers/LayerDelegate.ts new file mode 100644 index 000000000..3b5030aa4 --- /dev/null +++ b/frontend/src/modules/LayerSpike/layers/LayerDelegate.ts @@ -0,0 +1,53 @@ +import { v4 } from "uuid"; + +import { Broker } from "./Broker"; +import { LayerManager } from "./LayerManager"; +import { Message, MessageDirection, MessageType } from "./Message"; +import { SettingsContextDelegateTopic } from "./SettingsContextDelegate"; +import { Item, Settings, SettingsContext } from "./interfaces"; + +export class LayerDelegate implements Item { + private _name: string; + private _id: string; + private _broker: Broker = new Broker(null); + private _settingsContext: SettingsContext; + private _layerManager: LayerManager | null = null; + + constructor(name: string, settingsContext: SettingsContext) { + this._id = v4(); + this._name = name; + this._settingsContext = settingsContext; + this._settingsContext.getDelegate().makeSubscriberFunction(SettingsContextDelegateTopic.SETTINGS_CHANGED)( + () => { + this._broker.emit(new Message(MessageType.SETTINGS_CHANGED, MessageDirection.UP)); + } + ); + } + + getBroker(): Broker { + return this._broker; + } + + getId(): string { + return this._id; + } + + getName(): string { + return this._name; + } + + getSettingsContext(): SettingsContext { + return this._settingsContext; + } + + setLayerManager(layerManager: LayerManager | null): void { + this._layerManager = layerManager; + } + + getLayerManager(): LayerManager { + if (this._layerManager === null) { + throw new Error("LayerManager not set"); + } + return this._layerManager; + } +} diff --git a/frontend/src/modules/LayerSpike/layers/LayerManager.ts b/frontend/src/modules/LayerSpike/layers/LayerManager.ts new file mode 100644 index 000000000..8883065d5 --- /dev/null +++ b/frontend/src/modules/LayerSpike/layers/LayerManager.ts @@ -0,0 +1,33 @@ +import { WorkbenchSession } from "@framework/WorkbenchSession"; +import { WorkbenchSettings } from "@framework/WorkbenchSettings"; + +import { GroupDelegate } from "./GroupDelegate"; +import { View } from "./View"; + +export class LayerManager { + private _workbenchSession: WorkbenchSession; + private _workbenchSettings: WorkbenchSettings; + private _groupDelegate: GroupDelegate; + + constructor(workbenchSession: WorkbenchSession, workbenchSettings: WorkbenchSettings) { + this._workbenchSession = workbenchSession; + this._workbenchSettings = workbenchSettings; + this._groupDelegate = new GroupDelegate(this); + } + + getWorkbenchSession(): WorkbenchSession { + return this._workbenchSession; + } + + getWorkbenchSettings(): WorkbenchSettings { + return this._workbenchSettings; + } + + getGroupDelegate(): GroupDelegate { + return this._groupDelegate; + } + + makeView(name: string): View { + return new View(this, name); + } +} diff --git a/frontend/src/modules/LayerSpike/layers/Message.ts b/frontend/src/modules/LayerSpike/layers/Message.ts new file mode 100644 index 000000000..92c262a2d --- /dev/null +++ b/frontend/src/modules/LayerSpike/layers/Message.ts @@ -0,0 +1,36 @@ +export enum MessageDirection { + UP = "UP", + DOWN = "DOWN", +} + +export enum MessageType { + SETTINGS_CHANGED = "SETTINGS_CHANGED", + AVAILABLE_SETTINGS_CHANGED = "AVAILABLE_SETTINGS_CHANGED", +} + +export class Message { + private _direction: MessageDirection; + private _type: MessageType; + private _propagationStopped: boolean = false; + + constructor(type: MessageType, direction: MessageDirection) { + this._type = type; + this._direction = direction; + } + + getType() { + return this._type; + } + + getDirection() { + return this._direction; + } + + stopPropagation() { + this._propagationStopped = true; + } + + isPropagationStopped() { + return this._propagationStopped; + } +} diff --git a/frontend/src/modules/LayerSpike/layers/SettingsContext.ts b/frontend/src/modules/LayerSpike/layers/SettingsContext.ts deleted file mode 100644 index 8cfa3834a..000000000 --- a/frontend/src/modules/LayerSpike/layers/SettingsContext.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { PublishSubscribe, PublishSubscribeHandler } from "./PublishSubscribeHandler"; -import { Setting, SettingTopic } from "./interfaces"; - -export enum SettingsContextTopic { - AVAILABE_SETTINGS_CHANGED = "AVAILABE_SETTINGS_CHANGED", -} - -export type SettingsContextTopicPayloads = { - [SettingsContextTopic.AVAILABE_SETTINGS_CHANGED]: Setting[]; -}; - -export class SettingsContextHelper implements PublishSubscribe { - private _settings: Setting[]; - private _publishSubscribeHandler = new PublishSubscribeHandler(); - private _checkIfRefetchRequired: () => boolean; - private _fetchAvailableSettings: () => any[][]; - - constructor(checkIfRefetchRequired: () => boolean, fetchAvailableSettings: () => any[][]) { - this._settings = []; - } - - addSetting(setting: Setting) { - this._settings.push(setting); - setting.makeSubscriberFunction(SettingTopic.VALUE_CHANGED)(() => { - this.maybeRefetchAvailableSettings(); - }); - } - - getSettings() { - return this._settings; - } - - private maybeRefetchAvailableSettings() { - if (this._checkIfRefetchRequired()) { - const newSettings = this._fetchAvailableSettings(); - this._publishSubscribeHandler.notifySubscribers(SettingsContextTopic.AVAILABE_SETTINGS_CHANGED); - } - } - - makeSnapshotGetter(topic: T): () => SettingsContextTopicPayloads[T] { - const snapshotGetter = (): any => { - if (topic === SettingsContextTopic.AVAILABE_SETTINGS_CHANGED) { - return this._settings; - } - }; - - return snapshotGetter; - } - - makeSubscriberFunction(topic: SettingsContextTopic): (onStoreChangeCallback: () => void) => () => void { - return this._publishSubscribeHandler.makeSubscriberFunction(topic); - } -} diff --git a/frontend/src/modules/LayerSpike/layers/SettingsContextDelegate.ts b/frontend/src/modules/LayerSpike/layers/SettingsContextDelegate.ts new file mode 100644 index 000000000..bd56714f7 --- /dev/null +++ b/frontend/src/modules/LayerSpike/layers/SettingsContextDelegate.ts @@ -0,0 +1,95 @@ +import { isEqual } from "lodash"; + +import { PublishSubscribe, PublishSubscribeHandler } from "./PublishSubscribeHandler"; +import { Setting, SettingTopic, Settings } from "./interfaces"; + +export enum SettingsContextDelegateTopic { + SETTINGS_CHANGED = "SETTINGS_CHANGED", + REFETCH_REQUIRED = "REFETCH_REQUIRED", + AVAILABLE_SETTINGS_CHANGED = "AVAILABLE_SETTINGS_CHANGED", +} + +export type SettingsContextDelegatePayloads = { + [SettingsContextDelegateTopic.SETTINGS_CHANGED]: void; + [SettingsContextDelegateTopic.AVAILABLE_SETTINGS_CHANGED]: void; + [SettingsContextDelegateTopic.REFETCH_REQUIRED]: void; +}; + +export interface MaybeFetchDatFunction { + ( + oldValues: Record, + newValues: Record + ): boolean; +} + +export interface FetchDataFunction { + (values: Record): void; +} + +export class SettingsContextDelegate + implements PublishSubscribe +{ + private _settings: Record>; + private _cachedValues: Record = {} as Record< + keyof TSettings, + TSettings[keyof TSettings] + >; + private _values: Record = {} as Record< + keyof TSettings, + TSettings[keyof TSettings] + >; + private _availableSettingsValues: Partial> = {}; + private _publishSubscribeHandler = new PublishSubscribeHandler(); + private _refetchRequired: MaybeFetchDatFunction; + + constructor( + settings: Record>, + refetchRequiredFunc: MaybeFetchDatFunction + ) { + for (const key in settings) { + this._values[key] = settings[key].getValue(); + settings[key].makeSubscriberFunction(SettingTopic.VALUE_CHANGED)(() => { + this._values[key] = settings[key].getValue(); + this.handleSettingsChanged(); + }); + } + + this._settings = settings; + this._cachedValues = { ...this._values }; + this._refetchRequired = refetchRequiredFunc; + } + + private handleSettingsChanged() { + if (!isEqual(this._cachedValues, this._values)) { + if (this._refetchRequired(this._cachedValues, this._values)) { + this._publishSubscribeHandler.notifySubscribers(SettingsContextDelegateTopic.REFETCH_REQUIRED); + } + this._cachedValues = { ...this._values }; + this._publishSubscribeHandler.notifySubscribers(SettingsContextDelegateTopic.SETTINGS_CHANGED); + } + } + + getSettings() { + return this._settings; + } + + makeSnapshotGetter(topic: T): () => SettingsContextDelegatePayloads[T] { + const snapshotGetter = (): any => { + if (topic === SettingsContextDelegateTopic.SETTINGS_CHANGED) { + return; + } + if (topic === SettingsContextDelegateTopic.REFETCH_REQUIRED) { + return; + } + if (topic === SettingsContextDelegateTopic.AVAILABLE_SETTINGS_CHANGED) { + return; + } + }; + + return snapshotGetter; + } + + makeSubscriberFunction(topic: SettingsContextDelegateTopic): (onStoreChangeCallback: () => void) => () => void { + return this._publishSubscribeHandler.makeSubscriberFunction(topic); + } +} diff --git a/frontend/src/modules/LayerSpike/layers/View.ts b/frontend/src/modules/LayerSpike/layers/View.ts index 0356f04c7..fc4d2a3e6 100644 --- a/frontend/src/modules/LayerSpike/layers/View.ts +++ b/frontend/src/modules/LayerSpike/layers/View.ts @@ -1,15 +1,23 @@ import { v4 } from "uuid"; -import { Group, GroupHandler } from "./GroupHandler"; +import { Broker } from "./Broker"; +import { GroupDelegate } from "./GroupDelegate"; +import { LayerManager } from "./LayerManager"; +import { Group } from "./interfaces"; export class View implements Group { - private _groupHandler: GroupHandler = new GroupHandler(); + private _groupHandler: GroupDelegate; private _name: string; private _id: string; - constructor(name: string) { + constructor(layerManager: LayerManager, name: string) { this._id = v4(); this._name = name; + this._groupHandler = new GroupDelegate(layerManager); + } + + getBroker(): Broker { + return this._groupHandler.getBroker(); } getId() { @@ -20,7 +28,7 @@ export class View implements Group { return this._name; } - getGroupHandler(): GroupHandler { + getGroupDelegate(): GroupDelegate { return this._groupHandler; } diff --git a/frontend/src/modules/LayerSpike/layers/components/Group.tsx b/frontend/src/modules/LayerSpike/layers/components/GroupComponent.tsx similarity index 60% rename from frontend/src/modules/LayerSpike/layers/components/Group.tsx rename to frontend/src/modules/LayerSpike/layers/components/GroupComponent.tsx index 113a1d874..db363f726 100644 --- a/frontend/src/modules/LayerSpike/layers/components/Group.tsx +++ b/frontend/src/modules/LayerSpike/layers/components/GroupComponent.tsx @@ -1,24 +1,20 @@ -import { WorkbenchSession } from "@framework/WorkbenchSession"; -import { WorkbenchSettings } from "@framework/WorkbenchSettings"; import { SortableListGroup } from "@lib/components/SortableList"; import { makeComponent } from "./utils"; -import { GroupBaseTopic, useGroupBaseTopicValue } from "../GroupHandler"; +import { GroupBaseTopic, useGroupBaseTopicValue } from "../GroupDelegate"; import { Group } from "../interfaces"; export type LayerComponentProps = { group: Group; - workbenchSettings: WorkbenchSettings; - workbenchSession: WorkbenchSession; }; export function GroupComponent(props: LayerComponentProps): React.ReactNode { - const children = useGroupBaseTopicValue(props.group.getGroupHandler(), GroupBaseTopic.CHILDREN_CHANGED); + const children = useGroupBaseTopicValue(props.group.getGroupDelegate(), GroupBaseTopic.CHILDREN_CHANGED); return ( - {children.map((child) => makeComponent(child, props.workbenchSettings, props.workbenchSession))} + {children.map((child) => makeComponent(child))} ); } diff --git a/frontend/src/modules/LayerSpike/layers/components/Layer.tsx b/frontend/src/modules/LayerSpike/layers/components/Layer.tsx deleted file mode 100644 index d9ddb2366..000000000 --- a/frontend/src/modules/LayerSpike/layers/components/Layer.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { WorkbenchSession } from "@framework/WorkbenchSession"; -import { WorkbenchSettings } from "@framework/WorkbenchSettings"; -import { SortableListItem } from "@lib/components/SortableList"; - -import { SettingComponent } from "./Setting"; - -import { LayerBase } from "../LayerBase"; -import { Setting } from "../interfaces"; - -export type LayerComponentProps = { - layer: LayerBase; - onRemove: (id: string) => void; - workbenchSettings: WorkbenchSettings; - workbenchSession: WorkbenchSession; -}; - -export function Layer(props: LayerComponentProps): React.ReactNode { - function makeSetting(setting: Setting) { - return ( - - ); - } - return ( - -
- {props.layer - .getSettingsContext() - .getSettings() - .map((setting) => makeSetting(setting))} -
-
- ); -} diff --git a/frontend/src/modules/LayerSpike/layers/components/LayerComponent.tsx b/frontend/src/modules/LayerSpike/layers/components/LayerComponent.tsx new file mode 100644 index 000000000..da44a626e --- /dev/null +++ b/frontend/src/modules/LayerSpike/layers/components/LayerComponent.tsx @@ -0,0 +1,40 @@ +import React from "react"; + +import { SortableListItem } from "@lib/components/SortableList"; + +import { SettingComponent } from "./SettingComponent"; + +import { Layer, Setting } from "../interfaces"; + +export type LayerComponentProps = { + layer: Layer; + onRemove: (id: string) => void; +}; + +export function LayerComponent(props: LayerComponentProps): React.ReactNode { + function makeSetting(setting: Setting) { + const manager = props.layer.getLayerDelegate().getLayerManager(); + 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 ( + +
{makeSettings(props.layer.getSettingsContext().getSettings())}
+
+ ); +} diff --git a/frontend/src/modules/LayerSpike/layers/components/Setting.tsx b/frontend/src/modules/LayerSpike/layers/components/SettingComponent.tsx similarity index 100% rename from frontend/src/modules/LayerSpike/layers/components/Setting.tsx rename to frontend/src/modules/LayerSpike/layers/components/SettingComponent.tsx index 3bb54127c..9609d94ab 100644 --- a/frontend/src/modules/LayerSpike/layers/components/Setting.tsx +++ b/frontend/src/modules/LayerSpike/layers/components/SettingComponent.tsx @@ -6,8 +6,8 @@ import { Setting, SettingTopic } from "../interfaces"; export type SettingComponentProps = { setting: Setting; - workbenchSettings: WorkbenchSettings; workbenchSession: WorkbenchSession; + workbenchSettings: WorkbenchSettings; }; export function SettingComponent(props: SettingComponentProps): React.ReactNode { @@ -26,8 +26,8 @@ export function SettingComponent(props: SettingComponentProps): onValueChange={handleValueChanged} value={value} availableValues={props.setting.getAvailableValues()} - workbenchSettings={props.workbenchSettings} workbenchSession={props.workbenchSession} + workbenchSettings={props.workbenchSettings} /> diff --git a/frontend/src/modules/LayerSpike/layers/components/utils.tsx b/frontend/src/modules/LayerSpike/layers/components/utils.tsx index f73507007..76fa3630c 100644 --- a/frontend/src/modules/LayerSpike/layers/components/utils.tsx +++ b/frontend/src/modules/LayerSpike/layers/components/utils.tsx @@ -1,39 +1,16 @@ -import { WorkbenchSession } from "@framework/WorkbenchSession"; -import { WorkbenchSettings } from "@framework/WorkbenchSettings"; import { SortableListItemProps } from "@lib/components/SortableList"; -import { GroupComponent } from "./Group"; -import { Layer } from "./Layer"; +import { GroupComponent } from "./GroupComponent"; +import { LayerComponent } from "./LayerComponent"; -import { GroupHandler } from "../GroupHandler"; -import { LayerBase } from "../LayerBase"; -import { Item, instanceofGroup } from "../interfaces"; +import { Item, instanceofGroup, instanceofLayer } from "../interfaces"; -export function makeComponent( - item: Item, - workbenchSettings: WorkbenchSettings, - workbenchSession: WorkbenchSession -): React.ReactElement { - if (item instanceof LayerBase) { - return ( - {}} - workbenchSession={workbenchSession} - workbenchSettings={workbenchSettings} - /> - ); +export function makeComponent(item: Item): React.ReactElement { + if (instanceofLayer(item)) { + return {}} />; } if (instanceofGroup(item)) { - return ( - - ); + return ; } throw new Error("Not implemented"); } diff --git a/frontend/src/modules/LayerSpike/layers/implementations/Ensemble.tsx b/frontend/src/modules/LayerSpike/layers/implementations/Ensemble.tsx index d03cf88f6..5605df278 100644 --- a/frontend/src/modules/LayerSpike/layers/implementations/Ensemble.tsx +++ b/frontend/src/modules/LayerSpike/layers/implementations/Ensemble.tsx @@ -5,7 +5,7 @@ import { useEnsembleSet } from "@framework/WorkbenchSession"; import { EnsembleDropdown } from "@framework/components/EnsembleDropdown"; import { PublishSubscribeHandler } from "../PublishSubscribeHandler"; -import { Setting, SettingComponentProps, SettingTopic, SettingTopicPayloads, SettingsContext } from "../interfaces"; +import { Setting, SettingComponentProps, SettingTopic, SettingTopicPayloads } from "../interfaces"; export class Ensemble implements Setting { private _value: EnsembleIdent | null = null; @@ -17,6 +17,10 @@ export class Ensemble implements Setting { return "Ensemble"; } + getValue(): EnsembleIdent | null { + return this._value; + } + setValue(value: EnsembleIdent | null) { this._value = value; this._publishSubscribeHandler.notifySubscribers(SettingTopic.VALUE_CHANGED); diff --git a/frontend/src/modules/LayerSpike/layers/implementations/SurfaceContext.ts b/frontend/src/modules/LayerSpike/layers/implementations/SurfaceContext.ts deleted file mode 100644 index 993d4157b..000000000 --- a/frontend/src/modules/LayerSpike/layers/implementations/SurfaceContext.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Ensemble } from "./Ensemble"; - -import { SettingsContextHelper } from "../SettingsContext"; -import { SettingsContext } from "../interfaces"; - -export class SurfaceContext implements SettingsContext { - private _contextHelper: SettingsContextHelper; - - constructor() { - this._contextHelper = new SettingsContextHelper(this.checkIfRefetchRequired); - this._contextHelper.addSetting(new Ensemble()); - } - - getSettings() { - return this._contextHelper.getSettings(); - } - - private checkIfRefetchRequired(): boolean { - return false; - } -} diff --git a/frontend/src/modules/LayerSpike/layers/implementations/SurfaceLayer.ts b/frontend/src/modules/LayerSpike/layers/implementations/SurfaceLayer.ts deleted file mode 100644 index 8afa12c30..000000000 --- a/frontend/src/modules/LayerSpike/layers/implementations/SurfaceLayer.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { SurfaceContext } from "./SurfaceContext"; - -import { LayerBase } from "../LayerBase"; - -export class SurfaceLayer extends LayerBase { - constructor() { - super("Surface", new SurfaceContext()); - } -} diff --git a/frontend/src/modules/LayerSpike/layers/implementations/SurfaceLayer/SurfaceContext.ts b/frontend/src/modules/LayerSpike/layers/implementations/SurfaceLayer/SurfaceContext.ts new file mode 100644 index 000000000..7037e9ca3 --- /dev/null +++ b/frontend/src/modules/LayerSpike/layers/implementations/SurfaceLayer/SurfaceContext.ts @@ -0,0 +1,30 @@ +import { SurfaceSettings } from "./types"; + +import { SettingsContextDelegate } from "../../SettingsContextDelegate"; +import { SettingsContext } from "../../interfaces"; +import { Ensemble } from "../Ensemble"; + +export class SurfaceContext implements SettingsContext { + private _contextDelegate: SettingsContextDelegate; + + constructor() { + this._contextDelegate = new SettingsContextDelegate( + { + ensemble: new Ensemble(), + }, + this.checkIfRefetchRequired.bind(this) + ); + } + + getDelegate(): SettingsContextDelegate { + return this._contextDelegate; + } + + getSettings() { + return this._contextDelegate.getSettings(); + } + + private checkIfRefetchRequired(): boolean { + return false; + } +} diff --git a/frontend/src/modules/LayerSpike/layers/implementations/SurfaceLayer/SurfaceLayer.ts b/frontend/src/modules/LayerSpike/layers/implementations/SurfaceLayer/SurfaceLayer.ts new file mode 100644 index 000000000..522aaef4c --- /dev/null +++ b/frontend/src/modules/LayerSpike/layers/implementations/SurfaceLayer/SurfaceLayer.ts @@ -0,0 +1,33 @@ +import { SurfaceContext } from "./SurfaceContext"; +import { SurfaceSettings } from "./types"; + +import { LayerDelegate } from "../../LayerDelegate"; +import { Layer } from "../../interfaces"; + +export class SurfaceLayer implements Layer { + private _layerDelegate: LayerDelegate; + + constructor() { + this._layerDelegate = new LayerDelegate("Surface", new SurfaceContext()); + } + + getId() { + return this._layerDelegate.getId(); + } + + getName() { + return this._layerDelegate.getName(); + } + + getBroker() { + return this._layerDelegate.getBroker(); + } + + getSettingsContext() { + return this._layerDelegate.getSettingsContext(); + } + + getLayerDelegate(): LayerDelegate { + return this._layerDelegate; + } +} diff --git a/frontend/src/modules/LayerSpike/layers/implementations/SurfaceLayer/types.ts b/frontend/src/modules/LayerSpike/layers/implementations/SurfaceLayer/types.ts new file mode 100644 index 000000000..779d08b75 --- /dev/null +++ b/frontend/src/modules/LayerSpike/layers/implementations/SurfaceLayer/types.ts @@ -0,0 +1,5 @@ +import { EnsembleIdent } from "@framework/EnsembleIdent"; + +export type SurfaceSettings = { + ensemble: EnsembleIdent | null; +}; diff --git a/frontend/src/modules/LayerSpike/layers/implementations/View.ts b/frontend/src/modules/LayerSpike/layers/implementations/View.ts index c7ca64696..b9f2cddb0 100644 --- a/frontend/src/modules/LayerSpike/layers/implementations/View.ts +++ b/frontend/src/modules/LayerSpike/layers/implementations/View.ts @@ -1,14 +1,16 @@ -import { GroupHandler } from "../GroupHandler"; +import { GroupDelegate } from "../GroupDelegate"; +import { LayerManager } from "../LayerManager"; import { Group } from "../interfaces"; export class View implements Group { private _name: string; private _id: string; - private _groupHandler: GroupHandler = new GroupHandler(); + private _groupHandler: GroupDelegate; - constructor(name: string) { + constructor(layerManager: LayerManager, name: string) { this._id = "view"; this._name = name; + this._groupHandler = new GroupDelegate(layerManager); } getId(): string { @@ -23,7 +25,11 @@ export class View implements Group { this._name = name; } - getGroupHandler(): GroupHandler { + getGroupDelegate(): GroupDelegate { return this._groupHandler; } + + getBroker() { + return this._groupHandler.getBroker(); + } } diff --git a/frontend/src/modules/LayerSpike/layers/interfaces.ts b/frontend/src/modules/LayerSpike/layers/interfaces.ts index b88af3618..8540fb1bf 100644 --- a/frontend/src/modules/LayerSpike/layers/interfaces.ts +++ b/frontend/src/modules/LayerSpike/layers/interfaces.ts @@ -1,11 +1,15 @@ import { WorkbenchSession } from "@framework/WorkbenchSession"; import { WorkbenchSettings } from "@framework/WorkbenchSettings"; -import { GroupHandler } from "./GroupHandler"; +import { Broker } from "./Broker"; +import { GroupDelegate } from "./GroupDelegate"; +import { LayerDelegate } from "./LayerDelegate"; import { PublishSubscribe } from "./PublishSubscribeHandler"; +import { SettingsContextDelegate } from "./SettingsContextDelegate"; export interface Item { getId(): string; + getBroker(): Broker; } export function instanceofItem(item: any): item is Item { @@ -15,32 +19,48 @@ export function instanceofItem(item: any): item is Item { export interface Group extends Item { getName(): string; setName(name: string): void; - getGroupHandler(): GroupHandler; + getGroupDelegate(): GroupDelegate; } export function instanceofGroup(item: Item): item is Group { return ( (item as Group).getName !== undefined && (item as Group).setName !== undefined && - (item as Group).getGroupHandler !== undefined + (item as Group).getGroupDelegate !== undefined ); } -export interface SettingsContext { - getSettings(): Setting[]; +export interface Layer extends Item { + getName(): string; + getSettingsContext(): SettingsContext; + getLayerDelegate(): LayerDelegate; +} + +export function instanceofLayer(item: Item): item is Layer { + return ( + (item as Layer).getSettingsContext !== undefined && + (item as Layer).getLayerDelegate !== undefined && + (item as Layer).getName !== undefined + ); +} + +export interface SettingsContext { + getSettings(): Record>; + getDelegate(): SettingsContextDelegate; } export type SettingComponentProps = { onValueChange: (newValue: TValue) => void; value: TValue; availableValues: TValue[]; - workbenchSettings: WorkbenchSettings; workbenchSession: WorkbenchSession; + workbenchSettings: WorkbenchSettings; }; export interface Setting extends PublishSubscribe> { getLabel(): string; setValue(value: TValue): void; + getValue(): TValue; getAvailableValues(): TValue[]; makeComponent(): (props: SettingComponentProps) => React.ReactNode; } @@ -52,3 +72,7 @@ export enum SettingTopic { export type SettingTopicPayloads = { [SettingTopic.VALUE_CHANGED]: TValue; }; + +export type Settings = { + [key: string]: unknown; +}; diff --git a/frontend/src/modules/LayerSpike/layers/settings.ts b/frontend/src/modules/LayerSpike/layers/settings.ts deleted file mode 100644 index 85f0b72eb..000000000 --- a/frontend/src/modules/LayerSpike/layers/settings.ts +++ /dev/null @@ -1 +0,0 @@ -export enum SettingType {} diff --git a/frontend/src/modules/LayerSpike/settings.tsx b/frontend/src/modules/LayerSpike/settings.tsx index 696de88bb..c04e41b3b 100644 --- a/frontend/src/modules/LayerSpike/settings.tsx +++ b/frontend/src/modules/LayerSpike/settings.tsx @@ -4,23 +4,23 @@ import { ModuleSettingsProps } from "@framework/Module"; import { SortableList } from "@lib/components/SortableList"; import { GroupAdd, Layers } from "@mui/icons-material"; -import { GroupBaseTopic, GroupHandler, useGroupBaseTopicValue } from "./layers/GroupHandler"; -import { View } from "./layers/View"; +import { GroupBaseTopic, useGroupBaseTopicValue } from "./layers/GroupDelegate"; +import { LayerManager } from "./layers/LayerManager"; import { makeComponent } from "./layers/components/utils"; -import { SurfaceLayer } from "./layers/implementations/SurfaceLayer"; +import { SurfaceLayer } from "./layers/implementations/SurfaceLayer/SurfaceLayer"; import { instanceofGroup } from "./layers/interfaces"; export function Settings(props: ModuleSettingsProps): React.ReactNode { - const mainGroup = React.useRef(new GroupHandler()); - - const items = useGroupBaseTopicValue(mainGroup.current, GroupBaseTopic.CHILDREN_CHANGED); + const layerManager = React.useRef(new LayerManager(props.workbenchSession, props.workbenchSettings)); + const groupDelegate = layerManager.current.getGroupDelegate(); + const items = useGroupBaseTopicValue(groupDelegate, GroupBaseTopic.CHILDREN_CHANGED); function handleAddLayer() { - mainGroup.current.appendChild(new SurfaceLayer()); + groupDelegate.appendChild(new SurfaceLayer()); } function handleAddGroup() { - mainGroup.current.appendChild(new View("View")); + groupDelegate.appendChild(layerManager.current.makeView("New Group")); } function handleItemMoved( @@ -29,24 +29,24 @@ export function Settings(props: ModuleSettingsProps): React.ReactNode { destinationId: string | null, position: number ) { - const movedItem = mainGroup.current.findDescendantById(movedItemId); + const movedItem = groupDelegate.findDescendantById(movedItemId); if (!movedItem) { return; } - let origin = mainGroup.current; + let origin = layerManager.current.getGroupDelegate(); if (originId) { - const candidate = mainGroup.current.findDescendantById(originId); + const candidate = groupDelegate.findDescendantById(originId); if (candidate && instanceofGroup(candidate)) { - origin = candidate.getGroupHandler(); + origin = candidate.getGroupDelegate(); } } - let destination = mainGroup.current; + let destination = layerManager.current.getGroupDelegate(); if (destinationId) { - const candidate = mainGroup.current.findDescendantById(destinationId); + const candidate = groupDelegate.findDescendantById(destinationId); if (candidate && instanceofGroup(candidate)) { - destination = candidate.getGroupHandler(); + destination = candidate.getGroupDelegate(); } } @@ -55,8 +55,8 @@ export function Settings(props: ModuleSettingsProps): React.ReactNode { return; } - destination.insertChild(movedItem, position); origin.removeChild(movedItem); + destination.insertChild(movedItem, position); } return ( @@ -71,9 +71,7 @@ export function Settings(props: ModuleSettingsProps): React.ReactNode {
- - {items.map((item) => makeComponent(item, props.workbenchSettings, props.workbenchSession))} - + {items.map((item) => makeComponent(item))}
);