Skip to content

Commit

Permalink
feat(plugins): Hides plugin tabs if no layers support them
Browse files Browse the repository at this point in the history
Closes #2369
  • Loading branch information
DamonU2 committed Jul 18, 2024
1 parent 0408913 commit 09c3607
Show file tree
Hide file tree
Showing 13 changed files with 174 additions and 85 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/type-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ jobs:
rm -r common
rm -r packages
git config --global user.name $USER
git config --global user.email "[email protected]"
git config --global user.name "Damon Ulmi"
git add .
git status
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { GeoChartConfig } from '@/core/utils/config/reader/uuid-config-reader';
import { logger } from '@/core/utils/logger';

import { AbstractEventProcessor, BatchedPropagationLayerDataArrayByMap } from '@/api/event-processors/abstract-event-processor';
import { UIEventProcessor } from './ui-event-processor';

// GV Important: See notes in header of MapEventProcessor file for information on the paradigm to apply when working with UIEventProcessor vs UIState

Expand Down Expand Up @@ -120,9 +121,12 @@ export class GeochartEventProcessor extends AbstractEventProcessor {
});
});

// set store charts config
// Set store charts config
this.getGeochartState(mapId)?.setterActions.setGeochartCharts(chartData);

// If there is chart data, tab should not be hidden
if (Object.keys(chartData).length) UIEventProcessor.showTab(mapId, 'geochart');

