@skyhook-io/k8s-ui 1.14.2 → 1.14.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skyhook-io/k8s-ui",
3
- "version": "1.14.2",
3
+ "version": "1.14.3",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/skyhook-io/radar",
@@ -716,7 +716,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
716
716
  { key: 'namespace', label: 'Namespace', width: 'w-48' },
717
717
  { key: 'status', label: 'Phase', width: 'w-28' },
718
718
  { key: 'duration', label: 'Duration', width: 'w-24' },
719
- { key: 'progress', label: 'Progress', width: 'w-24', tooltip: 'Succeeded steps / Total steps' },
719
+ { key: 'progress', label: 'Progress', width: 'w-24', tooltip: 'Completed tasks / currently known total; the total can grow during execution, and completion does not imply success' },
720
720
  { key: 'template', label: 'Template', width: 'w-40' },
721
721
  { key: 'age', label: 'Age', width: 'w-24' },
722
722
  ],
@@ -835,13 +835,13 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
835
835
  { key: 'name', label: 'Name' },
836
836
  { key: 'status', label: 'Status', width: 'w-24' },
837
837
  { key: 'nodeClass', label: 'Node Class', width: 'w-36' },
838
- { key: 'limits', label: 'Limits', width: 'w-36', tooltip: 'CPU and memory limits' },
839
- { key: 'disruption', label: 'Disruption', width: 'w-40' },
838
+ { key: 'limits', label: 'Limits', width: 'w-36', tooltip: 'Configured provisioning ceilings — not what the pool has provisioned. Concurrent provisioning can exceed them during rapid scale-out, and a limit does not remove nodes already running.' },
839
+ { key: 'disruption', label: 'Disruption', width: 'w-40', tooltip: 'Which nodes Karpenter may consolidate; budgets and timing controls can still prevent removal or replacement' },
840
840
  { key: 'age', label: 'Age', width: 'w-24' },
841
841
  ],
842
842
  nodeclaims: [
843
843
  { key: 'name', label: 'Name' },
844
- { key: 'status', label: 'Status', width: 'w-24' },
844
+ { key: 'status', label: 'Status', width: 'w-24', tooltip: 'Launched means a cloud instance exists; Registered means it has joined Kubernetes; Ready means the node is fully initialized' },
845
845
  { key: 'instanceType', label: 'Instance Type', width: 'w-32' },
846
846
  { key: 'capacityType', label: 'Capacity', width: 'w-24', tooltip: 'Spot or On-Demand' },
847
847
  { key: 'zone', label: 'Zone', width: 'w-28' },
@@ -899,23 +899,23 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
899
899
  nvidiaclusterpolicies: [
900
900
  { key: 'name', label: 'Name' },
901
901
  { key: 'status', label: 'Status', width: 'w-28' },
902
- { key: 'components', label: 'Components', width: 'w-64', tooltip: 'Enabled GPU Operator components' },
903
- { key: 'mig', label: 'MIG', width: 'w-24' },
902
+ { key: 'components', label: 'Components', width: 'w-64', tooltip: 'Enabled GPU Operator components" with "GPU Operator components enabled in spec — not whether they are running' },
903
+ { key: 'mig', label: 'MIG', width: 'w-24', tooltip: 'Multi-Instance GPU exposure: single advertises uniform partitions as nvidia.com/gpu; mixed advertises separate partition profiles; none disables MIG-aware exposure' },
904
904
  { key: 'age', label: 'Age', width: 'w-24' },
905
905
  ],
906
906
  nvidiadrivers: [
907
907
  { key: 'name', label: 'Name' },
908
908
  { key: 'status', label: 'Status', width: 'w-28' },
909
- { key: 'driverType', label: 'Type', width: 'w-28' },
910
- { key: 'version', label: 'Version', width: 'w-32' },
909
+ { key: 'driverType', label: 'Type', width: 'w-28', tooltip: 'Driver role: gpu for standard GPU workloads, vgpu for virtual GPU guests, or vgpu-host-manager for virtualization hosts' },
910
+ { key: 'version', label: 'Version', width: 'w-32', tooltip: 'Driver version requested in spec — nodes may still be running the previous one' },
911
911
  { key: 'age', label: 'Age', width: 'w-24' },
912
912
  ],
913
913
  clusterqueues: [
914
914
  { key: 'name', label: 'Name' },
915
915
  { key: 'status', label: 'Status', width: 'w-24' },
916
- { key: 'cohort', label: 'Cohort', width: 'w-32' },
917
- { key: 'pendingWorkloads', label: 'Pending', width: 'w-24', tooltip: 'Pending workloads' },
918
- { key: 'admittedWorkloads', label: 'Admitted', width: 'w-24', tooltip: 'Admitted workloads' },
916
+ { key: 'cohort', label: 'Cohort', width: 'w-32', tooltip: 'Queues in this cohort can share unused quota, subject to borrowing and lending limits' },
917
+ { key: 'pendingWorkloads', label: 'Pending', width: 'w-24', tooltip: 'Workloads in this ClusterQueue waiting for admission, across namespaces; inspect workload status for the blocker' },
918
+ { key: 'admittedWorkloads', label: 'Admitted', width: 'w-24', tooltip: 'Unfinished workloads admitted through this ClusterQueue, across namespaces; admission does not mean their pods are running' },
919
919
  { key: 'flavors', label: 'Flavors', width: 'w-40' },
920
920
  { key: 'age', label: 'Age', width: 'w-24' },
921
921
  ],
@@ -924,8 +924,8 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
924
924
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
925
925
  { key: 'status', label: 'Status', width: 'w-24' },
926
926
  { key: 'clusterQueue', label: 'Cluster Queue', width: 'w-40' },
927
- { key: 'pendingWorkloads', label: 'Pending', width: 'w-24' },
928
- { key: 'admittedWorkloads', label: 'Admitted', width: 'w-24' },
927
+ { key: 'pendingWorkloads', label: 'Pending', width: 'w-24', tooltip: 'Workloads submitted to this LocalQueue that are waiting for ClusterQueue admission' },
928
+ { key: 'admittedWorkloads', label: 'Admitted', width: 'w-24', tooltip: 'Unfinished workloads from this LocalQueue admitted to its ClusterQueue; their pods may still be waiting to run' },
929
929
  { key: 'age', label: 'Age', width: 'w-24' },
930
930
  ],
931
931
  workloads: [
@@ -946,14 +946,14 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
946
946
  admissionchecks: [
947
947
  { key: 'name', label: 'Name' },
948
948
  { key: 'status', label: 'Status', width: 'w-24' },
949
- { key: 'controllerName', label: 'Controller', width: 'w-64' },
949
+ { key: 'controllerName', label: 'Controller', width: 'w-64', tooltip: 'Controller responsible for this check; workloads requiring it cannot be admitted until the check passes' },
950
950
  { key: 'age', label: 'Age', width: 'w-24' },
951
951
  ],
952
952
  provisioningrequests: [
953
953
  { key: 'name', label: 'Name' },
954
954
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
955
955
  { key: 'status', label: 'Status', width: 'w-28' },
956
- { key: 'provisioningClassName', label: 'Class', width: 'w-56' },
956
+ { key: 'provisioningClassName', label: 'Class', width: 'w-56', tooltip: 'Provisioning mode: check-capacity checks existing capacity without reserving it; best-effort-atomic-scale-up creates capacity atomically' },
957
957
  { key: 'podSets', label: 'Pod Sets', width: 'w-24' },
958
958
  { key: 'age', label: 'Age', width: 'w-24' },
959
959
  ],
@@ -979,7 +979,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
979
979
  { key: 'name', label: 'Name' },
980
980
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
981
981
  { key: 'status', label: 'Status', width: 'w-28' },
982
- { key: 'serviceStatus', label: 'Service Status', width: 'w-28' },
982
+ { key: 'serviceStatus', label: 'Service Status', width: 'w-28', tooltip: "KubeRay's serving-readiness flag; this does not describe the active rollout phase." },
983
983
  { key: 'clusters', label: 'Clusters', width: 'w-56', tooltip: 'Active and pending RayCluster names' },
984
984
  { key: 'age', label: 'Age', width: 'w-24' },
985
985
  ],
@@ -989,7 +989,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
989
989
  { key: 'status', label: 'Status', width: 'w-24' },
990
990
  { key: 'schedule', label: 'Schedule', width: 'w-32' },
991
991
  { key: 'timeZone', label: 'Time Zone', width: 'w-36', tooltip: 'IANA zone the schedule is read in; unset follows the local zone of the KubeRay operator pod' },
992
- { key: 'lastSchedule', label: 'Last Schedule', width: 'w-28' },
992
+ { key: 'lastSchedule', label: 'Last Schedule', width: 'w-28', tooltip: 'Time since the last recorded schedule; this does not confirm the job started or succeeded.' },
993
993
  { key: 'age', label: 'Age', width: 'w-24' },
994
994
  ],
995
995
  leaderworkersets: [
@@ -1010,7 +1010,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1010
1010
  { key: 'ready', label: 'Ready', width: 'w-20' },
1011
1011
  { key: 'succeeded', label: 'Succeeded', width: 'w-24' },
1012
1012
  { key: 'failed', label: 'Failed', width: 'w-20' },
1013
- { key: 'restarts', label: 'Restarts', width: 'w-24' },
1013
+ { key: 'restarts', label: 'Restarts', width: 'w-24', tooltip: 'Whole-JobSet restarts by the failure policy — every child Job is recreated' },
1014
1014
  { key: 'age', label: 'Age', width: 'w-24' },
1015
1015
  ],
