diff --git a/frontend/src/lib/utils/arrays.ts b/frontend/src/lib/utils/arrays.ts index 4892060f8..67a736f48 100644 --- a/frontend/src/lib/utils/arrays.ts +++ b/frontend/src/lib/utils/arrays.ts @@ -12,3 +12,26 @@ export function arrayMove(array: T[], from: number, to: number, moveAmt = 1): return newArrray.toSpliced(to, 0, ...movedItems); } + +/** + * Sort an array of strings according to a specified order, with values not in the order list sorted alphabetically at the end. + * + * @param values List of values to sort + * @param valuesByOrder A list of values defining the desired order. Values not in this list will be sorted alphabetically after the ordered values. + * @returns Returns a new array with the values sorted according to the specified order. + */ +export function sortStringArray(values: string[], valuesByOrder: string[]): string[] { + // Build quick lookup for order indices to avoid repeated indexOf + const orderIndex = new Map(valuesByOrder.map((value, idx) => [value, idx])); + + return values.sort((a, b) => { + const ia = orderIndex.has(a) ? orderIndex.get(a)! : -1; + const ib = orderIndex.has(b) ? orderIndex.get(b)! : -1; + + if (ia !== -1 && ib !== -1) return ia - ib; // both in order list + if (ia !== -1) return -1; // only a in order + if (ib !== -1) return 1; // only b in order + + return a.localeCompare(b); // neither in order list + }); +} diff --git a/frontend/src/modules/2DViewer/DataProviderFramework/customDataProviderImplementations/ObservedSurfaceProvider.ts b/frontend/src/modules/2DViewer/DataProviderFramework/customDataProviderImplementations/ObservedSurfaceProvider.ts index 3a8e4fbe3..870d529c1 100644 --- a/frontend/src/modules/2DViewer/DataProviderFramework/customDataProviderImplementations/ObservedSurfaceProvider.ts +++ b/frontend/src/modules/2DViewer/DataProviderFramework/customDataProviderImplementations/ObservedSurfaceProvider.ts @@ -2,6 +2,7 @@ import { isEqual } from "lodash"; import type { SurfaceDataPng_api } from "@api"; import { SurfaceTimeType_api, getObservedSurfacesMetadataOptions, getSurfaceDataOptions } from "@api"; +import { sortStringArray } from "@lib/utils/arrays"; import type { CustomDataProviderImplementation, DataProviderInformationAccessors, @@ -129,8 +130,7 @@ export class ObservedSurfaceProvider ), ), ]; - - return availableSurfaceNames; + return sortStringArray(availableSurfaceNames, data.surface_names_in_strat_order); }); availableSettingsUpdater(Setting.TIME_OR_INTERVAL, ({ getLocalSetting, getHelperDependency }) => { diff --git a/frontend/src/modules/Intersection/DataProviderFramework/customDataProviderImplementations/EnsembleWellborePicksProvider.ts b/frontend/src/modules/Intersection/DataProviderFramework/customDataProviderImplementations/EnsembleWellborePicksProvider.ts index e56ad7832..7ed74d907 100644 --- a/frontend/src/modules/Intersection/DataProviderFramework/customDataProviderImplementations/EnsembleWellborePicksProvider.ts +++ b/frontend/src/modules/Intersection/DataProviderFramework/customDataProviderImplementations/EnsembleWellborePicksProvider.ts @@ -108,11 +108,7 @@ export class EnsembleWellborePicksProvider return []; } - return wellborePicks - .filter((elm) => elm.interpreter === selectedInterpreter) - .sort((a, b) => { - return a.pickIdentifier.localeCompare(b.pickIdentifier); - }); + return wellborePicks.filter((elm) => elm.interpreter === selectedInterpreter); }); } diff --git a/frontend/src/modules/Intersection/DataProviderFramework/customDataProviderImplementations/RealizationSurfacesProvider.ts b/frontend/src/modules/Intersection/DataProviderFramework/customDataProviderImplementations/RealizationSurfacesProvider.ts index 8fe3908aa..750e3694f 100644 --- a/frontend/src/modules/Intersection/DataProviderFramework/customDataProviderImplementations/RealizationSurfacesProvider.ts +++ b/frontend/src/modules/Intersection/DataProviderFramework/customDataProviderImplementations/RealizationSurfacesProvider.ts @@ -7,6 +7,7 @@ import { postGetSurfaceIntersectionOptions, } from "@api"; import { IntersectionType } from "@framework/types/intersection"; +import { sortStringArray } from "@lib/utils/arrays"; import { assertNonNull } from "@lib/utils/assertNonNull"; import { createIntersectionPolylineWithSectionLengthsForField, @@ -151,7 +152,7 @@ export class RealizationSurfacesProvider return getAvailableIntersectionOptions(wellboreHeaders, fieldIntersectionPolylines); }); - const depthSurfaceMetadataDep = helperDependency(async ({ getLocalSetting, abortSignal }) => { + const surfaceMetadataSetDep = helperDependency(async ({ getLocalSetting, abortSignal }) => { const ensembleIdent = getLocalSetting(Setting.ENSEMBLE); if (!ensembleIdent) { @@ -168,15 +169,17 @@ export class RealizationSurfacesProvider }), }); - const depthSurfacesMetadata = surfaceMetadata.surfaces.filter( - (elm) => elm.attribute_type === SurfaceAttributeType_api.DEPTH, - ); - return depthSurfacesMetadata; + return surfaceMetadata; }); availableSettingsUpdater(Setting.ATTRIBUTE, ({ getHelperDependency }) => { - const depthSurfacesMetadata = getHelperDependency(depthSurfaceMetadataDep); - + const surfaceMetadataSet = getHelperDependency(surfaceMetadataSetDep); + if (!surfaceMetadataSet) { + return []; + } + const depthSurfacesMetadata = surfaceMetadataSet.surfaces.filter( + (elm) => elm.attribute_type === SurfaceAttributeType_api.DEPTH, + ); if (!depthSurfacesMetadata) { return []; } @@ -186,16 +189,19 @@ export class RealizationSurfacesProvider availableSettingsUpdater(Setting.SURFACE_NAMES, ({ getLocalSetting, getHelperDependency }) => { const attribute = getLocalSetting(Setting.ATTRIBUTE); - const depthSurfacesMetadata = getHelperDependency(depthSurfaceMetadataDep); + const surfaceMetadataSet = getHelperDependency(surfaceMetadataSetDep); - if (!attribute || !depthSurfacesMetadata) { + if (!attribute || !surfaceMetadataSet) { return []; } + const depthSurfacesMetadata = surfaceMetadataSet.surfaces.filter( + (elm) => elm.attribute_type === SurfaceAttributeType_api.DEPTH, + ); - // Filter depth surfaces metadata by the selected attribute - return Array.from( + const filteredSurfaceNames = Array.from( new Set(depthSurfacesMetadata.filter((elm) => elm.attribute_name === attribute).map((elm) => elm.name)), - ).sort(); + ); + return sortStringArray(filteredSurfaceNames, surfaceMetadataSet.surface_names_in_strat_order); }); // Create intersection polyline and actual section lengths data asynchronously diff --git a/frontend/src/modules/Intersection/DataProviderFramework/customDataProviderImplementations/SurfacesPerRealizationValuesProvider.ts b/frontend/src/modules/Intersection/DataProviderFramework/customDataProviderImplementations/SurfacesPerRealizationValuesProvider.ts index e549057a6..0446bb075 100644 --- a/frontend/src/modules/Intersection/DataProviderFramework/customDataProviderImplementations/SurfacesPerRealizationValuesProvider.ts +++ b/frontend/src/modules/Intersection/DataProviderFramework/customDataProviderImplementations/SurfacesPerRealizationValuesProvider.ts @@ -7,6 +7,7 @@ import { postGetSampleSurfaceInPointsOptions, } from "@api"; import { IntersectionType } from "@framework/types/intersection"; +import { sortStringArray } from "@lib/utils/arrays"; import { assertNonNull } from "@lib/utils/assertNonNull"; import { createIntersectionPolylineWithSectionLengthsForField, @@ -155,7 +156,7 @@ export class SurfacesPerRealizationValuesProvider return getAvailableIntersectionOptions(wellboreHeaders, fieldIntersectionPolylines); }); - const depthSurfaceMetadataDep = helperDependency(async ({ getLocalSetting, abortSignal }) => { + const surfaceMetadataSetDep = helperDependency(async ({ getLocalSetting, abortSignal }) => { const ensembleIdent = getLocalSetting(Setting.ENSEMBLE); if (!ensembleIdent) { @@ -172,15 +173,17 @@ export class SurfacesPerRealizationValuesProvider }), }); - const depthSurfacesMetadata = surfaceMetadata.surfaces.filter( - (elm) => elm.attribute_type === SurfaceAttributeType_api.DEPTH, - ); - return depthSurfacesMetadata; + return surfaceMetadata; }); availableSettingsUpdater(Setting.ATTRIBUTE, ({ getHelperDependency }) => { - const depthSurfacesMetadata = getHelperDependency(depthSurfaceMetadataDep); - + const surfaceMetadataSet = getHelperDependency(surfaceMetadataSetDep); + if (!surfaceMetadataSet) { + return []; + } + const depthSurfacesMetadata = surfaceMetadataSet.surfaces.filter( + (elm) => elm.attribute_type === SurfaceAttributeType_api.DEPTH, + ); if (!depthSurfacesMetadata) { return []; } @@ -190,16 +193,19 @@ export class SurfacesPerRealizationValuesProvider availableSettingsUpdater(Setting.SURFACE_NAMES, ({ getLocalSetting, getHelperDependency }) => { const attribute = getLocalSetting(Setting.ATTRIBUTE); - const depthSurfacesMetadata = getHelperDependency(depthSurfaceMetadataDep); + const surfaceMetadataSet = getHelperDependency(surfaceMetadataSetDep); - if (!attribute || !depthSurfacesMetadata) { + if (!attribute || !surfaceMetadataSet) { return []; } + const depthSurfacesMetadata = surfaceMetadataSet.surfaces.filter( + (elm) => elm.attribute_type === SurfaceAttributeType_api.DEPTH, + ); - // Filter depth surfaces metadata by the selected attribute - return Array.from( + const filteredSurfaceNames = Array.from( new Set(depthSurfacesMetadata.filter((elm) => elm.attribute_name === attribute).map((elm) => elm.name)), - ).sort(); + ); + return sortStringArray(filteredSurfaceNames, surfaceMetadataSet.surface_names_in_strat_order); }); // Create intersection polyline and actual section lengths data asynchronously diff --git a/frontend/src/modules/_shared/DataProviderFramework/dataProviders/implementations/RealizationSurfaceProvider.ts b/frontend/src/modules/_shared/DataProviderFramework/dataProviders/implementations/RealizationSurfaceProvider.ts index 5cb465b68..020667de8 100644 --- a/frontend/src/modules/_shared/DataProviderFramework/dataProviders/implementations/RealizationSurfaceProvider.ts +++ b/frontend/src/modules/_shared/DataProviderFramework/dataProviders/implementations/RealizationSurfaceProvider.ts @@ -7,6 +7,7 @@ import { getRealizationSurfacesMetadataOptions, getSurfaceDataOptions, } from "@api"; +import { sortStringArray } from "@lib/utils/arrays"; import type { CustomDataProviderImplementation, DataProviderInformationAccessors, @@ -189,8 +190,7 @@ export class RealizationSurfaceProvider ), ), ]; - - return availableSurfaceNames; + return sortStringArray(availableSurfaceNames, data.surface_names_in_strat_order); }); availableSettingsUpdater(Setting.TIME_OR_INTERVAL, ({ getLocalSetting, getHelperDependency }) => { diff --git a/frontend/src/modules/_shared/DataProviderFramework/dataProviders/implementations/StatisticalSurfaceProvider.ts b/frontend/src/modules/_shared/DataProviderFramework/dataProviders/implementations/StatisticalSurfaceProvider.ts index c8b33edcc..46e350727 100644 --- a/frontend/src/modules/_shared/DataProviderFramework/dataProviders/implementations/StatisticalSurfaceProvider.ts +++ b/frontend/src/modules/_shared/DataProviderFramework/dataProviders/implementations/StatisticalSurfaceProvider.ts @@ -12,6 +12,7 @@ import { } from "@api"; import { lroProgressBus } from "@framework/LroProgressBus"; import { wrapLongRunningQuery } from "@framework/utils/lro/longRunningApiCalls"; +import { sortStringArray } from "@lib/utils/arrays"; import type { CustomDataProviderImplementation, DataProviderInformationAccessors, @@ -187,8 +188,7 @@ export class StatisticalSurfaceProvider ), ), ]; - - return availableSurfaceNames; + return sortStringArray(availableSurfaceNames, data.surface_names_in_strat_order); }); availableSettingsUpdater(Setting.TIME_OR_INTERVAL, ({ getLocalSetting, getHelperDependency }) => {