Skip to content

Commit

Permalink
Utilize new status writer for settings and view + bug fix
Browse files Browse the repository at this point in the history
- Improve usage of status writer for settings and view
- Fix bug: Render `ContentError` in view withing wrapperDivRef to ensure correct sizing.
  • Loading branch information
jorgenherje committed Oct 16, 2023
1 parent 9f94ec6 commit 6c58497
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 19 deletions.
26 changes: 22 additions & 4 deletions frontend/src/modules/SimulationTimeSeriesMatrix/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { EnsembleIdent } from "@framework/EnsembleIdent";
import { Parameter, ParameterIdent, ParameterType } from "@framework/EnsembleParameters";
import { EnsembleSet } from "@framework/EnsembleSet";
import { ModuleFCProps } from "@framework/Module";
import { useSettingsStatusWriter } from "@framework/StatusWriter";
import { useEnsembleSet } from "@framework/WorkbenchSession";
import { MultiEnsembleSelect } from "@framework/components/MultiEnsembleSelect";
import { ParameterListFilter } from "@framework/components/ParameterListFilter";
Expand Down Expand Up @@ -39,6 +40,7 @@ import {
VisualizationModeEnumToStringMapping,
} from "./state";
import { EnsembleVectorListsHelper } from "./utils/ensemblesVectorListHelper";
import { makeDisplayStringFromStringArray } from "./utils/stringUtils";