1016
1016
  inferenceservices: [
@@ -1065,7 +1065,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1065
1065
  inferencepools: [
1066
1066
  { key: 'name', label: 'Name' },
1067
1067
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1068
- { key: 'status', label: 'Status', width: 'w-36', tooltip: 'Gateway acceptance and EPP resolution' },
1068
+ { key: 'status', label: 'Status', width: 'w-36', tooltip: 'Gateway acceptance and reference errors across reported parents; Accepted does not prove backend Pods are ready.' },
1069
1069
  { key: 'selector', label: 'Selector', width: 'w-48' },
1070
1070
  { key: 'targetPorts', label: 'Target Ports', width: 'w-28' },
1071
1071
  { key: 'extensionRef', label: 'Endpoint Picker', width: 'w-40', tooltip: 'EPP extension service' },
@@ -1076,7 +1076,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1076
1076
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1077
1077
  { key: 'status', label: 'Status', width: 'w-24' },
1078
1078
  { key: 'poolRef', label: 'Pool', width: 'w-40', tooltip: 'Target InferencePool' },
1079
- { key: 'priority', label: 'Priority', width: 'w-24' },
1079
+ { key: 'priority', label: 'Priority', width: 'w-24', tooltip: 'Higher values are served first when pool resources are scarce; an unset priority is treated as 0.' },
1080
1080
  { key: 'age', label: 'Age', width: 'w-24' },
1081
1081
  ],
1082
1082
  volcanojobs: [
@@ -1084,7 +1084,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1084
1084
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1085
1085
  { key: 'status', label: 'Status', width: 'w-28' },
1086
1086
  { key: 'queue', label: 'Queue', width: 'w-32' },
1087
- { key: 'minAvailable', label: 'Min Available', width: 'w-28' },
1087
+ { key: 'minAvailable', label: 'Min Available', width: 'w-28', tooltip: 'Minimum pods that must be schedulable together for gang scheduling to start the job' },
1088
1088
  { key: 'pods', label: 'Pods', width: 'w-44', tooltip: 'Running / succeeded / failed pod counts' },
1089
1089
  { key: 'age', label: 'Age', width: 'w-24' },
1090
1090
  ],
@@ -1092,8 +1092,8 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1092
1092
  { key: 'name', label: 'Name' },
1093
1093
  { key: 'status', label: 'Status', width: 'w-24' },
1094
1094
  { key: 'weight', label: 'Weight', width: 'w-20' },
1095
- { key: 'capability', label: 'Capability', width: 'w-48' },
1096
- { key: 'allocated', label: 'Allocated', width: 'w-48' },
1095
+ { key: 'capability', label: 'Capability', width: 'w-48', tooltip: 'Configured resource limits for this queue; actual allocation also depends on available resources and scheduler policy' },
1096
+ { key: 'allocated', label: 'Allocated', width: 'w-48', tooltip: 'Resources the scheduler reports as allocated to this queue; these are allocations, not measured CPU or memory use' },
1097
1097
  { key: 'podGroups', label: 'PodGroups', width: 'w-44', tooltip: 'PodGroup counts by state' },
1098
1098
  { key: 'age', label: 'Age', width: 'w-24' },
1099
1099
  ],
@@ -1109,7 +1109,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1109
1109
  { key: 'name', label: 'Name' },
1110
1110
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1111
1111
  { key: 'status', label: 'Status', width: 'w-28' },
1112
- { key: 'flows', label: 'Flows', width: 'w-20' },
1112
+ { key: 'flows', label: 'Flows', width: 'w-20', tooltip: 'Declared job stages; dependencies control when each stage can start' },
1113
1113
  { key: 'age', label: 'Age', width: 'w-24' },
1114
1114
  ],
1115
1115
  jobtemplates: [
@@ -1121,10 +1121,10 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1121
1121
  kaiqueues: [
1122
1122
  { key: 'name', label: 'Name' },
1123
1123
  { key: 'status', label: 'Status', width: 'w-24' },
1124
- { key: 'parentQueue', label: 'Parent', width: 'w-32' },
1125
- { key: 'priority', label: 'Priority', width: 'w-20' },
1126
- { key: 'quota', label: 'Quota', width: 'w-52', tooltip: 'GPU fractions, CPU millicpus, memory MB; -1 = unlimited' },
1127
- { key: 'allocated', label: 'Allocated', width: 'w-48' },
1124
+ { key: 'parentQueue', label: 'Parent', width: 'w-32', tooltip: 'Parent queue whose resources are shared among its children; ancestor limits constrain allocations' },
1125
+ { key: 'priority', label: 'Priority', width: 'w-20', tooltip: "Higher priority favors allocation of resources above quota and delays reclaim; it does not increase the queue's guaranteed quota" },
1126
+ { key: 'quota', label: 'Quota', width: 'w-52', tooltip: 'Guaranteed resource allocation; the queue may exceed it when spare resources and configured limits allow' },
1127
+ { key: 'allocated', label: 'Allocated', width: 'w-48', tooltip: 'Resources allocated to this queue and its descendants, including scheduled pods still starting; this is not measured utilization' },
1128
1128
  { key: 'age', label: 'Age', width: 'w-24' },
1129
1129
  ],
1130
1130
  kaipodgroups: [
@@ -1139,9 +1139,9 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1139
1139
  { key: 'name', label: 'Name' },
1140
1140
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1141
1141
  { key: 'status', label: 'Status', width: 'w-28' },
1142
- { key: 'instanceType', label: 'Instance Type', width: 'w-40', tooltip: 'GPU node SKU provisioned for the workspace' },
1142
+ { key: 'instanceType', label: 'Instance Type', width: 'w-40', tooltip: 'Requested node instance type; actual node hardware is not checked.' },
1143
1143
  { key: 'preset', label: 'Model', width: 'w-44', tooltip: 'Preset model (inference or tuning)' },
1144
- { key: 'nodes', label: 'Nodes', width: 'w-20', tooltip: 'Worker nodes ready / target' },
1144
+ { key: 'nodes', label: 'Nodes', width: 'w-20', tooltip: 'Worker nodes listed by KAITO, with the target count when available; listing does not confirm readiness.' },
1145
1145
  { key: 'age', label: 'Age', width: 'w-24' },
1146
1146
  ],
1147
1147
  ragengines: [
@@ -1149,7 +1149,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1149
1149
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1150
1150
  { key: 'status', label: 'Status', width: 'w-28' },
1151
1151
  { key: 'embedding', label: 'Embedding Model', width: 'w-56', tooltip: 'Local model ID/image or remote endpoint' },
1152
- { key: 'instanceType', label: 'Instance Type', width: 'w-40' },
1152
+ { key: 'instanceType', label: 'Instance Type', width: 'w-40', tooltip: 'Requested node instance type; actual node hardware is not checked.' },
1153
1153
  { key: 'age', label: 'Age', width: 'w-24' },
1154
1154
  ],
1155
1155
  nimservices: [
@@ -1212,7 +1212,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1212
1212
  { key: 'name', label: 'Name' },
1213
1213
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1214
1214
  { key: 'status', label: 'Status', width: 'w-28' },
1215
- { key: 'runtime', label: 'Runtime', width: 'w-44', tooltip: 'Training runtime reference' },
1215
+ { key: 'runtime', label: 'Runtime', width: 'w-44', tooltip: 'Runtime template supplying training defaults; TrainJob settings can override its image and node count.' },
1216
1216
  { key: 'suspended', label: 'Suspended', width: 'w-24' },
1217
1217
  { key: 'age', label: 'Age', width: 'w-24' },
1218
1218
  ],
@@ -1271,18 +1271,18 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1271
1271
  policyreports: [
1272
1272
  { key: 'name', label: 'Name' },
1273
1273
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1274
- { key: 'scope', label: 'Subject', width: 'w-56' },
1274
+ { key: 'scope', label: 'Subject', width: 'w-56', tooltip: "The resource this report is about. Kyverno names the report after the resource's UID; use Subject to identify it." },
1275
1275
  { key: 'status', label: 'Status', width: 'w-32' },
1276
1276
  { key: 'pass', label: 'Pass', width: 'w-16' },
1277
1277
  { key: 'fail', label: 'Fail', width: 'w-16' },
1278
1278
  { key: 'warn', label: 'Warn', width: 'w-20' },
1279
- { key: 'error', label: 'Err', width: 'w-16' },
1279
+ { key: 'error', label: 'Err', width: 'w-16', tooltip: 'Checks that could not be evaluated, for example because of missing context or a broken expression. Errors are not violations, but zero failures does not establish compliance while checks remain unevaluated.' },
1280
1280
  { key: 'skip', label: 'Skip', width: 'w-16' },
1281
1281
  { key: 'age', label: 'Age', width: 'w-24' },
1282
1282
  ],
1283
1283
  clusterpolicyreports: [
1284
1284
  { key: 'name', label: 'Name' },
1285
- { key: 'scope', label: 'Subject', width: 'w-56' },
1285
+ { key: 'scope', label: 'Subject', width: 'w-56', tooltip: "The resource this report is about. Kyverno names the report after the resource's UID; use Subject to identify it." },
1286
1286
  { key: 'status', label: 'Status', width: 'w-32' },
1287
1287
  { key: 'pass', label: 'Pass', width: 'w-16' },
1288
1288
  { key: 'fail', label: 'Fail', width: 'w-16' },
@@ -1296,14 +1296,16 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1296
1296
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1297
1297
  { key: 'status', label: 'Status', width: 'w-24' },
1298
1298
  { key: 'action', label: 'Action', width: 'w-36', tooltip: 'Enforcement at admission — Enforce blocks, Audit reports; Background only or Inactive when admission is disabled' },
1299
- { key: 'rules', label: 'Rules', width: 'w-20' },
1299
+ { key: 'ruleTypes', label: 'Types', width: 'w-40', tooltip: 'Rule kinds this policy declares. A policy can carry several, and the mix decides what it can do to a request.' },
1300
+ { key: 'rules', label: 'Rules', width: 'w-20', defaultVisible: false },
1300
1301
  { key: 'age', label: 'Age', width: 'w-24' },
1301
1302
  ],
1302
1303
  clusterpolicies: [
1303
1304
  { key: 'name', label: 'Name' },
1304
1305
  { key: 'status', label: 'Status', width: 'w-24' },
1305
1306
  { key: 'action', label: 'Action', width: 'w-36', tooltip: 'Enforcement at admission — Enforce blocks, Audit reports; Background only or Inactive when admission is disabled' },
1306
- { key: 'rules', label: 'Rules', width: 'w-20' },
1307
+ { key: 'ruleTypes', label: 'Types', width: 'w-40', tooltip: 'Rule kinds this policy declares. A policy can carry several, and the mix decides what it can do to a request.' },
1308
+ { key: 'rules', label: 'Rules', width: 'w-20', defaultVisible: false },
1307
1309
  { key: 'age', label: 'Age', width: 'w-24' },
1308
1310
  ],
1309
1311
  // Kyverno modern CEL family (policies.kyverno.io). "Enforcement" is the
@@ -1384,7 +1386,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1384
1386
  // getModernKyvernoPolicyStatus), so a second one would be redundant.
1385
1387
  deletingpolicies: [
1386
1388
  { key: 'name', label: 'Name' },
1387
- { key: 'lastRun', label: 'Last Run', width: 'w-28', tooltip: 'When the schedule last fired. A scheduled policy that has never run is the failure worth catching — Kyverno rejects uncompilable policies at admission, so a broken one never exists to flag.' },
1389
+ { key: 'lastRun', label: 'Last Run', width: 'w-28', tooltip: 'Last execution time reported by Kyverno. A timestamp does not prove every matching resource was deleted.' },
1388
1390
  { key: 'schedule', label: 'Schedule', width: 'w-32', tooltip: 'Cron schedule on which matched resources are deleted' },
1389
1391
  { key: 'appliesTo', label: 'Deletes', width: 'min-w-40' },
1390
1392
  { key: 'rules', label: 'Conditions', width: 'w-28', tooltip: 'CEL conditions narrowing what is deleted; none means every matched resource' },
@@ -1393,7 +1395,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1393
1395
  namespaceddeletingpolicies: [
1394
1396
  { key: 'name', label: 'Name' },
1395
1397
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1396
- { key: 'lastRun', label: 'Last Run', width: 'w-28', tooltip: 'When the schedule last fired. A scheduled policy that has never run is the failure worth catching — Kyverno rejects uncompilable policies at admission, so a broken one never exists to flag.' },
1398
+ { key: 'lastRun', label: 'Last Run', width: 'w-28', tooltip: 'Last execution time reported by Kyverno. A timestamp does not prove every matching resource was deleted.' },
1397
1399
  { key: 'schedule', label: 'Schedule', width: 'w-32' },
1398
1400
  { key: 'appliesTo', label: 'Deletes', width: 'min-w-40' },
1399
1401
  { key: 'rules', label: 'Conditions', width: 'w-28' },
@@ -1410,12 +1412,14 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1410
1412
  { key: 'name', label: 'Name' },
1411
1413
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1412
1414
  { key: 'schedule', label: 'Schedule', width: 'w-32' },
1415
+ { key: 'lastRun', label: 'Last Run', width: 'w-28', tooltip: 'Time since the controller last recorded an execution. A dash means it has not recorded one.' },
1413
1416
  { key: 'appliesTo', label: 'Deletes', width: 'min-w-40' },
1414
1417
  { key: 'age', label: 'Age', width: 'w-24' },
1415
1418
  ],
1416
1419
  clustercleanuppolicies: [
1417
1420
  { key: 'name', label: 'Name' },
1418
1421
  { key: 'schedule', label: 'Schedule', width: 'w-32' },
1422
+ { key: 'lastRun', label: 'Last Run', width: 'w-28', tooltip: 'Time since the controller last recorded an execution. A dash means it has not recorded one.' },
1419
1423
  { key: 'appliesTo', label: 'Deletes', width: 'min-w-40' },
1420
1424
  { key: 'age', label: 'Age', width: 'w-24' },
1421
1425
  ],
@@ -1459,7 +1463,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1459
1463
  workflowtemplates: [
1460
1464
  { key: 'name', label: 'Name' },
1461
1465
  { key: 'namespace', label: 'Namespace', width: 'w-48' },
1462
- { key: 'entrypoint', label: 'Entrypoint', width: 'w-36' },
1466
+ { key: 'entrypoint', label: 'Entrypoint', width: 'w-36', tooltip: 'Default template invoked when submitted as a workflow; submission may override it' },
1463
1467
  { key: 'templates', label: 'Templates', width: 'w-24' },
1464
1468
  { key: 'age', label: 'Age', width: 'w-24' },
1465
1469
  ],
@@ -1481,21 +1485,21 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1481
1485
  { key: 'name', label: 'Name' },
1482
1486
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1483
1487
  { key: 'selector', label: 'Selector', width: 'w-48' },
1484
- { key: 'serviceAccountSelector', label: 'Service Account Selector', width: 'w-48', defaultVisible: false },
1485
- { key: 'tier', label: 'Tier', width: 'w-28' },
1486
- { key: 'order', label: 'Order', width: 'w-24' },
1487
- { key: 'types', label: 'Types', width: 'w-28' },
1488
+ { key: 'serviceAccountSelector', label: 'Service Account Selector', width: 'w-48', defaultVisible: false, tooltip: 'Endpoints must match both this service-account selector and the endpoint Selector; matching either one alone is insufficient.' },
1489
+ { key: 'tier', label: 'Tier', width: 'w-28', tooltip: 'Tier precedence applies before policy Order. An earlier tier can allow or deny traffic before this policy is reached.' },
1490
+ { key: 'order', label: 'Order', width: 'w-24', tooltip: 'Evaluation order within the tier — lowest runs first. Unset runs after every ordered policy.' },
1491
+ { key: 'types', label: 'Types', width: 'w-28', tooltip: "Traffic directions this policy governs. If no applicable policy in the tier takes action, the tier's default action applies (Deny unless configured as Pass)." },
1488
1492
  { key: 'rules', label: 'Rules', width: 'w-24', tooltip: 'Ingress / Egress rule count' },
1489
1493
  { key: 'age', label: 'Age', width: 'w-24' },
1490
1494
  ],
1491
1495
  calicoglobalnetworkpolicies: [
1492
1496
  { key: 'name', label: 'Name' },
1493
1497
  { key: 'selector', label: 'Selector', width: 'w-48' },
1494
- { key: 'namespaceSelector', label: 'Namespace Selector', width: 'w-48', defaultVisible: false },
1495
- { key: 'serviceAccountSelector', label: 'Service Account Selector', width: 'w-48', defaultVisible: false },
1496
- { key: 'tier', label: 'Tier', width: 'w-28' },
1497
- { key: 'order', label: 'Order', width: 'w-24' },
1498
- { key: 'types', label: 'Types', width: 'w-28' },
1498
+ { key: 'namespaceSelector', label: 'Namespace Selector', width: 'w-48', defaultVisible: false, tooltip: 'Adds a namespace restriction to the endpoint Selector. Unset adds no namespace restriction; the other selectors still apply.' },
1499
+ { key: 'serviceAccountSelector', label: 'Service Account Selector', width: 'w-48', defaultVisible: false, tooltip: 'Endpoints must match both this service-account selector and the endpoint Selector; matching either one alone is insufficient.' },
1500
+ { key: 'tier', label: 'Tier', width: 'w-28', tooltip: 'Tier precedence applies before policy Order. An earlier tier can allow or deny traffic before this policy is reached.' },
1501
+ { key: 'order', label: 'Order', width: 'w-24', tooltip: 'Evaluation order within the tier — lowest runs first. Unset runs after every ordered policy.' },
1502
+ { key: 'types', label: 'Types', width: 'w-28', tooltip: "Traffic directions this policy governs. If no applicable policy in the tier takes action, the tier's default action applies (Deny unless configured as Pass)." },
1499
1503
  { key: 'rules', label: 'Rules', width: 'w-24', tooltip: 'Ingress / Egress rule count' },
1500
1504
  { key: 'age', label: 'Age', width: 'w-24' },
1501
1505
  ],
@@ -1503,57 +1507,57 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1503
1507
  { key: 'name', label: 'Name' },
1504
1508
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1505
1509
  { key: 'selector', label: 'Selector', width: 'w-48' },
1506
- { key: 'serviceAccountSelector', label: 'Service Account Selector', width: 'w-48', defaultVisible: false },
1507
- { key: 'tier', label: 'Tier', width: 'w-28' },
1508
- { key: 'order', label: 'Order', width: 'w-24' },
1509
- { key: 'stagedAction', label: 'Staged Action', width: 'w-32' },
1510
- { key: 'types', label: 'Types', width: 'w-28' },
1510
+ { key: 'serviceAccountSelector', label: 'Service Account Selector', width: 'w-48', defaultVisible: false, tooltip: 'Endpoints must match both this service-account selector and the endpoint Selector; matching either one alone is insufficient.' },
1511
+ { key: 'tier', label: 'Tier', width: 'w-28', tooltip: 'Tier precedence applies before policy Order. An earlier tier can allow or deny traffic before this policy is reached.' },
1512
+ { key: 'order', label: 'Order', width: 'w-24', tooltip: 'Evaluation order within the tier — lowest runs first. Unset runs after every ordered policy.' },
1513
+ { key: 'stagedAction', label: 'Staged Action', width: 'w-32', tooltip: 'Staged policies do not enforce traffic. Set and Learn preview rules; Delete stages removal of the matching enforced policy; Ignore is skipped. Omitted means Set.' },
1514
+ { key: 'types', label: 'Types', width: 'w-28', tooltip: "Traffic directions this policy governs. If no applicable policy in the tier takes action, the tier's default action applies (Deny unless configured as Pass)." },
1511
1515
  { key: 'rules', label: 'Rules', width: 'w-24', tooltip: 'Ingress / Egress rule count' },
1512
1516
  { key: 'age', label: 'Age', width: 'w-24' },
1513
1517
  ],
