Skip to content

Commit

Permalink
add role and cluster role
Browse files Browse the repository at this point in the history
  • Loading branch information
maciaszczykm committed Mar 29, 2024
1 parent f164f00 commit 92d4146
Show file tree
Hide file tree
Showing 10 changed files with 424 additions and 31 deletions.
74 changes: 72 additions & 2 deletions assets/src/components/kubernetes/access/ClusterRole.tsx
Original file line number Diff line number Diff line change
@@ -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<TabEntry> = [
{ path: '', label: 'Policy rules' },
{ path: 'raw', label: 'Raw' },
] as const

export default function ClusterRole(): ReactElement {
return <div>ClusterRole details</div>
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 <LoadingIndicator />

return (
<ResourceDetails
tabs={directory}
sidecar={<MetadataSidecar objectMeta={cr?.objectMeta} />}
>
<Outlet context={cr} />
</ResourceDetails>
)
}

export function RolePolicyRules(): ReactElement {
const cr = useOutletContext() as ClusterRoleT

return (
<FullHeightTableWrap>
<PolicyRules rules={cr.rules} />
</FullHeightTableWrap>
)
}
88 changes: 86 additions & 2 deletions assets/src/components/kubernetes/access/Role.tsx
Original file line number Diff line number Diff line change
@@ -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<TabEntry> = [
{ path: '', label: 'Policy rules' },
{ path: 'raw', label: 'Raw' },
] as const

export default function Role(): ReactElement {
return <div>Role details</div>
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 <LoadingIndicator />

return (
<ResourceDetails
tabs={directory}
sidecar={<MetadataSidecar objectMeta={role?.objectMeta} />}
>
<Outlet context={role} />
</ResourceDetails>
)
}

export function RolePolicyRules(): ReactElement {
const role = useOutletContext() as RoleT

return (
<FullHeightTableWrap>
<PolicyRules rules={role.rules} />
</FullHeightTableWrap>
)
}
59 changes: 59 additions & 0 deletions assets/src/components/kubernetes/common/PolicyRules.tsx
Original file line number Diff line number Diff line change
@@ -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<PolicyRuleT>()

const columns = [
columnHelper.accessor((rule) => rule?.resources, {
id: 'resources',
header: 'Resources',
cell: ({ getValue }) =>
getValue()?.map((resource) => <div>{resource}</div>),
}),
columnHelper.accessor((rule) => rule?.nonResourceURLs, {
id: 'nonResourceURLs',
header: 'Non-resource URL',
cell: ({ getValue }) =>
getValue()?.map((nonResourceURL) => <div>{nonResourceURL}</div>),
}),
columnHelper.accessor((rule) => rule?.resourceNames, {
id: 'resourceNames',
header: 'Resource names',
cell: ({ getValue }) =>
getValue()?.map((resourceName) => <div>{resourceName}</div>),
}),
columnHelper.accessor((rule) => rule?.verbs, {
id: 'verbs',
header: 'Verbs',
cell: ({ getValue }) => getValue()?.map((verb) => <div>{verb}</div>),
}),
columnHelper.accessor((rule) => rule?.apiGroups, {
id: 'apiGroups',
header: 'API groups',
cell: ({ getValue }) =>
getValue()?.map((apiGroup) => <div>{apiGroup}</div>),
}),
]

export default function PolicyRules({
rules,
}: {
rules: Array<Maybe<PolicyRuleT>>
}): ReactElement {
return (
<Table
data={rules}
columns={columns}
css={{
maxHeight: 'unset',
height: '100%',
}}
/>
)
}
18 changes: 6 additions & 12 deletions assets/src/components/kubernetes/configuration/ConfigMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -25,7 +24,7 @@ import ResourceDetails, { TabEntry } from '../ResourceDetails'
import { getBreadcrumbs } from './ConfigMaps'

const directory: Array<TabEntry> = [
{ path: '', label: 'Info' },
{ path: '', label: 'Data' },
{ path: 'raw', label: 'Raw' },
] as const

Expand Down Expand Up @@ -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(
() => [
Expand All @@ -100,14 +99,9 @@ export function ConfigMapInfo(): ReactElement {
[cm?.data]
)

return (
<section>
<SubTitle>Data</SubTitle>
{!isEmpty(cm?.data) ? (
<Code tabs={tabs} />
) : (
'There is no data to display.'
)}
</section>
return !isEmpty(cm?.data) ? (
<Code tabs={tabs} />
) : (
<div>There is no data to display.</div>
)
}
10 changes: 4 additions & 6 deletions assets/src/components/kubernetes/configuration/Secret.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import ResourceDetails, { TabEntry } from '../ResourceDetails'
import { getBreadcrumbs } from './Secrets'

const directory: Array<TabEntry> = [
{ path: '', label: 'Info' },
{ path: '', label: 'Data' },
{ path: 'raw', label: 'Raw' },
] as const

Expand Down Expand Up @@ -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)
Expand All @@ -169,13 +169,11 @@ export function SecretInfo(): ReactElement {
<div
css={{
...theme.partials.text.subtitle1,
alignItems: 'end',
justifyContent: 'space-between',
justifyContent: 'end',
display: 'flex',
marginBottom: theme.spacing.medium,
marginBottom: theme.spacing.small,
}}
>
<span>Data</span>
<Button
floating
startIcon={revealAll ? <EyeClosedIcon /> : <EyeIcon />}
Expand Down
Loading

0 comments on commit 92d4146

Please sign in to comment.