diff --git a/frontend/public/locales/en/translation.json b/frontend/public/locales/en/translation.json index 94503de173a..731c2f3dfe5 100644 --- a/frontend/public/locales/en/translation.json +++ b/frontend/public/locales/en/translation.json @@ -2039,6 +2039,7 @@ "No risks found": "No risks found", "No role assignments": "No role assignments", "No role assignments have been created for this user yet. Create a role assignment to grant specific permissions.": "No role assignments have been created for this user yet. Create a role assignment to grant specific permissions.", + "No roles": "No roles", "No status": "No status", "No users": "No users", "No users in group": "No users in group", @@ -2197,6 +2198,7 @@ "Permanently destroy clusters?": "Permanently destroy clusters?", "Permanently remove node pool {{name}}?": "Permanently remove node pool {{name}}?", "Permission created": "Permission created", + "Permissions": "Permissions", "Persistent volume": "Persistent volume", "Persistent volume storage class for etcd data volumes": "Persistent volume storage class for etcd data volumes", "Personalize this view": "Personalize this view", diff --git a/frontend/src/NavigationPath.tsx b/frontend/src/NavigationPath.tsx index 0fd88864686..4edb5f0e5d3 100644 --- a/frontend/src/NavigationPath.tsx +++ b/frontend/src/NavigationPath.tsx @@ -209,10 +209,10 @@ export enum NavigationPath { // RBAC Roles roles = '/multicloud/user-management/roles', - rolesDetails = '/multicloud/user-management/roles/:id', - rolesPermissions = '/multicloud/user-management/roles/:id/permissions', - rolesRoleAssignments = '/multicloud/user-management/roles/:id/role-assignments', - rolesYaml = '/multicloud/user-management/roles/:id/yaml', + roleDetails = '/multicloud/user-management/roles/:id', + rolePermissions = '/multicloud/user-management/roles/:id/permissions', + roleRoleAssignments = '/multicloud/user-management/roles/:id/role-assignments', + roleYaml = '/multicloud/user-management/roles/:id/yaml', emptyPath = '', } diff --git a/frontend/src/resources/rbac.ts b/frontend/src/resources/rbac.ts index 2b5101d5cd6..83cc2395b36 100644 --- a/frontend/src/resources/rbac.ts +++ b/frontend/src/resources/rbac.ts @@ -152,3 +152,7 @@ export function listRoles() { export function listRoleBindings() { return listResources(RoleBindingDefinition) } + +export function listVirtualizationClusterRoles() { + return listResources(ClusterRoleDefinition, ['rbac.open-cluster-management.io/filter=vm-clusterroles']) +} diff --git a/frontend/src/routes/Infrastructure/VirtualMachines/VirtualMachinesPage.tsx b/frontend/src/routes/Infrastructure/VirtualMachines/VirtualMachinesPage.tsx index 98bf797bb4d..3b62cf66d5f 100644 --- a/frontend/src/routes/Infrastructure/VirtualMachines/VirtualMachinesPage.tsx +++ b/frontend/src/routes/Infrastructure/VirtualMachines/VirtualMachinesPage.tsx @@ -20,7 +20,7 @@ import { useLocation, useNavigate, Outlet, Link } from 'react-router-dom-v5-comp import { Pages, usePageVisitMetricHandler } from '../../../hooks/console-metrics' import { useTranslation } from '../../../lib/acm-i18next' import { NavigationPath } from '../../../NavigationPath' -import { RoleAssignments } from '../../UserManagement/Roles/RoleAssignments' +import { RoleAssignments } from '../../UserManagement/Roles/Role/RoleAssignments' import { OCP_DOC } from '../../../lib/doc-util' import { PluginContext } from '../../../lib/PluginContext' import { ConfigMap } from '../../../resources' diff --git a/frontend/src/routes/UserManagement/Roles/RoleAssignments.test.tsx b/frontend/src/routes/UserManagement/Roles/Role/RoleAssignments.test.tsx similarity index 93% rename from frontend/src/routes/UserManagement/Roles/RoleAssignments.test.tsx rename to frontend/src/routes/UserManagement/Roles/Role/RoleAssignments.test.tsx index 39b27893f1c..1fed8aa943a 100644 --- a/frontend/src/routes/UserManagement/Roles/RoleAssignments.test.tsx +++ b/frontend/src/routes/UserManagement/Roles/Role/RoleAssignments.test.tsx @@ -3,7 +3,7 @@ import { render, screen } from '@testing-library/react' import { MemoryRouter } from 'react-router-dom-v5-compat' import { RecoilRoot } from 'recoil' -import { nockIgnoreRBAC } from '../../../lib/nock-util' +import { nockIgnoreRBAC } from '../../../../lib/nock-util' import { RoleAssignments } from './RoleAssignments' function Component({ roleId = 'test-role' }: { roleId?: string }) { diff --git a/frontend/src/routes/UserManagement/Roles/Role/RoleAssignments.tsx b/frontend/src/routes/UserManagement/Roles/Role/RoleAssignments.tsx new file mode 100644 index 00000000000..14574557f16 --- /dev/null +++ b/frontend/src/routes/UserManagement/Roles/Role/RoleAssignments.tsx @@ -0,0 +1,13 @@ +/* Copyright Contributors to the Open Cluster Management project */ +import { PageSection } from '@patternfly/react-core' +//import { useTranslation } from '../../../lib/acm-i18next' +import { useCurrentRole } from '../RolesPage' + +const RoleAssignments = () => { + //const { t } = useTranslation() + const role = useCurrentRole() + + return Role assignments page for Role: {role?.metadata.name} +} + +export { RoleAssignments } diff --git a/frontend/src/routes/UserManagement/Roles/RoleDetail.test.tsx b/frontend/src/routes/UserManagement/Roles/Role/RoleDetails.test.tsx similarity index 89% rename from frontend/src/routes/UserManagement/Roles/RoleDetail.test.tsx rename to frontend/src/routes/UserManagement/Roles/Role/RoleDetails.test.tsx index 8eb83d4f8d5..294c74a01cc 100644 --- a/frontend/src/routes/UserManagement/Roles/RoleDetail.test.tsx +++ b/frontend/src/routes/UserManagement/Roles/Role/RoleDetails.test.tsx @@ -3,8 +3,8 @@ import { render, screen } from '@testing-library/react' import { MemoryRouter } from 'react-router-dom-v5-compat' import { RecoilRoot } from 'recoil' -import { nockIgnoreRBAC } from '../../../lib/nock-util' -import { RoleDetail } from './RoleDetail' +import { nockIgnoreRBAC } from '../../../../lib/nock-util' +import { RoleDetail } from './RoleDetails' function Component({ roleId = 'test-role' }: { roleId?: string }) { return ( diff --git a/frontend/src/routes/UserManagement/Roles/Role/RoleDetails.tsx b/frontend/src/routes/UserManagement/Roles/Role/RoleDetails.tsx new file mode 100644 index 00000000000..ffe478add89 --- /dev/null +++ b/frontend/src/routes/UserManagement/Roles/Role/RoleDetails.tsx @@ -0,0 +1,13 @@ +/* Copyright Contributors to the Open Cluster Management project */ +import { PageSection } from '@patternfly/react-core' +//import { useTranslation } from '../../../lib/acm-i18next' +import { useCurrentRole } from '../RolesPage' + +const RoleDetail = () => { + //const { t } = useTranslation() + const role = useCurrentRole() + + return Role detail page for Role: {role?.metadata.name} +} + +export { RoleDetail } diff --git a/frontend/src/routes/UserManagement/Roles/Role/RolePage.tsx b/frontend/src/routes/UserManagement/Roles/Role/RolePage.tsx new file mode 100644 index 00000000000..11b561fc9ce --- /dev/null +++ b/frontend/src/routes/UserManagement/Roles/Role/RolePage.tsx @@ -0,0 +1,92 @@ +/* Copyright Contributors to the Open Cluster Management project */ +import { useParams, useLocation, Link, Outlet, useNavigate } from 'react-router-dom-v5-compat' +import { useTranslation } from '../../../../lib/acm-i18next' +import { useRolesContext, useCurrentRole } from '../RolesPage' +import { + AcmPage, + AcmPageHeader, + AcmSecondaryNav, + AcmSecondaryNavItem, + AcmLoadingPage, + AcmButton, +} from '../../../../ui-components' +import { NavigationPath } from '../../../../NavigationPath' +import { generatePath } from 'react-router-dom-v5-compat' +import { Page, PageSection } from '@patternfly/react-core' +import { ErrorPage } from '../../../../components/ErrorPage' +import { ResourceError, ResourceErrorCode } from '../../../../resources/utils' + +const RolePage = () => { + const { t } = useTranslation() + const { id = undefined } = useParams() + const location = useLocation() + const navigate = useNavigate() + const { loading } = useRolesContext() + const role = useCurrentRole() + + const isDetailsActive = location.pathname === generatePath(NavigationPath.roleDetails, { id: id ?? '' }) + const isPermissionsActive = location.pathname.includes('/permissions') + const isRoleAssignmentsActive = location.pathname.includes('/role-assignments') + const isYamlActive = location.pathname.includes('/yaml') + + switch (true) { + case loading: + return ( + + + + ) + case !role: + return ( + + navigate(NavigationPath.roles)} style={{ marginRight: '10px' }}> + {t('button.backToRoles')} + + } + /> + + ) + default: + return ( + + + {t('Details')} + + + {t('Permissions')} + + + + {t('Role assignments')} + + + + {t('YAML')} + + + } + /> + } + > + + + ) + } +} + +export { RolePage } diff --git a/frontend/src/routes/UserManagement/Roles/RolePermissions.test.tsx b/frontend/src/routes/UserManagement/Roles/Role/RolePermissions.test.tsx similarity index 93% rename from frontend/src/routes/UserManagement/Roles/RolePermissions.test.tsx rename to frontend/src/routes/UserManagement/Roles/Role/RolePermissions.test.tsx index af381d0b947..44b83431269 100644 --- a/frontend/src/routes/UserManagement/Roles/RolePermissions.test.tsx +++ b/frontend/src/routes/UserManagement/Roles/Role/RolePermissions.test.tsx @@ -3,7 +3,7 @@ import { render, screen } from '@testing-library/react' import { MemoryRouter } from 'react-router-dom-v5-compat' import { RecoilRoot } from 'recoil' -import { nockIgnoreRBAC } from '../../../lib/nock-util' +import { nockIgnoreRBAC } from '../../../../lib/nock-util' import { RolePermissions } from './RolePermissions' function Component({ roleId = 'test-role' }: { roleId?: string }) { diff --git a/frontend/src/routes/UserManagement/Roles/Role/RolePermissions.tsx b/frontend/src/routes/UserManagement/Roles/Role/RolePermissions.tsx new file mode 100644 index 00000000000..e0c31a937ae --- /dev/null +++ b/frontend/src/routes/UserManagement/Roles/Role/RolePermissions.tsx @@ -0,0 +1,13 @@ +/* Copyright Contributors to the Open Cluster Management project */ +import { PageSection } from '@patternfly/react-core' +//import { useTranslation } from '../../../lib/acm-i18next' +import { useCurrentRole } from '../RolesPage' + +const RolePermissions = () => { + //const { t } = useTranslation() + const role = useCurrentRole() + + return Role permissions page for Role: {role?.metadata.name} +} + +export { RolePermissions } diff --git a/frontend/src/routes/UserManagement/Roles/RoleYaml.test.tsx b/frontend/src/routes/UserManagement/Roles/Role/RoleYaml.test.tsx similarity index 92% rename from frontend/src/routes/UserManagement/Roles/RoleYaml.test.tsx rename to frontend/src/routes/UserManagement/Roles/Role/RoleYaml.test.tsx index 8beafe3e0a1..2f57a0ad839 100644 --- a/frontend/src/routes/UserManagement/Roles/RoleYaml.test.tsx +++ b/frontend/src/routes/UserManagement/Roles/Role/RoleYaml.test.tsx @@ -3,7 +3,7 @@ import { render, screen } from '@testing-library/react' import { MemoryRouter } from 'react-router-dom-v5-compat' import { RecoilRoot } from 'recoil' -import { nockIgnoreRBAC } from '../../../lib/nock-util' +import { nockIgnoreRBAC } from '../../../../lib/nock-util' import { RoleYaml } from './RoleYaml' function Component({ roleId = 'test-role' }: { roleId?: string }) { diff --git a/frontend/src/routes/UserManagement/Roles/Role/RoleYaml.tsx b/frontend/src/routes/UserManagement/Roles/Role/RoleYaml.tsx new file mode 100644 index 00000000000..2a86e885ee5 --- /dev/null +++ b/frontend/src/routes/UserManagement/Roles/Role/RoleYaml.tsx @@ -0,0 +1,13 @@ +/* Copyright Contributors to the Open Cluster Management project */ +import { PageSection } from '@patternfly/react-core' +//import { useTranslation } from '../../../lib/acm-i18next' +import { useCurrentRole } from '../RolesPage' + +const RoleYaml = () => { + //const { t } = useTranslation() + const role = useCurrentRole() + + return Role YAML page for Role: {role?.metadata.name} +} + +export { RoleYaml } diff --git a/frontend/src/routes/UserManagement/Roles/RoleAssignments.tsx b/frontend/src/routes/UserManagement/Roles/RoleAssignments.tsx deleted file mode 100644 index 48340f10f0a..00000000000 --- a/frontend/src/routes/UserManagement/Roles/RoleAssignments.tsx +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright Contributors to the Open Cluster Management project */ -import { PageSection } from '@patternfly/react-core' -import { useParams } from 'react-router-dom-v5-compat' -import { useTranslation } from '../../../lib/acm-i18next' -import { AcmPage, AcmPageContent, AcmPageHeader } from '../../../ui-components' - -const RoleAssignments = () => { - const { t } = useTranslation() - const { id = undefined } = useParams() - - return ( - }> - - Role assignments page for ID: {id} - - - ) -} - -export { RoleAssignments } diff --git a/frontend/src/routes/UserManagement/Roles/RoleDetail.tsx b/frontend/src/routes/UserManagement/Roles/RoleDetail.tsx deleted file mode 100644 index 83bbd579803..00000000000 --- a/frontend/src/routes/UserManagement/Roles/RoleDetail.tsx +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright Contributors to the Open Cluster Management project */ -import { PageSection } from '@patternfly/react-core' -import { useParams } from 'react-router-dom-v5-compat' -import { useTranslation } from '../../../lib/acm-i18next' -import { AcmPage, AcmPageContent, AcmPageHeader } from '../../../ui-components' - -const RoleDetail = () => { - const { t } = useTranslation() - const { id = undefined } = useParams() - - return ( - }> - - Role detail page for ID: {id} - - - ) -} - -export { RoleDetail } diff --git a/frontend/src/routes/UserManagement/Roles/RolePermissions.tsx b/frontend/src/routes/UserManagement/Roles/RolePermissions.tsx deleted file mode 100644 index ea568270ba4..00000000000 --- a/frontend/src/routes/UserManagement/Roles/RolePermissions.tsx +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright Contributors to the Open Cluster Management project */ -import { PageSection } from '@patternfly/react-core' -import { useParams } from 'react-router-dom-v5-compat' -import { useTranslation } from '../../../lib/acm-i18next' -import { AcmPage, AcmPageContent, AcmPageHeader } from '../../../ui-components' - -const RolePermissions = () => { - const { t } = useTranslation() - const { id = undefined } = useParams() - - return ( - }> - - Role permissions page for ID: {id} - - - ) -} - -export { RolePermissions } diff --git a/frontend/src/routes/UserManagement/Roles/RoleYaml.tsx b/frontend/src/routes/UserManagement/Roles/RoleYaml.tsx deleted file mode 100644 index 060021d83f8..00000000000 --- a/frontend/src/routes/UserManagement/Roles/RoleYaml.tsx +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright Contributors to the Open Cluster Management project */ -import { PageSection } from '@patternfly/react-core' -import { useParams } from 'react-router-dom-v5-compat' -import { useTranslation } from '../../../lib/acm-i18next' -import { AcmPage, AcmPageContent, AcmPageHeader } from '../../../ui-components' - -const RoleYaml = () => { - const { t } = useTranslation() - const { id = undefined } = useParams() - - return ( - }> - - Role YAML page for ID: {id} - - - ) -} - -export { RoleYaml } diff --git a/frontend/src/routes/UserManagement/Roles/Roles.tsx b/frontend/src/routes/UserManagement/Roles/Roles.tsx deleted file mode 100644 index 0ed1f212db2..00000000000 --- a/frontend/src/routes/UserManagement/Roles/Roles.tsx +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright Contributors to the Open Cluster Management project */ -import { PageSection } from '@patternfly/react-core' -import { useTranslation } from '../../../lib/acm-i18next' -import { AcmPage, AcmPageContent, AcmPageHeader } from '../../../ui-components' - -const Roles = () => { - const { t } = useTranslation() - - return ( - }> - - Roles list - - - ) -} - -export { Roles } diff --git a/frontend/src/routes/UserManagement/Roles/RolesManagement.tsx b/frontend/src/routes/UserManagement/Roles/RolesManagement.tsx index 2c945cf0855..58b37788dea 100644 --- a/frontend/src/routes/UserManagement/Roles/RolesManagement.tsx +++ b/frontend/src/routes/UserManagement/Roles/RolesManagement.tsx @@ -1,27 +1,39 @@ /* Copyright Contributors to the Open Cluster Management project */ import { Navigate, Route, Routes } from 'react-router-dom-v5-compat' import { NavigationPath, createRoutePathFunction } from '../../../NavigationPath' -import { Roles } from './Roles' -import { RoleDetail } from './RoleDetail' -import { RoleYaml } from './RoleYaml' -import { RolePermissions } from './RolePermissions' -import { RoleAssignments } from './RoleAssignments' +import { RolesPage, RolesContextProvider } from './RolesPage' +import { RolePage } from './Role/RolePage' +import { RoleDetail } from './Role/RoleDetails' +import { RoleYaml } from './Role/RoleYaml' +import { RolePermissions } from './Role/RolePermissions' +import { RoleAssignments } from './Role/RoleAssignments' const rolesChildPath = createRoutePathFunction(NavigationPath.roles) export default function RolesManagement() { return ( - - {/* Role detail routes */} - } /> - } /> - } /> - } /> + + + {/* Individual role page tabs */} + }> + } /> + + }> + } /> + + }> + } /> + + }> + } /> + - {/* Main roles page */} - } /> + {/* Main roles page with list of roles */} + } /> - } /> - + {/* Default redirect to roles */} + } /> + + ) } diff --git a/frontend/src/routes/UserManagement/Roles/Roles.test.tsx b/frontend/src/routes/UserManagement/Roles/RolesPage.test.tsx similarity index 91% rename from frontend/src/routes/UserManagement/Roles/Roles.test.tsx rename to frontend/src/routes/UserManagement/Roles/RolesPage.test.tsx index 2f371613c74..4c2e6be013d 100644 --- a/frontend/src/routes/UserManagement/Roles/Roles.test.tsx +++ b/frontend/src/routes/UserManagement/Roles/RolesPage.test.tsx @@ -4,13 +4,13 @@ import { render, screen } from '@testing-library/react' import { MemoryRouter } from 'react-router-dom-v5-compat' import { RecoilRoot } from 'recoil' import { nockIgnoreRBAC } from '../../../lib/nock-util' -import { Roles } from './Roles' +import { RolesPage } from './RolesPage' function Component() { return ( - + ) diff --git a/frontend/src/routes/UserManagement/Roles/RolesPage.tsx b/frontend/src/routes/UserManagement/Roles/RolesPage.tsx new file mode 100644 index 00000000000..6f6c9fa3983 --- /dev/null +++ b/frontend/src/routes/UserManagement/Roles/RolesPage.tsx @@ -0,0 +1,69 @@ +/* Copyright Contributors to the Open Cluster Management project */ +import { createContext, useContext, ReactNode, useMemo } from 'react' +import { useParams } from 'react-router-dom-v5-compat' +import { useTranslation } from '../../../lib/acm-i18next' +import { useQuery } from '../../../lib/useQuery' +import { listVirtualizationClusterRoles, ClusterRole } from '../../../resources/rbac' +import { AcmPage, AcmPageContent, AcmPageHeader } from '../../../ui-components' +import { RolesTable } from './RolesTable' + +export type RolesContextType = { + clusterRoles?: ClusterRole[] + loading: boolean +} + +const RolesContext = createContext(undefined) + +export const useRolesContext = () => { + const context = useContext(RolesContext) + if (!context) { + throw new Error('useRolesContext must be used within RolesContextProvider') + } + return context +} + +export const useCurrentRole = () => { + const { id } = useParams() + const { clusterRoles } = useRolesContext() + + return useMemo(() => { + if (!clusterRoles || !id) return undefined + return clusterRoles.find((r) => r.metadata.uid === id || r.metadata.name === id) + }, [clusterRoles, id]) +} + +export const RolesContextProvider = ({ children }: { children: ReactNode }) => { + const { data: clusterRoles, loading } = useQuery(listVirtualizationClusterRoles) + //TODO: look into hanging apicalls at apiPaths that proceeds this api call which causes stuck loading page + + const contextValue: RolesContextType = { + clusterRoles, + loading, + } + + return {children} +} + +const RolesPage = () => { + const { t } = useTranslation() + + // TODO: implement loading page? + // TODO: check page for rbac permission? + return ( + + } + > + + + + + ) +} + +export { RolesPage } diff --git a/frontend/src/routes/UserManagement/Roles/RolesTable.tsx b/frontend/src/routes/UserManagement/Roles/RolesTable.tsx new file mode 100644 index 00000000000..0d5323f5ee4 --- /dev/null +++ b/frontend/src/routes/UserManagement/Roles/RolesTable.tsx @@ -0,0 +1,54 @@ +/* Copyright Contributors to the Open Cluster Management project */ +import { PageSection } from '@patternfly/react-core' +import { useMemo, useCallback } from 'react' +import { useTranslation } from '../../../lib/acm-i18next' +import { ClusterRole } from '../../../resources/rbac' +import { AcmEmptyState, AcmTable, compareStrings, AcmLoadingPage } from '../../../ui-components' +import { rolesTableColumns, useFilters, Role } from './RolesTableHelper' +import { useRolesContext } from './RolesPage' + +const RolesTable = () => { + const { t } = useTranslation() + const { clusterRoles, loading } = useRolesContext() + + const roles = useMemo(() => { + if (!clusterRoles) return [] + + return clusterRoles + .map( + (clusterRole: ClusterRole): Role => ({ + name: clusterRole.metadata.name || '', + description: 'kubevirt.io cluster role', + category: 'Virtualization', + type: 'ClusterRole', + permissions: 'TBD', + uid: clusterRole.metadata.uid || clusterRole.metadata.name || '', + }) + ) + .sort((a, b) => compareStrings(a.name, b.name)) + }, [clusterRoles]) + + const keyFn = useCallback((role: Role) => role.uid, []) + + const filters = useFilters() + const columns = rolesTableColumns({ t }) + + return ( + + {loading ? ( + + ) : ( + + key="roles-table" + filters={filters} + columns={columns} + keyFn={keyFn} + items={roles} + emptyState={} + /> + )} + + ) +} + +export { RolesTable } diff --git a/frontend/src/routes/UserManagement/Roles/RolesTableHelper.tsx b/frontend/src/routes/UserManagement/Roles/RolesTableHelper.tsx new file mode 100644 index 00000000000..69d9c8dad42 --- /dev/null +++ b/frontend/src/routes/UserManagement/Roles/RolesTableHelper.tsx @@ -0,0 +1,114 @@ +/* Copyright Contributors to the Open Cluster Management project */ +import { cellWidth } from '@patternfly/react-table' +import { useMemo } from 'react' +import { TFunction } from 'react-i18next' +import { generatePath, Link } from 'react-router-dom-v5-compat' +import { HighlightSearchText } from '../../../components/HighlightSearchText' +import { NavigationPath } from '../../../NavigationPath' +import { IAcmTableColumn } from '../../../ui-components/AcmTable/AcmTableTypes' + +import { Label } from '@patternfly/react-core' + +const EXPORT_FILE_PREFIX = 'roles-table' + +export interface Role { + name: string + description: string + category: string + type: string + permissions: string + uid: string +} + +type RolesTableHelperProps = { + t: TFunction +} + +const COLUMN_CELLS = { + NAME: (role: Role, search: string) => ( + + + + + + ), + DESCRIPTION: (role: Role) => {role.description}, + CATEGORY: (role: Role) => , + TYPE: (role: Role) => {role.type}, + PERMISSIONS: (role: Role) => {role.permissions}, +} + +export const rolesTableColumns = ({ t }: Pick): IAcmTableColumn[] => [ + { + header: t('Role'), + sort: 'name', + search: 'name', + transforms: [cellWidth(25)], + cell: (role, search) => COLUMN_CELLS.NAME(role, search), + exportContent: (role) => role.name, + }, + { + header: t('Description'), + sort: 'description', + search: 'description', + transforms: [cellWidth(30)], + cell: (role) => COLUMN_CELLS.DESCRIPTION(role), + exportContent: (role) => role.description, + }, + { + header: t('Category'), + sort: 'category', + transforms: [cellWidth(15)], + cell: (role) => COLUMN_CELLS.CATEGORY(role), + exportContent: (role) => role.category, + }, + { + header: t('Type'), + sort: 'type', + transforms: [cellWidth(15)], + cell: (role) => COLUMN_CELLS.TYPE(role), + exportContent: (role) => role.type, + }, + { + header: t('Permissions'), + sort: 'permissions', + transforms: [cellWidth(15)], + cell: (role) => COLUMN_CELLS.PERMISSIONS(role), + exportContent: (role) => role.permissions.toString(), + }, +] + +export const useFilters = () => { + return useMemo( + () => [ + { + id: 'category', + label: 'Category', + tableFilterFn: (selection: string[], role: Role) => { + if (selection.length === 0) return true + return selection.some((selected: string) => role.category === selected) + }, + options: [ + { label: 'System', value: 'System' }, + { label: 'Custom', value: 'Custom' }, + { label: 'Default', value: 'Default' }, + ], + }, + { + id: 'type', + label: 'Type', + tableFilterFn: (selection: string[], role: Role) => { + if (selection.length === 0) return true + return selection.some((selected: string) => role.type === selected) + }, + options: [ + { label: 'ClusterRole', value: 'ClusterRole' }, + { label: 'Role', value: 'Role' }, + ], + }, + ], + [] + ) +} + +export { EXPORT_FILE_PREFIX, COLUMN_CELLS }