Skip to content

Commit

Permalink
Merge branch 'develop' into fix-hover-tooltip
Browse files Browse the repository at this point in the history
  • Loading branch information
cphelefu authored May 22, 2024
2 parents 33919b5 + 2578e08 commit daa24aa
Show file tree
Hide file tree
Showing 28 changed files with 619 additions and 525 deletions.
1 change: 1 addition & 0 deletions packages/geoview-core/src/api/plugin/plugin-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export type TypePluginStructure = {
defaultConfig?: () => TypeJsonObject;
added?: () => void;
removed?: () => void;
onSelected?: () => void;
};

/** ******************************************************************************************************************************
Expand Down
1 change: 1 addition & 0 deletions packages/geoview-core/src/core/components/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './layer-list';
export * from './layer-title';
export * from './layout';
export * from './use-footer-panel-height';
export * from './use-lightbox';
Original file line number Diff line number Diff line change
@@ -1,26 +1,32 @@
import { useState } from 'react';
import { Box } from '@/ui';
import { LightBoxSlides, LightboxImg } from '@/core/components/lightbox/lightbox';

interface UseLightBoxReturnType {
initLightBox: (images: string, alias: string, index: number | undefined) => void;
LightBoxComponent: () => JSX.Element;
}

/**
* Custom Lightbox hook which handle rendering of the lightbox.
* @returns {Object}
* @returns {UseLightBoxReturnType}
*/
// TODO: Refactor - Maybe worth creating an explicit type here instead of 'any'?
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function useLightBox(): any {
export function useLightBox(): UseLightBoxReturnType {
const [isLightBoxOpen, setIsLightBoxOpen] = useState(false);
const [slides, setSlides] = useState<LightBoxSlides[]>([]);
const [slidesIndex, setSlidesIndex] = useState(0);

/**
* Initialize lightbox with state.
* @param {string} images images url formatted as string and joined with ';' identifier.
* @param {string} cellId id of the cell.
* @param {string} alias alt tag for the image.
* @param {number | undefined} index index of the image which is displayed.
*/
const initLightBox = (images: string, cellId: string): void => {
const initLightBox = (images: string, alias: string, index: number | undefined): void => {
setIsLightBoxOpen(true);
const slidesList = images.split(';').map((item) => ({ src: item, alt: cellId, downloadUrl: item }));
const slidesList = images.split(';').map((item) => ({ src: item, alt: alias, downloadUrl: item }));
setSlides(slidesList);
setSlidesIndex(index ?? 0);
};

/**
Expand Down
82 changes: 54 additions & 28 deletions packages/geoview-core/src/core/components/data-table/data-panel.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useTheme } from '@mui/material/styles';
import { delay } from 'lodash';
import { Box, FilterAltIcon, Skeleton } from '@/ui';
import DataTable from './data-table';
import {
Expand All @@ -15,12 +16,8 @@ import { useUIActiveFooterBarTabId } from '@/core/stores/store-interface-and-int
import { LayerListEntry, Layout } from '@/core/components/common';
import { logger } from '@/core/utils/logger';
import { useFeatureFieldInfos } from './hooks';
import { TypeFieldEntry, TypeLayerData } from '@/geo/layer/layer-sets/abstract-layer-set';
import { LAYER_STATUS, TABS } from '@/core/utils/constant';

export interface MappedLayerDataType extends TypeLayerData {
fieldInfos: Record<string, TypeFieldEntry | undefined>;
}
import { MappedLayerDataType } from './data-table-types';

interface DataPanelType {
fullWidth?: boolean;
Expand Down Expand Up @@ -64,6 +61,9 @@ export function Datapanel({ fullWidth = false }: DataPanelType): JSX.Element {
*/
const handleLayerChange = useCallback(
(_layer: LayerListEntry) => {
// Log
logger.logTraceUseCallback('DATA-PANEL - handleLayerChange');

setSelectedLayerPath(_layer.layerPath);
setIsLoading(true);

Expand All @@ -83,40 +83,59 @@ export function Datapanel({ fullWidth = false }: DataPanelType): JSX.Element {
* @param {string} layerPath The path of the layer
* @returns boolean
*/
const isMapFilteredSelectedForLayer = (layerPath: string): boolean =>
!!datatableSettings[layerPath].mapFilteredRecord && !!datatableSettings[layerPath].rowsFilteredRecord;
const isMapFilteredSelectedForLayer = useCallback(
(layerPath: string): boolean => {
// Log
logger.logTraceUseCallback('DATA-PANEL - isMapFilteredSelectedForLayer');

return !datatableSettings[layerPath].mapFilteredRecord && !!datatableSettings[layerPath].rowsFilteredRecord;
},
[datatableSettings]
);

/**
* Get number of features of a layer with filtered or selected layer or unknown when data table is loaded.
* @param {string} layerPath the path of the layer
* @returns
*/
const getFeaturesOfLayer = (layerPath: string): string => {
if (datatableSettings[layerPath] && datatableSettings[layerPath].rowsFilteredRecord) {
return `${datatableSettings[layerPath].rowsFilteredRecord} ${t('dataTable.featureFiltered')}`;
}
let featureStr = t('dataTable.noFeatures');
const features = orderedLayerData?.find((layer) => layer.layerPath === layerPath)?.features?.length ?? 0;
if (features > 0) {
featureStr = `${features} ${t('dataTable.features')}`;
}
return featureStr;
};
const getFeaturesOfLayer = useCallback(
(layerPath: string): string => {
// Log
logger.logTraceUseCallback('DATA-PANEL - getFeaturesOfLayer');

if (datatableSettings[layerPath] && datatableSettings[layerPath].rowsFilteredRecord) {
return `${datatableSettings[layerPath].rowsFilteredRecord} ${t('dataTable.featureFiltered')}`;
}
let featureStr = t('dataTable.noFeatures');
const features = orderedLayerData?.find((layer) => layer.layerPath === layerPath)?.features?.length ?? 0;
if (features > 0) {
featureStr = `${features} ${t('dataTable.features')}`;
}
return featureStr;
},
[datatableSettings, orderedLayerData, t]
);

/**
* Create layer tooltip
* @param {string} layerName en/fr layer name
* @param {string} layerPath the path of the layer.
* @returns
*/
const getLayerTooltip = (layerName: string, layerPath: string): JSX.Element => {
return (
<Box sx={{ display: 'flex', alignContent: 'center', '& svg ': { width: '0.75em', height: '0.75em' } }}>
{`${layerName}, ${getFeaturesOfLayer(layerPath)}`}
{isMapFilteredSelectedForLayer(layerPath) && <FilterAltIcon />}
</Box>
);
};
const getLayerTooltip = useCallback(
(layerName: string, layerPath: string): JSX.Element => {
// Log
logger.logTraceUseCallback('DATA-PANEL - getLayerTooltip');

return (
<Box sx={{ display: 'flex', alignContent: 'center', '& svg ': { width: '0.75em', height: '0.75em' } }}>
{`${layerName}, ${getFeaturesOfLayer(layerPath)}`}
{isMapFilteredSelectedForLayer(layerPath) && <FilterAltIcon />}
</Box>
);
},
[getFeaturesOfLayer, isMapFilteredSelectedForLayer]
);

/**
* Checks if layer is disabled when layer is selected and features have null value.
Expand All @@ -143,8 +162,7 @@ export function Datapanel({ fullWidth = false }: DataPanelType): JSX.Element {
// Log
logger.logTraceUseEffect('DATA-PANEL - isLoading', isLoading, selectedLayerPath);

// TODO: Get rid of this setTimeout of 1 second?
const clearLoading = setTimeout(() => {
const clearLoading = delay(() => {
setIsLoading(false);
}, 100);
return () => clearTimeout(clearLoading);
Expand Down Expand Up @@ -172,6 +190,11 @@ export function Datapanel({ fullWidth = false }: DataPanelType): JSX.Element {
return () => !!orderedLayerData.find((layer) => layer.queryStatus === LAYER_STATUS.PROCESSING);
}, [orderedLayerData]);

/**
* Render the right panel content based on table data and layer loading status.
* NOTE: Here we return null, so that in responsive grid layout, it can be used as flag to render the guide for data table.
* @returns {JSX.Element | null} JSX.Element | null
*/
const renderContent = (): JSX.Element | null => {
if (isLoading || memoIsLayerQueryStatusProcessing()) {
return <Skeleton variant="rounded" width="100%" height={400} sx={{ bgcolor: theme.palette.grey[400] }} />;
Expand All @@ -191,6 +214,9 @@ export function Datapanel({ fullWidth = false }: DataPanelType): JSX.Element {
return null;
};

/**
* Callback function to update the store state for clearing the selecting layer from left panel.
*/
const handleGuideIsOpen = useCallback(
(guideIsOpen: boolean): void => {
if (guideIsOpen) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,14 @@ import {
} from '@/ui';
import { useUIActiveFocusItem, useUIStoreActions } from '@/core/stores/store-interface-and-intial-values/ui-state';
import { useLayerSelectedLayerPath } from '@/core/stores/store-interface-and-intial-values/layer-state';

import { FieldInfos } from './data-table';
import { getSxClasses } from './data-table-style';
import { logger } from '@/core/utils/logger';
import { useDataTableAllFeaturesDataArray } from '@/core/stores/store-interface-and-intial-values/data-table-state';
import { useFeatureFieldInfos } from './hooks';
import { TypeFieldEntry } from '@/geo/layer/layer-sets/abstract-layer-set';

interface ColumnsType {
[key: string]: FieldInfos;
[key: string]: TypeFieldEntry;
}
/**
* Open lighweight version (no function) of data table in a modal window
Expand Down Expand Up @@ -63,9 +62,19 @@ export default function DataTableModal(): JSX.Element {
* @param {string} cellValue cell value to be displayed in cell
* @returns {JSX.Element}
*/
const getCellValue = (cellValue: string): JSX.Element => {
return <Box sx={sxClasses.tableCell}>{cellValue}</Box>;
};
const getCellValue = useCallback(
(cellValue: string): JSX.Element => {
// Log
logger.logTraceUseCallback('DATA-TABLE-MODAL - getCellValue');

return (
<Box component="div" sx={sxClasses.tableCell}>
{cellValue}
</Box>
);
},
[sxClasses.tableCell]
);

/**
* Create table header cell
Expand Down
Original file line number Diff line number Diff line change
@@ -1,78 +1,77 @@
import { Theme } from '@mui/material';

// ? I doubt we want to define an explicit type for style properties?
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const getSxClasses = (theme: Theme): any => ({
dataPanel: { background: theme.palette.geoViewColor.bgColor.main, paddingBottom: '1rem' },
gridContainer: { paddingLeft: '1rem', paddingRight: '1rem' },
selectedRows: {
transition: 'box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms',
fontWeight: 400,
fontSize: theme.palette.geoViewFontSize.sm,
linHeight: 1.43,
letterSpacing: '0.01071em',
display: 'flex',
padding: '6px',
},
selectedRowsDirection: {
display: 'flex',
flexDirection: 'column',
},
tableCell: { whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' },
dataTableWrapper: {
'& .MuiTableContainer-root': {
borderRadius: '6px',
export const getSxClasses = (theme: Theme) =>
({
dataPanel: { background: theme.palette.geoViewColor.bgColor.main, paddingBottom: '1rem' },
gridContainer: { paddingLeft: '1rem', paddingRight: '1rem' },
selectedRows: {
transition: 'box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms',
fontWeight: 400,
fontSize: theme.palette.geoViewFontSize.sm,
linHeight: 1.43,
letterSpacing: '0.01071em',
display: 'flex',
padding: '6px',
},
'& .MuiToolbar-root ': {
borderRadius: '6px',
selectedRowsDirection: {
display: 'flex',
flexDirection: 'column',
},
},
filterMap: {
'& .Mui-checked': {
'& .MuiTouchRipple-root': {
color: theme.palette.action.active,
tableCell: { whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' },
dataTableWrapper: {
'& .MuiTableContainer-root': {
borderRadius: '6px',
},
},
'& .MuiTouchRipple-root': {
color: theme.palette.geoViewColor.grey.dark[900],
},
},
tableHeadCell: {
'& .MuiCollapse-wrapperInner': {
'& .MuiBox-root': {
gridTemplateColumns: '1fr',
'& .MuiToolbar-root ': {
borderRadius: '6px',
},
},
'& .MuiInput-root': { fontSize: theme.palette.geoViewFontSize.sm, '& .MuiSvgIcon-root': { width: '0.75em', height: '0.75em' } },
'& .MuiBadge-root': {
marginLeft: '0.5rem',
'>span': {
width: '100%',
filterMap: {
'& .Mui-checked': {
'& .MuiTouchRipple-root': {
color: theme.palette.action.active,
},
},
svg: {
marginTop: '0.25rem',
marginBottom: '0.25rem',
'& .MuiTouchRipple-root': {
color: theme.palette.geoViewColor.grey.dark[900],
},
'& .keyboard-focused': {
backgroundColor: 'rgba(81, 91, 165, 0.08)',
borderRadius: '50%',
border: `1px solid black !important`,
'> svg': {
opacity: 1,
},
tableHeadCell: {
'& .MuiCollapse-wrapperInner': {
'& .MuiBox-root': {
gridTemplateColumns: '1fr',
},
},
'& .MuiInput-root': { fontSize: theme.palette.geoViewFontSize.sm, '& .MuiSvgIcon-root': { width: '0.75em', height: '0.75em' } },
'& .MuiBadge-root': {
marginLeft: '0.5rem',
'>span': {
width: '100%',
},
svg: {
marginTop: '0.25rem',
marginBottom: '0.25rem',
},
'& .keyboard-focused': {
backgroundColor: 'rgba(81, 91, 165, 0.08)',
borderRadius: '50%',
border: `1px solid black !important`,
'> svg': {
opacity: 1,
},
},
},
},
dataTableInstructionsTitle: {
fontSize: theme.palette.geoViewFontSize.lg,
fontWeight: '600',
lineHeight: '1.5em',
},
dataTableInstructionsBody: {
fontSize: theme.palette.geoViewFontSize.sm,
},
rightPanelContainer: {
overflowY: 'auto',
color: theme.palette.geoViewColor.textColor.main,
},
},
dataTableInstructionsTitle: {
fontSize: theme.palette.geoViewFontSize.lg,
fontWeight: '600',
lineHeight: '1.5em',
},
dataTableInstructionsBody: {
fontSize: theme.palette.geoViewFontSize.sm,
},
rightPanelContainer: {
overflowY: 'auto',
color: theme.palette.geoViewColor.textColor.main,
},
});
} as const);
Loading

0 comments on commit daa24aa

Please sign in to comment.