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

Commit a59ee86

Browse files
committed
fix: don't blink yellow forever for kubectl events
in support of this fix, this PR allows push providers to specify whether the `update()` call should be reflected as a change in the UI. this allows the kubectl push provider to special case Events, which, though "yellow" or "red", should not be blinky, because they'll be yellow or red forever. Fixes #4869
1 parent f6176a1 commit a59ee86

File tree

9 files changed

+83
-29
lines changed

9 files changed

+83
-29
lines changed

packages/core/src/core/jobs/watchable.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,32 @@ export interface Watchable {
3333

3434
/** callbacks to indicate state changes */
3535
export interface WatchPusher {
36-
update: (response: Row, batch?: boolean) => void
36+
/**
37+
*
38+
* @param response Updated row model
39+
*
40+
* @param batch? is this part of a batch update? Updates to the view
41+
* will be deferred until a call to batchUpdateDone()
42+
*
43+
* @param changed? allows push provider to specify whether this
44+
* update should be visualized as a change to the model [default:
45+
* true]
46+
*/
47+
update: (response: Row, batch?: boolean, changed?: boolean) => void
48+
49+
/** A batch of calls to `update` is complete */
3750
batchUpdateDone: () => void
3851

52+
/** The given keyed row is gone */
3953
offline: (rowKey: string) => void
4054

55+
/** No more updates will be performed */
4156
done: () => void
57+
58+
/** The entire underlying model has disappared */
4259
allOffline: () => void
60+
61+
/** The header model has changed */
4362
header: (response: Row) => void
4463
}
4564

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ export default class LivePaginatedTable extends PaginatedTable<LiveProps, LiveSt
9191
}
9292
})
9393

94-
const newRow = kuiRow2carbonRow(this.state.headers)(kuiRow, foundIndex)
94+
const newRow = kuiRow2carbonRow(this.state.headers, true)(kuiRow, foundIndex)
9595
const newRows = existingRows
9696
.slice(0, foundIndex)
9797
.concat([newRow])
@@ -116,8 +116,8 @@ export default class LivePaginatedTable extends PaginatedTable<LiveProps, LiveSt
116116
* update consumes the update notification and apply it to the table view
117117
*
118118
*/
119-
private update(newKuiRow: KuiRow, batch = false) {
120-
const existingRows = this.state.rows
119+
private update(newKuiRow: KuiRow, batch = false, justUpdated = true) {
120+
const existingRows = this._deferredUpdate || this.state.rows
121121
const nRowsBefore = existingRows.length
122122

123123
const foundIndex = existingRows.findIndex(
@@ -129,7 +129,7 @@ export default class LivePaginatedTable extends PaginatedTable<LiveProps, LiveSt
129129

130130
const insertionIndex = foundIndex === -1 ? nRowsBefore : foundIndex
131131

132-
const newRow = kuiRow2carbonRow(this.state.headers)(newKuiRow, insertionIndex)
132+
const newRow = kuiRow2carbonRow(this.state.headers, justUpdated)(newKuiRow, insertionIndex)
133133

134134
// Notes: since PaginatedTable is a React.PureComponent, we will
135135
// need to create a new array, rather than mutating the existing
@@ -151,8 +151,6 @@ export default class LivePaginatedTable extends PaginatedTable<LiveProps, LiveSt
151151

152152
if (!batch) {
153153
this.setState({ rows: newRows })
154-
} else if (this._deferredUpdate) {
155-
this._deferredUpdate = newRows
156154
} else {
157155
this._deferredUpdate = newRows
158156
}

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,17 @@ export default class PaginatedTable<P extends Props, S extends State> extends Re
204204
}
205205
>
206206
{response.header && renderHeader(response.header, renderOpts)}
207-
{renderBody(response.body, renderOpts, tab, repl, offset)}
207+
{renderBody(
208+
response.body,
209+
this.state.rows.reduce((M, _) => {
210+
if (_.justUpdated) M[_.rowKey] = true
211+
return M
212+
}, {} as Record<string, boolean>),
213+
renderOpts,
214+
tab,
215+
repl,
216+
offset
217+
)}
208218
</Table>
209219
</TableContainer>
210220
)}

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

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import * as React from 'react'
2020
import { DataTableCustomRenderProps, TableBody, TableRow } from 'carbon-components-react'
2121

2222
import renderCell from './TableCell'
23+
import { NamedDataTableRow } from './kui2carbon'
2324

2425
/**
2526
* Render the TableBody part
@@ -29,24 +30,30 @@ import renderCell from './TableCell'
2930
*/
3031
export default function renderBody(
3132
kuiBody: KuiRow[],
32-
renderOpts: DataTableCustomRenderProps,
33+
justUpdated: Record<string, boolean>, // rowKey index
34+
renderOpts: DataTableCustomRenderProps<NamedDataTableRow>,
3335
tab: Tab,
3436
repl: REPL,
3537
offset: number
3638
) {
3739
return (
3840
<TableBody>
39-
{renderOpts.rows.map((row, ridx) => (
40-
<TableRow
41-
key={row.id}
42-
{...renderOpts.getRowProps({
43-
row,
44-
'data-name': kuiBody[offset + ridx].name
45-
})}
46-
>
47-
{row.cells.map(renderCell(kuiBody[offset + ridx], row, tab, repl))}
48-
</TableRow>
49-
))}
41+
{renderOpts.rows.map((row, ridx) => {
42+
const kuiRow = kuiBody[offset + ridx]
43+
const updated = justUpdated[kuiRow.rowKey]
44+
45+
return (
46+
<TableRow
47+
key={row.id}
48+
{...renderOpts.getRowProps({
49+
row,
50+
'data-name': kuiBody[offset + ridx].name
51+
})}
52+
>
53+
{row.cells.map(renderCell(kuiRow, updated, tab, repl))}
54+
</TableRow>
55+
)
56+
})}
5057
</TableBody>
5158
)
5259
}

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import { Cell as KuiCell, Row as KuiRow, Tab, REPL } from '@kui-shell/core'
1818

