From da248eff5791f7bd9fc03f5038adb639442b6665 Mon Sep 17 00:00:00 2001 From: Viorel Cojocaru Date: Sat, 18 May 2024 19:09:59 +0200 Subject: [PATCH] enhance(ui): MetricsTreemap - improve group title click - add hover state - toggle search --- .../bundle-assets/bundle-assets.jsx | 44 ++++++++++++++----- .../bundle-modules/bundle-modules.tsx | 36 +++++++++++---- .../bundle-packages/bundle-packages.jsx | 26 ++++++++--- .../metrics-treemap.module.css | 15 ++++++- .../metrics-treemap/metrics-treemap.tsx | 6 ++- 5 files changed, 96 insertions(+), 31 deletions(-) diff --git a/packages/ui/src/components/bundle-assets/bundle-assets.jsx b/packages/ui/src/components/bundle-assets/bundle-assets.jsx index 5ca8b633e6..66aacc8cf4 100644 --- a/packages/ui/src/components/bundle-assets/bundle-assets.jsx +++ b/packages/ui/src/components/bundle-assets/bundle-assets.jsx @@ -49,10 +49,10 @@ const DISPLAY_TYPE_GROUPS = { const getFileTypeFilters = (filters) => Object.entries(FILE_TYPE_LABELS).map(([key, label]) => ({ - key, - label, - defaultValue: get(filters, `${ASSET_FILE_TYPE}.${key}`, true), -})); + key, + label, + defaultValue: get(filters, `${ASSET_FILE_TYPE}.${key}`, true), + })); const getFilters = ({ compareMode, filters }) => ({ [ASSET_FILTERS.CHANGED]: { @@ -163,9 +163,18 @@ RowHeader.defaultProps = { }; const ViewMetricsTreemap = (props) => { - const { metricsTableTitle, jobs, items, displayType, emptyMessage, showEntryInfo, updateSearch } = - props; + const { + metricsTableTitle, + jobs, + items, + displayType, + emptyMessage, + showEntryInfo, + updateSearch, + search, + } = props; + // Get treenodes based on group const treeNodes = useMemo(() => { if (displayType.groupBy === 'folder') { return getTreemapNodesGroupedByPath(items); @@ -174,19 +183,28 @@ const ViewMetricsTreemap = (props) => { return getTreemapNodes(items); }, [items, displayType.groupBy]); + // Search based on the group path on group title click const onGroupClick = useCallback( (groupPath) => { + // Clear seach when groupPath is emty (root) + if (groupPath === '') { + updateSearch(''); + return; + } // Search by group path // 1. use `^` to match only the string beggining - // 2. add `/` suffix to match only exact directories - // 3. if the group path is empty(root), clear search - if (groupPath) { - updateSearch(`^${groupPath}/`); - } else { + // 2. add `/` suffix to exactly match the directory + const newSearch = `^${groupPath}/`; + + // Reset search when toggling the same groupPath + if (newSearch === search) { updateSearch(''); + return; } + + updateSearch(`^${groupPath}/`); }, - [updateSearch], + [updateSearch, search], ); return ( @@ -215,6 +233,7 @@ ViewMetricsTreemap.propTypes = { emptyMessage: PropTypes.node.isRequired, showEntryInfo: PropTypes.func.isRequired, updateSearch: PropTypes.func.isRequired, + search: PropTypes.string.isRequired, }; export const BundleAssets = (props) => { @@ -348,6 +367,7 @@ export const BundleAssets = (props) => { emptyMessage={emptyMessage} showEntryInfo={showEntryInfo} updateSearch={updateSearch} + search={search} /> )} diff --git a/packages/ui/src/components/bundle-modules/bundle-modules.tsx b/packages/ui/src/components/bundle-modules/bundle-modules.tsx index 2c168cb566..81e4dc0796 100644 --- a/packages/ui/src/components/bundle-modules/bundle-modules.tsx +++ b/packages/ui/src/components/bundle-modules/bundle-modules.tsx @@ -74,12 +74,22 @@ interface ViewMetricsTreemapProps { emptyMessage: React.ReactNode; showEntryInfo: React.ComponentProps['onItemClick']; updateSearch: (newSerarch: string) => void; + search: string; } const ViewMetricsTreemap = (props: ViewMetricsTreemapProps) => { - const { metricsTableTitle, jobs, items, displayType, emptyMessage, showEntryInfo, updateSearch } = - props; + const { + metricsTableTitle, + jobs, + items, + displayType, + emptyMessage, + showEntryInfo, + updateSearch, + search, + } = props; + // Get treenodes based on group const treeNodes = useMemo(() => { if (displayType.groupBy === 'folder') { return getTreemapNodesGroupedByPath(items); @@ -88,19 +98,28 @@ const ViewMetricsTreemap = (props: ViewMetricsTreemapProps) => { return getTreemapNodes(items); }, [items, displayType]); + // Search based on the group path on group title click const onGroupClick = useCallback( (groupPath: string) => { + // Clear seach when groupPath is emty (root) + if (groupPath === '') { + updateSearch(''); + return; + } // Search by group path // 1. use `^` to match only the string beggining - // 2. add `/` suffix to match only exact directories - // 3. if the group path is empty(root), clear search - if (groupPath) { - updateSearch(`^${groupPath}/`); - } else { + // 2. add `/` suffix to exactly match the directory + const newSearch = `^${groupPath}/`; + + // Reset search when toggling the same groupPath + if (newSearch === search) { updateSearch(''); + return; } + + updateSearch(newSearch); }, - [updateSearch], + [updateSearch, search], ); return ( @@ -306,6 +325,7 @@ export const BundleModules = (props: BundleModulesProps) => { emptyMessage={emptyMessage} showEntryInfo={showEntryInfo} updateSearch={updateSearch} + search={search} /> )} diff --git a/packages/ui/src/components/bundle-packages/bundle-packages.jsx b/packages/ui/src/components/bundle-packages/bundle-packages.jsx index f5e8e30e3b..7d2b80c2a0 100644 --- a/packages/ui/src/components/bundle-packages/bundle-packages.jsx +++ b/packages/ui/src/components/bundle-packages/bundle-packages.jsx @@ -120,8 +120,9 @@ RowHeader.propTypes = { }; const ViewMetricsTreemap = (props) => { - const { metricsTableTitle, jobs, items, displayType, emptyMessage, showEntryInfo, updateSearch } = props; + const { metricsTableTitle, jobs, items, displayType, emptyMessage, showEntryInfo, updateSearch, search } = props; + // Get treenodes based on group const treeNodes = useMemo(() => { if (displayType.groupBy === 'folder') { return getTreemapNodesGroupedByPath(items); @@ -130,19 +131,28 @@ const ViewMetricsTreemap = (props) => { return getTreemapNodes(items); }, [items, displayType.groupBy]); + // Search based on the group path on group title click const onGroupClick = useCallback( (groupPath) => { + // Clear seach when groupPath is emty (root) + if (groupPath === '') { + updateSearch(''); + return; + } // Search by group path // 1. use `^` to match only the string beggining - // 2. add `/` suffix to match only exact directories - // 3. if the group path is empty(root), clear search - if (groupPath) { - updateSearch(`^${groupPath}/`); - } else { + // 2. add `/` suffix to exactly match the directory + const newSearch = `^${groupPath}/`; + + // Reset search when toggling the same groupPath + if (newSearch === search) { updateSearch(''); + return; } + + updateSearch(newSearch); }, - [updateSearch], + [updateSearch, search], ); return ( @@ -171,6 +181,7 @@ ViewMetricsTreemap.propTypes = { emptyMessage: PropTypes.node.isRequired, showEntryInfo: PropTypes.func.isRequired, updateSearch: PropTypes.func.isRequired, + search: PropTypes.string.isRequired, }; export const BundlePackages = (props) => { @@ -300,6 +311,7 @@ export const BundlePackages = (props) => { emptyMessage={emptyMessage} showEntryInfo={showEntryInfo} updateSearch={updateSearch} + search={search} /> )} diff --git a/packages/ui/src/components/metrics-treemap/metrics-treemap.module.css b/packages/ui/src/components/metrics-treemap/metrics-treemap.module.css index a58081c05a..e99e9aa262 100644 --- a/packages/ui/src/components/metrics-treemap/metrics-treemap.module.css +++ b/packages/ui/src/components/metrics-treemap/metrics-treemap.module.css @@ -24,8 +24,9 @@ } .tileGroupTitle { + position: relative; width: 100%; - padding: 4px 2px 4px var(--space-xxsmall); + padding: var(--space-xxxsmall) 1px var(--space-xxxsmall) var(--space-xxsmall); color: var(--color-text); font-family: var(--font-family-fixed); font-size: 10px; @@ -36,7 +37,17 @@ } .tileGroupTitleTotal { - margin-left: var(--space-xxxsmall); + margin-left: var(--space-xxsmall); + color: var(--color-text-light); +} + +.tileGroupTitle { + transition: var(--ui-transition-out); +} + +.tileGroupTitle:hover .tileGroupTitleText { + text-decoration: underline; + transition: var(--ui-transition-in); } /** Tile group size variation */ diff --git a/packages/ui/src/components/metrics-treemap/metrics-treemap.tsx b/packages/ui/src/components/metrics-treemap/metrics-treemap.tsx index 4efb41c0c1..96b827a71e 100644 --- a/packages/ui/src/components/metrics-treemap/metrics-treemap.tsx +++ b/packages/ui/src/components/metrics-treemap/metrics-treemap.tsx @@ -350,7 +350,9 @@ const TileGroup = (props: TileGroupProps) => { style={{ left, top, width, height }} className={rootClassName} > -
{title}
+
+ {title} +
); } @@ -365,7 +367,7 @@ const TileGroup = (props: TileGroupProps) => { > {title && (
- {title} + {title} {metricRunInfo && ( {`${metricRunInfo.displayValue}`}