From 9ddebf91f28c8e46ade5817ef182b82ba56f7817 Mon Sep 17 00:00:00 2001 From: testA113 Date: Sat, 5 Oct 2024 10:57:06 +1300 Subject: [PATCH] update roles tables --- .../ClusterRoleBindingsDatatable/types.ts | 1 + .../RoleBindingsDatatable.tsx | 52 ++++++----- ...BindingsQuery.ts => useAllRoleBindings.ts} | 2 +- ...gsMutation.ts => useDeleteRoleBindings.ts} | 2 +- .../RolesView/RoleBindingsDatatable/types.ts | 6 +- .../RolesDatatable/RolesDatatable.tsx | 89 ++++++++++++++----- .../RolesDatatable/columns/helper.ts | 4 +- .../RolesDatatable/columns/namespace.tsx | 4 +- ...{useGetAllRolesQuery.ts => useAllRoles.ts} | 2 +- ...leteRolesMutation.ts => useDeleteRoles.ts} | 2 +- .../RolesView/RolesDatatable/types.ts | 8 +- 11 files changed, 110 insertions(+), 62 deletions(-) rename app/react/kubernetes/more-resources/RolesView/RoleBindingsDatatable/queries/{useGetAllRoleBindingsQuery.ts => useAllRoleBindings.ts} (95%) rename app/react/kubernetes/more-resources/RolesView/RoleBindingsDatatable/queries/{useDeleteRoleBindingsMutation.ts => useDeleteRoleBindings.ts} (91%) rename app/react/kubernetes/more-resources/RolesView/RolesDatatable/queries/{useGetAllRolesQuery.ts => useAllRoles.ts} (96%) rename app/react/kubernetes/more-resources/RolesView/RolesDatatable/queries/{useDeleteRolesMutation.ts => useDeleteRoles.ts} (92%) diff --git a/app/react/kubernetes/more-resources/ClusterRolesView/ClusterRoleBindingsDatatable/types.ts b/app/react/kubernetes/more-resources/ClusterRolesView/ClusterRoleBindingsDatatable/types.ts index e56bfac36..472e9bf82 100644 --- a/app/react/kubernetes/more-resources/ClusterRolesView/ClusterRoleBindingsDatatable/types.ts +++ b/app/react/kubernetes/more-resources/ClusterRolesView/ClusterRoleBindingsDatatable/types.ts @@ -14,6 +14,7 @@ export type ClusterRoleSubject = { export type ClusterRoleBinding = { name: string; uid: string; + namespace: string; roleRef: ClusterRoleRef; subjects: ClusterRoleSubject[] | null; creationDate: string; diff --git a/app/react/kubernetes/more-resources/RolesView/RoleBindingsDatatable/RoleBindingsDatatable.tsx b/app/react/kubernetes/more-resources/RolesView/RoleBindingsDatatable/RoleBindingsDatatable.tsx index 6083b61ef..0e94790dc 100644 --- a/app/react/kubernetes/more-resources/RolesView/RoleBindingsDatatable/RoleBindingsDatatable.tsx +++ b/app/react/kubernetes/more-resources/RolesView/RoleBindingsDatatable/RoleBindingsDatatable.tsx @@ -2,45 +2,56 @@ import { Trash2, Link as LinkIcon } from 'lucide-react'; import { useRouter } from '@uirouter/react'; import { Row } from '@tanstack/react-table'; import clsx from 'clsx'; +import { useMemo } from 'react'; import { useEnvironmentId } from '@/react/hooks/useEnvironmentId'; import { useAuthorizations, Authorized } from '@/react/hooks/useUser'; import { notifyError, notifySuccess } from '@/portainer/services/notifications'; import { SystemResourceDescription } from '@/react/kubernetes/datatables/SystemResourceDescription'; -import { createStore } from '@/react/kubernetes/datatables/default-kube-datatable-store'; -import { useNamespacesQuery } from '@/react/kubernetes/namespaces/queries/useNamespacesQuery'; +import { + DefaultDatatableSettings, + TableSettings as KubeTableSettings, +} from '@/react/kubernetes/datatables/DefaultDatatableSettings'; import { CreateFromManifestButton } from '@/react/kubernetes/components/CreateFromManifestButton'; -import { isSystemNamespace } from '@/react/kubernetes/namespaces/queries/useIsSystemNamespace'; +import { useKubeStore } from '@/react/kubernetes/datatables/default-kube-datatable-store'; import { confirmDelete } from '@@/modals/confirm'; import { Datatable, Table, TableSettingsMenu } from '@@/datatables'; import { LoadingButton } from '@@/buttons'; -import { useTableState } from '@@/datatables/useTableState'; - -import { DefaultDatatableSettings } from '../../../datatables/DefaultDatatableSettings'; +import { + type FilteredColumnsTableSettings, + filteredColumnsSettings, +} from '@@/datatables/types'; import { RoleBinding } from './types'; import { columns } from './columns'; -import { useGetAllRoleBindingsQuery } from './queries/useGetAllRoleBindingsQuery'; -import { useDeleteRoleBindingsMutation } from './queries/useDeleteRoleBindingsMutation'; +import { useAllRoleBindings } from './queries/useAllRoleBindings'; +import { useDeleteRoleBindings } from './queries/useDeleteRoleBindings'; const storageKey = 'roleBindings'; -const settingsStore = createStore(storageKey); +interface TableSettings + extends KubeTableSettings, + FilteredColumnsTableSettings {} export function RoleBindingsDatatable() { const environmentId = useEnvironmentId(); - const tableState = useTableState(settingsStore, storageKey); - const namespacesQuery = useNamespacesQuery(environmentId); - const roleBindingsQuery = useGetAllRoleBindingsQuery(environmentId, { + const tableState = useKubeStore( + storageKey, + undefined, + (set) => ({ + ...filteredColumnsSettings(set), + }) + ); + const roleBindingsQuery = useAllRoleBindings(environmentId, { autoRefreshRate: tableState.autoRefreshRate * 1000, - enabled: namespacesQuery.isSuccess, }); - - const filteredRoleBindings = tableState.showSystemResources - ? roleBindingsQuery.data - : roleBindingsQuery.data?.filter( - (rb) => !isSystemNamespace(rb.namespace, namespacesQuery.data) - ); + const filteredRoleBindings = useMemo( + () => + tableState.showSystemResources + ? roleBindingsQuery.data + : roleBindingsQuery.data?.filter((rb) => !rb.isSystem), + [roleBindingsQuery.data, tableState.showSystemResources] + ); const { authorized: isAuthorisedToAddEdit } = useAuthorizations([ 'K8sRoleBindingsW', @@ -100,8 +111,7 @@ type TableActionsProps = { function TableActions({ selectedItems }: TableActionsProps) { const environmentId = useEnvironmentId(); - const deleteRoleBindingsMutation = - useDeleteRoleBindingsMutation(environmentId); + const deleteRoleBindingsMutation = useDeleteRoleBindings(environmentId); const router = useRouter(); async function handleRemoveClick(roles: SelectedRole[]) { diff --git a/app/react/kubernetes/more-resources/RolesView/RoleBindingsDatatable/queries/useGetAllRoleBindingsQuery.ts b/app/react/kubernetes/more-resources/RolesView/RoleBindingsDatatable/queries/useAllRoleBindings.ts similarity index 95% rename from app/react/kubernetes/more-resources/RolesView/RoleBindingsDatatable/queries/useGetAllRoleBindingsQuery.ts rename to app/react/kubernetes/more-resources/RolesView/RoleBindingsDatatable/queries/useAllRoleBindings.ts index e5ddbea33..5b544e0f8 100644 --- a/app/react/kubernetes/more-resources/RolesView/RoleBindingsDatatable/queries/useGetAllRoleBindingsQuery.ts +++ b/app/react/kubernetes/more-resources/RolesView/RoleBindingsDatatable/queries/useAllRoleBindings.ts @@ -8,7 +8,7 @@ import { RoleBinding } from '../types'; import { queryKeys } from './query-keys'; -export function useGetAllRoleBindingsQuery( +export function useAllRoleBindings( environmentId: EnvironmentId, options?: { autoRefreshRate?: number; enabled?: boolean } ) { diff --git a/app/react/kubernetes/more-resources/RolesView/RoleBindingsDatatable/queries/useDeleteRoleBindingsMutation.ts b/app/react/kubernetes/more-resources/RolesView/RoleBindingsDatatable/queries/useDeleteRoleBindings.ts similarity index 91% rename from app/react/kubernetes/more-resources/RolesView/RoleBindingsDatatable/queries/useDeleteRoleBindingsMutation.ts rename to app/react/kubernetes/more-resources/RolesView/RoleBindingsDatatable/queries/useDeleteRoleBindings.ts index 029ee7e4b..79c153bc5 100644 --- a/app/react/kubernetes/more-resources/RolesView/RoleBindingsDatatable/queries/useDeleteRoleBindingsMutation.ts +++ b/app/react/kubernetes/more-resources/RolesView/RoleBindingsDatatable/queries/useDeleteRoleBindings.ts @@ -6,7 +6,7 @@ import { EnvironmentId } from '@/react/portainer/environments/types'; import { queryKeys } from './query-keys'; -export function useDeleteRoleBindingsMutation(environmentId: EnvironmentId) { +export function useDeleteRoleBindings(environmentId: EnvironmentId) { const queryClient = useQueryClient(); return useMutation(deleteRoleBindings, { ...withInvalidate(queryClient, [queryKeys.list(environmentId)]), diff --git a/app/react/kubernetes/more-resources/RolesView/RoleBindingsDatatable/types.ts b/app/react/kubernetes/more-resources/RolesView/RoleBindingsDatatable/types.ts index 59807c588..9c2ebf737 100644 --- a/app/react/kubernetes/more-resources/RolesView/RoleBindingsDatatable/types.ts +++ b/app/react/kubernetes/more-resources/RolesView/RoleBindingsDatatable/types.ts @@ -15,12 +15,8 @@ export type RoleBinding = { name: string; uid: string; namespace: string; - resourceVersion: string; - creationDate: string; - annotations: Record | null; - roleRef: RoleRef; subjects: RoleSubject[] | null; - + creationDate: string; isSystem: boolean; }; diff --git a/app/react/kubernetes/more-resources/RolesView/RolesDatatable/RolesDatatable.tsx b/app/react/kubernetes/more-resources/RolesView/RolesDatatable/RolesDatatable.tsx index 09e183213..2a1ffb6e7 100644 --- a/app/react/kubernetes/more-resources/RolesView/RolesDatatable/RolesDatatable.tsx +++ b/app/react/kubernetes/more-resources/RolesView/RolesDatatable/RolesDatatable.tsx @@ -1,56 +1,76 @@ import { Trash2, UserCheck } from 'lucide-react'; import { useRouter } from '@uirouter/react'; +import { useMemo } from 'react'; import { useEnvironmentId } from '@/react/hooks/useEnvironmentId'; import { Authorized } from '@/react/hooks/useUser'; import { notifyError, notifySuccess } from '@/portainer/services/notifications'; import { SystemResourceDescription } from '@/react/kubernetes/datatables/SystemResourceDescription'; -import { createStore } from '@/react/kubernetes/datatables/default-kube-datatable-store'; -import { useNamespacesQuery } from '@/react/kubernetes/namespaces/queries/useNamespacesQuery'; import { CreateFromManifestButton } from '@/react/kubernetes/components/CreateFromManifestButton'; import { useUnauthorizedRedirect } from '@/react/hooks/useUnauthorizedRedirect'; -import { isSystemNamespace } from '@/react/kubernetes/namespaces/queries/useIsSystemNamespace'; +import { + DefaultDatatableSettings, + TableSettings as KubeTableSettings, +} from '@/react/kubernetes/datatables/DefaultDatatableSettings'; +import { useKubeStore } from '@/react/kubernetes/datatables/default-kube-datatable-store'; import { confirmDelete } from '@@/modals/confirm'; import { Datatable, TableSettingsMenu } from '@@/datatables'; import { LoadingButton } from '@@/buttons'; -import { useTableState } from '@@/datatables/useTableState'; +import { + type FilteredColumnsTableSettings, + filteredColumnsSettings, +} from '@@/datatables/types'; -import { DefaultDatatableSettings } from '../../../datatables/DefaultDatatableSettings'; +import { useAllRoleBindings } from '../RoleBindingsDatatable/queries/useAllRoleBindings'; +import { RoleBinding } from '../RoleBindingsDatatable/types'; import { columns } from './columns'; -import { Role } from './types'; -import { useGetAllRolesQuery } from './queries/useGetAllRolesQuery'; -import { useDeleteRolesMutation } from './queries/useDeleteRolesMutation'; +import { Role, RoleRowData } from './types'; +import { useAllRoles } from './queries/useAllRoles'; +import { useDeleteRoles } from './queries/useDeleteRoles'; const storageKey = 'roles'; -const settingsStore = createStore(storageKey); +interface TableSettings + extends KubeTableSettings, + FilteredColumnsTableSettings {} export function RolesDatatable() { - const environmentId = useEnvironmentId(); - const tableState = useTableState(settingsStore, storageKey); - const namespacesQuery = useNamespacesQuery(environmentId); - const rolesQuery = useGetAllRolesQuery(environmentId, { - autoRefreshRate: tableState.autoRefreshRate * 1000, - enabled: namespacesQuery.isSuccess, - }); useUnauthorizedRedirect( { authorizations: ['K8sRolesW'] }, { to: 'kubernetes.dashboard' } ); - const filteredRoles = tableState.showSystemResources - ? rolesQuery.data - : rolesQuery.data?.filter( - (role) => !isSystemNamespace(role.namespace, namespacesQuery.data) - ); + const environmentId = useEnvironmentId(); + const tableState = useKubeStore( + storageKey, + undefined, + (set) => ({ + ...filteredColumnsSettings(set), + }) + ); + const rolesQuery = useAllRoles(environmentId, { + autoRefreshRate: tableState.autoRefreshRate * 1000, + }); + const roleBindingsQuery = useAllRoleBindings(environmentId, { + autoRefreshRate: tableState.autoRefreshRate * 1000, + }); + const roleRowData = useRoleRowData(rolesQuery.data, roleBindingsQuery.data); + + const filteredRoles = useMemo( + () => + tableState.showSystemResources + ? roleRowData + : roleRowData.filter((role) => !role.isSystem), + [roleRowData, tableState.showSystemResources] + ); return ( + roles?.map((role) => { + const isUsed = roleBindings?.some( + (roleBinding) => + roleBinding.roleRef.name === role.name && + roleBinding.namespace === role.namespace + ); + return { ...role, isUnused: !isUsed }; + }), + [roles, roleBindings] + ); + + return roleRowData ?? []; +} diff --git a/app/react/kubernetes/more-resources/RolesView/RolesDatatable/columns/helper.ts b/app/react/kubernetes/more-resources/RolesView/RolesDatatable/columns/helper.ts index cae915061..acac7cf61 100644 --- a/app/react/kubernetes/more-resources/RolesView/RolesDatatable/columns/helper.ts +++ b/app/react/kubernetes/more-resources/RolesView/RolesDatatable/columns/helper.ts @@ -1,5 +1,5 @@ import { createColumnHelper } from '@tanstack/react-table'; -import { Role } from '../types'; +import { RoleRowData } from '../types'; -export const columnHelper = createColumnHelper(); +export const columnHelper = createColumnHelper(); diff --git a/app/react/kubernetes/more-resources/RolesView/RolesDatatable/columns/namespace.tsx b/app/react/kubernetes/more-resources/RolesView/RolesDatatable/columns/namespace.tsx index 3d2f8021d..378ef2627 100644 --- a/app/react/kubernetes/more-resources/RolesView/RolesDatatable/columns/namespace.tsx +++ b/app/react/kubernetes/more-resources/RolesView/RolesDatatable/columns/namespace.tsx @@ -3,7 +3,7 @@ import { Row } from '@tanstack/react-table'; import { filterHOC } from '@@/datatables/Filter'; import { Link } from '@@/Link'; -import { Role } from '../types'; +import { RoleRowData } from '../types'; import { columnHelper } from './helper'; @@ -26,7 +26,7 @@ export const namespace = columnHelper.accessor((row) => row.namespace, { filter: filterHOC('Filter by namespace'), }, enableColumnFilter: true, - filterFn: (row: Row, _columnId: string, filterValue: string[]) => + filterFn: (row: Row, _columnId: string, filterValue: string[]) => filterValue.length === 0 || filterValue.includes(row.original.namespace ?? ''), }); diff --git a/app/react/kubernetes/more-resources/RolesView/RolesDatatable/queries/useGetAllRolesQuery.ts b/app/react/kubernetes/more-resources/RolesView/RolesDatatable/queries/useAllRoles.ts similarity index 96% rename from app/react/kubernetes/more-resources/RolesView/RolesDatatable/queries/useGetAllRolesQuery.ts rename to app/react/kubernetes/more-resources/RolesView/RolesDatatable/queries/useAllRoles.ts index e7d692cd6..a4019466b 100644 --- a/app/react/kubernetes/more-resources/RolesView/RolesDatatable/queries/useGetAllRolesQuery.ts +++ b/app/react/kubernetes/more-resources/RolesView/RolesDatatable/queries/useAllRoles.ts @@ -11,7 +11,7 @@ const queryKeys = { ['environments', environmentId, 'kubernetes', 'roles'] as const, }; -export function useGetAllRolesQuery( +export function useAllRoles( environmentId: EnvironmentId, options?: { autoRefreshRate?: number; enabled?: boolean } ) { diff --git a/app/react/kubernetes/more-resources/RolesView/RolesDatatable/queries/useDeleteRolesMutation.ts b/app/react/kubernetes/more-resources/RolesView/RolesDatatable/queries/useDeleteRoles.ts similarity index 92% rename from app/react/kubernetes/more-resources/RolesView/RolesDatatable/queries/useDeleteRolesMutation.ts rename to app/react/kubernetes/more-resources/RolesView/RolesDatatable/queries/useDeleteRoles.ts index 211ac8a16..6b4cc96fc 100644 --- a/app/react/kubernetes/more-resources/RolesView/RolesDatatable/queries/useDeleteRolesMutation.ts +++ b/app/react/kubernetes/more-resources/RolesView/RolesDatatable/queries/useDeleteRoles.ts @@ -6,7 +6,7 @@ import { EnvironmentId } from '@/react/portainer/environments/types'; import { queryKeys } from './query-keys'; -export function useDeleteRolesMutation(environmentId: EnvironmentId) { +export function useDeleteRoles(environmentId: EnvironmentId) { const queryClient = useQueryClient(); return useMutation(deleteRole, { ...withInvalidate(queryClient, [queryKeys.list(environmentId)]), diff --git a/app/react/kubernetes/more-resources/RolesView/RolesDatatable/types.ts b/app/react/kubernetes/more-resources/RolesView/RolesDatatable/types.ts index cd2bdddf6..05e30cad5 100644 --- a/app/react/kubernetes/more-resources/RolesView/RolesDatatable/types.ts +++ b/app/react/kubernetes/more-resources/RolesView/RolesDatatable/types.ts @@ -8,12 +8,10 @@ export type Role = { name: string; uid: string; namespace: string; - resourceVersion: string; creationDate: string; - annotations?: Record; - - rules: Rule[]; - isSystem: boolean; +}; + +export type RoleRowData = Role & { isUnused: boolean; };