Repository navigation
Commit 1e94aaf
authored
Detail pages and logs fit at laptop widths; Pending Pods and scheduling causes read plainly (#2074)
Carved out of #1922. This is the shared detail-page UI from that PR:
every resource kind gets it, so it is reviewed here on its own rather
than inside a CloudNativePG change. Merge before #1922, whose
CloudNativePG pages pass the opt-in header props carried here.
## What users see
### Expanded view: tabs on one line at laptop widths
At 1280px the tab strip used to wrap the actions bar onto two rows and
leave Rollback or Delete on a line of their own. Tabs now drop their
icons only while they don't fit, and the strip keeps the active tab in
view. Scope controls wrap instead of pushing tabs out, and the tabs get
a focus ring. The actions bar puts object actions (Set image, Restart,
Rollback) and utility actions (compare, delete) in two groups that wrap
as groups.
Before / after, Deployment at 1280×800:


### Drawer header: unchanged
#1922 puts the drawer's name on the title line beside the header
buttons. That saves a line for short names, but when the labelled
Investigate button shows, the name gets about 300px: a Pod name such as
`su-unschedulable-7d98c9cc76-4rdf7` was cut to
`su-unschedulable-7d98c9cc76…`. So the drawer keeps main's layout here:
kind and status beside the controls, then the name on its own full-width
line. The hooks #1922's pages use there still work: a host's status
badge, and object actions in the actions bar.
### Pending Pods say what is actually going on
- A container that hasn't started reads **Not started** in neutral grey,
instead of red **Not Ready** / **unknown** or amber **Pending**. Only a
reported failure (a non-zero exit, or a waiting reason such as
`ImagePullBackOff` or `CrashLoopBackOff`) is red; `ContainerCreating`
and `PodInitializing` stay neutral.
- When the metrics API answers but no container, init containers
included, has run yet, Resource Usage says **No usage yet: this Pod is
not running** instead of **Metrics unavailable. Radar cannot read
metrics.k8s.io.** The Pod metrics history response gains
`metricsAPIReachable`.
- The drawer's issue row gives the scheduler's reasons in plain words on
their own line, every cause kept, with the raw message in the details.
Before, the row cut the cause off after a few words.
Before / after, unschedulable Pod with an init container (the cluster's
metrics-server is healthy):


### Logs
- At 1280px the toolbar used to squeeze its labels ("1/1 pods" and the
level chips broke inside the label) and push Export and Clear off
screen. Display and utility controls now wrap onto a second row as a
group.
- Export and Clear are disabled while nothing is loaded.
- The capture time and any notice share one status line.
- Long lines break between words before breaking inside one, a
structured line keeps `{N fields}` whole, and a CloudNativePG PostgreSQL
record shows the database's message.
- `WorkloadLogsViewer` gains `initialContainer`, plus opt-ins
`emptySourceState` and `disableSourceControlsWithoutSource`.


### Issue titles
Issue rows on Home and the Issues page take the reason's title when the
category would name the wrong operation. Today that is CloudNativePG WAL
archiving and last-backup issues, which main titles "Backup failed".
### Namespace switch
No visible change on a view-filter switch: both builds send the same six
requests after picking a namespace. What changes:
- the switch waits 15s instead of 5s;
- after a client timeout, a view-filter switch reads the server's scope
and reports success if the pick was applied;
- a cache-scoped switch (`--namespace-scope`) refreshes every query
except the scope it just wrote, without cancelling refetches in flight.
### Timeline
A Pod row is tagged by the state the change produced: unhealthy when a
container just exited with an error, degraded from the moment the Pod
lost readiness until it returns. Before, it waited out the
standing-state grace periods. A clean container exit still reads as
completion, and a Pod still starting up keeps its grace.
### Smaller fixes
- **Sidebar:** a filter keeps a category's matching workspace views (all
of them when the term names the category or an API group). Arrow keys
and Enter reach them. The heading reads **Views** instead of
**Workspace**. Today only the CloudNativePG workspace has views.
- **Row menus:** Escape closes the menu without also closing the drawer.
- **YAML:** the Edit button uses the accent token instead of
`text-blue-*`.
- **Logging:** a namespace name is no longer used as a console format
string.
## Radar Hub and library consumers
All changes to `@skyhook-io/k8s-ui` and `@skyhook-io/radar-app` are
additive:
- `WorkloadView` gains the opt-in host props `titlePrefix`,
`inlineBadges`, `namespaceNote`, `renderStatusBadge`, `statusNote`,
`hideKindBadge`, `subheader`, `tabOrder`, `specTab` and
`renderHeaderActions`. `WorkloadExtraTab` gains `badge`.
- `DetailShell` gains `subheader` and `wrapHeader`; `ResourceActionsBar`
gains `leadingActions`.
- `IssueRow` and `ResourceIssuesSection` gain `compact`.
`LogCore.emptyMessage` widens from `string` to `ReactNode`.
`MetricsUnavailableNotice` gains `noUsageYet`.
- New package exports: `issueTitle`, `issueReasonTitle`, `tokenizeJson`.
`summarizeSchedulerMessage` gains an optional `{ plain }` argument.
**Version skew.** Hub runs the newest UI against older Radars:
- `metricsAPIReachable` is absent there, so a Pending Pod keeps the old
metrics notice.
- An issue without a decomposed `cause` falls back to the raw scheduler
message. The plain-words summary handles that too (see the deviations).
The expanded header and tab strip change for Hub users exactly as they
do in Radar.
`radar-app` now imports `issueTitle` from `k8s-ui`. This ships in
`k8s-ui` 1.17.0, which the peer floor (`>=1.17.0`) already requires.
## Deviations from #1922
Code is copied verbatim from #1922 at `01f2a97ab` except:
- **The drawer header keeps main's layout** (owner decision; see
[above](#drawer-header-unchanged)). The renderStatusBadge hook,
`leadingActions` and the non-shrinking utility buttons stay, and the
drawer case in `WorkloadView.spec.test.tsx` now checks that the name has
its own line.
- `ResourcesSidebar.tsx` leaves out `countLowerBound` and its test. It
needs `facts/certaintyGlyph`, which stays in #1922.
- `status-tone.tsx` carries only `toneTextClass`, which the logs status
line uses. `toneFillClass`, `worseTone` and their exports stay in #1922.
- `server.go` carries only the `metricsAPIReachable` hunk. The CNPG
routes and the move to `internal/integration` stay.
`server_smoke_test.go` carries `TestPodMetricsHistoryAPIReachability`.
- `client.ts` carries `podMetricsQuery`, `metricsAPIReachable` and the
namespace-switch hunks. `useIssues(enabled)`, `useSubjectIssues`, the
memoized `useRadarFeature`, the new PVC usage statuses and
`ApplyResourceResult.uid` stay; they belong to the other carve-outs or
to CNPG.
- The work order's inventory didn't list three files, but they are what
makes the plain scheduling cause reach users, so this PR carries them:
`IssuesView.tsx` and `ResourceIssuesSection.tsx` (with its test), and
the one-line `compact={!expanded}` in web `WorkloadView.tsx`.
- `summarizeSchedulerMessage(…, { plain: true })` also handles the
scheduler phrasing in current Kubernetes. On EKS 1.34 the message reads
`6 node(s) had untolerated taint(s), 8 node(s) didn't match Pod's node
affinity/selector. no new claims to deallocate, preemption: …`, and
#1922's version returned `6 node(s) had untolerated taint(s); 8 node(s)
didn't match Pod's node affinity/selector. no new claims to deallocate;
` (raw clauses and a trailing `; `). It now returns `6 nodes have taints
the Pod does not tolerate; 8 nodes do not match the Pod’s node affinity
or selector`. The test uses that message. The phrase is removed with a
plain match: CodeQL flagged the first version's `\s*` as polynomial on
long runs of spaces.
- Messages are split into clauses in one pass. #1922's lookahead
(`/[,;](?![^\[\]{}]*[\]}])/`) rescanned the rest of the message at every
comma, so a 240 KB custom-scheduler message took about 7 s and blocked
the drawer. The one-pass split keeps the same rule: no split where the
next bracket ahead closes. A test covers a 10,000-clause message.
- "No usage yet" also checks init containers. #1922 looked only at
regular containers, so a Pending Pod running its init container read
"this Pod is not running". Test added in `PodRenderer.test.tsx`.
- Timeline readiness stays degraded until it returns. In #1922 only the
row where readiness dropped was degraded. A later change while the Pod
was still unready (for example, attaching a debug container) fell back
to the 5-minute standing-state grace and read healthy, which ended the
incident early. Readiness now counts as lost when the Ready condition
went false after a running container had started; at startup it goes
false first, so the startup grace stays. One case in #1922's test
described a Pod that had run for an hour and just lost readiness while
calling it startup; it now uses a Pod that is actually starting. New
cases cover a later unready change and a Pod first seen after losing
readiness. A clean exit (code 0) also no longer counts as completion
when the Pod restarts its containers (`restartPolicy: Always`), and a
restarted container's previous run counts as proof that readiness was
lost. Before, a liveness restart that exited cleanly turned the row
green while the Pod was still unready.
- `WorkloadView` asks a host's `renderStatusBadge` for a badge only once
the resource has loaded. In #1922 it was called with `undefined` during
loading: a callback that reads fields throws, and the CloudNativePG
Cluster badge read "Phase Not reported" until the object arrived. Test:
`waits for the resource before asking a host for its status badge`.
- The timeout reconcile applies only to view-filter switches. A
`--namespace-scope` rescope publishes its target before the cache
rebuild finishes (`reinitializeNamespaceScope` sets the override before
`InitAllSubsystems`) and can still roll back, so a matching scope
doesn't prove it succeeded. Test:
`client.namespaceSwitch.hook.test.tsx`.
## Left in #1922
The drawer title-line layout stays there until it adapts to long names.
The rest is opt-in only or CloudNativePG-specific:
- `AreaChart` (`shadedRanges`), `CreateResourceDialog` (`onBack`,
`initialMode`, `lockMode`), `DockContext` / `TerminalTab` (`shell`,
`sessionNote`), `AlertBanner.action`, `.btn-secondary`;
- the DatabaseRole renderer dispatch, `ResourcesView.renderKindView` and
the web wiring to `web/src/integrations`;
- the `facts`, `problems`, `FoldSection`, `RefLink`, `grant` and
`ActionConfirmDialog` components;
- the `stripTrailingSlashes` refactor and DESIGN.md's facts section.
## Testing
- `go build ./... && go test ./...`, `make tsc`, k8s-ui `tsc` + vitest
(245 files, 4,486 tests), web vitest (167 files, 1,998 tests), and `npm
run lint` all pass. Lint reports 0 errors and the same 489 warnings as
main.
- **Before/after on a live EKS 1.34 cluster.** Main and this branch ran
side by side against the same cluster at 1280×800 and 1920×1080, in
light and dark. Captures:
- a Deployment, drawer and expanded;
- an unschedulable Pod (a fixture with an init container) and a running
Pod;
- a Service;
- an uncurated CRD (`ClickHouseInstallation`);
- workload and single-Pod logs, including a workload with no running
Pod;
- the namespace switch.
All captures showed the "What users see" changes above. Export and Clear
were disabled on the empty logs view, and the namespace switch sent
identical requests on both builds.
- Not exercised live:
- the sidebar views filter, whose only views are on the CloudNativePG
workspace page (the keyboard tests cover it);
- the timeline health tags (Go tests);
- the reconcile after a client timeout
(`client.namespaceSwitch.test.ts`).
## After this merges
#1922 merges main and takes main's version of every file here, including
main's drawer header in `WorkloadView.tsx` (owner decision): it does not
re-apply its title-line drawer layout. Its own changes to
`ResourcesSidebar.tsx` (`countLowerBound`), `status-tone.tsx`,
`server.go`, `client.ts` and web `WorkloadView.tsx` go back on top. It
also picks up the scheduler-summary fix above.1 parent 6713f57 commit 1e94aaf
46 files changed
Lines changed: 1714 additions & 266 deletions
File tree
- internal
- k8s
- server
- packages/k8s-ui/src
- components
- issues
- logs
- resources
- renderers
- ui
- workload
- utils
- web/src
- api
- components
- home
- workload
- contexts
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
916 | 916 | | |
917 | 917 | | |
918 | 918 | | |
919 | | - | |
| 919 | + | |
920 | 920 | | |
921 | 921 | | |
922 | 922 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
49 | 49 | | |
50 | 50 | | |
51 | 51 | | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
149 | 149 | | |
150 | 150 | | |
151 | 151 | | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3488 | 3488 | | |
3489 | 3489 | | |
3490 | 3490 | | |
3491 | | - | |
| 3491 | + | |
| 3492 | + | |
| 3493 | + | |
| 3494 | + | |
| 3495 | + | |
| 3496 | + | |
3492 | 3497 | | |
3493 | 3498 | | |
3494 | 3499 | | |
| |||
3499 | 3504 | | |
3500 | 3505 | | |
3501 | 3506 | | |
3502 | | - | |
| 3507 | + | |
| 3508 | + | |
| 3509 | + | |
| 3510 | + | |
3503 | 3511 | | |
3504 | 3512 | | |
3505 | 3513 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2055 | 2055 | | |
2056 | 2056 | | |
2057 | 2057 | | |
| 2058 | + | |
| 2059 | + | |
| 2060 | + | |
| 2061 | + | |
| 2062 | + | |
| 2063 | + | |
| 2064 | + | |
| 2065 | + | |
| 2066 | + | |
| 2067 | + | |
| 2068 | + | |
| 2069 | + | |
| 2070 | + | |
| 2071 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
1 | 2 | | |
2 | 3 | | |
3 | 4 | | |
| |||
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
16 | | - | |
| 17 | + | |
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
| |||
168 | 169 | | |
169 | 170 | | |
170 | 171 | | |
| 172 | + | |
171 | 173 | | |
172 | 174 | | |
173 | 175 | | |
| |||
195 | 197 | | |
196 | 198 | | |
197 | 199 | | |
| 200 | + | |
198 | 201 | | |
199 | 202 | | |
200 | 203 | | |
| |||
208 | 211 | | |
209 | 212 | | |
210 | 213 | | |
| 214 | + | |
211 | 215 | | |
212 | 216 | | |
213 | 217 | | |
| |||
289 | 293 | | |
290 | 294 | | |
291 | 295 | | |
292 | | - | |
| 296 | + | |
293 | 297 | | |
294 | 298 | | |
295 | 299 | | |
296 | 300 | | |
297 | 301 | | |
298 | 302 | | |
299 | 303 | | |
300 | | - | |
| 304 | + | |
301 | 305 | | |
302 | 306 | | |
303 | 307 | | |
| |||
307 | 311 | | |
308 | 312 | | |
309 | 313 | | |
| 314 | + | |
310 | 315 | | |
311 | 316 | | |
312 | 317 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
106 | 106 | | |
107 | 107 | | |
108 | 108 | | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| 11 | + | |
11 | 12 | | |
| 13 | + | |
12 | 14 | | |
13 | 15 | | |
14 | 16 | | |
| |||
36 | 38 | | |
37 | 39 | | |
38 | 40 | | |
| 41 | + | |
39 | 42 | | |
40 | 43 | | |
41 | 44 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
| 27 | + | |
| 28 | + | |
27 | 29 | | |
28 | 30 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | | - | |
| 5 | + | |
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| |||
83 | 83 | | |
84 | 84 | | |
85 | 85 | | |
| 86 | + | |
| 87 | + | |
86 | 88 | | |
87 | 89 | | |
88 | 90 | | |
| |||
0 commit comments