Skip to content

Commit

Permalink
Further experiments/adjustments
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenthoms committed Jan 19, 2024
1 parent 6f96c25 commit c8f23f6
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 174 deletions.
12 changes: 3 additions & 9 deletions frontend/src/framework/Module.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@ import { WorkbenchServices } from "./WorkbenchServices";
import { WorkbenchSession } from "./WorkbenchSession";
import { WorkbenchSettings } from "./WorkbenchSettings";

export type ModuleFCProps<
S extends StateBaseType,
TBusinessLogic extends ModuleBusinessLogic<any, any, any, any> | never = never
> = {
export type ModuleFCProps<S extends StateBaseType, TBusinessLogic extends ModuleBusinessLogic<any> | never = never> = {
moduleContext: ModuleContext<S, TBusinessLogic>;
workbenchSession: WorkbenchSession;
workbenchServices: WorkbenchServices;
Expand All @@ -29,7 +26,7 @@ export type ModuleFCProps<

export type ModuleFC<
S extends StateBaseType,
TBusinessLogic extends ModuleBusinessLogic<any, any, any, any> | never = never
TBusinessLogic extends ModuleBusinessLogic<any> | never = never
> = React.FC<ModuleFCProps<S, TBusinessLogic>>;

export enum ImportState {
Expand All @@ -39,10 +36,7 @@ export enum ImportState {
Failed = "Failed",
}

export class Module<
StateType extends StateBaseType,
TBusinessLogic extends ModuleBusinessLogic<any, any, any, any> | never = never
> {
export class Module<StateType extends StateBaseType, TBusinessLogic extends ModuleBusinessLogic<any> | never = never> {
private _name: string;
private _defaultTitle: string;
public viewFC: ModuleFC<StateType, TBusinessLogic>;
Expand Down
67 changes: 17 additions & 50 deletions frontend/src/framework/ModuleBusinessLogic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,18 @@ import { WorkbenchSession } from "@framework/WorkbenchSession";
import { WorkbenchSettings } from "@framework/WorkbenchSettings";
import { QueryClient } from "@tanstack/react-query";

export type ModuleBusinessLogicState<TFetchedData, TUserSelections, TUtilityStates, TLoadingStates> = {
fetchedData: TFetchedData;
userSelections: TUserSelections;
utilityStates: TUtilityStates;
loadingStates: TLoadingStates;
};

export class ModuleBusinessLogic<TFetchedData, TUserSelections, TUtilityStates, TLoadingStates> {
import { merge } from "lodash";

type DeepPartial<T> = T extends object
? {
[P in keyof T]?: DeepPartial<T[P]>;
}
: T;

export class ModuleBusinessLogic<TState> {
protected _queryClient: QueryClient;
_state: ModuleBusinessLogicState<TFetchedData, TUserSelections, TUtilityStates, TLoadingStates> = {
fetchedData: {} as TFetchedData,
userSelections: {} as TUserSelections,
utilityStates: {} as TUtilityStates,
loadingStates: {} as TLoadingStates,
};
_state: TState = {} as TState;

private _subscribers: Set<() => void> = new Set();
private _timeout: ReturnType<typeof setTimeout> | null = null;
protected _workbenchSession: WorkbenchSession;
Expand Down Expand Up @@ -48,7 +45,7 @@ export class ModuleBusinessLogic<TFetchedData, TUserSelections, TUtilityStates,
};
}

getSnapshot(): ModuleBusinessLogicState<TFetchedData, TUserSelections, TUtilityStates, TLoadingStates> {
getSnapshot(): TState {
return this._state;
}

Expand All @@ -65,48 +62,18 @@ export class ModuleBusinessLogic<TFetchedData, TUserSelections, TUtilityStates,
}, 100);
}

protected updateFetchedData(newState: Partial<TFetchedData>) {
this._state = { ...this._state, fetchedData: { ...this._state.fetchedData, ...newState } };

this.notifySubscribers();
}

protected updateUserSelections(newState: Partial<TUserSelections>) {
this._state = { ...this._state, userSelections: { ...this._state.userSelections, ...newState } };

this.notifySubscribers();
}

protected updateUtilityStates(newState: Partial<TUtilityStates>) {
this._state = { ...this._state, utilityStates: { ...this._state.utilityStates, ...newState } };
protected updateState(newState: DeepPartial<TState>) {
merge(this._state, newState);

this.notifySubscribers();
}

protected updateLoadingStates(newState: Partial<TLoadingStates>) {
this._state = { ...this._state, loadingStates: { ...this._state.loadingStates, ...newState } };

this.notifySubscribers();
}

protected getFetchedData(): TFetchedData {
return this._state.fetchedData;
}

protected getUserSelections(): TUserSelections {
return this._state.userSelections;
}

protected getUtilityStates(): TUtilityStates {
return this._state.utilityStates;
}

protected getLoadingStates(): TLoadingStates {
return this._state.loadingStates;
protected getState(): TState {
return this._state;
}
}

export function useBusinessLogic<T extends ModuleBusinessLogic<any, any, any, any>>(businessLogic: T): T["_state"] {
export function useBusinessLogic<T extends ModuleBusinessLogic<any>>(businessLogic: T): T["_state"] {
const state = React.useSyncExternalStore<T["_state"]>(businessLogic.subscribe, businessLogic.getSnapshot);

return state;
Expand Down
5 changes: 1 addition & 4 deletions frontend/src/framework/ModuleContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@ import { ModuleInstanceStatusController } from "./ModuleInstanceStatusController
import { StateBaseType, StateStore, useSetStoreValue, useStoreState, useStoreValue } from "./StateStore";
import { SyncSettingKey } from "./SyncSettings";

export class ModuleContext<
S extends StateBaseType,
TBusinessLogic extends ModuleBusinessLogic<any, any, any, any> | never
> {
export class ModuleContext<S extends StateBaseType, TBusinessLogic extends ModuleBusinessLogic<any> | never> {
private _moduleInstance: ModuleInstance<S, TBusinessLogic>;
private _stateStore: StateStore<S>;

Expand Down
9 changes: 3 additions & 6 deletions frontend/src/framework/ModuleInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@ export enum ModuleInstanceState {
RESETTING,
}

export class ModuleInstance<
StateType extends StateBaseType,
TBusinessLogic extends ModuleBusinessLogic<any, any, any, any> | never
> {
export class ModuleInstance<StateType extends StateBaseType, TBusinessLogic extends ModuleBusinessLogic<any> | never> {
private _id: string;
private _title: string;
private _initialised: boolean;
Expand All @@ -46,7 +43,7 @@ export class ModuleInstance<
private _inputChannelDefs: InputBroadcastChannelDef[];
private _inputChannels: Record<string, BroadcastChannel> = {};
private _workbench: Workbench;
private _businessLogic: ModuleBusinessLogic<any, any, any, any> | null = null;
private _businessLogic: ModuleBusinessLogic<any> | null = null;

constructor(
module: Module<StateType, TBusinessLogic>,
Expand Down Expand Up @@ -104,7 +101,7 @@ export class ModuleInstance<
}
}

getBusinessLogic(): ModuleBusinessLogic<any, any, any, any> | null {
getBusinessLogic(): ModuleBusinessLogic<any> | null {
return this._businessLogic;
}

Expand Down
4 changes: 2 additions & 2 deletions frontend/src/framework/ModuleRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { StateBaseType, StateOptions } from "./StateStore";
import { SyncSettingKey } from "./SyncSettings";
import { ModuleNotFoundPlaceholder } from "./internal/ModuleNotFoundPlaceholder";

export type RegisterModuleOptions<TBusinessLogic extends ModuleBusinessLogic<any, any, any, any> | never> = {
export type RegisterModuleOptions<TBusinessLogic extends ModuleBusinessLogic<any> | never> = {
moduleName: string;
defaultTitle: string;
syncableSettingKeys?: SyncSettingKey[];
Expand Down Expand Up @@ -53,7 +53,7 @@ export class ModuleRegistry {

static initModule<
ModuleStateType extends StateBaseType,
TBusinessLogic extends ModuleBusinessLogic<any, any, any, any> | never = never
TBusinessLogic extends ModuleBusinessLogic<any> | never = never
>(
moduleName: string,
defaultState: ModuleStateType,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Frequency_api } from "@api";
import { Frequency_api, VectorRealizationData_api } from "@api";
import { apiService } from "@framework/ApiService";
import { EnsembleIdent } from "@framework/EnsembleIdent";
import { ModuleBusinessLogic } from "@framework/ModuleBusinessLogic";
Expand Down Expand Up @@ -31,7 +31,14 @@ export interface LoadingStates {
vectorData: boolean;
}

export class BusinessLogic extends ModuleBusinessLogic<FetchedData, UserSelections, UtilityStates, LoadingStates> {
export interface State {
fetchedData: FetchedData;
userSelections: UserSelections;
utilityStates: UtilityStates;
loadingStates: LoadingStates;
}

export class BusinessLogic extends ModuleBusinessLogic<State> {
constructor(
workbenchServices: WorkbenchServices,
workbenchSession: WorkbenchSession,
Expand All @@ -44,6 +51,7 @@ export class BusinessLogic extends ModuleBusinessLogic<FetchedData, UserSelectio
this._state = {
fetchedData: {
vectorDescriptions: [],
vectorData: [],
},
userSelections: {
ensembleIdent: null,
Expand All @@ -58,6 +66,7 @@ export class BusinessLogic extends ModuleBusinessLogic<FetchedData, UserSelectio
},
loadingStates: {
vectors: false,
vectorData: false,
},
};

Expand All @@ -76,45 +85,50 @@ export class BusinessLogic extends ModuleBusinessLogic<FetchedData, UserSelectio

handleEnsembleSetChange() {
const newEnsembleSet = this._workbenchSession.getEnsembleSet();
const currentEnsembleIdent = this.getUserSelections().ensembleIdent;
const currentEnsembleIdent = this.getState().userSelections.ensembleIdent;
if (!currentEnsembleIdent || newEnsembleSet.findEnsemble(currentEnsembleIdent)) {
this.updateUserSelections({ ensembleIdent: newEnsembleSet.getEnsembleArr()[0].getIdent() });
this.updateState({ userSelections: { ensembleIdent: newEnsembleSet.getEnsembleArr()[0].getIdent() } });
}
}

setEnsembleIdent(ensembleIdent: EnsembleIdent | null) {
this.updateUserSelections({ ensembleIdent });
this.updateState({ userSelections: { ensembleIdent } });
this.fetchVectors();
}

setResamplingFrequency(resamplingFrequency: Frequency_api | null) {
this.updateUserSelections({ resamplingFrequency });
this.updateState({ userSelections: { resamplingFrequency } });
}

setShowStatistics(showStatistics: boolean) {
this.updateUserSelections({ showStatistics });
this.updateState({ userSelections: { showStatistics } });
}

setShowRealizations(showRealizations: boolean) {
this.updateUserSelections({ showRealizations });
this.updateState({ userSelections: { showRealizations } });
}

setShowHistorical(showHistorical: boolean) {
this.updateUserSelections({ showHistorical });
this.updateState({ userSelections: { showHistorical } });
}

setVector(vector: string) {
this.updateUtilityStates({ hasHistoricalVector: this.hasHistoricalVector(vector) });
this.updateUserSelections({ vector });
this.updateState({
userSelections: { vector },
utilityStates: { hasHistoricalVector: this.hasHistoricalVector(vector) },
});
this.fetchVectorData();
}

private hasHistoricalVector(nonHistoricalVectorName: string): boolean {
if (!this.getFetchedData().vectorDescriptions || this.getFetchedData().vectorDescriptions.length === 0) {
if (
!this.getState().fetchedData.vectorDescriptions ||
this.getState().fetchedData.vectorDescriptions.length === 0
) {
return false;
}

const foundItem = this.getFetchedData().vectorDescriptions.find(
const foundItem = this.getState().fetchedData.vectorDescriptions.find(
(item) => item.name === nonHistoricalVectorName
);
if (foundItem) {
Expand All @@ -125,43 +139,45 @@ export class BusinessLogic extends ModuleBusinessLogic<FetchedData, UserSelectio
}

private async fetchVectors() {
this.updateLoadingStates({ vectors: true });
// This should be a separate module, but for now we just do it here for testing
this.updateState({ loadingStates: { vectors: true } });

const vectors = await this._queryClient.fetchQuery({
queryKey: ["getVectorList", this.getUserSelections().ensembleIdent],
queryKey: ["getVectorList", this.getState().userSelections.ensembleIdent],
queryFn: () =>
apiService.timeseries.getVectorList(
this.getUserSelections().ensembleIdent?.getCaseUuid() ?? "",
this.getUserSelections().ensembleIdent?.getEnsembleName() ?? ""
this.getState().userSelections.ensembleIdent?.getCaseUuid() ?? "",
this.getState().userSelections.ensembleIdent?.getEnsembleName() ?? ""
),
});

this.updateFetchedData({ vectorDescriptions: vectors });
this.updateLoadingStates({ vectors: false });
this.updateState({ loadingStates: { vectors: false }, fetchedData: { vectorDescriptions: vectors } });
}

private async fetchVectorData() {
this.updateLoadingStates({ vectorData: true });
// This should be a separate module, but for now we just do it here for testing
this.updateState({ loadingStates: { vectorData: true } });

const userSelections = this.getState().userSelections;

const vectorData = await this._queryClient.fetchQuery({
queryKey: [
"getVectorData",
this.getUserSelections().ensembleIdent,
this.getUserSelections().vector,
this.getUserSelections().resamplingFrequency,
this.getUserSelections().showRealizations,
userSelections.ensembleIdent,
userSelections.vector,
userSelections.resamplingFrequency,
userSelections.showRealizations,
],
queryFn: () =>
apiService.timeseries.getRealizationsVectorData(
this.getUserSelections().ensembleIdent?.getCaseUuid() ?? "",
this.getUserSelections().ensembleIdent?.getEnsembleName() ?? "",
this.getUserSelections().vector,
this.getUserSelections().resamplingFrequency,
userSelections.ensembleIdent?.getCaseUuid() ?? "",
userSelections.ensembleIdent?.getEnsembleName() ?? "",
userSelections.vector,
userSelections.resamplingFrequency,
undefined
),
});

this.updateFetchedData({ vectorData });
this.updateLoadingStates({ vectorData: false });
this.updateState({ fetchedData: { vectorData }, loadingStates: { vectorData: false } });
}
}
Loading

0 comments on commit c8f23f6

Please sign in to comment.