Skip to content

Commit

Permalink
Add before layer id when adding documents label (#387) (#388)
Browse files Browse the repository at this point in the history
Signed-off-by: Junqiu Lei <junqiu@amazon.com>
(cherry picked from commit e21cd6c)

Co-authored-by: Junqiu Lei <junqiu@amazon.com>
  • Loading branch information
opensearch-trigger-bot[bot] and junqiu-lei committed Apr 10, 2023
1 parent c24d7d1 commit 85d7c94
Show file tree
Hide file tree
Showing 14 changed files with 203 additions and 111 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
* Update draw filter shape ui properties ([#372](https://github.com/opensearch-project/dashboards-maps/pull/372))
* Add filter bar to display global geospatial filters ([#371](https://github.com/opensearch-project/dashboards-maps/pull/371))
* Change font opacity along with OpenSearch base map layer ([#373](https://github.com/opensearch-project/dashboards-maps/pull/373))
* Add before layer id when adding documents label ([#387](https://github.com/opensearch-project/dashboards-maps/pull/387))

### Bug Fixes
* Fix property value undefined check ([#276](https://github.com/opensearch-project/dashboards-maps/pull/276))
Expand Down
2 changes: 1 addition & 1 deletion common/map_saved_object_attributes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { SavedObjectAttributes } from 'opensearch-dashboards/server';
import { SavedObjectAttributes } from '../../../src/core/types';

export interface MapSavedObjectAttributes extends SavedObjectAttributes {
/** Title of the map */
Expand Down
1 change: 0 additions & 1 deletion public/components/layer_config/layer_config_panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ export const LayerConfigPanel = ({
updateLayer();
closeLayerConfigPanel(false);
setOriginLayerConfig(null);
setSelectedLayerConfig(undefined);
if (isNewLayer) {
setIsNewLayer(false);
}
Expand Down
5 changes: 1 addition & 4 deletions public/components/layer_control_panel/hide_layer_button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,15 @@

import { EuiButtonIcon, EuiFlexItem } from '@elastic/eui';
import React, { useState } from 'react';
import { Map as Maplibre } from 'maplibre-gl';
import {
LAYER_PANEL_HIDE_LAYER_ICON,
LAYER_PANEL_SHOW_LAYER_ICON,
LAYER_VISIBILITY,
} from '../../../common';
import { MapLayerSpecification } from '../../model/mapLayerType';
import { updateLayerVisibilityHandler } from '../../model/map/layer_operations';
import { MaplibreRef } from '../../model/layersFunctions';

interface MaplibreRef {
current: Maplibre | null;
}
interface HideLayerProps {
layer: MapLayerSpecification;
maplibreRef: MaplibreRef;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ import {
EuiToolTip,
} from '@elastic/eui';
import { I18nProvider } from '@osd/i18n/react';
import { Map as Maplibre } from 'maplibre-gl';
import './layer_control_panel.scss';
import { isEqual } from 'lodash';
import { i18n } from '@osd/i18n';
import { MaplibreRef } from 'public/model/layersFunctions';
import { IndexPattern } from '../../../../../src/plugins/data/public';
import { AddLayerPanel } from '../add_layer_panel';
import { LayerConfigPanel } from '../layer_config';
Expand All @@ -38,10 +38,6 @@ import { moveLayers, removeLayers } from '../../model/map/layer_operations';
import { DeleteLayerModal } from './delete_layer_modal';
import { HideLayer } from './hide_layer_button';

interface MaplibreRef {
current: Maplibre | null;
}

interface Props {
maplibreRef: MaplibreRef;
setLayers: (layers: MapLayerSpecification[]) => void;
Expand Down
1 change: 1 addition & 0 deletions public/components/map_container/map_container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ export const MapContainer = ({
maplibreRef
);
}
setSelectedLayerConfig(undefined);
} else {
renderDataLayers(layers, mapState, services, maplibreRef, dashboardProps);
renderBaseLayers(layers, maplibreRef);
Expand Down
7 changes: 2 additions & 5 deletions public/model/OSMLayerFunctions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Map as Maplibre, LayerSpecification, SymbolLayerSpecification } from 'maplibre-gl';
import { LayerSpecification, SymbolLayerSpecification } from 'maplibre-gl';
import { OSMLayerSpecification } from './mapLayerType';
import {
addOSMLayerSource,
Expand All @@ -9,10 +9,7 @@ import {
updateOSMStyleLayer,
} from './map/layer_operations';
import { getMapLanguage } from '../../common/util';

interface MaplibreRef {
current: Maplibre | null;
}
import { MaplibreRef } from './layersFunctions';

// Fetch style layers from OpenSearch vector tile service
const fetchStyleLayers = (url: string) => {
Expand Down
7 changes: 2 additions & 5 deletions public/model/customLayerFunctions.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import { Map as Maplibre, AttributionControl, RasterSourceSpecification } from 'maplibre-gl';
import { AttributionControl, RasterSourceSpecification } from 'maplibre-gl';
import { CustomLayerSpecification, OSMLayerSpecification } from './mapLayerType';
import { hasLayer, removeLayers } from './map/layer_operations';

interface MaplibreRef {
current: Maplibre | null;
}
import { MaplibreRef } from './layersFunctions';

const updateLayerConfig = (layerConfig: CustomLayerSpecification, maplibreRef: MaplibreRef) => {
const maplibreInstance = maplibreRef.current;
Expand Down
8 changes: 3 additions & 5 deletions public/model/documentLayerFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { Map as Maplibre } from 'maplibre-gl';
import { parse } from 'wellknown';
import { DocumentLayerSpecification } from './mapLayerType';
import { convertGeoPointToGeoJSON, isGeoJSON } from '../utils/geo_formater';
Expand All @@ -21,10 +20,8 @@ import {
removeSymbolLayer,
createSymbolLayerSpecification,
} from './map/layer_operations';
import { getMaplibreAboveLayerId, MaplibreRef } from './layersFunctions';

interface MaplibreRef {
current: Maplibre | null;
}
// https://opensearch.org/docs/1.3/opensearch/supported-field-types/geo-shape
const openSearchGeoJSONMap = new Map<string, string>([
['point', 'Point'],
Expand Down Expand Up @@ -227,7 +224,8 @@ const renderLabelLayer = (layerConfig: DocumentLayerSpecification, maplibreRef:
if (hasLabelLayer) {
updateSymbolLayer(maplibreRef.current!, symbolLayerSpec);
} else {
addSymbolLayer(maplibreRef.current!, symbolLayerSpec);
const beforeLayerId = getMaplibreAboveLayerId(layerConfig.id, maplibreRef.current!);
addSymbolLayer(maplibreRef.current!, symbolLayerSpec, beforeLayerId);
}
} else {
// If the label set to disabled, remove the label layer if it exists
Expand Down
6 changes: 1 addition & 5 deletions public/model/layerRenderController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,13 @@ import {
Query,
TimeRange,
} from '../../../../src/plugins/data/common';
import { getBaseLayers, getDataLayers, layersFunctionMap } from './layersFunctions';
import { getBaseLayers, getDataLayers, layersFunctionMap, MaplibreRef } from './layersFunctions';
import { MapServices } from '../types';
import { MapState } from './mapState';
import { GeoBounds, getBounds } from './map/boundary';
import { buildBBoxFilter, buildGeoShapeFilter } from './geo/filter';
import { DashboardProps } from '../components/map_page/map_page';

interface MaplibreRef {
current: Maplibre | null;
}

interface MapGlobalStates {
timeRange: TimeRange;
query: Query;
Expand Down
105 changes: 105 additions & 0 deletions public/model/layersFunction.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import {
baseLayerTypeLookup,
getBaseLayers,
getDataLayers,
getMaplibreAboveLayerId,
layersFunctionMap,
layersTypeIconMap,
layersTypeNameMap,
} from './layersFunctions';
import { MapLayerSpecification } from './mapLayerType';
import { OSMLayerFunctions } from './OSMLayerFunctions';
import { DocumentLayerFunctions } from './documentLayerFunctions';
import { CustomLayerFunctions } from './customLayerFunctions';
import { MockMaplibreMap } from './map/__mocks__/map';
import { MockLayer } from './map/__mocks__/layer';
import { Map as Maplibre } from 'maplibre-gl';

describe('getDataLayers', () => {
it('should return an array of DataLayerSpecification objects', () => {
const layers = [
{ type: 'opensearch_vector_tile_map', name: 'layer1' },
{ type: 'custom_map', name: 'layer2' },
{ type: 'documents', name: 'layer3' },
{ type: 'opensearch_vector_tile_map', name: 'layer4' },
{ type: 'custom_map', name: 'layer5' },
] as unknown as MapLayerSpecification[];
const dataLayers = getDataLayers(layers);
expect(dataLayers).toHaveLength(1);
expect(dataLayers[0].name).toBe('layer3');
});
});

describe('getBaseLayers', () => {
it('should return an array of BaseLayerSpecification objects', () => {
const layers = [
{ type: 'opensearch_vector_tile_map', name: 'layer1' },
{ type: 'custom_map', name: 'layer2' },
{ type: 'documents', name: 'layer3' },
{ type: 'opensearch_vector_tile_map', name: 'layer4' },
{ type: 'custom_map', name: 'layer5' },
] as unknown as MapLayerSpecification[];
const baseLayers = getBaseLayers(layers);
expect(baseLayers).toHaveLength(4);
expect(baseLayers[0].name).toBe('layer1');
expect(baseLayers[1].name).toBe('layer2');
expect(baseLayers[2].name).toBe('layer4');
expect(baseLayers[3].name).toBe('layer5');
});
});

describe('Exported objects', () => {
it('should have the correct values assigned to their keys', () => {
expect(layersFunctionMap).toEqual({
opensearch_vector_tile_map: OSMLayerFunctions,
documents: DocumentLayerFunctions,
custom_map: CustomLayerFunctions,
});

expect(layersTypeNameMap).toEqual({
opensearch_vector_tile_map: 'OpenSearch map',
documents: 'Documents',
custom_map: 'Custom map',
});

expect(layersTypeIconMap).toEqual({
opensearch_vector_tile_map: 'globe',
documents: 'document',
custom_map: 'globe',
});

expect(baseLayerTypeLookup).toEqual({
opensearch_vector_tile_map: true,
custom_map: true,
documents: false,
});
});
});

describe('getMaplibreAboveLayerId', () => {
const mockMapLayer1Id = 'layer-1';
const mockMapLayer2Id = 'layer-2';
const mockMbLayer1: MockLayer = new MockLayer(`${mockMapLayer1Id}-1`);
const mockMbLayer2: MockLayer = new MockLayer(`${mockMapLayer1Id}-2`);
const mockMbLayer3: MockLayer = new MockLayer(`${mockMapLayer2Id}-1`);
const mockMap = new MockMaplibreMap([
mockMbLayer1,
mockMbLayer2,
mockMbLayer3,
]) as unknown as Maplibre;

it('should return the id of the layer above the given mapLayerId', () => {
const aboveLayerId = getMaplibreAboveLayerId(mockMapLayer1Id, mockMap);
expect(aboveLayerId).toBe(`${mockMapLayer2Id}-1`);
});

it('should return undefined if there is no layer above the given mapLayerId', () => {
const aboveLayerId = getMaplibreAboveLayerId(mockMapLayer2Id, mockMap);
expect(aboveLayerId).toBeUndefined();
});

it('should return undefined if the given mapLayerId is not found', () => {
const aboveLayerId = getMaplibreAboveLayerId('undefined-layer', mockMap);
expect(aboveLayerId).toBeUndefined();
});
});
44 changes: 15 additions & 29 deletions public/model/layersFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,7 @@ import {
import { CustomLayerFunctions } from './customLayerFunctions';
import { getLayers } from './map/layer_operations';

interface MaplibreRef {
current: Maplibre | null;
}

interface MaplibreRef {
export interface MaplibreRef {
current: Maplibre | null;
}

Expand All @@ -39,21 +35,6 @@ export const layersTypeNameMap: { [key: string]: string } = {
[DASHBOARDS_MAPS_LAYER_TYPE.CUSTOM_MAP]: DASHBOARDS_MAPS_LAYER_NAME.CUSTOM_MAP,
};

export const getMaplibreBeforeLayerId = (
selectedLayer: MapLayerSpecification,
maplibreRef: MaplibreRef,
beforeLayerId: string | undefined
): string | undefined => {
const currentLoadedMbLayers = getLayers(maplibreRef.current!);
if (beforeLayerId) {
const beforeMbLayer = currentLoadedMbLayers.find((mbLayer) =>
mbLayer.id.includes(beforeLayerId)
);
return beforeMbLayer?.id;
}
return undefined;
};

export const layersTypeIconMap: { [key: string]: string } = {
[DASHBOARDS_MAPS_LAYER_TYPE.OPENSEARCH_MAP]: DASHBOARDS_MAPS_LAYER_ICON.OPENSEARCH_MAP,
[DASHBOARDS_MAPS_LAYER_TYPE.DOCUMENTS]: DASHBOARDS_MAPS_LAYER_ICON.DOCUMENTS,
Expand All @@ -74,15 +55,20 @@ export const getBaseLayers = (layers: MapLayerSpecification[]): BaseLayerSpecifi
return layers.filter((layer) => baseLayerTypeLookup[layer.type]) as BaseLayerSpecification[];
};

// Get layer id from layers that is above the selected layer
export const getMapBeforeLayerId = (
layers: MapLayerSpecification[],
selectedLayerId: string
export const getMaplibreAboveLayerId = (
mapLayerId: string,
maplibre: Maplibre
): string | undefined => {
const selectedLayerIndex = layers.findIndex((layer) => layer.id === selectedLayerId);
const beforeLayers = layers.slice(selectedLayerIndex + 1);
if (beforeLayers.length === 0) {
return undefined;
const currentLoadedMbLayers = getLayers(maplibre);
const matchingMbLayers = currentLoadedMbLayers.filter((mbLayer) =>
mbLayer.id.includes(mapLayerId)
);
if (matchingMbLayers.length > 0) {
const highestMbLayerIndex = currentLoadedMbLayers.indexOf(
matchingMbLayers[matchingMbLayers.length - 1]
);
const aboveMbLayer = currentLoadedMbLayers[highestMbLayerIndex + 1];
return aboveMbLayer?.id;
}
return beforeLayers[0]?.id;
return undefined;
};
Loading

0 comments on commit 85d7c94

Please sign in to comment.