Skip to content

Commit

Permalink
Merge branch 'kubernetes' of github.com:pluralsh/console into kubernetes
Browse files Browse the repository at this point in the history
  • Loading branch information
floreks committed Apr 2, 2024
2 parents 3d49e33 + c24d380 commit f62138c
Show file tree
Hide file tree
Showing 5 changed files with 355 additions and 18 deletions.
87 changes: 82 additions & 5 deletions assets/src/components/kubernetes/cluster/Namespace.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
import { ReactElement, useMemo } from 'react'
import { SidecarItem, useSetBreadcrumbs } from '@pluralsh/design-system'
import { SidecarItem, Table, useSetBreadcrumbs } from '@pluralsh/design-system'
import { Outlet, useOutletContext, useParams } from 'react-router-dom'
import { createColumnHelper } from '@tanstack/react-table'
import { isEmpty } from 'lodash'

import {
Common_EventList as EventListT,
Common_Event as EventT,
Limitrange_LimitRangeItem as LimitRangeT,
NamespaceEventsQuery,
NamespaceEventsQueryVariables,
NamespaceQueryVariables,
Namespace_Namespace as NamespaceT,
Namespace_NamespaceDetail as NamespaceT,
Resourcequota_ResourceQuotaDetail as ResourceQuotaT,
useNamespaceEventsQuery,
useNamespaceQuery,
} from '../../../generated/graphql-kubernetes'
import { KubernetesClient } from '../../../helpers/kubernetes.client'
import LoadingIndicator from '../../utils/LoadingIndicator'
import { MetadataSidecar, useKubernetesCluster } from '../utils'
import { getResourceDetailsAbsPath } from '../../../routes/kubernetesRoutesConsts'

import ResourceDetails, { TabEntry } from '../ResourceDetails'

import { ResourceList } from '../ResourceList'
import { SubTitle } from '../../cluster/nodes/SubTitle'

import { getBreadcrumbs } from './Namespaces'
import { NamespacePhaseChip } from './utils'
Expand Down Expand Up @@ -76,10 +79,84 @@ export default function Namespace(): ReactElement {
)
}

const rqColumnHelper = createColumnHelper<ResourceQuotaT>()

const rqColumns = [
rqColumnHelper.accessor((rq) => rq?.objectMeta.name, {
id: 'name',
header: 'Name',
cell: ({ getValue }) => getValue(),
}),
rqColumnHelper.accessor((rq) => rq?.scopes, {
id: 'scopes',
header: 'Scopes',
cell: ({ getValue }) => getValue()?.map((scope) => <div>{scope}</div>),
}),
rqColumnHelper.accessor((rq) => rq?.statusList, {
id: 'statusList',
header: 'Status list',
cell: ({ getValue }) => JSON.stringify(getValue()),
}),
]

const lrColumnHelper = createColumnHelper<LimitRangeT>()

const lrColumns = [
lrColumnHelper.accessor((lr) => lr?.resourceName, {
id: 'name',
header: 'Name',
cell: ({ getValue }) => getValue(),
}),
lrColumnHelper.accessor((lr) => lr?.resourceType, {
id: 'type',
header: 'Type',
cell: ({ getValue }) => getValue(),
}),
lrColumnHelper.accessor((lr) => lr?.default, {
id: 'default',
header: 'Default',
cell: ({ getValue }) => getValue(),
}),
lrColumnHelper.accessor((lr) => lr?.defaultRequest, {
id: 'defaultRequest',
header: 'Default request',
cell: ({ getValue }) => getValue(),
}),
]

export function NamespaceInfo(): ReactElement {
const namespace = useOutletContext() as NamespaceT

return <section>TODO</section>
return (
<>
{!isEmpty(namespace?.resourceQuotaList?.items) && (
<section>
<SubTitle>Resource quotas</SubTitle>
<Table
data={namespace?.resourceQuotaList?.items}
columns={rqColumns}
css={{
maxHeight: '500px',
height: '100%',
}}
/>
</section>
)}
{!isEmpty(namespace?.resourceLimits) && (
<section>
<SubTitle>Resource limits</SubTitle>
<Table
data={namespace?.resourceLimits}
columns={lrColumns}
css={{
maxHeight: '500px',
height: '100%',
}}
/>
</section>
)}
</>
)
}

export function NamespaceEvents(): ReactElement {
Expand Down
162 changes: 151 additions & 11 deletions assets/src/components/kubernetes/cluster/Node.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
import { ReactElement, useMemo } from 'react'
import { SidecarItem, useSetBreadcrumbs } from '@pluralsh/design-system'
import React, { ReactElement, useMemo } from 'react'
import {
Card,
ChipList,
SidecarItem,
useSetBreadcrumbs,
} from '@pluralsh/design-system'
import { Outlet, useOutletContext, useParams } from 'react-router-dom'

import { useTheme } from 'styled-components'

import {
Common_EventList as EventListT,
Common_Event as EventT,
NodeEventsQuery,
NodeEventsQueryVariables,
NodePodsQuery,
NodePodsQueryVariables,
NodeQueryVariables,
Node_Node as NodeT,
Node_NodeDetail as NodeT,
Pod_PodList as PodListT,
Pod_Pod as PodT,
useNodeEventsQuery,
useNodePodsQuery,
useNodeQuery,
} from '../../../generated/graphql-kubernetes'
import { KubernetesClient } from '../../../helpers/kubernetes.client'
Expand All @@ -21,12 +33,23 @@ import ResourceDetails, { TabEntry } from '../ResourceDetails'

import { ResourceList } from '../ResourceList'

import { getBreadcrumbs } from './Namespaces'
import { NamespacePhaseChip } from './utils'
import { SubTitle } from '../../cluster/nodes/SubTitle'

import { ResourceInfoCardEntry } from '../common/ResourceInfoCard'

import { GaugeWrap, ResourceGauge } from '../../cluster/Gauges'

import { usePodColumns } from '../workloads/Pods'

import Conditions from '../common/Conditions'

import { getBreadcrumbs } from './Nodes'
import { useEventsColumns } from './Events'
import { NodeReadyChip } from './utils'

const directory: Array<TabEntry> = [
{ path: '', label: 'Info' },
{ path: 'pods', label: 'Pods' },
{ path: 'events', label: 'Events' },
{ path: 'raw', label: 'Raw' },
] as const
Expand All @@ -43,7 +66,7 @@ export default function Node(): ReactElement {
} as NodeQueryVariables,
})

const namespace = data?.handleGetNodeDetail
const node = data?.handleGetNodeDetail

useSetBreadcrumbs(
useMemo(
Expand All @@ -64,22 +87,139 @@ export default function Node(): ReactElement {
<ResourceDetails
tabs={directory}
sidecar={
<MetadataSidecar resource={namespace}>
<SidecarItem heading="Phase">
<NamespacePhaseChip phase={namespace?.phase} />
<MetadataSidecar resource={node}>
<SidecarItem heading="Ready">
{/* TODO: Fix on the API side? It works in the list view. */}
<NodeReadyChip ready={node?.ready} />
</SidecarItem>
{/* TODO: Fix on the API side? */}
<SidecarItem heading="Phase">{node?.phase}</SidecarItem>
</MetadataSidecar>
}
>
<Outlet context={namespace} />
<Outlet context={node} />
</ResourceDetails>
)
}

export function NodeInfo(): ReactElement {
const theme = useTheme()
const node = useOutletContext() as NodeT

return <section>TODO</section>
return (
<>
<section>
<SubTitle>Allocated resources</SubTitle>
<Card>
<GaugeWrap
heading="Memory reservation"
width="auto"
height="auto"
>
<ResourceGauge
limits={node.allocatedResources.memoryLimits}
requests={node.allocatedResources.memoryRequests}
total={node.allocatedResources.memoryCapacity}
type="memory"
/>
</GaugeWrap>
TODO
</Card>
</section>
<section>
<SubTitle>Conditions</SubTitle>
<Conditions conditions={node.conditions} />
</section>
<section>
<SubTitle>Node information</SubTitle>
<Card
css={{
display: 'flex',
gap: theme.spacing.large,
padding: theme.spacing.medium,
}}
>
<ResourceInfoCardEntry heading="Provider ID">
{node?.providerID}
</ResourceInfoCardEntry>
<ResourceInfoCardEntry heading="Unschedulable">
{node?.unschedulable ? 'True' : 'False'}
</ResourceInfoCardEntry>
<ResourceInfoCardEntry heading="Pod CIDR">
{node?.podCIDR}
</ResourceInfoCardEntry>
<ResourceInfoCardEntry heading="Addresses">
<ChipList
size="small"
limit={5}
values={node.addresses || []}
transformValue={(a) => `${a?.type}: ${a?.address}`}
emptyState={<div>None</div>}
/>
</ResourceInfoCardEntry>
<ResourceInfoCardEntry heading="Taints">
<ChipList
size="small"
limit={5}
values={node.taints || []}
transformValue={(t) => `${t?.key}=${t?.value}:${t?.effect}`}
emptyState={<div>None</div>}
/>
</ResourceInfoCardEntry>
<ResourceInfoCardEntry heading="Machine ID">
{node?.nodeInfo.machineID}
</ResourceInfoCardEntry>
<ResourceInfoCardEntry heading="System UUID">
{node?.nodeInfo.systemUUID}
</ResourceInfoCardEntry>
<ResourceInfoCardEntry heading="Boot ID">
{node?.nodeInfo.bootID}
</ResourceInfoCardEntry>
<ResourceInfoCardEntry heading="Kernel version">
{node?.nodeInfo.kernelVersion}
</ResourceInfoCardEntry>
<ResourceInfoCardEntry heading="OS image">
{node?.nodeInfo.osImage}
</ResourceInfoCardEntry>
<ResourceInfoCardEntry heading="Container runtime version">
{node?.nodeInfo.containerRuntimeVersion}
</ResourceInfoCardEntry>
<ResourceInfoCardEntry heading="kubelet version">
{node?.nodeInfo.kubeletVersion}
</ResourceInfoCardEntry>
<ResourceInfoCardEntry heading="kube-proxy version">
{node?.nodeInfo.kubeProxyVersion}
</ResourceInfoCardEntry>
<ResourceInfoCardEntry heading="Operating system">
{node?.nodeInfo.operatingSystem}
</ResourceInfoCardEntry>
<ResourceInfoCardEntry heading="Architecture">
{node?.nodeInfo.architecture}
</ResourceInfoCardEntry>
</Card>
</section>
</>
)
}

export function NodePods(): ReactElement {
const { name } = useParams()
const columns = usePodColumns()

// TODO: Pagination etc.
return (
<ResourceList<PodListT, PodT, NodePodsQuery, NodePodsQueryVariables>
namespaced
columns={columns}
query={useNodePodsQuery}
queryOptions={{
variables: { name } as NodePodsQueryVariables,
}}
queryName="handleGetNodePods"
itemsKey="pods"
disableOnRowClick
/>
)
}

export function NodeEvents(): ReactElement {
Expand Down
Loading

0 comments on commit f62138c

Please sign in to comment.