1514
1518
  calicostagedglobalnetworkpolicies: [
1515
1519
  { key: 'name', label: 'Name' },
1516
1520
  { key: 'selector', label: 'Selector', width: 'w-48' },
1517
- { key: 'namespaceSelector', label: 'Namespace Selector', width: 'w-48', defaultVisible: false },
1518
- { key: 'serviceAccountSelector', label: 'Service Account Selector', width: 'w-48', defaultVisible: false },
1519
- { key: 'tier', label: 'Tier', width: 'w-28' },
1520
- { key: 'order', label: 'Order', width: 'w-24' },
1521
- { key: 'stagedAction', label: 'Staged Action', width: 'w-32' },
1522
- { key: 'types', label: 'Types', width: 'w-28' },
1521
+ { key: 'namespaceSelector', label: 'Namespace Selector', width: 'w-48', defaultVisible: false, tooltip: 'Adds a namespace restriction to the endpoint Selector. Unset adds no namespace restriction; the other selectors still apply.' },
1522
+ { key: 'serviceAccountSelector', label: 'Service Account Selector', width: 'w-48', defaultVisible: false, tooltip: 'Endpoints must match both this service-account selector and the endpoint Selector; matching either one alone is insufficient.' },
1523
+ { key: 'tier', label: 'Tier', width: 'w-28', tooltip: 'Tier precedence applies before policy Order. An earlier tier can allow or deny traffic before this policy is reached.' },
1524
+ { key: 'order', label: 'Order', width: 'w-24', tooltip: 'Evaluation order within the tier — lowest runs first. Unset runs after every ordered policy.' },
1525
+ { key: 'stagedAction', label: 'Staged Action', width: 'w-32', tooltip: 'Staged policies do not enforce traffic. Set and Learn preview rules; Delete stages removal of the matching enforced policy; Ignore is skipped. Omitted means Set.' },
1526
+ { key: 'types', label: 'Types', width: 'w-28', tooltip: "Traffic directions this policy governs. If no applicable policy in the tier takes action, the tier's default action applies (Deny unless configured as Pass)." },
1523
1527
  { key: 'rules', label: 'Rules', width: 'w-24', tooltip: 'Ingress / Egress rule count' },
1524
1528
  { key: 'age', label: 'Age', width: 'w-24' },
1525
1529
  ],
1526
1530
  calicoippools: [
1527
1531
  { key: 'name', label: 'Name' },
1528
1532
  { key: 'cidr', label: 'CIDR', width: 'w-44' },
1529
- { key: 'blockSize', label: 'Block Size', width: 'w-28' },
1530
- { key: 'encapsulation', label: 'Encapsulation', width: 'w-36' },
1531
- { key: 'natOutgoing', label: 'NAT Outgoing', width: 'w-32' },
1533
+ { key: 'blockSize', label: 'Block Size', width: 'w-28', tooltip: 'CIDR prefix of each allocation block. A node can hold several blocks, so this is not a per-node pod cap. Unset means /26 for IPv4, /122 for IPv6.' },
1534
+ { key: 'encapsulation', label: 'Encapsulation', width: 'w-36', tooltip: 'Overlay used for pod traffic between nodes. None routes pod addresses directly; CrossSubnet tunnels only between nodes on different subnets.' },
1535
+ { key: 'natOutgoing', label: 'NAT Outgoing', width: 'w-32', tooltip: 'When enabled, outgoing traffic from this pool is masqueraded for destinations outside all Calico IP pools.' },
1532
1536
  { key: 'disabled', label: 'Disabled', width: 'w-28' },
1533
- { key: 'allowedUses', label: 'Allowed Uses', width: 'w-40', defaultVisible: false },
1537
+ { key: 'allowedUses', label: 'Allowed Uses', width: 'w-40', defaultVisible: false, tooltip: 'Pools without Workload are skipped for automatic pod IP allocation. Omitted or empty allows Workload and Tunnel; existing allocations are unchanged.' },
1534
1538
  { key: 'nodeSelector', label: 'Node Selector', width: 'w-48', defaultVisible: false },
1535
1539
  { key: 'age', label: 'Age', width: 'w-24' },
1536
1540
  ],
