From 14ad8738c9cd93f16aa60dd90ff52699764847f8 Mon Sep 17 00:00:00 2001 From: Keith Chong Date: Wed, 1 Oct 2025 15:34:38 -0400 Subject: [PATCH] Application list page sorting issue (#7821) Signed-off-by: Keith Chong --- .../application/ApplicationResourcesTab.tsx | 59 +++++++------- .../application/ApplicationSyncStatusTab.tsx | 59 +++++++------- .../application/History/History.tsx | 48 ++++++----- .../components/shared/ApplicationList.tsx | 81 +++++++++---------- 4 files changed, 122 insertions(+), 125 deletions(-) diff --git a/src/gitops/components/application/ApplicationResourcesTab.tsx b/src/gitops/components/application/ApplicationResourcesTab.tsx index 98ce4754..1db7a3d3 100644 --- a/src/gitops/components/application/ApplicationResourcesTab.tsx +++ b/src/gitops/components/application/ApplicationResourcesTab.tsx @@ -72,16 +72,33 @@ const ApplicationResourcesTab: React.FC = ({ obj } if (resources.length === 0) { currentActiveState = DataViewState.empty; } + + const COLUMNS_KEYS_INDEXES = React.useMemo( + () => [ + { key: 'name', index: 0 }, + { key: 'namespace', index: 1 }, + { key: 'sync-wave', index: 2 }, + { key: 'sync-status', index: 3 }, + { key: 'health-status', index: 4 }, + ], + [], + ); + const [searchParams, setSearchParams] = useSearchParams(); const { sortBy, direction, onSort } = useDataViewSort({ searchParams, setSearchParams }); - const getSortParams = (columnId: string, columnIndex: number) => ({ + const sortByIndex = React.useMemo( + () => COLUMNS_KEYS_INDEXES.findIndex((item) => item.key === sortBy), + [COLUMNS_KEYS_INDEXES, sortBy], + ); + + const getSortParams = (columnIndex: number) => ({ sortBy: { - index: columnIndex, + index: sortByIndex, direction, defaultDirection: 'asc' as const, }, onSort: (_event: any, index: number, dir: 'asc' | 'desc') => { - onSort(_event, columnId, dir); + onSort(_event, COLUMNS_KEYS_INDEXES[index].key, dir); }, columnIndex, }); @@ -185,18 +202,11 @@ const sortData = ( } if (direction === 'asc') { - if (aValue < bValue) { - return -1; - } else if (aValue > bValue) { - return 1; - } - return 0; + // eslint-disable-next-line no-nested-ternary + return aValue < bValue ? -1 : aValue > bValue ? 1 : 0; } else { - if (aValue > bValue) { - return -1; - } else if (aValue < bValue) { - return 1; - } + // eslint-disable-next-line no-nested-ternary + return aValue > bValue ? -1 : aValue < bValue ? 1 : 0; } }); }; @@ -204,57 +214,46 @@ const sortData = ( export const useResourceColumnsDV = (getSortParams) => { const columns: DataViewTh[] = [ { - id: 'name', cell: t('plugin__gitops-plugin~Name'), props: { - key: 'name', 'aria-label': 'name', className: 'pf-m-width-25', - sort: getSortParams('name', 0), + sort: getSortParams(0), }, }, { - id: 'namespace', cell: 'Namespace', props: { - key: 'namespace', 'aria-label': 'namespace', className: 'pf-m-width-20', - sort: getSortParams('namespace', 1), + sort: getSortParams(1), }, }, { - id: 'sync-wave', cell: 'Sync Wave', props: { - key: 'sync-wave', 'aria-label': 'sync wave', className: 'pf-m-width-15', - sort: getSortParams('sync-wave', 2), + sort: getSortParams(2), }, }, { - id: 'sync-status', cell: 'Sync Status', props: { - key: 'sync-status', 'aria-label': 'sync status', className: 'pf-m-width-15', - sort: getSortParams('sync-status', 3), + sort: getSortParams(3), }, }, { - id: 'health-status', cell: 'Health Status', props: { - key: 'health-status', 'aria-label': 'health status', className: 'pf-m-width-15', - sort: getSortParams('health-status', 4), + sort: getSortParams(4), }, }, { - id: 'actions', cell: '', props: { 'aria-label': 'actions' }, }, diff --git a/src/gitops/components/application/ApplicationSyncStatusTab.tsx b/src/gitops/components/application/ApplicationSyncStatusTab.tsx index 60422d37..5797ef3c 100644 --- a/src/gitops/components/application/ApplicationSyncStatusTab.tsx +++ b/src/gitops/components/application/ApplicationSyncStatusTab.tsx @@ -80,16 +80,31 @@ const ApplicationSyncStatusTab: React.FC = ({ obj if (resources.length === 0) { currentActiveState = DataViewState.empty; } + + const COLUMNS_KEYS_INDEXES = React.useMemo( + () => [ + { key: 'name', index: 0 }, + { key: 'namespace', index: 1 }, + { key: 'status', index: 2 }, + { key: 'hook', index: 3 }, + { key: 'message', index: 4 }, + ], + [], + ); const [searchParams, setSearchParams] = useSearchParams(); const { sortBy, direction, onSort } = useDataViewSort({ searchParams, setSearchParams }); - const getSortParams = (columnId: string, columnIndex: number) => ({ + const sortByIndex = React.useMemo( + () => COLUMNS_KEYS_INDEXES.findIndex((item) => item.key === sortBy), + [COLUMNS_KEYS_INDEXES, sortBy], + ); + const getSortParams = (columnIndex: number) => ({ sortBy: { - index: columnIndex, + index: sortByIndex, direction, defaultDirection: 'asc' as const, }, onSort: (_event: any, index: number, dir: 'asc' | 'desc') => { - onSort(_event, columnId, dir); + onSort(_event, COLUMNS_KEYS_INDEXES[index].key, dir); }, columnIndex, }); @@ -325,20 +340,11 @@ const sortData = ( } if (direction === 'asc') { - if (aValue < bValue) { - return -1; - } else if (aValue > bValue) { - return 1; - } - return 0; - // return aValue < bValue ? -1 : aValue > bValue ? 1 : 0; + // eslint-disable-next-line no-nested-ternary + return aValue < bValue ? -1 : aValue > bValue ? 1 : 0; } else { - if (aValue > bValue) { - return -1; - } else if (aValue < bValue) { - return 1; - } - return 0; // return aValue > bValue ? -1 : aValue < bValue ? 1 : 0; + // eslint-disable-next-line no-nested-ternary + return aValue > bValue ? -1 : aValue < bValue ? 1 : 0; } }); }; @@ -346,57 +352,46 @@ const sortData = ( export const useResourceColumnsDV = (getSortParams) => { const columns: DataViewTh[] = [ { - id: 'name', cell: t('plugin__gitops-plugin~Name'), props: { - key: 'name', 'aria-label': 'name', className: 'pf-m-width-25', - sort: getSortParams('name', 0), + sort: getSortParams(0), }, }, { - id: 'namespace', cell: 'Namespace', props: { - key: 'namespace', 'aria-label': 'namespace', className: 'pf-m-width-20', - sort: getSortParams('namespace', 1), + sort: getSortParams(1), }, }, { - id: 'status', cell: 'Status', props: { - key: 'status', 'aria-label': 'status', className: 'pf-m-width-15', - sort: getSortParams('status', 2), + sort: getSortParams(2), }, }, { - id: 'hook', cell: 'Hook', props: { - key: 'hook', 'aria-label': 'hook', className: 'pf-m-width-15', - sort: getSortParams('hook', 3), + sort: getSortParams(3), }, }, { - id: 'message', cell: 'Message', props: { - key: 'message', 'aria-label': 'message', className: 'pf-m-width-15', - sort: getSortParams('message', 4), + sort: getSortParams(4), }, }, { - id: 'actions', cell: '', props: { 'aria-label': 'actions', diff --git a/src/gitops/components/application/History/History.tsx b/src/gitops/components/application/History/History.tsx index 25a91396..f25a886b 100644 --- a/src/gitops/components/application/History/History.tsx +++ b/src/gitops/components/application/History/History.tsx @@ -26,16 +26,31 @@ interface HistoryListProps { } const HistoryList: React.FC = ({ history, obj }) => { + const COLUMNS_KEYS_INDEXES = React.useMemo( + () => [ + { key: 'id', index: 0 }, + { key: 'started-at', index: 1 }, + { key: 'deployed-at', index: 2 }, + { key: 'initiated-by', index: 3 }, + { key: 'revision', index: 4 }, + ], + [], + ); + const [searchParams, setSearchParams] = useSearchParams(); const { sortBy, direction, onSort } = useDataViewSort({ searchParams, setSearchParams }); - const getSortParams = (columnId: string, columnIndex: number) => ({ + const sortByIndex = React.useMemo( + () => COLUMNS_KEYS_INDEXES.findIndex((item) => item.key === sortBy), + [COLUMNS_KEYS_INDEXES, sortBy], + ); + const getSortParams = (columnIndex: number) => ({ sortBy: { - index: columnIndex, + index: sortByIndex, direction, defaultDirection: 'asc' as const, }, onSort: (_event: any, index: number, dir: 'asc' | 'desc') => { - onSort(_event, columnId, dir); + onSort(_event, COLUMNS_KEYS_INDEXES[index].key, dir); }, columnIndex, }); @@ -169,12 +184,12 @@ const useRowsDV = (history: ApplicationHistory[], app: ApplicationKind): DataVie }, { cell: , - id: 'deployStartedAt', + id: 'started-at', dataLabel: 'Deployed Started At', }, { cell: , - id: 'deployedAt', + id: 'deployed-at', dataLabel: 'Depoyed At', }, { @@ -195,48 +210,39 @@ const useRowsDV = (history: ApplicationHistory[], app: ApplicationKind): DataVie const useColumnsDV = (getSortParams) => { const columns: DataViewTh[] = [ { - id: 'id', cell: 'ID', props: { - key: 'id', 'aria-label': 'ID', - sort: getSortParams('id', 0), + sort: getSortParams(0), }, }, { cell: 'Deploy Started At', - id: 'deployStartedAt', props: { - key: `deployStartedAt`, className: 'pf-m-width-15', - sort: getSortParams('deployStartedAt', 1), + sort: getSortParams(1), }, }, { cell: 'Deployed At', - id: 'deployedAt', props: { - key: 'deployedAt', className: 'pf-m-width-15', - sort: getSortParams('deployedAt', 2), + sort: getSortParams(2), }, }, { cell: 'Initiated By', - id: 'initiated-by', props: { - key: 'initiated-by', className: 'pf-m-width-15', - sort: getSortParams('initiated-by', 3), + sort: getSortParams(3), }, }, { cell: 'Revision(s) and Source Repo URL(s)', - id: 'revision', props: { key: 'revision', className: 'gitops-admin-plugin__history-id-column pf-m-width-50', - sort: getSortParams('revision', 4), + sort: getSortParams(4), }, }, ]; @@ -259,11 +265,11 @@ const sortData = ( aValue = a.id || ''; bValue = b.id || ''; break; - case 'deployStartedAt': + case 'started-at': aValue = a.deployStartedAt || ''; bValue = b.deployStartedAt || ''; break; - case 'deployedAt': + case 'deployed-at': aValue = a.deployedAt || ''; bValue = b.deployedAt || ''; break; diff --git a/src/gitops/components/shared/ApplicationList.tsx b/src/gitops/components/shared/ApplicationList.tsx index fd2f8fbf..4c994961 100644 --- a/src/gitops/components/shared/ApplicationList.tsx +++ b/src/gitops/components/shared/ApplicationList.tsx @@ -25,7 +25,7 @@ import { import { useDataViewSort } from '@patternfly/react-data-view/dist/dynamic/Hooks'; import DataView, { DataViewState } from '@patternfly/react-data-view/dist/esm/DataView'; import { CubesIcon } from '@patternfly/react-icons'; -import { Tbody, Td, Tr } from '@patternfly/react-table'; +import { Tbody, Td, ThProps, Tr } from '@patternfly/react-table'; import { useApplicationActionsProvider } from '../..//hooks/useApplicationActionsProvider'; import RevisionFragment from '../..//Revision/Revision'; @@ -90,17 +90,33 @@ const ApplicationList: React.FC = ({ }); const { t } = useTranslation(); + const initIndex: number = namespace ? 0 : 1; + const COLUMNS_KEYS_INDEXES = React.useMemo( + () => [ + { key: 'name', index: 0 }, + ...(!namespace ? [{ key: 'namespace', index: 1 }] : []), + { key: 'sync-status', index: 1 + initIndex }, + { key: 'health-status', index: 2 + initIndex }, + { key: 'revision', index: 3 + initIndex }, + { key: 'project', index: 4 + initIndex }, + ], + [namespace, initIndex], + ); const [searchParams, setSearchParams] = useSearchParams(); const { sortBy, direction, onSort } = useDataViewSort({ searchParams, setSearchParams }); - const getSortParams = (columnId: string, columnIndex: number) => ({ + const sortByIndex = React.useMemo( + () => COLUMNS_KEYS_INDEXES.findIndex((item) => item.key === sortBy), + [COLUMNS_KEYS_INDEXES, sortBy], + ); + const getSortParams = (columnIndex: number): ThProps['sort'] => ({ sortBy: { - index: columnIndex, + index: sortByIndex, direction, - defaultDirection: 'asc' as const, + defaultDirection: 'asc', }, - onSort: (_event: any, index: number, dir: 'asc' | 'desc') => { - onSort(_event, columnId, dir); + onSort: (_event: any, index: number, dir) => { + onSort(_event, COLUMNS_KEYS_INDEXES[index].key, dir); }, columnIndex, }); @@ -187,7 +203,7 @@ export const sortData = ( sortBy: string | undefined, direction: 'asc' | 'desc' | undefined, ) => { - if (!sortBy || !direction) return data; + if (!(sortBy && direction)) return data; return [...data].sort((a, b) => { let aValue: any, bValue: any; @@ -197,6 +213,10 @@ export const sortData = ( aValue = a.metadata?.name || ''; bValue = b.metadata?.name || ''; break; + case 'namespace': + aValue = a.metadata?.namespace || ''; + bValue = b.metadata?.namespace || ''; + break; case 'sync-status': aValue = a.status?.sync?.status || ''; bValue = b.status?.sync?.status || ''; @@ -218,20 +238,11 @@ export const sortData = ( } if (direction === 'asc') { - if (aValue < bValue) { - return -1; - } else if (aValue > bValue) { - return 1; - } - return 0; - // return aValue < bValue ? -1 : aValue > bValue ? 1 : 0; + // eslint-disable-next-line no-nested-ternary + return aValue < bValue ? -1 : aValue > bValue ? 1 : 0; } else { - if (aValue > bValue) { - return -1; - } else if (aValue < bValue) { - return 1; - } - return 0; // return aValue > bValue ? -1 : aValue < bValue ? 1 : 0; + // eslint-disable-next-line no-nested-ternary + return aValue > bValue ? -1 : aValue < bValue ? 1 : 0; } }); }; @@ -348,81 +359,67 @@ const useApplicationRowsDV = (applicationsList, namespace): DataViewTr[] => { return rows; }; -const useColumnsDV = (namespace, getSortParams) => { - const i: number = namespace ? 1 : 0; +const useColumnsDV = (namespace, getSortParams): DataViewTh[] => { + const i: number = namespace ? 0 : 1; const { t } = useTranslation('plugin__gitops-plugin'); const columns: DataViewTh[] = [ { - id: 'name', cell: t('plugin__gitops-plugin~Name'), props: { - key: 'name', 'aria-label': 'name', className: 'pf-m-width-25', - sort: getSortParams('name', 0), + sort: getSortParams(0), }, }, ...(!namespace ? [ { - id: 'namespace', cell: 'Namespace', props: { - key: 'namespace', 'aria-label': 'namespace', className: 'pf-m-width-15', - sort: getSortParams('namespace', 1), + sort: getSortParams(1), }, }, ] : []), { - id: 'sync-status', cell: 'Sync Status', props: { - key: 'sync-status', 'aria-label': 'sync status', className: 'pf-m-width-15', - sort: getSortParams('sync-status', 1 + i), + sort: getSortParams(1 + i), }, }, { - id: 'health-status', cell: 'Health Status', props: { - key: 'health-status', 'aria-label': 'health status', className: 'pf-m-width-15', - sort: getSortParams('health-status', 2 + i), + sort: getSortParams(2 + i), }, }, { - id: 'revision', cell: 'Revision', props: { - key: 'revision', 'aria-label': 'revision', className: 'pf-m-width-12', - sort: getSortParams('revision', 3 + i), + sort: getSortParams(3 + i), }, }, { - id: 'project', cell: 'App Project', props: { - key: 'project', 'aria-label': 'project', className: 'pf-m-width-20', - sort: getSortParams('project', 4 + i), + sort: getSortParams(4 + i), }, }, { - id: 'actions', cell: '', props: { 'aria-label': 'actions' }, }, ]; - return columns; };