enum StatisticsType {
INDIVIDUAL = "Individual",
Expand All @@ -47,6 +49,7 @@ enum StatisticsType {

export function settings({ moduleContext, workbenchSession }: ModuleFCProps<State>) {
const ensembleSet = useEnsembleSet(workbenchSession);
const statusWriter = useSettingsStatusWriter(moduleContext);

// Store state/values
const [resampleFrequency, setResamplingFrequency] = moduleContext.useStoreState("resamplingFrequency");
Expand Down Expand Up @@ -125,19 +128,34 @@ export function settings({ moduleContext, workbenchSession }: ModuleFCProps<Stat
setStatisticsType(computedStatisticsType);
}

// Set warning for selected vectors not existing in a selected ensemble
for (const ensembleIdent of selectedEnsembleIdents) {
const nonExistingVectors = selectedVectorNames.filter(
(vector) => !ensembleVectorListsHelper.isVectorInEnsemble(ensembleIdent, vector)
);
if (nonExistingVectors.length === 0) {
continue;
}

const ensembleStr = ensembleSet.findEnsemble(ensembleIdent)?.getDisplayName() ?? ensembleIdent.toString();
statusWriter.addWarning(
`Vector ${makeDisplayStringFromStringArray(nonExistingVectors)} does not exist in ensemble ${ensembleStr}`
);
}

React.useEffect(
function propagateVectorSpecsToView() {
const newVectorSpecifications: VectorSpec[] = [];
for (const ensemble of selectedEnsembleIdents) {
for (const ensembleIdent of selectedEnsembleIdents) {
for (const vector of selectedVectorNames) {
if (!ensembleVectorListsHelper.isVectorInEnsemble(ensemble, vector)) {
if (!ensembleVectorListsHelper.isVectorInEnsemble(ensembleIdent, vector)) {
continue;
}

newVectorSpecifications.push({
ensembleIdent: ensemble,
ensembleIdent: ensembleIdent,
vectorName: vector,
hasHistoricalVector: ensembleVectorListsHelper.hasHistoricalVector(ensemble, vector),
hasHistoricalVector: ensembleVectorListsHelper.hasHistoricalVector(ensembleIdent, vector),
});
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Utility function to make a display friendly string from an array of strings.
*
* Example: ["a", "b", "c"] -> "a, b and c"
*/
export function makeDisplayStringFromStringArray(stringArray: string[]): string {
return stringArray.length === 0
? ""
: stringArray.length === 1
? stringArray[0]
: stringArray.slice(0, -1).join(", ") + " and " + stringArray[stringArray.length - 1];
}
52 changes: 37 additions & 15 deletions frontend/src/modules/SimulationTimeSeriesMatrix/view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ export const view = ({ moduleContext, workbenchSession, workbenchSettings }: Mod
const wrapperDivSize = useElementSize(wrapperDivRef);

const ensembleSet = useEnsembleSet(workbenchSession);

const statusWriter = useViewStatusWriter(moduleContext);

// Store values
Expand Down Expand Up @@ -68,20 +67,26 @@ export const view = ({ moduleContext, workbenchSession, workbenchSettings }: Mod
vectorSpecificationsWithHistoricalData?.some((vec) => vec.hasHistoricalVector) ?? false
);

// Get fetching status from queries
const isQueryFetching =
vectorDataQueries.some((query) => query.isFetching) ||
vectorStatisticsQueries.some((query) => query.isFetching) ||
historicalVectorDataQueries.some((query) => query.isFetching);

statusWriter.setLoading(isQueryFetching);

const hasQueryError =
vectorDataQueries.some((query) => query.isError) ||
vectorStatisticsQueries.some((query) => query.isError) ||
historicalVectorDataQueries.some((query) => query.isError);
if (hasQueryError) {
statusWriter.addError("One or more queries have an error state.");
return <ContentError>One or more queries have an error state.</ContentError>;
// Get error/warning status from queries
const hasRealizationsQueryError = vectorDataQueries.some((query) => query.isError);
const hasStatisticsQueryError = vectorStatisticsQueries.some((query) => query.isError);
const hasHistoricalVectorQueryError = historicalVectorDataQueries.some((query) => query.isError);
if (hasRealizationsQueryError) {
statusWriter.addError("One or more realization data queries have an error state.");
}
if (hasStatisticsQueryError) {
statusWriter.addError("One or more statistics data queries have an error state.");
}
if (hasHistoricalVectorQueryError) {
statusWriter.addWarning("One or more historical data queries have an error state.");
}

// Map vector specifications and queries with data
Expand Down Expand Up @@ -114,12 +119,25 @@ export const view = ({ moduleContext, workbenchSession, workbenchSettings }: Mod
// Create parameter color scale helper
const doColorByParameter =
colorRealizationsByParameter &&
visualizationMode === VisualizationMode.INDIVIDUAL_REALIZATIONS &&
parameterIdent !== null &&
selectedEnsembles.some((ensemble) => ensemble.getParameters().hasParameter(parameterIdent));
const ensemblesParameterColoring = doColorByParameter
? new EnsemblesContinuousParameterColoring(selectedEnsembles, parameterIdent, parameterColorScale)
: null;

// Set warning for ensembles without selected parameter when coloring is enabled
if (doColorByParameter && ensemblesParameterColoring) {
const ensemblesWithoutParameter = selectedEnsembles.filter(
(ensemble) => !ensemblesParameterColoring.hasParameterForEnsemble(ensemble.getIdent())
);
for (const ensemble of ensemblesWithoutParameter) {
statusWriter.addWarning(
`Ensemble ${ensemble.getDisplayName()} does not have parameter ${ensemblesParameterColoring.getParameterDisplayName()}`
);
}
}

// Callback function for ensemble display name
function makeEnsembleDisplayName(ensembleIdent: EnsembleIdent): string {
const ensembleNameCount = selectedEnsembles.filter(
Expand Down Expand Up @@ -193,16 +211,20 @@ export const view = ({ moduleContext, workbenchSession, workbenchSettings }: Mod
subplotBuilder.addHistoryTraces(loadedVectorSpecificationsAndHistoricalData);
}

// TODO: Keep uirevision?
const doRenderContentError = hasRealizationsQueryError || hasStatisticsQueryError;
const plotData = subplotBuilder.createPlotData();
return (
<div className="w-full h-full" ref={wrapperDivRef}>
<Plot
key={plotData.length} // Note: To trigger re-render and remove legends when plotData is empty
data={plotData}
layout={subplotBuilder.createPlotLayout()}
config={{ scrollZoom: true }}
/>
{doRenderContentError ? (
<ContentError>One or more queries have an error state.</ContentError>
) : (
<Plot
key={plotData.length} // Note: Temporary to trigger re-render and remove legends when plotData is empty
data={plotData}
layout={subplotBuilder.createPlotLayout()}
config={{ scrollZoom: true }}
/>
)}
</div>
);
};
11 changes: 11 additions & 0 deletions frontend/tests/unit-tests/SimulationTimeSeriesMatrixUtils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// import { scaleHexColorLightness } from "@modules/SimulationTimeSeriesMatrix/utils/colorUtils";
import { makeDisplayStringFromStringArray } from "@modules/SimulationTimeSeriesMatrix/utils/stringUtils";

describe("Test of utility functions for SimulationTimeSeriesMatrix module", () => {
test("Test make display string from string array", () => {
expect(makeDisplayStringFromStringArray(["a", "b", "c"])).toBe("a, b and c");
expect(makeDisplayStringFromStringArray(["a"])).toBe("a");
expect(makeDisplayStringFromStringArray([])).toBe("");
expect(makeDisplayStringFromStringArray(["a", "b"])).toBe("a and b");
});
});

0 comments on commit 6c58497

Please sign in to comment.