1537
1541
  calicohostendpoints: [
1538
1542
  { key: 'name', label: 'Name' },
1539
1543
  { key: 'node', label: 'Node', width: 'w-48' },
1540
- { key: 'interfaceName', label: 'Interface', width: 'w-32' },
1544
+ { key: 'interfaceName', label: 'Interface', width: 'w-32', tooltip: '* applies policy to all host interfaces. When unset, Calico identifies the interface using Expected IPs.' },
1541
1545
  { key: 'expectedIPs', label: 'Expected IPs', width: 'w-48' },
1542
- { key: 'profiles', label: 'Profiles', width: 'w-48', defaultVisible: false },
1546
+ { key: 'profiles', label: 'Profiles', width: 'w-48', defaultVisible: false, tooltip: "Profiles apply only if policy evaluation reaches them. A tier's implicit deny stops traffic before profiles, even when no rule matched." },
1543
1547
  { key: 'age', label: 'Age', width: 'w-24' },
1544
1548
  ],
1545
1549
  calicotiers: [
1546
1550
  { key: 'name', label: 'Name' },
1547
- { key: 'order', label: 'Order', width: 'w-24' },
1548
- { key: 'defaultAction', label: 'Default Action', width: 'w-36' },
1551
+ { key: 'order', label: 'Order', width: 'w-24', tooltip: 'Order this tier is evaluated in — lowest first. Unset runs after every ordered tier.' },
1552
+ { key: 'defaultAction', label: 'Default Action', width: 'w-36', tooltip: 'If this tier selects the endpoint and traffic direction but no rule decides the packet, Deny drops it and Pass continues evaluation. Tiers with no applicable policy are skipped.' },
1549
1553
  { key: 'age', label: 'Age', width: 'w-24' },
1550
1554
  ],
1551
1555
  calicostagedkubernetesnetworkpolicies: [
1552
1556
  { key: 'name', label: 'Name' },
1553
1557
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1554
1558
  { key: 'selector', label: 'Pod Selector', width: 'w-48' },
1555
- { key: 'stagedAction', label: 'Staged Action', width: 'w-32' },
1556
- { key: 'types', label: 'Types', width: 'w-28' },
1559
+ { key: 'stagedAction', label: 'Staged Action', width: 'w-32', tooltip: 'Staged policies do not enforce traffic. Set and Learn preview rules; Delete stages removal of the matching enforced policy; Ignore is skipped. Omitted means Set.' },
1560
+ { key: 'types', label: 'Types', width: 'w-28', tooltip: 'An explicitly listed direction can have zero rules. When policyTypes is omitted, Ingress is included and Egress is added when egress rules exist.' },
1557
1561
  { key: 'rules', label: 'Rules', width: 'w-24', tooltip: 'Ingress / Egress rule count' },
1558
1562
  { key: 'age', label: 'Age', width: 'w-24' },
1559
1563
  ],
@@ -1672,7 +1676,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1672
1676
  { key: 'name', label: 'Name' },
1673
1677
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1674
1678
  { key: 'url', label: 'URL', width: 'w-64' },
1675
- { key: 'type', label: 'Type', width: 'w-20', tooltip: 'default (Helm) or oci' },
1679
+ { key: 'type', label: 'Type', width: 'w-20', tooltip: 'default: Flux fetches a Helm repository index. oci: a registry reference with no reconciliation status of its own' },
1676
1680
  { key: 'status', label: 'Status', width: 'w-24' },
1677
1681
  { key: 'age', label: 'Age', width: 'w-24' },
1678
1682
  ],
@@ -1684,7 +1688,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1684
1688
  { key: 'status', label: 'Status', width: 'w-24' },
1685
1689
  { key: 'revision', label: 'Revision', width: 'w-48', tooltip: 'Applied git revision' },
1686
1690
  { key: 'inventory', label: 'Resources', width: 'w-24', tooltip: 'Number of managed resources' },
1687
- { key: 'lastUpdated', label: 'Last Updated', width: 'w-28', tooltip: 'Time since last successful reconciliation' },
1691
+ { key: 'lastUpdated', label: 'Last Updated', width: 'w-28', tooltip: 'Time since the last recorded reconciliation attempt; falls back to the last Ready transition. Neither guarantees success.' },
1688
1692
  { key: 'age', label: 'Age', width: 'w-24' },
1689
1693
  ],
