From 26311b39fbd919476fa1c5fd3ab08fcf57c44b55 Mon Sep 17 00:00:00 2001 From: Keith Chong Date: Wed, 17 Dec 2025 16:56:06 -0500 Subject: [PATCH] Show All Namespaces or Current Namespace Only option (#8535) Signed-off-by: Keith Chong --- locales/en/olm.json | 5 +++ locales/ja/olm.json | 5 +++ locales/ko/olm.json | 5 +++ locales/zh/olm.json | 5 +++ src/gitops/components/project/ProjectList.tsx | 22 ++++++++-- src/gitops/components/rollout/RolloutList.tsx | 24 +++++++++-- .../AnalysisRunStatus/AnalysisRunStatus.tsx | 6 +-- .../ShowOperandsInAllNamespacesRadioGroup.tsx | 40 +++++++++++++++++++ .../components/shared/AllNamespaces/index.ts | 2 + .../useShowOperandsInAllNamespaces.ts | 25 ++++++++++++ .../components/shared/ApplicationList.tsx | 37 +++++++++++++++-- .../components/shared/ApplicationSetList.tsx | 22 ++++++++-- 12 files changed, 179 insertions(+), 19 deletions(-) create mode 100644 locales/en/olm.json create mode 100644 locales/ja/olm.json create mode 100644 locales/ko/olm.json create mode 100644 locales/zh/olm.json create mode 100644 src/gitops/components/shared/AllNamespaces/ShowOperandsInAllNamespacesRadioGroup.tsx create mode 100644 src/gitops/components/shared/AllNamespaces/index.ts create mode 100644 src/gitops/components/shared/AllNamespaces/useShowOperandsInAllNamespaces.ts diff --git a/locales/en/olm.json b/locales/en/olm.json new file mode 100644 index 00000000..2345b476 --- /dev/null +++ b/locales/en/olm.json @@ -0,0 +1,5 @@ +{ + "Show operands in:": "Show operands in:", + "All namespaces": "All namespaces", + "Current namespace only": "Current namespace only" +} diff --git a/locales/ja/olm.json b/locales/ja/olm.json new file mode 100644 index 00000000..2345b476 --- /dev/null +++ b/locales/ja/olm.json @@ -0,0 +1,5 @@ +{ + "Show operands in:": "Show operands in:", + "All namespaces": "All namespaces", + "Current namespace only": "Current namespace only" +} diff --git a/locales/ko/olm.json b/locales/ko/olm.json new file mode 100644 index 00000000..2345b476 --- /dev/null +++ b/locales/ko/olm.json @@ -0,0 +1,5 @@ +{ + "Show operands in:": "Show operands in:", + "All namespaces": "All namespaces", + "Current namespace only": "Current namespace only" +} diff --git a/locales/zh/olm.json b/locales/zh/olm.json new file mode 100644 index 00000000..2345b476 --- /dev/null +++ b/locales/zh/olm.json @@ -0,0 +1,5 @@ +{ + "Show operands in:": "Show operands in:", + "All namespaces": "All namespaces", + "Current namespace only": "Current namespace only" +} diff --git a/src/gitops/components/project/ProjectList.tsx b/src/gitops/components/project/ProjectList.tsx index 9b733305..5ace36b9 100644 --- a/src/gitops/components/project/ProjectList.tsx +++ b/src/gitops/components/project/ProjectList.tsx @@ -35,6 +35,10 @@ import { Tbody, Td, Tr } from '@patternfly/react-table'; import { ApplicationKind } from '../../models/ApplicationModel'; import { AppProjectKind, AppProjectModel } from '../../models/AppProjectModel'; +import { + ShowOperandsInAllNamespacesRadioGroup, + useShowOperandsInAllNamespaces, +} from '../shared/AllNamespaces'; import { GitOpsDataViewTable, useGitOpsDataViewSort } from '../shared/DataView'; import { useProjectActionsProvider } from './hooks/useProjectActionsProvider'; @@ -53,6 +57,12 @@ const ProjectList: React.FC = ({ showTitle, }) => { const location = useLocation(); + const [showOperandsInAllNamespaces] = useShowOperandsInAllNamespaces(); + const listAllNamespaces = + location.pathname?.includes('openshift-gitops-operator') && showOperandsInAllNamespaces; + if (listAllNamespaces) { + namespace = null; + } const [appProjects, loaded, loadError] = useK8sWatchResource({ isList: true, groupVersionKind: { @@ -60,7 +70,7 @@ const ProjectList: React.FC = ({ kind: 'AppProject', version: 'v1alpha1', }, - namespaced: true, + namespaced: !listAllNamespaces, namespace, }); @@ -77,17 +87,16 @@ const ProjectList: React.FC = ({ }); const columnSortConfig = React.useMemo(() => { - const showNamespace = !namespace || namespace === ''; return [ 'name', - ...(showNamespace ? ['namespace'] : []), + ...(!listAllNamespaces || !namespace || namespace === '' ? ['namespace'] : []), 'description', 'applications', 'labels', 'last-updated', 'actions', ].map((key) => ({ key })); - }, [namespace]); + }, [listAllNamespaces, namespace]); const { searchParams, sortBy, direction, getSortParams } = useGitOpsDataViewSort(columnSortConfig); @@ -195,6 +204,11 @@ const ProjectList: React.FC = ({ badge={ location?.pathname?.includes('openshift-gitops-operator') ? null : } + helpText={ + location.pathname?.includes('openshift-gitops-operator') ? ( + + ) : null + } hideFavoriteButton={false} > diff --git a/src/gitops/components/rollout/RolloutList.tsx b/src/gitops/components/rollout/RolloutList.tsx index 46be949b..f2fe99c4 100644 --- a/src/gitops/components/rollout/RolloutList.tsx +++ b/src/gitops/components/rollout/RolloutList.tsx @@ -34,6 +34,10 @@ import { DataViewTh, DataViewTr } from '@patternfly/react-data-view/dist/esm/Dat import { CubesIcon, SearchIcon } from '@patternfly/react-icons'; import { Tbody, Td, ThProps, Tr } from '@patternfly/react-table'; +import { + ShowOperandsInAllNamespacesRadioGroup, + useShowOperandsInAllNamespaces, +} from '../shared/AllNamespaces'; import { GitOpsDataViewTable, useGitOpsDataViewSort } from '../shared/DataView'; import { useRolloutActionsProvider } from './hooks/useRolloutActionsProvider'; @@ -73,6 +77,12 @@ const RolloutList: React.FC = ({ hideNameLabelFilters, showTitle, }) => { + const [showOperandsInAllNamespaces] = useShowOperandsInAllNamespaces(); + const listAllNamespaces = + location.pathname?.includes('openshift-gitops-operator') && showOperandsInAllNamespaces; + if (listAllNamespaces) { + namespace = null; + } const [rollouts, loaded, loadError] = useK8sWatchResource({ isList: true, groupVersionKind: { @@ -80,14 +90,14 @@ const RolloutList: React.FC = ({ kind: 'Rollout', version: 'v1alpha1', }, - namespaced: true, + namespaced: !listAllNamespaces, namespace, }); const columnSortConfig = React.useMemo( () => [ 'name', - ...(!namespace ? ['namespace'] : []), + ...(!listAllNamespaces || !namespace ? ['namespace'] : []), 'status', 'pods', 'labels', @@ -95,7 +105,7 @@ const RolloutList: React.FC = ({ 'last-updated', 'actions', ].map((key) => ({ key })), - [namespace], + [listAllNamespaces, namespace], ); const { searchParams, sortBy, direction, getSortParams } = @@ -153,7 +163,7 @@ const RolloutList: React.FC = ({ @@ -164,6 +174,7 @@ const RolloutList: React.FC = ({ const topologyUrl = namespace ? '/topology/ns/' + namespace + '?view=graph' : '/topology/all-namespaces?view=graph'; + return ( <> {showTitle == undefined && ( @@ -172,6 +183,11 @@ const RolloutList: React.FC = ({ badge={ location.pathname?.includes('openshift-gitops-operator') ? null : } + helpText={ + location.pathname?.includes('openshift-gitops-operator') ? ( + + ) : null + } > {t('Create Rollout')} diff --git a/src/gitops/components/rollout/components/AnalysisRunStatus/AnalysisRunStatus.tsx b/src/gitops/components/rollout/components/AnalysisRunStatus/AnalysisRunStatus.tsx index f0c67e99..374ea0bf 100644 --- a/src/gitops/components/rollout/components/AnalysisRunStatus/AnalysisRunStatus.tsx +++ b/src/gitops/components/rollout/components/AnalysisRunStatus/AnalysisRunStatus.tsx @@ -101,11 +101,7 @@ const Metrics: React.FC = ({ arInfo }) => { } return ( <> - + Started At: diff --git a/src/gitops/components/shared/AllNamespaces/ShowOperandsInAllNamespacesRadioGroup.tsx b/src/gitops/components/shared/AllNamespaces/ShowOperandsInAllNamespacesRadioGroup.tsx new file mode 100644 index 00000000..766ba1eb --- /dev/null +++ b/src/gitops/components/shared/AllNamespaces/ShowOperandsInAllNamespacesRadioGroup.tsx @@ -0,0 +1,40 @@ +import * as React from 'react'; + +import { t } from '@gitops/utils/hooks/useGitOpsTranslation'; +import { useShowOperandsInAllNamespaces } from '@gitops-shared/AllNamespaces/useShowOperandsInAllNamespaces'; +import { Form, FormGroup, Radio } from '@patternfly/react-core'; + +export const ShowOperandsInAllNamespacesRadioGroup: React.FC = () => { + const [showOperandsInAllNamespaces, setShowOperandsInAllNamespaces] = + useShowOperandsInAllNamespaces(); + return ( +
+ + setShowOperandsInAllNamespaces(true)} + isChecked={showOperandsInAllNamespaces} + data-checked-state={showOperandsInAllNamespaces} + /> + setShowOperandsInAllNamespaces(false)} + isChecked={!showOperandsInAllNamespaces} + data-checked-state={!showOperandsInAllNamespaces} + /> + +
+ ); +}; diff --git a/src/gitops/components/shared/AllNamespaces/index.ts b/src/gitops/components/shared/AllNamespaces/index.ts new file mode 100644 index 00000000..18bd39d4 --- /dev/null +++ b/src/gitops/components/shared/AllNamespaces/index.ts @@ -0,0 +1,2 @@ +export * from './ShowOperandsInAllNamespacesRadioGroup'; +export * from './useShowOperandsInAllNamespaces'; diff --git a/src/gitops/components/shared/AllNamespaces/useShowOperandsInAllNamespaces.ts b/src/gitops/components/shared/AllNamespaces/useShowOperandsInAllNamespaces.ts new file mode 100644 index 00000000..ff535b34 --- /dev/null +++ b/src/gitops/components/shared/AllNamespaces/useShowOperandsInAllNamespaces.ts @@ -0,0 +1,25 @@ +import { useCallback } from 'react'; +import { RootStateOrAny, useDispatch, useSelector } from 'react-redux'; +import { action } from 'typesafe-actions'; +type UseShowOperandsInAllNamespaces = () => [boolean, (value: boolean) => void]; + +// This hook can be used to consume and update the showOperandsInAllNamespaces redux state +export const useShowOperandsInAllNamespaces: UseShowOperandsInAllNamespaces = () => { + const dispatch = useDispatch(); + const showOperandsInAllNamespaces = useSelector((state: RootStateOrAny) => + state.UI.get('showOperandsInAllNamespaces'), + ); + const setShowOperandsInAllNamespaces = useCallback( + (value: boolean) => dispatch(uiActionsSetShowOperandsInAllNamespaces(value)), + [dispatch], + ); + return [showOperandsInAllNamespaces, setShowOperandsInAllNamespaces]; +}; + +export enum ActionType { + SetShowOperandsInAllNamespaces = 'setShowOperandsInAllNamespaces', +} + +export const uiActionsSetShowOperandsInAllNamespaces = (value: boolean) => { + return action(ActionType.SetShowOperandsInAllNamespaces, { value }); +}; diff --git a/src/gitops/components/shared/ApplicationList.tsx b/src/gitops/components/shared/ApplicationList.tsx index dc9850ca..3b425012 100644 --- a/src/gitops/components/shared/ApplicationList.tsx +++ b/src/gitops/components/shared/ApplicationList.tsx @@ -14,6 +14,7 @@ import { useK8sWatchResource, useListPageFilter, } from '@openshift-console/dynamic-plugin-sdk'; +import { ErrorState } from '@patternfly/react-component-groups'; import { EmptyState, EmptyStateBody, Flex, FlexItem, Spinner } from '@patternfly/react-core'; import { DataViewTh, DataViewTr } from '@patternfly/react-data-view/dist/esm/DataViewTable'; import { CubesIcon } from '@patternfly/react-icons'; @@ -35,6 +36,10 @@ import ActionsDropdown from '../../utils/components/ActionDropDown/ActionDropDow import { isApplicationRefreshing } from '../../utils/gitops'; import { modelToGroupVersionKind, modelToRef } from '../../utils/utils'; +import { + ShowOperandsInAllNamespacesRadioGroup, + useShowOperandsInAllNamespaces, +} from './AllNamespaces'; import { GitOpsDataViewTable, useGitOpsDataViewSort } from './DataView'; interface ApplicationProps { @@ -72,6 +77,12 @@ const ApplicationList: React.FC = ({ hideNameLabelFilters, showTitle, }) => { + const [showOperandsInAllNamespaces] = useShowOperandsInAllNamespaces(); + const listAllNamespaces = + location.pathname?.includes('openshift-gitops-operator') && showOperandsInAllNamespaces; + if (listAllNamespaces) { + namespace = null; + } const [applications, loaded, loadError] = useK8sWatchResource({ isList: true, groupVersionKind: { @@ -79,7 +90,7 @@ const ApplicationList: React.FC = ({ kind: 'Application', version: 'v1alpha1', }, - namespaced: true, + namespaced: !listAllNamespaces, namespace, }); @@ -88,14 +99,14 @@ const ApplicationList: React.FC = ({ () => [ 'name', - ...(!namespace ? ['namespace'] : []), + ...(!listAllNamespaces || !namespace ? ['namespace'] : []), 'sync-status', 'health-status', 'revision', 'project', 'actions', ].map((key) => ({ key })), - [namespace], + [listAllNamespaces, namespace], ); const { searchParams, sortBy, direction, getSortParams } = @@ -173,6 +184,20 @@ const ApplicationList: React.FC = ({ ); + const error = loadError && ( + + + + + + + + ); return (
{showTitle == undefined && (project == undefined || appset == undefined) && ( @@ -181,6 +206,11 @@ const ApplicationList: React.FC = ({ badge={ location.pathname?.includes('openshift-gitops-operator') ? null : } + helpText={ + location.pathname?.includes('openshift-gitops-operator') ? ( + + ) : null + } hideFavoriteButton={false} > @@ -203,6 +233,7 @@ const ApplicationList: React.FC = ({ rows={rows} isEmpty={filteredBySearch.length === 0} emptyState={empty} + errorState={error || undefined} isError={!!loadError} /> diff --git a/src/gitops/components/shared/ApplicationSetList.tsx b/src/gitops/components/shared/ApplicationSetList.tsx index dd3fbb7a..bad16c56 100644 --- a/src/gitops/components/shared/ApplicationSetList.tsx +++ b/src/gitops/components/shared/ApplicationSetList.tsx @@ -32,6 +32,10 @@ import { ApplicationSetStatus } from '../../utils/constants'; import { getAppSetGeneratorCount, getAppSetStatus } from '../../utils/gitops'; import { modelToGroupVersionKind, modelToRef } from '../../utils/utils'; +import { + ShowOperandsInAllNamespacesRadioGroup, + useShowOperandsInAllNamespaces, +} from './AllNamespaces'; import { GitOpsDataViewTable, useGitOpsDataViewSort } from './DataView'; const formatCreationTimestamp = (timestamp: string): string => { @@ -102,6 +106,13 @@ const ApplicationSetList: React.FC = ({ hideNameLabelFilters, showTitle, }) => { + const [showOperandsInAllNamespaces] = useShowOperandsInAllNamespaces(); + const listAllNamespaces = + location.pathname?.includes('openshift-gitops-operator') && showOperandsInAllNamespaces; + if (listAllNamespaces) { + namespace = null; + } + const [applicationSets, loaded, loadError] = useK8sWatchResource({ isList: true, groupVersionKind: { @@ -109,7 +120,7 @@ const ApplicationSetList: React.FC = ({ kind: 'ApplicationSet', version: 'v1alpha1', }, - namespaced: true, + namespaced: !listAllNamespaces, namespace, }); @@ -131,14 +142,14 @@ const ApplicationSetList: React.FC = ({ () => [ 'name', - ...(!namespace ? ['namespace'] : []), + ...(!listAllNamespaces || !namespace ? ['namespace'] : []), 'status', 'generated-apps', 'generators', 'created-at', 'actions', ].map((key) => ({ key })), - [namespace], + [listAllNamespaces, namespace], ); const { searchParams, sortBy, direction, getSortParams } = @@ -243,6 +254,11 @@ const ApplicationSetList: React.FC = ({ badge={ location.pathname?.includes('openshift-gitops-operator') ? null : } + helpText={ + location.pathname?.includes('openshift-gitops-operator') ? ( + + ) : null + } hideFavoriteButton={false} >