diff --git a/assets/src/components/kubernetes/access/ClusterRole.tsx b/assets/src/components/kubernetes/access/ClusterRole.tsx index 66e4f6001..b33e79fc4 100644 --- a/assets/src/components/kubernetes/access/ClusterRole.tsx +++ b/assets/src/components/kubernetes/access/ClusterRole.tsx @@ -1,5 +1,75 @@ -import { ReactElement } from 'react' +import { ReactElement, useMemo } from 'react' +import { Outlet, useOutletContext, useParams } from 'react-router-dom' +import { useSetBreadcrumbs } from '@pluralsh/design-system' + +import { KubernetesClient } from '../../../helpers/kubernetes.client' +import { + ClusterRoleQueryVariables, + Clusterrole_ClusterRoleDetail as ClusterRoleT, + useClusterRoleQuery, +} from '../../../generated/graphql-kubernetes' +import { MetadataSidecar, useKubernetesCluster } from '../utils' + +import { getResourceDetailsAbsPath } from '../../../routes/kubernetesRoutesConsts' +import LoadingIndicator from '../../utils/LoadingIndicator' +import ResourceDetails, { TabEntry } from '../ResourceDetails' +import PolicyRules from '../common/PolicyRules' + +import { FullHeightTableWrap } from '../../utils/layout/FullHeightTableWrap' + +import { getBreadcrumbs } from './ClusterRoles' + +const directory: Array = [ + { path: '', label: 'Policy rules' }, + { path: 'raw', label: 'Raw' }, +] as const export default function ClusterRole(): ReactElement { - return
ClusterRole details
+ const cluster = useKubernetesCluster() + const { clusterId, name = '' } = useParams() + const { data, loading } = useClusterRoleQuery({ + client: KubernetesClient(clusterId ?? ''), + skip: !clusterId, + pollInterval: 30_000, + variables: { + name, + } as ClusterRoleQueryVariables, + }) + + const cr = data?.handleGetClusterRoleDetail + + useSetBreadcrumbs( + useMemo( + () => [ + ...getBreadcrumbs(cluster), + + { + label: name ?? '', + url: getResourceDetailsAbsPath(clusterId, 'clusterrole', name), + }, + ], + [cluster, clusterId, name] + ) + ) + + if (loading) return + + return ( + } + > + + + ) +} + +export function RolePolicyRules(): ReactElement { + const cr = useOutletContext() as ClusterRoleT + + return ( + + + + ) } diff --git a/assets/src/components/kubernetes/access/Role.tsx b/assets/src/components/kubernetes/access/Role.tsx index 20221dc4c..63ad6a80c 100644 --- a/assets/src/components/kubernetes/access/Role.tsx +++ b/assets/src/components/kubernetes/access/Role.tsx @@ -1,5 +1,89 @@ -import { ReactElement } from 'react' +import { ReactElement, useMemo } from 'react' +import { Outlet, useOutletContext, useParams } from 'react-router-dom' +import { useSetBreadcrumbs } from '@pluralsh/design-system' + +import { MetadataSidecar, useKubernetesCluster } from '../utils' +import { + RoleQueryVariables, + Role_RoleDetail as RoleT, + useRoleQuery, +} from '../../../generated/graphql-kubernetes' +import { KubernetesClient } from '../../../helpers/kubernetes.client' + +import { + ROLES_REL_PATH, + getAccessAbsPath, + getResourceDetailsAbsPath, +} from '../../../routes/kubernetesRoutesConsts' +import { NAMESPACE_PARAM } from '../Kubernetes' +import LoadingIndicator from '../../utils/LoadingIndicator' +import ResourceDetails, { TabEntry } from '../ResourceDetails' + +import { SubTitle } from '../../cluster/nodes/SubTitle' + +import PolicyRules from '../common/PolicyRules' + +import { FullHeightTableWrap } from '../../utils/layout/FullHeightTableWrap' + +import { getBreadcrumbs } from './Roles' + +const directory: Array = [ + { path: '', label: 'Policy rules' }, + { path: 'raw', label: 'Raw' }, +] as const export default function Role(): ReactElement { - return
Role details
+ const cluster = useKubernetesCluster() + const { clusterId, name = '', namespace = '' } = useParams() + const { data, loading } = useRoleQuery({ + client: KubernetesClient(clusterId ?? ''), + skip: !clusterId, + pollInterval: 30_000, + variables: { + name, + namespace, + } as RoleQueryVariables, + }) + + const role = data?.handleGetRoleDetail + + useSetBreadcrumbs( + useMemo( + () => [ + ...getBreadcrumbs(cluster), + { + label: namespace ?? '', + url: `${getAccessAbsPath( + cluster?.id + )}/${ROLES_REL_PATH}?${NAMESPACE_PARAM}=${namespace}`, + }, + { + label: name ?? '', + url: getResourceDetailsAbsPath(clusterId, 'role', name, namespace), + }, + ], + [cluster, clusterId, name, namespace] + ) + ) + + if (loading) return + + return ( + } + > + + + ) +} + +export function RolePolicyRules(): ReactElement { + const role = useOutletContext() as RoleT + + return ( + + + + ) } diff --git a/assets/src/components/kubernetes/common/PolicyRules.tsx b/assets/src/components/kubernetes/common/PolicyRules.tsx new file mode 100644 index 000000000..45bfe9b09 --- /dev/null +++ b/assets/src/components/kubernetes/common/PolicyRules.tsx @@ -0,0 +1,59 @@ +import { ReactElement } from 'react' +import { Table } from '@pluralsh/design-system' +import { createColumnHelper } from '@tanstack/react-table' + +import { + Maybe, + V1_PolicyRule as PolicyRuleT, +} from '../../../generated/graphql-kubernetes' + +const columnHelper = createColumnHelper() + +const columns = [ + columnHelper.accessor((rule) => rule?.resources, { + id: 'resources', + header: 'Resources', + cell: ({ getValue }) => + getValue()?.map((resource) =>
{resource}
), + }), + columnHelper.accessor((rule) => rule?.nonResourceURLs, { + id: 'nonResourceURLs', + header: 'Non-resource URL', + cell: ({ getValue }) => + getValue()?.map((nonResourceURL) =>
{nonResourceURL}
), + }), + columnHelper.accessor((rule) => rule?.resourceNames, { + id: 'resourceNames', + header: 'Resource names', + cell: ({ getValue }) => + getValue()?.map((resourceName) =>
{resourceName}
), + }), + columnHelper.accessor((rule) => rule?.verbs, { + id: 'verbs', + header: 'Verbs', + cell: ({ getValue }) => getValue()?.map((verb) =>
{verb}
), + }), + columnHelper.accessor((rule) => rule?.apiGroups, { + id: 'apiGroups', + header: 'API groups', + cell: ({ getValue }) => + getValue()?.map((apiGroup) =>
{apiGroup}
), + }), +] + +export default function PolicyRules({ + rules, +}: { + rules: Array> +}): ReactElement { + return ( + + ) +} diff --git a/assets/src/components/kubernetes/configuration/ConfigMap.tsx b/assets/src/components/kubernetes/configuration/ConfigMap.tsx index eb54e466b..2a0db64d1 100644 --- a/assets/src/components/kubernetes/configuration/ConfigMap.tsx +++ b/assets/src/components/kubernetes/configuration/ConfigMap.tsx @@ -11,7 +11,6 @@ import { } from '../../../generated/graphql-kubernetes' import { KubernetesClient } from '../../../helpers/kubernetes.client' import LoadingIndicator from '../../utils/LoadingIndicator' -import { SubTitle } from '../../cluster/nodes/SubTitle' import { MetadataSidecar, useKubernetesCluster } from '../utils' import { NAMESPACE_PARAM } from '../Kubernetes' import { @@ -25,7 +24,7 @@ import ResourceDetails, { TabEntry } from '../ResourceDetails' import { getBreadcrumbs } from './ConfigMaps' const directory: Array = [ - { path: '', label: 'Info' }, + { path: '', label: 'Data' }, { path: 'raw', label: 'Raw' }, ] as const @@ -80,7 +79,7 @@ export default function ConfigMap(): ReactElement { ) } -export function ConfigMapInfo(): ReactElement { +export function ConfigMapData(): ReactElement { const cm = useOutletContext() as ConfigMapT const tabs = useMemo( () => [ @@ -100,14 +99,9 @@ export function ConfigMapInfo(): ReactElement { [cm?.data] ) - return ( -
- Data - {!isEmpty(cm?.data) ? ( - - ) : ( - 'There is no data to display.' - )} -
+ return !isEmpty(cm?.data) ? ( + + ) : ( +
There is no data to display.
) } diff --git a/assets/src/components/kubernetes/configuration/Secret.tsx b/assets/src/components/kubernetes/configuration/Secret.tsx index 5d034929a..680c75720 100644 --- a/assets/src/components/kubernetes/configuration/Secret.tsx +++ b/assets/src/components/kubernetes/configuration/Secret.tsx @@ -32,7 +32,7 @@ import ResourceDetails, { TabEntry } from '../ResourceDetails' import { getBreadcrumbs } from './Secrets' const directory: Array = [ - { path: '', label: 'Info' }, + { path: '', label: 'Data' }, { path: 'raw', label: 'Raw' }, ] as const @@ -151,7 +151,7 @@ const columns = [ }), ] -export function SecretInfo(): ReactElement { +export function SecretData(): ReactElement { const theme = useTheme() const secret = useOutletContext() as SecretT const [revealAll, setRevealAll] = useState(false) @@ -169,13 +169,11 @@ export function SecretInfo(): ReactElement {
- Data