Skip to content

Commit 990c1de

Browse files
committed
Implement module persistence
1 parent b4a0208 commit 990c1de

File tree

11 files changed

+318
-186
lines changed

11 files changed

+318
-186
lines changed

frontend/src/modules/FlowNetwork/interfaces.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,21 @@ import {
66
edgeMetadataListAtom,
77
nodeMetadataListAtom,
88
queryStatusAtom,
9+
} from "./settings/atoms/derivedAtoms";
10+
import {
911
selectedDateTimeAtom,
1012
selectedEdgeKeyAtom,
1113
selectedNodeKeyAtom,
12-
} from "./settings/atoms/derivedAtoms";
14+
} from "./settings/atoms/persistableFixableAtoms";
1315
import type { QueryStatus } from "./types";
1416

1517
type SettingsToViewInterface = {
1618
edgeMetadataList: FlowNetworkMetadata_api[];
1719
nodeMetadataList: FlowNetworkMetadata_api[];
1820
datedNetworks: DatedFlowNetwork_api[];
19-
selectedEdgeKey: string; // | null;
20-
selectedNodeKey: string; // | null;
21-
selectedDateTime: string; // | null;
21+
selectedEdgeKey: string;
22+
selectedNodeKey: string;
23+
selectedDateTime: string;
2224
queryStatus: QueryStatus;
2325
};
2426