1690
1694
  helmreleases: [
@@ -1712,8 +1716,8 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1712
1716
  applications: [
1713
1717
  { key: 'name', label: 'Name' },
1714
1718
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1715
- { key: 'project', label: 'Project', width: 'w-28' },
1716
- { key: 'sync', label: 'Sync', width: 'w-24' },
1719
+ { key: 'project', label: 'Project', width: 'w-28', tooltip: 'AppProject the app belongs to — bounds which repos and clusters it may deploy to' },
1720
+ { key: 'sync', label: 'Sync', width: 'w-24', tooltip: "Whether live resources match Argo's desired manifests; Synced does not mean Healthy" },
1717
1721
  { key: 'health', label: 'Health', width: 'w-24' },
1718
1722
  { key: 'repo', label: 'Repository', width: 'w-48' },
1719
1723
  { key: 'age', label: 'Age', width: 'w-24' },
@@ -1740,7 +1744,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1740
1744
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1741
1745
  { key: 'container', label: 'Container', width: 'w-28' },
1742
1746
  { key: 'image', label: 'Image', width: 'w-48' },
1743
- { key: 'critical', label: 'C', width: 'w-12', tooltip: 'Critical vulnerabilities' },
1747
+ { key: 'critical', label: 'C', width: 'w-12', tooltip: 'Critical-severity vulnerabilities. C/H/M/L = Critical, High, Medium, Low.' },
1744
1748
  { key: 'high', label: 'H', width: 'w-12', tooltip: 'High vulnerabilities' },
1745
1749
  { key: 'medium', label: 'M', width: 'w-12', tooltip: 'Medium vulnerabilities' },
1746
1750
  { key: 'low', label: 'L', width: 'w-12', tooltip: 'Low vulnerabilities' },
@@ -1750,7 +1754,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1750
1754
  { key: 'name', label: 'Name' },
1751
1755
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1752
1756
  { key: 'status', label: 'Status', width: 'w-28' },
1753
- { key: 'critical', label: 'C', width: 'w-12', tooltip: 'Critical findings' },
1757
+ { key: 'critical', label: 'C', width: 'w-12', tooltip: 'Critical-severity failed checks. C/H/M/L = Critical, High, Medium, Low.' },
1754
1758
  { key: 'high', label: 'H', width: 'w-12', tooltip: 'High findings' },
1755
1759
  { key: 'medium', label: 'M', width: 'w-12', tooltip: 'Medium findings' },
1756
1760
  { key: 'low', label: 'L', width: 'w-12', tooltip: 'Low findings' },
@@ -1761,7 +1765,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1761
1765
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1762
1766
  { key: 'container', label: 'Container', width: 'w-28' },
1763
1767
  { key: 'image', label: 'Image', width: 'w-48' },
1764
- { key: 'critical', label: 'C', width: 'w-12', tooltip: 'Critical secrets' },
1768
+ { key: 'critical', label: 'C', width: 'w-12', tooltip: 'Critical-severity exposed secrets. C/H/M/L = Critical, High, Medium, Low.' },
1765
1769
  { key: 'high', label: 'H', width: 'w-12', tooltip: 'High secrets' },
1766
1770
  { key: 'medium', label: 'M', width: 'w-12', tooltip: 'Medium secrets' },
1767
1771
  { key: 'low', label: 'L', width: 'w-12', tooltip: 'Low secrets' },
@@ -1797,13 +1801,15 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1797
1801
  sbomreports: [
1798
1802
  { key: 'name', label: 'Name' },
1799
1803
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1804
+ { key: 'image', label: 'Image', width: 'w-48', tooltip: 'Image the SBOM describes. The container name alone does not identify what was scanned.' },
1800
1805
  { key: 'container', label: 'Container', width: 'w-28' },
1801
- { key: 'components', label: 'Components', width: 'w-24' },
1806
+ { key: 'components', label: 'Components', width: 'w-24', tooltip: 'Packages and libraries found in the image' },
1802
1807
  { key: 'status', label: 'Status', width: 'w-28' },
1803
1808
  { key: 'age', label: 'Age', width: 'w-16' },
1804
1809
  ],
1805
1810
  clustersbomreports: [
1806
1811
  { key: 'name', label: 'Name' },
1812
+ { key: 'image', label: 'Image', width: 'w-48', tooltip: 'Image the SBOM describes. The container name alone does not identify what was scanned.' },
1807
1813
  { key: 'components', label: 'Components', width: 'w-24' },
1808
1814
  { key: 'status', label: 'Status', width: 'w-28' },
1809
1815
  { key: 'age', label: 'Age', width: 'w-16' },
@@ -1864,10 +1870,10 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1864
1870
  { key: 'name', label: 'Name' },
1865
1871
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1866
1872
  { key: 'status', label: 'Status', width: 'w-36' },
1867
- { key: 'storageLocation', label: 'Storage', width: 'w-36' },
1873
+ { key: 'storageLocation', label: 'Storage', width: 'w-36', tooltip: "The backup's storage location. A completed backup still needs this location reachable to restore from." },
1868
1874
  { key: 'namespaces', label: 'Scope', width: 'w-24', tooltip: 'Included namespaces (* = all)' },
1869
1875
  { key: 'duration', label: 'Duration', width: 'w-24' },
1870
- { key: 'expiry', label: 'Expires', width: 'w-24' },
1876
+ { key: 'expiry', label: 'Expires', width: 'w-24', tooltip: "When Velero's retention makes this backup eligible for cleanup. Expired means Velero intends to delete it, not that it is gone — and not that a restore will work." },
1871
1877
  { key: 'errors', label: 'Errors', width: 'w-28' },
1872
1878
  { key: 'age', label: 'Age', width: 'w-24' },
1873
1879
  ],
@@ -1911,7 +1917,8 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1911
1917
  { key: 'name', label: 'Name' },
1912
1918
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1913
1919
  { key: 'status', label: 'Status', width: 'w-36' },
1914
- { key: 'repositoryType', label: 'Type', width: 'w-24' },
1920
+ { key: 'repositoryType', label: 'Type', width: 'w-24', tooltip: 'kopia or restic. Restic is deprecated — Velero 1.17 stopped creating restic backups and 1.19 drops restic restore.' },
1921
+ { key: 'volumeNamespace', label: 'Volume NS', width: 'w-36', tooltip: 'Namespace whose volumes this repository stores. Distinct from the namespace the repository object lives in.' },
1915
1922
  { key: 'age', label: 'Age', width: 'w-24' },
1916
1923
  ],
1917
1924
  backupstoragelocations: [
@@ -1920,8 +1927,8 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1920
1927
  { key: 'status', label: 'Status', width: 'w-36' },
1921
1928
  { key: 'provider', label: 'Provider', width: 'w-24' },
1922
1929
  { key: 'bucket', label: 'Bucket', width: 'w-40' },
1923
- { key: 'default', label: 'Default', width: 'w-24' },
1924
- { key: 'lastValidation', label: 'Validated', width: 'w-28' },
1930
+ { key: 'default', label: 'Default', width: 'w-24', tooltip: 'Whether this location is marked default. A backup naming no storage location is written to the default one.' },
1931
+ { key: 'lastValidation', label: 'Validated', width: 'w-28', tooltip: 'Time since Velero last validated this location. An old value means availability has not been checked recently; validation may be disabled or configured to run less often.' },
1925
1932
  { key: 'age', label: 'Age', width: 'w-24' },
1926
1933
  ],
1927
1934
  // ============================================================================
@@ -1941,7 +1948,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1941
1948
  { key: 'status', label: 'Status', width: 'w-44' },
1942
1949
  { key: 'instances', label: 'Instances', width: 'w-28', tooltip: 'Ready/Total' },
1943
1950
  { key: 'primary', label: 'Primary', width: 'w-36' },
1944
- { key: 'image', label: 'Image', width: 'w-28' },
1951
+ { key: 'image', label: 'Image', width: 'w-28', tooltip: 'Configured image tag, or the operator-resolved image for a catalog-backed cluster. This does not confirm that every instance has finished updating.' },
1945
1952
  // No Storage column: it rendered spec.storage.size, the configured REQUEST.
1946
1953
  // The useful number is actual usage (kubectl cnpg status shows "Size: 158M")
1947
1954
  // and that isn't in the CR. A plausible-but-wrong-meaning number is worse
@@ -1959,7 +1966,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1959
1966
  updaterequests: [
1960
1967
  { key: 'name', label: 'Name' },
1961
1968
  { key: 'namespace', label: 'Namespace', width: 'w-32' },
1962
- { key: 'status', label: 'State', width: 'w-28' },
1969
+ { key: 'status', label: 'State', width: 'w-28', tooltip: 'Pending work Kyverno has queued but not yet applied; Failed is work it tried and could not.' },
1963
1970
  { key: 'type', label: 'Type', width: 'w-24' },
1964
1971
  { key: 'policy', label: 'Policy', width: 'w-52' },
1965
1972
  { key: 'triggers', label: 'Triggered By', width: 'w-56' },
@@ -1970,7 +1977,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1970
1977
  { key: 'namespace', label: 'Namespace', width: 'w-32' },
1971
1978
  { key: 'status', label: 'Outcome', width: 'w-28' },
1972
1979
  { key: 'subject', label: 'About', width: 'w-56' },
1973
- { key: 'source', label: 'Produced By', width: 'w-36' },
1980
+ { key: 'source', label: 'Produced By', width: 'w-36', tooltip: 'Admission: evaluated during an API admission request. Background scan: evaluated against existing resources.' },
1974
1981
  { key: 'results', label: 'Results', width: 'w-24' },
1975
1982
  { key: 'age', label: 'Age', width: 'w-24' },
1976
1983
  ],
@@ -1985,7 +1992,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
1985
1992
  cnpgdatabases: [
1986
1993
  { key: 'name', label: 'Name' },
1987
1994
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
1988
- { key: 'status', label: 'Applied', width: 'w-32' },
1995
+ { key: 'status', label: 'Applied', width: 'w-32', tooltip: 'Whether the operator has applied this to PostgreSQL. Pending means it has not reconciled it yet — not that it failed.' },
1989
1996
  { key: 'cluster', label: 'Cluster', width: 'w-36' },
1990
1997
  { key: 'target', label: 'Database', width: 'w-40' },
1991
1998
  { key: 'message', label: 'Message', width: 'w-64' },
@@ -2081,8 +2088,8 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2081
2088
  { key: 'name', label: 'Name' },
2082
2089
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
2083
2090
  { key: 'status', label: 'Status', width: 'w-24' },
2084
- { key: 'hosts', label: 'Hosts', width: 'w-48' },
2085
- { key: 'gateways', label: 'Gateways', width: 'w-40' },
2091
+ { key: 'hosts', label: 'Hosts', width: 'w-48', tooltip: 'Request hostnames this VirtualService matches — not the backends it routes to' },
2092
+ { key: 'gateways', label: 'Gateways', width: 'w-40', tooltip: "Where these routing rules apply. '-' means the default mesh gateway — sidecar traffic; individual route matches can override this." },
2086
2093
  { key: 'routes', label: 'Routes', width: 'w-20', tooltip: 'HTTP + TCP + TLS routes' },
2087
2094
  { key: 'age', label: 'Age', width: 'w-24' },
2088
2095
  ],
@@ -2093,7 +2100,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2093
2100
  { key: 'host', label: 'Host', width: 'w-48', tooltip: "The service this rule's traffic policy applies to" },
2094
2101
  { key: 'subsets', label: 'Subsets', width: 'w-20', tooltip: 'Named backend groups that routes can select, often for canary releases. Defining subsets does not send traffic to them.' },
2095
2102
  { key: 'tlsMode', label: 'Client TLS', width: 'w-28', tooltip: 'Declared client-side TLS mode for this host at the rule level. Subset and port policies can override it; this does not establish the effective mTLS posture.' },
2096
- { key: 'loadBalancer', label: 'LB Policy', width: 'w-28', tooltip: "Load balancing algorithm declared by this rule. '-' means none is set, so Istio applies its mesh default (LEAST_REQUEST since 1.14, overridable per mesh). Subset and port policies can differ." },
2103
+ { key: 'loadBalancer', label: 'LB Policy', width: 'w-28', tooltip: "Load balancing algorithm for this host. A dash means Istio's mesh default applies (LEAST_REQUEST since Istio 1.14). Subset and port policies can differ." },
2097
2104
  { key: 'age', label: 'Age', width: 'w-24' },
2098
2105
  ],
2099
2106
  serviceentries: [
@@ -2107,8 +2114,8 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2107
2114
  peerauthentications: [
2108
2115
  { key: 'name', label: 'Name' },
2109
2116
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
2110
- { key: 'mode', label: 'mTLS Mode', width: 'w-28' },
2111
- { key: 'selector', label: 'Selector', width: 'w-48' },
2117
+ { key: 'mode', label: 'mTLS Mode', width: 'w-28', tooltip: 'Incoming connection policy: STRICT requires mTLS; PERMISSIVE also accepts plaintext; DISABLE turns mTLS off (unsupported in ambient). UNSET inherits the broader policy, defaulting to PERMISSIVE. Port-level overrides can differ.' },
2118
+ { key: 'selector', label: 'Selector', width: 'w-48', tooltip: 'Selects workloads in this namespace. No selector defines a namespace default, or a mesh default in the root namespace; more specific policies can override it.' },
2112
2119
  { key: 'age', label: 'Age', width: 'w-24' },
2113
2120
  ],
2114
2121
  authorizationpolicies: [
@@ -2126,7 +2133,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2126
2133
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
2127
2134
  { key: 'status', label: 'Status', width: 'w-28' },
2128
2135
  { key: 'url', label: 'URL', width: 'w-56' },
2129
- { key: 'latestRevision', label: 'Latest Revision', width: 'w-44' },
2136
+ { key: 'latestRevision', label: 'Latest Revision', width: 'w-44', tooltip: 'Newest revision that has reported Ready. A newer revision may still be starting or may have failed; this revision need not receive traffic.' },
2130
2137
  { key: 'traffic', label: 'Traffic', width: 'w-48' },
2131
2138
  { key: 'age', label: 'Age', width: 'w-24' },
2132
2139
  ],
@@ -2135,16 +2142,16 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2135
2142
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
2136
2143
  { key: 'status', label: 'Status', width: 'w-28' },
2137
2144
  { key: 'latestCreated', label: 'Latest Created', width: 'w-48' },
2138
- { key: 'latestReady', label: 'Latest Ready', width: 'w-48' },
2145
+ { key: 'latestReady', label: 'Latest Ready', width: 'w-48', tooltip: 'Newest revision that has reported Ready. If it differs from Latest Created, the newer revision may still be starting or may have failed; inspect Status.' },
2139
2146
  { key: 'age', label: 'Age', width: 'w-24' },
2140
2147
  ],
2141
2148
  knativerevisions: [
2142
2149
  { key: 'name', label: 'Name' },
2143
2150
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
2144
2151
  { key: 'status', label: 'Status', width: 'w-28' },
2145
- { key: 'routing', label: 'Traffic', width: 'w-20', tooltip: 'Whether this revision is receiving traffic' },
2152
+ { key: 'routing', label: 'Traffic', width: 'w-20', tooltip: 'Active: marked for Route traffic, even if scaled to zero. Reserve: not currently marked for Route traffic. Neither value measures incoming requests.' },
2146
2153
  { key: 'image', label: 'Image', width: 'w-48' },
2147
- { key: 'concurrency', label: 'Concurrency', width: 'w-32' },
2154
+ { key: 'concurrency', label: 'Concurrency', width: 'w-32', tooltip: "Hard limit on simultaneous requests handled by each pod; excess requests are buffered. Unlimited removes this cap, not autoscaling's target." },
2148
2155
  { key: 'age', label: 'Age', width: 'w-24' },
2149
2156
  ],
2150
2157
  knativeroutes: [
@@ -2169,7 +2176,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2169
2176
  { key: 'status', label: 'Status', width: 'w-28' },
2170
2177
  { key: 'broker', label: 'Broker', width: 'w-36' },
2171
2178
  { key: 'subscriber', label: 'Subscriber', width: 'w-48' },
2172
- { key: 'filter', label: 'Filter', width: 'w-48' },
2179
+ { key: 'filter', label: 'Filter', width: 'w-48', tooltip: 'Selects which broker events are eligible for delivery. No filtering admits every event; it does not guarantee successful delivery. Expression filters override attribute filters.' },
2173
2180
  { key: 'age', label: 'Age', width: 'w-24' },
2174
2181
  ],
