From 8d25b2bbdabbed953cc00ac502c20c86a3bf633a Mon Sep 17 00:00:00 2001 From: Junqiu Lei Date: Tue, 21 Feb 2023 13:20:39 -0800 Subject: [PATCH] Refactor data handler into parent component (#271) Signed-off-by: Junqiu Lei --- .../document_layer_config_panel.tsx | 6 +- .../layer_config/layer_config_panel.tsx | 4 + .../layer_control_panel.tsx | 95 ++------------- .../map_container/map_container.tsx | 112 +++++++++++++----- public/components/map_page/map_page.tsx | 18 +-- .../components/map_top_nav/top_nav_menu.tsx | 13 +- public/embeddable/map_component.tsx | 2 +- public/model/layerRenderController.ts | 7 +- public/model/layersFunctions.ts | 21 ++++ 9 files changed, 146 insertions(+), 132 deletions(-) diff --git a/public/components/layer_config/documents_config/document_layer_config_panel.tsx b/public/components/layer_config/documents_config/document_layer_config_panel.tsx index 2a99abac..febf8793 100644 --- a/public/components/layer_config/documents_config/document_layer_config_panel.tsx +++ b/public/components/layer_config/documents_config/document_layer_config_panel.tsx @@ -55,7 +55,7 @@ export const DocumentLayerConfigPanel = (props: Props) => { ), - testSubj: 'dataTab', + testsubj: 'dataTab', }, { id: 'style--id', @@ -66,7 +66,7 @@ export const DocumentLayerConfigPanel = (props: Props) => { ), - testSubj: 'styleTab', + testsubj: 'styleTab', }, { id: 'settings--id', @@ -77,7 +77,7 @@ export const DocumentLayerConfigPanel = (props: Props) => { ), - testSubj: 'settingsTab', + testsubj: 'settingsTab', }, ]; return ; diff --git a/public/components/layer_config/layer_config_panel.tsx b/public/components/layer_config/layer_config_panel.tsx index 4dc9cc9f..52c8c146 100644 --- a/public/components/layer_config/layer_config_panel.tsx +++ b/public/components/layer_config/layer_config_panel.tsx @@ -42,6 +42,7 @@ interface Props { isLayerExists: Function; originLayerConfig: MapLayerSpecification | null; setOriginLayerConfig: Function; + setIsUpdatingLayerRender: (isUpdatingLayerRender: boolean) => void; } export const LayerConfigPanel = ({ @@ -55,6 +56,7 @@ export const LayerConfigPanel = ({ isLayerExists, originLayerConfig, setOriginLayerConfig, + setIsUpdatingLayerRender, }: Props) => { const [isUpdateDisabled, setIsUpdateDisabled] = useState(false); const [unsavedModalVisible, setUnsavedModalVisible] = useState(false); @@ -84,9 +86,11 @@ export const LayerConfigPanel = ({ } }; const onUpdate = () => { + setIsUpdatingLayerRender(true); updateLayer(); closeLayerConfigPanel(false); setOriginLayerConfig(null); + setSelectedLayerConfig(undefined); if (isNewLayer) { setIsNewLayer(false); } diff --git a/public/components/layer_control_panel/layer_control_panel.tsx b/public/components/layer_control_panel/layer_control_panel.tsx index 65b5761c..3a290c77 100644 --- a/public/components/layer_control_panel/layer_control_panel.tsx +++ b/public/components/layer_control_panel/layer_control_panel.tsx @@ -34,13 +34,8 @@ import { LAYER_PANEL_SHOW_LAYER_ICON, LAYER_VISIBILITY, } from '../../../common'; -import { referenceLayerTypeLookup } from '../../model/layersFunctions'; import { useOpenSearchDashboards } from '../../../../../src/plugins/opensearch_dashboards_react/public'; import { MapServices } from '../../types'; -import { - handleDataLayerRender, - handleReferenceLayerRender, -} from '../../model/layerRenderController'; import { MapState } from '../../model/mapState'; import { ConfigSchema } from '../../../common/config'; import { moveLayers, removeLayers, updateLayerVisibility } from '../../model/map/layer_operations'; @@ -59,7 +54,10 @@ interface Props { mapState: MapState; zoom: number; mapConfig: ConfigSchema; - inDashboardMode: boolean; + isReadOnlyMode: boolean; + selectedLayerConfig: MapLayerSpecification | undefined; + setSelectedLayerConfig: (layerConfig: MapLayerSpecification | undefined) => void; + setIsUpdatingLayerRender: (isUpdatingLayerRender: boolean) => void; } export const LayerControlPanel = memo( @@ -67,26 +65,17 @@ export const LayerControlPanel = memo( maplibreRef, setLayers, layers, - layersIndexPatterns, - setLayersIndexPatterns, - mapState, zoom, mapConfig, - inDashboardMode, + isReadOnlyMode, + selectedLayerConfig, + setSelectedLayerConfig, + setIsUpdatingLayerRender, }: Props) => { const { services } = useOpenSearchDashboards(); - const { - data: { indexPatterns }, - notifications, - } = services; const [isLayerConfigVisible, setIsLayerConfigVisible] = useState(false); const [isLayerControlVisible, setIsLayerControlVisible] = useState(true); - const [selectedLayerConfig, setSelectedLayerConfig] = useState< - MapLayerSpecification | undefined - >(); - const [initialLayersLoaded, setInitialLayersLoaded] = useState(false); - const [isUpdatingLayerRender, setIsUpdatingLayerRender] = useState(false); const [isNewLayer, setIsNewLayer] = useState(false); const [isDeleteLayerModalVisible, setIsDeleteLayerModalVisible] = useState(false); const [originLayerConfig, setOriginLayerConfig] = useState(null); @@ -95,39 +84,6 @@ export const LayerControlPanel = memo( >(); const [visibleLayers, setVisibleLayers] = useState([]); - useEffect(() => { - if (!isUpdatingLayerRender && initialLayersLoaded) { - return; - } - if (layers.length <= 0) { - return; - } - - if (initialLayersLoaded) { - if (!selectedLayerConfig) { - return; - } - if (referenceLayerTypeLookup[selectedLayerConfig.type]) { - handleReferenceLayerRender(selectedLayerConfig, maplibreRef, undefined); - } else { - updateIndexPatterns(); - handleDataLayerRender(selectedLayerConfig, mapState, services, maplibreRef, undefined); - } - setSelectedLayerConfig(undefined); - } else { - layers.forEach((layer) => { - const beforeLayerId = getMapBeforeLayerId(layer); - if (referenceLayerTypeLookup[layer.type]) { - handleReferenceLayerRender(layer, maplibreRef, beforeLayerId); - } else { - handleDataLayerRender(layer, mapState, services, maplibreRef, beforeLayerId); - } - }); - setInitialLayersLoaded(true); - } - setIsUpdatingLayerRender(false); - }, [layers]); - useEffect(() => { const getCurrentVisibleLayers = () => { return layers.filter( @@ -138,16 +94,6 @@ export const LayerControlPanel = memo( setVisibleLayers(getCurrentVisibleLayers()); }, [layers, zoom]); - // Get layer id from layers that is above the selected layer - function getMapBeforeLayerId(selectedLayer: MapLayerSpecification): string | undefined { - const selectedLayerIndex = layers.findIndex((layer) => layer.id === selectedLayer.id); - const beforeLayers = layers.slice(selectedLayerIndex + 1); - if (beforeLayers.length === 0) { - return undefined; - } - return beforeLayers[0]?.id; - } - const closeLayerConfigPanel = () => { setIsLayerConfigVisible(false); setTimeout(() => { @@ -178,7 +124,6 @@ export const LayerControlPanel = memo( }; } setLayers(layersClone); - setIsUpdatingLayerRender(true); }; const removeLayer = (layerId: string) => { @@ -199,7 +144,7 @@ export const LayerControlPanel = memo( const onClickLayerName = (layer: MapLayerSpecification) => { if (hasUnsavedChanges()) { - notifications.toasts.addWarning( + services.toastNotifications.addWarning( `You have unsaved changes for ${selectedLayerConfig?.name}` ); } else { @@ -261,25 +206,6 @@ export const LayerControlPanel = memo( return layersClone.reverse(); }; - const updateIndexPatterns = async () => { - if (!selectedLayerConfig) { - return; - } - if (referenceLayerTypeLookup[selectedLayerConfig.type]) { - return; - } - const findIndexPattern = layersIndexPatterns.find( - // @ts-ignore - (indexPattern) => indexPattern.id === selectedLayerConfig.source.indexPatternId - ); - if (!findIndexPattern) { - // @ts-ignore - const newIndexPattern = await indexPatterns.get(selectedLayerConfig.source.indexPatternId); - const cloneLayersIndexPatterns = [...layersIndexPatterns, newIndexPattern]; - setLayersIndexPatterns(cloneLayersIndexPatterns); - } - }; - const onLayerVisibilityChange = (layer: MapLayerSpecification) => { if (layer.visibility === LAYER_VISIBILITY.VISIBLE) { layer.visibility = LAYER_VISIBILITY.NONE; @@ -322,7 +248,7 @@ export const LayerControlPanel = memo( return visibleLayers.includes(layer); }; - if (inDashboardMode) { + if (isReadOnlyMode) { return null; } @@ -480,6 +406,7 @@ export const LayerControlPanel = memo( isLayerExists={isLayerExists} originLayerConfig={originLayerConfig} setOriginLayerConfig={setOriginLayerConfig} + setIsUpdatingLayerRender={setIsUpdatingLayerRender} /> )} void; @@ -35,11 +43,13 @@ interface MapContainerProps { maplibreRef: React.MutableRefObject; mapState: MapState; mapConfig: ConfigSchema; - inDashboardMode: boolean; + isReadOnlyMode: boolean; timeRange?: TimeRange; refreshConfig?: RefreshInterval; filters?: Filter[]; query?: Query; + isUpdatingLayerRender: boolean; + setIsUpdatingLayerRender: (isUpdatingLayerRender: boolean) => void; } export const MapContainer = ({ @@ -50,17 +60,22 @@ export const MapContainer = ({ maplibreRef, mapState, mapConfig, - inDashboardMode, + isReadOnlyMode, timeRange, refreshConfig, filters, query, + isUpdatingLayerRender, + setIsUpdatingLayerRender, }: MapContainerProps) => { const { services } = useOpenSearchDashboards(); const mapContainer = useRef(null); const [mounted, setMounted] = useState(false); const [zoom, setZoom] = useState(MAP_INITIAL_STATE.zoom); const [coordinates, setCoordinates] = useState(); + const [selectedLayerConfig, setSelectedLayerConfig] = useState< + MapLayerSpecification | undefined + >(); useEffect(() => { if (!mapContainer.current) return; @@ -93,7 +108,7 @@ export const MapContainer = ({ let resizeChecker: ResizeChecker; if (mapContainerElement) { resizeChecker = new ResizeChecker(mapContainerElement); - if (inDashboardMode) { + if (isReadOnlyMode) { resizeChecker.on( 'resize', throttle(() => { @@ -206,25 +221,6 @@ export const MapContainer = ({ }; }, [layers, mapState, services]); - // Update data layers when state bar time range, filters and query changes - useEffect(() => { - layers.forEach((layer: MapLayerSpecification) => { - if (referenceLayerTypeLookup[layer.type]) { - return; - } - handleDataLayerRender( - layer, - mapState, - services, - maplibreRef, - undefined, - timeRange, - filters, - query - ); - }); - }, [timeRange, mapState, filters]); - // Update data layers when state bar enable auto refresh useEffect(() => { let intervalId: NodeJS.Timeout | undefined; @@ -241,6 +237,65 @@ export const MapContainer = ({ return () => clearInterval(intervalId); }, [refreshConfig]); + useEffect(() => { + if (!mounted) { + return; + } + + if (layers.length <= 0) { + return; + } + + if (isUpdatingLayerRender || isReadOnlyMode) { + if (selectedLayerConfig) { + if (referenceLayerTypeLookup[selectedLayerConfig.type]) { + handleReferenceLayerRender(selectedLayerConfig, maplibreRef, undefined); + } else { + updateIndexPatterns(); + handleDataLayerRender(selectedLayerConfig, mapState, services, maplibreRef, undefined); + } + } else { + getDataLayers(layers).forEach((layer: MapLayerSpecification) => { + const beforeLayerId = getMapBeforeLayerId(layers, layer.id); + handleDataLayerRender( + layer, + mapState, + services, + maplibreRef, + beforeLayerId, + timeRange, + filters, + query + ); + }); + getReferenceLayers(layers).forEach((layer: MapLayerSpecification) => { + const beforeLayerId = getMapBeforeLayerId(layers, layer.id); + handleReferenceLayerRender(layer, maplibreRef, beforeLayerId); + }); + } + setIsUpdatingLayerRender(false); + } + }, [layers, mounted, timeRange, filters, query, mapState, isReadOnlyMode]); + + const updateIndexPatterns = async () => { + if (!selectedLayerConfig) { + return; + } + if (referenceLayerTypeLookup[selectedLayerConfig.type]) { + return; + } + const findIndexPattern = layersIndexPatterns.find( + // @ts-ignore + (indexPattern) => indexPattern.id === selectedLayerConfig.source.indexPatternId + ); + if (!findIndexPattern) { + // @ts-ignore + const newIndexPattern = await indexPatterns.get(selectedLayerConfig.source.indexPatternId); + const cloneLayersIndexPatterns = [...layersIndexPatterns, newIndexPattern]; + setLayersIndexPatterns(cloneLayersIndexPatterns); + } + }; + return (
)}
diff --git a/public/components/map_page/map_page.tsx b/public/components/map_page/map_page.tsx index 0151d9a0..f6726825 100644 --- a/public/components/map_page/map_page.tsx +++ b/public/components/map_page/map_page.tsx @@ -37,7 +37,7 @@ interface MapComponentProps { mapConfig: ConfigSchema; mapIdFromSavedObject: string; timeRange?: TimeRange; - inDashboardMode: boolean; + isReadOnlyMode: boolean; refreshConfig?: RefreshInterval; filters?: Filter[]; query?: Query; @@ -46,7 +46,7 @@ export const MapComponent = ({ mapIdFromSavedObject, mapConfig, timeRange, - inDashboardMode, + isReadOnlyMode, refreshConfig, filters, query, @@ -61,6 +61,7 @@ export const MapComponent = ({ const [layersIndexPatterns, setLayersIndexPatterns] = useState([]); const maplibreRef = useRef(null); const [mapState, setMapState] = useState(getInitialMapState()); + const [isUpdatingLayerRender, setIsUpdatingLayerRender] = useState(true); useEffect(() => { if (mapIdFromSavedObject) { @@ -91,10 +92,10 @@ export const MapComponent = ({ return (
- {inDashboardMode ? null : ( + {isReadOnlyMode ? null : ( )} @@ -113,11 +115,13 @@ export const MapComponent = ({ maplibreRef={maplibreRef} mapState={mapState} mapConfig={mapConfig} - inDashboardMode={inDashboardMode} + isReadOnlyMode={isReadOnlyMode} timeRange={timeRange} refreshConfig={refreshConfig} filters={filters} query={query} + isUpdatingLayerRender={isUpdatingLayerRender} + setIsUpdatingLayerRender={setIsUpdatingLayerRender} />
); @@ -125,7 +129,5 @@ export const MapComponent = ({ export const MapPage = ({ mapConfig }: MapPageProps) => { const { id: mapId } = useParams<{ id: string }>(); - return ( - - ); + return ; }; diff --git a/public/components/map_top_nav/top_nav_menu.tsx b/public/components/map_top_nav/top_nav_menu.tsx index b5b9a184..7d688b51 100644 --- a/public/components/map_top_nav/top_nav_menu.tsx +++ b/public/components/map_top_nav/top_nav_menu.tsx @@ -24,21 +24,23 @@ interface MapTopNavMenuProps { maplibreRef: any; mapState: MapState; setMapState: (mapState: MapState) => void; - inDashboardMode: boolean; + isReadOnlyMode: boolean; timeRange?: TimeRange; originatingApp?: string; + setIsUpdatingLayerRender: (isUpdatingLayerRender: boolean) => void; } export const MapTopNavMenu = ({ mapIdFromUrl, savedMapObject, - inDashboardMode, + isReadOnlyMode, timeRange, layers, layersIndexPatterns, maplibreRef, mapState, setMapState, + setIsUpdatingLayerRender, }: MapTopNavMenuProps) => { const { services } = useOpenSearchDashboards(); const { @@ -96,6 +98,7 @@ export const MapTopNavMenu = ({ }; const handleQuerySubmit = ({ query, dateRange }: { query?: Query; dateRange: TimeRange }) => { + setIsUpdatingLayerRender(true); if (query) { setMapState({ ...mapState, query }); } @@ -105,7 +108,7 @@ export const MapTopNavMenu = ({ }; useEffect(() => { - if (!inDashboardMode) { + if (!isReadOnlyMode) { setDateFrom(mapState.timeRange.from); setDateTo(mapState.timeRange.to); } else { @@ -144,9 +147,9 @@ export const MapTopNavMenu = ({ config={config} setMenuMountPoint={setHeaderActionMenu} indexPatterns={layersIndexPatterns || []} - showSearchBar={!inDashboardMode} + showSearchBar={!isReadOnlyMode} showFilterBar={false} - showDatePicker={!inDashboardMode} + showDatePicker={!isReadOnlyMode} showQueryBar={true} showSaveQuery={true} showQueryInput={true} diff --git a/public/embeddable/map_component.tsx b/public/embeddable/map_component.tsx index a2fb58f4..afb420f2 100644 --- a/public/embeddable/map_component.tsx +++ b/public/embeddable/map_component.tsx @@ -41,7 +41,7 @@ export function MapEmbeddableComponentInner({ embeddable, input }: Props) { mapConfig={embeddable.getMapConfig()} mapIdFromSavedObject={input.savedObjectId} timeRange={timeRange} - inDashboardMode={true} + isReadOnlyMode={true} refreshConfig={refreshConfig} filters={filters} query={query} diff --git a/public/model/layerRenderController.ts b/public/model/layerRenderController.ts index cf160535..e4b276a2 100644 --- a/public/model/layerRenderController.ts +++ b/public/model/layerRenderController.ts @@ -4,7 +4,7 @@ */ import { Map as Maplibre } from 'maplibre-gl'; -import { DocumentLayerSpecification, MapLayerSpecification } from './mapLayerType'; +import { MapLayerSpecification } from './mapLayerType'; import { DASHBOARDS_MAPS_LAYER_TYPE } from '../../common'; import { buildOpenSearchQuery, @@ -92,7 +92,7 @@ export const prepareDataLayerSource = ( }; export const handleDataLayerRender = ( - mapLayer: DocumentLayerSpecification, + mapLayer: MapLayerSpecification, mapState: MapState, services: MapServices, maplibreRef: MaplibreRef, @@ -101,6 +101,9 @@ export const handleDataLayerRender = ( filtersFromDashboard?: Filter[], query?: Query ) => { + if (mapLayer.type !== DASHBOARDS_MAPS_LAYER_TYPE.DOCUMENTS) { + return; + } // filters are passed from dashboard filters and geo bounding box filters const filters: Filter[] = []; filters.push(...(filtersFromDashboard ? filtersFromDashboard : [])); diff --git a/public/model/layersFunctions.ts b/public/model/layersFunctions.ts index 71625459..52448abc 100644 --- a/public/model/layersFunctions.ts +++ b/public/model/layersFunctions.ts @@ -61,3 +61,24 @@ export const referenceLayerTypeLookup = { [DASHBOARDS_MAPS_LAYER_TYPE.CUSTOM_MAP]: true, [DASHBOARDS_MAPS_LAYER_TYPE.DOCUMENTS]: false, }; + +export const getDataLayers = (layers: MapLayerSpecification[]) => { + return layers.filter((layer) => !referenceLayerTypeLookup[layer.type]); +}; + +export const getReferenceLayers = (layers: MapLayerSpecification[]) => { + return layers.filter((layer) => referenceLayerTypeLookup[layer.type]); +}; + +// Get layer id from layers that is above the selected layer +export const getMapBeforeLayerId = ( + layers: MapLayerSpecification[], + selectedLayerId: string +): string | undefined => { + const selectedLayerIndex = layers.findIndex((layer) => layer.id === selectedLayerId); + const beforeLayers = layers.slice(selectedLayerIndex + 1); + if (beforeLayers.length === 0) { + return undefined; + } + return beforeLayers[0]?.id; +};