@@ -37,13 +39,13 @@ export const settingsToViewInterfaceInitialization: InterfaceInitialization<Sett
3739
return get(datedNetworksAtom);
3840
},
3941
selectedEdgeKey: (get) => {
40-
return get(selectedEdgeKeyAtom) ?? "";
42+
return get(selectedEdgeKeyAtom).value ?? "";
4143
},
4244
selectedNodeKey: (get) => {
43-
return get(selectedNodeKeyAtom) ?? "";
45+
return get(selectedNodeKeyAtom).value ?? "";
4446
},
4547
selectedDateTime: (get) => {
46-
return get(selectedDateTimeAtom) ?? "";
48+
return get(selectedDateTimeAtom).value ?? "";
4749
},
4850
queryStatus: (get) => {
4951
return get(queryStatusAtom);

frontend/src/modules/FlowNetwork/loadModule.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@ import { ModuleRegistry } from "@framework/ModuleRegistry";
22

33
import type { Interfaces } from "./interfaces";
44
import { settingsToViewInterfaceInitialization } from "./interfaces";
5+
import { serializeStateFunctions, type SerializedState } from "./persistence";
56
import { MODULE_NAME } from "./registerModule";
67
import { Settings } from "./settings/settings";
78
import { View } from "./view";
89

9-
const module = ModuleRegistry.initModule<Interfaces>(MODULE_NAME, { settingsToViewInterfaceInitialization });
10+
const module = ModuleRegistry.initModule<Interfaces, SerializedState>(MODULE_NAME, {
11+
settingsToViewInterfaceInitialization,
12+
...serializeStateFunctions,
13+
});
1014

1115
module.viewFC = View;
1216
module.settingsFC = Settings;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import type { ModuleComponentSerializationFunctions, ModuleStateSchema } from "@framework/Module";
2+
3+
import {
4+
deserializeSettings,
5+
SERIALIZED_SETTINGS_SCHEMA,
6+
serializeSettings,
7+
type SerializedSettings,
8+
} from "./settings/persistence";
9+
10+
export type SerializedState = {
11+
settings: SerializedSettings;
12+
};
13+
14+
export const SERIALIZED_STATE_SCHEMA: ModuleStateSchema<SerializedState> = {
15+
settings: SERIALIZED_SETTINGS_SCHEMA,
16+
} as const;
17+
18+
export const serializeStateFunctions: ModuleComponentSerializationFunctions<SerializedState> = {
19+
serializeStateFunctions: {
20+
settings: serializeSettings,
21+
},
22+
deserializeStateFunctions: {
23+
settings: deserializeSettings,
24+
},
25+
};

frontend/src/modules/FlowNetwork/registerModule.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,20 @@ import { ModuleDataTagId } from "@framework/ModuleDataTags";
33
import { ModuleRegistry } from "@framework/ModuleRegistry";
44

55
import type { Interfaces } from "./interfaces";
6+
import { SERIALIZED_STATE_SCHEMA, type SerializedState } from "./persistence";
67
import { preview } from "./preview";
78

89
export const MODULE_NAME = "FlowNetwork";
910

1011
const description = "Visualizes dated flow networks over time.";
1112

12-
ModuleRegistry.registerModule<Interfaces>({
13+
ModuleRegistry.registerModule<Interfaces, SerializedState>({
1314
moduleName: MODULE_NAME,
1415
defaultTitle: "Flow Network",
1516
category: ModuleCategory.MAIN,
1617
devState: ModuleDevState.PROD,
1718
dataTagIds: [ModuleDataTagId.GROUP_TREE, ModuleDataTagId.SUMMARY],
1819
preview,
1920
description,
21+
serializedStateSchema: SERIALIZED_STATE_SCHEMA,
2022
});
Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,9 @@
11
import { atom } from "jotai";
22

33
import { Frequency_api, NodeType_api } from "@api";
4-
import type { RegularEnsembleIdent } from "@framework/RegularEnsembleIdent";
5-
import { atomWithCompare } from "@framework/utils/atomUtils";
6-
import { areEnsembleIdentsEqual } from "@framework/utils/ensembleIdentUtils";
7-
84

95
export const selectedResamplingFrequencyAtom = atom<Frequency_api>(Frequency_api.YEARLY);
106

117
export const selectedNodeTypesAtom = atom<Set<NodeType_api>>(
128
new Set([NodeType_api.INJ, NodeType_api.PROD, NodeType_api.OTHER]),
139
);
14-
15-
export const userSelectedDateTimeAtom = atom<string | null>(null);
16-
17-
export const userSelectedRealizationNumberAtom = atom<number | null>(null);
18-
19-
export const validRealizationNumbersAtom = atom<number[] | null>(null);
20-
21-
export const userSelectedEnsembleIdentAtom = atomWithCompare<RegularEnsembleIdent | null>(null, areEnsembleIdentsEqual);
22-
23-
export const userSelectedEdgeKeyAtom = atom<string | null>(null);
24-
25-
export const userSelectedNodeKeyAtom = atom<string | null>(null);

frontend/src/modules/FlowNetwork/settings/atoms/derivedAtoms.ts

Lines changed: 9 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,25 @@
11
import { atom } from "jotai";
22

33
import type { DatedFlowNetwork_api, FlowNetworkMetadata_api } from "@api";
4-
import { EnsembleSetAtom } from "@framework/GlobalAtoms";
5-
import type { RegularEnsembleIdent } from "@framework/RegularEnsembleIdent";
6-
import { fixupRegularEnsembleIdent } from "@framework/utils/ensembleUiHelpers";
7-
4+
import { ValidEnsembleRealizationsFunctionAtom } from "@framework/GlobalAtoms";
85

96
import { QueryStatus } from "../../types";
107

11-
import {
12-
userSelectedDateTimeAtom,
13-
userSelectedEdgeKeyAtom,
14-
userSelectedEnsembleIdentAtom,
15-
userSelectedNodeKeyAtom,
16-
userSelectedRealizationNumberAtom,
17-
validRealizationNumbersAtom,
18-
} from "./baseAtoms";
8+
import { selectedEnsembleIdentAtom } from "./persistableFixableAtoms";
199
import { realizationFlowNetworkQueryAtom } from "./queryAtoms";
2010

21-
2211
export const flowNetworkQueryResultAtom = atom((get) => {
2312
return get(realizationFlowNetworkQueryAtom);
2413
});
2514

26-
export const selectedEnsembleIdentAtom = atom<RegularEnsembleIdent | null>((get) => {
27-
const ensembleSet = get(EnsembleSetAtom);
28-
const userSelectedEnsembleIdent = get(userSelectedEnsembleIdentAtom);
29-
30-
const validEnsembleIdent = fixupRegularEnsembleIdent(userSelectedEnsembleIdent, ensembleSet);
31-
return validEnsembleIdent;
32-
});
33-
34-
export const selectedRealizationNumberAtom = atom<number | null>((get) => {
35-
const userSelectedRealizationNumber = get(userSelectedRealizationNumberAtom);
36-
const validRealizationNumbers = get(validRealizationNumbersAtom);
37-
38-
if (!validRealizationNumbers) {
39-
return null;
40-
}
41-
42-
if (userSelectedRealizationNumber === null) {
43-
const firstRealization = validRealizationNumbers.length > 0 ? validRealizationNumbers[0] : null;
44-
return firstRealization;
45-
}
15+
export const availableRealizationsAtom = atom<number[]>((get) => {
16+
const selectedEnsembleIdent = get(selectedEnsembleIdentAtom).value;
17+
const validEnsembleRealizationsFunction = get(ValidEnsembleRealizationsFunctionAtom);
4618

47-
const validRealizationNumber = validRealizationNumbers.includes(userSelectedRealizationNumber)
48-
? userSelectedRealizationNumber
49-
: null;
50-
return validRealizationNumber;
19+
const validRealizationNumbers = selectedEnsembleIdent
20+
? [...validEnsembleRealizationsFunction(selectedEnsembleIdent)]
21+
: [];
22+
return validRealizationNumbers;
5123
});
5224

5325
export const queryStatusAtom = atom<QueryStatus>((get) => {
@@ -77,20 +49,6 @@ export const availableDateTimesAtom = atom<string[]>((get) => {
7749
return Array.from(dateTimes);
7850
});
7951

80-
export const selectedDateTimeAtom = atom<string | null>((get) => {
81-
const availableDateTimes = get(availableDateTimesAtom);
82-
const userSelectedDateTime = get(userSelectedDateTimeAtom);
83-
84-
if (availableDateTimes.length === 0) {
85-
return null;
86-
}
87-
if (!userSelectedDateTime || !availableDateTimes.includes(userSelectedDateTime)) {
88-
return availableDateTimes[0];
89-
}
90-
91-
return userSelectedDateTime;
92-
});
93-
9452
export const edgeMetadataListAtom = atom<FlowNetworkMetadata_api[]>((get) => {
9553
const flowNetworkQueryResult = get(flowNetworkQueryResultAtom);
9654

@@ -102,21 +60,6 @@ export const edgeMetadataListAtom = atom<FlowNetworkMetadata_api[]>((get) => {
10260
return data.edgeMetadataList;
10361
});
10462

105-
export const selectedEdgeKeyAtom = atom<string | null>((get) => {
106-
const availableEdgesMetadataList = get(edgeMetadataListAtom);
107-
const availableEdgeKeys = availableEdgesMetadataList.map((item) => item.key);
108-
const userSelectedEdgeKey = get(userSelectedEdgeKeyAtom);
109-
110-
if (availableEdgesMetadataList.length === 0) {
111-
return null;
112-
}
113-
if (!userSelectedEdgeKey || !availableEdgeKeys.includes(userSelectedEdgeKey)) {
114-
return availableEdgeKeys[0];
115-
}
116-
117-
return userSelectedEdgeKey;
118-
});
119-
12063
export const nodeMetadataListAtom = atom<FlowNetworkMetadata_api[]>((get) => {
12164
const flowNetworkQueryResult = get(flowNetworkQueryResultAtom);
12265

@@ -128,21 +71,6 @@ export const nodeMetadataListAtom = atom<FlowNetworkMetadata_api[]>((get) => {
12871
return data.nodeMetadataList;
12972
});
13073

131-
export const selectedNodeKeyAtom = atom<string | null>((get) => {
132-
const availableNodesMetadataList = get(nodeMetadataListAtom);
133-
const availableNodeKeys = availableNodesMetadataList.map((item) => item.key);
134-
const userSelectedNodeKey = get(userSelectedNodeKeyAtom);
135-
136-
if (availableNodesMetadataList.length === 0) {
137-
return null;
138-
}
139-
if (!userSelectedNodeKey || !availableNodeKeys.includes(userSelectedNodeKey)) {
140-
return availableNodeKeys[0];
141-
}
142-
143-
return userSelectedNodeKey;
144-
});
145-
14674
export const datedNetworksAtom = atom<DatedFlowNetwork_api[]>((get) => {
14775
const flowNetworkQueryResult = get(flowNetworkQueryResultAtom);
14876

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { EnsembleSetAtom } from "@framework/GlobalAtoms";
2+
import type { RegularEnsembleIdent } from "@framework/RegularEnsembleIdent";
3+
import { persistableFixableAtom } from "@framework/utils/atomUtils";
4+
import { areEnsembleIdentsEqual } from "@framework/utils/ensembleIdentUtils";
5+
import { fixupRegularEnsembleIdent } from "@framework/utils/ensembleUiHelpers";
6+
7+
import {
8+
availableDateTimesAtom,
9+
availableRealizationsAtom,
10+
edgeMetadataListAtom,
11+
nodeMetadataListAtom,
12+
} from "./derivedAtoms";
13+
14+
export const selectedEnsembleIdentAtom = persistableFixableAtom<RegularEnsembleIdent | null>({
15+
initialValue: null,
16+
areEqualFunction: areEnsembleIdentsEqual,
17+
isValidFunction: ({ get, value }) => {
18+
const ensembleSet = get(EnsembleSetAtom);
19+
return value !== null && ensembleSet.hasEnsemble(value);
20+
},
21+
fixupFunction: ({ get, value }) => {
22+
const ensembleSet = get(EnsembleSetAtom);
23+
24+
return fixupRegularEnsembleIdent(value ?? null, ensembleSet);
25+
},
26+
});
27+
28+
export const selectedRealizationAtom = persistableFixableAtom<number | null>({
29+
initialValue: null,
30+
isValidFunction: ({ get, value }) => {
31+
const availableRealizations = get(availableRealizationsAtom);
32+
33+
if (value === null) {
34+
return availableRealizations.length === 0;
35+
}
36+
return availableRealizations.includes(value);
37+
},
38+
fixupFunction: ({ get, value }) => {
39+
const availableRealizations = get(availableRealizationsAtom);
40+
if (value === null || value === undefined) {
41+
return availableRealizations[0] ?? null;
42+
}
43+
44+
// When value is invalid number, enforce user to reselect
45+
return null;
46+
},
47+
});
48+
49+
export const selectedDateTimeAtom = persistableFixableAtom<string | null>({
50+
initialValue: null,
51+
isValidFunction: ({ get, value }) => {
52+
const availableDateTimes = get(availableDateTimesAtom);
53+
54+
if (!value) {
55+
return availableDateTimes.length === 0;
56+
}
57+
return availableDateTimes.includes(value);
58+
},
59+
fixupFunction: ({ get }) => {
60+
const availableDateTimes = get(availableDateTimesAtom);
61+
return availableDateTimes[0] ?? null;
62+
},
63+
});
64+
65+
export const selectedEdgeKeyAtom = persistableFixableAtom<string | null>({
66+
initialValue: null,
67+
isValidFunction: ({ get, value }) => {
68+
const availableEdgesMetadataList = get(edgeMetadataListAtom);
69+
const availableEdgeKeys = availableEdgesMetadataList.map((item) => item.key);
70+
71+
if (!value) {
72+
return availableEdgeKeys.length === 0;
73+
}
74+
return availableEdgeKeys.includes(value);
75+
},
76+
fixupFunction: ({ get }) => {
77+
const availableEdgesMetadataList = get(edgeMetadataListAtom);
78+
const availableEdgeKeys = availableEdgesMetadataList.map((item) => item.key);
79+
return availableEdgeKeys[0] ?? null;
80+
},
81+
});
82+
83+
export const selectedNodeKeyAtom = persistableFixableAtom<string | null>({
84+
initialValue: null,
85+
isValidFunction: ({ get, value }) => {
86+
const availableNodesMetadataList = get(nodeMetadataListAtom);
87+
const availableNodeKeys = availableNodesMetadataList.map((item) => item.key);
88+
89+
if (!value) {
90+
return availableNodeKeys.length === 0;
91+
}
92+
return availableNodeKeys.includes(value);
93+
},
94+
fixupFunction: ({ get }) => {
95+
const availableNodesMetadataList = get(nodeMetadataListAtom);
96+
const availableNodeKeys = availableNodesMetadataList.map((item) => item.key);
97+
return availableNodeKeys[0] ?? null;
98+
},
99+
});

0 commit comments

Comments
 (0)