// Log
logger.logInfo('Added GeoChart configs for layer paths:', layerPaths);
}
Expand All @@ -145,6 +149,9 @@ export class GeochartEventProcessor extends AbstractEventProcessor {
// Update the layer data array in the store
this.getGeochartState(mapId)!.setterActions.setGeochartCharts({ ...this.getGeochartState(mapId)?.geochartChartsConfig, ...toAdd });

// Make sure tab is not hidden
UIEventProcessor.showTab(mapId, 'geochart');

// Log
logger.logInfo('Added GeoChart configs for layer path:', layerPath);
}
Expand All @@ -171,6 +178,9 @@ export class GeochartEventProcessor extends AbstractEventProcessor {
// Update the layer data array in the store
this.getGeochartState(mapId)!.setterActions.setGeochartCharts({ ...chartConfigs });

// If there are no more geochart layers, hide tab
if (!Object.keys(this.getGeochartState(mapId)!.geochartChartsConfig).length) UIEventProcessor.hideTab(mapId, 'geochart');

// Log
logger.logInfo('Removed GeoChart configs for layer path:', layerPath);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,12 +303,14 @@ export class MapEventProcessor extends AbstractEventProcessor {
}

/**
* Gets the ordered layer info.
* Gets map layer paths in order.
* @param {string} mapId - The map id
* @returns {TypeOrderedLayerInfo[]} The ordered layer info
* @returns {string[]} The ordered layer paths
*/
static getMapLayerOrder(mapId: string): TypeOrderedLayerInfo[] {
return this.getMapStateProtected(mapId).orderedLayerInfo;
static getMapLayerOrder(mapId: string): string[] {
return this.getMapStateProtected(mapId).orderedLayerInfo.map((orderedLayerInfo) => {
return orderedLayerInfo.layerPath;
});
}

static getMapState(mapId: string): TypeMapState {
Expand Down Expand Up @@ -453,6 +455,11 @@ export class MapEventProcessor extends AbstractEventProcessor {
// GV No need to save in the store, because this will trigger an event on MapViewer which will take care of updating the store
}

/**
* Gets the ordered layer info.
* @param {string} mapId - The map id
* @returns {TypeOrderedLayerInfo[]} The ordered layer info
*/
static getMapOrderedLayerInfo(mapId: string): TypeOrderedLayerInfo[] {
return this.getMapStateProtected(mapId).orderedLayerInfo;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { MapEventProcessor } from './map-event-processor';
import { AbstractGVVector } from '@/geo/layer/gv-layers/vector/abstract-gv-vector';
import { GVWMS } from '@/geo/layer/gv-layers/raster/gv-wms';
import { GVEsriImage } from '@/geo/layer/gv-layers/raster/gv-esri-image';
import { UIEventProcessor } from './ui-event-processor';

// GV Important: See notes in header of MapEventProcessor file for information on the paradigm to apply when working with UIEventProcessor vs UIState

Expand Down Expand Up @@ -85,6 +86,9 @@ export class TimeSliderEventProcessor extends AbstractEventProcessor {

const { defaultValue, field, filtering, minAndMax, values } = timeSliderLayer[layerPath];
this.applyFilters(mapId, layerPath, defaultValue, field, filtering, minAndMax, values);

// Make sure tab is visible
UIEventProcessor.showTab(mapId, 'time-slider');
}

/**
Expand All @@ -95,6 +99,10 @@ export class TimeSliderEventProcessor extends AbstractEventProcessor {
static removeTimeSliderLayer(mapId: string, layerPath: string): void {
// Redirect
this.getTimesliderState(mapId)?.setterActions.removeTimeSliderLayer(layerPath);

// If there are no layers with time dimension, hide tab
if (!this.getTimesliderState(mapId) || !Object.keys(this.getTimesliderState(mapId)!.timeSliderLayers).length)
UIEventProcessor.hideTab(mapId, 'time-slider');
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,26 @@ export class UIEventProcessor extends AbstractEventProcessor {
* @param {string} mapId The mapId
* @returns {IUIState} The UI state.
*/
protected static getUIState(mapId: string): IUIState {
protected static getUIStateProtected(mapId: string): IUIState {
// Return the time slider state
return super.getState(mapId).uiState;
}

// #region
static getActiveFooterBarTab(mapId: string): string {
return this.getUIState(mapId).activeFooterBarTabId;
return this.getUIStateProtected(mapId).activeFooterBarTabId;
}

static getAppBarComponents(mapId: string): TypeValidAppBarCoreProps[] {
return this.getUIState(mapId).appBarComponents;
return this.getUIStateProtected(mapId).appBarComponents;
}

static getCorePackageComponents(mapId: string): TypeMapCorePackages {
return this.getUIState(mapId).corePackagesComponents;
return this.getUIStateProtected(mapId).corePackagesComponents;
}

static getFooterBarIsCollapsed(mapId: string): boolean {
return this.getUIStateProtected(mapId).footerBarIsCollapsed;
}
// #endregion

Expand All @@ -41,15 +45,33 @@ export class UIEventProcessor extends AbstractEventProcessor {
// **********************************************************
// GV NEVER add a store action who does set state AND map action at a same time.
// GV Review the action in store state to make sure
static hideTab(mapId: string, tab: string): void {
if (!this.getUIStateProtected(mapId).hiddenTabs.includes(tab))
this.getUIStateProtected(mapId).setterActions.setHiddenTabs([...this.getUIStateProtected(mapId).hiddenTabs, tab]);
}

static showTab(mapId: string, tab: string): void {
const curHiddenTabs = this.getUIStateProtected(mapId).hiddenTabs;
const tabIndex = curHiddenTabs.indexOf(tab);
if (tabIndex !== -1) {
curHiddenTabs.splice(tabIndex, 1);
this.getUIStateProtected(mapId).setterActions.setHiddenTabs(curHiddenTabs);
}
}

static setActiveFooterBarTab(mapId: string, id: string): void {
this.getUIState(mapId).setterActions.setActiveFooterBarTab(id);
this.getUIStateProtected(mapId).setterActions.setActiveFooterBarTab(id);
}

static setActiveAppBarTab(mapId: string, tabId: string, tabGroup: string, isOpen: boolean): void {
this.getUIState(mapId).setterActions.setActiveAppBarTab(tabId, tabGroup, isOpen);
this.getUIStateProtected(mapId).setterActions.setActiveAppBarTab(tabId, tabGroup, isOpen);
}

static getActiveAppBarTab(mapId: string): ActiveAppBarTabType {
return this.getUIState(mapId).activeAppBarTab;
return this.getUIStateProtected(mapId).activeAppBarTab;
}

static setFooterBarIsCollapsed(mapId: string, collapsed: boolean): void {
this.getUIStateProtected(mapId).setterActions.setFooterBarIsCollapsed(collapsed);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -349,15 +349,17 @@ function DataTable({ data, layerPath, tableHeight = '500px' }: DataTableProps):
/>
),
ZOOM: (
<IconButton
color="primary"
// Function returns void promise instead of void, other work arounds led to more eslint issues
// eslint-disable-next-line @typescript-eslint/no-misused-promises
onClick={() => handleZoomIn(feature)}
disabled={!feature.extent && feature.geoviewLayerType !== CONST_LAYER_TYPES.ESRI_DYNAMIC}
>
<ZoomInSearchIcon />
</IconButton>
<Box component="span">
<IconButton
color="primary"
// Function returns void promise instead of void, other work arounds led to more eslint issues
// eslint-disable-next-line @typescript-eslint/no-misused-promises
onClick={() => handleZoomIn(feature)}
disabled={!feature.extent && feature.geoviewLayerType !== CONST_LAYER_TYPES.ESRI_DYNAMIC}
>
<ZoomInSearchIcon />
</IconButton>
</Box>
),
DETAILS: (
<Box marginLeft="0.3rem">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ export function FooterBar(props: FooterBarProps): JSX.Element | null {
label: `${camelCase(tab)}.title`,
icon: allTabs[tab]?.icon ?? '',
content: allTabs[tab]?.content ?? '',
};
}) as unknown as TypeTabs[];
} as TypeTabs;
});
}, [memoTabs, tabsList]);

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/geoview-core/src/core/stores/state-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export class StateApi {
// Apply some ordering logic
const direction = move < 0 ? -1 : 1;
let absoluteMoves = Math.abs(move);
const orderedLayers = [...MapEventProcessor.getMapLayerOrder(this.mapId)];
const orderedLayers = [...MapEventProcessor.getMapOrderedLayerInfo(this.mapId)];
let startingIndex = -1;
for (let i = 0; i < orderedLayers.length; i++) if (orderedLayers[i].layerPath === layerPath) startingIndex = i;
const layerInfo = orderedLayers[startingIndex];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { TypeMapCorePackages, TypeNavBarProps, TypeValidAppBarCoreProps } from '
import { useGeoViewStore } from '@/core/stores/stores-managers';
import { TypeSetStore, TypeGetStore } from '@/core/stores/geoview-store';
import { TypeMapFeaturesConfig } from '@/core/types/global-types';
import { UIEventProcessor } from '@/api/event-processors/event-processor-children/ui-event-processor';

// GV Important: See notes in header of MapEventProcessor file for information on the paradigm to apply when working with UIEventProcessor vs UIState

Expand All @@ -23,6 +24,7 @@ export interface IUIState {
appBarComponents: TypeValidAppBarCoreProps[];
corePackagesComponents: TypeMapCorePackages;
focusITem: FocusItemProps;
hiddenTabs: string[];
mapInfoExpanded: boolean;
navBarComponents: TypeNavBarProps;
footerPanelResizeValue: number;
Expand All @@ -31,8 +33,10 @@ export interface IUIState {
setDefaultConfigValues: (geoviewConfig: TypeMapFeaturesConfig) => void;

actions: {
hideTab: (tab: string) => void;
closeModal: () => void;
openModal: (uiFocus: FocusItemProps) => void;
showTab: (tab: string) => void;
setActiveFooterBarTab: (id: string) => void;
setActiveAppBarTab: (tabId: string, tabGroup: string, isOpen: boolean) => void;
setActiveTrapGeoView: (active: boolean) => void;
Expand All @@ -48,6 +52,7 @@ export interface IUIState {
setActiveAppBarTab: (tabId: string, tabGroup: string, isOpen: boolean) => void;
setActiveTrapGeoView: (active: boolean) => void;
setFooterPanelResizeValue: (value: number) => void;
setHiddenTabs: (hiddenTabs: string[]) => void;
setMapInfoExpanded: (expanded: boolean) => void;
setFooterBarIsCollapsed: (collapsed: boolean) => void;
};
Expand All @@ -69,6 +74,7 @@ export function initializeUIState(set: TypeSetStore, get: TypeGetStore): IUIStat
activeTrapGeoView: false,
corePackagesComponents: [],
focusITem: { activeElementId: false, callbackElementId: false },
hiddenTabs: ['time-slider', 'geochart'],
mapInfoExpanded: false,
navBarComponents: [],
footerPanelResizeValue: 35,
Expand All @@ -90,6 +96,10 @@ export function initializeUIState(set: TypeSetStore, get: TypeGetStore): IUIStat
// #region ACTIONS

actions: {
hideTab: (tab: string): void => {
// Redirect to event processor
UIEventProcessor.hideTab(get().mapId, tab);
},
closeModal: () => {
// Redirect to setter
get().uiState.setterActions.closeModal();
Expand All @@ -98,6 +108,10 @@ export function initializeUIState(set: TypeSetStore, get: TypeGetStore): IUIStat
// Redirect to setter
get().uiState.setterActions.openModal(uiFocus);
},
showTab: (tab: string): void => {
// Redirect to event processor
UIEventProcessor.showTab(get().mapId, tab);
},
setActiveFooterBarTab: (id: string) => {
// Redirect to setter
get().uiState.setterActions.setActiveFooterBarTab(id);
Expand Down Expand Up @@ -158,6 +172,14 @@ export function initializeUIState(set: TypeSetStore, get: TypeGetStore): IUIStat
},
});
},
setHiddenTabs: (hiddenTabs: string[]) => {
set({
uiState: {
...get().uiState,
hiddenTabs: [...hiddenTabs],
},
});
},
setFooterPanelResizeValue: (value) => {
set({
uiState: {
Expand Down Expand Up @@ -220,6 +242,7 @@ export const useUICorePackagesComponents = (): TypeMapCorePackages =>
useStore(useGeoViewStore(), (state) => state.uiState.corePackagesComponents);
export const useUIFooterPanelResizeValue = (): number => useStore(useGeoViewStore(), (state) => state.uiState.footerPanelResizeValue);
export const useUIFooterPanelResizeValues = (): number[] => useStore(useGeoViewStore(), (state) => state.uiState.footerPanelResizeValues);
export const useUIHiddenTabs = (): string[] => useStore(useGeoViewStore(), (state) => state.uiState.hiddenTabs);
export const useUIMapInfoExpanded = (): boolean => useStore(useGeoViewStore(), (state) => state.uiState.mapInfoExpanded);
export const useUINavbarComponents = (): TypeNavBarProps => useStore(useGeoViewStore(), (state) => state.uiState.navBarComponents);
export const useUIFooterBarIsCollapsed = (): boolean => useStore(useGeoViewStore(), (state) => state.uiState.footerBarIsCollapsed);
Expand Down
12 changes: 6 additions & 6 deletions packages/geoview-core/src/geo/layer/layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1395,17 +1395,17 @@ export class LayerApi {
*/
setOrToggleLayerVisibility(layerPath: string, newValue?: boolean): void {
// Apply some visibility logic
const curOrderedLayerInfo = MapEventProcessor.getMapLayerOrder(this.getMapId());
const curOrderedLayerInfo = MapEventProcessor.getMapOrderedLayerInfo(this.getMapId());
const layerVisibility = MapEventProcessor.getMapVisibilityFromOrderedLayerInfo(this.getMapId(), layerPath);
// Determine the outcome of the new visibility based on parameters
const newVisibility = newValue !== undefined ? newValue : !layerVisibility;
const layerInfos = curOrderedLayerInfo.filter((info: { layerPath: string }) => info.layerPath.startsWith(layerPath));
const layerInfos = curOrderedLayerInfo.filter((info: TypeOrderedLayerInfo) => info.layerPath.startsWith(layerPath));
const parentLayerPathArray = layerPath.split('/');
parentLayerPathArray.pop();
const parentLayerPath = parentLayerPathArray.join('/');
const parentLayerInfo = curOrderedLayerInfo.find((info: { layerPath: string }) => info.layerPath === parentLayerPath);
const parentLayerInfo = curOrderedLayerInfo.find((info: TypeOrderedLayerInfo) => info.layerPath === parentLayerPath);

layerInfos.forEach((layerInfo: { visible: boolean; layerPath: string }) => {
layerInfos.forEach((layerInfo: TypeOrderedLayerInfo) => {
if (layerInfo) {
// If the new visibility is different than before
if (newVisibility !== layerVisibility) {
Expand All @@ -1431,9 +1431,9 @@ export class LayerApi {
}
}
const children = curOrderedLayerInfo.filter(
(info: { layerPath: string }) => info.layerPath.startsWith(parentLayerPath) && info.layerPath !== parentLayerPath
(info: TypeOrderedLayerInfo) => info.layerPath.startsWith(parentLayerPath) && info.layerPath !== parentLayerPath
);
if (!children.some((child: { visible: boolean }) => child.visible === true)) {
if (!children.some((child: TypeOrderedLayerInfo) => child.visible === true)) {
this.setOrToggleLayerVisibility(parentLayerPath, false);

// Emit event
Expand Down
2 changes: 1 addition & 1 deletion packages/geoview-core/src/geo/map/map-viewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -826,7 +826,7 @@ export class MapViewer {
* @returns {TypeOrderedLayerInfo[]} The ordered layer info
*/
getMapLayerOrderInfo(): TypeOrderedLayerInfo[] {
return MapEventProcessor.getMapLayerOrder(this.mapId);
return MapEventProcessor.getMapOrderedLayerInfo(this.mapId);
}

/**
Expand Down
4 changes: 3 additions & 1 deletion packages/geoview-core/src/ui/tabs/tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Select, TypeMenuItemProps } from '@/ui/select/select';
import { getSxClasses } from './tabs-style';
import { TabPanel } from './tab-panel';
import { useMapSize } from '@/core/stores/store-interface-and-intial-values/map-state';
import { useUIHiddenTabs } from '@/core/stores/store-interface-and-intial-values/ui-state';

/**
* Type used for properties of each tab
Expand Down Expand Up @@ -84,6 +85,7 @@ export function Tabs(props: TypeTabsProps): JSX.Element {

// get store values and actions
const mapSize = useMapSize();
const hiddenTabs = useUIHiddenTabs();

// show/hide dropdown based on map size
const initMobileDropdown = mapSize[0] !== 0 ? mapSize[0] < theme.breakpoints.values.sm : false;
Expand Down Expand Up @@ -197,7 +199,7 @@ export function Tabs(props: TypeTabsProps): JSX.Element {
iconPosition="start"
id={`tab-${index}`}
onClick={() => handleClick(index)}
sx={sxClasses.tab}
sx={hiddenTabs.includes(tab.id) ? { display: 'none' } : sxClasses.tab}
{...tabProps}
/>
);
Expand Down
Loading

0 comments on commit 09c3607

Please sign in to comment.