2175
2182
  eventtypes: [
@@ -2186,7 +2193,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2186
2193
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
2187
2194
  { key: 'status', label: 'Status', width: 'w-28' },
2188
2195
  { key: 'schedule', label: 'Schedule', width: 'w-36' },
2189
- { key: 'sink', label: 'Sink', width: 'w-48' },
2196
+ { key: 'sink', label: 'Sink', width: 'w-48', tooltip: 'Requested event destination. A displayed reference does not prove it resolved or received events; inspect conditions when delivery fails.' },
2190
2197
  { key: 'data', label: 'Data', width: 'w-36' },
2191
2198
  { key: 'age', label: 'Age', width: 'w-24' },
2192
2199
  ],
@@ -2243,14 +2250,14 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2243
2250
  { key: 'name', label: 'Name' },
2244
2251
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
2245
2252
  { key: 'status', label: 'Status', width: 'w-28' },
2246
- { key: 'steps', label: 'Steps', width: 'w-16' },
2253
+ { key: 'steps', label: 'Steps', width: 'w-16', tooltip: "Stages events pass through in order; each stage's reply feeds the next" },
2247
2254
  { key: 'age', label: 'Age', width: 'w-24' },
2248
2255
  ],
2249
2256
  parallels: [
2250
2257
  { key: 'name', label: 'Name' },
2251
2258
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
2252
2259
  { key: 'status', label: 'Status', width: 'w-28' },
2253
- { key: 'branches', label: 'Branches', width: 'w-20' },
2260
+ { key: 'branches', label: 'Branches', width: 'w-20', tooltip: 'Independent filter-and-subscriber pairs; every event is offered to all of them' },
2254
2261
  { key: 'age', label: 'Age', width: 'w-24' },
2255
2262
  ],
2256
2263
  // Knative Networking
@@ -2260,7 +2267,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2260
2267
  { key: 'status', label: 'Status', width: 'w-28' },
2261
2268
  { key: 'ingressClass', label: 'Class', width: 'w-24' },
2262
2269
  { key: 'hosts', label: 'Hosts', width: 'w-56' },
2263
- { key: 'visibility', label: 'Visibility', width: 'w-28' },
2270
+ { key: 'visibility', label: 'Visibility', width: 'w-28', tooltip: 'Requested exposure across all rules. ExternalIP means at least one rule requests external exposure; ClusterLocal means all rules request cluster-only exposure. This does not verify connectivity.' },
2264
2271
  { key: 'age', label: 'Age', width: 'w-24' },
2265
2272
  ],
2266
2273
  knativecertificates: [
@@ -2269,13 +2276,14 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2269
2276
  { key: 'status', label: 'Status', width: 'w-28' },
2270
2277
  { key: 'dnsNames', label: 'DNS Names', width: 'w-56' },
2271
2278
  { key: 'secretName', label: 'Secret', width: 'w-44' },
2279
+ { key: 'expires', label: 'Expires', width: 'w-28', tooltip: 'Expiry of the certificate in the named Secret, as the controller reported it.' },
2272
2280
  { key: 'age', label: 'Age', width: 'w-24' },
2273
2281
  ],
2274
2282
  serverlessservices: [
2275
2283
  { key: 'name', label: 'Name' },
2276
2284
  { key: 'namespace', label: 'Namespace', width: 'w-36' },
2277
2285
  { key: 'status', label: 'Status', width: 'w-28' },
2278
- { key: 'mode', label: 'Mode', width: 'w-20' },
2286
+ { key: 'mode', label: 'Mode', width: 'w-20', tooltip: 'Requested backend mode: Serve selects revision pods; Proxy selects activators. Activators may remain involved with healthy pods for burst handling, so Proxy does not prove a cold start.' },
2279
2287
  { key: 'age', label: 'Age', width: 'w-24' },
2280
2288
  ],
2281
2289
  domainmappings: [
@@ -2289,7 +2297,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2289
2297
  ingressroutes: [
2290
2298
  { key: 'name', label: 'Name', width: 'min-w-40' },
2291
2299
  { key: 'namespace', label: 'Namespace', width: 'w-36 shrink-0' },
2292
- { key: 'entrypoints', label: 'Entry Points', width: 'w-32 shrink-0' },
2300
+ { key: 'entrypoints', label: 'Entry Points', width: 'w-32 shrink-0', tooltip: 'Entry points this route binds to. When unset, Traefik uses the default entry points from its static configuration.' },
2293
2301
  { key: 'hosts', label: 'Hosts', width: 'min-w-44' },
2294
2302
  { key: 'routes', label: 'Routes', width: 'min-w-48' },
2295
2303
  { key: 'tls', label: 'TLS', width: 'w-14 shrink-0' },
@@ -2299,7 +2307,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2299
2307
  ingressroutetcps: [
2300
2308
  { key: 'name', label: 'Name', width: 'min-w-40' },
2301
2309
  { key: 'namespace', label: 'Namespace', width: 'w-36 shrink-0' },
2302
- { key: 'entrypoints', label: 'Entry Points', width: 'w-32 shrink-0' },
2310
+ { key: 'entrypoints', label: 'Entry Points', width: 'w-32 shrink-0', tooltip: 'Entry points this route binds to. When unset, Traefik uses the default entry points from its static configuration.' },
2303
2311
  { key: 'hosts', label: 'Hosts', width: 'min-w-44' },
2304
2312
  { key: 'routes', label: 'Routes', width: 'min-w-48' },
2305
2313
  { key: 'tls', label: 'TLS', width: 'w-14 shrink-0' },
@@ -2309,7 +2317,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2309
2317
  ingressrouteudps: [
2310
2318
  { key: 'name', label: 'Name', width: 'min-w-40' },
2311
2319
  { key: 'namespace', label: 'Namespace', width: 'w-36 shrink-0' },
2312
- { key: 'entrypoints', label: 'Entry Points', width: 'w-32 shrink-0' },
2320
+ { key: 'entrypoints', label: 'Entry Points', width: 'w-32 shrink-0', tooltip: 'Entry points this route binds to. When unset it is attached to every available UDP entry point; asDefault has no effect on UDP.' },
2313
2321
  { key: 'routes', label: 'Routes', width: 'min-w-48' },
2314
2322
  { key: 'age', label: 'Age', width: 'w-24 shrink-0' },
2315
2323
  ],
@@ -2349,7 +2357,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2349
2357
  tlsoptions: [
2350
2358
  { key: 'name', label: 'Name', width: 'min-w-40' },
2351
2359
  { key: 'namespace', label: 'Namespace', width: 'w-36 shrink-0' },
2352
- { key: 'minVersion', label: 'Min TLS', width: 'w-24 shrink-0' },
2360
+ { key: 'minVersion', label: 'Min TLS', width: 'w-24 shrink-0', tooltip: "Lowest TLS version accepted; connections below it are rejected. A dash means the resource sets no minimum, so Traefik's own default applies." },
2353
2361
  { key: 'age', label: 'Age', width: 'w-24 shrink-0' },
2354
2362
  ],
2355
2363
  tlsstores: [
@@ -2365,7 +2373,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2365
2373
  { key: 'class', label: 'Class', width: 'w-32 shrink-0' },
2366
2374
  { key: 'cpReplicas', label: 'CP Ready', width: 'w-24 shrink-0', tooltip: 'Control plane replicas (ready/desired)' },
2367
2375
  { key: 'workerReplicas', label: 'Workers', width: 'w-20 shrink-0', tooltip: 'Worker replicas (ready/desired)' },
2368
- { key: 'phase', label: 'Phase', width: 'w-28 shrink-0' },
2376
+ { key: 'phase', label: 'Phase', width: 'w-28 shrink-0', tooltip: 'Lifecycle phase while the cluster is still provisioning or deleting; the Available/Ready condition once it has landed.' },
2369
2377
  { key: 'version', label: 'Version', width: 'w-24 shrink-0' },
2370
2378
  { key: 'age', label: 'Age', width: 'w-24 shrink-0' },
2371
2379
  ],
@@ -2374,6 +2382,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2374
2382
  { key: 'namespace', label: 'Namespace', width: 'w-36 shrink-0' },
2375
2383
  { key: 'cluster', label: 'Cluster', width: 'w-32 shrink-0' },
2376
2384
  { key: 'ready', label: 'Ready', width: 'w-20 shrink-0', tooltip: 'Ready replicas / desired' },
2385
+ { key: 'upToDate', label: 'Up-to-date', width: 'w-24', tooltip: 'Machines already running the current spec. Fewer than Ready means a rollout is still in progress.' },
2377
2386
  { key: 'phase', label: 'Phase', width: 'w-28 shrink-0' },
2378
2387
  { key: 'version', label: 'Version', width: 'w-24 shrink-0' },
2379
2388
  { key: 'age', label: 'Age', width: 'w-24 shrink-0' },
@@ -2383,7 +2392,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2383
2392
  { key: 'namespace', label: 'Namespace', width: 'w-36 shrink-0' },
2384
2393
  { key: 'cluster', label: 'Cluster', width: 'w-32 shrink-0' },
2385
2394
  { key: 'role', label: 'Role', width: 'w-28 shrink-0' },
2386
- { key: 'phase', label: 'Phase', width: 'w-28 shrink-0' },
2395
+ { key: 'phase', label: 'Phase', width: 'w-28 shrink-0', tooltip: 'Lifecycle milestone; Running does not guarantee that the node is currently Ready.' },
2387
2396
  { key: 'node', label: 'Node', width: 'w-32 shrink-0' },
2388
2397
  { key: 'version', label: 'Version', width: 'w-24 shrink-0' },
2389
2398
  { key: 'age', label: 'Age', width: 'w-24 shrink-0' },
@@ -2441,7 +2450,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2441
2450
  { key: 'name', label: 'Name', width: 'min-w-40' },
2442
2451
  { key: 'namespace', label: 'Namespace', width: 'w-36 shrink-0' },
2443
2452
  { key: 'instanceType', label: 'Instance', width: 'w-28 shrink-0' },
2444
- { key: 'replicas', label: 'Ready', width: 'w-20 shrink-0', tooltip: 'Ready replicas' },
2453
+ { key: 'replicas', label: 'Ready', width: 'w-20 shrink-0', tooltip: "Replicas the provider reports, over the autoscaling maximum when one is set. The second number is a ceiling, not a target, so this is not a ready/desired ratio." },
2445
2454
  { key: 'capacityType', label: 'Capacity', width: 'w-28 shrink-0' },
2446
2455
  { key: 'status', label: 'Status', width: 'w-28 shrink-0' },
2447
2456
  { key: 'age', label: 'Age', width: 'w-24 shrink-0' },
@@ -2459,7 +2468,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2459
2468
  { key: 'name', label: 'Name', width: 'min-w-40' },
2460
2469
  { key: 'namespace', label: 'Namespace', width: 'w-36 shrink-0' },
2461
2470
  { key: 'instanceType', label: 'Instance', width: 'w-28 shrink-0' },
2462
- { key: 'capacity', label: 'Capacity', width: 'w-32 shrink-0', tooltip: 'Computed CPU/memory' },
2471
+ { key: 'capacity', label: 'Capacity', width: 'w-32 shrink-0', tooltip: 'Per-node CPU and memory reported by the provider for scale-from-zero estimation.' },
2463
2472
  { key: 'age', label: 'Age', width: 'w-24 shrink-0' },
2464
2473
  ],
2465
2474
  awsmanagedclusters: [
@@ -2484,7 +2493,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2484
2493
  { key: 'name', label: 'Name', width: 'min-w-40' },
2485
2494
  { key: 'namespace', label: 'Namespace', width: 'w-36 shrink-0' },
2486
2495
  { key: 'machineType', label: 'Machine Type', width: 'w-32 shrink-0' },
2487
- { key: 'replicas', label: 'Replicas', width: 'w-20 shrink-0' },
2496
+ { key: 'replicas', label: 'Replicas', width: 'w-20 shrink-0', tooltip: "Replicas the provider reports as observed. Not a ready/desired ratio, and the pool's autoscaling bounds are not shown here." },
2488
2497
  { key: 'status', label: 'Status', width: 'w-28 shrink-0' },
2489
2498
  { key: 'age', label: 'Age', width: 'w-24 shrink-0' },
2490
2499
  ],
@@ -2523,9 +2532,9 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2523
2532
  { key: 'name', label: 'Name', width: 'min-w-40' },
2524
2533
  { key: 'namespace', label: 'Namespace', width: 'w-36 shrink-0' },
2525
2534
  { key: 'sku', label: 'VM Size', width: 'w-32 shrink-0' },
2526
- { key: 'mode', label: 'Mode', width: 'w-20 shrink-0' },
2527
- { key: 'replicas', label: 'Replicas', width: 'w-20 shrink-0' },
2528
- { key: 'priority', label: 'Priority', width: 'w-24 shrink-0' },
2535
+ { key: 'mode', label: 'Mode', width: 'w-20 shrink-0', tooltip: 'System pools are preferred for critical AKS system pods; User pools are intended for applications. Mode does not enforce workload isolation.' },
2536
+ { key: 'replicas', label: 'Replicas', width: 'w-20 shrink-0', tooltip: "Replicas the provider reports as observed. Not a ready/desired ratio, and the pool's autoscaling bounds are not shown here." },
2537
+ { key: 'priority', label: 'Priority', width: 'w-24 shrink-0', tooltip: 'Spot VMs may be evicted for capacity or price; Regular VMs are not Spot. This is unrelated to Kubernetes scheduling priority.' },
2529
2538
  { key: 'status', label: 'Status', width: 'w-28 shrink-0' },
2530
2539
  { key: 'age', label: 'Age', width: 'w-24 shrink-0' },
2531
2540
  ],
@@ -2552,11 +2561,11 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2552
2561
  httpproxies: [
2553
2562
  { key: 'name', label: 'Name', width: 'min-w-40' },
2554
2563
  { key: 'namespace', label: 'Namespace', width: 'w-36 shrink-0' },
2555
- { key: 'fqdn', label: 'FQDN', width: 'min-w-44' },
2564
+ { key: 'fqdn', label: 'FQDN', width: 'min-w-44', tooltip: 'Virtual-host hostname this proxy declares. A dash means it declares none, which is normal for an included proxy — its routes are served under the roots that include it.' },
2556
2565
  { key: 'routes', label: 'Routes', width: 'w-20 shrink-0' },
2557
- { key: 'includes', label: 'Includes', width: 'w-24 shrink-0' },
2566
+ { key: 'includes', label: 'Includes', width: 'w-24 shrink-0', tooltip: "Child HTTPProxies this one directly includes. They contribute routing configuration, so a proxy can serve traffic even when its own Routes count is zero." },
2558
2567
  { key: 'tls', label: 'TLS', width: 'w-14 shrink-0' },
2559
- { key: 'status', label: 'Status', width: 'w-28 shrink-0' },
2568
+ { key: 'status', label: 'Status', width: 'w-28 shrink-0', tooltip: "Contour's verdict on this proxy. Orphaned means no root proxy includes it, so it serves no traffic." },
2560
2569
  { key: 'age', label: 'Age', width: 'w-24 shrink-0' },
2561
2570
  ],
2562
2571
  // Crossplane — Managed Resources are unbounded (one kind per provider CRD);
@@ -2566,7 +2575,7 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2566
2575
  { key: 'namespace', label: 'Namespace', width: 'w-32 shrink-0' },
2567
2576
  { key: 'kind', label: 'Kind', width: 'w-32 shrink-0' },
2568
2577
  { key: 'external', label: 'External Name', width: 'min-w-48' },
2569
- { key: 'provider', label: 'Provider Config', width: 'w-40 shrink-0' },
2578
+ { key: 'provider', label: 'Provider Config', width: 'w-40 shrink-0', tooltip: 'Provider configuration selecting the credentials and connection settings used to manage this external resource.' },
2570
2579
  { key: 'status', label: 'Status', width: 'w-32 shrink-0' },
2571
2580
  { key: 'age', label: 'Age', width: 'w-24 shrink-0' },
2572
2581
  ],