1919
import * as React from 'react'
20-
import { TableCell, DataTableRow, DataTableCell } from 'carbon-components-react'
20+
import { TableCell, DataTableCell } from 'carbon-components-react'
2121

2222
/**
2323
* Generate an onclick handler for a cell
@@ -58,7 +58,7 @@ export function onClickForCell(
5858
* Render a TableCell part
5959
*
6060
*/
61-
export default function renderCell(kuiRow: KuiRow, row: DataTableRow, tab: Tab, repl: REPL) {
61+
export default function renderCell(kuiRow: KuiRow, justUpdated: boolean, tab: Tab, repl: REPL) {
6262
return function KuiTableCell(cell: DataTableCell, cidx: number) {
6363
// e.g. is this a badge/status-like cell?
6464
const tag = cidx > 0 && kuiRow.attributes[cidx - 1].tag
@@ -95,7 +95,13 @@ export default function renderCell(kuiRow: KuiRow, row: DataTableRow, tab: Tab,
9595
className={outerClassName}
9696
>
9797
{tag === 'badge' && (
98-
<span title={innerText} data-tag="badge-circle" className={kuiRow.attributes[cidx - 1].css} />
98+
<span
99+
key={kuiRow.attributes[cidx - 1].css /* force restart of animation if color changes */}
100+
title={innerText}
101+
data-tag="badge-circle"
102+
className={kuiRow.attributes[cidx - 1].css}
103+
data-just-updated={justUpdated || undefined}
104+
/>
99105
)}
100106
<span className="kui--cell-inner-text">{innerText}</span>
101107
</span>

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { DataTableHeader, DataTableRow } from 'carbon-components-react'
2020
export interface NamedDataTableRow extends DataTableRow {
2121
NAME: string
2222
rowKey: string
23+
justUpdated: boolean
2324
}
2425

2526
/** attempt to infer header model from body model */
@@ -56,11 +57,11 @@ export function kuiHeader2carbonHeader(header: KuiRow): DataTableHeader[] {
5657
* DataTable.
5758
*
5859
*/
59-
export function kuiRow2carbonRow(headers: DataTableHeader[]) {
60+
export function kuiRow2carbonRow(headers: DataTableHeader[], justUpdated = false) {
6061
return (row: KuiRow, ridx: number): NamedDataTableRow => {
6162
const isSelected = row.rowCSS ? row.rowCSS.includes('selected-row') : false
6263

63-
const rowData = { id: ridx.toString(), rowKey: row.rowKey, isSelected, NAME: '' }
64+
const rowData = { id: ridx.toString(), rowKey: row.rowKey, isSelected, NAME: '', justUpdated }
6465
rowData[headers[0].key] = row.name
6566

6667
if (!row.key) {

plugins/plugin-client-common/web/css/static/ui.css

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,11 @@ input.repl-partial,
696696
animation: pulse 1000ms 1;
697697
}
698698
body {
699-
--animation-repeating-pulse: pulse 1000ms infinite alternate-reverse;
699+
--animation-short-repeating-pulse: pulse 1000ms 3 alternate-reverse;
700+
--animation-medium-repeating-pulse: pulse 1000ms 6 alternate-reverse;
701+
--animation-long-repeating-pulse: pulse 1000ms 20 alternate-reverse;
702+
--animation-infinite-repeating-pulse: pulse 1000ms infinite alternate-reverse;
703+
--animation-repeating-pulse: var(--animation-infinite-repeating-pulse);
700704
}
701705
.repeating-pulse {
702706
animation: var(--animation-repeating-pulse);

plugins/plugin-client-common/web/scss/components/Table/badges.scss

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,13 @@
103103
}
104104

105105
[data-table-watching='true'] .bx--data-table {
106-
[data-tag='badge-circle'].yellow-background {
107-
animation: var(--animation-repeating-pulse);
106+
[data-tag='badge-circle'][data-just-updated] {
107+
&.yellow-background {
108+
animation: var(--animation-infinite-repeating-pulse);
109+
}
110+
111+
&.red-background {
112+
animation: pulse 1000ms 6 alternate-reverse;
113+
}
108114
}
109115
}

plugins/plugin-kubectl/src/controller/kubectl/watch/get-watch.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,13 +238,16 @@ class KubectlWatcher implements Abortable, Watcher {
238238
// based on the information we got back, 1) we push updates to
239239
// the table model; and 2) we may be able to discern that we
240240
// can stop watching
241+
const apiVersion = rows[0][2].value
242+
const kind = rows[0][1].value
243+
const isEvent = apiVersion === 'v1' && kind === 'Event'
241244
table.body.forEach(row => {
242245
// push an update to the table model
243246
// true means we want to do a batch update
244247
if (row.isDeleted) {
245248
this.pusher.offline(row.name)
246249
} else {
247-
this.pusher.update(row, true)
250+
this.pusher.update(row, true, !isEvent)
248251
}
249252
})
250253

0 commit comments

Comments
 (0)