From 1e61f7e305898b66c485d38bc4a118325ca51730 Mon Sep 17 00:00:00 2001 From: Ali <83188384+testA113@users.noreply.github.com> Date: Wed, 23 Aug 2023 09:13:35 +1200 Subject: [PATCH] fix(ingress): handle system resources [EE-4775] (#9972) * fix(ingress): handle system resources [EE-4775] --- .../ConfigMapsDatatable.tsx | 20 +++---- .../SecretsDatatable/SecretsDatatable.tsx | 20 +++---- .../IngressDatatable/IngressDatatable.tsx | 60 ++++++++++++++----- .../IngressDatatable/columns/className.tsx | 1 + .../IngressDatatable/columns/ingressRules.tsx | 2 +- .../IngressDatatable/columns/name.tsx | 37 ++++++++---- .../IngressDatatable/columns/type.tsx | 1 + app/react/kubernetes/ingresses/queries.ts | 6 +- .../ServicesDatatable/ServicesDatatable.tsx | 18 +++--- 9 files changed, 105 insertions(+), 60 deletions(-) diff --git a/app/react/kubernetes/configs/ListView/ConfigMapsDatatable/ConfigMapsDatatable.tsx b/app/react/kubernetes/configs/ListView/ConfigMapsDatatable/ConfigMapsDatatable.tsx index e38fd3ec8..839345e0e 100644 --- a/app/react/kubernetes/configs/ListView/ConfigMapsDatatable/ConfigMapsDatatable.tsx +++ b/app/react/kubernetes/configs/ListView/ConfigMapsDatatable/ConfigMapsDatatable.tsx @@ -3,11 +3,7 @@ import { FileCode, Plus, Trash2 } from 'lucide-react'; import { ConfigMap } from 'kubernetes-types/core/v1'; import { useEnvironmentId } from '@/react/hooks/useEnvironmentId'; -import { - Authorized, - useAuthorizations, - useCurrentUser, -} from '@/react/hooks/useUser'; +import { Authorized, useAuthorizations } from '@/react/hooks/useUser'; import { useNamespaces } from '@/react/kubernetes/namespaces/queries'; import { DefaultDatatableSettings } from '@/react/kubernetes/datatables/DefaultDatatableSettings'; import { createStore } from '@/react/kubernetes/datatables/default-kube-datatable-store'; @@ -39,7 +35,9 @@ const settingsStore = createStore(storageKey); export function ConfigMapsDatatable() { const tableState = useTableState(settingsStore, storageKey); const readOnly = !useAuthorizations(['K8sConfigMapsW']); - const { isAdmin } = useCurrentUser(); + const canAccessSystemResources = useAuthorizations( + 'K8sAccessSystemNamespaces' + ); const environmentId = useEnvironmentId(); const { data: namespaces, ...namespacesQuery } = useNamespaces( @@ -63,10 +61,10 @@ export function ConfigMapsDatatable() { () => configMaps?.filter( (configMap) => - (isAdmin && tableState.showSystemResources) || + (canAccessSystemResources && tableState.showSystemResources) || !isSystemNamespace(configMap.metadata?.namespace ?? '') ) || [], - [configMaps, tableState, isAdmin] + [configMaps, tableState, canAccessSystemResources] ); const configMapRowData = useConfigMapRowData( filteredConfigMaps, @@ -95,13 +93,15 @@ export function ConfigMapsDatatable() { )} description={ } /> diff --git a/app/react/kubernetes/configs/ListView/SecretsDatatable/SecretsDatatable.tsx b/app/react/kubernetes/configs/ListView/SecretsDatatable/SecretsDatatable.tsx index fd7ff79fd..b1c7ee2b0 100644 --- a/app/react/kubernetes/configs/ListView/SecretsDatatable/SecretsDatatable.tsx +++ b/app/react/kubernetes/configs/ListView/SecretsDatatable/SecretsDatatable.tsx @@ -3,11 +3,7 @@ import { Lock, Plus, Trash2 } from 'lucide-react'; import { Secret } from 'kubernetes-types/core/v1'; import { useEnvironmentId } from '@/react/hooks/useEnvironmentId'; -import { - Authorized, - useAuthorizations, - useCurrentUser, -} from '@/react/hooks/useUser'; +import { Authorized, useAuthorizations } from '@/react/hooks/useUser'; import { useNamespaces } from '@/react/kubernetes/namespaces/queries'; import { DefaultDatatableSettings } from '@/react/kubernetes/datatables/DefaultDatatableSettings'; import { createStore } from '@/react/kubernetes/datatables/default-kube-datatable-store'; @@ -39,7 +35,9 @@ const settingsStore = createStore(storageKey); export function SecretsDatatable() { const tableState = useTableState(settingsStore, storageKey); const readOnly = !useAuthorizations(['K8sSecretsW']); - const { isAdmin } = useCurrentUser(); + const canAccessSystemResources = useAuthorizations( + 'K8sAccessSystemNamespaces' + ); const environmentId = useEnvironmentId(); const { data: namespaces, ...namespacesQuery } = useNamespaces( @@ -63,10 +61,10 @@ export function SecretsDatatable() { () => secrets?.filter( (secret) => - (isAdmin && tableState.showSystemResources) || + (canAccessSystemResources && tableState.showSystemResources) || !isSystemNamespace(secret.metadata?.namespace ?? '') ) || [], - [secrets, tableState, isAdmin] + [secrets, tableState, canAccessSystemResources] ); const secretRowData = useSecretRowData( filteredSecrets, @@ -95,13 +93,15 @@ export function SecretsDatatable() { )} description={ } /> diff --git a/app/react/kubernetes/ingresses/IngressDatatable/IngressDatatable.tsx b/app/react/kubernetes/ingresses/IngressDatatable/IngressDatatable.tsx index db55dacc3..d192efbd6 100644 --- a/app/react/kubernetes/ingresses/IngressDatatable/IngressDatatable.tsx +++ b/app/react/kubernetes/ingresses/IngressDatatable/IngressDatatable.tsx @@ -1,16 +1,20 @@ import { Plus, Trash2 } from 'lucide-react'; import { useRouter } from '@uirouter/react'; +import { useMemo } from 'react'; import { useEnvironmentId } from '@/react/hooks/useEnvironmentId'; import { useNamespaces } from '@/react/kubernetes/namespaces/queries'; import { useAuthorizations, Authorized } from '@/react/hooks/useUser'; import Route from '@/assets/ico/route.svg?c'; +import { DefaultDatatableSettings } from '@/react/kubernetes/datatables/DefaultDatatableSettings'; +import { createStore } from '@/react/kubernetes/datatables/default-kube-datatable-store'; +import { isSystemNamespace } from '@/react/kubernetes/namespaces/utils'; +import { SystemResourceDescription } from '@/react/kubernetes/datatables/SystemResourceDescription'; import { confirmDelete } from '@@/modals/confirm'; -import { Datatable } from '@@/datatables'; +import { Datatable, TableSettingsMenu } from '@@/datatables'; import { Button } from '@@/buttons'; import { Link } from '@@/Link'; -import { createPersistedStore } from '@@/datatables/types'; import { useTableState } from '@@/datatables/useTableState'; import { DeleteIngressesRequest, Ingress } from '../types'; @@ -26,26 +30,42 @@ interface SelectedIngress { } const storageKey = 'ingressClassesNameSpace'; -const settingsStore = createPersistedStore(storageKey); +const settingsStore = createStore(storageKey); export function IngressDatatable() { + const tableState = useTableState(settingsStore, storageKey); const environmentId = useEnvironmentId(); + const canAccessSystemResources = useAuthorizations( + 'K8sAccessSystemNamespaces' + ); const { data: namespaces, ...namespacesQuery } = useNamespaces(environmentId); - const ingressesQuery = useIngresses( + const { data: ingresses, ...ingressesQuery } = useIngresses( environmentId, - Object.keys(namespaces || {}) + Object.keys(namespaces || {}), + { + autoRefreshRate: tableState.autoRefreshRate * 1000, + } + ); + + const filteredIngresses = useMemo( + () => + ingresses?.filter( + (ingress) => + (canAccessSystemResources && tableState.showSystemResources) || + !isSystemNamespace(ingress.Namespace ?? '') + ) || [], + [ingresses, tableState, canAccessSystemResources] ); const deleteIngressesMutation = useDeleteIngresses(); - const tableState = useTableState(settingsStore, storageKey); const router = useRouter(); return ( row.Name + row.Type + row.Namespace} renderTableActions={tableActions} + renderTableSettings={() => ( + + + + )} + description={ + + } disableSelect={useCheckboxes()} /> ); @@ -62,7 +97,6 @@ export function IngressDatatable() {
@@ -92,9 +122,7 @@ export function IngressDatatable() { className="space-left no-decoration" params={{ referrer: 'kubernetes.ingresses' }} > - +
diff --git a/app/react/kubernetes/ingresses/IngressDatatable/columns/className.tsx b/app/react/kubernetes/ingresses/IngressDatatable/columns/className.tsx index 30546b2fa..cc864c117 100644 --- a/app/react/kubernetes/ingresses/IngressDatatable/columns/className.tsx +++ b/app/react/kubernetes/ingresses/IngressDatatable/columns/className.tsx @@ -3,4 +3,5 @@ import { columnHelper } from './helper'; export const className = columnHelper.accessor('ClassName', { header: 'Class Name', id: 'className', + cell: ({ row }) => row.original.ClassName || '-', }); diff --git a/app/react/kubernetes/ingresses/IngressDatatable/columns/ingressRules.tsx b/app/react/kubernetes/ingresses/IngressDatatable/columns/ingressRules.tsx index 7d145e27a..4978255e1 100644 --- a/app/react/kubernetes/ingresses/IngressDatatable/columns/ingressRules.tsx +++ b/app/react/kubernetes/ingresses/IngressDatatable/columns/ingressRules.tsx @@ -32,7 +32,7 @@ function Cell({ row }: CellContext) { } return ( -
+
{paths.map((path) => (
diff --git a/app/react/kubernetes/ingresses/IngressDatatable/columns/name.tsx b/app/react/kubernetes/ingresses/IngressDatatable/columns/name.tsx index 42b7d747f..44c6a0767 100644 --- a/app/react/kubernetes/ingresses/IngressDatatable/columns/name.tsx +++ b/app/react/kubernetes/ingresses/IngressDatatable/columns/name.tsx @@ -1,8 +1,10 @@ import { CellContext } from '@tanstack/react-table'; import { Authorized } from '@/react/hooks/useUser'; +import { isSystemNamespace } from '@/react/kubernetes/namespaces/utils'; import { Link } from '@@/Link'; +import { Badge } from '@@/Badge'; import { Ingress } from '../../types'; @@ -16,20 +18,29 @@ export const name = columnHelper.accessor('Name', { function Cell({ row, getValue }: CellContext) { const name = getValue(); + const namespace = row.original.Namespace; + const isSystemIngress = isSystemNamespace(namespace); return ( - - - {name} - - +
+ + + {name} + + + {isSystemIngress && ( + + system + + )} +
); } diff --git a/app/react/kubernetes/ingresses/IngressDatatable/columns/type.tsx b/app/react/kubernetes/ingresses/IngressDatatable/columns/type.tsx index 1a165071b..8ad56b94a 100644 --- a/app/react/kubernetes/ingresses/IngressDatatable/columns/type.tsx +++ b/app/react/kubernetes/ingresses/IngressDatatable/columns/type.tsx @@ -3,4 +3,5 @@ import { columnHelper } from './helper'; export const type = columnHelper.accessor('Type', { header: 'Type', id: 'type', + cell: ({ row }) => row.original.Type || '-', }); diff --git a/app/react/kubernetes/ingresses/queries.ts b/app/react/kubernetes/ingresses/queries.ts index 78940173f..86ea4a380 100644 --- a/app/react/kubernetes/ingresses/queries.ts +++ b/app/react/kubernetes/ingresses/queries.ts @@ -55,7 +55,8 @@ export function useIngress( export function useIngresses( environmentId: EnvironmentId, - namespaces?: string[] + namespaces?: string[], + options?: { autoRefreshRate?: number } ) { return useQuery( [ @@ -117,6 +118,9 @@ export function useIngresses( { enabled: !!namespaces?.length, ...withError('Unable to get ingresses'), + refetchInterval() { + return options?.autoRefreshRate ?? false; + }, } ); } diff --git a/app/react/kubernetes/services/ServicesView/ServicesDatatable/ServicesDatatable.tsx b/app/react/kubernetes/services/ServicesView/ServicesDatatable/ServicesDatatable.tsx index edab47c50..038924ad5 100644 --- a/app/react/kubernetes/services/ServicesView/ServicesDatatable/ServicesDatatable.tsx +++ b/app/react/kubernetes/services/ServicesView/ServicesDatatable/ServicesDatatable.tsx @@ -4,11 +4,7 @@ import clsx from 'clsx'; import { Row } from '@tanstack/react-table'; import { useEnvironmentId } from '@/react/hooks/useEnvironmentId'; -import { - Authorized, - useAuthorizations, - useCurrentUser, -} from '@/react/hooks/useUser'; +import { Authorized, useAuthorizations } from '@/react/hooks/useUser'; import { notifyError, notifySuccess } from '@/portainer/services/notifications'; import { pluralize } from '@/portainer/helpers/strings'; @@ -48,11 +44,13 @@ export function ServicesDatatable() { ); const readOnly = !useAuthorizations(['K8sServiceW']); - const { isAdmin } = useCurrentUser(); + const canAccessSystemResources = useAuthorizations( + 'K8sAccessSystemNamespaces' + ); const filteredServices = services?.filter( (service) => - (isAdmin && tableState.showSystemResources) || + (canAccessSystemResources && tableState.showSystemResources) || !isSystemNamespace(service.Namespace) ); @@ -75,13 +73,15 @@ export function ServicesDatatable() { )} description={ } renderRow={servicesRenderRow}