@@ -2586,14 +2595,14 @@ const KNOWN_COLUMNS: Record<string, Column[]> = {
2586
2595
  compositions: [
2587
2596
  { key: 'name', label: 'Name', width: 'min-w-40' },
2588
2597
  { key: 'composite', label: 'Composite Kind', width: 'w-44 shrink-0' },
2589
- { key: 'mode', label: 'Mode', width: 'w-24 shrink-0' },
2598
+ { key: 'mode', label: 'Mode', width: 'w-24 shrink-0', tooltip: 'Pipeline runs composition functions. Resources uses native patch-and-transform composition and must be migrated before upgrading to Crossplane v2.' },
2590
2599
  { key: 'functions', label: 'Functions', width: 'w-28 shrink-0' },
2591
2600
  { key: 'age', label: 'Age', width: 'w-24 shrink-0' },
2592
2601
  ],
2593
2602
  compositeresourcedefinitions: [
2594
2603
  { key: 'name', label: 'Name', width: 'min-w-40' },
2595
2604
  { key: 'kind', label: 'Kind', width: 'w-40 shrink-0' },
2596
- { key: 'claim', label: 'Claim Kind', width: 'w-40 shrink-0' },
2605
+ { key: 'claim', label: 'Claim Kind', width: 'w-40 shrink-0', tooltip: 'Optional namespaced claim kind. Crossplane v2 supports claims only for XRDs using LegacyCluster scope.' },
2597
2606
  { key: 'age', label: 'Age', width: 'w-24 shrink-0' },
2598
2607
  ],
2599
2608
  }
