Compare commits

..
Author SHA1 Message Date
james.maesandClaude Opus 5.5 21f22bb926 fix(widget): cluster nodes table in four columns
Where the node runs and its version fold into the Node column, so the table
stays readable at every width (hosts gate widgets at four columns).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 12:24:56 -05:00
3 changed files with 73 additions and 34 deletions

No files matched your search

+55 -26
View File
@@ -1,31 +1,60 @@
# Use the latest 2.1 version of CircleCI pipeline process engine.
# See: https://circleci.com/docs/reference/configuration-reference/
version: 2.1
# Define a job to be invoked later in a workflow.
# See: https://circleci.com/docs/guides/orchestrate/jobs-steps/#jobs-overview & https://circleci.com/docs/reference/configuration-reference/#jobs
jobs:
say-hello:
# Specify the execution environment. You can specify an image from Docker Hub or use one of our convenience images from CircleCI's Developer Hub.
# See: https://circleci.com/docs/guides/execution-managed/executor-intro/ & https://circleci.com/docs/reference/configuration-reference/#executor-job
docker:
# Specify the version you desire here
# See: https://circleci.com/developer/images/image/cimg/base
- image: cimg/base:current
orbs:
qqq-orb: kingsrook/qqq-orb@0.6.9
# Add steps to the job
# See: https://circleci.com/docs/guides/orchestrate/jobs-steps/#steps-overview & https://circleci.com/docs/reference/configuration-reference/#steps
steps:
# Checkout the code as the first step.
- checkout
- run:
name: "Say hello"
command: "echo Hello, World!"
commands:
configure-package-install:
steps:
- run:
name: Keep package installation unattended
command: |
# These build machines are discarded after the job.
sudo install -d /etc/needrestart/conf.d
printf '%s\n' '$nrconf{restart} = "l";' | sudo tee /etc/needrestart/conf.d/99-qqq-ci.conf >/dev/null
# Orchestrate jobs using workflows
# See: https://circleci.com/docs/guides/orchestrate/workflows/ & https://circleci.com/docs/reference/configuration-reference/#workflows
workflows:
say-hello-workflow: # This is the name of the workflow, feel free to change it to better match your workflow.
# Inside the workflow, you define the jobs you want to run.
jobs:
- say-hello
test_only:
jobs:
- qqq-orb/mvn_test_only:
pre-steps:
- configure-package-install
context: [qqq-maven-registry-credentials]
filters:
branches:
ignore: /(develop|release\/.*)/
publish_snapshot:
jobs:
- qqq-orb/mvn_publish:
pre-steps:
- configure-package-install
context: [qqq-maven-registry-credentials]
branch_type: snapshot
filters:
branches:
only: [develop]
publish_release_candidate:
jobs:
- qqq-orb/mvn_publish:
pre-steps:
- configure-package-install
context: [qqq-maven-registry-credentials]
branch_type: release_candidate
filters:
branches:
only: [/release\/.*/]
publish_release:
jobs:
- qqq-orb/mvn_publish:
pre-steps:
- configure-package-install
context: [qqq-maven-registry-credentials]
branch_type: release
filters:
branches:
ignore: /.*/
tags:
only: [/^v\d+\.\d+\.\d+$/]
@@ -67,8 +67,6 @@ public class ClusterNodesWidgetRenderer extends AbstractWidgetRenderer
static final String NODE = "node";
static final String STATUS = "status";
static final String HEARTBEAT = "heartbeat";
static final String WHERE = "where";
static final String VERSION = "version";
@@ -96,7 +94,7 @@ public class ClusterNodesWidgetRenderer extends AbstractWidgetRenderer
}
TableData table = new TableData(null, List.of(
column("Role", ROLE), column("Node", NODE), column("Status", STATUS), column("Last heartbeat", HEARTBEAT), column("Where", WHERE), column("Version", VERSION)), rows)
column("Role", ROLE), column("Node", NODE), column("Status", STATUS), column("Last heartbeat", HEARTBEAT)), rows)
.withNoRowsFoundHTML("No nodes are running. A node appears here once it starts with the Cluster qbit.")
.withRowsPerPage(50)
.withHidePaginationDropdown(true);
@@ -112,17 +110,29 @@ public class ClusterNodesWidgetRenderer extends AbstractWidgetRenderer
{
Map<String, Object> row = new LinkedHashMap<>();
row.put(ROLE, roleLabel(role));
row.put(NODE, node.getValueString(ClusterTables.NODE_ID));
row.put(NODE, nodeText(node));
row.put(STATUS, statusText(node));
row.put(HEARTBEAT, age(node.getValueInstant(ClusterTables.HEARTBEAT_AT), now));
row.put(WHERE, Stream.of(node.getValueString(ClusterTables.K8S_NODE_NAME), node.getValueString(ClusterTables.ZONE), node.getValueString(ClusterTables.DEPLOYMENT))
.filter(StringUtils::hasContent).collect(Collectors.joining(", ")));
row.put(VERSION, node.getValueString(ClusterTables.VERSION) == null ? "" : node.getValueString(ClusterTables.VERSION));
return (row);
}
/*******************************************************************************
** The node id, with where it runs and its version folded in (four columns
** keep the table readable at every width): "web-7f9 (k8s-2, website-backend, 0.1.110)".
*******************************************************************************/
static String nodeText(QRecord node)
{
String details = Stream.of(node.getValueString(ClusterTables.K8S_NODE_NAME), node.getValueString(ClusterTables.ZONE), node.getValueString(ClusterTables.DEPLOYMENT),
node.getValueString(ClusterTables.VERSION))
.filter(StringUtils::hasContent).collect(Collectors.joining(", "));
String nodeId = node.getValueString(ClusterTables.NODE_ID);
return (details.isEmpty() ? nodeId : nodeId + " (" + details + ")");
}
/*******************************************************************************
** "Up", "Draining", "Up, drain requested", "Lost".
*******************************************************************************/
@@ -118,7 +118,7 @@ class ClusterSettingsWidgetHealthTest extends BaseClusterTest
assertThat(rows.get(0).get("heartbeat")).isEqualTo("5 hours ago");
assertThat(rows.get(2).get("status")).isEqualTo("Up, drain requested");
assertThat(rows.get(3).get("heartbeat")).isEqualTo("3 minutes ago");
assertThat(table.getColumns()).hasSize(6);
assertThat(table.getColumns()).as("four columns: readable at every width").hasSize(4);
assertThat(lost).isNotNull();
assertThat(ClusterNodesWidgetRenderer.class).isNotNull();