Skip to content
This repository was archived by the owner on Jul 30, 2025. It is now read-only.

Commit cd642d9

Browse files
committed
feat: revive "app" and "tier" columns from deprecated kubectl tree view
This PR requires adding an optional metadata attribute to the core Table.Row model Fixes #6591
1 parent d9717ff commit cd642d9

File tree

10 files changed

+81
-17
lines changed

10 files changed

+81
-17
lines changed

packages/core/src/models/entity.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export interface MetadataNamedResource {
4949
namespace?: string
5050
generation?: string
5151
creationTimestamp?: string
52+
labels?: Record<string, string>
5253
}
5354
}
5455

packages/core/src/webapp/models/table.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,23 @@
1818

1919
import { ReactElement } from 'react'
2020
import { Breadcrumb } from '../../models/NavResponse'
21-
import { MetadataBearing, Entity } from '../../models/entity'
21+
import { MetadataBearing, MetadataNamedResource, Entity } from '../../models/entity'
2222

2323
export class Row {
2424
attributes?: Cell[]
2525

2626
/** uniquely identifies this row in a given table; if not defined, we will use the name field as the row key */
2727
rowKey?: string
2828

29+
/** optional associated metadata for the corresponding resource */
30+
object?: Pick<MetadataNamedResource, 'metadata'> & {
31+
spec?: {
32+
selector?: {
33+
matchLabels?: Record<string, string>
34+
}
35+
}
36+
}
37+
2938
/** the key-value pair for the first column */
3039
key?: string
3140
name: string

plugins/plugin-client-common/src/components/Content/Table/LivePaginatedTable.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import { Table as KuiTable, Row as KuiRow, Watchable } from '@kui-shell/core'
1818

1919
import PaginatedTable, { Props, State } from './PaginatedTable'
20-
import { kuiHeader2carbonHeader, kuiRow2carbonRow, NamedDataTableRow } from './kui2carbon'
20+
import { kuiHeaderFromBody, kuiHeader2carbonHeader, kuiRow2carbonRow, NamedDataTableRow } from './kui2carbon'
2121

2222
type LiveProps = Props<KuiTable & Watchable> & { onRender: (hasContent: boolean) => void }
2323

@@ -132,6 +132,13 @@ export default class LivePaginatedTable extends PaginatedTable<LiveProps, LiveSt
132132
*
133133
*/
134134
private update(newKuiRow: KuiRow, batch = false, justUpdated = true) {
135+
if (!this.props.response.header) {
136+
const header = kuiHeaderFromBody([newKuiRow])
137+
if (header) {
138+
this.header(header)
139+
}
140+
}
141+
135142
const existingRows = this._deferredUpdate || this.state.rows
136143
const nRowsBefore = existingRows.length
137144

plugins/plugin-client-common/src/components/Content/Table/kui2carbon.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,26 @@ export interface NamedDataTableRow extends DataTableRow {
2323
justUpdated: boolean
2424
}
2525

26+
export function kuiHeaderFromBody(body: KuiTable['body']): KuiTable['header'] {
27+
if (body.length > 0) {
28+
const attributes = (body[0].attributes || []).map(({ key, value }) => ({
29+
key: key || value,
30+
value: key || value
31+
}))
32+
return { key: body[0].key, name: body[0].name, attributes }
33+
}
34+
}
35+
2636
/** attempt to infer header model from body model */
2737
function headerFromBody(table: KuiTable) {
2838
if (table.body.length > 0) {
2939
const attrs = (table.body[0].attributes || []).map(({ key, value }) => ({
3040
key: key || value,
3141
header: key || value
3242
}))
33-
const headers = [{ key: 'NAME', header: 'NAME' }, ...attrs]
43+
const headers = [{ key: 'Name', header: 'Name' }, ...attrs]
3444
table.header = {
35-
name: 'NAME',
45+
name: 'Name',
3646
attributes: attrs.map(({ key }) => ({ key, value: key }))
3747
}
3848
return headers
@@ -70,12 +80,11 @@ export function kuiRow2carbonRow(headers: DataTableHeader[], justUpdated = false
7080

7181
if (!row.attributes) row.attributes = []
7282
row.attributes.forEach((attr, cidx) => {
73-
const { key, value } = attr
74-
const kkey = headers[cidx + 1].key
75-
if (!key) {
83+
const kkey = attr.key || headers[cidx + 1] ? headers[cidx + 1].key : undefined
84+
if (!attr.key && kkey) {
7685
attr.key = kkey
7786
}
78-
rowData[kkey] = value
87+
rowData[kkey] = attr.value
7988
})
8089

8190
if (!rowData.NAME) {

plugins/plugin-kubectl/src/controller/client/direct/status.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { Abortable, Arguments, CodedError, Row, Table, Watchable, Watcher, Watch
2121
import { getTable } from './get'
2222
import fabricate404Table from './404'
2323
import URLFormatter, { urlFormatterFor } from './url'
24-
import { unifyHeaders, unifyRow, unifyRows } from './unify'
24+
import { unifyRow, unifyRows } from './unify'
2525
import makeWatchable, { DirectWatcher, SingleKindDirectWatcher } from './watch'
2626

2727
import { Explained } from '../../kubectl/explain'
@@ -113,8 +113,10 @@ class MultiKindWatcher implements Abortable, Watcher {
113113

114114
private myPusher(idx: number): WatchPusher {
115115
const overrides: Pick<WatchPusher, 'header' | 'update' | 'done'> = {
116-
header: (header: Row) => {
117-
this.pusher.header(unifyHeaders([header]))
116+
header: () => {
117+
// instead: have the view infer headers from the body; this
118+
// allows for more schema flexibility across rows
119+
// this.pusher.header(unifyHeaders([header]))
118120
},
119121
update: (row: Row, batch?: boolean, changed?: boolean) => {
120122
debug('update of unified row', row.rowKey, this.kind[idx].kind, row.attributes[1].value)
@@ -236,7 +238,9 @@ export default async function watchMulti(
236238
: undefined
237239

238240
// header and body
239-
const header = unifyHeaders([].concat(...tables.map(_ => _.table.header)))
241+
// re: header, have the view infer headers from the body; this
242+
// allows for more schema flexibility across rows
243+
const header = undefined // unifyHeaders([].concat(...tables.map(_ => _.table.header)))
240244
const body = unifyRows(
241245
[].concat(...tables.map(_ => _.table.body)),
242246
flatten(

plugins/plugin-kubectl/src/controller/client/direct/unify.ts

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { Table, Row } from '@kui-shell/core'
17+
import { Cell, Row, Table } from '@kui-shell/core'
1818
import TrafficLight, { toTrafficLight } from '../../../lib/model/traffic-light'
1919

2020
/** Do not i18n! */
@@ -40,11 +40,12 @@ export function rowWith(
4040
kind: string,
4141
status: string,
4242
trafficLight: TrafficLight,
43-
originalRow?: Row
43+
originalRow?: Row,
44+
extraAttrs: Cell[] = []
4445
): Row {
4546
const overlay: Row = {
4647
name,
47-
attributes: [
48+
attributes: extraAttrs.concat([
4849
{
4950
key: Kind,
5051
value: kind
@@ -55,7 +56,7 @@ export function rowWith(
5556
tag: 'badge',
5657
css: trafficLight
5758
}
58-
]
59+
])
5960
}
6061

6162
if (originalRow) {
@@ -70,14 +71,43 @@ export function unifyHeaders(headers: Table['header'][]): Table['header'] {
7071
return standardStatusHeader
7172
}
7273

74+
function getFromLabel(object: Row['object'], field: string): string {
75+
return object.metadata.labels[field]
76+
}
77+
78+
function getFromSelector(object: Row['object'], field: string) {
79+
if (object.spec && object.spec.selector && object.spec.selector.matchLabels) {
80+
return object.spec.selector.matchLabels[field]
81+
}
82+
}
83+
7384
export function unifyRow(row: Row, kind: string): Row {
7485
const name = row.name
7586

7687
const badgeColumnIdx = row.attributes.findIndex(_ => _.tag === 'badge')
7788
const status = badgeColumnIdx >= 0 ? row.attributes[badgeColumnIdx].value : 'Unknown'
7889
const trafficLight = badgeColumnIdx >= 0 ? toTrafficLight(row.attributes[badgeColumnIdx].css) : TrafficLight.Gray
7990

80-
return rowWith(name, kind, status, trafficLight, row)
91+
const extraAttrs: Cell[] = []
92+
if (row.object) {
93+
const tier =
94+
getFromLabel(row.object, 'tier') ||
95+
getFromLabel(row.object, 'app.kubernetes.io/component') ||
96+
getFromSelector(row.object, 'tier')
97+
if (tier) {
98+
extraAttrs.push({ key: 'Tier', value: tier })
99+
}
100+
101+
const app =
102+
getFromLabel(row.object, 'app') ||
103+
getFromLabel(row.object, 'app.kubernetes.io/name') ||
104+
getFromSelector(row.object, 'app')
105+
if (app) {
106+
extraAttrs.push({ key: 'Application', value: app })
107+
}
108+
}
109+
110+
return rowWith(name, kind, status, trafficLight, row, extraAttrs)
81111
}
82112

83113
export function unifyRows(rows: Table['body'], kinds: string | string[]): Table['body'] {

plugins/plugin-kubectl/src/lib/view/formatTable.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,7 @@ export async function toKuiTable(
700700
const onclick = onclickFor(row, name)
701701

702702
return {
703+
object: row.object,
703704
key: forAllNamespaces ? row.object.metadata.namespace : columnDefinitions[0].name,
704705
rowKey,
705706
name: forAllNamespaces ? row.object.metadata.namespace : name,

plugins/plugin-kubectl/tests/data/k8s/application/guestbook/frontend-deployment.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ metadata:
44
name: frontend
55
labels:
66
app: guestbook
7+
tier: frontend
78
spec:
89
selector:
910
matchLabels:

plugins/plugin-kubectl/tests/data/k8s/application/guestbook/redis-master-deployment.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ metadata:
44
name: redis-master
55
labels:
66
app: redis
7+
tier: backend
78
spec:
89
selector:
910
matchLabels:

plugins/plugin-kubectl/tests/data/k8s/application/guestbook/redis-slave-deployment.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ metadata:
44
name: redis-slave
55
labels:
66
app: redis
7+
tier: backend
78
spec:
89
selector:
910
matchLabels:

0 commit comments

Comments
 (0)