@jupytergis/base 0.12.2 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/lib/commands/index.js +2 -6
  2. package/lib/dialogs/symbology/hooks/useEffectiveSymbologyParams.d.ts +16 -0
  3. package/lib/dialogs/symbology/hooks/useEffectiveSymbologyParams.js +24 -0
  4. package/lib/dialogs/symbology/hooks/useOkSignal.d.ts +6 -0
  5. package/lib/dialogs/symbology/hooks/useOkSignal.js +25 -0
  6. package/lib/dialogs/symbology/symbologyDialog.d.ts +4 -2
  7. package/lib/dialogs/symbology/symbologyDialog.js +6 -10
  8. package/lib/dialogs/symbology/symbologyUtils.d.ts +25 -2
  9. package/lib/dialogs/symbology/symbologyUtils.js +74 -4
  10. package/lib/dialogs/symbology/tiff_layer/TiffRendering.js +3 -3
  11. package/lib/dialogs/symbology/tiff_layer/types/MultibandColor.js +31 -34
  12. package/lib/dialogs/symbology/tiff_layer/types/SingleBandPseudoColor.js +68 -62
  13. package/lib/dialogs/symbology/vector_layer/VectorRendering.js +33 -21
  14. package/lib/dialogs/symbology/vector_layer/types/Canonical.js +23 -24
  15. package/lib/dialogs/symbology/vector_layer/types/Categorized.js +49 -50
  16. package/lib/dialogs/symbology/vector_layer/types/Graduated.js +53 -62
  17. package/lib/dialogs/symbology/vector_layer/types/Heatmap.js +35 -34
  18. package/lib/dialogs/symbology/vector_layer/types/SimpleSymbol.js +45 -47
  19. package/lib/formbuilder/objectform/StoryEditorForm.js +0 -17
  20. package/lib/formbuilder/objectform/baseform.d.ts +11 -0
  21. package/lib/formbuilder/objectform/baseform.js +72 -38
  22. package/lib/formbuilder/objectform/components/LayerSelect.d.ts +7 -0
  23. package/lib/formbuilder/objectform/components/LayerSelect.js +43 -0
  24. package/lib/formbuilder/objectform/components/OpacitySlider.d.ts +4 -0
  25. package/lib/formbuilder/objectform/components/OpacitySlider.js +40 -0
  26. package/lib/formbuilder/objectform/components/SegmentFormSymbology.d.ts +3 -0
  27. package/lib/formbuilder/objectform/components/SegmentFormSymbology.js +59 -0
  28. package/lib/formbuilder/objectform/layer/storySegmentLayerForm.d.ts +2 -2
  29. package/lib/formbuilder/objectform/layer/storySegmentLayerForm.js +19 -0
  30. package/lib/formbuilder/objectform/source/geojsonsource.js +1 -3
  31. package/lib/mainview/mainView.js +6 -1
  32. package/lib/panelview/rightpanel.d.ts +3 -1
  33. package/lib/panelview/rightpanel.js +2 -2
  34. package/lib/panelview/story-maps/StoryViewerPanel.d.ts +3 -1
  35. package/lib/panelview/story-maps/StoryViewerPanel.js +127 -19
  36. package/lib/shared/hooks/useLatest.d.ts +1 -0
  37. package/lib/shared/hooks/useLatest.js +8 -0
  38. package/lib/types.d.ts +1 -0
  39. package/lib/types.js +6 -1
  40. package/package.json +2 -2
  41. package/style/base.css +8 -0
  42. package/style/storyPanel.css +4 -4
@@ -10,6 +10,7 @@ import keybindings from '../keybindings.json';
10
10
  import { getSingleSelectedLayer } from '../processing/index';
11
11
  import { addProcessingCommands } from '../processing/processingCommands';
12
12
  import { getGeoJSONDataFromLayerSource, downloadFile } from '../tools';
13
+ import { SYMBOLOGY_VALID_LAYER_TYPES } from '../types';
13
14
  import { JupyterGISDocumentWidget } from '../widget';
14
15
  const POINT_SELECTION_TOOL_CLASS = 'jGIS-point-selection-tool';
