diff --git a/src/Shared/Components/CICDHistory/ConflictedResourcesTable.tsx b/src/Shared/Components/CICDHistory/ConflictedResourcesTable.tsx index 238293eae..9e24fc76f 100644 --- a/src/Shared/Components/CICDHistory/ConflictedResourcesTable.tsx +++ b/src/Shared/Components/CICDHistory/ConflictedResourcesTable.tsx @@ -10,7 +10,6 @@ import './ConflictedResourcesTable.scss' const Wrapper = ({ children }: TableViewWrapperProps) => (
{children}
) -const filter = () => true const ConflictedResourcesTable = ({ resourceConflictDetails }: ConflictedResourcesTableProps) => { const rows: RowsType = useMemo( @@ -42,7 +41,7 @@ const ConflictedResourcesTable = ({ resourceConflictDetails }: ConflictedResourc }} filtersVariant={FiltersTypeEnum.STATE} ViewWrapper={Wrapper} - filter={filter} + filter={null} /> ) } diff --git a/src/Shared/Components/Table/InternalTable.tsx b/src/Shared/Components/Table/InternalTable.tsx index 99a7045d3..007ab9084 100644 --- a/src/Shared/Components/Table/InternalTable.tsx +++ b/src/Shared/Components/Table/InternalTable.tsx @@ -58,6 +58,7 @@ const InternalTable = < clearFilters: userGivenUrlClearFilters, rowStartIconConfig, onRowClick, + areFiltersApplied: userProvidedAreFiltersApplied, }: InternalTableProps) => { const { sortBy, @@ -126,6 +127,7 @@ const InternalTable = < rows, filter, filterData, + additionalProps, visibleColumns.find(({ field }) => field === sortBy)?.comparator, ) @@ -140,10 +142,14 @@ const InternalTable = < // useAsync hook for 'rows' scenario const [_areRowsLoading, rowsResult, rowsError, reloadRows] = useAsync( handleFiltering, - [searchKey, sortBy, sortOrder, rows, JSON.stringify(otherFilters), visibleColumns], + [searchKey, filter, sortBy, sortOrder, rows, JSON.stringify(otherFilters), visibleColumns], !!rows, ) + // NOTE: passing getRows to queryKey won't trigger a refetch + // since it is a function + const lastUpdatedGetRowsInstance = useMemo(() => new Date().toISOString(), [getRows]) + // useAsync hook for 'getRows' scenario const { isFetching: _areGetRowsLoading, @@ -160,8 +166,7 @@ const InternalTable = < searchKey, sortBy, sortOrder, - // !TODO: functions in queryKey cannot trigger refetch - // getRows, + lastUpdatedGetRowsInstance, offset, pageSize, JSON.stringify(otherFilters), @@ -191,7 +196,8 @@ const InternalTable = < } if (!areFilteredRowsLoading && !filteredRows?.length && !loading) { - return filtersVariant !== FiltersTypeEnum.NONE && areFiltersApplied ? ( + return filtersVariant !== FiltersTypeEnum.NONE && + (userProvidedAreFiltersApplied !== undefined ? userProvidedAreFiltersApplied : areFiltersApplied) ? ( { const scrollEventHandler = () => { @@ -188,7 +190,7 @@ const TableContent = < useEffectAfterMount(() => { setActiveRowIndex(0) - }, [offset, visibleRows]) + }, [offset]) useEffect(() => { setIdentifiers?.( @@ -203,6 +205,54 @@ const TableContent = < handleSorting(newSortBy) } + useEffect(() => { + if (!isAnyRowExpandable) { + return () => {} + } + + const getExpandCollapseRowHandler = + (state: boolean) => + ({ detail: { activeRowData } }) => { + if ((activeRowData as RowType).expandableRows) { + setExpandState((prev) => ({ + ...prev, + [activeRowData.id]: state, + })) + } + } + + const handleExpandRow = getExpandCollapseRowHandler(true) + const handleCollapseRow = getExpandCollapseRowHandler(false) + + const signals = EVENT_TARGET as SignalsType + + signals.addEventListener(SignalEnum.EXPAND_ROW, handleExpandRow) + signals.addEventListener(SignalEnum.COLLAPSE_ROW, handleCollapseRow) + + return () => { + signals.removeEventListener(SignalEnum.EXPAND_ROW, handleExpandRow) + signals.removeEventListener(SignalEnum.COLLAPSE_ROW, handleCollapseRow) + } + }, [isAnyRowExpandable]) + + useEffect(() => { + if (!onRowClick) { + return () => {} + } + + const handleEnterPress = ({ detail: { activeRowData } }) => { + onRowClick(activeRowData, activeRowData.id.startsWith('expanded-row-' satisfies ExpandedRowPrefixType)) + } + + const signals = EVENT_TARGET as SignalsType + + signals.addEventListener(SignalEnum.ENTER_PRESSED, handleEnterPress) + + return () => { + signals.removeEventListener(SignalEnum.ENTER_PRESSED, handleEnterPress) + } + }, [onRowClick]) + const toggleExpandAll = (e: MouseEvent) => { e.stopPropagation() @@ -247,14 +297,16 @@ const TableContent = < return Object.values(bulkSelectionState) } + const showIconOrExpandActionGutter = isBulkSelectionConfigured || !!rowStartIconConfig || isAnyRowExpandable + const renderRows = () => { - if (loading) { + if (loading && !visibleColumns.length) { return SHIMMER_DUMMY_ARRAY.map((shimmerRowLabel) => (
- {isBulkSelectionConfigured ?
: null} + {showIconOrExpandActionGutter ?
: null} {SHIMMER_DUMMY_ARRAY.map((shimmerCellLabel) => (
))} @@ -262,7 +314,7 @@ const TableContent = < )) } - if (areFilteredRowsLoading) { + if (areFilteredRowsLoading || (loading && visibleColumns.length)) { return SHIMMER_DUMMY_ARRAY.map((shimmerRowLabel) => (
+ {showIconOrExpandActionGutter ? ( +
+
+
+ ) : null} {visibleColumns.map(({ label }) => (
@@ -364,7 +421,7 @@ const TableContent = < ariaLabel="Expand/Collapse row" showAriaLabelInTippy={false} variant={ButtonVariantType.borderLess} - size={ComponentSizeType.xs} + size={ComponentSizeType.xxs} style={ButtonStyleType.neutral} onClick={toggleExpandRow} /> @@ -467,9 +524,9 @@ const TableContent = < ref={headerRef} className="bg__primary dc__min-width-fit-content px-20 border__secondary--bottom dc__position-sticky dc__zi-2 dc__top-0 generic-table__header" > - {loading ? ( + {loading && !visibleColumns.length ? (
- {isBulkSelectionConfigured ?
: null} + {showIconOrExpandActionGutter ?
: null} {SHIMMER_DUMMY_ARRAY.map((label) => (
))} @@ -498,13 +555,15 @@ const TableContent = < ariaLabel="Expand/Collapse all rows" showAriaLabelInTippy={false} variant={ButtonVariantType.borderLess} - size={ComponentSizeType.xs} + size={ComponentSizeType.xxs} style={ButtonStyleType.neutral} onClick={toggleExpandAll} />
) : null} + {!isAnyRowExpandable && rowStartIconConfig &&
} + {visibleColumns.map( ( { diff --git a/src/Shared/Components/Table/styles.scss b/src/Shared/Components/Table/styles.scss index ecc29cb3f..16bfa0e00 100644 --- a/src/Shared/Components/Table/styles.scss +++ b/src/Shared/Components/Table/styles.scss @@ -43,7 +43,7 @@ &.expand-row-btn::before, &.row-start-icon::before, - &.expanded-tree-libe::before { + &.expanded-tree-line::before { left: -24px; width: 24px; } @@ -76,6 +76,10 @@ outline: none; } + &--expanded-row:has(+ .generic-table__row--expanded-row) { + border-bottom: 0px; + } + &:hover, &:hover > *, &--active, diff --git a/src/Shared/Components/Table/types.ts b/src/Shared/Components/Table/types.ts index ddf7f27ea..a45d2b7f8 100644 --- a/src/Shared/Components/Table/types.ts +++ b/src/Shared/Components/Table/types.ts @@ -33,6 +33,8 @@ import { useBulkSelection, UseBulkSelectionProps } from '../BulkSelection' export interface UseFiltersReturnType extends UseStateFiltersReturnType {} export enum SignalEnum { + COLLAPSE_ROW = 'collapse-row', + EXPAND_ROW = 'expand-row', ENTER_PRESSED = 'enter-pressed', DELETE_PRESSED = 'delete-pressed', ESCAPE_PRESSED = 'escape-pressed', @@ -237,7 +239,11 @@ export type ViewWrapperProps< : {}) > -type FilterConfig = { +type FilterConfig< + FilterVariant extends FiltersTypeEnum, + RowData extends unknown, + AdditionalProps extends Record, +> = { filtersVariant: FilterVariant /** * Props for useUrlFilters/useStateFilters hooks @@ -251,12 +257,14 @@ type FilterConfig, filterData: UseFiltersReturnType) => boolean + : (row: RowType, filterData: UseFiltersReturnType, additionalProps: AdditionalProps) => boolean clearFilters?: FilterVariant extends FiltersTypeEnum.URL ? () => void : FilterVariant extends FiltersTypeEnum.STATE ? never : never + + areFiltersApplied?: FilterVariant extends FiltersTypeEnum.NONE ? never : boolean } export type InternalTableProps< @@ -360,7 +368,7 @@ export type InternalTableProps< pageSizeOptions?: never } ) & - FilterConfig + FilterConfig export type UseResizableTableConfigWrapperProps< RowData extends unknown, @@ -415,6 +423,7 @@ export type TableProps< | 'clearFilters' | 'rowStartIconConfig' | 'onRowClick' + | 'areFiltersApplied' > export type BulkActionStateType = string | null diff --git a/src/Shared/Components/Table/useTableWithKeyboardShortcuts.ts b/src/Shared/Components/Table/useTableWithKeyboardShortcuts.ts index a7a67a14b..cb51044c9 100644 --- a/src/Shared/Components/Table/useTableWithKeyboardShortcuts.ts +++ b/src/Shared/Components/Table/useTableWithKeyboardShortcuts.ts @@ -101,6 +101,20 @@ const useTableWithKeyboardShortcuts = < ) useEffect(() => { + registerShortcut({ + keys: ['ArrowLeft'], + callback: () => { + dispatchEvent(SignalEnum.COLLAPSE_ROW) + }, + }) + + registerShortcut({ + keys: ['ArrowRight'], + callback: () => { + dispatchEvent(SignalEnum.EXPAND_ROW) + }, + }) + registerShortcut({ keys: ['ArrowDown'], callback: () => { @@ -142,6 +156,8 @@ const useTableWithKeyboardShortcuts = < unregisterShortcut(['Enter']) unregisterShortcut(['Backspace']) unregisterShortcut(['.']) + unregisterShortcut(['ArrowLeft']) + unregisterShortcut(['ArrowRight']) } }, [getMoveFocusToNextRowHandler, getMoveFocusToPreviousRowHandler, dispatchEvent]) diff --git a/src/Shared/Components/Table/utils.ts b/src/Shared/Components/Table/utils.ts index 8e9ff9580..5d0f4b46a 100644 --- a/src/Shared/Components/Table/utils.ts +++ b/src/Shared/Components/Table/utils.ts @@ -42,11 +42,12 @@ export const searchAndSortRows = < rows: TableProps['rows'], filter: TableProps['filter'], filterData: UseFiltersReturnType, + additionalProps: AdditionalProps, comparator?: Column['comparator'], ): Awaited['getRows']>> => { const { sortBy, sortOrder } = filterData ?? {} - const filteredRows = filter ? rows.filter((row) => filter(row, filterData)) : rows + const filteredRows = filter ? rows.filter((row) => filter(row, filterData, additionalProps)) : rows return { rows: