Skip to content

Commit

Permalink
feat: inspect table view
Browse files Browse the repository at this point in the history
  • Loading branch information
robot9706 committed Oct 6, 2023
1 parent 2ba944b commit f825349
Show file tree
Hide file tree
Showing 3 changed files with 285 additions and 9 deletions.
221 changes: 221 additions & 0 deletions web/frontend/src/components/nodes/inspect-table-view.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
import clsx from 'clsx'
import { useTranslation } from 'react-i18next'
import { DyoLabel } from 'src/elements/dyo-label'
import { DyoList } from 'src/elements/dyo-list'

type KeyValue = {
key: string
value: string
}

interface KeyValueTableProps {
data: KeyValue[]
translateKeys?: boolean
}

const KeyValueTable = (props: KeyValueTableProps) => {
const { data, translateKeys } = props

const { t } = useTranslation('nodes')

const headers = ['common:key', 'common:value']

const defaultHeaderClass = 'uppercase text-lens-text-0 text-sm font-semibold bg-lens-surface-3.5 px-2 py-3 h-11'
const headerClasses = [clsx('rounded-tl-lg pl-4', defaultHeaderClass), clsx('rounded-tr-lg pr-4', defaultHeaderClass)]

const columnWidths = ['w-1/2', 'w-1/2']
const defaultItemClass = 'h-12 min-h-min text-lens-text-1 p-2 line-clamp-1 text-ellipsis'
const itemClasses = [clsx('pl-4', defaultItemClass), clsx('pr-4', defaultItemClass)]

const itemBuilder = (item: KeyValue) => {
const { key, value } = item

const keyTranslate = translateKeys ? t(key) : key

return [<span title={keyTranslate}>{keyTranslate}</span>, <span title={value}>{value}</span>]
}

return (
<DyoList
className="bg-lens-surface-4"
headers={headers.map(it => t(it))}
headerClassName={headerClasses}
columnWidths={columnWidths}
itemClassName={itemClasses}
data={data}
itemBuilder={itemBuilder}
/>
)
}

interface MountsTableProps {
data: any[]
}

const MountsTable = (props: MountsTableProps) => {
const { data } = props

const { t } = useTranslation('nodes')

const headers = [
'mountsInfo.type',
'mountsInfo.source',
'mountsInfo.dest',
'mountsInfo.mode',
'mountsInfo.rw',
'mountsInfo.propagation',
]

const defaultHeaderClass = 'uppercase text-lens-text-0 text-sm font-semibold bg-lens-surface-3.5 px-2 py-3 h-11'
const headerClasses = [
clsx('rounded-tl-lg pl-4', defaultHeaderClass),
...Array.from({ length: headers.length - 2 }).map(() => defaultHeaderClass),
clsx('rounded-tr-lg pr-4', defaultHeaderClass),
]

const columnWidths = ['w-3/12', 'w-3/12', 'w-3/12', 'w-1/12', 'w-1/12', 'w-1/12']
const defaultItemClass = 'h-12 min-h-min text-lens-text-1 p-2 line-clamp-1 text-ellipsis'
const itemClasses = [
clsx('pl-4', defaultItemClass),
...Array.from({ length: headers.length - 2 }).map(() => defaultItemClass),
clsx('pr-4', defaultItemClass),
]

const itemBuilder = (item: any) => {
const { Type: type, Source: source, Destination: dest, Mode: mode, RW: rw, Propagation: propagation } = item

return [
<span>{type}</span>,
<span title={source}>{source}</span>,
<span title={dest}>{dest}</span>,
<span>{mode}</span>,
<span>{rw}</span>,
<span>{propagation}</span>,
]
}

return (
<DyoList
className="bg-lens-surface-4"
headers={headers.map(it => t(it))}
headerClassName={headerClasses}
columnWidths={columnWidths}
itemClassName={itemClasses}
data={data}
itemBuilder={itemBuilder}
/>
)
}

interface InspectTableViewProps {
inspect: any
}

const InspectTableView = (props: InspectTableViewProps) => {
const { inspect } = props
const {
Id: id,
Config: config,
Image: imageHash,
Name: name,
RestartCount: restartCount,
NetworkSettings: networkSettings,
State: state,
Mounts: mounts,
} = inspect
const { Env: env, Labels: labels, Image: image, Hostname: hostname } = config
const { Networks: networks, IPAddress: ipAddress } = networkSettings
const { Status: status, ExitCode: exitCode } = state

const { t } = useTranslation('nodes')

const envTableData = env.map(it => {
const split = it.split('=')
return {
key: split[0],
value: split[1],
}
})

const labelsTableData = Object.entries(labels).map(([key, value]) => ({ key, value: value as string }))

const general: KeyValue[] = [
{
key: 'inspectGeneral.id',
value: id,
},
{
key: 'inspectGeneral.name',
value: name,
},
{
key: 'inspectGeneral.status',
value: status,
},
{
key: 'inspectGeneral.exitCode',
value: exitCode,
},
{
key: 'inspectGeneral.image',
value: image,
},
{
key: 'inspectGeneral.imageHash',
value: imageHash,
},
{
key: 'inspectGeneral.restartCount',
value: restartCount,
},
{
key: 'inspectGeneral.hostName',
value: hostname,
},
{
key: 'inspectGeneral.ip',
value: ipAddress === '' ? '-' : ipAddress,
},
]

const networkTableData = Object.entries(networks).map(([name, network]) => {
const { IPAddress: ip, Gateway: gateway } = network as any

return {
key: name,
value: t('networkInfo', {
ip: ip === '' ? '-' : ip,
gateway: gateway === '' ? '-' : gateway,
}),
}
})

return (
<>
<div className="grid grid-cols-1 xl:grid-cols-2 gap-4 my-4">
<div className="flex flex-col">
<DyoLabel className="text-lg">{t('general')}</DyoLabel>
<KeyValueTable data={general} translateKeys />
</div>
<div className="flex flex-col">
<DyoLabel className="text-lg">{t('environment')}</DyoLabel>
<KeyValueTable data={envTableData} />
</div>
<div className="flex flex-col">
<DyoLabel className="text-lg">{t('labels')}</DyoLabel>
<KeyValueTable data={labelsTableData} />
</div>
<div className="flex flex-col">
<DyoLabel className="text-lg">{t('networks')}</DyoLabel>
<KeyValueTable data={networkTableData} />
</div>
</div>
<div className="flex flex-col">
<DyoLabel className="text-lg">{t('mounts')}</DyoLabel>
<MountsTable data={mounts} />
</div>
</>
)
}

export default InspectTableView
32 changes: 32 additions & 0 deletions web/frontend/src/locales/en/nodes.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,37 @@
"installed": "Installed",
"updateCompleted": "Update completed",
"tokenReplaced": "Token replaced"
},

"json": "Json",
"table": "Table",

"general": "General",
"environment": "Environment",
"labels": "Labels",
"networks": "Networks",
"mounts": "Mounts",

"networkInfo": "IP: {{ip}}, Gateway: {{gateway}}",

"inspectGeneral": {
"id": "Id",
"name": "Name",
"image": "Image",
"imageHash": "Image hash",
"exitCode": "Exit code",
"status": "Status",
"restartCount": "Restart count",
"hostName": "Host name",
"ip": "IP"
},

"mountsInfo": {
"type": "Type",
"source": "Source",
"dest": "Destination",
"mode": "Mode",
"rw": "RW",
"propagation": "Propagation"
}
}
41 changes: 32 additions & 9 deletions web/frontend/src/pages/nodes/[nodeId]/inspect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useParams } from 'react-router-dom'
import { Page } from 'src/components/layout'
import InspectTableView from 'src/components/nodes/inspect-table-view'
import { BreadcrumbLink } from 'src/components/shared/breadcrumb'
import JsonEditor from 'src/components/shared/json-editor-dynamic-module'
import JsonEditor from 'src/components/shared/json-editor'
import PageHeading from 'src/components/shared/page-heading'
import DyoButton from 'src/elements/dyo-button'
import { DyoCard } from 'src/elements/dyo-card'
Expand All @@ -30,14 +31,15 @@ interface ContainerInspectPageProps {
name: string
}

type ViewState = 'table' | 'json'

const NodeContainerInspectPage = (props: ContainerInspectPageProps) => {
const { inspect, node, prefix, name } = props

const { t } = useTranslation('common')
const { t } = useTranslation('nodes')
const [viewState, setViewState] = useState<ViewState>('table')

const pageLink: BreadcrumbLink = {
name: t('nodes'),
name: t('common:nodes'),
url: ROUTE_NODES,
}
Expand All @@ -48,32 +50,53 @@ const NodeContainerInspectPage = (props: ContainerInspectPageProps) => {
url: `${nodeDetailsUrl(node.id)}`,
},
{
name: t('log'),
name: t('common:log'),
url: `${nodeContainerInspectUrl(node.id, { prefix, name })}`,
},
]

return (
<Page title={t('image')}>
<Page title={t('common:inspect')}>
<PageHeading pageLink={pageLink} sublinks={sublinks}>
<DyoButton className="ml-auto px-6" secondary href={nodeDetailsUrl(node.id)}>
{t('back')}
{t('common:back')}
</DyoButton>
</PageHeading>

<DyoCard className="p-4">
<div className="flex mb-4 justify-between items-start">
<DyoHeading element="h4" className="text-xl text-lens-bright">
{t('inspectOf', { name: prefix ? `${prefix}-${name}` : name })}
<DyoHeading element="h4" className="text-xl text-lens-text-0">
{t('common:inspectOf', { name: prefix ? `${prefix}-${name}` : name })}
</DyoHeading>

<div className="flex">
<DyoButton
text
thin
textColor="text-lens-text-0"
underlined={viewState === 'table'}
onClick={() => setViewState('table')}
heightClassName="pb-2"
className="mx-4"
>
{t('table')}
</DyoButton>

<DyoButton
text
thin
textColor="text-lens-text-0"
underlined={viewState === 'json'}
onClick={() => setViewState('json')}
className="mx-4"
heightClassName="pb-2"
>
{t('json')}
</DyoButton>
</div>
</div>

<JsonEditor value={inspect} disabled />
{viewState === 'table' ? <InspectTableView inspect={inspect} /> : <JsonEditor value={inspect} disabled />}
</DyoCard>
</Page>
)
Expand Down

0 comments on commit f825349

Please sign in to comment.