15
16
  function loadKeybindings(commands, keybindings) {
@@ -70,12 +71,7 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
70
71
  if (!layer) {
71
72
  return false;
72
73
  }
73
- const isValidLayer = [
74
- 'VectorLayer',
75
- 'VectorTileLayer',
76
- 'WebGlLayer',
77
- 'HeatmapLayer',
78
- ].includes(layer.type);
74
+ const isValidLayer = SYMBOLOGY_VALID_LAYER_TYPES.includes(layer.type);
79
75
  return isValidLayer;
80
76
  }, execute: Private.createSymbologyDialog(tracker, state) }, icons.get(CommandIDs.symbology)));
81
77
  commands.addCommand(CommandIDs.redo, Object.assign({ label: trans.__('Redo'), isEnabled: () => {
@@ -0,0 +1,16 @@
1
+ import { IJGISLayer, IJupyterGISModel } from '@jupytergis/schema';
2
+ import { type IEffectiveSymbologyParams } from '../symbologyUtils';
3
+ export interface IUseEffectiveSymbologyParamsArgs {
4
+ model: IJupyterGISModel;
5
+ layerId: string | undefined;
6
+ layer: IJGISLayer | null | undefined;
7
+ isStorySegmentOverride?: boolean;
8
+ segmentId?: string;
9
+ }
10
+ /**
11
+ * Resolve the effective symbology params (layer.parameters or segment override)
12
+ * for the current dialog context. Pass a type parameter to narrow the return
13
+ * type for the layer kind this component uses (e.g. VectorSymbologyParams for
14
+ * vector symbology components).
15
+ */
16
+ export declare function useEffectiveSymbologyParams<T extends IEffectiveSymbologyParams = IEffectiveSymbologyParams>({ model, layerId, layer, isStorySegmentOverride, segmentId, }: IUseEffectiveSymbologyParamsArgs): T | null;
@@ -0,0 +1,24 @@
1
+ import { useMemo, useRef } from 'react';
2
+ import { getEffectiveSymbologyParams, } from '../symbologyUtils';
3
+ /**
4
+ * Resolve the effective symbology params (layer.parameters or segment override)
5
+ * for the current dialog context. Pass a type parameter to narrow the return
6
+ * type for the layer kind this component uses (e.g. VectorSymbologyParams for
7
+ * vector symbology components).
8
+ */
9
+ export function useEffectiveSymbologyParams({ model, layerId, layer, isStorySegmentOverride, segmentId, }) {
10
+ const result = useMemo(() => {
11
+ if (!layerId || !layer) {
12
+ return null;
13
+ }
14
+ return getEffectiveSymbologyParams(model, layerId, layer, isStorySegmentOverride, segmentId);
15
+ }, [model, layerId, layer, isStorySegmentOverride, segmentId]);
16
+ // Stabilize reference
17
+ const prevRef = useRef({ value: null, serialized: '' });
18
+ const serialized = result === null ? '' : JSON.stringify(result);
19
+ if (serialized === prevRef.current.serialized) {
20
+ return prevRef.current.value;
21
+ }
22
+ prevRef.current = { value: result, serialized };
23
+ return result;
24
+ }
@@ -0,0 +1,6 @@
1
+ import { Signal } from '@lumino/signaling';
2
+ type OkSignalPromise = {
3
+ promise: Promise<Signal<any, null>>;
4
+ };
5
+ export declare function useOkSignal(okSignalPromise: OkSignalPromise, handleOk: () => void): void;
6
+ export {};
@@ -0,0 +1,25 @@
1
+ import { useCallback, useEffect, useRef } from 'react';
2
+ export function useOkSignal(okSignalPromise, handleOk) {
3
+ const handleOkRef = useRef(handleOk);
4
+ useEffect(() => {
5
+ handleOkRef.current = handleOk;
6
+ }, [handleOk]);
7
+ const slot = useCallback(() => {
8
+ handleOkRef.current();
9
+ }, []);
10
+ useEffect(() => {
11
+ let disposed = false;
12
+ okSignalPromise.promise.then(okSignal => {
13
+ if (disposed) {
14
+ return;
15
+ }
16
+ okSignal.connect(slot);
17
+ });
18
+ return () => {
19
+ disposed = true;
20
+ okSignalPromise.promise.then(okSignal => {
21
+ okSignal.disconnect(slot);
22
+ });
23
+ };
24
+ }, [okSignalPromise, slot]);
25
+ }
@@ -6,10 +6,10 @@ import { Signal } from '@lumino/signaling';
6
6
  import { SymbologyTab, SymbologyValue } from "../../types";
7
7
  export interface ISymbologyDialogProps {
8
8
  model: IJupyterGISModel;
9
- state: IStateDB;
10
9
  okSignalPromise: PromiseDelegate<Signal<SymbologyWidget, null>>;
11
- cancel: () => void;
12
10
  layerId?: string;
11
+ isStorySegmentOverride?: boolean;
12
+ segmentId?: string;
13
13
  }
14
14
  export interface ISymbologyDialogWithAttributesProps extends ISymbologyDialogProps {
15
15
  selectableAttributesAndValues: Record<string, Set<any>>;
@@ -21,6 +21,8 @@ export type ISymbologyTabbedDialogWithAttributesProps = ISymbologyDialogWithAttr
21
21
  export interface ISymbologyWidgetOptions {
22
22
  model: IJupyterGISModel;
23
23
  state: IStateDB;
24
+ isStorySegmentOverride?: boolean;
25
+ segmentId?: string;
24
26
  }
25
27
  export interface IStopRow {
26
28
  stop: number;
@@ -4,7 +4,7 @@ import { Signal } from '@lumino/signaling';
4
4
  import React, { useEffect, useState } from 'react';
5
5
  import TiffRendering from './tiff_layer/TiffRendering';
6
6
  import VectorRendering from './vector_layer/VectorRendering';
7
- const SymbologyDialog = ({ model, state, okSignalPromise, cancel, }) => {
7
+ const SymbologyDialog = ({ model, okSignalPromise, isStorySegmentOverride, segmentId, }) => {
8
8
  const [selectedLayer, setSelectedLayer] = useState(null);
9
9
  const [componentToRender, setComponentToRender] = useState(null);
10
10
  let LayerSymbology;
@@ -37,10 +37,10 @@ const SymbologyDialog = ({ model, state, okSignalPromise, cancel, }) => {
37
37
  case 'VectorLayer':
38
38
  case 'VectorTileLayer':
39
39
  case 'HeatmapLayer':
40
- LayerSymbology = (React.createElement(VectorRendering, { model: model, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: selectedLayer }));
40
+ LayerSymbology = (React.createElement(VectorRendering, { model: model, okSignalPromise: okSignalPromise, layerId: selectedLayer, isStorySegmentOverride: isStorySegmentOverride, segmentId: segmentId }));
41
41
  break;
42
42
  case 'WebGlLayer':
43
- LayerSymbology = (React.createElement(TiffRendering, { model: model, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: selectedLayer }));
43
+ LayerSymbology = (React.createElement(TiffRendering, { model: model, okSignalPromise: okSignalPromise, layerId: selectedLayer, isStorySegmentOverride: isStorySegmentOverride, segmentId: segmentId }));
44
44
  break;
45
45
  default:
46
46
  LayerSymbology = React.createElement("div", null, "Layer Type Not Supported");
@@ -51,11 +51,8 @@ const SymbologyDialog = ({ model, state, okSignalPromise, cancel, }) => {
51
51
  };
52
52
  export class SymbologyWidget extends Dialog {
53
53
  constructor(options) {
54
- const cancelCallback = () => {
55
- this.resolve(0);
56
- };
57
54
  const okSignalPromise = new PromiseDelegate();
58
- const body = (React.createElement(SymbologyDialog, { model: options.model, okSignalPromise: okSignalPromise, cancel: cancelCallback, state: options.state }));
55
+ const body = (React.createElement(SymbologyDialog, { model: options.model, okSignalPromise: okSignalPromise, isStorySegmentOverride: options.isStorySegmentOverride, segmentId: options.segmentId }));
59
56
  super({ title: 'Symbology', body });
60
57
  this.id = 'jupytergis::symbologyWidget';
61
58
  this.okSignal = new Signal(this);
@@ -63,12 +60,11 @@ export class SymbologyWidget extends Dialog {
63
60
  this.addClass('jp-gis-symbology-dialog');
64
61
  }
65
62
  resolve(index) {
66
- if (index === 0) {
67
- super.resolve(index);
68
- }
69
63
  if (index === 1) {
64
+ // Emit signal to let symbology components save
70
65
  this.okSignal.emit(null);
71
66
  }
67
+ super.resolve(index);
72
68
  }
73
69
  }
74
70
  export default SymbologyWidget;
@@ -1,8 +1,31 @@
1
- import { IJGISLayer } from '@jupytergis/schema';
1
+ import { IJGISLayer, IJupyterGISModel, IVectorLayer, IWebGlLayer } from '@jupytergis/schema';
2
2
  import { ColorRampName } from './colorRampUtils';
3
3
  import { IStopRow } from './symbologyDialog';
4
+ /** Payload when saving symbology; shape matches vector or WebGl layer params. */
5
+ export interface ISymbologyPayload {
6
+ symbologyState: IVectorLayer['symbologyState'] | IWebGlLayer['symbologyState'];
7
+ color?: IVectorLayer['color'] | IWebGlLayer['color'];
8
+ }
9
+ export interface ISaveSymbologyOptions {
10
+ model: IJupyterGISModel;
11
+ layerId: string;
12
+ isStorySegmentOverride?: boolean;
13
+ segmentId?: string;
14
+ payload: ISymbologyPayload;
15
+ mutateLayerBeforeSave?: (layer: any) => void;
16
+ }
17
+ export type VectorSymbologyParams = Pick<IVectorLayer, 'symbologyState' | 'color'>;
18
+ export type WebGlSymbologyParams = Pick<IWebGlLayer, 'symbologyState' | 'color'>;
19
+ /** Params-shaped object used for reading symbology (layer.parameters or segment override). */
20
+ export type IEffectiveSymbologyParams = VectorSymbologyParams | WebGlSymbologyParams;
21
+ /**
22
+ * Resolve the effective symbology params for this dialog: either the layer's
23
+ * parameters or the matching segment override when editing a story-segment override.
24
+ */
25
+ export declare function getEffectiveSymbologyParams(model: IJupyterGISModel, layerId: string, layer: IJGISLayer | null | undefined, isStorySegmentOverride?: boolean, segmentId?: string): IEffectiveSymbologyParams | null;
26
+ export declare function saveSymbology(options: ISaveSymbologyOptions): void;
4
27
  export declare namespace VectorUtils {
5
- const buildColorInfo: (layer: IJGISLayer) => IStopRow[];
28
+ const buildColorInfo: (layerParamers: VectorSymbologyParams) => IStopRow[];
6
29
  const buildRadiusInfo: (layer: IJGISLayer) => IStopRow[];
7
30
  }
8
31
  export declare namespace Utils {
@@ -1,14 +1,84 @@
1
1
  import colormap from 'colormap';
2
2
  const COLOR_EXPR_STOPS_START = 3;
3
+ /**
4
+ * Resolve the effective symbology params for this dialog: either the layer's
5
+ * parameters or the matching segment override when editing a story-segment override.
6
+ */
7
+ export function getEffectiveSymbologyParams(model, layerId, layer, isStorySegmentOverride, segmentId) {
8
+ var _a, _b, _c;
9
+ if (!(layer === null || layer === void 0 ? void 0 : layer.parameters)) {
10
+ return null;
11
+ }
12
+ if (!isStorySegmentOverride) {
13
+ return layer.parameters;
14
+ }
15
+ if (!segmentId) {
16
+ return null;
17
+ }
18
+ const segment = model.getLayer(segmentId);
19
+ const override = (_b = (_a = segment === null || segment === void 0 ? void 0 : segment.parameters) === null || _a === void 0 ? void 0 : _a.layerOverride) === null || _b === void 0 ? void 0 : _b.find((override) => override.targetLayer === layerId);
20
+ if (!override.symbologyState) {
21
+ override.symbologyState = {};
22
+ }
23
+ return (_c = override) !== null && _c !== void 0 ? _c : null;
24
+ }
25
+ export function saveSymbology(options) {
26
+ const { model, layerId, isStorySegmentOverride, segmentId, payload, mutateLayerBeforeSave, } = options;
27
+ if (!isStorySegmentOverride) {
28
+ const layer = model.getLayer(layerId);
29
+ if (!(layer === null || layer === void 0 ? void 0 : layer.parameters)) {
30
+ return;
31
+ }
32
+ layer.parameters.symbologyState = payload.symbologyState;
33
+ if (payload.color !== undefined) {
34
+ layer.parameters.color = payload.color;
35
+ }
36
+ mutateLayerBeforeSave === null || mutateLayerBeforeSave === void 0 ? void 0 : mutateLayerBeforeSave(layer);
37
+ model.sharedModel.updateLayer(layerId, layer);
38
+ return;
39
+ }
40
+ if (!segmentId) {
41
+ return;
42
+ }
43
+ const segment = model.getLayer(segmentId);
44
+ if (!(segment === null || segment === void 0 ? void 0 : segment.parameters)) {
45
+ return;
46
+ }
47
+ if (!segment.parameters.layerOverride) {
48
+ segment.parameters.layerOverride = [];
49
+ }
50
+ // Find the override for the target layer (from the selected layer in the dialog)
51
+ const targetLayerId = model.selected
52
+ ? Object.keys(model.selected).find(id => { var _a; return id !== segmentId && ((_a = model.getLayer(id)) === null || _a === void 0 ? void 0 : _a.type) !== 'StorySegmentLayer'; })
53
+ : undefined;
54
+ if (!targetLayerId) {
55
+ return;
56
+ }
57
+ const overrides = segment.parameters.layerOverride;
58
+ let override = overrides.find((override) => override.targetLayer === targetLayerId);
59
+ if (!override) {
60
+ // Create new override entry
61
+ override = {
62
+ targetLayer: targetLayerId,
63
+ visible: true,
64
+ opacity: 1,
65
+ };
66
+ overrides.push(override);
67
+ }
68
+ override.symbologyState = payload.symbologyState;
69
+ if (payload.color !== undefined) {
70
+ override.color = payload.color;
71
+ }
72
+ model.sharedModel.updateLayer(segmentId, segment);
73
+ }
3
74
  export var VectorUtils;
4
75
  (function (VectorUtils) {
5
- VectorUtils.buildColorInfo = (layer) => {
6
- var _a;
76
+ VectorUtils.buildColorInfo = (layerParamers) => {
7
77
  // This it to parse a color object on the layer
8
- if (!((_a = layer.parameters) === null || _a === void 0 ? void 0 : _a.color)) {
78
+ if (!(layerParamers === null || layerParamers === void 0 ? void 0 : layerParamers.color)) {
9
79
  return [];
10
80
  }
11
- const color = layer.parameters.color;
81
+ const color = layerParamers.color;
12
82
  // If color is a string we don't need to parse
13
83
  if (typeof color === 'string') {
14
84
  return [];
@@ -1,7 +1,7 @@
1
1
  import React, { useEffect, useState } from 'react';
2
2
  import MultibandColor from './types/MultibandColor';
3
3
  import SingleBandPseudoColor from './types/SingleBandPseudoColor';
4
- const TiffRendering = ({ model, state, okSignalPromise, cancel, layerId, }) => {
4
+ const TiffRendering = ({ model, okSignalPromise, layerId, isStorySegmentOverride, segmentId, }) => {
5
5
  const renderTypes = ['Singleband Pseudocolor', 'Multiband Color'];
6
6
  const [selectedRenderType, setSelectedRenderType] = useState();
7
7
  const [componentToRender, setComponentToRender] = useState(null);
@@ -21,10 +21,10 @@ const TiffRendering = ({ model, state, okSignalPromise, cancel, layerId, }) => {
21
21
  }
22
22
  switch (selectedRenderType) {
23
23
  case 'Singleband Pseudocolor':
24
- RenderComponent = (React.createElement(SingleBandPseudoColor, { model: model, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: layerId }));
24
+ RenderComponent = (React.createElement(SingleBandPseudoColor, { model: model, okSignalPromise: okSignalPromise, layerId: layerId, isStorySegmentOverride: isStorySegmentOverride, segmentId: segmentId }));
25
25
  break;
26
26
  case 'Multiband Color':
27
- RenderComponent = (React.createElement(MultibandColor, { model: model, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: layerId }));
27
+ RenderComponent = (React.createElement(MultibandColor, { model: model, okSignalPromise: okSignalPromise, layerId: layerId, isStorySegmentOverride: isStorySegmentOverride, segmentId: segmentId }));
28
28
  break;
29
29
  default:
30
30
  RenderComponent = React.createElement("div", null, "Render Type Not Implemented (yet)");
@@ -1,13 +1,24 @@
1
- import React, { useEffect, useRef, useState } from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
2
  import useGetBandInfo from "../../hooks/useGetBandInfo";
3
+ import { useOkSignal } from "../../hooks/useOkSignal";
4
+ import { saveSymbology, } from "../../symbologyUtils";
3
5
  import BandRow from "../components/BandRow";
4
6
  import { LoadingOverlay } from "../../../../shared/components/loading";
5
- const MultibandColor = ({ model, okSignalPromise, cancel, layerId, }) => {
7
+ import { useLatest } from "../../../../shared/hooks/useLatest";
8
+ import { useEffectiveSymbologyParams } from '../../hooks/useEffectiveSymbologyParams';
9
+ const MultibandColor = ({ model, okSignalPromise, layerId, isStorySegmentOverride, segmentId, }) => {
6
10
  if (!layerId) {
7
11
  return;
8
12
  }
9
13
  const layer = model.getLayer(layerId);
10
- if (!(layer === null || layer === void 0 ? void 0 : layer.parameters)) {
14
+ const params = useEffectiveSymbologyParams({
15
+ model,
16
+ layerId: layerId,
17
+ layer,
18
+ isStorySegmentOverride,
19
+ segmentId,
20
+ });
21
+ if (!params || !layer) {
11
22
  return;
12
23
  }
13
24
  const { bandRows, setBandRows, loading } = useGetBandInfo(model, layer);
@@ -17,33 +28,14 @@ const MultibandColor = ({ model, okSignalPromise, cancel, layerId, }) => {
17
28
  blue: 3,
18
29
  alpha: 4,
19
30
  });
20
- const numOfBandsRef = useRef(0);
21
- const selectedBandsRef = useRef({
22
- red: selectedBands.red,
23
- green: selectedBands.green,
24
- blue: selectedBands.blue,
25
- alpha: selectedBands.alpha,
26
- });
31
+ const numOfBandsRef = useLatest(bandRows.length);
32
+ const selectedBandsRef = useLatest(selectedBands);
27
33
  useEffect(() => {
28
34
  populateOptions();
29
- okSignalPromise.promise.then(okSignal => {
30
- okSignal.connect(handleOk);
31
- });
32
- return () => {
33
- okSignalPromise.promise.then(okSignal => {
34
- okSignal.disconnect(handleOk, this);
35
- });
36
- };
37
35
  }, []);
38
- useEffect(() => {
39
- numOfBandsRef.current = bandRows.length;
40
- }, [bandRows]);
41
- useEffect(() => {
42
- selectedBandsRef.current = selectedBands;
43
- }, [selectedBands]);
44
36
  const populateOptions = async () => {
45
37
  var _a, _b, _c, _d, _e, _f, _g, _h;
46
- const layerParams = layer.parameters;
38
+ const layerParams = params;
47
39
  const red = (_b = (_a = layerParams.symbologyState) === null || _a === void 0 ? void 0 : _a.redBand) !== null && _b !== void 0 ? _b : 1;
48
40
  const green = (_d = (_c = layerParams.symbologyState) === null || _c === void 0 ? void 0 : _c.greenBand) !== null && _d !== void 0 ? _d : 2;
49
41
  const blue = (_f = (_e = layerParams.symbologyState) === null || _e === void 0 ? void 0 : _e.blueBand) !== null && _f !== void 0 ? _f : 3;
@@ -54,10 +46,6 @@ const MultibandColor = ({ model, okSignalPromise, cancel, layerId, }) => {
54
46
  setSelectedBands(prevBands => (Object.assign(Object.assign({}, prevBands), { [color]: value })));
55
47
  };
56
48
  const handleOk = () => {
57
- // Update layer
58
- if (!layer.parameters) {
59
- return;
60
- }
61
49
  const colorExpr = ['array'];
62
50
  const colors = ['red', 'green', 'blue'];
63
51
  colors.forEach(color => {
@@ -78,12 +66,21 @@ const MultibandColor = ({ model, okSignalPromise, cancel, layerId, }) => {
78
66
  blueBand: selectedBandsRef.current.blue,
79
67
  alphaBand: selectedBandsRef.current.alpha,
80
68
  };
81
- layer.parameters.symbologyState = symbologyState;
82
- layer.parameters.color = colorExpr;
83
- layer.type = 'WebGlLayer';
84
- model.sharedModel.updateLayer(layerId, layer);
85
- cancel();
69
+ saveSymbology({
70
+ model,
71
+ layerId,
72
+ isStorySegmentOverride,
73
+ segmentId,
74
+ payload: {
75
+ symbologyState,
76
+ color: colorExpr,
77
+ },
78
+ mutateLayerBeforeSave: targetLayer => {
79
+ targetLayer.type = 'WebGlLayer';
80
+ },
81
+ });
86
82
  };
83
+ useOkSignal(okSignalPromise, handleOk);
87
84
  return (React.createElement("div", { className: "jp-gis-layer-symbology-container" },
88
85
  React.createElement("div", { className: "jp-gis-band-container" },
89
86
  React.createElement(LoadingOverlay, { loading: loading }),