@@ -5078,8 +5087,10 @@ export function ResourcesView({
5078
5087
  // DaemonSet: numberAvailable, others: availableReplicas
5079
5088
  return status.numberAvailable ?? status.availableReplicas ?? 0
5080
5089
  case 'upToDate':
5081
- // DaemonSet: updatedNumberScheduled, others: updatedReplicas
5082
- return status.updatedNumberScheduled ?? status.updatedReplicas ?? 0
5090
+ // DaemonSet: updatedNumberScheduled; CAPI v1beta2: upToDateReplicas;
5091
+ // others: updatedReplicas. Same precedence the cells display, or a row
5092
+ // sorts as zero while showing a real count.
5093
+ return status.updatedNumberScheduled ?? status.upToDateReplicas ?? status.updatedReplicas ?? 0
5083
5094
  case 'restarts':
5084
5095
  if (kindLower === 'jobsets') return getJobSetRestarts(resource)
5085
5096
  return getPodRestarts(resource)
@@ -12,6 +12,7 @@ import {
12
12
  getClusterClassStatus,
13
13
  getMachineHealthCheckStatus, getMachineHealthCheckHealthy, getMachineHealthCheckClusterName,
14
14
  getClusterProvider,
15
+ getMachineDeploymentUpToDate,
15
16
  } from '../resource-utils-capi'
16
17
 
17
18
  function StatusBadge({ resource, getStatus }: { resource: any; getStatus: (r: any) => { text: string; color: string } }) {
@@ -78,6 +79,8 @@ export function CAPIMachineDeploymentCell({ resource, column }: { resource: any;
78
79
  return <TextCell value={getMachineClusterName(resource)} />
79
80
  case 'ready':
80
81
  return <TextCell value={getMachineDeploymentReplicas(resource)} />
82
+ case 'upToDate':
83
+ return <TextCell value={getMachineDeploymentUpToDate(resource)} />
81
84
  case 'version':
82
85
  return <TextCell value={getMachineDeploymentVersion(resource)} />
83
86
  default:
@@ -48,8 +48,8 @@ export function CertificateCell({ resource, column }: { resource: any; column: s
48
48
  case 'expires': {
49
49
  const expiry = getCertificateExpiry(resource)
50
50
  return (
51
- <span className={clsx(
52
- 'text-sm font-medium',
51
+ <span title={expiry.text} className={clsx(
52
+ 'text-sm font-medium truncate block',
53
53
  expiry.level === 'unhealthy' ? 'text-red-400' :
54
54
  expiry.level === 'degraded' ? 'text-yellow-400' :
55
55
  expiry.level === 'healthy' ? 'text-green-400' :
@@ -28,6 +28,9 @@ import {
28
28
  getDomainMappingUrl,
29
29
  getServerlessServiceMode,
30
30
  } from '../resource-utils-knative'
31
+ // Knative's Certificate reports status.notAfter like any other TLS certificate,
32
+ // so it shares the expiry formatter rather than re-deriving the thresholds.
33
+ import { getCertificateExpiry, healthColors } from '../resource-utils'
31
34
 
32
35
  function StatusCell({ resource, getStatus }: { resource: any; getStatus: (r: any) => { text: string; color: string } }) {
33
36
  const status = getStatus(resource)
@@ -366,6 +369,16 @@ export function KnativeCertificateCell({ resource, column }: { resource: any; co
366
369
  }
367
370
  case 'secretName':
368
371
  return <TextCell value={resource?.spec?.secretName || '-'} />
372
+ case 'expires': {
373
+ const expiry = getCertificateExpiry(resource)
374
+ // "Expired 365d ago" is far wider than the column; bound it like the
375
+ // other status badges that carry arbitrary-length text.
376
+ return (
377
+ <span className={clsx('badge truncate max-w-full', healthColors[expiry.level])} title={expiry.text}>
378
+ {expiry.text}
379
+ </span>
380
+ )
381
+ }
369
382
  default:
370
383
  return <DefaultCell />
371
384
  }
@@ -8,6 +8,7 @@ import {
8
8
  getKyvernoPolicyStatus,
9
9
  getKyvernoEnforcement,
10
10
  getKyvernoPolicyRuleCount,
11
+ getKyvernoPolicyRuleTypes,
11
12
  } from '../resource-utils-kyverno'
12
13
  import {
13
14
  getKyvernoRequestState,
@@ -93,6 +94,12 @@ export function KyvernoPolicyCell({ resource, column }: { resource: any; column:
93
94
  </span>
94
95
  )
95
96
  }
97
+ case 'ruleTypes': {
98
+ const types = getKyvernoPolicyRuleTypes(resource)
99
+ return (
100
+ <span className="text-sm text-theme-text-secondary truncate block" title={types}>{types}</span>
101
+ )
102
+ }
96
103
  case 'rules': {
97
104
  const count = getKyvernoPolicyRuleCount(resource)
98
105
  return <span className="text-sm text-theme-text-secondary">{count}</span>
@@ -129,6 +129,12 @@ export function KyvernoCleanupPolicyCell({ resource, column }: { resource: any;
129
129
  const status = getKyvernoCleanupPolicyStatus(resource)
130
130
  return <span className={clsx('badge', status.color)}>{status.text}</span>
131
131
  }
132
+ case 'lastRun': {
133
+ const last = getKyvernoLastExecutionTime(resource)
134
+ return last
135
+ ? <span className="text-sm text-theme-text-secondary">{formatAge(last)}</span>
136
+ : <span className="text-sm text-theme-text-tertiary">-</span>
137
+ }
132
138
  case 'schedule': {
133
139
  const schedule = getKyvernoCleanupSchedule(resource)
134
140
  return schedule ? (
@@ -6,6 +6,7 @@ import {
6
6
  getVulnerabilityReportSummary,
7
7
  getVulnerabilityReportContainer,
8
8
  getVulnerabilityReportImage,
9
+ getSbomReportImage,
9
10
  getConfigAuditReportSummary,
10
11
  getConfigAuditReportStatus,
11
12
  getExposedSecretReportSummary,
@@ -133,6 +134,12 @@ export function ClusterComplianceReportCell({ resource, column }: { resource: an
133
134
 
134
135
  export function SbomReportCell({ resource, column }: { resource: any; column: string }) {
135
136
  switch (column) {
137
+ case 'image': {
138
+ const image = getSbomReportImage(resource)
139
+ return (
140
+ <span className="text-sm text-theme-text-secondary truncate block" title={image}>{image}</span>
141
+ )
142
+ }
136
143
  case 'container':
137
144
  return <span className="text-sm text-theme-text-secondary">{getSbomReportContainer(resource)}</span>
138
145
  case 'components': {
@@ -30,6 +30,7 @@ import {
30
30
  getVSLConfig,
31
31
  getBackupRepositoryStatus,
32
32
  getBackupRepositoryType,
33
+ getBackupRepositoryVolumeNamespace,
33
34
  } from '../resource-utils-velero'
34
35
 
35
36
  // The detail-page Phase value. The badge carries the same label the table
@@ -235,6 +236,8 @@ export function BackupRepositoryCell({ resource, column }: { resource: any; colu
235
236
  </span>
236
237
  )
237
238
  }
239
+ case 'volumeNamespace':
240
+ return <span className="text-sm text-theme-text-secondary">{getBackupRepositoryVolumeNamespace(resource)}</span>
238
241
  case 'repositoryType': {
239
242
  const type = getBackupRepositoryType(resource)
240
243
  // restic is on its way out (no new backups since v1.17, restore dropped in
@@ -174,6 +174,12 @@ describe('IPPool derivations', () => {
174
174
  getCalicoIPPoolAllowedUses({ spec: { allowedUses: ['Tunnel'] } }),
175
175
  ).toBe('Tunnel')
176
176
  })
177
+
178
+ it('treats an empty allowedUses list as the default, not as no uses', () => {
179
+ // Calico: "If not specified or empty, defaults to ["Tunnel", "Workload"]".
180
+ // A dash here would read as a pool that allocates for nothing.
181
+ expect(getCalicoIPPoolAllowedUses({ spec: { allowedUses: [] } })).toBe('Workload, Tunnel')
182
+ })
177
183
  })
178
184
 
179
185
  describe('derived policy types', () => {
@@ -256,6 +256,10 @@ export function getCalicoIPPoolEncapsulation(pool: any): string {
256
256
 
257
257
  export function getCalicoIPPoolAllowedUses(pool: any): string {
258
258
  const uses = pool?.spec?.allowedUses
259
- if (!Array.isArray(uses)) return 'Workload, Tunnel'
260
- return uses.length > 0 ? uses.map(String).join(', ') : '-'
259
+ // Calico documents an empty list as equivalent to an absent one: "If not
260
+ // specified or empty, defaults to ["Tunnel", "Workload"] for
261
+ // back-compatibility." Rendering a dash there would read as a pool that
262
+ // allocates for nothing.
263
+ if (!Array.isArray(uses) || uses.length === 0) return 'Workload, Tunnel'
264
+ return uses.map(String).join(', ')
261
265
  }
@@ -102,6 +102,9 @@ export const getExposedSecretReportSummary = getVulnerabilityReportSummary
102
102
  export const getExposedSecretReportContainer = getVulnerabilityReportContainer
103
103
  export const getExposedSecretReportImage = getVulnerabilityReportImage
104
104
 
105
+ // SBOM reports carry the same report.artifact/registry shape as the scan reports.
106
+ export const getSbomReportImage = getVulnerabilityReportImage
107
+
105
108
  export const getExposedSecretReportStatus = getVulnerabilityReportStatus
106
109
 
107
110
  // ============================================================================
@@ -11,7 +11,8 @@ import { getNodePoolStatus, getNodeClaimStatus } from './resource-utils-karpente
11
11
  import { getScaledObjectStatus, getScaledJobStatus } from './resource-utils-keda'
12
12
  import { getGitRepositoryStatus, getOCIRepositoryStatus, getHelmRepositoryStatus, getHelmRepositoryType, getKustomizationStatus, getFluxHelmReleaseStatus, getFluxAlertStatus } from './resource-utils-flux'
13
13
  import { getArgoApplicationStatus, getArgoApplicationSetStatus, getArgoApplicationSync, getArgoApplicationHealth, getArgoApplicationProject } from './resource-utils-argo'
14
- import { getPolicyReportStatus as _getPolicyReportStatus, getKyvernoPolicyStatus as _getKyvernoPolicyStatus } from './resource-utils-kyverno'
14
+ import { getVulnerabilityReportImage as _getVulnerabilityReportImage } from './resource-utils-trivy'
15
+ import { getKyvernoPolicyRuleTypes as _getKyvernoPolicyRuleTypes, getPolicyReportStatus as _getPolicyReportStatus, getKyvernoPolicyStatus as _getKyvernoPolicyStatus } from './resource-utils-kyverno'
15
16
  import { getResourceClaimStatus as _getResourceClaimStatus, getResourceClaimDeviceClasses as _getResourceClaimDeviceClasses, getResourceClaimTemplateDeviceClasses as _getResourceClaimTemplateDeviceClasses, getResourceClaimAllocation as _getResourceClaimAllocation, getResourceClaimReservedFor as _getResourceClaimReservedFor } from './resource-utils-dra'
16
17
  import { getNvidiaClusterPolicyStatus as _getNvidiaClusterPolicyStatus, getNvidiaClusterPolicyEnabledComponents as _getNvidiaClusterPolicyEnabledComponents, getNvidiaDriverStatus as _getNvidiaDriverStatus } from './resource-utils-nvidia'
17
18
  import { getClusterQueueStatus as _getClusterQueueStatus, getLocalQueueStatus as _getLocalQueueStatus, getKueueWorkloadStatus as _getKueueWorkloadStatus, getResourceFlavorStatus as _getResourceFlavorStatus, getAdmissionCheckStatus as _getAdmissionCheckStatus, getProvisioningRequestStatus as _getProvisioningRequestStatus } from './resource-utils-kueue'
@@ -2594,6 +2595,20 @@ export function getCellFilterValue(resource: any, column: string, kind: string):
2594
2595
  case 'mig':
2595
2596
  if (kindLower === 'nvidiaclusterpolicies') return resource.spec?.mig?.strategy || ''
2596
2597
  break
2598
+ // Trivy keeps the scanned image under report.artifact, so the generic
2599
+ // spec/status probe finds nothing and the header would offer a filter
2600
+ // button that never populates.
2601
+ case 'image':
2602
+ if (kindLower === 'vulnerabilityreports' || kindLower === 'sbomreports'
2603
+ || kindLower === 'clustersbomreports' || kindLower === 'exposedsecretreports') {
2604
+ return _getVulnerabilityReportImage(resource)
2605
+ }
2606
+ break
2607
+ case 'ruleTypes':
2608
+ if (kindLower === 'kyvernopolicies' || kindLower === 'clusterpolicies') {
2609
+ return _getKyvernoPolicyRuleTypes(resource)
2610
+ }
2611
+ break
2597
2612
  // The fallback would read spec.timeZone and yield '' for an undeclared
2598
2613
  // zone, so those rows would drop out of a filter the cell shows a value for.
2599
2614
  case 'timeZone':
@@ -2622,6 +2637,7 @@ export {
2622
2637
  getVulnerabilityReportSummary,
2623
2638
  getVulnerabilityReportStatus,
2624
2639
  getVulnerabilityReportImage,
2640
+ getSbomReportImage,
2625
2641
  getVulnerabilityReportContainer,
2626
2642
  getConfigAuditReportSummary,
2627
2643
  getConfigAuditReportStatus,
@@ -1,4 +1,5 @@
1
1
  import { describe, it, expect } from 'vitest'
2
+ import { getCellFilterValue } from './resource-utils'
2
3
  import { getCellFilterKind, hasCuratedColumns, isColumnFilterableByDistinctCount, normalizeKindToPlural, SKIP_FILTER_COLUMNS } from './ResourcesView'
3
4
 
4
5
  describe('isColumnFilterableByDistinctCount', () => {
@@ -98,3 +99,22 @@ describe('GPU ecosystem column routing', () => {
98
99
  expect(hasCuratedColumns('inferenceobjectives', 'example.io')).toBe(false)
99
100
  })
100
101
  })
102
+
103
+ describe('filter values for columns whose data sits outside spec/status', () => {
104
+ // getCellFilterValue's fallback probes status[key]/spec[key]. A column whose
105
+ // value lives elsewhere needs an explicit case, or the header reserves a
106
+ // filter button that can never populate.
107
+ it('reads the scanned image out of the Trivy report', () => {
108
+ const report = {
109
+ report: { registry: { server: 'ghcr.io' }, artifact: { repository: 'acme/api', tag: 'v2' } },
110
+ }
111
+ for (const kind of ['vulnerabilityreports', 'sbomreports', 'clustersbomreports']) {
112
+ expect(getCellFilterValue(report, 'image', kind)).toContain('acme/api')
113
+ }
114
+ })
115
+
116
+ it('reads Kyverno rule types out of the rules array', () => {
117
+ const policy = { spec: { rules: [{ validate: {} }, { mutate: {} }] } }
118
+ expect(getCellFilterValue(policy, 'ruleTypes', 'clusterpolicies')).toBe('validate, mutate')
119
+ })
120
+ })