diff --git a/.playwright-mcp/page-2026-03-24T18-41-08-535Z.png b/.playwright-mcp/page-2026-03-24T18-41-08-535Z.png new file mode 100644 index 00000000..84fe7248 Binary files /dev/null and b/.playwright-mcp/page-2026-03-24T18-41-08-535Z.png differ diff --git a/.playwright-mcp/page-2026-03-24T18-41-32-291Z.png b/.playwright-mcp/page-2026-03-24T18-41-32-291Z.png new file mode 100644 index 00000000..f9c6f1e3 Binary files /dev/null and b/.playwright-mcp/page-2026-03-24T18-41-32-291Z.png differ diff --git a/.playwright-mcp/page-2026-03-24T19-34-41-650Z.png b/.playwright-mcp/page-2026-03-24T19-34-41-650Z.png new file mode 100644 index 00000000..d7268502 Binary files /dev/null and b/.playwright-mcp/page-2026-03-24T19-34-41-650Z.png differ diff --git a/.playwright-mcp/page-2026-03-24T19-51-20-426Z.png b/.playwright-mcp/page-2026-03-24T19-51-20-426Z.png new file mode 100644 index 00000000..1a34b91a Binary files /dev/null and b/.playwright-mcp/page-2026-03-24T19-51-20-426Z.png differ diff --git a/.playwright-mcp/page-2026-03-24T19-53-00-560Z.png b/.playwright-mcp/page-2026-03-24T19-53-00-560Z.png new file mode 100644 index 00000000..17a798a9 Binary files /dev/null and b/.playwright-mcp/page-2026-03-24T19-53-00-560Z.png differ diff --git a/.superpowers/brainstorm/10188-1774613058/.server-stopped b/.superpowers/brainstorm/10188-1774613058/.server-stopped new file mode 100644 index 00000000..3e928a00 --- /dev/null +++ b/.superpowers/brainstorm/10188-1774613058/.server-stopped @@ -0,0 +1 @@ +{"reason":"idle timeout","timestamp":1774616238650} diff --git a/.superpowers/brainstorm/10188-1774613058/.server.pid b/.superpowers/brainstorm/10188-1774613058/.server.pid new file mode 100644 index 00000000..a7fe8fa4 --- /dev/null +++ b/.superpowers/brainstorm/10188-1774613058/.server.pid @@ -0,0 +1 @@ +10188 diff --git a/.superpowers/brainstorm/10188-1774613058/component-hierarchy.html b/.superpowers/brainstorm/10188-1774613058/component-hierarchy.html new file mode 100644 index 00000000..121fd7a5 --- /dev/null +++ b/.superpowers/brainstorm/10188-1774613058/component-hierarchy.html @@ -0,0 +1,105 @@ +

ProcessDiagram Component Hierarchy

+

How the SVG rendering is structured — from data fetch to pixels

+ +
+
+
Component Tree
+
+
ProcessDiagram — root, fetches layout, manages state
+
+
<svg> container with viewBox (zoom/pan transforms)
+
+
DiagramSection label="Main Route"
+
+
<g> edges layer (rendered first, behind nodes)
+
+
DiagramEdge × N — SVG <path> with arrowhead
+
+
<g> nodes layer
+
+
DiagramNode × N — top-bar card
+
+
ConfigBadge × 0..N — tap/trace indicators
+
NodeToolbar — floating on hover
+
+
CompoundNode × 0..N — choice/split container
+
+
DiagramNode × N — children inside compound
+
+
+
+
DiagramSection label="onException" variant="error"
+
+
same edge + node structure as above
+
+
+
ZoomControls — HTML overlay (not SVG)
+
+
+
+
+ +
+
+
SVG Structure (simplified)
+
+
<div class="process-diagram">            /* wrapper div */
+  <svg viewBox="0 0 {w} {h}">            /* zoom = viewBox transform */
+    <g class="diagram-content">           /* pan offset */
+
+      <!-- Main Route section -->
+      <g class="section section--main">
+        <g class="edges">
+          <path d="M 100 40 C ..." />     /* cubic bezier edge */
+          <marker>...</marker>             /* arrowhead def */
+        </g>
+        <g class="nodes">
+          <g transform="translate(x, y)"> /* positioned by ELK */
+            <rect .../>                    /* card background */
+            <rect .../>                    /* color top bar */
+            <text>LOG</text>              /* label */
+            <g class="badges">...</g>     /* config indicators */
+          </g>
+        </g>
+      </g>
+
+      <!-- Error Handler section -->
+      <g class="section section--error"
+         transform="translate(0, {mainH + gap})">
+        <text>onException</text>          /* section label */
+        <line .../>                        /* divider line */
+        <g class="edges">...</g>
+        <g class="nodes">...</g>
+      </g>
+
+    </g>
+  </svg>
+  <div class="zoom-controls">...</div>    /* HTML overlay */
+</div>
+
+
+
+ +
+
+
Data Flow
+
+
+GET /diagrams/{hash}/render?direction=LR
+        │
+        ▼
+  DiagramLayout { nodes[], edges[], width, height }
+        │
+        ▼
+  separateFlows(nodes)  →  mainNodes[] + errorSections[]
+        │                       │
+        ▼                       ▼
+  renderMainSection()    renderErrorSection()
+        │                       │
+        ▼                       ▼
+  SVG groups with              SVG groups offset below
+  ELK x/y coordinates         main section by mainHeight + gap
+
+
+
+
\ No newline at end of file diff --git a/.superpowers/brainstorm/10188-1774613058/interactions-detail.html b/.superpowers/brainstorm/10188-1774613058/interactions-detail.html new file mode 100644 index 00000000..56b36425 --- /dev/null +++ b/.superpowers/brainstorm/10188-1774613058/interactions-detail.html @@ -0,0 +1,164 @@ +

Node Interactions & Config Badges

+

Hover toolbar, selection states, and active config indicators

+ +
+
+
Node States
+
+ + + + NORMAL + + + + + + LOG + Processing order + + + + HOVERED (toolbar appears) + + + + + + LOG + Processing order + + + + + + + 🔍 + + + + T + + + + + + + + + + + + + + SELECTED (click) + + + + + + + LOG + Processing order + + + + WITH CONFIG BADGES + + + + + + LOG + Processing order + + + + TRACE + + + + + TAP + + + + + ERROR HANDLER NODE + + + + + + ON_EXCEPTION + java.lang.Exception + + + + COMPOUND NODE (CHOICE) + + + + + ◆ CHOICE + + + + + + + WHEN + type == 'A' + + + + + + + OTHERWISE + + + + +
+
+
+ +
+
+
Toolbar Actions
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IconActionDescription
🔍InspectSelect node & open detail side-panel
TToggle TraceEnable/disable capture of input+output for this processor
Configure TapOpen tap expression editor for this processor
MoreCopy processor ID, jump to code, view in search
+
+
+
\ No newline at end of file diff --git a/.superpowers/brainstorm/10188-1774613058/node-interactions.html b/.superpowers/brainstorm/10188-1774613058/node-interactions.html new file mode 100644 index 00000000..445e0bfb --- /dev/null +++ b/.superpowers/brainstorm/10188-1774613058/node-interactions.html @@ -0,0 +1,119 @@ +

Node Interaction Model

+

What happens when you interact with a processor node on the diagram?

+ +
+ +
+
+ + + + + + + + LOG + Processing order + normal state + + + + + + + + + + LOG + Processing order + click = select + + + + + + + + + LOG + Processing order + + + + 🔍 View Snapshot + + ⚙ Enable Tracing + 📌 Set Tap + + 📋 Copy Processor ID + + right-click = context menu + + + + + + + + +
+
+

A: Click-Select + Right-Click Menu

+

Click to select a node (amber highlight ring). Right-click for context menu with tracing/tap/snapshot actions. Clean separation of concerns. Standard desktop UX.

+
+
+ + +
+
+ + + + + + + + LOG + Processing order + normal state + + + + + + + + + LOG + Processing order + + + + 🔍 + + 📌 + 📋 + + + hover = toolbar appears + + + + + + + + + + LOG + Processing order + click = select + + +
+
+

B: Hover Floating Toolbar

+

Hover reveals a dark floating icon toolbar above the node. Click still selects. More discoverable than right-click, but can feel cluttered on dense diagrams.

+
+
+
\ No newline at end of file diff --git a/.superpowers/brainstorm/10188-1774613058/node-style.html b/.superpowers/brainstorm/10188-1774613058/node-style.html new file mode 100644 index 00000000..271e60ff --- /dev/null +++ b/.superpowers/brainstorm/10188-1774613058/node-style.html @@ -0,0 +1,208 @@ +

Node Visual Style

+

Which processor node style fits our design system best? Think MuleSoft / TIBCO BW5 but adapted to our warm parchment theme.

+ +
+ +
+
+ + + + + + + + FROM + direct:orders + + + + + + + + + + + LOG + Processing order + + + + + + + + + + + TO + kafka:processed + + + + + + CHOICE + + + + + + + WHEN + header.type == 'A' + + + + + + + + OTHERWISE + default branch + + + +
+
+

A: Icon Sidebar Blocks

+

MuleSoft-style: colored icon strip on the left, label + detail on the right. Color encodes node type. Compound nodes (choice, split) use dashed containers.

+
+
+ + +
+
+ + + + + + + FROM + direct:orders + + + + + + + + + + LOG + Processing order + + + + + + + + + + TO + kafka:processed + + + + + + CHOICE + + + + + + WHEN + type == 'A' + + + + + + + OTHERWISE + default + + + +
+
+

B: Rounded Pills

+

Softer, more modern look with pill-shaped nodes and circular icons. Lighter feel. Compounds still use dashed containers.

+
+
+ + +
+
+ + + + + + + + FROM + direct:orders + + + + + + + + + + + LOG + Processing order + + + + + + + + + + + TO + kafka:processed + + + + + + + + CHOICE + + + + + + + WHEN + type == 'A' + + + + + + + + OTHERWISE + default + + + +
+
+

C: Top-Bar Cards

+

TIBCO BW5-inspired: white cards with colored top accent bar. Clean, professional, card-like. Compound nodes get a full colored header bar with white title text.

+
+
+
\ No newline at end of file diff --git a/.superpowers/brainstorm/10188-1774613058/waiting.html b/.superpowers/brainstorm/10188-1774613058/waiting.html new file mode 100644 index 00000000..f92c257a --- /dev/null +++ b/.superpowers/brainstorm/10188-1774613058/waiting.html @@ -0,0 +1,3 @@ +
+

Continuing in terminal...

+
\ No newline at end of file diff --git a/.superpowers/brainstorm/14618-1774629192/.server-stopped b/.superpowers/brainstorm/14618-1774629192/.server-stopped new file mode 100644 index 00000000..27a3aaad --- /dev/null +++ b/.superpowers/brainstorm/14618-1774629192/.server-stopped @@ -0,0 +1 @@ +{"reason":"idle timeout","timestamp":1774632733532} diff --git a/.superpowers/brainstorm/14618-1774629192/.server.pid b/.superpowers/brainstorm/14618-1774629192/.server.pid new file mode 100644 index 00000000..cc71cea6 --- /dev/null +++ b/.superpowers/brainstorm/14618-1774629192/.server.pid @@ -0,0 +1 @@ +14618 diff --git a/.superpowers/brainstorm/14618-1774629192/detail-panel-tabs.html b/.superpowers/brainstorm/14618-1774629192/detail-panel-tabs.html new file mode 100644 index 00000000..2938d77f --- /dev/null +++ b/.superpowers/brainstorm/14618-1774629192/detail-panel-tabs.html @@ -0,0 +1,287 @@ +

Detail Panel: Tab Designs

+

Bottom panel content when a processor node is selected

+ +
+
Info Tab — processor metadata + attributes
+
+ +
+ bean:validate + FAILED + processor-5 +
+ +
+
Info
+
Headers
+
Input
+
Output
+
Error
+
Config
+
Timeline
+
+ +
+
+
Processor ID
+
processor-5
+
+
+
Type
+
BEAN
+
+
+
Status
+
FAILED
+
+
+
Start Time
+
14:32:05.123
+
+
+
End Time
+
14:32:05.243
+
+
+
Duration
+
120ms
+
+
+
Endpoint URI
+
bean:orderValidator?method=validate
+
+
+
Resolved URI
+
bean://com.example.OrderValidator?method=validate
+
+ +
+
Attributes
+
+ orderId: ORD-1234 + customer: Acme Corp + priority: HIGH +
+
+
+
+
+ +
+ +
+
Headers Tab — input vs output side by side
+
+
+ log:incoming + COMPLETED + processor-2 +
+
+
Info
+
Headers
+
Input
+
Output
+
Error
+
Config
+
Timeline
+
+ +
+ +
+
Input Headers
+ + + + + + + + + + + + + + + + + +
Content-Typeapplication/json
JMSMessageIDID:broker-42
breadcrumbIdabc-123-def
CamelHttpMethodPOST
+
+ +
+
Output Headers
+ + + + + + + + + + + + + + + + + + + + + +
Content-Typeapplication/json
JMSMessageIDID:broker-42
breadcrumbIdabc-123-def
CamelHttpMethodPOST
orderStatusvalidated (new)
+
+
+
+
+ +
+ +
+
Input Tab — formatted message body
+
+
+ log:incoming + COMPLETED + processor-2 · 5ms +
+
+
Info
+
Headers
+
Input
+
Output
+
Error
+
Config
+
Timeline
+
+ +
+
+ JSON · 234 bytes + +
+
{
+  "orderId": "ORD-1234",
+  "customer": {
+    "name": "Acme Corp",
+    "id": 42
+  },
+  "items": [
+    {
+      "product": "Widget A",
+      "quantity": 5,
+      "price": 29.99
+    }
+  ],
+  "priority": "HIGH"
+}
+
+
+
+ +
+ +
+
Timeline Tab — Gantt-style processor durations
+
+
+ content-based-routing + FAILED + 247ms total +
+
+
Info
+
Headers
+
Input
+
Output
+
Error
+
Config
+
Timeline
+
+ +
+ +
+ 0ms50ms100ms150ms200ms247ms +
+ +
+ +
+ from:jms +
+
+
+ 2ms +
+ +
+ log +
+
+
+ 5ms +
+ +
+ setHeader +
+
+
+ 1ms +
+ +
+ bean:validate +
+
+
+ 120ms +
+ +
+ to:http +
+ +
+ +
+ to:jms +
+ +
+
+
Click a bar to select that processor in the diagram
+
+
+
+ +
+ +
+
Error Tab — grayed out when no error on selected processor
+
+
+ log:incoming + COMPLETED + processor-2 · 5ms +
+
+
Info
+
Headers
+
Input
+
Output
+
Error
+
Config
+
Timeline
+
+
+ No error on this processor +
+
+
diff --git a/.superpowers/brainstorm/14618-1774629192/execution-overlay-design.html b/.superpowers/brainstorm/14618-1774629192/execution-overlay-design.html new file mode 100644 index 00000000..3184c7a0 --- /dev/null +++ b/.superpowers/brainstorm/14618-1774629192/execution-overlay-design.html @@ -0,0 +1,207 @@ +

Execution Overlay: Full Design Mockup

+

ExecutionDiagram component — diagram with execution overlay + detail panel

+ +
+
ExecutionDiagram — Failed Exchange View
+
+ +
+ Exchange + abc-123-def-456 + FAILED + sample-app / content-based-routing + 247ms +
+ +
+
+ + +
+ + +
+ + + + +
+ +
+ + +
+
+
+
+
from:jms:orders
+
ENDPOINT
+
+
+
2ms
+
+ + + + + +
+
+
+
+
log:incoming
+
LOG
+
+
+
5ms
+
+ + + + + +
+ +
CHOICE
+
+ +
+
WHEN: header.type == 'A'
+
+ +
+
+
+
+
bean:validate
+
FAILED
+
+
+
120ms
+ +
!
+
+ + + + +
+
+
+
+
to:http:api
+
TO
+
+
+
+
+
+ + +
+
OTHERWISE
+
+
+
+
to:direct:alt
+
DIRECT
+
+
+
+
+
+
+
+ + +
+ + 100% + + +
+ + +
+
+
+
+
+
+
+
+
+
+ + +
+ + +
+ +
+ bean:validate + FAILED + processor-5 · 120ms +
+ + +
+
Info
+
Headers
+
Input
+
Output
+
Error
+
Config
+
Timeline
+
+ + +
+
+
Exception
+
javax.validation.ValidationException
+
+
+
Message
+
Order quantity must be positive: received -3
+
+
+
Root Cause
+
java.lang.IllegalArgumentException: quantity must be > 0
+
+
+
Stack Trace
+
at com.example.OrderValidator.validate(OrderValidator.java:42)
+at com.example.OrderRoute.process(OrderRoute.java:18)
+at org.apache.camel.processor.DelegateSyncProcessor.process(...)
+at org.apache.camel.processor.Pipeline.process(Pipeline.java:184)
+... 8 more
+
+
+
+
+
+
+ +
+

Design Decisions Shown

+
+
+ Executed (OK)
+ Green left border, duration badge bottom-right +
+
+ Failed
+ Red border, red tint background, red ! badge top-right +
+
+ Not Executed
+ Dimmed to 35% opacity — full topology visible +
+
+ Selected
+ Amber ring (existing), detail panel updates below +
+
+
diff --git a/.superpowers/brainstorm/14618-1774629192/iteration-stepper.html b/.superpowers/brainstorm/14618-1774629192/iteration-stepper.html new file mode 100644 index 00000000..ad9bee76 --- /dev/null +++ b/.superpowers/brainstorm/14618-1774629192/iteration-stepper.html @@ -0,0 +1,143 @@ +

Per-Compound Iteration Stepper

+

Each loop/split compound gets its own stepper in the header bar

+ +
+
Loop with iteration stepper — iteration 3 of 5
+
+ + +
+ +
+ LOOP + +
+ + 3 / 5 + +
+
+ + +
+ +
+
+
+
+
transform
+
TRANSFORM
+
+
+
3ms
+
+
+ + + + +
+
+
+
+
to:http:api
+
TO
+
+
+
45ms
+
+
+ + + + +
+
+
+
+
log:result
+
LOG
+
+
+
1ms
+
+
+
+
+
+
+ +

Nested Loops

+

Each compound level has its own independent stepper

+ +
+
Outer loop (iteration 2/3) containing inner split (branch 1/4)
+
+ + +
+
+ LOOP +
+ + 2 / 3 + +
+
+ +
+
+ + +
+
+
+
+
setBody
+
SET_BODY
+
+
+
+
+ + + + +
+
+ SPLIT +
+ + 1 / 4 + +
+
+
+
+
+
+
+
to:kafka
+
TO
+
+
+
+
+
+
+
+
+
+
+
+ +

Stepper Behavior

+
+ +
diff --git a/.superpowers/brainstorm/14618-1774629192/layout-overview.html b/.superpowers/brainstorm/14618-1774629192/layout-overview.html new file mode 100644 index 00000000..ae786a80 --- /dev/null +++ b/.superpowers/brainstorm/14618-1774629192/layout-overview.html @@ -0,0 +1,166 @@ +

Execution Overlay: Page Layout

+

How should the diagram + execution details be arranged?

+ +
+ +
+
+
+ +
+ +
+
DIAGRAM
+ +
+
from:jms
+
+
log
+
+
bean
+
+
to:http
+
+ +
100%
+ +
Loop 2/5
+
+ +
+ +
+
+ Input + Output + Headers + Error + Timeline +
+
+
{"orderId": "ORD-1234",
+
 "product": "Widget A",
+
 "quantity": 5}
+
+
+
+
+
+
+

A: Top/Bottom Split (IDE Style)

+

Diagram on top, tabbed detail panel below. Resizable splitter between them. Maximizes diagram width. Tabs: Input, Output, Headers, Error, Timeline.

+
+

Pros

  • Full diagram width
  • Familiar IDE pattern
  • Detail panel always visible
+

Cons

  • Vertical space shared
  • Diagram shrinks on small screens
+
+
+
+ + +
+
+
+
+ +
+
DIAGRAM
+
+
from:jms
+
+
log
+
+
bean
+
+
100%
+
+ +
+ +
+
log (processor-3)
+
COMPLETED - 12ms
+
+
+ Input + Output + Headers +
+
+
+
{"orderId": "ORD-1234",
+
 "product": "Widget A",
+
 "quantity": 5,
+
 "price": 29.99}
+
+
+
+
+
+
+

B: Left/Right Split

+

Diagram on left, collapsible detail panel on right. Slide-in when node selected. Diagram keeps full height.

+
+

Pros

  • Full diagram height
  • Panel can collapse
  • Good for wide screens
+

Cons

  • Steals diagram width
  • Tight on narrow screens
+
+
+
+ + +
+
+
+
+ +
+
DIAGRAM
+
+
from:jms
+
+
log
+
+
bean
+
+
to:http
+
+
100%
+
+ +
+
+ +
+
Processors
+
+
from:jms - 2ms
+
log - 12ms
+
bean - FAILED
+
to:http - skipped
+
+
+ +
+
+ Input + Output + Headers +
+
+
{"orderId": "ORD-1234",
+
 "product": "Widget A"}
+
+
+
+
+
+
+
+

C: Top/Bottom with Processor List

+

Diagram on top, bottom split into processor list (left) + detail tabs (right). Clicking processor in list or diagram syncs selection. Most information density.

+
+

Pros

  • Processor list as navigation
  • Full diagram width
  • Maximum information density
+

Cons

  • More complex layout
  • May feel crowded
+
+
+
+
diff --git a/.superpowers/brainstorm/14618-1774629192/overlay-intensity.html b/.superpowers/brainstorm/14618-1774629192/overlay-intensity.html new file mode 100644 index 00000000..43e3cd25 --- /dev/null +++ b/.superpowers/brainstorm/14618-1774629192/overlay-intensity.html @@ -0,0 +1,190 @@ +

Execution Overlay: Visual Intensity Comparison

+

How strong should the overlay tinting be?

+ +
+ +
+
Current: Subtle (border only)
+
+
+ +
+ Completed +
+
+
+
from:jms:orders
+
ENDPOINT
+
+
2ms
+
+
+ +
+ Failed +
+
+
+
bean:validate
+
BEAN
+
+
120ms
+
!
+
+
+ +
+ Skipped +
+
+
+
to:http:api
+
TO
+
+
+
+
+
+
+ + +
+
Proposed: Tinted backgrounds
+
+
+ +
+ Completed +
+
+
+
from:jms:orders
+
ENDPOINT
+
+
2ms
+
+
+ +
+ Failed +
+
+
+
bean:validate
+
FAILED
+
+
120ms
+
!
+
+
+ +
+ Skipped +
+
+
+
to:http:api
+
TO
+
+
+
+
+
+
+
+ +

Full Flow Comparison

+

Same route, tinted version — see how it reads at a glance

+ +
+
Tinted overlay on a full route
+
+
+ + +
+
+
+
+
from:jms:orders
+
ENDPOINT
+
+
+
2ms
+
+ + + + +
+
+
+
+
log:incoming
+
LOG
+
+
+
5ms
+
+ + + + +
+
+
+
+
setHeader:type
+
SET_HEADER
+
+
+
1ms
+
+ + + + +
+
+
+
+
bean:validate
+
FAILED
+
+
+
120ms
+
!
+
+ + + + +
+
+
+
+
to:http:api
+
TO
+
+
+
+ + + + +
+
+
+
+
to:jms:result
+
TO
+
+
+
+
+ +
+ Note: Edges between executed nodes turn green. Edges leading to skipped nodes become dashed gray. +
+
+
diff --git a/.superpowers/brainstorm/14618-1774629192/overlay-with-markers.html b/.superpowers/brainstorm/14618-1774629192/overlay-with-markers.html new file mode 100644 index 00000000..5d832e6c --- /dev/null +++ b/.superpowers/brainstorm/14618-1774629192/overlay-with-markers.html @@ -0,0 +1,159 @@ +

Execution Overlay: Success + Error Markers

+

Every executed node gets a status badge — green check or red exclamation

+ +
+
Full route with status markers
+
+
+ + +
+
+
+
+
from:jms:orders
+
ENDPOINT
+
+
+
2ms
+ +
+
+ + + + +
+
+
+
+
log:incoming
+
LOG
+
+
+
5ms
+
+
+ + + + +
+
+
+
+
setHeader:type
+
SET_HEADER
+
+
+
1ms
+
+
+ + + + +
+
+
+
+
bean:validate
+
FAILED
+
+
+
120ms
+ +
!
+
+ + + + +
+
+
+
+
to:http:api
+
TO
+
+
+
+ + + + +
+
+
+
+
to:jms:result
+
TO
+
+
+
+
+
+
+ +

Node State Legend

+
+ + +
+
+
+
5ms
+
+
+
Completed
+
Green tint + border + check badge + duration
+
+
+ + +
+
+
!
+
120ms
+
+
+
Failed
+
Red tint + border + ! badge + duration
+
+
+ + +
+
+
!
+
+
85ms
+
+
+
Sub-route Failure
+
Same as failed + drill-down arrow
+
+
+ + +
+
+
+
+
Skipped
+
35% opacity, no badge, no duration
+
+
+
+ +

Edge States

+
+
+ +
Traversed — green, solid
+
+
+ +
Not traversed — gray, dashed
+
+
diff --git a/.superpowers/brainstorm/14618-1774629192/waiting.html b/.superpowers/brainstorm/14618-1774629192/waiting.html new file mode 100644 index 00000000..ef076525 --- /dev/null +++ b/.superpowers/brainstorm/14618-1774629192/waiting.html @@ -0,0 +1,3 @@ +
+

Continuing in terminal...

+
diff --git a/.superpowers/brainstorm/2048-1774541143/content/appconfig-detail-new-sections.html b/.superpowers/brainstorm/2048-1774541143/content/appconfig-detail-new-sections.html new file mode 100644 index 00000000..877b9891 --- /dev/null +++ b/.superpowers/brainstorm/2048-1774541143/content/appconfig-detail-new-sections.html @@ -0,0 +1,181 @@ +

AppConfigDetailPage — New Sections

+

Taps overview, route recording map, and compress success toggle added to existing config page

+ +
+
AppConfigDetailPage — Full Layout (scrollable)
+
+ + +
+ + order-service + v14 · Updated 3 min ago +
+ +
+
+ + +
+
Logging
+
+
+
Log Forwarding Level
+ INFO +
+
+
+ + +
+
Observability
+
+
+
Engine Level
+ REGULAR +
+
+
Payload Capture
+ BOTH +
+
+
Metrics
+ ON +
+
+
Sampling Rate
+ 1.0 +
+
+
Compress Success
+ OFF +
+
+
+ + +
+
Traced Processors
+
2 processors with custom capture modes
+ + + + + + + + + + + + + + + + + +
Processor IDCapture Mode
unmarshal1BOTH
toDatabaseINPUT
+
+ + +
+
+
Data Extraction Taps
+ 3 taps · manage on route pages +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeProcessorExpressionLanguageEnabled
orderIdunmarshal1${body.orderId}simple
customerIdunmarshal1${body.customer.id}simple
orderTotalenrichPrice$.totaljsonpath
+
+ + +
+
+
Route Recording
+ 4 of 5 routes recording +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RouteRecording
processOrder +
+
+
+
processPayment +
+
+
+
sendNotification +
+
+
+
handleRefund +
+
+
+
healthCheck +
+
+
+
+
+ +
+
diff --git a/.superpowers/brainstorm/2048-1774541143/content/appconfig-final-layout.html b/.superpowers/brainstorm/2048-1774541143/content/appconfig-final-layout.html new file mode 100644 index 00000000..b35590a2 --- /dev/null +++ b/.superpowers/brainstorm/2048-1774541143/content/appconfig-final-layout.html @@ -0,0 +1,149 @@ +

AppConfigDetailPage — Final Layout

+

Three clean sections: Settings, Traces & Taps, Route Recording

+ +
+
AppConfigDetailPage — Complete
+
+ + +
+ + order-service + v14 · Updated 3 min ago +
+ +
+
+ + +
+
Settings
+
+
+
Log Forwarding
+ INFO +
+
+
Engine Level
+ REGULAR +
+
+
Payload Capture
+ BOTH +
+
+
Metrics
+ ON +
+
+
Sampling Rate
+ 1.0 +
+
+
Compress Success
+ OFF +
+
+
+ + +
+
+
Traces & Taps
+ 2 traced · 3 taps · manage taps on route pages +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ProcessorCaptureTaps
unmarshal1BOTH +
+ orderId + customerId +
+
toDatabaseINPUT
enrichPrice + orderTotal +
+
+ + +
+
+
Route Recording
+ 4 of 5 routes recording +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RouteRecording
processOrder +
+
+
+
processPayment +
+
+
+
sendNotification +
+
+
+
handleRefund +
+
+
+
healthCheck +
+
+
+
+
+ +
+
diff --git a/.superpowers/brainstorm/2048-1774541143/content/appconfig-traces-taps-merged.html b/.superpowers/brainstorm/2048-1774541143/content/appconfig-traces-taps-merged.html new file mode 100644 index 00000000..f3766181 --- /dev/null +++ b/.superpowers/brainstorm/2048-1774541143/content/appconfig-traces-taps-merged.html @@ -0,0 +1,77 @@ +

AppConfigDetailPage — Merged "Traces & Taps" Section

+

Single table combining traced processors and data extraction taps

+ +
+
Traces & Taps — Merged Table
+
+ +
+
+
Traces & Taps
+ 2 traced · 3 taps · manage taps on route pages +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ProcessorCaptureTaps
unmarshal1 + BOTH + +
+ orderId + customerId +
+
toDatabase + INPUT + + +
enrichPrice + + +
+ orderTotal +
+
+
+ +
+
+ +
+ +
+

Design Notes

+ +
diff --git a/.superpowers/brainstorm/2048-1774541143/content/exchange-detail-mockup.html b/.superpowers/brainstorm/2048-1774541143/content/exchange-detail-mockup.html new file mode 100644 index 00000000..ca06e2e4 --- /dev/null +++ b/.superpowers/brainstorm/2048-1774541143/content/exchange-detail-mockup.html @@ -0,0 +1,150 @@ +

ExchangeDetail — Business Attributes & Replay

+

New elements added to the existing exchange detail page

+ +
+
Exchange Detail Page — Header Card (enhanced)
+
+ + +
+
+
+ + a1b2c3d4-e5f6-7890-abcd-ef1234567890 + COMPLETED +
+
+ Route: processOrder + App: order-service + Correlation: corr-abc123 +
+
+
+ + +
+
+ + +
+ Attributes + orderId: ORD-2024-78542 + customerId: CUST-1234 + orderTotal: €149.90 + region: EU-WEST +
+ + +
+
+
Duration
+
245ms
+
+
+
Agent
+
order-svc-01
+
+
+
Started
+
14:23:45.123
+
+
+
Processors
+
12
+
+
+
+
+ +
+ +
+
Replay Confirmation Dialog
+
+
+
+ Replay Exchange + +
+
+ This will re-execute the exchange on the target agent. The original exchange data will be used as input. +
+
+
Original Exchange
+
a1b2c3d4-e5f6-7890-abcd-ef1234567890
+
+
+
Target Agent
+
+ order-svc-01 + +
+
+
+
Route
+
processOrder
+
+
+ + +
+
+
+
+ +
+ +
+
Dashboard — Exchanges Table (with business attributes)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StatusRouteAppAttributesExchange IDDuration
OKprocessOrderorder-svc + ORD-78542 + CUST-1234 + a1b2c3d4-e5f6…245ms
ERRprocessPaymentpayment-svc + PAY-91023 + +2 + f8e7d6c5-b4a3…1,234ms
OKsendNotificationnotif-svc12345678-abcd…89ms
+
+ Note: Attributes column shows first 2 values as compact badges, "+N" overflow indicator when more exist. Em-dash when no attributes extracted. +
+
+
diff --git a/.superpowers/brainstorm/2048-1774541143/content/replay-dialog-v2.html b/.superpowers/brainstorm/2048-1774541143/content/replay-dialog-v2.html new file mode 100644 index 00000000..86785ce1 --- /dev/null +++ b/.superpowers/brainstorm/2048-1774541143/content/replay-dialog-v2.html @@ -0,0 +1,138 @@ +

Replay Dialog — Revised

+

Target agent selection + editable payload and headers

+ +
+
Replay Exchange Dialog (large modal)
+
+
+ + +
+ Replay Exchange + +
+ +
+ +
+ This will re-execute the exchange on the selected agent. +
+ + +
+
Target Agent
+
+ order-svc-01 + +
+
Only LIVE agents for this application are shown
+
+ + +
+
Headers
+
Body
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + +
KeyValue
+ + Add header +
+
+
+ + +
+ + +
+
+
+
+ +
+ +
+
Replay Dialog — Body Tab
+
+
+ + +
+ Replay Exchange + +
+ +
+ +
+ This will re-execute the exchange on the selected agent. +
+ + +
+
Target Agent
+
+ order-svc-01 + +
+
+ + +
+
Headers
+
Body
+
+ + +
+
+ JSON +
+
{
+  "orderId": "ORD-2024-78542",
+  "customerId": "CUST-1234",
+  "items": [
+    {
+      "sku": "WIDGET-001",
+      "qty": 3,
+      "price": 49.97
+    }
+  ],
+  "total": 149.90
+}
+
+
+ + +
+ + +
+
+
+
diff --git a/.superpowers/brainstorm/2048-1774541143/content/route-detail-taps.html b/.superpowers/brainstorm/2048-1774541143/content/route-detail-taps.html new file mode 100644 index 00000000..b9849034 --- /dev/null +++ b/.superpowers/brainstorm/2048-1774541143/content/route-detail-taps.html @@ -0,0 +1,221 @@ +

RouteDetail — Tap Management & Recording Toggle

+

New "Taps" tab on RouteDetail + recording toggle in header

+ +
+
RouteDetail Page — Header with Recording Toggle
+
+ + +
+
+
processOrder
+
+ order-service + | + 99.2% success + | + 245ms avg +
+
+
+ +
+ Recording +
+
+
+
+
+
+ + +
+
+
Success Rate
+
99.2%
+
+
+
Avg Duration
+
245ms
+
+
+
Total
+
12,482
+
+
+
Active Taps
+
3
+
+
+ + +
+
Overview
+
Processors
+
Errors
+
Executions
+
Taps
+
+ + +
+
Data Extraction Taps
+ +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeProcessorExpressionLanguageTargetTypeEnabled
orderIdunmarshal1${body.orderId}simpleOUTPUTBUSINESS +
+
+
+
+ + +
customerIdunmarshal1${body.customer.id}simpleOUTPUTCORRELATION +
+
+
+
+ + +
orderTotalenrichPrice$.totaljsonpathOUTPUTBUSINESS +
+
+
+
+ + +
+
+
+
+ +
+ +
+
Add/Edit Tap — Modal Dialog
+
+
+ + +
+ Add Tap + +
+ +
+ +
+
Attribute Name *
+ +
+ + +
+
Processor *
+
+ Select processor… + +
+
Processors from this route's diagram
+
+ + +
+
+
Language *
+
+ simple + +
+
+
+
Target *
+
+ OUTPUT + +
+
+
+ + +
+
Expression *
+ +
Camel expression — evaluated at the selected processor
+
+ + +
+
Attribute Type
+
+
BUSINESS_OBJECT
+
CORRELATION
+
EVENT
+
CUSTOM
+
+
+ + +
+
+
+
+ Enabled +
+
+ + +
+ + +
+
+
+
diff --git a/.superpowers/brainstorm/2048-1774541143/content/tap-test-expression.html b/.superpowers/brainstorm/2048-1774541143/content/tap-test-expression.html new file mode 100644 index 00000000..8beadf39 --- /dev/null +++ b/.superpowers/brainstorm/2048-1774541143/content/tap-test-expression.html @@ -0,0 +1,175 @@ +

Add Tap — With Expression Testing

+

Collapsible test section at bottom of the tap modal

+ +
+
Add Tap Modal — Test Expression (Recent Exchange)
+
+
+ + +
+ Add Tap + +
+ +
+ +
+
Attribute Name *
+ +
+ +
+
Processor *
+
+ unmarshal1 + +
+
+ +
+
+
Language
+
+ simple +
+
+
+
Target
+
+ OUTPUT +
+
+
+ +
+
Expression *
+ +
+ +
+
Attribute Type
+
+
BUSINESS_OBJECT
+
CORRELATION
+
EVENT
+
CUSTOM
+
+
+ + +
+
+ + Test Expression +
+ + +
+
Recent Exchange
+
Custom Payload
+
+ + +
+
+
+
+ + a1b2c3d4-e5f6-7890 + · + 245ms + · + 2 min ago +
+ +
+
+ + +
+ +
+
Result
+
ORD-2024-78542
+
+
+
+
+
+ + +
+ + +
+
+
+
+ +
+ +
+
Test Expression — Custom Payload Mode
+
+
+ + +
+ Add Tap + +
+ +
+ +
+ ⬆ Form fields above (attribute name, processor, language, target, expression, type) +
+ + +
+
+ + Test Expression +
+ + +
+
Recent Exchange
+
Custom Payload
+
+ + +
+
+ +
+ + +
+ +
+
Error
+
Expression evaluation timed out (50ms limit)
+
+
+
Evaluated by agent order-svc-01 using Camel's simple language
+
+
+
+ + +
+ + +
+
+
+
diff --git a/.superpowers/brainstorm/2048-1774541143/content/traces-taps-with-route.html b/.superpowers/brainstorm/2048-1774541143/content/traces-taps-with-route.html new file mode 100644 index 00000000..853c15f7 --- /dev/null +++ b/.superpowers/brainstorm/2048-1774541143/content/traces-taps-with-route.html @@ -0,0 +1,61 @@ +

Traces & Taps — With Route Column

+

Route column added to prevent ambiguity across routes

+ +
+
Traces & Taps — Updated
+
+ +
+
+
Traces & Taps
+ 3 traced · 4 taps · manage taps on route pages +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RouteProcessorCaptureTaps
processOrderunmarshal1BOTH +
+ orderId + customerId +
+
processOrderenrichPrice + orderTotal +
processPaymenttoDatabaseINPUT
processPaymentvalidate1 + paymentRef +
+
+ +
+
diff --git a/.superpowers/brainstorm/2048-1774541143/content/waiting.html b/.superpowers/brainstorm/2048-1774541143/content/waiting.html new file mode 100644 index 00000000..f92c257a --- /dev/null +++ b/.superpowers/brainstorm/2048-1774541143/content/waiting.html @@ -0,0 +1,3 @@ +
+

Continuing in terminal...

+
\ No newline at end of file diff --git a/.superpowers/brainstorm/2048-1774541143/state/server-stopped b/.superpowers/brainstorm/2048-1774541143/state/server-stopped new file mode 100644 index 00000000..a38defed --- /dev/null +++ b/.superpowers/brainstorm/2048-1774541143/state/server-stopped @@ -0,0 +1 @@ +{"reason":"idle timeout","timestamp":1774552065018} diff --git a/.superpowers/brainstorm/2048-1774541143/state/server.pid b/.superpowers/brainstorm/2048-1774541143/state/server.pid new file mode 100644 index 00000000..c873496a --- /dev/null +++ b/.superpowers/brainstorm/2048-1774541143/state/server.pid @@ -0,0 +1 @@ +2048 diff --git a/UI_FINDINGS.md b/UI_FINDINGS.md new file mode 100644 index 00000000..ee01397c --- /dev/null +++ b/UI_FINDINGS.md @@ -0,0 +1,294 @@ +# UI/UX Evaluation Report — Cameleer3 Server + +**Date:** 2026-03-25 +**Evaluated URL:** http://192.168.50.86:30090/ +**Methodology:** Playwright-driven navigation of all major pages (14 screenshots), evaluated by 3 specialist agents: Visual Design, Information Architecture & Usability, Readability & Accessibility. + +--- + +## Executive Summary + +The Cameleer3 dashboard has a **distinctive, well-crafted warm amber design language** that stands out in the observability space. The core monitoring pages (Dashboard, Exchange Detail, Routes, Agents) are polished and consistent. The design system provides a solid foundation. + +**Key strengths:** KPI strip pattern, command palette (Ctrl+K), agent card grouping, dark mode token system, cohesive brand identity. + +**Critical gaps to address:** +1. **Font sizes too small** — pervasive 10-11px text for critical data impairs reading under stress +2. **Color contrast failures** — `--text-muted` and `--text-faint` fail WCAG AA in both themes +3. **Status indicators rely on color alone** — not accessible for color-blind users +4. **Admin infrastructure pages lag in polish** — Database/OpenSearch use ad-hoc styling +5. **Dashboard is a monitoring display, not yet an incident response tool** — missing error highlighting, per-route error breakdowns, actionable status pages + +**Overall Score: 7/10** — Strong foundation, needs targeted fixes for production readiness under stress. + +--- + +## Pages Evaluated + +| # | Page | Screenshot | +|---|------|-----------| +| 1 | Login | `screenshots/14-login-page.png` | +| 2 | Dashboard (light) | `screenshots/01-dashboard.png` | +| 3 | Dashboard + Detail Panel | `screenshots/02-dashboard-detail-panel.png` | +| 4 | Exchange Detail | `screenshots/03-exchange-detail.png` | +| 5 | Routes Metrics | `screenshots/04-routes-metrics.png` | +| 6 | Agent Health | `screenshots/05-agents.png` | +| 7 | Agent Instance | `screenshots/06-agent-instance.png` | +| 8 | Admin RBAC | `screenshots/07-admin-rbac.png` | +| 9 | Admin Audit Log | `screenshots/08-admin-audit.png` | +| 10 | Admin OIDC | `screenshots/09-admin-oidc.png` | +| 11 | Admin Database | `screenshots/10-admin-database.png` | +| 12 | Admin OpenSearch | `screenshots/11-admin-opensearch.png` | +| 13 | Command Palette | `screenshots/12-command-palette.png` | +| 14 | Dashboard (dark) | `screenshots/13-dashboard-dark-mode.png` | + +--- + +## Page-by-Page Findings + +### Login Page + +- **[Important]** No brand identity — missing camel logo/icon from sidebar. First impression feels generic. +- **[Important]** Sign-in button color mismatch — uses washed-out gold, not the saturated `--amber` (#C6820E) used throughout the app. +- **[Important]** No SSO/OIDC button visible — system supports OIDC but login page only shows username/password. +- **[Important]** Subtitle text `--text-muted` (#9C9184) on white fails WCAG AA (~2.8:1, needs 4.5:1). +- **[Important]** White text on amber button fails WCAG AA for normal text (~3.2:1). +- **[Nice-to-have]** Card has no shadow/border against the `--bg-body` cream background — minimal separation. + +### Dashboard + +- **[Important]** Errors KPI card uses red/orange accent border even when errors = 0. Zero-error state should feel reassuring (green/neutral), not alarming. Creates false alarm fatigue. +- **[Important]** Table lacks visible sort indicators — no arrows showing current sort direction. +- **[Important]** Duration column uses color alone (`.durFast` green, `.durSlow` amber, `.durBreach` red) — not color-blind safe. +- **[Important]** Status dots are ~6px — too small to reliably identify, especially for color-blind users. +- **[Critical]** Table meta text at 11px with `--text-muted` is borderline illegible for fatigued users. +- **[Critical]** KPI stat labels at 10px with `--text-muted` — below recommended 12px minimum. +- **[Nice-to-have]** Exchange ID column too wide — truncate to 8 chars with copy-on-click. + +### Dashboard — Detail Panel + +- **[Important]** Panel lacks clear visual separation from main table — needs left border accent or different background. +- **[Important]** Processor timeline preview in panel is too small to read — adds visual noise without utility. +- **[Critical]** Overview labels at 10px with `--text-muted` — nearly invisible. +- **[Critical]** Panel section meta at 10px with `--text-faint` (#C4BAB0) on white — contrast ratio ~1.9:1, severely fails WCAG AA. +- **[Nice-to-have]** No quick actions (copy exchange ID, view logs, view route diagram). + +### Exchange Detail + +- **[Critical]** Processor timeline label column too narrow — processor names are truncated/illegible. This is the page's primary visualization. +- **[Critical]** No error highlighting in processor timeline — failed processors need red bars/icons. During incidents, engineers must instantly see WHICH processor failed. +- **[Important]** No linkage to route diagram — "View in Route Diagram" would overlay execution on the visual route graph. +- **[Important]** Long exchange ID in breadcrumb is visually heavy — truncate with copy button. +- **[Important]** Header stat labels at 10px uppercase with `--text-muted` — same contrast issue. + +### Routes Metrics + +- **[Important]** KPI number formatting inconsistent — Dashboard shows "11.742 ms" (decimal + space), Routes shows "11742ms" (no decimal, no space). +- **[Important]** No per-route error rate column — error rate in KPI strip but not broken down per route. +- **[Important]** Charts disconnected from table — clicking a route should filter/highlight its chart data. +- **[Nice-to-have]** No visual comparison between routes (bar chart or heatmap for quick identification of slowest). + +### Agent Health + +- **[Critical]** Stale/Dead agent visual distinction is too subtle — at 3am, the difference between LIVE and DEAD must scream. Dead agents should have prominent red background or strikethrough, not just `--text-muted`. +- **[Critical]** Agent state dots (green live, amber stale, gray dead) use color alone — no shape variation for color-blind users. +- **[Important]** "2/26" active routes KPI is ambiguous — unit and meaning need to be explicit. +- **[Nice-to-have]** Timeline at bottom takes significant space — consider making it collapsible. + +### Agent Instance Detail + +- **[Important]** Charts lack threshold/alert lines — CPU at 2% is fine, but where is "concerning"? Configurable thresholds (CPU > 80%, Memory > 90%) would make charts actionable. +- **[Important]** Chart axis labels appear too small. +- **[Nice-to-have]** GC Pauses uses area fill while others use line charts — minor inconsistency. +- **[Nice-to-have]** Six charts in 2x3 grid can create cognitive overload — consider collapsible groups. + +### Admin — RBAC + +- **[Important]** KPI strip for "Users: 1, Groups: 2, Roles: 4" has too much visual weight — these low-value numbers don't need full stat-card treatment. +- **[Important]** "ADMIN" role badge vs "ADMINS" group badge look identical — different badge styles needed (outlined for groups, filled for roles). +- **[Nice-to-have]** Empty detail panel ("Select a user to view details") needs icon/illustration. + +### Admin — Audit Log + +- **[Important]** "no data" empty state is uninformative — should explain "No audit events match your filters" with guidance. +- **[Important]** No export functionality — audit logs need CSV/JSON export for compliance. +- **[Important]** Date range filters use raw datetime inputs — inconsistent with dashboard's polished time range pills. + +### Admin — OIDC Config + +- **[Critical]** "Delete OIDC Configuration" is a destructive action without confirmation dialog — could lock out all SSO users. +- **[Important]** No inline validation — Issuer URL should validate format on blur, required fields need indicators. +- **[Nice-to-have]** No connection test result display area. + +### Admin — Database + +- **[Important]** Visual treatment inconsistent with rest of app — "Connected" status and pool stats use ad-hoc text, not design system components. +- **[Important]** Page title "Database Administration" implies actions, but page is read-only — rename to "Database Status" or add operations. +- **[Nice-to-have]** Table row counts should be right-aligned for numerical scanning. + +### Admin — OpenSearch + +- **[Critical]** "Disconnected" status displayed as plain text — needs error styling (red text, error badge, or status banner). Infrastructure disconnection is a critical state. +- **[Important]** "Yellow" cluster health displayed as plain text with no visual hierarchy — same size/weight as version number and node count. +- **[Important]** Indexing pipeline stats use ad-hoc inline format — should use consistent stat-card pattern. +- **[Important]** "Disconnected" + "Yellow" health shown simultaneously is contradictory — if disconnected, clarify whether data is stale. + +### Command Palette + +- **[Nice-to-have]** No visible keyboard navigation hint for currently selected item. +- **[Nice-to-have]** Empty palette should show recent/frequent items instead of requiring typing. +- Overall well-executed — categories, counts, keyboard hints in footer. + +### Dark Mode + +- **[Critical]** `--text-muted` (#7A7068) on `--bg-surface` (#242019) is ~2.9:1 — fails WCAG AA. Affects ALL muted labels across every page. +- **[Critical]** `--text-faint` (#4A4238) on `--bg-surface` (#242019) is ~1.4:1 — catastrophically fails WCAG AA. Essentially invisible. +- **[Important]** `--amber` (#D4941E) on `--bg-surface` (#242019) is ~3.6:1 — amber links/active text fail AA. +- **[Important]** KPI sparkline chart lines are harder to read — thin strokes need increased width or brightness. +- **[Important]** Sidebar boundary contrast drops significantly (`--sidebar-bg` #141210 vs `--bg-body` #1A1714 is only ~6 units apart). +- **[Important]** Table row alternation contrast near zero in dark mode. +- **[Nice-to-have]** Amber accent color shift from #C6820E to #D4941E is well-handled. +- **[Nice-to-have]** Semantic colors (success, error, warning) appropriately increase luminance. + +--- + +## Cross-Cutting Issues + +### 1. Color Contrast (WCAG AA Failures) + +**Light Mode:** + +| Element | Foreground | Background | Ratio | Required | Verdict | +|---------|-----------|------------|-------|----------|---------| +| StatCard labels, table meta, section headers | `--text-muted` #9C9184 | #FFFFFF | ~3.0:1 | 4.5:1 | **FAIL** | +| Panel meta, overview hints | `--text-faint` #C4BAB0 | #FFFFFF | ~1.9:1 | 4.5:1 | **FAIL** | +| Sign-in button text | #FFFFFF | `--amber` #C6820E | ~3.2:1 | 4.5:1 | **FAIL** | +| Sidebar muted text | #9C9184 | `--sidebar-bg` #2C2520 | ~3.1:1 | 4.5:1 | **FAIL** | + +**Dark Mode:** + +| Element | Foreground | Background | Ratio | Required | Verdict | +|---------|-----------|------------|-------|----------|---------| +| All muted labels | #7A7068 | #242019 | ~2.9:1 | 4.5:1 | **FAIL** | +| All faint hints | #4A4238 | #242019 | ~1.4:1 | 4.5:1 | **FAIL** | +| Amber links/active text | #D4941E | #242019 | ~3.6:1 | 4.5:1 | **FAIL** | + +**Fix:** Change `--text-muted` to **#766A5E** (light) / **#9A9088** (dark). Restrict `--text-faint` to decorative use only or lighten dark variant to #6A6058. + +### 2. Font Size Floor + +10px text is used for: StatCard labels, overview labels, chain labels, section meta, error class names, detail labels, sidebar tree labels. 11px is used for: table meta, error messages, pagination, toggle buttons, chart titles. + +**Fix:** Establish `--font-size-min: 12px` as a design system floor. Update all 10px instances to 12px, all 11px instances to 12px. + +### 3. Number/Unit Formatting + +Inconsistent across pages: +- Dashboard: "11.742 ms" (decimal + space) +- Routes: "11742ms" (no decimal, no space) +- Dashboard: "1.1 msg/s" vs Agent Instance: "0.1/s" + +**Fix:** Create a shared formatting utility enforcing: consistent decimal precision, space before unit, consistent abbreviations. + +### 4. KPI Strip Inconsistency + +Used on Dashboard, Routes, Agents, Agent Instance (consistent). But RBAC uses oversized cards for trivial counts, and Database/OpenSearch use ad-hoc text rendering. + +**Fix:** Admin infra pages should adopt KPI stat strip or a compact-stat component. + +### 5. Empty States + +Inconsistent handling: +- Audit Log: "no data" in plain gray +- RBAC detail: "Select a user to view details" in gray +- No consistent empty state component with icon + message + CTA + +**Fix:** Design system EmptyState component with icon, message, and optional action. + +### 6. Status Indicator Accessibility + +Color-only status encoding throughout: +- Duration: green (fast), amber (slow), red (breach) — no icons +- Status dots: green (live), amber (stale), gray (dead) — no shapes +- Agent dead state uses `--text-muted` instead of `--error` + +**Fix:** Add shape variation (checkmark/triangle/X), increase dot size to 10px minimum, always render text label alongside. + +### 7. Sidebar Structure + +Same apps listed 3x (under Applications, Agents, Routes) — triples sidebar length and scales poorly. + +**Fix:** Unified application-centric tree where expanding an app shows its agents and routes as children. + +--- + +## Prioritized Recommendations + +### Critical (fix now) + +| # | Recommendation | Impact | +|---|---------------|--------| +| 1 | **Bump `--text-muted` to WCAG AA compliance** — #766A5E (light) / #9A9088 (dark). Single highest-impact fix across all pages. | Fixes majority of contrast failures | +| 2 | **Establish 12px minimum font size** — update all 10px and 11px instances. Especially StatCard labels, overview labels, table meta. | Readable under stress | +| 3 | **Add error highlighting to processor timeline** — red bars, error icons for failed processors. Core debugging view. | Incident response speed | +| 4 | **Make Stale/Dead agent states unmistakable** — full card background color (yellow stale, red dead), prominent badge. Change dead from `--text-muted` to `--error`. | Prevents missed outages | +| 5 | **Fix OpenSearch "Disconnected" status** — use error badge/banner, add "Reconnect" action, clarify stale data. | Actionable admin page | +| 6 | **Add confirmation dialog for OIDC deletion** — type-to-confirm to prevent locking out SSO users. | Prevents lockout | +| 7 | **Color Errors KPI card conditionally** — green/neutral at 0, red only when > 0. Prevents false alarm fatigue. | Reduces noise | + +### Important (next sprint) + +| # | Recommendation | Impact | +|---|---------------|--------| +| 8 | **Add secondary encoding to status indicators** — shapes (checkmark/triangle/X) alongside color dots. Increase dot size to 10px+. | Accessibility compliance | +| 9 | **Standardize number/unit formatting** — shared utility for decimals, spacing, unit abbreviations. | Visual consistency | +| 10 | **Add per-route error rate to Routes table** — essential for isolating failing routes. | Incident triage | +| 11 | **Add visible sort indicators to data tables** — arrows on column headers. | Data exploration | +| 12 | **Bring admin infra pages to design system quality** — replace ad-hoc text with KPI strips/stat cards. | Professional polish | +| 13 | **Fix login page brand identity** — add camel logo, use correct `--amber` for button, add SSO button when OIDC configured. | First impression | +| 14 | **Fix dark mode specifics** — increase sidebar boundary contrast (add 1px border), boost chart stroke width, fix amber link contrast. | Dark mode usability | +| 15 | **Widen processor timeline label column** — prevent name truncation, add tooltips for long names. | Core visualization | +| 16 | **Add detail panel visual separation** — 2px left border accent. | Layout clarity | +| 17 | **Pin Admin/API Docs to sidebar footer** — accessible without scrolling. | Navigation | +| 18 | **Audit log improvements** — informative empty state, CSV/JSON export, date picker consistent with dashboard. | Admin usability | +| 19 | **OIDC form validation** — inline URL validation, required field indicators, test result display. | Configuration safety | +| 20 | **Fix amber button text contrast** — darken button to #8B5A06 or use dark text on amber. | Accessibility | + +### Nice-to-have (backlog) + +| # | Recommendation | Impact | +|---|---------------|--------| +| 21 | Unify sidebar into single application-centric tree (Applications > agents + routes) | Scalability | +| 22 | Truncate Exchange IDs to 8 chars with copy-on-click | Table space | +| 23 | Add threshold/alert lines to agent metric charts | Actionable monitoring | +| 24 | Link charts to table selection on Routes Metrics | Data exploration | +| 25 | Add clickable KPI cards navigating to filtered views | Navigation shortcuts | +| 26 | Add `prefers-reduced-motion` support for StatusDot pulse animation | Accessibility | +| 27 | Add tooltips to sparkline charts showing value on hover | Data context | +| 28 | Replace hardcoded `#5db866` in Dashboard.module.css with `var(--success)` | Token compliance | +| 29 | Add keyboard navigation indicators to command palette (selected item highlight) | Power user UX | +| 30 | Show recent/frequent items in empty command palette | Discoverability | +| 31 | Consolidate duplicated table-header CSS into design system component | Maintainability | +| 32 | Login page card shadow for visual lift | Polish | +| 33 | Collapsible agent event timeline | Space efficiency | +| 34 | Dark mode `--text-faint` increase to #6A6058 for 3:1 minimum | Accessibility | +| 35 | Increase DataTable row height to 44px (touch target minimum) | Accessibility | + +--- + +## Dark Mode Assessment + +**Grade: Good foundation, specific contrast concerns.** + +**What works well:** +- Token system remaps all semantic colors without introducing cold blue-grays — warm brand preserved +- Amber accent brightens appropriately (#C6820E → #D4941E) +- Error/warning/success colors increase luminance correctly +- Shadows shift from warm semi-transparent to opaque — correct for dark backgrounds + +**What needs fixing:** +- Sidebar contrast: `--sidebar-bg` #141210 vs `--bg-body` #1A1714 only ~6 units apart (was ~50 in light mode) +- Chart line visibility: thin 1-2px strokes need increased width +- Table row alternation: near-zero contrast between `--bg-surface` and `--bg-raised` +- `--text-faint`: essentially invisible at 1.4:1 contrast +- `--text-muted`: 2.9:1 — below AA minimum diff --git a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/diagram/ElkDiagramRenderer.java b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/diagram/ElkDiagramRenderer.java index 38e4e54e..76b5067f 100644 --- a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/diagram/ElkDiagramRenderer.java +++ b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/diagram/ElkDiagramRenderer.java @@ -109,7 +109,7 @@ public class ElkDiagramRenderer implements DiagramRenderer { NodeType.DO_TRY, NodeType.DO_CATCH, NodeType.DO_FINALLY, NodeType.EIP_LOOP, NodeType.EIP_MULTICAST, NodeType.EIP_AGGREGATE, NodeType.ON_EXCEPTION, NodeType.ERROR_HANDLER, - NodeType.ON_COMPLETION, NodeType.EIP_CIRCUIT_BREAKER + NodeType.ON_COMPLETION ); /** Top-level handler types laid out in their own separate ELK graph. */ @@ -621,84 +621,6 @@ public class ElkDiagramRenderer implements DiagramRenderer { sectionOrder.add(handler.getId()); } - ctx.doTrySectionOrder.put(rn.getId(), sectionOrder); - } else if (isCompound && rn.getType() == NodeType.EIP_CIRCUIT_BREAKER) { - // CIRCUIT_BREAKER: vertical container with _CB_MAIN for main path - // and onFallback as a compound section below (like DO_TRY pattern) - ctx.compoundNodeIds.add(rn.getId()); - elkNode.setWidth(200); - elkNode.setHeight(100); - elkNode.setProperty(CoreOptions.ALGORITHM, "org.eclipse.elk.layered"); - elkNode.setProperty(CoreOptions.DIRECTION, Direction.DOWN); - elkNode.setProperty(CoreOptions.SPACING_NODE_NODE, NODE_SPACING * 0.4); - elkNode.setProperty(CoreOptions.SPACING_EDGE_NODE, EDGE_SPACING * 0.3); - elkNode.setProperty(CoreOptions.PADDING, - new org.eclipse.elk.core.math.ElkPadding(COMPOUND_TOP_PADDING, - COMPOUND_SIDE_PADDING, COMPOUND_SIDE_PADDING, COMPOUND_SIDE_PADDING)); - - // Separate main path children from onFallback child - List mainChildren = new ArrayList<>(); - RouteNode fallbackNode = null; - for (RouteNode child : rn.getChildren()) { - if ("onFallback".equals(child.getLabel())) { - fallbackNode = child; - } else { - mainChildren.add(child); - } - } - - List sectionOrder = new ArrayList<>(); - - // Virtual _CB_MAIN wrapper for main path (horizontal flow) - if (!mainChildren.isEmpty()) { - String wrapperId = rn.getId() + "._cb_main"; - ElkNode wrapper = ctx.factory.createElkNode(); - wrapper.setIdentifier(wrapperId); - wrapper.setParent(elkNode); - wrapper.setWidth(200); - wrapper.setHeight(40); - wrapper.setProperty(CoreOptions.ALGORITHM, "org.eclipse.elk.layered"); - wrapper.setProperty(CoreOptions.DIRECTION, Direction.RIGHT); - wrapper.setProperty(CoreOptions.SPACING_NODE_NODE, NODE_SPACING * 0.5); - wrapper.setProperty(CoreOptions.SPACING_EDGE_NODE, EDGE_SPACING * 0.5); - wrapper.setProperty(CoreOptions.PADDING, - new org.eclipse.elk.core.math.ElkPadding(8, 8, 8, 8)); - ctx.compoundNodeIds.add(wrapperId); - ctx.elkNodeMap.put(wrapperId, wrapper); - sectionOrder.add(wrapperId); - - for (RouteNode child : mainChildren) { - ctx.childNodeIds.add(child.getId()); - createElkNodeRecursive(child, wrapper, ctx); - } - } - - // onFallback as compound section containing its children - if (fallbackNode != null) { - ctx.childNodeIds.add(fallbackNode.getId()); - ElkNode fallbackElk = ctx.factory.createElkNode(); - fallbackElk.setIdentifier(fallbackNode.getId()); - fallbackElk.setParent(elkNode); - fallbackElk.setWidth(200); - fallbackElk.setHeight(40); - fallbackElk.setProperty(CoreOptions.ALGORITHM, "org.eclipse.elk.layered"); - fallbackElk.setProperty(CoreOptions.DIRECTION, Direction.RIGHT); - fallbackElk.setProperty(CoreOptions.SPACING_NODE_NODE, NODE_SPACING * 0.5); - fallbackElk.setProperty(CoreOptions.SPACING_EDGE_NODE, EDGE_SPACING * 0.5); - fallbackElk.setProperty(CoreOptions.PADDING, - new org.eclipse.elk.core.math.ElkPadding(18, 8, 8, 8)); - ctx.compoundNodeIds.add(fallbackNode.getId()); - ctx.elkNodeMap.put(fallbackNode.getId(), fallbackElk); - sectionOrder.add(fallbackNode.getId()); - - if (fallbackNode.getChildren() != null) { - for (RouteNode child : fallbackNode.getChildren()) { - ctx.childNodeIds.add(child.getId()); - createElkNodeRecursive(child, fallbackElk, ctx); - } - } - } - ctx.doTrySectionOrder.put(rn.getId(), sectionOrder); } else if (isCompound) { ctx.compoundNodeIds.add(rn.getId()); @@ -768,55 +690,6 @@ public class ElkDiagramRenderer implements DiagramRenderer { children.add(extractPositionedNode(handler, childElk, rootNode, ctx)); } } - } else if (rn.getType() == NodeType.EIP_CIRCUIT_BREAKER) { - // CIRCUIT_BREAKER: extract _CB_MAIN wrapper, then onFallback section - String mainWrapperId = rn.getId() + "._cb_main"; - ElkNode mainWrapperElk = ctx.elkNodeMap.get(mainWrapperId); - if (mainWrapperElk != null) { - List wrapperChildren = new ArrayList<>(); - for (RouteNode child : rn.getChildren()) { - if (!"onFallback".equals(child.getLabel())) { - ElkNode childElk = ctx.elkNodeMap.get(child.getId()); - if (childElk != null) { - wrapperChildren.add(extractPositionedNode(child, childElk, rootNode, ctx)); - } - } - } - children.add(new PositionedNode( - mainWrapperId, "", "_CB_MAIN", - getAbsoluteX(mainWrapperElk, rootNode), - getAbsoluteY(mainWrapperElk, rootNode), - mainWrapperElk.getWidth(), mainWrapperElk.getHeight(), - wrapperChildren, null)); - ctx.compoundInfos.put(mainWrapperId, new CompoundInfo(mainWrapperId, Color.WHITE)); - } - // onFallback section with its children, type overridden to _CB_FALLBACK - for (RouteNode child : rn.getChildren()) { - if ("onFallback".equals(child.getLabel())) { - ElkNode childElk = ctx.elkNodeMap.get(child.getId()); - if (childElk != null) { - List fallbackChildren = new ArrayList<>(); - if (child.getChildren() != null) { - for (RouteNode fc : child.getChildren()) { - ElkNode fcElk = ctx.elkNodeMap.get(fc.getId()); - if (fcElk != null) { - fallbackChildren.add(extractPositionedNode(fc, fcElk, rootNode, ctx)); - } - } - } - children.add(new PositionedNode( - child.getId(), - child.getLabel() != null ? child.getLabel() : "", - "_CB_FALLBACK", - getAbsoluteX(childElk, rootNode), - getAbsoluteY(childElk, rootNode), - childElk.getWidth(), childElk.getHeight(), - fallbackChildren, null)); - ctx.compoundInfos.put(child.getId(), - new CompoundInfo(child.getId(), colorForType(rn.getType()))); - } - } - } } else { for (RouteNode child : rn.getChildren()) { ElkNode childElk = ctx.elkNodeMap.get(child.getId()); diff --git a/ci-log.txt b/ci-log.txt new file mode 100644 index 00000000..cc1147fb --- /dev/null +++ b/ci-log.txt @@ -0,0 +1,402 @@ +2026-03-25T12:05:26.5603617Z my-docker-runner(version:v0.3.0) received task 1104 of job build, be triggered by event: push +2026-03-25T12:05:26.5608954Z workflow prepared +2026-03-25T12:05:26.5610069Z evaluating expression 'github.event_name != 'delete'' +2026-03-25T12:05:26.5611215Z expression 'github.event_name != 'delete'' evaluated to 'true' +2026-03-25T12:05:26.5611555Z 🚀 Start image=maven:3.9-eclipse-temurin-17 +2026-03-25T12:05:26.5687706Z 🐳 docker pull image=maven:3.9-eclipse-temurin-17 platform= username= forcePull=true +2026-03-25T12:05:26.5688071Z 🐳 docker pull maven:3.9-eclipse-temurin-17 +2026-03-25T12:05:26.5688457Z pulling image 'docker.io/library/maven:3.9-eclipse-temurin-17' () +2026-03-25T12:05:27.4255898Z Pulling from library/maven :: 3.9-eclipse-temurin-17 +2026-03-25T12:05:27.4496622Z Digest: sha256:39a5260d49fe20e5f407bf63f63a267d9870965bcd1d114e52e1e50ba1c55a32 :: +2026-03-25T12:05:27.4497205Z Status: Image is up to date for maven:3.9-eclipse-temurin-17 :: +2026-03-25T12:05:27.4684745Z 🐳 docker create image=maven:3.9-eclipse-temurin-17 platform= entrypoint=["/bin/sleep" "10800"] cmd=[] network="gitea_gitea_default" +2026-03-25T12:05:27.4853152Z Custom container.Config from options ==> &{Hostname: Domainname: User: AttachStdin:false AttachStdout:true AttachStderr:true ExposedPorts:map[] Tty:false OpenStdin:false StdinOnce:false Env:[] Cmd:[] Healthcheck: ArgsEscaped:false Image: Volumes:map[] WorkingDir: Entrypoint:[] NetworkDisabled:false MacAddress: OnBuild:[] Labels:map[] StopSignal: StopTimeout: Shell:[]} +2026-03-25T12:05:27.4854116Z Merged container.Config ==> &{Hostname: Domainname: User: AttachStdin:false AttachStdout:true AttachStderr:true ExposedPorts:map[] Tty:false OpenStdin:false StdinOnce:false Env:[RUNNER_TOOL_CACHE=/opt/hostedtoolcache RUNNER_OS=Linux RUNNER_ARCH=ARM64 RUNNER_TEMP=/tmp LANG=C.UTF-8] Cmd:[] Healthcheck: ArgsEscaped:false Image:maven:3.9-eclipse-temurin-17 Volumes:map[] WorkingDir:/workspace/***/***3-server Entrypoint:[/bin/sleep 10800] NetworkDisabled:false MacAddress: OnBuild:[] Labels:map[] StopSignal: StopTimeout: Shell:[]} +2026-03-25T12:05:27.4855205Z Custom container.HostConfig from options ==> &{Binds:[] ContainerIDFile: LogConfig:{Type: Config:map[]} NetworkMode:gitea_gitea_default PortBindings:map[] RestartPolicy:{Name:no MaximumRetryCount:0} AutoRemove:false VolumeDriver: VolumesFrom:[] ConsoleSize:[0 0] Annotations:map[] CapAdd:[] CapDrop:[] CgroupnsMode: DNS:[] DNSOptions:[] DNSSearch:[] ExtraHosts:[] GroupAdd:[] IpcMode: Cgroup: Links:[] OomScoreAdj:0 PidMode: Privileged:false PublishAllPorts:false ReadonlyRootfs:false SecurityOpt:[] StorageOpt:map[] Tmpfs:map[] UTSMode: UsernsMode: ShmSize:0 Sysctls:map[] Runtime: Isolation: Resources:{CPUShares:0 Memory:0 NanoCPUs:0 CgroupParent: BlkioWeight:0 BlkioWeightDevice:[] BlkioDeviceReadBps:[] BlkioDeviceWriteBps:[] BlkioDeviceReadIOps:[] BlkioDeviceWriteIOps:[] CPUPeriod:0 CPUQuota:0 CPURealtimePeriod:0 CPURealtimeRuntime:0 CpusetCpus: CpusetMems: Devices:[] DeviceCgroupRules:[] DeviceRequests:[] KernelMemory:0 KernelMemoryTCP:0 MemoryReservation:0 MemorySwap:0 MemorySwappiness:0x228ace413ac8 OomKillDisable:0x228ace4139c3 PidsLimit:0x228ace413b28 Ulimits:[] CPUCount:0 CPUPercent:0 IOMaximumIOps:0 IOMaximumBandwidth:0} Mounts:[] MaskedPaths:[] ReadonlyPaths:[] Init:} +2026-03-25T12:05:27.4856294Z --network and --net in the options will be ignored. +2026-03-25T12:05:27.4856928Z Merged container.HostConfig ==> &{Binds:[/var/run/docker.sock:/var/run/docker.sock] ContainerIDFile: LogConfig:{Type: Config:map[]} NetworkMode:gitea_gitea_default PortBindings:map[] RestartPolicy:{Name:no MaximumRetryCount:0} AutoRemove:true VolumeDriver: VolumesFrom:[] ConsoleSize:[0 0] Annotations:map[] CapAdd:[] CapDrop:[] CgroupnsMode: DNS:[] DNSOptions:[] DNSSearch:[] ExtraHosts:[] GroupAdd:[] IpcMode: Cgroup: Links:[] OomScoreAdj:0 PidMode: Privileged:false PublishAllPorts:false ReadonlyRootfs:false SecurityOpt:[] StorageOpt:map[] Tmpfs:map[] UTSMode: UsernsMode: ShmSize:0 Sysctls:map[] Runtime: Isolation: Resources:{CPUShares:0 Memory:0 NanoCPUs:0 CgroupParent: BlkioWeight:0 BlkioWeightDevice:[] BlkioDeviceReadBps:[] BlkioDeviceWriteBps:[] BlkioDeviceReadIOps:[] BlkioDeviceWriteIOps:[] CPUPeriod:0 CPUQuota:0 CPURealtimePeriod:0 CPURealtimeRuntime:0 CpusetCpus: CpusetMems: Devices:[] DeviceCgroupRules:[] DeviceRequests:[] KernelMemory:0 KernelMemoryTCP:0 MemoryReservation:0 MemorySwap:0 MemorySwappiness:0x228ace413ac8 OomKillDisable:0x228ace4139c3 PidsLimit:0x228ace413b28 Ulimits:[] CPUCount:0 CPUPercent:0 IOMaximumIOps:0 IOMaximumBandwidth:0} Mounts:[{Type:volume Source:act-toolcache Target:/opt/hostedtoolcache ReadOnly:false Consistency: BindOptions: VolumeOptions: TmpfsOptions: ClusterOptions:} {Type:volume Source:GITEA-ACTIONS-TASK-1104_WORKFLOW-CI_JOB-build-env Target:/var/run/act ReadOnly:false Consistency: BindOptions: VolumeOptions: TmpfsOptions: ClusterOptions:} {Type:volume Source:GITEA-ACTIONS-TASK-1104_WORKFLOW-CI_JOB-build Target:/workspace/***/***3-server ReadOnly:false Consistency: BindOptions: VolumeOptions: TmpfsOptions: ClusterOptions:}] MaskedPaths:[] ReadonlyPaths:[] Init:} +2026-03-25T12:05:27.5978022Z Created container name=GITEA-ACTIONS-TASK-1104_WORKFLOW-CI_JOB-build id=7218bfea7789106d54e48224d5541c49969b5cca00766ae2ffdcbc415f9c35ae from image maven:3.9-eclipse-temurin-17 (platform: ) +2026-03-25T12:05:27.5978558Z ENV ==> [RUNNER_TOOL_CACHE=/opt/hostedtoolcache RUNNER_OS=Linux RUNNER_ARCH=ARM64 RUNNER_TEMP=/tmp LANG=C.UTF-8] +2026-03-25T12:05:27.5978778Z 🐳 docker run image=maven:3.9-eclipse-temurin-17 platform= entrypoint=["/bin/sleep" "10800"] cmd=[] network="gitea_gitea_default" +2026-03-25T12:05:27.5978979Z Starting container: 7218bfea7789106d54e48224d5541c49969b5cca00766ae2ffdcbc415f9c35ae +2026-03-25T12:05:27.8074630Z Started container: 7218bfea7789106d54e48224d5541c49969b5cca00766ae2ffdcbc415f9c35ae +2026-03-25T12:05:27.9290310Z Writing entry to tarball workflow/event.json len:5028 +2026-03-25T12:05:27.9290900Z Writing entry to tarball workflow/envs.txt len:0 +2026-03-25T12:05:27.9291139Z Extracting content to '/var/run/act/' +2026-03-25T12:05:27.9477718Z ☁ git clone 'https://github.com/actions/checkout' # ref=v4 +2026-03-25T12:05:27.9478182Z cloning https://github.com/actions/checkout to /root/.cache/act/c3fe249fe73091a17d6638fe1341e7bd0bcc3466ce52323c0688e83e2463a4ab +2026-03-25T12:05:28.2648306Z Non-terminating error while running 'git clone': some refs were not updated +2026-03-25T12:05:28.2717948Z ☁ git clone 'https://github.com/actions/cache' # ref=v4 +2026-03-25T12:05:28.2718527Z cloning https://github.com/actions/cache to /root/.cache/act/6b4e4eb40e21c1bd02cb00a273f4d79af7c42205c1390e4e65c594ecd7a3696e +2026-03-25T12:05:29.0246163Z Non-terminating error while running 'git clone': some refs were not updated +2026-03-25T12:05:29.0434354Z evaluating expression '' +2026-03-25T12:05:29.0435137Z expression '' evaluated to 'true' +2026-03-25T12:05:29.0435325Z ⭐ Run Main Install Node.js 22 +2026-03-25T12:05:29.0435581Z Writing entry to tarball workflow/outputcmd.txt len:0 +2026-03-25T12:05:29.0435798Z Writing entry to tarball workflow/statecmd.txt len:0 +2026-03-25T12:05:29.0435957Z Writing entry to tarball workflow/pathcmd.txt len:0 +2026-03-25T12:05:29.0436104Z Writing entry to tarball workflow/envs.txt len:0 +2026-03-25T12:05:29.0436243Z Writing entry to tarball workflow/SUMMARY.md len:0 +2026-03-25T12:05:29.0436418Z Extracting content to '/var/run/act' +2026-03-25T12:05:29.0641886Z Wrote command \n\napt-get update && apt-get install -y ca-certificates curl gnupg\nmkdir -p /etc/apt/keyrings\ncurl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg\necho "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" > /etc/apt/sources.list.d/nodesource.list\napt-get update && apt-get install -y nodejs\n\n\n to 'workflow/0.sh' +2026-03-25T12:05:29.0642653Z Writing entry to tarball workflow/0.sh len:407 +2026-03-25T12:05:29.0642896Z Extracting content to '/var/run/act' +2026-03-25T12:05:29.0664683Z 🐳 docker exec cmd=[sh -e /var/run/act/workflow/0.sh] user= workdir= +2026-03-25T12:05:29.0665120Z Exec command '[sh -e /var/run/act/workflow/0.sh]' +2026-03-25T12:05:29.0665572Z Working directory '/workspace/***/***3-server' +2026-03-25T12:05:29.1930283Z Get:1 http://ports.ubuntu.com/ubuntu-ports noble InRelease [256 kB] +2026-03-25T12:05:29.3020283Z Get:2 http://ports.ubuntu.com/ubuntu-ports noble-updates InRelease [126 kB] +2026-03-25T12:05:29.3278285Z Get:3 http://ports.ubuntu.com/ubuntu-ports noble-backports InRelease [126 kB] +2026-03-25T12:05:29.3533160Z Get:4 http://ports.ubuntu.com/ubuntu-ports noble-security InRelease [126 kB] +2026-03-25T12:05:29.3799993Z Get:5 http://ports.ubuntu.com/ubuntu-ports noble/universe arm64 Packages [19.0 MB] +2026-03-25T12:05:29.8392869Z Get:6 http://ports.ubuntu.com/ubuntu-ports noble/restricted arm64 Packages [113 kB] +2026-03-25T12:05:29.8393771Z Get:7 http://ports.ubuntu.com/ubuntu-ports noble/multiverse arm64 Packages [274 kB] +2026-03-25T12:05:29.8394197Z Get:8 http://ports.ubuntu.com/ubuntu-ports noble/main arm64 Packages [1,776 kB] +2026-03-25T12:05:29.8802923Z Get:9 http://ports.ubuntu.com/ubuntu-ports noble-updates/multiverse arm64 Packages [45.7 kB] +2026-03-25T12:05:29.8812220Z Get:10 http://ports.ubuntu.com/ubuntu-ports noble-updates/main arm64 Packages [2,451 kB] +2026-03-25T12:05:29.9387427Z Get:11 http://ports.ubuntu.com/ubuntu-ports noble-updates/universe arm64 Packages [2,057 kB] +2026-03-25T12:05:29.9942591Z Get:12 http://ports.ubuntu.com/ubuntu-ports noble-updates/restricted arm64 Packages [5,019 kB] +2026-03-25T12:05:30.1164288Z Get:13 http://ports.ubuntu.com/ubuntu-ports noble-backports/multiverse arm64 Packages [695 B] +2026-03-25T12:05:30.1180686Z Get:14 http://ports.ubuntu.com/ubuntu-ports noble-backports/universe arm64 Packages [36.1 kB] +2026-03-25T12:05:30.1181823Z Get:15 http://ports.ubuntu.com/ubuntu-ports noble-backports/main arm64 Packages [49.5 kB] +2026-03-25T12:05:30.1182817Z Get:16 http://ports.ubuntu.com/ubuntu-ports noble-security/universe arm64 Packages [1,502 kB] +2026-03-25T12:05:30.1538385Z Get:17 http://ports.ubuntu.com/ubuntu-ports noble-security/multiverse arm64 Packages [44.1 kB] +2026-03-25T12:05:30.1539003Z Get:18 http://ports.ubuntu.com/ubuntu-ports noble-security/restricted arm64 Packages [4,828 kB] +2026-03-25T12:05:30.2657962Z Get:19 http://ports.ubuntu.com/ubuntu-ports noble-security/main arm64 Packages [2,087 kB] +2026-03-25T12:05:31.5132214Z Fetched 39.9 MB in 2s (16.9 MB/s) +2026-03-25T12:05:32.8027349Z Reading package lists... +2026-03-25T12:05:34.1413764Z Reading package lists... +2026-03-25T12:05:34.4862647Z Building dependency tree... +2026-03-25T12:05:34.4864531Z Reading state information... +2026-03-25T12:05:35.2536110Z ca-certificates is already the newest version (20240203). +2026-03-25T12:05:35.2536691Z curl is already the newest version (8.5.0-2ubuntu10.8). +2026-03-25T12:05:35.2536858Z gnupg is already the newest version (2.4.4-2ubuntu17.4). +2026-03-25T12:05:35.2537061Z 0 upgraded, 0 newly installed, 0 to remove and 18 not upgraded. +2026-03-25T12:05:35.5548236Z Get:1 https://deb.nodesource.com/node_22.x nodistro InRelease [12.1 kB] +2026-03-25T12:05:35.7037091Z Hit:2 http://ports.ubuntu.com/ubuntu-ports noble InRelease +2026-03-25T12:05:35.7322162Z Hit:3 http://ports.ubuntu.com/ubuntu-ports noble-updates InRelease +2026-03-25T12:05:35.7599694Z Hit:4 http://ports.ubuntu.com/ubuntu-ports noble-backports InRelease +2026-03-25T12:05:35.7870145Z Hit:5 http://ports.ubuntu.com/ubuntu-ports noble-security InRelease +2026-03-25T12:05:35.8551499Z Get:6 https://deb.nodesource.com/node_22.x nodistro/main arm64 Packages [9,040 B] +2026-03-25T12:05:35.9067803Z Fetched 21.2 kB in 1s (41.2 kB/s) +2026-03-25T12:05:37.2373298Z Reading package lists... +2026-03-25T12:05:38.5735995Z Reading package lists... +2026-03-25T12:05:38.9087319Z Building dependency tree... +2026-03-25T12:05:38.9087899Z Reading state information... +2026-03-25T12:05:39.5855767Z The following additional packages will be installed: +2026-03-25T12:05:39.5870559Z libpython3-stdlib libpython3.12-minimal libpython3.12-stdlib media-types +2026-03-25T12:05:39.5880369Z netbase python3 python3-minimal python3.12 python3.12-minimal +2026-03-25T12:05:39.5913231Z Suggested packages: +2026-03-25T12:05:39.5913883Z python3-doc python3-tk python3-venv python3.12-venv python3.12-doc +2026-03-25T12:05:39.5914038Z binfmt-support +2026-03-25T12:05:39.6741455Z The following NEW packages will be installed: +2026-03-25T12:05:39.6754401Z libpython3-stdlib libpython3.12-minimal libpython3.12-stdlib media-types +2026-03-25T12:05:39.6762410Z netbase nodejs python3 python3-minimal python3.12 python3.12-minimal +2026-03-25T12:05:39.7694458Z 0 upgraded, 10 newly installed, 0 to remove and 18 not upgraded. +2026-03-25T12:05:39.7694946Z Need to get 42.9 MB of archives. +2026-03-25T12:05:39.7695098Z After this operation, 259 MB of additional disk space will be used. +2026-03-25T12:05:39.7695287Z Get:1 http://ports.ubuntu.com/ubuntu-ports noble-updates/main arm64 libpython3.12-minimal arm64 3.12.3-1ubuntu0.12 [834 kB] +2026-03-25T12:05:39.8854035Z Get:2 https://deb.nodesource.com/node_22.x nodistro/main arm64 nodejs arm64 22.22.1-1nodesource1 [37.0 MB] +2026-03-25T12:05:39.9473201Z Get:3 http://ports.ubuntu.com/ubuntu-ports noble-updates/main arm64 python3.12-minimal arm64 3.12.3-1ubuntu0.12 [2,252 kB] +2026-03-25T12:05:40.0068444Z Get:4 http://ports.ubuntu.com/ubuntu-ports noble-updates/main arm64 python3-minimal arm64 3.12.3-0ubuntu2.1 [27.4 kB] +2026-03-25T12:05:40.0073156Z Get:5 http://ports.ubuntu.com/ubuntu-ports noble/main arm64 media-types all 10.1.0 [27.5 kB] +2026-03-25T12:05:40.0077139Z Get:6 http://ports.ubuntu.com/ubuntu-ports noble/main arm64 netbase all 6.4 [13.1 kB] +2026-03-25T12:05:40.0079975Z Get:7 http://ports.ubuntu.com/ubuntu-ports noble-updates/main arm64 libpython3.12-stdlib arm64 3.12.3-1ubuntu0.12 [2,037 kB] +2026-03-25T12:05:40.0421355Z Get:8 http://ports.ubuntu.com/ubuntu-ports noble-updates/main arm64 python3.12 arm64 3.12.3-1ubuntu0.12 [651 kB] +2026-03-25T12:05:40.0818905Z Get:9 http://ports.ubuntu.com/ubuntu-ports noble-updates/main arm64 libpython3-stdlib arm64 3.12.3-0ubuntu2.1 [10.1 kB] +2026-03-25T12:05:40.0822085Z Get:10 http://ports.ubuntu.com/ubuntu-ports noble-updates/main arm64 python3 arm64 3.12.3-0ubuntu2.1 [23.0 kB] +2026-03-25T12:05:41.0927970Z debconf: delaying package configuration, since apt-utils is not installed +2026-03-25T12:05:41.1546756Z Fetched 42.9 MB in 1s (38.8 MB/s) +2026-03-25T12:05:41.2105330Z Selecting previously unselected package libpython3.12-minimal:arm64. +2026-03-25T12:05:41.2141434Z (Reading database ... (Reading database ... 5% (Reading database ... 10% (Reading database ... 15% (Reading database ... 20% (Reading database ... 25% (Reading database ... 30% (Reading database ... 35% (Reading database ... 40% (Reading database ... 45% (Reading database ... 50% (Reading database ... 55% (Reading database ... 60% (Reading database ... 65% (Reading database ... 70% (Reading database ... 75% (Reading database ... 80% (Reading database ... 85% (Reading database ... 90% (Reading database ... 95% (Reading database ... 100% (Reading database ... 10203 files and directories currently installed.) +2026-03-25T12:05:41.2151206Z Preparing to unpack .../libpython3.12-minimal_3.12.3-1ubuntu0.12_arm64.deb ... +2026-03-25T12:05:41.2237074Z Unpacking libpython3.12-minimal:arm64 (3.12.3-1ubuntu0.12) ... +2026-03-25T12:05:41.3575893Z Selecting previously unselected package python3.12-minimal. +2026-03-25T12:05:41.3590278Z Preparing to unpack .../python3.12-minimal_3.12.3-1ubuntu0.12_arm64.deb ... +2026-03-25T12:05:41.3695167Z Unpacking python3.12-minimal (3.12.3-1ubuntu0.12) ... +2026-03-25T12:05:41.4592573Z Setting up libpython3.12-minimal:arm64 (3.12.3-1ubuntu0.12) ... +2026-03-25T12:05:41.4945507Z Setting up python3.12-minimal (3.12.3-1ubuntu0.12) ... +2026-03-25T12:05:42.5868849Z Selecting previously unselected package python3-minimal. +2026-03-25T12:05:42.5916327Z (Reading database ... (Reading database ... 5% (Reading database ... 10% (Reading database ... 15% (Reading database ... 20% (Reading database ... 25% (Reading database ... 30% (Reading database ... 35% (Reading database ... 40% (Reading database ... 45% (Reading database ... 50% (Reading database ... 55% (Reading database ... 60% (Reading database ... 65% (Reading database ... 70% (Reading database ... 75% (Reading database ... 80% (Reading database ... 85% (Reading database ... 90% (Reading database ... 95% (Reading database ... 100% (Reading database ... 10514 files and directories currently installed.) +2026-03-25T12:05:42.5927206Z Preparing to unpack .../0-python3-minimal_3.12.3-0ubuntu2.1_arm64.deb ... +2026-03-25T12:05:42.6014142Z Unpacking python3-minimal (3.12.3-0ubuntu2.1) ... +2026-03-25T12:05:42.6550947Z Selecting previously unselected package media-types. +2026-03-25T12:05:42.6565762Z Preparing to unpack .../1-media-types_10.1.0_all.deb ... +2026-03-25T12:05:42.6650215Z Unpacking media-types (10.1.0) ... +2026-03-25T12:05:42.7298448Z Selecting previously unselected package netbase. +2026-03-25T12:05:42.7308345Z Preparing to unpack .../2-netbase_6.4_all.deb ... +2026-03-25T12:05:42.7390454Z Unpacking netbase (6.4) ... +2026-03-25T12:05:42.7929628Z Selecting previously unselected package libpython3.12-stdlib:arm64. +2026-03-25T12:05:42.7930194Z Preparing to unpack .../3-libpython3.12-stdlib_3.12.3-1ubuntu0.12_arm64.deb ... +2026-03-25T12:05:42.8009455Z Unpacking libpython3.12-stdlib:arm64 (3.12.3-1ubuntu0.12) ... +2026-03-25T12:05:42.9412131Z Selecting previously unselected package python3.12. +2026-03-25T12:05:42.9416942Z Preparing to unpack .../4-python3.12_3.12.3-1ubuntu0.12_arm64.deb ... +2026-03-25T12:05:42.9542497Z Unpacking python3.12 (3.12.3-1ubuntu0.12) ... +2026-03-25T12:05:43.0104645Z Selecting previously unselected package libpython3-stdlib:arm64. +2026-03-25T12:05:43.0105209Z Preparing to unpack .../5-libpython3-stdlib_3.12.3-0ubuntu2.1_arm64.deb ... +2026-03-25T12:05:43.0184920Z Unpacking libpython3-stdlib:arm64 (3.12.3-0ubuntu2.1) ... +2026-03-25T12:05:43.0704590Z Setting up python3-minimal (3.12.3-0ubuntu2.1) ... +2026-03-25T12:05:43.2911706Z Selecting previously unselected package python3. +2026-03-25T12:05:43.2943227Z (Reading database ... (Reading database ... 5% (Reading database ... 10% (Reading database ... 15% (Reading database ... 20% (Reading database ... 25% (Reading database ... 30% (Reading database ... 35% (Reading database ... 40% (Reading database ... 45% (Reading database ... 50% (Reading database ... 55% (Reading database ... 60% (Reading database ... 65% (Reading database ... 70% (Reading database ... 75% (Reading database ... 80% (Reading database ... 85% (Reading database ... 90% (Reading database ... 95% (Reading database ... 100% (Reading database ... 10955 files and directories currently installed.) +2026-03-25T12:05:43.2945936Z Preparing to unpack .../python3_3.12.3-0ubuntu2.1_arm64.deb ... +2026-03-25T12:05:43.3054683Z Unpacking python3 (3.12.3-0ubuntu2.1) ... +2026-03-25T12:05:43.3791632Z Selecting previously unselected package nodejs. +2026-03-25T12:05:43.3792145Z Preparing to unpack .../nodejs_22.22.1-1nodesource1_arm64.deb ... +2026-03-25T12:05:43.3883396Z Unpacking nodejs (22.22.1-1nodesource1) ... +2026-03-25T12:05:45.1595580Z Setting up media-types (10.1.0) ... +2026-03-25T12:05:45.1928178Z Setting up netbase (6.4) ... +2026-03-25T12:05:45.2516737Z Setting up libpython3.12-stdlib:arm64 (3.12.3-1ubuntu0.12) ... +2026-03-25T12:05:45.2763302Z Setting up python3.12 (3.12.3-1ubuntu0.12) ... +2026-03-25T12:05:46.4572507Z Setting up libpython3-stdlib:arm64 (3.12.3-0ubuntu2.1) ... +2026-03-25T12:05:46.4827528Z Setting up python3 (3.12.3-0ubuntu2.1) ... +2026-03-25T12:05:46.5029071Z running python rtupdate hooks for python3.12... +2026-03-25T12:05:46.5029813Z running python post-rtupdate hooks for python3.12... +2026-03-25T12:05:46.6148316Z Setting up nodejs (22.22.1-1nodesource1) ... +2026-03-25T12:05:47.1121917Z ::add-matcher::/run/act/actions/c3fe249fe73091a17d6638fe1341e7bd0bcc3466ce52323c0688e83e2463a4ab/dist/problem-matcher.json +2026-03-25T12:05:47.1125470Z Syncing repository: ***/***3-server +2026-03-25T12:05:47.1131969Z ::group::Getting Git version info +2026-03-25T12:05:47.1168484Z Working directory is '/workspace/***/***3-server' +2026-03-25T12:05:47.1181789Z [command]/usr/bin/git version +2026-03-25T12:05:47.1229566Z git version 2.43.0 +2026-03-25T12:05:47.1261791Z ::endgroup:: +2026-03-25T12:05:47.1293796Z Temporarily overriding HOME='/tmp/5934957e-e423-4d52-bf2d-bec37cc99fdb' before making global git config changes +2026-03-25T12:05:47.1295018Z Adding repository directory to the temporary git global config as a safe directory +2026-03-25T12:05:47.1305207Z [command]/usr/bin/git config --global --add safe.directory /workspace/***/***3-server +2026-03-25T12:05:47.1341779Z Deleting the contents of '/workspace/***/***3-server' +2026-03-25T12:05:47.1347568Z ::group::Initializing the repository +2026-03-25T12:05:47.1353328Z [command]/usr/bin/git init /workspace/***/***3-server +2026-03-25T12:05:47.1387743Z hint: Using 'master' as the name for the initial branch. This default branch name +2026-03-25T12:05:47.1388199Z hint: is subject to change. To configure the initial branch name to use in all +2026-03-25T12:05:47.1388360Z hint: of your new repositories, which will suppress this warning, call: +2026-03-25T12:05:47.1388505Z hint: +2026-03-25T12:05:47.1388717Z hint: git config --global init.defaultBranch +2026-03-25T12:05:47.1388847Z hint: +2026-03-25T12:05:47.1389121Z hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and +2026-03-25T12:05:47.1389269Z hint: 'development'. The just-created branch can be renamed via this command: +2026-03-25T12:05:47.1389422Z hint: +2026-03-25T12:05:47.1389553Z hint: git branch -m +2026-03-25T12:05:47.1394082Z Initialized empty Git repository in /workspace/***/***3-server/.git/ +2026-03-25T12:05:47.1412922Z [command]/usr/bin/git remote add origin https://gitea.siegeln.net/***/***3-server +2026-03-25T12:05:47.1454222Z ::endgroup:: +2026-03-25T12:05:47.1455198Z ::group::Disabling automatic garbage collection +2026-03-25T12:05:47.1459932Z [command]/usr/bin/git config --local gc.auto 0 +2026-03-25T12:05:47.1511236Z ::endgroup:: +2026-03-25T12:05:47.1511645Z ::group::Setting up auth +2026-03-25T12:05:47.1516443Z [command]/usr/bin/git config --local --name-only --get-regexp core\.sshCommand +2026-03-25T12:05:47.1557420Z [command]/usr/bin/git submodule foreach --recursive sh -c "git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :" +2026-03-25T12:05:47.1744851Z [command]/usr/bin/git config --local --name-only --get-regexp http\.https\:\/\/gitea\.siegeln\.net\/\.extraheader +2026-03-25T12:05:47.1778167Z [command]/usr/bin/git submodule foreach --recursive sh -c "git config --local --name-only --get-regexp 'http\.https\:\/\/gitea\.siegeln\.net\/\.extraheader' && git config --local --unset-all 'http.https://gitea.siegeln.net/.extraheader' || :" +2026-03-25T12:05:47.1961322Z [command]/usr/bin/git config --local --name-only --get-regexp ^includeIf\.gitdir: +2026-03-25T12:05:47.1992646Z [command]/usr/bin/git submodule foreach --recursive git config --local --show-origin --name-only --get-regexp remote.origin.url +2026-03-25T12:05:47.2169231Z [command]/usr/bin/git config --local http.https://gitea.siegeln.net/.extraheader AUTHORIZATION: basic *** +2026-03-25T12:05:47.2203274Z ::endgroup:: +2026-03-25T12:05:47.2203661Z ::group::Fetching the repository +2026-03-25T12:05:47.2227031Z [command]/usr/bin/git -c protocol.version=2 fetch --no-tags --prune --no-recurse-submodules --depth=1 origin +c96fbef5d517a255fbebb231cfe07c32dd7af9a2:refs/remotes/origin/main +2026-03-25T12:05:47.5225105Z From https://gitea.siegeln.net/***/***3-server +2026-03-25T12:05:47.5225789Z * [new ref] c96fbef5d517a255fbebb231cfe07c32dd7af9a2 -> origin/main +2026-03-25T12:05:47.5242588Z ::endgroup:: +2026-03-25T12:05:47.5242939Z ::group::Determining the checkout info +2026-03-25T12:05:47.5245115Z ::endgroup:: +2026-03-25T12:05:47.5250211Z [command]/usr/bin/git sparse-checkout disable +2026-03-25T12:05:47.5286780Z [command]/usr/bin/git config --local --unset-all extensions.worktreeConfig +2026-03-25T12:05:47.5312590Z ::group::Checking out the ref +2026-03-25T12:05:47.5317724Z [command]/usr/bin/git checkout --progress --force -B main refs/remotes/origin/main +2026-03-25T12:05:47.5620122Z Switched to a new branch 'main' +2026-03-25T12:05:47.5620634Z branch 'main' set up to track 'origin/main'. +2026-03-25T12:05:47.5626584Z ::endgroup:: +2026-03-25T12:05:47.5669948Z [command]/usr/bin/git log -1 --format=%H +2026-03-25T12:05:47.5692040Z c96fbef5d517a255fbebb231cfe07c32dd7af9a2 +2026-03-25T12:05:47.5706708Z ::remove-matcher owner=checkout-git:: +2026-03-25T12:05:48.3567196Z (node:674) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead. +2026-03-25T12:05:48.3567623Z (Use `node --trace-deprecation ...` to show where the warning was created) +2026-03-25T12:05:49.1970440Z Cache Size: ~352 MB (368583412 B) +2026-03-25T12:05:49.2003055Z [command]/usr/bin/tar -xf /tmp/45f912d1-a147-43aa-9691-70814448aaf7/cache.tgz -P -C /workspace/***/***3-server -z +2026-03-25T12:05:52.7483801Z Cache restored successfully +2026-03-25T12:05:52.7951677Z Cache restored from key: linux-maven-9dd3df74bd8aba32251bb49c59e820a2aa73582b0f09ca6d6e930542cfb05391 +2026-03-25T12:05:59.8118885Z +2026-03-25T12:05:59.8119616Z added 213 packages, and audited 214 packages in 7s +2026-03-25T12:05:59.8120801Z +2026-03-25T12:05:59.8121169Z 58 packages are looking for funding +2026-03-25T12:05:59.8121449Z run `npm fund` for details +2026-03-25T12:05:59.8132812Z +2026-03-25T12:05:59.8133050Z found 0 vulnerabilities +2026-03-25T12:05:59.9967402Z +2026-03-25T12:05:59.9967960Z > ui@0.0.0 build +2026-03-25T12:05:59.9968142Z > tsc -p tsconfig.app.json --noEmit && vite build +2026-03-25T12:05:59.9968297Z +2026-03-25T12:06:06.5319156Z vite v8.0.1 building client environment for production... +2026-03-25T12:06:07.1364525Z  transforming...✓ 129 modules transformed. +2026-03-25T12:06:07.2755293Z rendering chunks... +2026-03-25T12:06:07.6308430Z computing gzip size... +2026-03-25T12:06:07.6646343Z dist/index.html 0.94 kB │ gzip: 0.41 kB +2026-03-25T12:06:07.6646953Z dist/assets/dm-sans-600-Aqo67rzb.woff2 14.14 kB +2026-03-25T12:06:07.6647195Z dist/assets/dm-sans-400-CW0RaeGs.woff2 14.20 kB +2026-03-25T12:06:07.6647355Z dist/assets/dm-sans-500-B9HHJjqV.woff2 14.30 kB +2026-03-25T12:06:07.6647500Z dist/assets/dm-sans-700-DvUfVpUG.woff2 14.34 kB +2026-03-25T12:06:07.6647639Z dist/assets/dm-sans-400-italic-DRLHr0TN.woff2 15.14 kB +2026-03-25T12:06:07.6647798Z dist/assets/jetbrains-mono-400-V6pRDFza.woff2 21.16 kB +2026-03-25T12:06:07.6647949Z dist/assets/jetbrains-mono-500-BWZEU5yA.woff2 21.83 kB +2026-03-25T12:06:07.6648100Z dist/assets/jetbrains-mono-600-C8RAYTDA.woff2 21.86 kB +2026-03-25T12:06:07.6648237Z dist/assets/OidcConfigPage-Bq9_k9q2.css 0.61 kB │ gzip: 0.31 kB +2026-03-25T12:06:07.6648385Z dist/assets/AuditLogPage-wcUcdzwn.css 1.19 kB │ gzip: 0.56 kB +2026-03-25T12:06:07.6648541Z dist/assets/RoutesMetrics-DaUBduav.css 1.46 kB │ gzip: 0.62 kB +2026-03-25T12:06:07.6648704Z dist/assets/RbacPage-5iGc4gch.css 1.98 kB │ gzip: 0.69 kB +2026-03-25T12:06:07.6648857Z dist/assets/AgentInstance--Z0IKMF0.css 2.50 kB │ gzip: 0.75 kB +2026-03-25T12:06:07.6649011Z dist/assets/AgentHealth-y0_55tmK.css 3.42 kB │ gzip: 1.04 kB +2026-03-25T12:06:07.6649159Z dist/assets/Dashboard-BYYJXEtx.css 3.64 kB │ gzip: 1.13 kB +2026-03-25T12:06:07.6649404Z dist/assets/RouteDetail-CjL6IMio.css 4.26 kB │ gzip: 1.09 kB +2026-03-25T12:06:07.6649547Z dist/assets/ExchangeDetail-VcItziWb.css 6.78 kB │ gzip: 1.67 kB +2026-03-25T12:06:07.6649698Z dist/assets/index-CXegvd7B.css 111.14 kB │ gzip: 18.21 kB +2026-03-25T12:06:07.6649862Z dist/assets/SwaggerPage-CH1CJXTy.css 176.70 kB │ gzip: 26.18 kB +2026-03-25T12:06:07.6650017Z dist/assets/use-refresh-interval-CBD44ngw.js 0.19 kB │ gzip: 0.15 kB +2026-03-25T12:06:07.6650157Z dist/assets/admin-api-Dldh4fYm.js 0.49 kB │ gzip: 0.35 kB +2026-03-25T12:06:07.6650297Z dist/assets/AdminLayout-CKg4TLhS.js 0.55 kB │ gzip: 0.34 kB +2026-03-25T12:06:07.6650468Z dist/assets/chunk-B3K2TuZy.js 0.55 kB │ gzip: 0.35 kB +2026-03-25T12:06:07.6650606Z dist/assets/agent-metrics-DI4HNJNm.js 0.59 kB │ gzip: 0.42 kB +2026-03-25T12:06:07.6650776Z dist/assets/SwaggerPage-ZwDCrEj1.js 0.87 kB │ gzip: 0.54 kB +2026-03-25T12:06:07.6650931Z dist/assets/diagram-mapping-zsjZZKRP.js 1.33 kB │ gzip: 0.68 kB +2026-03-25T12:06:07.6651084Z dist/assets/useMutation-CjGnzIYg.js 2.31 kB │ gzip: 0.97 kB +2026-03-25T12:06:07.6651227Z dist/assets/OpenSearchAdminPage-WnM4gikq.js 2.92 kB │ gzip: 1.17 kB +2026-03-25T12:06:07.6651367Z dist/assets/DatabaseAdminPage-CclQJ0Ok.js 3.09 kB │ gzip: 1.16 kB +2026-03-25T12:06:07.6651574Z dist/assets/AuditLogPage-4V3oK99a.js 4.53 kB │ gzip: 1.70 kB +2026-03-25T12:06:07.6651718Z dist/assets/OidcConfigPage-D0YsPv3U.js 5.38 kB │ gzip: 1.90 kB +2026-03-25T12:06:07.6651866Z dist/assets/RoutesMetrics-5XMqf33P.js 5.98 kB │ gzip: 2.10 kB +2026-03-25T12:06:07.6652008Z dist/assets/jsx-runtime-DdsoV0Vr.js 9.07 kB │ gzip: 3.52 kB +2026-03-25T12:06:07.6652178Z dist/assets/AgentInstance-Bzs6lRBr.js 9.86 kB │ gzip: 2.83 kB +2026-03-25T12:06:07.6652328Z dist/assets/Dashboard-C23kCbUs.js 10.16 kB │ gzip: 3.28 kB +2026-03-25T12:06:07.6652472Z dist/assets/auth-store-DCBo9Ans.js 10.34 kB │ gzip: 3.79 kB +2026-03-25T12:06:07.6652628Z dist/assets/AgentHealth-DwOu1dM9.js 11.36 kB │ gzip: 3.28 kB +2026-03-25T12:06:07.6652774Z dist/assets/RouteDetail-l02TOYKF.js 12.35 kB │ gzip: 4.07 kB +2026-03-25T12:06:07.6652926Z dist/assets/ExchangeDetail-BLpXn9YT.js 14.56 kB │ gzip: 4.25 kB +2026-03-25T12:06:07.6653071Z dist/assets/useQuery-oR6RVwVH.js 22.31 kB │ gzip: 7.37 kB +2026-03-25T12:06:07.6653215Z dist/assets/RbacPage-oz3jLDxG.js 25.49 kB │ gzip: 5.57 kB +2026-03-25T12:06:07.6653360Z dist/assets/index-COBtXOCg.js 205.44 kB │ gzip: 64.73 kB +2026-03-25T12:06:07.6653503Z dist/assets/index.es-BideRJQn.js 216.16 kB │ gzip: 66.22 kB +2026-03-25T12:06:07.6653661Z dist/assets/swagger-ui-bundle-BoDRmAdn.js 1,371.99 kB │ gzip: 390.77 kB +2026-03-25T12:06:07.6653794Z +2026-03-25T12:06:07.6657850Z ✓ built in 1.13s +2026-03-25T12:06:07.6667869Z [plugin builtin:vite-reporter] +2026-03-25T12:06:07.6668214Z (!) Some chunks are larger than 500 kB after minification. Consider: +2026-03-25T12:06:07.6668402Z - Using dynamic import() to code-split the application +2026-03-25T12:06:07.6668544Z - Use build.rolldownOptions.output.codeSplitting to improve chunking: https://rolldown.rs/reference/OutputOptions.codeSplitting +2026-03-25T12:06:07.6668727Z - Adjust chunk size limit for this warning via build.chunkSizeWarningLimit. +2026-03-25T12:06:09.5292704Z [INFO] Scanning for projects... +2026-03-25T12:06:09.9635324Z [INFO] ------------------------------------------------------------------------ +2026-03-25T12:06:09.9636148Z [INFO] Reactor Build Order: +2026-03-25T12:06:09.9636467Z [INFO] +2026-03-25T12:06:09.9659474Z [INFO] Cameleer3 Server Parent [pom] +2026-03-25T12:06:09.9660313Z [INFO] Cameleer3 Server Core [jar] +2026-03-25T12:06:09.9660795Z [INFO] Cameleer3 Server App [jar] +2026-03-25T12:06:09.9828555Z [INFO] +2026-03-25T12:06:09.9829990Z [INFO] ---------------< com.***3:***3-server-parent >---------------- +2026-03-25T12:06:09.9830445Z [INFO] Building Cameleer3 Server Parent 1.0-SNAPSHOT [1/3] +2026-03-25T12:06:09.9831993Z [INFO] from pom.xml +2026-03-25T12:06:09.9832701Z [INFO] --------------------------------[ pom ]--------------------------------- +2026-03-25T12:06:10.0308726Z [INFO] +2026-03-25T12:06:10.0310168Z [INFO] --- clean:3.4.1:clean (default-clean) @ ***3-server-parent --- +2026-03-25T12:06:10.1462826Z [INFO] +2026-03-25T12:06:10.1463418Z [INFO] ----------------< com.***3:***3-server-core >----------------- +2026-03-25T12:06:10.1463669Z [INFO] Building Cameleer3 Server Core 1.0-SNAPSHOT [2/3] +2026-03-25T12:06:10.1464039Z [INFO] from ***3-server-core/pom.xml +2026-03-25T12:06:10.1464250Z [INFO] --------------------------------[ jar ]--------------------------------- +2026-03-25T12:06:10.4658491Z [INFO] +2026-03-25T12:06:10.4659065Z [INFO] --- clean:3.4.1:clean (default-clean) @ ***3-server-core --- +2026-03-25T12:06:10.4666288Z [INFO] +2026-03-25T12:06:10.4667848Z [INFO] --- resources:3.3.1:resources (default-resources) @ ***3-server-core --- +2026-03-25T12:06:10.6497862Z [INFO] skip non existing resourceDirectory /workspace/***/***3-server/***3-server-core/src/main/resources +2026-03-25T12:06:10.6498571Z [INFO] skip non existing resourceDirectory /workspace/***/***3-server/***3-server-core/src/main/resources +2026-03-25T12:06:10.6506664Z [INFO] +2026-03-25T12:06:10.6508453Z [INFO] --- compiler:3.13.0:compile (default-compile) @ ***3-server-core --- +2026-03-25T12:06:10.8563867Z [INFO] Recompiling the module because of changed source code. +2026-03-25T12:06:10.8674155Z [INFO] Compiling 63 source files with javac [debug parameters release 17] to target/classes +2026-03-25T12:06:12.7604194Z [INFO] ------------------------------------------------------------- +2026-03-25T12:06:12.7607101Z [ERROR] COMPILATION ERROR : +2026-03-25T12:06:12.7610106Z [INFO] ------------------------------------------------------------- +2026-03-25T12:06:12.7612996Z [ERROR] /workspace/***/***3-server/***3-server-core/src/main/java/com/***3/server/core/logging/LogIndexService.java:[3,34] cannot find symbol +2026-03-25T12:06:12.7613413Z symbol: class LogEntry +2026-03-25T12:06:12.7614388Z location: package com.***3.common.model +2026-03-25T12:06:12.7616233Z [ERROR] /workspace/***/***3-server/***3-server-core/src/main/java/com/***3/server/core/logging/LogIndexService.java:[9,62] cannot find symbol +2026-03-25T12:06:12.7616604Z symbol: class LogEntry +2026-03-25T12:06:12.7617505Z location: interface com.***3.server.core.logging.LogIndexService +2026-03-25T12:06:12.7620033Z [INFO] 2 errors +2026-03-25T12:06:12.7622462Z [INFO] ------------------------------------------------------------- +2026-03-25T12:06:12.7631912Z [INFO] ------------------------------------------------------------------------ +2026-03-25T12:06:12.7640947Z [INFO] Reactor Summary for Cameleer3 Server Parent 1.0-SNAPSHOT: +2026-03-25T12:06:12.7641508Z [INFO] +2026-03-25T12:06:12.7641764Z [INFO] Cameleer3 Server Parent ............................ SUCCESS [ 0.164 s] +2026-03-25T12:06:12.7643553Z [INFO] Cameleer3 Server Core .............................. FAILURE [ 2.617 s] +2026-03-25T12:06:12.7646103Z [INFO] Cameleer3 Server App ............................... SKIPPED +2026-03-25T12:06:12.7647941Z [INFO] ------------------------------------------------------------------------ +2026-03-25T12:06:12.7649783Z [INFO] BUILD FAILURE +2026-03-25T12:06:12.7651509Z [INFO] ------------------------------------------------------------------------ +2026-03-25T12:06:12.7654688Z [INFO] Total time: 3.272 s +2026-03-25T12:06:12.7658348Z [INFO] Finished at: 2026-03-25T12:06:12Z +2026-03-25T12:06:12.7660448Z [INFO] ------------------------------------------------------------------------ +2026-03-25T12:06:12.7673796Z [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.13.0:compile (default-compile) on project ***3-server-core: Compilation failure: Compilation failure: +2026-03-25T12:06:12.7676849Z [ERROR] /workspace/***/***3-server/***3-server-core/src/main/java/com/***3/server/core/logging/LogIndexService.java:[3,34] cannot find symbol +2026-03-25T12:06:12.7678889Z [ERROR] symbol: class LogEntry +2026-03-25T12:06:12.7680952Z [ERROR] location: package com.***3.common.model +2026-03-25T12:06:12.7683008Z [ERROR] /workspace/***/***3-server/***3-server-core/src/main/java/com/***3/server/core/logging/LogIndexService.java:[9,62] cannot find symbol +2026-03-25T12:06:12.7684745Z [ERROR] symbol: class LogEntry +2026-03-25T12:06:12.7686592Z [ERROR] location: interface com.***3.server.core.logging.LogIndexService +2026-03-25T12:06:12.7688226Z [ERROR] -> [Help 1] +2026-03-25T12:06:12.7690315Z [ERROR] +2026-03-25T12:06:12.7692768Z [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch. +2026-03-25T12:06:12.7695202Z [ERROR] Re-run Maven using the -X switch to enable full debug logging. +2026-03-25T12:06:12.7696809Z [ERROR] +2026-03-25T12:06:12.7698861Z [ERROR] For more information about the errors and possible solutions, please read the following articles: +2026-03-25T12:06:12.7701441Z [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException +2026-03-25T12:06:12.7704048Z [ERROR] +2026-03-25T12:06:12.7706710Z [ERROR] After correcting the problems, you can resume the build with the command +2026-03-25T12:06:12.7709299Z [ERROR] mvn -rf :***3-server-core +2026-03-25T12:06:12.7956855Z ❌ Failure - Main Build and Test +2026-03-25T12:06:12.8053054Z exitcode '1': failure +2026-03-25T12:06:12.8172878Z expression '${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}' rewritten to 'format('{0}-maven-{1}', runner.os, hashFiles('**/pom.xml'))' +2026-03-25T12:06:12.8173396Z evaluating expression 'format('{0}-maven-{1}', runner.os, hashFiles('**/pom.xml'))' +2026-03-25T12:06:12.8173938Z Writing entry to tarball workflow/hashfiles/index.js len:168437 +2026-03-25T12:06:12.8175042Z Extracting content to '/var/run/act' +2026-03-25T12:06:12.8200679Z 🐳 docker exec cmd=[node /var/run/act/workflow/hashfiles/index.js] user= workdir= +2026-03-25T12:06:12.8201166Z Exec command '[node /var/run/act/workflow/hashfiles/index.js]' +2026-03-25T12:06:12.8201431Z Working directory '/workspace/***/***3-server' +2026-03-25T12:06:13.7622028Z expression 'format('{0}-maven-{1}', runner.os, hashFiles('**/pom.xml'))' evaluated to '%!t(string=Linux-maven-9dd3df74bd8aba32251bb49c59e820a2aa73582b0f09ca6d6e930542cfb05391)' +2026-03-25T12:06:13.7622739Z expression '${{ runner.os }}-maven-' rewritten to 'format('{0}-maven-', runner.os)' +2026-03-25T12:06:13.7622916Z evaluating expression 'format('{0}-maven-', runner.os)' +2026-03-25T12:06:13.7623310Z expression 'format('{0}-maven-', runner.os)' evaluated to '%!t(string=Linux-maven-)' +2026-03-25T12:06:13.7690142Z evaluating expression 'success()' +2026-03-25T12:06:13.7690751Z expression 'success()' evaluated to 'false' +2026-03-25T12:06:13.7690943Z Skipping step 'Cache Maven dependencies' due to 'success()' +2026-03-25T12:06:13.7866385Z evaluating expression 'always()' +2026-03-25T12:06:13.7867031Z expression 'always()' evaluated to 'true' +2026-03-25T12:06:13.7867186Z ⭐ Run Post actions/checkout@v4 +2026-03-25T12:06:13.7867446Z Writing entry to tarball workflow/outputcmd.txt len:0 +2026-03-25T12:06:13.7867652Z Writing entry to tarball workflow/statecmd.txt len:0 +2026-03-25T12:06:13.7867796Z Writing entry to tarball workflow/pathcmd.txt len:0 +2026-03-25T12:06:13.7867971Z Writing entry to tarball workflow/envs.txt len:0 +2026-03-25T12:06:13.7868116Z Writing entry to tarball workflow/SUMMARY.md len:0 +2026-03-25T12:06:13.7868291Z Extracting content to '/var/run/act' +2026-03-25T12:06:13.7889163Z run post step for 'actions/checkout@v4' +2026-03-25T12:06:13.7890176Z executing remote job container: [node /var/run/act/actions/c3fe249fe73091a17d6638fe1341e7bd0bcc3466ce52323c0688e83e2463a4ab/dist/index.js] +2026-03-25T12:06:13.7890429Z 🐳 docker exec cmd=[node /var/run/act/actions/c3fe249fe73091a17d6638fe1341e7bd0bcc3466ce52323c0688e83e2463a4ab/dist/index.js] user= workdir= +2026-03-25T12:06:13.7890606Z Exec command '[node /var/run/act/actions/c3fe249fe73091a17d6638fe1341e7bd0bcc3466ce52323c0688e83e2463a4ab/dist/index.js]' +2026-03-25T12:06:13.7891224Z Working directory '/workspace/***/***3-server' +2026-03-25T12:06:13.9476106Z [command]/usr/bin/git version +2026-03-25T12:06:13.9522100Z git version 2.43.0 +2026-03-25T12:06:13.9555048Z *** +2026-03-25T12:06:13.9573206Z Temporarily overriding HOME='/tmp/08ab9b22-8656-4251-863f-5956d0d8e373' before making global git config changes +2026-03-25T12:06:13.9573942Z Adding repository directory to the temporary git global config as a safe directory +2026-03-25T12:06:13.9598283Z [command]/usr/bin/git config --global --add safe.directory /workspace/***/***3-server +2026-03-25T12:06:13.9638135Z [command]/usr/bin/git config --local --name-only --get-regexp core\.sshCommand +2026-03-25T12:06:13.9679759Z [command]/usr/bin/git submodule foreach --recursive sh -c "git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :" +2026-03-25T12:06:13.9859674Z [command]/usr/bin/git config --local --name-only --get-regexp http\.https\:\/\/gitea\.siegeln\.net\/\.extraheader +2026-03-25T12:06:13.9881882Z http.https://gitea.siegeln.net/.extraheader +2026-03-25T12:06:13.9896989Z [command]/usr/bin/git config --local --unset-all http.https://gitea.siegeln.net/.extraheader +2026-03-25T12:06:13.9932110Z [command]/usr/bin/git submodule foreach --recursive sh -c "git config --local --name-only --get-regexp 'http\.https\:\/\/gitea\.siegeln\.net\/\.extraheader' && git config --local --unset-all 'http.https://gitea.siegeln.net/.extraheader' || :" +2026-03-25T12:06:14.0109604Z [command]/usr/bin/git config --local --name-only --get-regexp ^includeIf\.gitdir: +2026-03-25T12:06:14.0143262Z [command]/usr/bin/git submodule foreach --recursive git config --local --show-origin --name-only --get-regexp remote.origin.url +2026-03-25T12:06:14.0389618Z ✅ Success - Post actions/checkout@v4 +2026-03-25T12:06:14.0478463Z Cleaning up container for job build +2026-03-25T12:06:16.3320674Z Removed container: 7218bfea7789106d54e48224d5541c49969b5cca00766ae2ffdcbc415f9c35ae +2026-03-25T12:06:16.3335327Z 🐳 docker volume rm GITEA-ACTIONS-TASK-1104_WORKFLOW-CI_JOB-build +2026-03-25T12:06:16.5379506Z 🐳 docker volume rm GITEA-ACTIONS-TASK-1104_WORKFLOW-CI_JOB-build-env +2026-03-25T12:06:16.6181283Z 🏁 Job failed +2026-03-25T12:06:16.6241459Z Job 'build' failed diff --git a/ci-log2.txt b/ci-log2.txt new file mode 100644 index 00000000..90a703b2 --- /dev/null +++ b/ci-log2.txt @@ -0,0 +1,488 @@ +2026-03-25T12:11:15.0673241Z my-docker-runner(version:v0.3.0) received task 1109 of job build, be triggered by event: push +2026-03-25T12:11:15.0678286Z workflow prepared +2026-03-25T12:11:15.0679524Z evaluating expression 'github.event_name != 'delete'' +2026-03-25T12:11:15.0680588Z expression 'github.event_name != 'delete'' evaluated to 'true' +2026-03-25T12:11:15.0680862Z 🚀 Start image=maven:3.9-eclipse-temurin-17 +2026-03-25T12:11:15.0765600Z 🐳 docker pull image=maven:3.9-eclipse-temurin-17 platform= username= forcePull=true +2026-03-25T12:11:15.0766370Z 🐳 docker pull maven:3.9-eclipse-temurin-17 +2026-03-25T12:11:15.0766922Z pulling image 'docker.io/library/maven:3.9-eclipse-temurin-17' () +2026-03-25T12:11:15.9297560Z Pulling from library/maven :: 3.9-eclipse-temurin-17 +2026-03-25T12:11:15.9512271Z Digest: sha256:39a5260d49fe20e5f407bf63f63a267d9870965bcd1d114e52e1e50ba1c55a32 :: +2026-03-25T12:11:15.9512734Z Status: Image is up to date for maven:3.9-eclipse-temurin-17 :: +2026-03-25T12:11:15.9638746Z 🐳 docker create image=maven:3.9-eclipse-temurin-17 platform= entrypoint=["/bin/sleep" "10800"] cmd=[] network="gitea_gitea_default" +2026-03-25T12:11:15.9735982Z Custom container.Config from options ==> &{Hostname: Domainname: User: AttachStdin:false AttachStdout:true AttachStderr:true ExposedPorts:map[] Tty:false OpenStdin:false StdinOnce:false Env:[] Cmd:[] Healthcheck: ArgsEscaped:false Image: Volumes:map[] WorkingDir: Entrypoint:[] NetworkDisabled:false MacAddress: OnBuild:[] Labels:map[] StopSignal: StopTimeout: Shell:[]} +2026-03-25T12:11:15.9736700Z Merged container.Config ==> &{Hostname: Domainname: User: AttachStdin:false AttachStdout:true AttachStderr:true ExposedPorts:map[] Tty:false OpenStdin:false StdinOnce:false Env:[RUNNER_TOOL_CACHE=/opt/hostedtoolcache RUNNER_OS=Linux RUNNER_ARCH=ARM64 RUNNER_TEMP=/tmp LANG=C.UTF-8] Cmd:[] Healthcheck: ArgsEscaped:false Image:maven:3.9-eclipse-temurin-17 Volumes:map[] WorkingDir:/workspace/***/***3-server Entrypoint:[/bin/sleep 10800] NetworkDisabled:false MacAddress: OnBuild:[] Labels:map[] StopSignal: StopTimeout: Shell:[]} +2026-03-25T12:11:15.9737364Z Custom container.HostConfig from options ==> &{Binds:[] ContainerIDFile: LogConfig:{Type: Config:map[]} NetworkMode:gitea_gitea_default PortBindings:map[] RestartPolicy:{Name:no MaximumRetryCount:0} AutoRemove:false VolumeDriver: VolumesFrom:[] ConsoleSize:[0 0] Annotations:map[] CapAdd:[] CapDrop:[] CgroupnsMode: DNS:[] DNSOptions:[] DNSSearch:[] ExtraHosts:[] GroupAdd:[] IpcMode: Cgroup: Links:[] OomScoreAdj:0 PidMode: Privileged:false PublishAllPorts:false ReadonlyRootfs:false SecurityOpt:[] StorageOpt:map[] Tmpfs:map[] UTSMode: UsernsMode: ShmSize:0 Sysctls:map[] Runtime: Isolation: Resources:{CPUShares:0 Memory:0 NanoCPUs:0 CgroupParent: BlkioWeight:0 BlkioWeightDevice:[] BlkioDeviceReadBps:[] BlkioDeviceWriteBps:[] BlkioDeviceReadIOps:[] BlkioDeviceWriteIOps:[] CPUPeriod:0 CPUQuota:0 CPURealtimePeriod:0 CPURealtimeRuntime:0 CpusetCpus: CpusetMems: Devices:[] DeviceCgroupRules:[] DeviceRequests:[] KernelMemory:0 KernelMemoryTCP:0 MemoryReservation:0 MemorySwap:0 MemorySwappiness:0x228ace0e23c8 OomKillDisable:0x228ace0e22c3 PidsLimit:0x228ace0e2428 Ulimits:[] CPUCount:0 CPUPercent:0 IOMaximumIOps:0 IOMaximumBandwidth:0} Mounts:[] MaskedPaths:[] ReadonlyPaths:[] Init:} +2026-03-25T12:11:15.9738107Z --network and --net in the options will be ignored. +2026-03-25T12:11:15.9738529Z Merged container.HostConfig ==> &{Binds:[/var/run/docker.sock:/var/run/docker.sock] ContainerIDFile: LogConfig:{Type: Config:map[]} NetworkMode:gitea_gitea_default PortBindings:map[] RestartPolicy:{Name:no MaximumRetryCount:0} AutoRemove:true VolumeDriver: VolumesFrom:[] ConsoleSize:[0 0] Annotations:map[] CapAdd:[] CapDrop:[] CgroupnsMode: DNS:[] DNSOptions:[] DNSSearch:[] ExtraHosts:[] GroupAdd:[] IpcMode: Cgroup: Links:[] OomScoreAdj:0 PidMode: Privileged:false PublishAllPorts:false ReadonlyRootfs:false SecurityOpt:[] StorageOpt:map[] Tmpfs:map[] UTSMode: UsernsMode: ShmSize:0 Sysctls:map[] Runtime: Isolation: Resources:{CPUShares:0 Memory:0 NanoCPUs:0 CgroupParent: BlkioWeight:0 BlkioWeightDevice:[] BlkioDeviceReadBps:[] BlkioDeviceWriteBps:[] BlkioDeviceReadIOps:[] BlkioDeviceWriteIOps:[] CPUPeriod:0 CPUQuota:0 CPURealtimePeriod:0 CPURealtimeRuntime:0 CpusetCpus: CpusetMems: Devices:[] DeviceCgroupRules:[] DeviceRequests:[] KernelMemory:0 KernelMemoryTCP:0 MemoryReservation:0 MemorySwap:0 MemorySwappiness:0x228ace0e23c8 OomKillDisable:0x228ace0e22c3 PidsLimit:0x228ace0e2428 Ulimits:[] CPUCount:0 CPUPercent:0 IOMaximumIOps:0 IOMaximumBandwidth:0} Mounts:[{Type:volume Source:act-toolcache Target:/opt/hostedtoolcache ReadOnly:false Consistency: BindOptions: VolumeOptions: TmpfsOptions: ClusterOptions:} {Type:volume Source:GITEA-ACTIONS-TASK-1109_WORKFLOW-CI_JOB-build-env Target:/var/run/act ReadOnly:false Consistency: BindOptions: VolumeOptions: TmpfsOptions: ClusterOptions:} {Type:volume Source:GITEA-ACTIONS-TASK-1109_WORKFLOW-CI_JOB-build Target:/workspace/***/***3-server ReadOnly:false Consistency: BindOptions: VolumeOptions: TmpfsOptions: ClusterOptions:}] MaskedPaths:[] ReadonlyPaths:[] Init:} +2026-03-25T12:11:16.0650880Z Created container name=GITEA-ACTIONS-TASK-1109_WORKFLOW-CI_JOB-build id=81d7988ac62ef23d7fea4defd927f69654288f6f2a5992c3480ab61a65fc57f2 from image maven:3.9-eclipse-temurin-17 (platform: ) +2026-03-25T12:11:16.0651415Z ENV ==> [RUNNER_TOOL_CACHE=/opt/hostedtoolcache RUNNER_OS=Linux RUNNER_ARCH=ARM64 RUNNER_TEMP=/tmp LANG=C.UTF-8] +2026-03-25T12:11:16.0651606Z 🐳 docker run image=maven:3.9-eclipse-temurin-17 platform= entrypoint=["/bin/sleep" "10800"] cmd=[] network="gitea_gitea_default" +2026-03-25T12:11:16.0651774Z Starting container: 81d7988ac62ef23d7fea4defd927f69654288f6f2a5992c3480ab61a65fc57f2 +2026-03-25T12:11:16.2476626Z Started container: 81d7988ac62ef23d7fea4defd927f69654288f6f2a5992c3480ab61a65fc57f2 +2026-03-25T12:11:16.3385957Z Writing entry to tarball workflow/event.json len:6148 +2026-03-25T12:11:16.3386642Z Writing entry to tarball workflow/envs.txt len:0 +2026-03-25T12:11:16.3386938Z Extracting content to '/var/run/act/' +2026-03-25T12:11:16.3535771Z ☁ git clone 'https://github.com/actions/checkout' # ref=v4 +2026-03-25T12:11:16.3536162Z cloning https://github.com/actions/checkout to /root/.cache/act/c3fe249fe73091a17d6638fe1341e7bd0bcc3466ce52323c0688e83e2463a4ab +2026-03-25T12:11:16.6693512Z Non-terminating error while running 'git clone': some refs were not updated +2026-03-25T12:11:16.6760011Z ☁ git clone 'https://github.com/actions/cache' # ref=v4 +2026-03-25T12:11:16.6760438Z cloning https://github.com/actions/cache to /root/.cache/act/6b4e4eb40e21c1bd02cb00a273f4d79af7c42205c1390e4e65c594ecd7a3696e +2026-03-25T12:11:17.5454691Z Non-terminating error while running 'git clone': some refs were not updated +2026-03-25T12:11:17.5674244Z evaluating expression '' +2026-03-25T12:11:17.5675000Z expression '' evaluated to 'true' +2026-03-25T12:11:17.5675244Z ⭐ Run Main Install Node.js 22 +2026-03-25T12:11:17.5675584Z Writing entry to tarball workflow/outputcmd.txt len:0 +2026-03-25T12:11:17.5675865Z Writing entry to tarball workflow/statecmd.txt len:0 +2026-03-25T12:11:17.5676098Z Writing entry to tarball workflow/pathcmd.txt len:0 +2026-03-25T12:11:17.5676311Z Writing entry to tarball workflow/envs.txt len:0 +2026-03-25T12:11:17.5676498Z Writing entry to tarball workflow/SUMMARY.md len:0 +2026-03-25T12:11:17.5676698Z Extracting content to '/var/run/act' +2026-03-25T12:11:17.5917925Z Wrote command \n\napt-get update && apt-get install -y ca-certificates curl gnupg\nmkdir -p /etc/apt/keyrings\ncurl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg\necho "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" > /etc/apt/sources.list.d/nodesource.list\napt-get update && apt-get install -y nodejs\n\n\n to 'workflow/0.sh' +2026-03-25T12:11:17.5918846Z Writing entry to tarball workflow/0.sh len:407 +2026-03-25T12:11:17.5919160Z Extracting content to '/var/run/act' +2026-03-25T12:11:17.5943770Z 🐳 docker exec cmd=[sh -e /var/run/act/workflow/0.sh] user= workdir= +2026-03-25T12:11:17.5944375Z Exec command '[sh -e /var/run/act/workflow/0.sh]' +2026-03-25T12:11:17.5944971Z Working directory '/workspace/***/***3-server' +2026-03-25T12:11:17.8888948Z Get:1 http://ports.ubuntu.com/ubuntu-ports noble InRelease [256 kB] +2026-03-25T12:11:18.4199917Z Get:2 http://ports.ubuntu.com/ubuntu-ports noble-updates InRelease [126 kB] +2026-03-25T12:11:18.5517055Z Get:3 http://ports.ubuntu.com/ubuntu-ports noble-backports InRelease [126 kB] +2026-03-25T12:11:18.6832646Z Get:4 http://ports.ubuntu.com/ubuntu-ports noble-security InRelease [126 kB] +2026-03-25T12:11:18.8159266Z Get:5 http://ports.ubuntu.com/ubuntu-ports noble/restricted arm64 Packages [113 kB] +2026-03-25T12:11:18.8552983Z Get:6 http://ports.ubuntu.com/ubuntu-ports noble/main arm64 Packages [1,776 kB] +2026-03-25T12:11:19.1280961Z Get:7 http://ports.ubuntu.com/ubuntu-ports noble/universe arm64 Packages [19.0 MB] +2026-03-25T12:11:19.6229227Z Get:8 http://ports.ubuntu.com/ubuntu-ports noble/multiverse arm64 Packages [274 kB] +2026-03-25T12:11:19.6298357Z Get:9 http://ports.ubuntu.com/ubuntu-ports noble-updates/restricted arm64 Packages [5,019 kB] +2026-03-25T12:11:19.7533806Z Get:10 http://ports.ubuntu.com/ubuntu-ports noble-updates/main arm64 Packages [2,451 kB] +2026-03-25T12:11:19.8087840Z Get:11 http://ports.ubuntu.com/ubuntu-ports noble-updates/universe arm64 Packages [2,057 kB] +2026-03-25T12:11:19.8574738Z Get:12 http://ports.ubuntu.com/ubuntu-ports noble-updates/multiverse arm64 Packages [45.7 kB] +2026-03-25T12:11:19.8583840Z Get:13 http://ports.ubuntu.com/ubuntu-ports noble-backports/universe arm64 Packages [36.1 kB] +2026-03-25T12:11:19.8587388Z Get:14 http://ports.ubuntu.com/ubuntu-ports noble-backports/main arm64 Packages [49.5 kB] +2026-03-25T12:11:19.8599308Z Get:15 http://ports.ubuntu.com/ubuntu-ports noble-backports/multiverse arm64 Packages [695 B] +2026-03-25T12:11:19.8601750Z Get:16 http://ports.ubuntu.com/ubuntu-ports noble-security/main arm64 Packages [2,087 kB] +2026-03-25T12:11:19.9076502Z Get:17 http://ports.ubuntu.com/ubuntu-ports noble-security/multiverse arm64 Packages [44.1 kB] +2026-03-25T12:11:19.9088113Z Get:18 http://ports.ubuntu.com/ubuntu-ports noble-security/restricted arm64 Packages [4,828 kB] +2026-03-25T12:11:20.0209834Z Get:19 http://ports.ubuntu.com/ubuntu-ports noble-security/universe arm64 Packages [1,502 kB] +2026-03-25T12:11:21.2001793Z Fetched 39.9 MB in 4s (11.4 MB/s) +2026-03-25T12:11:22.4920632Z Reading package lists... +2026-03-25T12:11:23.8283529Z Reading package lists... +2026-03-25T12:11:24.1797003Z Building dependency tree... +2026-03-25T12:11:24.1797885Z Reading state information... +2026-03-25T12:11:24.9189505Z ca-certificates is already the newest version (20240203). +2026-03-25T12:11:24.9190005Z curl is already the newest version (8.5.0-2ubuntu10.8). +2026-03-25T12:11:24.9190221Z gnupg is already the newest version (2.4.4-2ubuntu17.4). +2026-03-25T12:11:24.9190409Z 0 upgraded, 0 newly installed, 0 to remove and 18 not upgraded. +2026-03-25T12:11:25.2124240Z Get:1 https://deb.nodesource.com/node_22.x nodistro InRelease [12.1 kB] +2026-03-25T12:11:25.2904786Z Get:2 https://deb.nodesource.com/node_22.x nodistro/main arm64 Packages [9,040 B] +2026-03-25T12:11:34.8063450Z Hit:3 http://ports.ubuntu.com/ubuntu-ports noble InRelease +2026-03-25T12:11:34.8884900Z Hit:4 http://ports.ubuntu.com/ubuntu-ports noble-updates InRelease +2026-03-25T12:11:34.9713799Z Hit:5 http://ports.ubuntu.com/ubuntu-ports noble-backports InRelease +2026-03-25T12:11:35.3400058Z Hit:6 http://ports.ubuntu.com/ubuntu-ports noble-security InRelease +2026-03-25T12:11:35.3911975Z Fetched 21.2 kB in 10s (2,048 B/s) +2026-03-25T12:11:36.6884300Z Reading package lists... +2026-03-25T12:11:38.0360973Z Reading package lists... +2026-03-25T12:11:38.4220315Z Building dependency tree... +2026-03-25T12:11:38.4221340Z Reading state information... +2026-03-25T12:11:39.0941013Z The following additional packages will be installed: +2026-03-25T12:11:39.0960465Z libpython3-stdlib libpython3.12-minimal libpython3.12-stdlib media-types +2026-03-25T12:11:39.0966161Z netbase python3 python3-minimal python3.12 python3.12-minimal +2026-03-25T12:11:39.0998340Z Suggested packages: +2026-03-25T12:11:39.0998714Z python3-doc python3-tk python3-venv python3.12-venv python3.12-doc +2026-03-25T12:11:39.0998888Z binfmt-support +2026-03-25T12:11:39.1810008Z The following NEW packages will be installed: +2026-03-25T12:11:39.1823006Z libpython3-stdlib libpython3.12-minimal libpython3.12-stdlib media-types +2026-03-25T12:11:39.1830570Z netbase nodejs python3 python3-minimal python3.12 python3.12-minimal +2026-03-25T12:11:39.2816298Z 0 upgraded, 10 newly installed, 0 to remove and 18 not upgraded. +2026-03-25T12:11:39.2816843Z Need to get 42.9 MB of archives. +2026-03-25T12:11:39.2817042Z After this operation, 259 MB of additional disk space will be used. +2026-03-25T12:11:39.2817215Z Get:1 http://ports.ubuntu.com/ubuntu-ports noble-updates/main arm64 libpython3.12-minimal arm64 3.12.3-1ubuntu0.12 [834 kB] +2026-03-25T12:11:39.3903078Z Get:2 https://deb.nodesource.com/node_22.x nodistro/main arm64 nodejs arm64 22.22.1-1nodesource1 [37.0 MB] +2026-03-25T12:11:39.4744824Z Get:3 http://ports.ubuntu.com/ubuntu-ports noble-updates/main arm64 python3.12-minimal arm64 3.12.3-1ubuntu0.12 [2,252 kB] +2026-03-25T12:11:39.5305320Z Get:4 http://ports.ubuntu.com/ubuntu-ports noble-updates/main arm64 python3-minimal arm64 3.12.3-0ubuntu2.1 [27.4 kB] +2026-03-25T12:11:39.5309325Z Get:5 http://ports.ubuntu.com/ubuntu-ports noble/main arm64 media-types all 10.1.0 [27.5 kB] +2026-03-25T12:11:39.5330600Z Get:6 http://ports.ubuntu.com/ubuntu-ports noble/main arm64 netbase all 6.4 [13.1 kB] +2026-03-25T12:11:39.5333740Z Get:7 http://ports.ubuntu.com/ubuntu-ports noble-updates/main arm64 libpython3.12-stdlib arm64 3.12.3-1ubuntu0.12 [2,037 kB] +2026-03-25T12:11:39.5758776Z Get:8 http://ports.ubuntu.com/ubuntu-ports noble-updates/main arm64 python3.12 arm64 3.12.3-1ubuntu0.12 [651 kB] +2026-03-25T12:11:39.5835423Z Get:9 http://ports.ubuntu.com/ubuntu-ports noble-updates/main arm64 libpython3-stdlib arm64 3.12.3-0ubuntu2.1 [10.1 kB] +2026-03-25T12:11:39.5839250Z Get:10 http://ports.ubuntu.com/ubuntu-ports noble-updates/main arm64 python3 arm64 3.12.3-0ubuntu2.1 [23.0 kB] +2026-03-25T12:11:40.4405153Z debconf: delaying package configuration, since apt-utils is not installed +2026-03-25T12:11:40.5017505Z Fetched 42.9 MB in 1s (45.9 MB/s) +2026-03-25T12:11:40.5588037Z Selecting previously unselected package libpython3.12-minimal:arm64. +2026-03-25T12:11:40.5615337Z (Reading database ... (Reading database ... 5% (Reading database ... 10% (Reading database ... 15% (Reading database ... 20% (Reading database ... 25% (Reading database ... 30% (Reading database ... 35% (Reading database ... 40% (Reading database ... 45% (Reading database ... 50% (Reading database ... 55% (Reading database ... 60% (Reading database ... 65% (Reading database ... 70% (Reading database ... 75% (Reading database ... 80% (Reading database ... 85% (Reading database ... 90% (Reading database ... 95% (Reading database ... 100% (Reading database ... 10203 files and directories currently installed.) +2026-03-25T12:11:40.5626546Z Preparing to unpack .../libpython3.12-minimal_3.12.3-1ubuntu0.12_arm64.deb ... +2026-03-25T12:11:40.5712786Z Unpacking libpython3.12-minimal:arm64 (3.12.3-1ubuntu0.12) ... +2026-03-25T12:11:40.7085040Z Selecting previously unselected package python3.12-minimal. +2026-03-25T12:11:40.7096226Z Preparing to unpack .../python3.12-minimal_3.12.3-1ubuntu0.12_arm64.deb ... +2026-03-25T12:11:40.7201720Z Unpacking python3.12-minimal (3.12.3-1ubuntu0.12) ... +2026-03-25T12:11:40.8107975Z Setting up libpython3.12-minimal:arm64 (3.12.3-1ubuntu0.12) ... +2026-03-25T12:11:40.8653673Z Setting up python3.12-minimal (3.12.3-1ubuntu0.12) ... +2026-03-25T12:11:41.9358111Z Selecting previously unselected package python3-minimal. +2026-03-25T12:11:41.9403560Z (Reading database ... (Reading database ... 5% (Reading database ... 10% (Reading database ... 15% (Reading database ... 20% (Reading database ... 25% (Reading database ... 30% (Reading database ... 35% (Reading database ... 40% (Reading database ... 45% (Reading database ... 50% (Reading database ... 55% (Reading database ... 60% (Reading database ... 65% (Reading database ... 70% (Reading database ... 75% (Reading database ... 80% (Reading database ... 85% (Reading database ... 90% (Reading database ... 95% (Reading database ... 100% (Reading database ... 10514 files and directories currently installed.) +2026-03-25T12:11:41.9413961Z Preparing to unpack .../0-python3-minimal_3.12.3-0ubuntu2.1_arm64.deb ... +2026-03-25T12:11:41.9559244Z Unpacking python3-minimal (3.12.3-0ubuntu2.1) ... +2026-03-25T12:11:42.0307879Z Selecting previously unselected package media-types. +2026-03-25T12:11:42.0325837Z Preparing to unpack .../1-media-types_10.1.0_all.deb ... +2026-03-25T12:11:42.0457110Z Unpacking media-types (10.1.0) ... +2026-03-25T12:11:42.1145168Z Selecting previously unselected package netbase. +2026-03-25T12:11:42.1159169Z Preparing to unpack .../2-netbase_6.4_all.deb ... +2026-03-25T12:11:42.1242901Z Unpacking netbase (6.4) ... +2026-03-25T12:11:42.1792726Z Selecting previously unselected package libpython3.12-stdlib:arm64. +2026-03-25T12:11:42.1793740Z Preparing to unpack .../3-libpython3.12-stdlib_3.12.3-1ubuntu0.12_arm64.deb ... +2026-03-25T12:11:42.1880816Z Unpacking libpython3.12-stdlib:arm64 (3.12.3-1ubuntu0.12) ... +2026-03-25T12:11:42.3101823Z Selecting previously unselected package python3.12. +2026-03-25T12:11:42.3113846Z Preparing to unpack .../4-python3.12_3.12.3-1ubuntu0.12_arm64.deb ... +2026-03-25T12:11:42.3201402Z Unpacking python3.12 (3.12.3-1ubuntu0.12) ... +2026-03-25T12:11:42.3772802Z Selecting previously unselected package libpython3-stdlib:arm64. +2026-03-25T12:11:42.3773312Z Preparing to unpack .../5-libpython3-stdlib_3.12.3-0ubuntu2.1_arm64.deb ... +2026-03-25T12:11:42.3858444Z Unpacking libpython3-stdlib:arm64 (3.12.3-0ubuntu2.1) ... +2026-03-25T12:11:42.4387555Z Setting up python3-minimal (3.12.3-0ubuntu2.1) ... +2026-03-25T12:11:42.6614832Z Selecting previously unselected package python3. +2026-03-25T12:11:42.6659520Z (Reading database ... (Reading database ... 5% (Reading database ... 10% (Reading database ... 15% (Reading database ... 20% (Reading database ... 25% (Reading database ... 30% (Reading database ... 35% (Reading database ... 40% (Reading database ... 45% (Reading database ... 50% (Reading database ... 55% (Reading database ... 60% (Reading database ... 65% (Reading database ... 70% (Reading database ... 75% (Reading database ... 80% (Reading database ... 85% (Reading database ... 90% (Reading database ... 95% (Reading database ... 100% (Reading database ... 10955 files and directories currently installed.) +2026-03-25T12:11:42.6670209Z Preparing to unpack .../python3_3.12.3-0ubuntu2.1_arm64.deb ... +2026-03-25T12:11:42.6782622Z Unpacking python3 (3.12.3-0ubuntu2.1) ... +2026-03-25T12:11:42.7536426Z Selecting previously unselected package nodejs. +2026-03-25T12:11:42.7543156Z Preparing to unpack .../nodejs_22.22.1-1nodesource1_arm64.deb ... +2026-03-25T12:11:42.7640439Z Unpacking nodejs (22.22.1-1nodesource1) ... +2026-03-25T12:11:44.5533574Z Setting up media-types (10.1.0) ... +2026-03-25T12:11:44.6116920Z Setting up netbase (6.4) ... +2026-03-25T12:11:44.7126932Z Setting up libpython3.12-stdlib:arm64 (3.12.3-1ubuntu0.12) ... +2026-03-25T12:11:44.7537181Z Setting up python3.12 (3.12.3-1ubuntu0.12) ... +2026-03-25T12:11:45.9736127Z Setting up libpython3-stdlib:arm64 (3.12.3-0ubuntu2.1) ... +2026-03-25T12:11:45.9995094Z Setting up python3 (3.12.3-0ubuntu2.1) ... +2026-03-25T12:11:46.0202105Z running python rtupdate hooks for python3.12... +2026-03-25T12:11:46.0202749Z running python post-rtupdate hooks for python3.12... +2026-03-25T12:11:46.1647503Z Setting up nodejs (22.22.1-1nodesource1) ... +2026-03-25T12:11:46.6406508Z ::add-matcher::/run/act/actions/c3fe249fe73091a17d6638fe1341e7bd0bcc3466ce52323c0688e83e2463a4ab/dist/problem-matcher.json +2026-03-25T12:11:46.6410499Z Syncing repository: ***/***3-server +2026-03-25T12:11:46.6414140Z ::group::Getting Git version info +2026-03-25T12:11:46.6414740Z Working directory is '/workspace/***/***3-server' +2026-03-25T12:11:46.6451296Z [command]/usr/bin/git version +2026-03-25T12:11:46.6498415Z git version 2.43.0 +2026-03-25T12:11:46.6528997Z ::endgroup:: +2026-03-25T12:11:46.6559915Z Temporarily overriding HOME='/tmp/b1eaf53a-eeb8-4afe-bb1b-963811cdef44' before making global git config changes +2026-03-25T12:11:46.6560661Z Adding repository directory to the temporary git global config as a safe directory +2026-03-25T12:11:46.6569698Z [command]/usr/bin/git config --global --add safe.directory /workspace/***/***3-server +2026-03-25T12:11:46.6604482Z Deleting the contents of '/workspace/***/***3-server' +2026-03-25T12:11:46.6609411Z ::group::Initializing the repository +2026-03-25T12:11:46.6614132Z [command]/usr/bin/git init /workspace/***/***3-server +2026-03-25T12:11:46.6647197Z hint: Using 'master' as the name for the initial branch. This default branch name +2026-03-25T12:11:46.6647668Z hint: is subject to change. To configure the initial branch name to use in all +2026-03-25T12:11:46.6647876Z hint: of your new repositories, which will suppress this warning, call: +2026-03-25T12:11:46.6648031Z hint: +2026-03-25T12:11:46.6648344Z hint: git config --global init.defaultBranch +2026-03-25T12:11:46.6648485Z hint: +2026-03-25T12:11:46.6648606Z hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and +2026-03-25T12:11:46.6648745Z hint: 'development'. The just-created branch can be renamed via this command: +2026-03-25T12:11:46.6648895Z hint: +2026-03-25T12:11:46.6649012Z hint: git branch -m +2026-03-25T12:11:46.6655581Z Initialized empty Git repository in /workspace/***/***3-server/.git/ +2026-03-25T12:11:46.6673484Z [command]/usr/bin/git remote add origin https://gitea.siegeln.net/***/***3-server +2026-03-25T12:11:46.6705963Z ::endgroup:: +2026-03-25T12:11:46.6706313Z ::group::Disabling automatic garbage collection +2026-03-25T12:11:46.6711562Z [command]/usr/bin/git config --local gc.auto 0 +2026-03-25T12:11:46.6742385Z ::endgroup:: +2026-03-25T12:11:46.6742714Z ::group::Setting up auth +2026-03-25T12:11:46.6753437Z [command]/usr/bin/git config --local --name-only --get-regexp core\.sshCommand +2026-03-25T12:11:46.6785919Z [command]/usr/bin/git submodule foreach --recursive sh -c "git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :" +2026-03-25T12:11:46.6964779Z [command]/usr/bin/git config --local --name-only --get-regexp http\.https\:\/\/gitea\.siegeln\.net\/\.extraheader +2026-03-25T12:11:46.6996612Z [command]/usr/bin/git submodule foreach --recursive sh -c "git config --local --name-only --get-regexp 'http\.https\:\/\/gitea\.siegeln\.net\/\.extraheader' && git config --local --unset-all 'http.https://gitea.siegeln.net/.extraheader' || :" +2026-03-25T12:11:46.7177068Z [command]/usr/bin/git config --local --name-only --get-regexp ^includeIf\.gitdir: +2026-03-25T12:11:46.7209537Z [command]/usr/bin/git submodule foreach --recursive git config --local --show-origin --name-only --get-regexp remote.origin.url +2026-03-25T12:11:46.7386392Z [command]/usr/bin/git config --local http.https://gitea.siegeln.net/.extraheader AUTHORIZATION: basic *** +2026-03-25T12:11:46.7420093Z ::endgroup:: +2026-03-25T12:11:46.7420425Z ::group::Fetching the repository +2026-03-25T12:11:46.7444311Z [command]/usr/bin/git -c protocol.version=2 fetch --no-tags --prune --no-recurse-submodules --depth=1 origin +7fd55ea8ba92830ddad59dd3fe3d9a0516254946:refs/remotes/origin/main +2026-03-25T12:11:47.0408153Z From https://gitea.siegeln.net/***/***3-server +2026-03-25T12:11:47.0408743Z * [new ref] 7fd55ea8ba92830ddad59dd3fe3d9a0516254946 -> origin/main +2026-03-25T12:11:47.0425449Z ::endgroup:: +2026-03-25T12:11:47.0425869Z ::group::Determining the checkout info +2026-03-25T12:11:47.0428330Z ::endgroup:: +2026-03-25T12:11:47.0434686Z [command]/usr/bin/git sparse-checkout disable +2026-03-25T12:11:47.0468001Z [command]/usr/bin/git config --local --unset-all extensions.worktreeConfig +2026-03-25T12:11:47.0494380Z ::group::Checking out the ref +2026-03-25T12:11:47.0499182Z [command]/usr/bin/git checkout --progress --force -B main refs/remotes/origin/main +2026-03-25T12:11:47.0799235Z Switched to a new branch 'main' +2026-03-25T12:11:47.0801974Z branch 'main' set up to track 'origin/main'. +2026-03-25T12:11:47.0807273Z ::endgroup:: +2026-03-25T12:11:47.0851193Z [command]/usr/bin/git log -1 --format=%H +2026-03-25T12:11:47.0873738Z 7fd55ea8ba92830ddad59dd3fe3d9a0516254946 +2026-03-25T12:11:47.0889884Z ::remove-matcher owner=checkout-git:: +2026-03-25T12:11:47.9031005Z (node:674) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead. +2026-03-25T12:11:47.9031552Z (Use `node --trace-deprecation ...` to show where the warning was created) +2026-03-25T12:11:48.7715362Z Cache Size: ~352 MB (368583412 B) +2026-03-25T12:11:48.7746030Z [command]/usr/bin/tar -xf /tmp/0d28713b-77ea-40d9-ac8d-19c5adfc0c5d/cache.tgz -P -C /workspace/***/***3-server -z +2026-03-25T12:11:52.3545912Z Cache restored successfully +2026-03-25T12:11:52.3981691Z Cache restored from key: linux-maven-9dd3df74bd8aba32251bb49c59e820a2aa73582b0f09ca6d6e930542cfb05391 +2026-03-25T12:11:59.0472225Z +2026-03-25T12:11:59.0473793Z added 213 packages, and audited 214 packages in 6s +2026-03-25T12:11:59.0474257Z +2026-03-25T12:11:59.0474791Z 58 packages are looking for funding +2026-03-25T12:11:59.0474965Z run `npm fund` for details +2026-03-25T12:11:59.0493731Z +2026-03-25T12:11:59.0494280Z found 0 vulnerabilities +2026-03-25T12:11:59.2308378Z +2026-03-25T12:11:59.2309072Z > ui@0.0.0 build +2026-03-25T12:11:59.2309247Z > tsc -p tsconfig.app.json --noEmit && vite build +2026-03-25T12:11:59.2309401Z +2026-03-25T12:12:05.6744989Z vite v8.0.1 building client environment for production... +2026-03-25T12:12:06.3075689Z  transforming...✓ 129 modules transformed. +2026-03-25T12:12:06.4496363Z rendering chunks... +2026-03-25T12:12:06.8014982Z computing gzip size... +2026-03-25T12:12:06.8346038Z dist/index.html 0.94 kB │ gzip: 0.41 kB +2026-03-25T12:12:06.8346660Z dist/assets/dm-sans-600-Aqo67rzb.woff2 14.14 kB +2026-03-25T12:12:06.8346848Z dist/assets/dm-sans-400-CW0RaeGs.woff2 14.20 kB +2026-03-25T12:12:06.8347005Z dist/assets/dm-sans-500-B9HHJjqV.woff2 14.30 kB +2026-03-25T12:12:06.8347232Z dist/assets/dm-sans-700-DvUfVpUG.woff2 14.34 kB +2026-03-25T12:12:06.8347378Z dist/assets/dm-sans-400-italic-DRLHr0TN.woff2 15.14 kB +2026-03-25T12:12:06.8347520Z dist/assets/jetbrains-mono-400-V6pRDFza.woff2 21.16 kB +2026-03-25T12:12:06.8347661Z dist/assets/jetbrains-mono-500-BWZEU5yA.woff2 21.83 kB +2026-03-25T12:12:06.8347799Z dist/assets/jetbrains-mono-600-C8RAYTDA.woff2 21.86 kB +2026-03-25T12:12:06.8347942Z dist/assets/OidcConfigPage-Bq9_k9q2.css 0.61 kB │ gzip: 0.31 kB +2026-03-25T12:12:06.8348093Z dist/assets/AuditLogPage-wcUcdzwn.css 1.19 kB │ gzip: 0.56 kB +2026-03-25T12:12:06.8348237Z dist/assets/RoutesMetrics-DaUBduav.css 1.46 kB │ gzip: 0.62 kB +2026-03-25T12:12:06.8348390Z dist/assets/RbacPage-5iGc4gch.css 1.98 kB │ gzip: 0.69 kB +2026-03-25T12:12:06.8348537Z dist/assets/AgentInstance--Z0IKMF0.css 2.50 kB │ gzip: 0.75 kB +2026-03-25T12:12:06.8348713Z dist/assets/AgentHealth-y0_55tmK.css 3.42 kB │ gzip: 1.04 kB +2026-03-25T12:12:06.8348861Z dist/assets/Dashboard-BYYJXEtx.css 3.64 kB │ gzip: 1.13 kB +2026-03-25T12:12:06.8349210Z dist/assets/RouteDetail-CjL6IMio.css 4.26 kB │ gzip: 1.09 kB +2026-03-25T12:12:06.8349349Z dist/assets/ExchangeDetail-VcItziWb.css 6.78 kB │ gzip: 1.67 kB +2026-03-25T12:12:06.8349503Z dist/assets/index-CXegvd7B.css 111.14 kB │ gzip: 18.21 kB +2026-03-25T12:12:06.8349645Z dist/assets/SwaggerPage-CH1CJXTy.css 176.70 kB │ gzip: 26.18 kB +2026-03-25T12:12:06.8349786Z dist/assets/use-refresh-interval-CBD44ngw.js 0.19 kB │ gzip: 0.15 kB +2026-03-25T12:12:06.8349931Z dist/assets/admin-api-Dldh4fYm.js 0.49 kB │ gzip: 0.35 kB +2026-03-25T12:12:06.8350083Z dist/assets/AdminLayout-CKg4TLhS.js 0.55 kB │ gzip: 0.34 kB +2026-03-25T12:12:06.8350288Z dist/assets/chunk-B3K2TuZy.js 0.55 kB │ gzip: 0.35 kB +2026-03-25T12:12:06.8350433Z dist/assets/agent-metrics-DI4HNJNm.js 0.59 kB │ gzip: 0.42 kB +2026-03-25T12:12:06.8350571Z dist/assets/SwaggerPage-ZwDCrEj1.js 0.87 kB │ gzip: 0.54 kB +2026-03-25T12:12:06.8350710Z dist/assets/diagram-mapping-zsjZZKRP.js 1.33 kB │ gzip: 0.68 kB +2026-03-25T12:12:06.8350879Z dist/assets/useMutation-CjGnzIYg.js 2.31 kB │ gzip: 0.97 kB +2026-03-25T12:12:06.8351033Z dist/assets/OpenSearchAdminPage-WnM4gikq.js 2.92 kB │ gzip: 1.17 kB +2026-03-25T12:12:06.8351173Z dist/assets/DatabaseAdminPage-CclQJ0Ok.js 3.09 kB │ gzip: 1.16 kB +2026-03-25T12:12:06.8351328Z dist/assets/AuditLogPage-4V3oK99a.js 4.53 kB │ gzip: 1.70 kB +2026-03-25T12:12:06.8351477Z dist/assets/OidcConfigPage-D0YsPv3U.js 5.38 kB │ gzip: 1.90 kB +2026-03-25T12:12:06.8351642Z dist/assets/RoutesMetrics-5XMqf33P.js 5.98 kB │ gzip: 2.10 kB +2026-03-25T12:12:06.8351804Z dist/assets/jsx-runtime-DdsoV0Vr.js 9.07 kB │ gzip: 3.52 kB +2026-03-25T12:12:06.8351939Z dist/assets/AgentInstance-Bzs6lRBr.js 9.86 kB │ gzip: 2.83 kB +2026-03-25T12:12:06.8352077Z dist/assets/Dashboard-C23kCbUs.js 10.16 kB │ gzip: 3.28 kB +2026-03-25T12:12:06.8352236Z dist/assets/auth-store-DCBo9Ans.js 10.34 kB │ gzip: 3.79 kB +2026-03-25T12:12:06.8352399Z dist/assets/AgentHealth-DwOu1dM9.js 11.36 kB │ gzip: 3.28 kB +2026-03-25T12:12:06.8352543Z dist/assets/RouteDetail-l02TOYKF.js 12.35 kB │ gzip: 4.07 kB +2026-03-25T12:12:06.8352685Z dist/assets/ExchangeDetail-BLpXn9YT.js 14.56 kB │ gzip: 4.25 kB +2026-03-25T12:12:06.8352827Z dist/assets/useQuery-oR6RVwVH.js 22.31 kB │ gzip: 7.37 kB +2026-03-25T12:12:06.8352968Z dist/assets/RbacPage-oz3jLDxG.js 25.49 kB │ gzip: 5.57 kB +2026-03-25T12:12:06.8353149Z dist/assets/index-COBtXOCg.js 205.44 kB │ gzip: 64.73 kB +2026-03-25T12:12:06.8353297Z dist/assets/index.es-BideRJQn.js 216.16 kB │ gzip: 66.22 kB +2026-03-25T12:12:06.8353439Z dist/assets/swagger-ui-bundle-BoDRmAdn.js 1,371.99 kB │ gzip: 390.77 kB +2026-03-25T12:12:06.8353572Z +2026-03-25T12:12:06.8353740Z ✓ built in 1.16s +2026-03-25T12:12:06.8356107Z [plugin builtin:vite-reporter] +2026-03-25T12:12:06.8356389Z (!) Some chunks are larger than 500 kB after minification. Consider: +2026-03-25T12:12:06.8356581Z - Using dynamic import() to code-split the application +2026-03-25T12:12:06.8356726Z - Use build.rolldownOptions.output.codeSplitting to improve chunking: https://rolldown.rs/reference/OutputOptions.codeSplitting +2026-03-25T12:12:06.8356917Z - Adjust chunk size limit for this warning via build.chunkSizeWarningLimit. +2026-03-25T12:12:08.8592085Z [INFO] Scanning for projects... +2026-03-25T12:12:09.3994902Z [INFO] ------------------------------------------------------------------------ +2026-03-25T12:12:09.3995662Z [INFO] Reactor Build Order: +2026-03-25T12:12:09.3995968Z [INFO] +2026-03-25T12:12:09.4015044Z [INFO] Cameleer3 Server Parent [pom] +2026-03-25T12:12:09.4016943Z [INFO] Cameleer3 Server Core [jar] +2026-03-25T12:12:09.4020267Z [INFO] Cameleer3 Server App [jar] +2026-03-25T12:12:09.4204897Z [INFO] +2026-03-25T12:12:09.4206974Z [INFO] ---------------< com.***3:***3-server-parent >---------------- +2026-03-25T12:12:09.4209665Z [INFO] Building Cameleer3 Server Parent 1.0-SNAPSHOT [1/3] +2026-03-25T12:12:09.4213444Z [INFO] from pom.xml +2026-03-25T12:12:09.4215425Z [INFO] --------------------------------[ pom ]--------------------------------- +2026-03-25T12:12:09.4758836Z [INFO] +2026-03-25T12:12:09.4761722Z [INFO] --- clean:3.4.1:clean (default-clean) @ ***3-server-parent --- +2026-03-25T12:12:09.5985349Z [INFO] +2026-03-25T12:12:09.5998691Z [INFO] ----------------< com.***3:***3-server-core >----------------- +2026-03-25T12:12:09.5999367Z [INFO] Building Cameleer3 Server Core 1.0-SNAPSHOT [2/3] +2026-03-25T12:12:09.5999608Z [INFO] from ***3-server-core/pom.xml +2026-03-25T12:12:09.5999870Z [INFO] --------------------------------[ jar ]--------------------------------- +2026-03-25T12:12:09.9264378Z [INFO] +2026-03-25T12:12:09.9265012Z [INFO] --- clean:3.4.1:clean (default-clean) @ ***3-server-core --- +2026-03-25T12:12:09.9294155Z [INFO] +2026-03-25T12:12:09.9294802Z [INFO] --- resources:3.3.1:resources (default-resources) @ ***3-server-core --- +2026-03-25T12:12:10.1415949Z [INFO] skip non existing resourceDirectory /workspace/***/***3-server/***3-server-core/src/main/resources +2026-03-25T12:12:10.1416720Z [INFO] skip non existing resourceDirectory /workspace/***/***3-server/***3-server-core/src/main/resources +2026-03-25T12:12:10.1433945Z [INFO] +2026-03-25T12:12:10.1434657Z [INFO] --- compiler:3.13.0:compile (default-compile) @ ***3-server-core --- +2026-03-25T12:12:10.3640938Z [INFO] Recompiling the module because of changed source code. +2026-03-25T12:12:10.3728671Z [INFO] Compiling 62 source files with javac [debug parameters release 17] to target/classes +2026-03-25T12:12:12.5455820Z [INFO] +2026-03-25T12:12:12.5458698Z [INFO] --- resources:3.3.1:testResources (default-testResources) @ ***3-server-core --- +2026-03-25T12:12:12.5545314Z [INFO] skip non existing resourceDirectory /workspace/***/***3-server/***3-server-core/src/test/resources +2026-03-25T12:12:12.5551351Z [INFO] +2026-03-25T12:12:12.5554792Z [INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ ***3-server-core --- +2026-03-25T12:12:12.5684758Z [INFO] Recompiling the module because of changed dependency. +2026-03-25T12:12:12.5695664Z [INFO] Compiling 3 source files with javac [debug parameters release 17] to target/test-classes +2026-03-25T12:12:13.8627365Z [INFO] +2026-03-25T12:12:13.8629352Z [INFO] --- surefire:3.5.2:test (default-test) @ ***3-server-core --- +2026-03-25T12:12:14.1009777Z [INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider +2026-03-25T12:12:14.1865594Z [INFO] +2026-03-25T12:12:14.1866264Z [INFO] ------------------------------------------------------- +2026-03-25T12:12:14.1866544Z [INFO] T E S T S +2026-03-25T12:12:14.1867788Z [INFO] ------------------------------------------------------- +2026-03-25T12:12:15.2551472Z [INFO] Running com.***3.server.core.detail.TreeReconstructionTest +2026-03-25T12:12:15.5724418Z OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended +2026-03-25T12:12:16.6140778Z [INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.313 s -- in com.***3.server.core.detail.TreeReconstructionTest +2026-03-25T12:12:16.6183288Z [INFO] Running com.***3.server.core.agent.AgentRegistryServiceTest +2026-03-25T12:12:16.6190775Z [INFO] Running com.***3.server.core.agent.AgentRegistryServiceTest$Commands +2026-03-25T12:12:16.6263438Z SLF4J(W): No SLF4J providers were found. +2026-03-25T12:12:16.6264169Z SLF4J(W): Defaulting to no-operation (NOP) logger implementation +2026-03-25T12:12:16.6264406Z SLF4J(W): See https://www.slf4j.org/codes.html#noProviders for further details. +2026-03-25T12:12:16.6999152Z [INFO] Tests run: 8, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.104 s -- in com.***3.server.core.agent.AgentRegistryServiceTest$Commands +2026-03-25T12:12:16.7024457Z [INFO] Running com.***3.server.core.agent.AgentRegistryServiceTest$Queries +2026-03-25T12:12:16.7186966Z [INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.028 s -- in com.***3.server.core.agent.AgentRegistryServiceTest$Queries +2026-03-25T12:12:16.7189398Z [INFO] Running com.***3.server.core.agent.AgentRegistryServiceTest$LifecycleTransitions +2026-03-25T12:12:16.7933600Z [INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.066 s -- in com.***3.server.core.agent.AgentRegistryServiceTest$LifecycleTransitions +2026-03-25T12:12:16.7944637Z [INFO] Running com.***3.server.core.agent.AgentRegistryServiceTest$Heartbeat +2026-03-25T12:12:16.8157231Z [INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.015 s -- in com.***3.server.core.agent.AgentRegistryServiceTest$Heartbeat +2026-03-25T12:12:16.8190493Z [INFO] Running com.***3.server.core.agent.AgentRegistryServiceTest$Registration +2026-03-25T12:12:16.8289762Z [INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.020 s -- in com.***3.server.core.agent.AgentRegistryServiceTest$Registration +2026-03-25T12:12:16.8405658Z [INFO] Tests run: 0, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.254 s -- in com.***3.server.core.agent.AgentRegistryServiceTest +2026-03-25T12:12:16.8433351Z [INFO] Running com.***3.server.core.ingestion.WriteBufferTest +2026-03-25T12:12:16.8748334Z [INFO] Tests run: 10, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.041 s -- in com.***3.server.core.ingestion.WriteBufferTest +2026-03-25T12:12:16.8990584Z [INFO] +2026-03-25T12:12:16.8991202Z [INFO] Results: +2026-03-25T12:12:16.8991549Z [INFO] +2026-03-25T12:12:16.8996481Z [INFO] Tests run: 37, Failures: 0, Errors: 0, Skipped: 0 +2026-03-25T12:12:16.8997041Z [INFO] +2026-03-25T12:12:16.9036244Z [INFO] +2026-03-25T12:12:16.9036930Z [INFO] --- jar:3.4.2:jar (default-jar) @ ***3-server-core --- +2026-03-25T12:12:17.3553610Z [INFO] Building jar: /workspace/***/***3-server/***3-server-core/target/***3-server-core-1.0-SNAPSHOT.jar +2026-03-25T12:12:17.4343059Z [INFO] +2026-03-25T12:12:17.4343761Z [INFO] -----------------< com.***3:***3-server-app >----------------- +2026-03-25T12:12:17.4344006Z [INFO] Building Cameleer3 Server App 1.0-SNAPSHOT [3/3] +2026-03-25T12:12:17.4346242Z [INFO] from ***3-server-app/pom.xml +2026-03-25T12:12:17.4347591Z [INFO] --------------------------------[ jar ]--------------------------------- +2026-03-25T12:12:18.7737910Z [INFO] +2026-03-25T12:12:18.7738533Z [INFO] --- clean:3.4.1:clean (default-clean) @ ***3-server-app --- +2026-03-25T12:12:18.7770445Z [INFO] +2026-03-25T12:12:18.7771175Z [INFO] --- resources:3.3.1:copy-resources (copy-ui-dist) @ ***3-server-app --- +2026-03-25T12:12:18.7925285Z [INFO] Copying 48 resources from ../ui/dist to target/classes/static +2026-03-25T12:12:18.8155069Z [INFO] +2026-03-25T12:12:18.8156631Z [INFO] --- resources:3.3.1:resources (default-resources) @ ***3-server-app --- +2026-03-25T12:12:18.8197148Z [INFO] Copying 1 resource from src/main/resources to target/classes +2026-03-25T12:12:18.8639638Z [INFO] Copying 4 resources from src/main/resources to target/classes +2026-03-25T12:12:18.8640395Z [INFO] +2026-03-25T12:12:18.8640613Z [INFO] --- compiler:3.13.0:compile (default-compile) @ ***3-server-app --- +2026-03-25T12:12:18.8844470Z [INFO] Recompiling the module because of changed dependency. +2026-03-25T12:12:18.8848893Z [INFO] Compiling 104 source files with javac [debug parameters release 17] to target/classes +2026-03-25T12:12:21.8486343Z [INFO] /workspace/***/***3-server/***3-server-app/src/main/java/com/***3/server/app/security/OidcTokenExchanger.java: /workspace/***/***3-server/***3-server-app/src/main/java/com/***3/server/app/security/OidcTokenExchanger.java uses or overrides a deprecated API. +2026-03-25T12:12:21.8487241Z [INFO] /workspace/***/***3-server/***3-server-app/src/main/java/com/***3/server/app/security/OidcTokenExchanger.java: Recompile with -Xlint:deprecation for details. +2026-03-25T12:12:21.8487541Z [INFO] ------------------------------------------------------------- +2026-03-25T12:12:21.8487894Z [ERROR] COMPILATION ERROR : +2026-03-25T12:12:21.8488157Z [INFO] ------------------------------------------------------------- +2026-03-25T12:12:21.8488337Z [ERROR] /workspace/***/***3-server/***3-server-app/src/main/java/com/***3/server/app/controller/LogIngestionController.java:[3,34] cannot find symbol +2026-03-25T12:12:21.8488560Z symbol: class LogBatch +2026-03-25T12:12:21.8488701Z location: package com.***3.common.model +2026-03-25T12:12:21.8488975Z [ERROR] /workspace/***/***3-server/***3-server-app/src/main/java/com/***3/server/app/search/OpenSearchLogIndex.java:[3,34] cannot find symbol +2026-03-25T12:12:21.8489229Z symbol: class LogEntry +2026-03-25T12:12:21.8489369Z location: package com.***3.common.model +2026-03-25T12:12:21.8489585Z [ERROR] /workspace/***/***3-server/***3-server-app/src/main/java/com/***3/server/app/controller/LogIngestionController.java:[40,57] cannot find symbol +2026-03-25T12:12:21.8489887Z symbol: class LogBatch +2026-03-25T12:12:21.8490086Z location: class com.***3.server.app.controller.LogIngestionController +2026-03-25T12:12:21.8490358Z [ERROR] /workspace/***/***3-server/***3-server-app/src/main/java/com/***3/server/app/search/OpenSearchLogIndex.java:[94,69] cannot find symbol +2026-03-25T12:12:21.8490581Z symbol: class LogEntry +2026-03-25T12:12:21.8490739Z location: class com.***3.server.app.search.OpenSearchLogIndex +2026-03-25T12:12:21.8490944Z [ERROR] /workspace/***/***3-server/***3-server-app/src/main/java/com/***3/server/app/search/OpenSearchLogIndex.java:[135,39] cannot find symbol +2026-03-25T12:12:21.8491180Z symbol: class LogEntry +2026-03-25T12:12:21.8491349Z location: class com.***3.server.app.search.OpenSearchLogIndex +2026-03-25T12:12:21.8491573Z [ERROR] /workspace/***/***3-server/***3-server-app/src/main/java/com/***3/server/app/search/OpenSearchLogIndex.java:[102,18] cannot find symbol +2026-03-25T12:12:21.8491783Z symbol: class LogEntry +2026-03-25T12:12:21.8491947Z location: class com.***3.server.app.search.OpenSearchLogIndex +2026-03-25T12:12:21.8492176Z [INFO] 6 errors +2026-03-25T12:12:21.8492385Z [INFO] ------------------------------------------------------------- +2026-03-25T12:12:21.8502503Z [INFO] ------------------------------------------------------------------------ +2026-03-25T12:12:21.8503274Z [INFO] Reactor Summary for Cameleer3 Server Parent 1.0-SNAPSHOT: +2026-03-25T12:12:21.8503850Z [INFO] +2026-03-25T12:12:21.8524175Z [INFO] Cameleer3 Server Parent ............................ SUCCESS [ 0.178 s] +2026-03-25T12:12:21.8524906Z [INFO] Cameleer3 Server Core .............................. SUCCESS [ 7.835 s] +2026-03-25T12:12:21.8525142Z [INFO] Cameleer3 Server App ............................... FAILURE [ 4.416 s] +2026-03-25T12:12:21.8525315Z [INFO] ------------------------------------------------------------------------ +2026-03-25T12:12:21.8525608Z [INFO] BUILD FAILURE +2026-03-25T12:12:21.8525797Z [INFO] ------------------------------------------------------------------------ +2026-03-25T12:12:21.8526046Z [INFO] Total time: 13.033 s +2026-03-25T12:12:21.8526239Z [INFO] Finished at: 2026-03-25T12:12:21Z +2026-03-25T12:12:21.8526470Z [INFO] ------------------------------------------------------------------------ +2026-03-25T12:12:21.8539577Z [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.13.0:compile (default-compile) on project ***3-server-app: Compilation failure: Compilation failure: +2026-03-25T12:12:21.8540261Z [ERROR] /workspace/***/***3-server/***3-server-app/src/main/java/com/***3/server/app/controller/LogIngestionController.java:[3,34] cannot find symbol +2026-03-25T12:12:21.8540576Z [ERROR] symbol: class LogBatch +2026-03-25T12:12:21.8540792Z [ERROR] location: package com.***3.common.model +2026-03-25T12:12:21.8541144Z [ERROR] /workspace/***/***3-server/***3-server-app/src/main/java/com/***3/server/app/search/OpenSearchLogIndex.java:[3,34] cannot find symbol +2026-03-25T12:12:21.8541428Z [ERROR] symbol: class LogEntry +2026-03-25T12:12:21.8541596Z [ERROR] location: package com.***3.common.model +2026-03-25T12:12:21.8541880Z [ERROR] /workspace/***/***3-server/***3-server-app/src/main/java/com/***3/server/app/controller/LogIngestionController.java:[40,57] cannot find symbol +2026-03-25T12:12:21.8542178Z [ERROR] symbol: class LogBatch +2026-03-25T12:12:21.8542402Z [ERROR] location: class com.***3.server.app.controller.LogIngestionController +2026-03-25T12:12:21.8542619Z [ERROR] /workspace/***/***3-server/***3-server-app/src/main/java/com/***3/server/app/search/OpenSearchLogIndex.java:[94,69] cannot find symbol +2026-03-25T12:12:21.8542855Z [ERROR] symbol: class LogEntry +2026-03-25T12:12:21.8543160Z [ERROR] location: class com.***3.server.app.search.OpenSearchLogIndex +2026-03-25T12:12:21.8543969Z [ERROR] /workspace/***/***3-server/***3-server-app/src/main/java/com/***3/server/app/search/OpenSearchLogIndex.java:[135,39] cannot find symbol +2026-03-25T12:12:21.8544642Z [ERROR] symbol: class LogEntry +2026-03-25T12:12:21.8544881Z [ERROR] location: class com.***3.server.app.search.OpenSearchLogIndex +2026-03-25T12:12:21.8545494Z [ERROR] /workspace/***/***3-server/***3-server-app/src/main/java/com/***3/server/app/search/OpenSearchLogIndex.java:[102,18] cannot find symbol +2026-03-25T12:12:21.8545978Z [ERROR] symbol: class LogEntry +2026-03-25T12:12:21.8546990Z [ERROR] location: class com.***3.server.app.search.OpenSearchLogIndex +2026-03-25T12:12:21.8552530Z [ERROR] -> [Help 1] +2026-03-25T12:12:21.8553088Z [ERROR] +2026-03-25T12:12:21.8553277Z [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch. +2026-03-25T12:12:21.8553504Z [ERROR] Re-run Maven using the -X switch to enable full debug logging. +2026-03-25T12:12:21.8553814Z [ERROR] +2026-03-25T12:12:21.8553972Z [ERROR] For more information about the errors and possible solutions, please read the following articles: +2026-03-25T12:12:21.8554191Z [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException +2026-03-25T12:12:21.8554524Z [ERROR] +2026-03-25T12:12:21.8554766Z [ERROR] After correcting the problems, you can resume the build with the command +2026-03-25T12:12:21.8554950Z [ERROR] mvn -rf :***3-server-app +2026-03-25T12:12:21.8980811Z ❌ Failure - Main Build and Test +2026-03-25T12:12:21.9062723Z exitcode '1': failure +2026-03-25T12:12:21.9180182Z expression '${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}' rewritten to 'format('{0}-maven-{1}', runner.os, hashFiles('**/pom.xml'))' +2026-03-25T12:12:21.9180620Z evaluating expression 'format('{0}-maven-{1}', runner.os, hashFiles('**/pom.xml'))' +2026-03-25T12:12:21.9181123Z Writing entry to tarball workflow/hashfiles/index.js len:168437 +2026-03-25T12:12:21.9182183Z Extracting content to '/var/run/act' +2026-03-25T12:12:21.9205901Z 🐳 docker exec cmd=[node /var/run/act/workflow/hashfiles/index.js] user= workdir= +2026-03-25T12:12:21.9206374Z Exec command '[node /var/run/act/workflow/hashfiles/index.js]' +2026-03-25T12:12:21.9206699Z Working directory '/workspace/***/***3-server' +2026-03-25T12:12:22.7260152Z expression 'format('{0}-maven-{1}', runner.os, hashFiles('**/pom.xml'))' evaluated to '%!t(string=Linux-maven-9dd3df74bd8aba32251bb49c59e820a2aa73582b0f09ca6d6e930542cfb05391)' +2026-03-25T12:12:22.7260875Z expression '${{ runner.os }}-maven-' rewritten to 'format('{0}-maven-', runner.os)' +2026-03-25T12:12:22.7261028Z evaluating expression 'format('{0}-maven-', runner.os)' +2026-03-25T12:12:22.7261357Z expression 'format('{0}-maven-', runner.os)' evaluated to '%!t(string=Linux-maven-)' +2026-03-25T12:12:22.7327149Z evaluating expression 'success()' +2026-03-25T12:12:22.7327979Z expression 'success()' evaluated to 'false' +2026-03-25T12:12:22.7328293Z Skipping step 'Cache Maven dependencies' due to 'success()' +2026-03-25T12:12:22.7512510Z evaluating expression 'always()' +2026-03-25T12:12:22.7513128Z expression 'always()' evaluated to 'true' +2026-03-25T12:12:22.7513287Z ⭐ Run Post actions/checkout@v4 +2026-03-25T12:12:22.7513573Z Writing entry to tarball workflow/outputcmd.txt len:0 +2026-03-25T12:12:22.7513775Z Writing entry to tarball workflow/statecmd.txt len:0 +2026-03-25T12:12:22.7513932Z Writing entry to tarball workflow/pathcmd.txt len:0 +2026-03-25T12:12:22.7514093Z Writing entry to tarball workflow/envs.txt len:0 +2026-03-25T12:12:22.7514225Z Writing entry to tarball workflow/SUMMARY.md len:0 +2026-03-25T12:12:22.7514367Z Extracting content to '/var/run/act' +2026-03-25T12:12:22.7536979Z run post step for 'actions/checkout@v4' +2026-03-25T12:12:22.7537953Z executing remote job container: [node /var/run/act/actions/c3fe249fe73091a17d6638fe1341e7bd0bcc3466ce52323c0688e83e2463a4ab/dist/index.js] +2026-03-25T12:12:22.7538205Z 🐳 docker exec cmd=[node /var/run/act/actions/c3fe249fe73091a17d6638fe1341e7bd0bcc3466ce52323c0688e83e2463a4ab/dist/index.js] user= workdir= +2026-03-25T12:12:22.7538387Z Exec command '[node /var/run/act/actions/c3fe249fe73091a17d6638fe1341e7bd0bcc3466ce52323c0688e83e2463a4ab/dist/index.js]' +2026-03-25T12:12:22.7538938Z Working directory '/workspace/***/***3-server' +2026-03-25T12:12:22.9226461Z [command]/usr/bin/git version +2026-03-25T12:12:22.9294115Z git version 2.43.0 +2026-03-25T12:12:22.9313788Z *** +2026-03-25T12:12:22.9331884Z Temporarily overriding HOME='/tmp/46bc4398-3611-45b9-b066-1bc035cefb59' before making global git config changes +2026-03-25T12:12:22.9332991Z Adding repository directory to the temporary git global config as a safe directory +2026-03-25T12:12:22.9358373Z [command]/usr/bin/git config --global --add safe.directory /workspace/***/***3-server +2026-03-25T12:12:22.9398746Z [command]/usr/bin/git config --local --name-only --get-regexp core\.sshCommand +2026-03-25T12:12:22.9439820Z [command]/usr/bin/git submodule foreach --recursive sh -c "git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :" +2026-03-25T12:12:22.9671213Z [command]/usr/bin/git config --local --name-only --get-regexp http\.https\:\/\/gitea\.siegeln\.net\/\.extraheader +2026-03-25T12:12:22.9698091Z http.https://gitea.siegeln.net/.extraheader +2026-03-25T12:12:22.9712560Z [command]/usr/bin/git config --local --unset-all http.https://gitea.siegeln.net/.extraheader +2026-03-25T12:12:22.9753243Z [command]/usr/bin/git submodule foreach --recursive sh -c "git config --local --name-only --get-regexp 'http\.https\:\/\/gitea\.siegeln\.net\/\.extraheader' && git config --local --unset-all 'http.https://gitea.siegeln.net/.extraheader' || :" +2026-03-25T12:12:22.9930624Z [command]/usr/bin/git config --local --name-only --get-regexp ^includeIf\.gitdir: +2026-03-25T12:12:22.9964029Z [command]/usr/bin/git submodule foreach --recursive git config --local --show-origin --name-only --get-regexp remote.origin.url +2026-03-25T12:12:23.0207464Z ✅ Success - Post actions/checkout@v4 +2026-03-25T12:12:23.0290989Z Cleaning up container for job build +2026-03-25T12:12:25.2118679Z Removed container: 81d7988ac62ef23d7fea4defd927f69654288f6f2a5992c3480ab61a65fc57f2 +2026-03-25T12:12:25.2138946Z 🐳 docker volume rm GITEA-ACTIONS-TASK-1109_WORKFLOW-CI_JOB-build +2026-03-25T12:12:25.4820522Z 🐳 docker volume rm GITEA-ACTIONS-TASK-1109_WORKFLOW-CI_JOB-build-env +2026-03-25T12:12:25.6034893Z 🏁 Job failed +2026-03-25T12:12:25.6094056Z Job 'build' failed diff --git a/docs/superpowers/plans/2026-03-28-navigation-redesign.md b/docs/superpowers/plans/2026-03-28-navigation-redesign.md new file mode 100644 index 00000000..03d99988 --- /dev/null +++ b/docs/superpowers/plans/2026-03-28-navigation-redesign.md @@ -0,0 +1,1301 @@ +# Navigation Redesign Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Redesign the navigation from page-based routing to a scope-based model with three content tabs (Exchanges, Dashboard, Runtime) and a scoping sidebar. + +**Architecture:** The sidebar becomes a scope filter (app -> route), not a navigator. Three content-level tabs (using SegmentedTabs from design system) switch the view. The URL structure changes from `/apps/:appId` to `/:tab/:appId`. The Exchanges tab transitions between full-width table (no route scope) and 3-column layout (route-scoped: exchange list | exchange header + diagram + details). + +**Tech Stack:** React 18, React Router v7, TypeScript, @cameleer/design-system v0.1.18, CSS Modules, TanStack Query + +**Spec:** `docs/superpowers/specs/2026-03-28-navigation-redesign-design.md` + +--- + +## File Structure + +**New files (create):** + +| File | Responsibility | +|------|---------------| +| `ui/src/hooks/useScope.ts` | Parse tab/appId/routeId/exchangeId from URL, provide navigation helpers | +| `ui/src/components/ScopeTrail.tsx` | Clickable scope trail (replaces breadcrumbs): All > app > route | +| `ui/src/components/ScopeTrail.module.css` | Scope trail styling | +| `ui/src/components/ContentTabs.tsx` | Tab bar (Exchanges \| Dashboard \| Runtime) using SegmentedTabs | +| `ui/src/components/ContentTabs.module.css` | Tab bar positioning/spacing | +| `ui/src/pages/Exchanges/ExchangesPage.tsx` | Orchestrates full-width table vs 3-column layout | +| `ui/src/pages/Exchanges/ExchangesPage.module.css` | 3-column grid, exchange list, right panel | +| `ui/src/pages/Exchanges/ExchangeList.tsx` | Compact exchange list for left column of 3-column view | +| `ui/src/pages/Exchanges/ExchangeHeader.tsx` | Exchange summary + correlation chain for right panel top | +| `ui/src/pages/RuntimeTab/RuntimePage.tsx` | Thin wrapper: renders AgentHealth or AgentInstance | +| `ui/src/pages/DashboardTab/DashboardPage.tsx` | Thin wrapper: renders RoutesMetrics or RouteDetail | + +**Modified files:** + +| File | Changes | +|------|---------| +| `ui/src/router.tsx` | New URL structure with 3 tab paths + scope params | +| `ui/src/components/LayoutShell.tsx` | Add ContentTabs + ScopeTrail, intercept sidebar navigation, remove agents from sidebar data | + +**Unchanged files (reused as-is):** + +| File | Used by | +|------|---------| +| `ui/src/pages/Dashboard/Dashboard.tsx` | ExchangesPage (full-width mode) | +| `ui/src/pages/AgentHealth/AgentHealth.tsx` | RuntimePage | +| `ui/src/pages/AgentInstance/AgentInstance.tsx` | RuntimePage | +| `ui/src/pages/Routes/RoutesMetrics.tsx` | DashboardPage | +| `ui/src/pages/Routes/RouteDetail.tsx` | DashboardPage | +| `ui/src/components/ExecutionDiagram/ExecutionDiagram.tsx` | ExchangesPage (3-column mode) | +| `ui/src/components/ProcessDiagram/ProcessDiagram.tsx` | ExchangesPage (topology-only when no exchange selected) | +| `ui/src/pages/Admin/AdminLayout.tsx` | Unchanged | + +--- + +## Design System Notes + +**Sidebar navigation interception:** The current `Sidebar` component has hardcoded `` paths (`/apps/:appId`, `/agents/:appId/:instanceId`). Since `SidebarProps` has no `onNavigate` callback, we intercept clicks via event delegation on a wrapper `
`, preventing default Link navigation and re-routing to the current tab's URL. This is a pragmatic workaround. A proper `onNavigate` prop should be added to the design system in a future update. + +**Agents removed from sidebar:** Pass `agents: []` in `SidebarApp` data. The Sidebar component renders nothing for empty agent arrays. + +**SegmentedTabs:** Available from `@cameleer/design-system`. Interface: `SegmentedTabs({ tabs: TabItem[], active: string, onChange: (value: string) => void })` where `TabItem = { label: ReactNode; count?: number; value: string }`. + +--- + +## Task 1: Create useScope hook + +**Files:** +- Create: `ui/src/hooks/useScope.ts` + +- [ ] **Step 1: Create the hook** + +```typescript +// ui/src/hooks/useScope.ts +import { useParams, useNavigate, useLocation } from 'react-router'; +import { useCallback } from 'react'; + +export type TabKey = 'exchanges' | 'dashboard' | 'runtime'; + +const VALID_TABS = new Set(['exchanges', 'dashboard', 'runtime']); + +export interface Scope { + tab: TabKey; + appId?: string; + routeId?: string; + exchangeId?: string; +} + +export function useScope() { + const params = useParams<{ tab?: string; appId?: string; routeId?: string; exchangeId?: string }>(); + const navigate = useNavigate(); + const location = useLocation(); + + // Derive tab from first URL segment — fallback to 'exchanges' + const rawTab = location.pathname.split('/').filter(Boolean)[0] ?? 'exchanges'; + const tab: TabKey = VALID_TABS.has(rawTab as TabKey) ? (rawTab as TabKey) : 'exchanges'; + + const scope: Scope = { + tab, + appId: params.appId, + routeId: params.routeId, + exchangeId: params.exchangeId, + }; + + const setTab = useCallback((newTab: TabKey) => { + // Preserve scope when switching tabs (except exchangeId which is tab-specific) + const parts = ['', newTab]; + if (scope.appId) parts.push(scope.appId); + if (scope.routeId) parts.push(scope.routeId); + navigate(parts.join('/')); + }, [navigate, scope.appId, scope.routeId]); + + const setApp = useCallback((appId: string | undefined) => { + if (!appId) { + navigate(`/${tab}`); + } else { + navigate(`/${tab}/${appId}`); + } + }, [navigate, tab]); + + const setRoute = useCallback((appId: string, routeId: string | undefined) => { + if (!routeId) { + navigate(`/${tab}/${appId}`); + } else { + navigate(`/${tab}/${appId}/${routeId}`); + } + }, [navigate, tab]); + + const setExchange = useCallback((appId: string, routeId: string, exchangeId: string | undefined) => { + if (!exchangeId) { + navigate(`/${tab}/${appId}/${routeId}`); + } else { + navigate(`/${tab}/${appId}/${routeId}/${exchangeId}`); + } + }, [navigate, tab]); + + const clearScope = useCallback(() => { + navigate(`/${tab}`); + }, [navigate, tab]); + + return { scope, setTab, setApp, setRoute, setExchange, clearScope }; +} +``` + +- [ ] **Step 2: Verify build** + +Run: `cd ui && npx tsc --noEmit` +Expected: No type errors + +- [ ] **Step 3: Commit** + +```bash +git add ui/src/hooks/useScope.ts +git commit -m "feat(ui): add useScope hook for tab+scope URL management" +``` + +--- + +## Task 2: Create ScopeTrail component + +**Files:** +- Create: `ui/src/components/ScopeTrail.tsx` +- Create: `ui/src/components/ScopeTrail.module.css` + +- [ ] **Step 1: Create the CSS module** + +```css +/* ui/src/components/ScopeTrail.module.css */ +.trail { + display: flex; + align-items: center; + gap: 0; + font-size: 0.8125rem; + color: var(--text-muted); + min-height: 1.5rem; +} + +.segment { + display: inline-flex; + align-items: center; +} + +.link { + color: var(--text-secondary); + text-decoration: none; + cursor: pointer; + background: none; + border: none; + padding: 0; + font: inherit; + font-size: 0.8125rem; +} + +.link:hover { + color: var(--amber); + text-decoration: underline; +} + +.separator { + margin: 0 0.375rem; + color: var(--text-muted); + user-select: none; +} + +.current { + color: var(--text-primary); + font-weight: 500; +} +``` + +- [ ] **Step 2: Create the component** + +```typescript +// ui/src/components/ScopeTrail.tsx +import type { Scope, TabKey } from '../hooks/useScope'; +import styles from './ScopeTrail.module.css'; + +interface ScopeTrailProps { + scope: Scope; + onNavigate: (path: string) => void; +} + +export function ScopeTrail({ scope, onNavigate }: ScopeTrailProps) { + const segments: { label: string; path: string }[] = [ + { label: 'All Applications', path: `/${scope.tab}` }, + ]; + + if (scope.appId) { + segments.push({ label: scope.appId, path: `/${scope.tab}/${scope.appId}` }); + } + + if (scope.routeId) { + segments.push({ label: scope.routeId, path: `/${scope.tab}/${scope.appId}/${scope.routeId}` }); + } + + return ( + + ); +} +``` + +- [ ] **Step 3: Verify build** + +Run: `cd ui && npx tsc --noEmit` + +- [ ] **Step 4: Commit** + +```bash +git add ui/src/components/ScopeTrail.tsx ui/src/components/ScopeTrail.module.css +git commit -m "feat(ui): add ScopeTrail component for scope-based breadcrumbs" +``` + +--- + +## Task 3: Create ContentTabs component + +**Files:** +- Create: `ui/src/components/ContentTabs.tsx` +- Create: `ui/src/components/ContentTabs.module.css` + +- [ ] **Step 1: Create the CSS module** + +```css +/* ui/src/components/ContentTabs.module.css */ +.wrapper { + padding: 0 1.5rem; + padding-top: 0.75rem; + padding-bottom: 0; +} +``` + +- [ ] **Step 2: Create the component** + +```typescript +// ui/src/components/ContentTabs.tsx +import { SegmentedTabs } from '@cameleer/design-system'; +import type { TabKey } from '../hooks/useScope'; +import styles from './ContentTabs.module.css'; + +const TABS = [ + { label: 'Exchanges', value: 'exchanges' as const }, + { label: 'Dashboard', value: 'dashboard' as const }, + { label: 'Runtime', value: 'runtime' as const }, +]; + +interface ContentTabsProps { + active: TabKey; + onChange: (tab: TabKey) => void; +} + +export function ContentTabs({ active, onChange }: ContentTabsProps) { + return ( +
+ onChange(v as TabKey)} + /> +
+ ); +} +``` + +- [ ] **Step 3: Verify build** + +Run: `cd ui && npx tsc --noEmit` + +- [ ] **Step 4: Commit** + +```bash +git add ui/src/components/ContentTabs.tsx ui/src/components/ContentTabs.module.css +git commit -m "feat(ui): add ContentTabs component (Exchanges | Dashboard | Runtime)" +``` + +--- + +## Task 4: Create ExchangeList component + +Compact exchange list for the left column of the 3-column Exchanges layout. + +**Files:** +- Create: `ui/src/pages/Exchanges/ExchangeList.tsx` +- Create: `ui/src/pages/Exchanges/ExchangeList.module.css` + +- [ ] **Step 1: Create the CSS module** + +```css +/* ui/src/pages/Exchanges/ExchangeList.module.css */ +.list { + display: flex; + flex-direction: column; + overflow-y: auto; + height: 100%; + border-right: 1px solid var(--border); + background: var(--surface); +} + +.item { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.625rem 0.75rem; + cursor: pointer; + border-bottom: 1px solid var(--border-light); + font-size: 0.8125rem; + transition: background 0.1s; +} + +.item:hover { + background: var(--surface-hover); +} + +.itemSelected { + background: var(--surface-active); + border-left: 3px solid var(--amber); + padding-left: calc(0.75rem - 3px); +} + +.dot { + width: 8px; + height: 8px; + border-radius: 50%; + flex-shrink: 0; +} + +.dotOk { background: var(--success); } +.dotErr { background: var(--error); } +.dotRun { background: var(--running); } + +.meta { + flex: 1; + min-width: 0; +} + +.exchangeId { + font-family: var(--font-mono); + font-size: 0.6875rem; + color: var(--text-muted); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.duration { + font-family: var(--font-mono); + font-size: 0.75rem; + color: var(--text-secondary); + flex-shrink: 0; +} + +.timestamp { + font-size: 0.6875rem; + color: var(--text-muted); + flex-shrink: 0; +} + +.empty { + padding: 2rem; + text-align: center; + color: var(--text-muted); + font-size: 0.8125rem; +} +``` + +- [ ] **Step 2: Create the component** + +```typescript +// ui/src/pages/Exchanges/ExchangeList.tsx +import type { ExecutionSummary } from '../../api/types'; +import styles from './ExchangeList.module.css'; + +interface ExchangeListProps { + exchanges: ExecutionSummary[]; + selectedId?: string; + onSelect: (exchange: ExecutionSummary) => void; +} + +function formatDuration(ms: number): string { + if (ms >= 60_000) return `${(ms / 1000).toFixed(0)}s`; + if (ms >= 1000) return `${(ms / 1000).toFixed(2)}s`; + return `${ms}ms`; +} + +function formatTime(iso: string): string { + const d = new Date(iso); + const h = String(d.getHours()).padStart(2, '0'); + const m = String(d.getMinutes()).padStart(2, '0'); + const s = String(d.getSeconds()).padStart(2, '0'); + return `${h}:${m}:${s}`; +} + +function dotClass(status: string): string { + switch (status) { + case 'COMPLETED': return styles.dotOk; + case 'FAILED': return styles.dotErr; + case 'RUNNING': return styles.dotRun; + default: return styles.dotOk; + } +} + +export function ExchangeList({ exchanges, selectedId, onSelect }: ExchangeListProps) { + if (exchanges.length === 0) { + return
No exchanges found
; + } + + return ( +
+ {exchanges.map((ex) => ( +
onSelect(ex)} + > + +
+
{ex.executionId.slice(0, 12)}
+
+ {formatDuration(ex.durationMs)} + {formatTime(ex.startTime)} +
+ ))} +
+ ); +} +``` + +- [ ] **Step 3: Verify build** + +Run: `cd ui && npx tsc --noEmit` + +- [ ] **Step 4: Commit** + +```bash +git add ui/src/pages/Exchanges/ExchangeList.tsx ui/src/pages/Exchanges/ExchangeList.module.css +git commit -m "feat(ui): add ExchangeList compact component for 3-column layout" +``` + +--- + +## Task 5: Create ExchangeHeader component + +Compact exchange summary + correlation chain for the top of the right panel. + +**Files:** +- Create: `ui/src/pages/Exchanges/ExchangeHeader.tsx` + +- [ ] **Step 1: Create the component** + +This component extracts the exchange header pattern from `ExchangeDetail.tsx` (lines ~1-50 of the header card section). + +```typescript +// ui/src/pages/Exchanges/ExchangeHeader.tsx +import { StatusDot, MonoText, Badge } from '@cameleer/design-system'; +import { useCorrelationChain } from '../../api/queries/correlation'; +import type { ExecutionDetail } from '../../components/ExecutionDiagram/types'; + +interface ExchangeHeaderProps { + detail: ExecutionDetail; + onExchangeClick?: (executionId: string) => void; +} + +function statusVariant(s: string): 'success' | 'error' | 'running' | 'warning' { + switch (s) { + case 'COMPLETED': return 'success'; + case 'FAILED': return 'error'; + case 'RUNNING': return 'running'; + default: return 'warning'; + } +} + +function formatDuration(ms: number): string { + if (ms >= 60_000) return `${(ms / 1000).toFixed(0)}s`; + if (ms >= 1000) return `${(ms / 1000).toFixed(2)}s`; + return `${ms}ms`; +} + +export function ExchangeHeader({ detail, onExchangeClick }: ExchangeHeaderProps) { + const { data: chain } = useCorrelationChain(detail.correlationId ?? null); + const correlatedExchanges = (chain ?? []).filter((e: any) => chain && chain.length > 1); + + return ( +
+
+ + {detail.exchangeId || detail.executionId} + + {detail.routeId} + + {formatDuration(detail.durationMs)} + +
+ + {/* Correlation chain */} + {correlatedExchanges.length > 1 && ( +
+ + Correlated: + + {correlatedExchanges.map((e: any) => ( + + ))} +
+ )} +
+ ); +} +``` + +**Note:** This uses inline styles intentionally since it's a compact, one-off header. If it grows, extract to a CSS module. + +- [ ] **Step 2: Check that `useCorrelationChain` exists** + +Run: `cd ui && grep -r "useCorrelationChain" src/api/queries/` + +Expected: Found in `correlation.ts`. If not found, check `executions.ts` for correlation query. + +- [ ] **Step 3: Verify build** + +Run: `cd ui && npx tsc --noEmit` + +- [ ] **Step 4: Commit** + +```bash +git add ui/src/pages/Exchanges/ExchangeHeader.tsx +git commit -m "feat(ui): add ExchangeHeader component with correlation chain" +``` + +--- + +## Task 6: Create ExchangesPage + +Orchestrates full-width table (no route scope) vs 3-column layout (route-scoped). + +**Files:** +- Create: `ui/src/pages/Exchanges/ExchangesPage.tsx` +- Create: `ui/src/pages/Exchanges/ExchangesPage.module.css` + +- [ ] **Step 1: Create the CSS module** + +```css +/* ui/src/pages/Exchanges/ExchangesPage.module.css */ +.threeColumn { + display: grid; + grid-template-columns: 280px 1fr; + height: 100%; + overflow: hidden; +} + +.rightPanel { + display: flex; + flex-direction: column; + overflow: hidden; + height: 100%; +} + +.emptyRight { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + color: var(--text-muted); + font-size: 0.875rem; +} +``` + +- [ ] **Step 2: Create the page component** + +```typescript +// ui/src/pages/Exchanges/ExchangesPage.tsx +import { useState, useMemo, useCallback } from 'react'; +import { useParams } from 'react-router'; +import { useGlobalFilters } from '@cameleer/design-system'; +import { useSearchExecutions } from '../../api/queries/executions'; +import { useDiagramByRoute } from '../../api/queries/diagrams'; +import { useRouteCatalog } from '../../api/queries/catalog'; +import type { ExecutionSummary } from '../../api/types'; +import { ExchangeList } from './ExchangeList'; +import { ExchangeHeader } from './ExchangeHeader'; +import { ExecutionDiagram } from '../../components/ExecutionDiagram/ExecutionDiagram'; +import { ProcessDiagram } from '../../components/ProcessDiagram'; +import { useExecutionDetail } from '../../api/queries/executions'; +import styles from './ExchangesPage.module.css'; + +// Lazy-import the full-width Dashboard for the no-route-scope view. +// This avoids duplicating the KPI strip + DataTable + detail panel logic. +import Dashboard from '../Dashboard/Dashboard'; + +export default function ExchangesPage() { + const { appId, routeId, exchangeId } = useParams<{ + appId?: string; routeId?: string; exchangeId?: string; + }>(); + + // If no route is scoped, render the existing full-width Dashboard table. + // Dashboard already reads appId/routeId from useParams(). + if (!routeId) { + return ; + } + + // Route is scoped: render 3-column layout + return ( + + ); +} + +// ─── 3-column view when route is scoped ───────────────────────────────────── + +interface RouteExchangeViewProps { + appId: string; + routeId: string; + initialExchangeId?: string; +} + +function RouteExchangeView({ appId, routeId, initialExchangeId }: RouteExchangeViewProps) { + const [selectedExchangeId, setSelectedExchangeId] = useState(initialExchangeId); + const { timeRange } = useGlobalFilters(); + const timeFrom = timeRange.start.toISOString(); + const timeTo = timeRange.end.toISOString(); + + // Fetch exchanges for this route + const { data: searchResult } = useSearchExecutions( + { timeFrom, timeTo, routeId, application: appId, sortField: 'startTime', sortDir: 'desc', offset: 0, limit: 50 }, + true, + ); + const exchanges: ExecutionSummary[] = searchResult?.data || []; + + // Fetch execution detail for selected exchange + const { data: detail } = useExecutionDetail(selectedExchangeId ?? null); + + // Fetch diagram for topology-only view (when no exchange selected) + const diagramQuery = useDiagramByRoute(appId, routeId); + + // Known route IDs for drill-down resolution + const { data: catalog } = useRouteCatalog(timeFrom, timeTo); + const knownRouteIds = useMemo(() => { + const ids = new Set(); + if (catalog) { + for (const app of catalog) { + for (const r of app.routes || []) { + ids.add(r.routeId); + } + } + } + return ids; + }, [catalog]); + + const handleExchangeSelect = useCallback((ex: ExecutionSummary) => { + setSelectedExchangeId(ex.executionId); + }, []); + + return ( +
+ {/* Left column: exchange list */} + + + {/* Right column: exchange header + diagram + detail */} +
+ {selectedExchangeId && detail ? ( + <> + + + + ) : ( + /* No exchange selected: show topology-only diagram */ + diagramQuery.data ? ( + + ) : ( +
+ Select an exchange to view execution details +
+ ) + )} +
+
+ ); +} +``` + +- [ ] **Step 3: Verify build** + +Run: `cd ui && npx tsc --noEmit` + +Fix any type errors. Common issues: +- `useDiagramByRoute` might need different params — check `ui/src/api/queries/diagrams.ts` +- `ExecutionSummary` import path — check `ui/src/api/types.ts` + +- [ ] **Step 4: Commit** + +```bash +git add ui/src/pages/Exchanges/ +git commit -m "feat(ui): add ExchangesPage with full-width and 3-column modes" +``` + +--- + +## Task 7: Create RuntimePage and DashboardPage wrappers + +Thin wrappers that render the existing page components based on URL params. + +**Files:** +- Create: `ui/src/pages/RuntimeTab/RuntimePage.tsx` +- Create: `ui/src/pages/DashboardTab/DashboardPage.tsx` + +- [ ] **Step 1: Create RuntimePage** + +```typescript +// ui/src/pages/RuntimeTab/RuntimePage.tsx +import { useParams } from 'react-router'; +import { lazy, Suspense } from 'react'; +import { Spinner } from '@cameleer/design-system'; + +const AgentHealth = lazy(() => import('../AgentHealth/AgentHealth')); +const AgentInstance = lazy(() => import('../AgentInstance/AgentInstance')); + +const Fallback =
; + +export default function RuntimePage() { + const { instanceId } = useParams<{ appId?: string; instanceId?: string }>(); + + // If instanceId is present, show agent instance detail; otherwise show agent health overview + if (instanceId) { + return ; + } + return ; +} +``` + +- [ ] **Step 2: Create DashboardPage** + +```typescript +// ui/src/pages/DashboardTab/DashboardPage.tsx +import { useParams } from 'react-router'; +import { lazy, Suspense } from 'react'; +import { Spinner } from '@cameleer/design-system'; + +const RoutesMetrics = lazy(() => import('../Routes/RoutesMetrics')); +const RouteDetail = lazy(() => import('../Routes/RouteDetail')); + +const Fallback =
; + +export default function DashboardPage() { + const { routeId } = useParams<{ appId?: string; routeId?: string }>(); + + // If routeId is present, show route detail; otherwise show routes metrics overview + if (routeId) { + return ; + } + return ; +} +``` + +- [ ] **Step 3: Verify build** + +Run: `cd ui && npx tsc --noEmit` + +- [ ] **Step 4: Commit** + +```bash +git add ui/src/pages/RuntimeTab/ ui/src/pages/DashboardTab/ +git commit -m "feat(ui): add RuntimePage and DashboardPage tab wrappers" +``` + +--- + +## Task 8: Update router with new URL structure + +Replace the old page-based routes with the new tab-based structure. + +**Files:** +- Modify: `ui/src/router.tsx` + +- [ ] **Step 1: Rewrite router.tsx** + +Replace the content of `ui/src/router.tsx` with: + +```typescript +// ui/src/router.tsx +import { createBrowserRouter, Navigate, useParams } from 'react-router'; +import { ProtectedRoute } from './auth/ProtectedRoute'; +import { LoginPage } from './auth/LoginPage'; +import { OidcCallback } from './auth/OidcCallback'; +import { LayoutShell } from './components/LayoutShell'; +import { lazy, Suspense } from 'react'; +import { Spinner } from '@cameleer/design-system'; + +const ExchangesPage = lazy(() => import('./pages/Exchanges/ExchangesPage')); +const DashboardPage = lazy(() => import('./pages/DashboardTab/DashboardPage')); +const RuntimePage = lazy(() => import('./pages/RuntimeTab/RuntimePage')); +const AdminLayout = lazy(() => import('./pages/Admin/AdminLayout')); +const RbacPage = lazy(() => import('./pages/Admin/RbacPage')); +const AuditLogPage = lazy(() => import('./pages/Admin/AuditLogPage')); +const OidcConfigPage = lazy(() => import('./pages/Admin/OidcConfigPage')); +const DatabaseAdminPage = lazy(() => import('./pages/Admin/DatabaseAdminPage')); +const OpenSearchAdminPage = lazy(() => import('./pages/Admin/OpenSearchAdminPage')); +const AppConfigPage = lazy(() => import('./pages/Admin/AppConfigPage')); +const SwaggerPage = lazy(() => import('./pages/Swagger/SwaggerPage')); + +function SuspenseWrapper({ children }: { children: React.ReactNode }) { + return ( +
}> + {children} + + ); +} + +export const router = createBrowserRouter([ + { path: '/login', element: }, + { path: '/oidc/callback', element: }, + { + element: , + children: [ + { + element: , + children: [ + // Default redirect + { index: true, element: }, + + // Exchanges tab + { path: 'exchanges', element: }, + { path: 'exchanges/:appId', element: }, + { path: 'exchanges/:appId/:routeId', element: }, + { path: 'exchanges/:appId/:routeId/:exchangeId', element: }, + + // Dashboard tab + { path: 'dashboard', element: }, + { path: 'dashboard/:appId', element: }, + { path: 'dashboard/:appId/:routeId', element: }, + + // Runtime tab + { path: 'runtime', element: }, + { path: 'runtime/:appId', element: }, + { path: 'runtime/:appId/:instanceId', element: }, + + // Legacy redirects (sidebar uses /apps/... and /agents/... paths) + { path: 'apps', element: }, + { path: 'apps/:appId', element: }, + { path: 'apps/:appId/:routeId', element: }, + { path: 'agents', element: }, + { path: 'agents/:appId', element: }, + { path: 'agents/:appId/:instanceId', element: }, + + // Old exchange detail redirect + { path: 'exchanges-old/:id', element: }, + + // Admin (unchanged) + { + path: 'admin', + element: , + children: [ + { index: true, element: }, + { path: 'rbac', element: }, + { path: 'audit', element: }, + { path: 'oidc', element: }, + { path: 'appconfig', element: }, + { path: 'database', element: }, + { path: 'opensearch', element: }, + ], + }, + { path: 'api-docs', element: }, + ], + }, + ], + }, +]); + +// Legacy redirect components — translate old sidebar paths to current tab +// (useParams is already imported at the top of this file) + +function LegacyAppRedirect() { + const { appId, routeId } = useParams<{ appId: string; routeId?: string }>(); + const path = routeId ? `/exchanges/${appId}/${routeId}` : `/exchanges/${appId}`; + return ; +} + +function LegacyAgentRedirect() { + const { appId, instanceId } = useParams<{ appId: string; instanceId?: string }>(); + const path = instanceId ? `/runtime/${appId}/${instanceId}` : `/runtime/${appId}`; + return ; +} +``` + +The `useParams` import from `react-router` is already at the top alongside the other router imports. The legacy redirects ensure the Sidebar's hardcoded `/apps/...` and `/agents/...` Links still work (they redirect to the Exchanges tab by default). + +- [ ] **Step 2: Verify build** + +Run: `cd ui && npx tsc --noEmit` + +- [ ] **Step 3: Commit** + +```bash +git add ui/src/router.tsx +git commit -m "feat(ui): restructure router for tab-based navigation with legacy redirects" +``` + +--- + +## Task 9: Update LayoutShell + +Wire ContentTabs, ScopeTrail, sidebar interception, and remove agents from sidebar data. + +**Files:** +- Modify: `ui/src/components/LayoutShell.tsx` + +- [ ] **Step 1: Update imports** + +Add these imports to the top of `LayoutShell.tsx`: + +```typescript +import { ContentTabs } from './ContentTabs'; +import { ScopeTrail } from './ScopeTrail'; +import { useScope } from '../hooks/useScope'; +``` + +- [ ] **Step 2: Remove agents from sidebar data** + +In the `sidebarApps` useMemo (around line 106), change the agents mapping to always return an empty array: + +Replace: +```typescript + agents: (app.agents || []).map((a: any) => ({ + id: a.id, + name: a.name, + status: a.status as 'live' | 'stale' | 'dead', + tps: a.tps, + })), +``` + +With: +```typescript + agents: [], +``` + +- [ ] **Step 3: Add scope + sidebar interception to LayoutContent** + +At the top of the `LayoutContent` function (after existing hooks around line 92), add: + +```typescript + const { scope, setTab, clearScope } = useScope(); +``` + +Add the sidebar click interceptor function (before the return statement): + +```typescript + // Intercept Sidebar's internal navigation to re-route through current tab + const handleSidebarClick = useCallback((e: React.MouseEvent) => { + const anchor = (e.target as HTMLElement).closest('a[href]'); + if (!anchor) return; + const href = anchor.getAttribute('href') || ''; + + // Intercept /apps/:appId and /apps/:appId/:routeId links + const appMatch = href.match(/^\/apps\/([^/]+)(?:\/(.+))?$/); + if (appMatch) { + e.preventDefault(); + const [, sAppId, sRouteId] = appMatch; + navigate(sRouteId ? `/${scope.tab}/${sAppId}/${sRouteId}` : `/${scope.tab}/${sAppId}`); + return; + } + + // Intercept /agents/* links — redirect to runtime tab + const agentMatch = href.match(/^\/agents\/([^/]+)(?:\/(.+))?$/); + if (agentMatch) { + e.preventDefault(); + const [, sAppId, sInstanceId] = agentMatch; + navigate(sInstanceId ? `/runtime/${sAppId}/${sInstanceId}` : `/runtime/${sAppId}`); + } + }, [navigate, scope.tab]); +``` + +- [ ] **Step 4: Replace breadcrumbs with ScopeTrail** + +Replace the existing `breadcrumb` useMemo block (lines 168-188) with: + +```typescript + // Breadcrumb is now the ScopeTrail — built from scope, not URL path + // Keep the old breadcrumb generation for admin pages only + const isAdminPage = location.pathname.startsWith('/admin'); + const breadcrumb = useMemo(() => { + if (!isAdminPage) return []; // ScopeTrail handles non-admin breadcrumbs + const LABELS: Record = { + admin: 'Admin', + rbac: 'Users & Roles', + audit: 'Audit Log', + oidc: 'OIDC', + database: 'Database', + opensearch: 'OpenSearch', + appconfig: 'App Config', + }; + const parts = location.pathname.split('/').filter(Boolean); + return parts.map((part, i) => ({ + label: LABELS[part] ?? part, + ...(i < parts.length - 1 ? { href: '/' + parts.slice(0, i + 1).join('/') } : {}), + })); + }, [location.pathname, isAdminPage]); +``` + +- [ ] **Step 5: Update CommandPalette submit handler** + +Replace the `handlePaletteSubmit` callback (around line 202) so it uses the Exchanges tab path: + +```typescript + const handlePaletteSubmit = useCallback((query: string) => { + // Full-text search: navigate to Exchanges tab with text param + const baseParts = [`/exchanges`]; + if (scope.appId) baseParts.push(scope.appId); + if (scope.routeId) baseParts.push(scope.routeId); + navigate(`${baseParts.join('/')}?text=${encodeURIComponent(query)}`); + }, [navigate, scope.appId, scope.routeId]); +``` + +- [ ] **Step 6: Update the search result paths in buildSearchData** + +In `buildSearchData` function, update the `path` values for apps and routes: + +Replace: +```typescript + path: `/apps/${app.appId}`, +``` +With: +```typescript + path: `/exchanges/${app.appId}`, +``` + +Replace: +```typescript + path: `/apps/${app.appId}/${route.routeId}`, +``` +With: +```typescript + path: `/exchanges/${app.appId}/${route.routeId}`, +``` + +Replace: +```typescript + path: `/agents/${agent.application}/${agent.id}`, +``` +With: +```typescript + path: `/runtime/${agent.application}/${agent.id}`, +``` + +- [ ] **Step 7: Update exchange search result paths** + +In the `searchData` useMemo (around line 132), update the exchange path: + +Replace: +```typescript + path: `/exchanges/${e.executionId}`, +``` + +With a path that includes the app and route for proper 3-column view: + +```typescript + path: `/exchanges/${e.applicationName ?? ''}/${e.routeId}/${e.executionId}`, +``` + +Do the same for `attributeItems` path. + +- [ ] **Step 8: Update the JSX return** + +Replace the return block of `LayoutContent` with: + +```typescript + return ( + + + + } + > + + setPaletteOpen(false)} + onOpen={() => setPaletteOpen(true)} + onSelect={handlePaletteSelect} + onSubmit={handlePaletteSubmit} + onQueryChange={setPaletteQuery} + data={searchData} + /> + + {/* Content tabs + scope trail — only for main content, not admin */} + {!isAdminPage && ( + <> + +
+ navigate(path)} /> +
+ + )} + +
+ +
+
+ ); +``` + +- [ ] **Step 9: Verify build** + +Run: `cd ui && npx tsc --noEmit` + +Fix any type errors. Then run the dev server: + +Run: `cd ui && npm run dev` + +Visually verify: +- Tab bar appears below TopBar with Exchanges | Dashboard | Runtime +- Scope trail shows "All Applications" by default +- Clicking an app in sidebar scopes to that app and stays on current tab +- Clicking a route transitions to 3-column layout (Exchanges tab) +- Clicking Dashboard or Runtime tabs shows the correct content +- Admin pages still work without tabs/scope trail + +- [ ] **Step 10: Commit** + +```bash +git add ui/src/components/LayoutShell.tsx +git commit -m "feat(ui): integrate ContentTabs, ScopeTrail, and sidebar scope interception" +``` + +--- + +## Task 10: Final cleanup and verification + +**Files:** +- Modify: `ui/src/pages/Dashboard/Dashboard.tsx` (update inspect link path) + +- [ ] **Step 1: Update Dashboard inspect link** + +In `Dashboard.tsx`, the inspect button navigates to `/exchanges/:id` (the old exchange detail page). Update it to stay in the current scope. Find the inspect column render (around line 347): + +Replace: +```typescript + navigate(`/exchanges/${row.executionId}`) +``` + +With: +```typescript + navigate(`/exchanges/${row.applicationName}/${row.routeId}/${row.executionId}`) +``` + +This navigates to the 3-column view with the exchange pre-selected. + +- [ ] **Step 2: Update Dashboard "Open full details" link** + +In the detail panel section (around line 465): + +Replace: +```typescript + onClick={() => navigate(`/exchanges/${detail.executionId}`)} +``` + +With: +```typescript + onClick={() => navigate(`/exchanges/${detail.applicationName}/${detail.routeId}/${detail.executionId}`)} +``` + +- [ ] **Step 3: Verify all navigation flows** + +Run the dev server and verify: + +```bash +cd ui && npm run dev +``` + +Verification checklist: +1. `/exchanges` — Shows full-width exchange table with KPI strip +2. Click app in sidebar — URL updates to `/exchanges/:appId`, table filters +3. Click route in sidebar — URL updates to `/exchanges/:appId/:routeId`, 3-column layout appears +4. Click exchange in left list — Right panel shows exchange header + diagram + details +5. Click "Dashboard" tab — URL changes to `/dashboard/:appId/:routeId` (scope preserved) +6. Dashboard tab shows RoutesMetrics (no route) or RouteDetail (with route) +7. Click "Runtime" tab — URL changes to `/runtime`, shows AgentHealth +8. Click agent in Runtime content — Shows AgentInstance detail +9. Scope trail segments are clickable and navigate correctly +10. Cmd+K search works, results navigate to correct new URLs +11. Admin pages (gear icon or /admin) still work with breadcrumbs, no tabs +12. Sidebar shows apps with routes only, no agents section + +- [ ] **Step 4: Verify production build** + +Run: `cd ui && npm run build` +Expected: Clean build with no errors + +- [ ] **Step 5: Commit** + +```bash +git add -A +git commit -m "feat(ui): complete navigation redesign - tab-based layout with scope filtering + +Redesigns navigation from page-based routing to scope-based model: +- Three content tabs: Exchanges, Dashboard, Runtime +- Sidebar simplified to app/route hierarchy (scope filter) +- Scope trail replaces breadcrumbs +- Exchanges tab: full-width table or 3-column layout with diagram +- Legacy URL redirects for backward compatibility" +``` + +--- + +## Known Limitations and Future Work + +1. **Sidebar design system update needed:** The click interception via event delegation is a workaround. A proper `onNavigate` prop should be added to the design system's `Sidebar` component. + +2. **Dashboard tab content:** The analytics/dashboard content is deferred per spec. Currently wraps existing RoutesMetrics and RouteDetail pages. + +3. **ExchangeDetail page:** The old full-page ExchangeDetail at `/exchanges/:id` is replaced by the inline 3-column view. The ExchangeDetail component file is not deleted — it may be useful for reference. Clean up when confident the new view covers all use cases. + +4. **Exchange header:** Uses inline styles for brevity. Extract to CSS module if it grows. + +5. **KPI hero per tab:** Currently only the Exchanges tab has a KPI strip (from Dashboard). The Dashboard and Runtime tabs will get their own KPI strips in future iterations. + +6. **Application log and replay:** These features from ExchangeDetail are accessible through the ExecutionDiagram's detail panel tabs but not directly in the exchange header. A future iteration could add log/replay buttons. diff --git a/openapi.json b/openapi.json new file mode 100644 index 00000000..2f1f050e --- /dev/null +++ b/openapi.json @@ -0,0 +1 @@ +{"openapi":"3.1.0","info":{"title":"Cameleer3 Server API","version":"1.0"},"servers":[{"url":"/api/v1","description":"Relative"}],"security":[{"bearer":[]}],"tags":[{"name":"Agent Events","description":"Agent lifecycle event log"},{"name":"Database Admin","description":"Database monitoring and management (ADMIN only)"},{"name":"Threshold Admin","description":"Monitoring threshold configuration (ADMIN only)"},{"name":"Agent Commands","description":"Command push endpoints for agent communication"},{"name":"User Admin","description":"User management (ADMIN only)"},{"name":"Agent Management","description":"Agent registration and lifecycle endpoints"},{"name":"Authentication","description":"Login and token refresh endpoints"},{"name":"Role Admin","description":"Role management (ADMIN only)"},{"name":"RBAC Stats","description":"RBAC statistics (ADMIN only)"},{"name":"OIDC Config Admin","description":"OIDC provider configuration (ADMIN only)"},{"name":"Route Metrics","description":"Route performance metrics"},{"name":"Search","description":"Transaction search endpoints"},{"name":"Agent SSE","description":"Server-Sent Events endpoint for agent communication"},{"name":"Ingestion","description":"Data ingestion endpoints"},{"name":"Audit Log","description":"Audit log viewer (ADMIN only)"},{"name":"Application Logs","description":"Query application logs stored in OpenSearch"},{"name":"Group Admin","description":"Group management (ADMIN only)"},{"name":"Diagrams","description":"Diagram rendering endpoints"},{"name":"OpenSearch Admin","description":"OpenSearch monitoring and management (ADMIN only)"},{"name":"Application Config","description":"Per-application observability configuration"},{"name":"Detail","description":"Execution detail and processor snapshot endpoints"},{"name":"Route Catalog","description":"Route catalog and discovery"}],"paths":{"/config/{application}":{"get":{"tags":["Application Config"],"summary":"Get application config","description":"Returns the current configuration for an application. Returns defaults if none stored.","operationId":"getConfig","parameters":[{"name":"application","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Config returned","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApplicationConfig"}}}}}},"put":{"tags":["Application Config"],"summary":"Update application config","description":"Saves config and pushes CONFIG_UPDATE to all LIVE agents of this application","operationId":"updateConfig","parameters":[{"name":"application","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationConfig"}}},"required":true},"responses":{"200":{"description":"Config saved and pushed","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApplicationConfig"}}}}}}},"/admin/users/{userId}":{"get":{"tags":["User Admin"],"summary":"Get user by ID with RBAC detail","operationId":"getUser","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"User found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserDetail"}}}},"404":{"description":"User not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserDetail"}}}}}},"put":{"tags":["User Admin"],"summary":"Update user display name or email","operationId":"updateUser","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRequest"}}},"required":true},"responses":{"200":{"description":"User updated"},"404":{"description":"User not found"}}},"delete":{"tags":["User Admin"],"summary":"Delete user","operationId":"deleteUser","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"User deleted"}}}},"/admin/thresholds":{"get":{"tags":["Threshold Admin"],"summary":"Get current threshold configuration","operationId":"getThresholds","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ThresholdConfig"}}}}}},"put":{"tags":["Threshold Admin"],"summary":"Update threshold configuration","operationId":"updateThresholds","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThresholdConfigRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ThresholdConfig"}}}}}}},"/admin/roles/{id}":{"get":{"tags":["Role Admin"],"summary":"Get role by ID with effective principals","operationId":"getRole","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Role found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RoleDetail"}}}},"404":{"description":"Role not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RoleDetail"}}}}}},"put":{"tags":["Role Admin"],"summary":"Update a custom role","operationId":"updateRole","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRoleRequest"}}},"required":true},"responses":{"200":{"description":"Role updated"},"403":{"description":"Cannot modify system role"},"404":{"description":"Role not found"}}},"delete":{"tags":["Role Admin"],"summary":"Delete a custom role","operationId":"deleteRole","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Role deleted"},"403":{"description":"Cannot delete system role"},"404":{"description":"Role not found"}}}},"/admin/oidc":{"get":{"tags":["OIDC Config Admin"],"summary":"Get OIDC configuration","operationId":"getConfig_1","responses":{"200":{"description":"Current OIDC configuration (client_secret masked)","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OidcAdminConfigResponse"}}}}}},"put":{"tags":["OIDC Config Admin"],"summary":"Save OIDC configuration","operationId":"saveConfig","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcAdminConfigRequest"}}},"required":true},"responses":{"200":{"description":"Configuration saved","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OidcAdminConfigResponse"}}}},"400":{"description":"Invalid configuration","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["OIDC Config Admin"],"summary":"Delete OIDC configuration","operationId":"deleteConfig","responses":{"204":{"description":"Configuration deleted"}}}},"/admin/groups/{id}":{"get":{"tags":["Group Admin"],"summary":"Get group by ID with effective roles","operationId":"getGroup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Group found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/GroupDetail"}}}},"404":{"description":"Group not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/GroupDetail"}}}}}},"put":{"tags":["Group Admin"],"summary":"Update group name or parent","operationId":"updateGroup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGroupRequest"}}},"required":true},"responses":{"200":{"description":"Group updated"},"404":{"description":"Group not found"},"409":{"description":"Cycle detected in group hierarchy"}}},"delete":{"tags":["Group Admin"],"summary":"Delete group","operationId":"deleteGroup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Group deleted"},"404":{"description":"Group not found"}}}},"/search/executions":{"get":{"tags":["Search"],"summary":"Search executions with basic filters","operationId":"searchGet","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"timeFrom","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"timeTo","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"correlationId","in":"query","required":false,"schema":{"type":"string"}},{"name":"text","in":"query","required":false,"schema":{"type":"string"}},{"name":"routeId","in":"query","required":false,"schema":{"type":"string"}},{"name":"agentId","in":"query","required":false,"schema":{"type":"string"}},{"name":"processorType","in":"query","required":false,"schema":{"type":"string"}},{"name":"application","in":"query","required":false,"schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}},{"name":"sortField","in":"query","required":false,"schema":{"type":"string"}},{"name":"sortDir","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SearchResultExecutionSummary"}}}}}},"post":{"tags":["Search"],"summary":"Advanced search with all filters","operationId":"searchPost","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SearchResultExecutionSummary"}}}}}}},"/data/metrics":{"post":{"tags":["Ingestion"],"summary":"Ingest agent metrics","description":"Accepts an array of MetricsSnapshot objects","operationId":"ingestMetrics","requestBody":{"content":{"application/json":{"schema":{"type":"string"}}},"required":true},"responses":{"202":{"description":"Data accepted for processing"},"400":{"description":"Invalid payload"},"503":{"description":"Buffer full, retry later"}}}},"/data/logs":{"post":{"tags":["Ingestion"],"summary":"Ingest application log entries","description":"Accepts a batch of log entries from an agent. Entries are indexed in OpenSearch.","operationId":"ingestLogs","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogBatch"}}},"required":true},"responses":{"202":{"description":"Logs accepted for indexing"}}}},"/data/executions":{"post":{"tags":["Ingestion"],"summary":"Ingest route execution data","description":"Accepts a single RouteExecution or an array of RouteExecutions","operationId":"ingestExecutions","requestBody":{"content":{"application/json":{"schema":{"type":"string"}}},"required":true},"responses":{"202":{"description":"Data accepted for processing"}}}},"/data/diagrams":{"post":{"tags":["Ingestion"],"summary":"Ingest route diagram data","description":"Accepts a single RouteGraph or an array of RouteGraphs","operationId":"ingestDiagrams","requestBody":{"content":{"application/json":{"schema":{"type":"string"}}},"required":true},"responses":{"202":{"description":"Data accepted for processing"}}}},"/config/{application}/test-expression":{"post":{"tags":["Application Config"],"summary":"Test a tap expression against sample data via a live agent","operationId":"testExpression","parameters":[{"name":"application","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestExpressionRequest"}}},"required":true},"responses":{"200":{"description":"Expression evaluated successfully","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestExpressionResponse"}}}},"404":{"description":"No live agent available for this application","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestExpressionResponse"}}}},"504":{"description":"Agent did not respond in time","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestExpressionResponse"}}}}}}},"/auth/refresh":{"post":{"tags":["Authentication"],"summary":"Refresh access token","operationId":"refresh","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshRequest"}}},"required":true},"responses":{"200":{"description":"Token refreshed","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuthTokenResponse"}}}},"401":{"description":"Invalid refresh token","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/auth/oidc/callback":{"post":{"tags":["Authentication"],"summary":"Exchange OIDC authorization code for JWTs","operationId":"callback","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallbackRequest"}}},"required":true},"responses":{"200":{"description":"Authentication successful","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuthTokenResponse"}}}},"401":{"description":"OIDC authentication failed","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Account not provisioned","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"OIDC not configured or disabled","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuthTokenResponse"}}}}}}},"/auth/login":{"post":{"tags":["Authentication"],"summary":"Login with local credentials","operationId":"login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Login successful","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuthTokenResponse"}}}},"401":{"description":"Invalid credentials","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/agents/{id}/refresh":{"post":{"tags":["Agent Management"],"summary":"Refresh access token","description":"Issues a new access JWT from a valid refresh token","operationId":"refresh_1","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRefreshRequest"}}},"required":true},"responses":{"200":{"description":"New access token issued","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AgentRefreshResponse"}}}},"401":{"description":"Invalid or expired refresh token","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AgentRefreshResponse"}}}},"404":{"description":"Agent not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AgentRefreshResponse"}}}}}}},"/agents/{id}/heartbeat":{"post":{"tags":["Agent Management"],"summary":"Agent heartbeat ping","description":"Updates the agent's last heartbeat timestamp","operationId":"heartbeat","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Heartbeat accepted"},"404":{"description":"Agent not registered"}}}},"/agents/{id}/commands":{"post":{"tags":["Agent Commands"],"summary":"Send command to a specific agent","description":"Sends a command to the specified agent via SSE","operationId":"sendCommand","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommandRequest"}}},"required":true},"responses":{"202":{"description":"Command accepted","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CommandSingleResponse"}}}},"400":{"description":"Invalid command payload","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CommandSingleResponse"}}}},"404":{"description":"Agent not registered","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CommandSingleResponse"}}}}}}},"/agents/{id}/commands/{commandId}/ack":{"post":{"tags":["Agent Commands"],"summary":"Acknowledge command receipt","description":"Agent acknowledges that it has received and processed a command, with result status and message","operationId":"acknowledgeCommand","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"commandId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommandAckRequest"}}}},"responses":{"200":{"description":"Command acknowledged"},"404":{"description":"Command not found"}}}},"/agents/register":{"post":{"tags":["Agent Management"],"summary":"Register an agent","description":"Registers a new agent or re-registers an existing one. Requires bootstrap token in Authorization header.","operationId":"register","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRegistrationRequest"}}},"required":true},"responses":{"200":{"description":"Agent registered successfully","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AgentRegistrationResponse"}}}},"400":{"description":"Invalid registration payload","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid bootstrap token","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AgentRegistrationResponse"}}}}}}},"/agents/groups/{group}/commands":{"post":{"tags":["Agent Commands"],"summary":"Send command to all agents in a group","description":"Sends a command to all LIVE agents in the specified group","operationId":"sendGroupCommand","parameters":[{"name":"group","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommandRequest"}}},"required":true},"responses":{"202":{"description":"Commands accepted","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CommandBroadcastResponse"}}}},"400":{"description":"Invalid command payload","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CommandBroadcastResponse"}}}}}}},"/agents/commands":{"post":{"tags":["Agent Commands"],"summary":"Broadcast command to all live agents","description":"Sends a command to all agents currently in LIVE state","operationId":"broadcastCommand","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommandRequest"}}},"required":true},"responses":{"202":{"description":"Commands accepted","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CommandBroadcastResponse"}}}},"400":{"description":"Invalid command payload","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CommandBroadcastResponse"}}}}}}},"/admin/users":{"get":{"tags":["User Admin"],"summary":"List all users with RBAC detail","operationId":"listUsers","responses":{"200":{"description":"User list returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserDetail"}}}}}}},"post":{"tags":["User Admin"],"summary":"Create a local user","operationId":"createUser","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserRequest"}}},"required":true},"responses":{"200":{"description":"User created","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserDetail"}}}}}}},"/admin/users/{userId}/roles/{roleId}":{"post":{"tags":["User Admin"],"summary":"Assign a role to a user","operationId":"assignRoleToUser","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"roleId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Role assigned"},"404":{"description":"User or role not found"}}},"delete":{"tags":["User Admin"],"summary":"Remove a role from a user","operationId":"removeRoleFromUser","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"roleId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Role removed"}}}},"/admin/users/{userId}/password":{"post":{"tags":["User Admin"],"summary":"Reset user password","operationId":"resetPassword","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPasswordRequest"}}},"required":true},"responses":{"204":{"description":"Password reset"}}}},"/admin/users/{userId}/groups/{groupId}":{"post":{"tags":["User Admin"],"summary":"Add a user to a group","operationId":"addUserToGroup","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"groupId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"User added to group"}}},"delete":{"tags":["User Admin"],"summary":"Remove a user from a group","operationId":"removeUserFromGroup","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"groupId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"User removed from group"}}}},"/admin/roles":{"get":{"tags":["Role Admin"],"summary":"List all roles (system and custom)","operationId":"listRoles","responses":{"200":{"description":"Role list returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RoleDetail"}}}}}}},"post":{"tags":["Role Admin"],"summary":"Create a custom role","operationId":"createRole","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRoleRequest"}}},"required":true},"responses":{"200":{"description":"Role created","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string","format":"uuid"}}}}}}}},"/admin/oidc/test":{"post":{"tags":["OIDC Config Admin"],"summary":"Test OIDC provider connectivity","operationId":"testConnection","responses":{"200":{"description":"Provider reachable","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OidcTestResult"}}}},"400":{"description":"Provider unreachable or misconfigured","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/admin/groups":{"get":{"tags":["Group Admin"],"summary":"List all groups with hierarchy and effective roles","operationId":"listGroups","responses":{"200":{"description":"Group list returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GroupDetail"}}}}}}},"post":{"tags":["Group Admin"],"summary":"Create a new group","operationId":"createGroup","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGroupRequest"}}},"required":true},"responses":{"200":{"description":"Group created","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string","format":"uuid"}}}}}}}},"/admin/groups/{id}/roles/{roleId}":{"post":{"tags":["Group Admin"],"summary":"Assign a role to a group","operationId":"assignRoleToGroup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"roleId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Role assigned to group"},"404":{"description":"Group not found"}}},"delete":{"tags":["Group Admin"],"summary":"Remove a role from a group","operationId":"removeRoleFromGroup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"roleId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Role removed from group"},"404":{"description":"Group not found"}}}},"/admin/database/queries/{pid}/kill":{"post":{"tags":["Database Admin"],"summary":"Terminate a query by PID","operationId":"killQuery","parameters":[{"name":"pid","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OK"}}}},"/search/stats":{"get":{"tags":["Search"],"summary":"Aggregate execution stats (P99 latency, active count)","operationId":"stats","parameters":[{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"routeId","in":"query","required":false,"schema":{"type":"string"}},{"name":"application","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ExecutionStats"}}}}}}},"/search/stats/timeseries":{"get":{"tags":["Search"],"summary":"Bucketed time-series stats over a time window","operationId":"timeseries","parameters":[{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"buckets","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":24}},{"name":"routeId","in":"query","required":false,"schema":{"type":"string"}},{"name":"application","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/StatsTimeseries"}}}}}}},"/routes/metrics":{"get":{"tags":["Route Metrics"],"summary":"Get route metrics","description":"Returns aggregated performance metrics per route for the given time window","operationId":"getMetrics","parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}},{"name":"appId","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Metrics returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RouteMetrics"}}}}}}}},"/routes/metrics/processors":{"get":{"tags":["Route Metrics"],"summary":"Get processor metrics","description":"Returns aggregated performance metrics per processor for the given route and time window","operationId":"getProcessorMetrics","parameters":[{"name":"routeId","in":"query","required":true,"schema":{"type":"string"}},{"name":"appId","in":"query","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Metrics returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProcessorMetrics"}}}}}}}},"/routes/catalog":{"get":{"tags":["Route Catalog"],"summary":"Get route catalog","description":"Returns all applications with their routes, agents, and health status","operationId":"getCatalog","parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Catalog returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AppCatalogEntry"}}}}}}}},"/logs":{"get":{"tags":["Application Logs"],"summary":"Search application log entries","description":"Returns log entries for a given application, optionally filtered by agent, level, time range, and text query","operationId":"searchLogs","parameters":[{"name":"application","in":"query","required":true,"schema":{"type":"string"}},{"name":"agentId","in":"query","required":false,"schema":{"type":"string"}},{"name":"level","in":"query","required":false,"schema":{"type":"string"}},{"name":"query","in":"query","required":false,"schema":{"type":"string"}},{"name":"exchangeId","in":"query","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":200}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/LogEntryResponse"}}}}}}}},"/executions/{executionId}":{"get":{"tags":["Detail"],"summary":"Get execution detail with nested processor tree","operationId":"getDetail","parameters":[{"name":"executionId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Execution detail found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ExecutionDetail"}}}},"404":{"description":"Execution not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ExecutionDetail"}}}}}}},"/executions/{executionId}/processors/{index}/snapshot":{"get":{"tags":["Detail"],"summary":"Get exchange snapshot for a specific processor","operationId":"getProcessorSnapshot","parameters":[{"name":"executionId","in":"path","required":true,"schema":{"type":"string"}},{"name":"index","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Snapshot data","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}},"404":{"description":"Snapshot not found","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/diagrams":{"get":{"tags":["Diagrams"],"summary":"Find diagram by application and route ID","description":"Resolves application to agent IDs and finds the latest diagram for the route","operationId":"findByApplicationAndRoute","parameters":[{"name":"application","in":"query","required":true,"schema":{"type":"string"}},{"name":"routeId","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Diagram layout returned","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DiagramLayout"}}}},"404":{"description":"No diagram found for the given application and route","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DiagramLayout"}}}}}}},"/diagrams/{contentHash}/render":{"get":{"tags":["Diagrams"],"summary":"Render a route diagram","description":"Returns SVG (default) or JSON layout based on Accept header","operationId":"renderDiagram","parameters":[{"name":"contentHash","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Diagram rendered successfully","content":{"image/svg+xml":{"schema":{"type":"string"}},"application/json":{"schema":{"$ref":"#/components/schemas/DiagramLayout"}}}},"404":{"description":"Diagram not found","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/config":{"get":{"tags":["Application Config"],"summary":"List all application configs","description":"Returns stored configurations for all applications","operationId":"listConfigs","responses":{"200":{"description":"Configs returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ApplicationConfig"}}}}}}}},"/auth/oidc/config":{"get":{"tags":["Authentication"],"summary":"Get OIDC config for SPA login flow","operationId":"getConfig_2","responses":{"200":{"description":"OIDC configuration","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OidcPublicConfigResponse"}}}},"404":{"description":"OIDC not configured or disabled","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OidcPublicConfigResponse"}}}},"500":{"description":"Failed to retrieve OIDC provider metadata","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/agents":{"get":{"tags":["Agent Management"],"summary":"List all agents","description":"Returns all registered agents with runtime metrics, optionally filtered by status and/or application","operationId":"listAgents","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"application","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Agent list returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AgentInstanceResponse"}}}}},"400":{"description":"Invalid status filter","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/agents/{id}/events":{"get":{"tags":["Agent SSE"],"summary":"Open SSE event stream","description":"Opens a Server-Sent Events stream for the specified agent. Commands (config-update, deep-trace, replay) are pushed as events. Ping keepalive comments sent every 15 seconds.","operationId":"events","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Last-Event-ID","in":"header","description":"Last received event ID (no replay, acknowledged only)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"SSE stream opened","content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/SseEmitter"}}}},"404":{"description":"Agent not registered","content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/SseEmitter"}}}}}}},"/agents/{agentId}/metrics":{"get":{"tags":["agent-metrics-controller"],"operationId":"getMetrics_1","parameters":[{"name":"agentId","in":"path","required":true,"schema":{"type":"string"}},{"name":"names","in":"query","required":true,"schema":{"type":"string"}},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"buckets","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":60}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AgentMetricsResponse"}}}}}}},"/agents/events-log":{"get":{"tags":["Agent Events"],"summary":"Query agent events","description":"Returns agent lifecycle events, optionally filtered by app and/or agent ID","operationId":"getEvents","parameters":[{"name":"appId","in":"query","required":false,"schema":{"type":"string"}},{"name":"agentId","in":"query","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}}],"responses":{"200":{"description":"Events returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AgentEventResponse"}}}}}}}},"/admin/rbac/stats":{"get":{"tags":["RBAC Stats"],"summary":"Get RBAC statistics for the dashboard","operationId":"getStats","responses":{"200":{"description":"RBAC stats returned","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RbacStats"}}}}}}},"/admin/opensearch/status":{"get":{"tags":["OpenSearch Admin"],"summary":"Get OpenSearch cluster status and version","operationId":"getStatus","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OpenSearchStatusResponse"}}}}}}},"/admin/opensearch/pipeline":{"get":{"tags":["OpenSearch Admin"],"summary":"Get indexing pipeline statistics","operationId":"getPipeline","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PipelineStatsResponse"}}}}}}},"/admin/opensearch/performance":{"get":{"tags":["OpenSearch Admin"],"summary":"Get OpenSearch performance metrics","operationId":"getPerformance","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PerformanceResponse"}}}}}}},"/admin/opensearch/indices":{"get":{"tags":["OpenSearch Admin"],"summary":"Get OpenSearch indices with pagination","operationId":"getIndices","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":20}},{"name":"search","in":"query","required":false,"schema":{"type":"string","default":""}},{"name":"prefix","in":"query","required":false,"schema":{"type":"string","default":"executions"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/IndicesPageResponse"}}}}}}},"/admin/database/tables":{"get":{"tags":["Database Admin"],"summary":"Get table sizes and row counts","operationId":"getTables","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TableSizeResponse"}}}}}}}},"/admin/database/status":{"get":{"tags":["Database Admin"],"summary":"Get database connection status and version","operationId":"getStatus_1","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DatabaseStatusResponse"}}}}}}},"/admin/database/queries":{"get":{"tags":["Database Admin"],"summary":"Get active queries","operationId":"getQueries","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ActiveQueryResponse"}}}}}}}},"/admin/database/pool":{"get":{"tags":["Database Admin"],"summary":"Get HikariCP connection pool stats","operationId":"getPool","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ConnectionPoolResponse"}}}}}}},"/admin/database/metrics-pipeline":{"get":{"tags":["Database Admin"],"summary":"Get metrics ingestion pipeline diagnostics","operationId":"getMetricsPipeline","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"object"}}}}}}}},"/admin/audit":{"get":{"tags":["Audit Log"],"summary":"Search audit log entries with pagination","operationId":"getAuditLog","parameters":[{"name":"username","in":"query","required":false,"schema":{"type":"string"}},{"name":"category","in":"query","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","default":"timestamp"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","default":"desc"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":25}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuditLogPageResponse"}}}}}}},"/admin/opensearch/indices/{name}":{"delete":{"tags":["OpenSearch Admin"],"summary":"Delete an OpenSearch index","operationId":"deleteIndex","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"}}}}},"components":{"schemas":{"ApplicationConfig":{"type":"object","properties":{"application":{"type":"string"},"version":{"type":"integer","format":"int32"},"updatedAt":{"type":"string","format":"date-time"},"engineLevel":{"type":"string"},"payloadCaptureMode":{"type":"string"},"metricsEnabled":{"type":"boolean"},"samplingRate":{"type":"number","format":"double"},"tracedProcessors":{"type":"object","additionalProperties":{"type":"string"}},"logForwardingLevel":{"type":"string"},"taps":{"type":"array","items":{"$ref":"#/components/schemas/TapDefinition"}},"tapVersion":{"type":"integer","format":"int32"},"routeRecording":{"type":"object","additionalProperties":{"type":"boolean"}},"compressSuccess":{"type":"boolean"}}},"TapDefinition":{"type":"object","properties":{"tapId":{"type":"string"},"processorId":{"type":"string"},"target":{"type":"string"},"expression":{"type":"string"},"language":{"type":"string"},"attributeName":{"type":"string"},"attributeType":{"type":"string"},"enabled":{"type":"boolean"},"version":{"type":"integer","format":"int32"}}},"UpdateUserRequest":{"type":"object","properties":{"displayName":{"type":"string"},"email":{"type":"string"}}},"DatabaseThresholdsRequest":{"type":"object","description":"Database monitoring thresholds","properties":{"connectionPoolWarning":{"type":"integer","format":"int32","description":"Connection pool usage warning threshold (percentage)","maximum":100,"minimum":0},"connectionPoolCritical":{"type":"integer","format":"int32","description":"Connection pool usage critical threshold (percentage)","maximum":100,"minimum":0},"queryDurationWarning":{"type":"number","format":"double","description":"Query duration warning threshold (seconds)"},"queryDurationCritical":{"type":"number","format":"double","description":"Query duration critical threshold (seconds)"}}},"OpenSearchThresholdsRequest":{"type":"object","description":"OpenSearch monitoring thresholds","properties":{"clusterHealthWarning":{"type":"string","description":"Cluster health warning threshold (GREEN, YELLOW, RED)","minLength":1},"clusterHealthCritical":{"type":"string","description":"Cluster health critical threshold (GREEN, YELLOW, RED)","minLength":1},"queueDepthWarning":{"type":"integer","format":"int32","description":"Queue depth warning threshold","minimum":0},"queueDepthCritical":{"type":"integer","format":"int32","description":"Queue depth critical threshold","minimum":0},"jvmHeapWarning":{"type":"integer","format":"int32","description":"JVM heap usage warning threshold (percentage)","maximum":100,"minimum":0},"jvmHeapCritical":{"type":"integer","format":"int32","description":"JVM heap usage critical threshold (percentage)","maximum":100,"minimum":0},"failedDocsWarning":{"type":"integer","format":"int32","description":"Failed document count warning threshold","minimum":0},"failedDocsCritical":{"type":"integer","format":"int32","description":"Failed document count critical threshold","minimum":0}}},"ThresholdConfigRequest":{"type":"object","description":"Threshold configuration for admin monitoring","properties":{"database":{"$ref":"#/components/schemas/DatabaseThresholdsRequest"},"opensearch":{"$ref":"#/components/schemas/OpenSearchThresholdsRequest"}},"required":["database","opensearch"]},"DatabaseThresholds":{"type":"object","properties":{"connectionPoolWarning":{"type":"integer","format":"int32"},"connectionPoolCritical":{"type":"integer","format":"int32"},"queryDurationWarning":{"type":"number","format":"double"},"queryDurationCritical":{"type":"number","format":"double"}}},"OpenSearchThresholds":{"type":"object","properties":{"clusterHealthWarning":{"type":"string"},"clusterHealthCritical":{"type":"string"},"queueDepthWarning":{"type":"integer","format":"int32"},"queueDepthCritical":{"type":"integer","format":"int32"},"jvmHeapWarning":{"type":"integer","format":"int32"},"jvmHeapCritical":{"type":"integer","format":"int32"},"failedDocsWarning":{"type":"integer","format":"int32"},"failedDocsCritical":{"type":"integer","format":"int32"}}},"ThresholdConfig":{"type":"object","properties":{"database":{"$ref":"#/components/schemas/DatabaseThresholds"},"opensearch":{"$ref":"#/components/schemas/OpenSearchThresholds"}}},"UpdateRoleRequest":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"scope":{"type":"string"}}},"OidcAdminConfigRequest":{"type":"object","description":"OIDC configuration update request","properties":{"enabled":{"type":"boolean"},"issuerUri":{"type":"string"},"clientId":{"type":"string"},"clientSecret":{"type":"string"},"rolesClaim":{"type":"string"},"defaultRoles":{"type":"array","items":{"type":"string"}},"autoSignup":{"type":"boolean"},"displayNameClaim":{"type":"string"}}},"ErrorResponse":{"type":"object","description":"Error response","properties":{"message":{"type":"string"}},"required":["message"]},"OidcAdminConfigResponse":{"type":"object","description":"OIDC configuration for admin management","properties":{"configured":{"type":"boolean"},"enabled":{"type":"boolean"},"issuerUri":{"type":"string"},"clientId":{"type":"string"},"clientSecretSet":{"type":"boolean"},"rolesClaim":{"type":"string"},"defaultRoles":{"type":"array","items":{"type":"string"}},"autoSignup":{"type":"boolean"},"displayNameClaim":{"type":"string"}}},"UpdateGroupRequest":{"type":"object","properties":{"name":{"type":"string"},"parentGroupId":{"type":"string","format":"uuid"}}},"SearchRequest":{"type":"object","properties":{"status":{"type":"string"},"timeFrom":{"type":"string","format":"date-time"},"timeTo":{"type":"string","format":"date-time"},"durationMin":{"type":"integer","format":"int64"},"durationMax":{"type":"integer","format":"int64"},"correlationId":{"type":"string"},"text":{"type":"string"},"textInBody":{"type":"string"},"textInHeaders":{"type":"string"},"textInErrors":{"type":"string"},"routeId":{"type":"string"},"agentId":{"type":"string"},"processorType":{"type":"string"},"application":{"type":"string"},"agentIds":{"type":"array","items":{"type":"string"}},"offset":{"type":"integer","format":"int32"},"limit":{"type":"integer","format":"int32"},"sortField":{"type":"string"},"sortDir":{"type":"string"}}},"ExecutionSummary":{"type":"object","properties":{"executionId":{"type":"string"},"routeId":{"type":"string"},"agentId":{"type":"string"},"applicationName":{"type":"string"},"status":{"type":"string"},"startTime":{"type":"string","format":"date-time"},"endTime":{"type":"string","format":"date-time"},"durationMs":{"type":"integer","format":"int64"},"correlationId":{"type":"string"},"errorMessage":{"type":"string"},"diagramContentHash":{"type":"string"},"highlight":{"type":"string"},"attributes":{"type":"object","additionalProperties":{"type":"string"}}},"required":["agentId","applicationName","attributes","correlationId","diagramContentHash","durationMs","endTime","errorMessage","executionId","highlight","routeId","startTime","status"]},"SearchResultExecutionSummary":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ExecutionSummary"}},"total":{"type":"integer","format":"int64"},"offset":{"type":"integer","format":"int32"},"limit":{"type":"integer","format":"int32"}},"required":["data","limit","offset","total"]},"LogBatch":{"type":"object","properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/LogEntry"}}}},"LogEntry":{"type":"object","properties":{"timestamp":{"type":"string","format":"date-time"},"level":{"type":"string"},"loggerName":{"type":"string"},"message":{"type":"string"},"threadName":{"type":"string"},"stackTrace":{"type":"string"},"mdc":{"type":"object","additionalProperties":{"type":"string"}}}},"TestExpressionRequest":{"type":"object","properties":{"expression":{"type":"string"},"language":{"type":"string"},"body":{"type":"string"},"target":{"type":"string"}}},"TestExpressionResponse":{"type":"object","properties":{"result":{"type":"string"},"error":{"type":"string"}}},"RefreshRequest":{"type":"object","properties":{"refreshToken":{"type":"string"}}},"AuthTokenResponse":{"type":"object","description":"JWT token pair","properties":{"accessToken":{"type":"string"},"refreshToken":{"type":"string"},"displayName":{"type":"string"},"idToken":{"type":"string","description":"OIDC id_token for end-session logout (only present after OIDC login)"}},"required":["accessToken","displayName","refreshToken"]},"CallbackRequest":{"type":"object","properties":{"code":{"type":"string"},"redirectUri":{"type":"string"}}},"LoginRequest":{"type":"object","properties":{"username":{"type":"string"},"password":{"type":"string"}}},"AgentRefreshRequest":{"type":"object","description":"Agent token refresh request","properties":{"refreshToken":{"type":"string"}},"required":["refreshToken"]},"AgentRefreshResponse":{"type":"object","description":"Refreshed access and refresh tokens","properties":{"accessToken":{"type":"string"},"refreshToken":{"type":"string"}},"required":["accessToken","refreshToken"]},"CommandRequest":{"type":"object","description":"Command to send to agent(s)","properties":{"type":{"type":"string","description":"Command type: config-update, deep-trace, or replay"},"payload":{"type":"object","description":"Command payload JSON"}},"required":["type"]},"CommandSingleResponse":{"type":"object","description":"Result of sending a command to a single agent","properties":{"commandId":{"type":"string"},"status":{"type":"string"}},"required":["commandId","status"]},"CommandAckRequest":{"type":"object","properties":{"status":{"type":"string"},"message":{"type":"string"},"data":{"type":"string"}}},"AgentRegistrationRequest":{"type":"object","description":"Agent registration payload","properties":{"agentId":{"type":"string"},"name":{"type":"string"},"application":{"type":"string","default":"default"},"version":{"type":"string"},"routeIds":{"type":"array","items":{"type":"string"}},"capabilities":{"type":"object","additionalProperties":{"type":"object"}}},"required":["agentId","name"]},"AgentRegistrationResponse":{"type":"object","description":"Agent registration result with JWT tokens and SSE endpoint","properties":{"agentId":{"type":"string"},"sseEndpoint":{"type":"string"},"heartbeatIntervalMs":{"type":"integer","format":"int64"},"serverPublicKey":{"type":"string"},"accessToken":{"type":"string"},"refreshToken":{"type":"string"}},"required":["accessToken","agentId","refreshToken","serverPublicKey","sseEndpoint"]},"CommandBroadcastResponse":{"type":"object","description":"Result of broadcasting a command to multiple agents","properties":{"commandIds":{"type":"array","items":{"type":"string"}},"targetCount":{"type":"integer","format":"int32"}},"required":["commandIds"]},"CreateUserRequest":{"type":"object","properties":{"username":{"type":"string"},"displayName":{"type":"string"},"email":{"type":"string"},"password":{"type":"string"}}},"GroupSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}},"RoleSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"system":{"type":"boolean"},"source":{"type":"string"}}},"UserDetail":{"type":"object","properties":{"userId":{"type":"string"},"provider":{"type":"string"},"email":{"type":"string"},"displayName":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"directRoles":{"type":"array","items":{"$ref":"#/components/schemas/RoleSummary"}},"directGroups":{"type":"array","items":{"$ref":"#/components/schemas/GroupSummary"}},"effectiveRoles":{"type":"array","items":{"$ref":"#/components/schemas/RoleSummary"}},"effectiveGroups":{"type":"array","items":{"$ref":"#/components/schemas/GroupSummary"}}}},"SetPasswordRequest":{"type":"object","properties":{"password":{"type":"string","minLength":1}}},"CreateRoleRequest":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"scope":{"type":"string"}}},"OidcTestResult":{"type":"object","description":"OIDC provider connectivity test result","properties":{"status":{"type":"string"},"authorizationEndpoint":{"type":"string"}},"required":["authorizationEndpoint","status"]},"CreateGroupRequest":{"type":"object","properties":{"name":{"type":"string"},"parentGroupId":{"type":"string","format":"uuid"}}},"ExecutionStats":{"type":"object","properties":{"totalCount":{"type":"integer","format":"int64"},"failedCount":{"type":"integer","format":"int64"},"avgDurationMs":{"type":"integer","format":"int64"},"p99LatencyMs":{"type":"integer","format":"int64"},"activeCount":{"type":"integer","format":"int64"},"totalToday":{"type":"integer","format":"int64"},"prevTotalCount":{"type":"integer","format":"int64"},"prevFailedCount":{"type":"integer","format":"int64"},"prevAvgDurationMs":{"type":"integer","format":"int64"},"prevP99LatencyMs":{"type":"integer","format":"int64"}},"required":["activeCount","avgDurationMs","failedCount","p99LatencyMs","prevAvgDurationMs","prevFailedCount","prevP99LatencyMs","prevTotalCount","totalCount","totalToday"]},"StatsTimeseries":{"type":"object","properties":{"buckets":{"type":"array","items":{"$ref":"#/components/schemas/TimeseriesBucket"}}},"required":["buckets"]},"TimeseriesBucket":{"type":"object","properties":{"time":{"type":"string","format":"date-time"},"totalCount":{"type":"integer","format":"int64"},"failedCount":{"type":"integer","format":"int64"},"avgDurationMs":{"type":"integer","format":"int64"},"p99DurationMs":{"type":"integer","format":"int64"},"activeCount":{"type":"integer","format":"int64"}},"required":["activeCount","avgDurationMs","failedCount","p99DurationMs","time","totalCount"]},"RouteMetrics":{"type":"object","description":"Aggregated route performance metrics","properties":{"routeId":{"type":"string"},"appId":{"type":"string"},"exchangeCount":{"type":"integer","format":"int64"},"successRate":{"type":"number","format":"double"},"avgDurationMs":{"type":"number","format":"double"},"p99DurationMs":{"type":"number","format":"double"},"errorRate":{"type":"number","format":"double"},"throughputPerSec":{"type":"number","format":"double"},"sparkline":{"type":"array","items":{"type":"number","format":"double"}}},"required":["appId","avgDurationMs","errorRate","exchangeCount","p99DurationMs","routeId","sparkline","successRate","throughputPerSec"]},"ProcessorMetrics":{"type":"object","properties":{"processorId":{"type":"string"},"processorType":{"type":"string"},"routeId":{"type":"string"},"appId":{"type":"string"},"totalCount":{"type":"integer","format":"int64"},"failedCount":{"type":"integer","format":"int64"},"avgDurationMs":{"type":"number","format":"double"},"p99DurationMs":{"type":"number","format":"double"},"errorRate":{"type":"number","format":"double"}},"required":["appId","avgDurationMs","errorRate","failedCount","p99DurationMs","processorId","processorType","routeId","totalCount"]},"AgentSummary":{"type":"object","description":"Summary of an agent instance for sidebar display","properties":{"id":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"},"tps":{"type":"number","format":"double"}},"required":["id","name","status","tps"]},"AppCatalogEntry":{"type":"object","description":"Application catalog entry with routes and agents","properties":{"appId":{"type":"string"},"routes":{"type":"array","items":{"$ref":"#/components/schemas/RouteSummary"}},"agents":{"type":"array","items":{"$ref":"#/components/schemas/AgentSummary"}},"agentCount":{"type":"integer","format":"int32"},"health":{"type":"string"},"exchangeCount":{"type":"integer","format":"int64"}},"required":["agentCount","agents","appId","exchangeCount","health","routes"]},"RouteSummary":{"type":"object","description":"Summary of a route within an application","properties":{"routeId":{"type":"string"},"exchangeCount":{"type":"integer","format":"int64"},"lastSeen":{"type":"string","format":"date-time"}},"required":["exchangeCount","lastSeen","routeId"]},"LogEntryResponse":{"type":"object","description":"Application log entry from OpenSearch","properties":{"timestamp":{"type":"string","description":"Log timestamp (ISO-8601)"},"level":{"type":"string","description":"Log level (INFO, WARN, ERROR, DEBUG)"},"loggerName":{"type":"string","description":"Logger name"},"message":{"type":"string","description":"Log message"},"threadName":{"type":"string","description":"Thread name"},"stackTrace":{"type":"string","description":"Stack trace (if present)"}}},"ExecutionDetail":{"type":"object","properties":{"executionId":{"type":"string"},"routeId":{"type":"string"},"agentId":{"type":"string"},"applicationName":{"type":"string"},"status":{"type":"string"},"startTime":{"type":"string","format":"date-time"},"endTime":{"type":"string","format":"date-time"},"durationMs":{"type":"integer","format":"int64"},"correlationId":{"type":"string"},"exchangeId":{"type":"string"},"errorMessage":{"type":"string"},"errorStackTrace":{"type":"string"},"diagramContentHash":{"type":"string"},"processors":{"type":"array","items":{"$ref":"#/components/schemas/ProcessorNode"}},"inputBody":{"type":"string"},"outputBody":{"type":"string"},"inputHeaders":{"type":"string"},"outputHeaders":{"type":"string"},"attributes":{"type":"object","additionalProperties":{"type":"string"}}},"required":["agentId","applicationName","attributes","correlationId","diagramContentHash","durationMs","endTime","errorMessage","errorStackTrace","exchangeId","executionId","inputBody","inputHeaders","outputBody","outputHeaders","processors","routeId","startTime","status"]},"ProcessorNode":{"type":"object","properties":{"processorId":{"type":"string"},"processorType":{"type":"string"},"status":{"type":"string"},"startTime":{"type":"string","format":"date-time"},"endTime":{"type":"string","format":"date-time"},"durationMs":{"type":"integer","format":"int64"},"diagramNodeId":{"type":"string"},"errorMessage":{"type":"string"},"errorStackTrace":{"type":"string"},"attributes":{"type":"object","additionalProperties":{"type":"string"}},"children":{"type":"array","items":{"$ref":"#/components/schemas/ProcessorNode"}}},"required":["attributes","children","diagramNodeId","durationMs","endTime","errorMessage","errorStackTrace","processorId","processorType","startTime","status"]},"DiagramLayout":{"type":"object","properties":{"width":{"type":"number","format":"double"},"height":{"type":"number","format":"double"},"nodes":{"type":"array","items":{"$ref":"#/components/schemas/PositionedNode"}},"edges":{"type":"array","items":{"$ref":"#/components/schemas/PositionedEdge"}}}},"PositionedEdge":{"type":"object","properties":{"sourceId":{"type":"string"},"targetId":{"type":"string"},"label":{"type":"string"},"points":{"type":"array","items":{"type":"array","items":{"type":"number","format":"double"}}}}},"PositionedNode":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"type":{"type":"string"},"x":{"type":"number","format":"double"},"y":{"type":"number","format":"double"},"width":{"type":"number","format":"double"},"height":{"type":"number","format":"double"}}},"OidcPublicConfigResponse":{"type":"object","description":"OIDC configuration for SPA login flow","properties":{"issuer":{"type":"string"},"clientId":{"type":"string"},"authorizationEndpoint":{"type":"string"},"endSessionEndpoint":{"type":"string","description":"Present if the provider supports RP-initiated logout"}},"required":["authorizationEndpoint","clientId","issuer"]},"AgentInstanceResponse":{"type":"object","description":"Agent instance summary with runtime metrics","properties":{"id":{"type":"string"},"name":{"type":"string"},"application":{"type":"string"},"status":{"type":"string"},"routeIds":{"type":"array","items":{"type":"string"}},"registeredAt":{"type":"string","format":"date-time"},"lastHeartbeat":{"type":"string","format":"date-time"},"version":{"type":"string"},"capabilities":{"type":"object","additionalProperties":{"type":"object"}},"tps":{"type":"number","format":"double"},"errorRate":{"type":"number","format":"double"},"activeRoutes":{"type":"integer","format":"int32"},"totalRoutes":{"type":"integer","format":"int32"},"uptimeSeconds":{"type":"integer","format":"int64"}},"required":["activeRoutes","application","capabilities","errorRate","id","lastHeartbeat","name","registeredAt","routeIds","status","totalRoutes","tps","uptimeSeconds","version"]},"SseEmitter":{"type":"object","properties":{"timeout":{"type":"integer","format":"int64"}}},"AgentMetricsResponse":{"type":"object","properties":{"metrics":{"type":"object","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/MetricBucket"}}}},"required":["metrics"]},"MetricBucket":{"type":"object","properties":{"time":{"type":"string","format":"date-time"},"value":{"type":"number","format":"double"}},"required":["time","value"]},"AgentEventResponse":{"type":"object","description":"Agent lifecycle event","properties":{"id":{"type":"integer","format":"int64"},"agentId":{"type":"string"},"appId":{"type":"string"},"eventType":{"type":"string"},"detail":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}},"required":["agentId","appId","detail","eventType","id","timestamp"]},"RoleDetail":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"scope":{"type":"string"},"system":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"assignedGroups":{"type":"array","items":{"$ref":"#/components/schemas/GroupSummary"}},"directUsers":{"type":"array","items":{"$ref":"#/components/schemas/UserSummary"}},"effectivePrincipals":{"type":"array","items":{"$ref":"#/components/schemas/UserSummary"}}}},"UserSummary":{"type":"object","properties":{"userId":{"type":"string"},"displayName":{"type":"string"},"provider":{"type":"string"}}},"RbacStats":{"type":"object","properties":{"userCount":{"type":"integer","format":"int32"},"activeUserCount":{"type":"integer","format":"int32"},"groupCount":{"type":"integer","format":"int32"},"maxGroupDepth":{"type":"integer","format":"int32"},"roleCount":{"type":"integer","format":"int32"}}},"OpenSearchStatusResponse":{"type":"object","description":"OpenSearch cluster status","properties":{"reachable":{"type":"boolean","description":"Whether the cluster is reachable"},"clusterHealth":{"type":"string","description":"Cluster health status (GREEN, YELLOW, RED)"},"version":{"type":"string","description":"OpenSearch version"},"nodeCount":{"type":"integer","format":"int32","description":"Number of nodes in the cluster"},"host":{"type":"string","description":"OpenSearch host"}}},"PipelineStatsResponse":{"type":"object","description":"Search indexing pipeline statistics","properties":{"queueDepth":{"type":"integer","format":"int32","description":"Current queue depth"},"maxQueueSize":{"type":"integer","format":"int32","description":"Maximum queue size"},"failedCount":{"type":"integer","format":"int64","description":"Number of failed indexing operations"},"indexedCount":{"type":"integer","format":"int64","description":"Number of successfully indexed documents"},"debounceMs":{"type":"integer","format":"int64","description":"Debounce interval in milliseconds"},"indexingRate":{"type":"number","format":"double","description":"Current indexing rate (docs/sec)"},"lastIndexedAt":{"type":"string","format":"date-time","description":"Timestamp of last indexed document"}}},"PerformanceResponse":{"type":"object","description":"OpenSearch performance metrics","properties":{"queryCacheHitRate":{"type":"number","format":"double","description":"Query cache hit rate (0.0-1.0)"},"requestCacheHitRate":{"type":"number","format":"double","description":"Request cache hit rate (0.0-1.0)"},"searchLatencyMs":{"type":"number","format":"double","description":"Average search latency in milliseconds"},"indexingLatencyMs":{"type":"number","format":"double","description":"Average indexing latency in milliseconds"},"jvmHeapUsedBytes":{"type":"integer","format":"int64","description":"JVM heap used in bytes"},"jvmHeapMaxBytes":{"type":"integer","format":"int64","description":"JVM heap max in bytes"}}},"IndexInfoResponse":{"type":"object","description":"OpenSearch index information","properties":{"name":{"type":"string","description":"Index name"},"docCount":{"type":"integer","format":"int64","description":"Document count"},"size":{"type":"string","description":"Human-readable index size"},"sizeBytes":{"type":"integer","format":"int64","description":"Index size in bytes"},"health":{"type":"string","description":"Index health status"},"primaryShards":{"type":"integer","format":"int32","description":"Number of primary shards"},"replicaShards":{"type":"integer","format":"int32","description":"Number of replica shards"}}},"IndicesPageResponse":{"type":"object","description":"Paginated list of OpenSearch indices","properties":{"indices":{"type":"array","description":"Index list for current page","items":{"$ref":"#/components/schemas/IndexInfoResponse"}},"totalIndices":{"type":"integer","format":"int64","description":"Total number of indices"},"totalDocs":{"type":"integer","format":"int64","description":"Total document count across all indices"},"totalSize":{"type":"string","description":"Human-readable total size"},"page":{"type":"integer","format":"int32","description":"Current page number (0-based)"},"pageSize":{"type":"integer","format":"int32","description":"Page size"},"totalPages":{"type":"integer","format":"int32","description":"Total number of pages"}}},"GroupDetail":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"parentGroupId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"directRoles":{"type":"array","items":{"$ref":"#/components/schemas/RoleSummary"}},"effectiveRoles":{"type":"array","items":{"$ref":"#/components/schemas/RoleSummary"}},"members":{"type":"array","items":{"$ref":"#/components/schemas/UserSummary"}},"childGroups":{"type":"array","items":{"$ref":"#/components/schemas/GroupSummary"}}}},"TableSizeResponse":{"type":"object","description":"Table size and row count information","properties":{"tableName":{"type":"string","description":"Table name"},"rowCount":{"type":"integer","format":"int64","description":"Approximate row count"},"dataSize":{"type":"string","description":"Human-readable data size"},"indexSize":{"type":"string","description":"Human-readable index size"},"dataSizeBytes":{"type":"integer","format":"int64","description":"Data size in bytes"},"indexSizeBytes":{"type":"integer","format":"int64","description":"Index size in bytes"}}},"DatabaseStatusResponse":{"type":"object","description":"Database connection and version status","properties":{"connected":{"type":"boolean","description":"Whether the database is reachable"},"version":{"type":"string","description":"PostgreSQL version string"},"host":{"type":"string","description":"Database host"},"schema":{"type":"string","description":"Current schema search path"},"timescaleDb":{"type":"boolean","description":"Whether TimescaleDB extension is available"}}},"ActiveQueryResponse":{"type":"object","description":"Currently running database query","properties":{"pid":{"type":"integer","format":"int32","description":"Backend process ID"},"durationSeconds":{"type":"number","format":"double","description":"Query duration in seconds"},"state":{"type":"string","description":"Backend state (active, idle, etc.)"},"query":{"type":"string","description":"SQL query text"}}},"ConnectionPoolResponse":{"type":"object","description":"HikariCP connection pool statistics","properties":{"activeConnections":{"type":"integer","format":"int32","description":"Number of currently active connections"},"idleConnections":{"type":"integer","format":"int32","description":"Number of idle connections"},"pendingThreads":{"type":"integer","format":"int32","description":"Number of threads waiting for a connection"},"maxWaitMs":{"type":"integer","format":"int64","description":"Maximum wait time in milliseconds"},"maxPoolSize":{"type":"integer","format":"int32","description":"Maximum pool size"}}},"AuditLogPageResponse":{"type":"object","description":"Paginated audit log entries","properties":{"items":{"type":"array","description":"Audit log entries","items":{"$ref":"#/components/schemas/AuditRecord"}},"totalCount":{"type":"integer","format":"int64","description":"Total number of matching entries"},"page":{"type":"integer","format":"int32","description":"Current page number (0-based)"},"pageSize":{"type":"integer","format":"int32","description":"Page size"},"totalPages":{"type":"integer","format":"int32","description":"Total number of pages"}}},"AuditRecord":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"timestamp":{"type":"string","format":"date-time"},"username":{"type":"string"},"action":{"type":"string"},"category":{"type":"string","enum":["INFRA","AUTH","USER_MGMT","CONFIG","RBAC","AGENT"]},"target":{"type":"string"},"detail":{"type":"object","additionalProperties":{"type":"object"}},"result":{"type":"string","enum":["SUCCESS","FAILURE"]},"ipAddress":{"type":"string"},"userAgent":{"type":"string"}}}},"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}}}} \ No newline at end of file diff --git a/org/eclipse/elk/alg/layered/options/.LayeredOptions.java._trace b/org/eclipse/elk/alg/layered/options/.LayeredOptions.java._trace new file mode 100644 index 00000000..144082a5 Binary files /dev/null and b/org/eclipse/elk/alg/layered/options/.LayeredOptions.java._trace differ diff --git a/org/eclipse/elk/core/options/CoreOptions.java b/org/eclipse/elk/core/options/CoreOptions.java new file mode 100644 index 00000000..fa48310b --- /dev/null +++ b/org/eclipse/elk/core/options/CoreOptions.java @@ -0,0 +1,2661 @@ +/** + * Copyright (c) 2015, 2020 Kiel University and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.elk.core.options; + +import java.util.EnumSet; +import org.eclipse.elk.core.data.ILayoutMetaDataProvider; +import org.eclipse.elk.core.data.LayoutAlgorithmData; +import org.eclipse.elk.core.data.LayoutCategoryData; +import org.eclipse.elk.core.data.LayoutOptionData; +import org.eclipse.elk.core.labels.ILabelManager; +import org.eclipse.elk.core.math.ElkMargin; +import org.eclipse.elk.core.math.ElkPadding; +import org.eclipse.elk.core.math.KVector; +import org.eclipse.elk.core.math.KVectorChain; +import org.eclipse.elk.core.util.BoxLayoutProvider; +import org.eclipse.elk.core.util.ExclusiveBounds; +import org.eclipse.elk.core.util.IndividualSpacings; +import org.eclipse.elk.graph.properties.IProperty; +import org.eclipse.elk.graph.properties.Property; + +/** + * Core definitions of the Eclipse Layout Kernel. + */ +@SuppressWarnings("all") +public class CoreOptions implements ILayoutMetaDataProvider { + /** + * Select a specific layout algorithm. + */ + public static final IProperty ALGORITHM = new Property( + "org.eclipse.elk.algorithm"); + + /** + * Meta data associated with the selected algorithm. + */ + public static final IProperty RESOLVED_ALGORITHM = new Property( + "org.eclipse.elk.resolvedAlgorithm"); + + /** + * Default value for {@link #ALIGNMENT}. + */ + private static final Alignment ALIGNMENT_DEFAULT = Alignment.AUTOMATIC; + + /** + * Alignment of the selected node relative to other nodes; + * the exact meaning depends on the used algorithm. + */ + public static final IProperty ALIGNMENT = new Property( + "org.eclipse.elk.alignment", + ALIGNMENT_DEFAULT, + null, + null); + + /** + * Lower bound value for {@link #ASPECT_RATIO}. + */ + private static final Comparable ASPECT_RATIO_LOWER_BOUND = ExclusiveBounds.greaterThan(0); + + /** + * The desired aspect ratio of the drawing, that is the quotient of width by height. + */ + public static final IProperty ASPECT_RATIO = new Property( + "org.eclipse.elk.aspectRatio", + null, + ASPECT_RATIO_LOWER_BOUND, + null); + + /** + * A fixed list of bend points for the edge. This is used by the 'Fixed Layout' algorithm to + * specify a pre-defined routing for an edge. The vector chain must include the source point, + * any bend points, and the target point, so it must have at least two points. + */ + public static final IProperty BEND_POINTS = new Property( + "org.eclipse.elk.bendPoints"); + + /** + * Default value for {@link #CONTENT_ALIGNMENT}. + */ + private static final EnumSet CONTENT_ALIGNMENT_DEFAULT = ContentAlignment.topLeft(); + + /** + * Specifies how the content of a node are aligned. Each node can individually control the alignment of its + * contents. I.e. if a node should be aligned top left in its parent node, the parent node should specify that + * option. + */ + public static final IProperty> CONTENT_ALIGNMENT = new Property>( + "org.eclipse.elk.contentAlignment", + CONTENT_ALIGNMENT_DEFAULT, + null, + null); + + /** + * Default value for {@link #DEBUG_MODE}. + */ + private static final boolean DEBUG_MODE_DEFAULT = false; + + /** + * Whether additional debug information shall be generated. + */ + public static final IProperty DEBUG_MODE = new Property( + "org.eclipse.elk.debugMode", + DEBUG_MODE_DEFAULT, + null, + null); + + /** + * Default value for {@link #DIRECTION}. + */ + private static final Direction DIRECTION_DEFAULT = Direction.UNDEFINED; + + /** + * Overall direction of edges: horizontal (right / left) or + * vertical (down / up). + */ + public static final IProperty DIRECTION = new Property( + "org.eclipse.elk.direction", + DIRECTION_DEFAULT, + null, + null); + + /** + * Default value for {@link #EDGE_ROUTING}. + */ + private static final EdgeRouting EDGE_ROUTING_DEFAULT = EdgeRouting.UNDEFINED; + + /** + * What kind of edge routing style should be applied for the content of a parent node. + * Algorithms may also set this option to single edges in order to mark them as splines. + * The bend point list of edges with this option set to SPLINES must be interpreted as control + * points for a piecewise cubic spline. + */ + public static final IProperty EDGE_ROUTING = new Property( + "org.eclipse.elk.edgeRouting", + EDGE_ROUTING_DEFAULT, + null, + null); + + /** + * Default value for {@link #EXPAND_NODES}. + */ + private static final boolean EXPAND_NODES_DEFAULT = false; + + /** + * If active, nodes are expanded to fill the area of their parent. + */ + public static final IProperty EXPAND_NODES = new Property( + "org.eclipse.elk.expandNodes", + EXPAND_NODES_DEFAULT, + null, + null); + + /** + * Default value for {@link #HIERARCHY_HANDLING}. + */ + private static final HierarchyHandling HIERARCHY_HANDLING_DEFAULT = HierarchyHandling.INHERIT; + + /** + * Determines whether separate layout runs are triggered for different compound nodes in a + * hierarchical graph. Setting a node's hierarchy handling to `INCLUDE_CHILDREN` will lay + * out that node and all of its descendants in a single layout run, until a descendant is + * encountered which has its hierarchy handling set to `SEPARATE_CHILDREN`. In general, + * `SEPARATE_CHILDREN` will ensure that a new layout run is triggered for a node with that + * setting. Including multiple levels of hierarchy in a single layout run may allow + * cross-hierarchical edges to be laid out properly. If the root node is set to `INHERIT` + * (or not set at all), the default behavior is `SEPARATE_CHILDREN`. + */ + public static final IProperty HIERARCHY_HANDLING = new Property( + "org.eclipse.elk.hierarchyHandling", + HIERARCHY_HANDLING_DEFAULT, + null, + null); + + /** + * Default value for {@link #PADDING}. + */ + private static final ElkPadding PADDING_DEFAULT = new ElkPadding(12); + + /** + * The padding to be left to a parent element's border when placing child elements. This can + * also serve as an output option of a layout algorithm if node size calculation is setup + * appropriately. + */ + public static final IProperty PADDING = new Property( + "org.eclipse.elk.padding", + PADDING_DEFAULT, + null, + null); + + /** + * Default value for {@link #INTERACTIVE}. + */ + private static final boolean INTERACTIVE_DEFAULT = false; + + /** + * Whether the algorithm should be run in interactive mode for the content of a parent node. + * What this means exactly depends on how the specific algorithm interprets this option. + * Usually in the interactive mode algorithms try to modify the current layout as little as + * possible. + */ + public static final IProperty INTERACTIVE = new Property( + "org.eclipse.elk.interactive", + INTERACTIVE_DEFAULT, + null, + null); + + /** + * Default value for {@link #INTERACTIVE_LAYOUT}. + */ + private static final boolean INTERACTIVE_LAYOUT_DEFAULT = false; + + /** + * Whether the graph should be changeable interactively and by setting constraints + */ + public static final IProperty INTERACTIVE_LAYOUT = new Property( + "org.eclipse.elk.interactiveLayout", + INTERACTIVE_LAYOUT_DEFAULT, + null, + null); + + /** + * Default value for {@link #OMIT_NODE_MICRO_LAYOUT}. + */ + private static final boolean OMIT_NODE_MICRO_LAYOUT_DEFAULT = false; + + /** + * Node micro layout comprises the computation of node dimensions (if requested), the placement of ports + * and their labels, and the placement of node labels. + * The functionality is implemented independent of any specific layout algorithm and shouldn't have any + * negative impact on the layout algorithm's performance itself. Yet, if any unforeseen behavior occurs, + * this option allows to deactivate the micro layout. + */ + public static final IProperty OMIT_NODE_MICRO_LAYOUT = new Property( + "org.eclipse.elk.omitNodeMicroLayout", + OMIT_NODE_MICRO_LAYOUT_DEFAULT, + null, + null); + + /** + * Default value for {@link #PORT_CONSTRAINTS}. + */ + private static final PortConstraints PORT_CONSTRAINTS_DEFAULT = PortConstraints.UNDEFINED; + + /** + * Defines constraints of the position of the ports of a node. + */ + public static final IProperty PORT_CONSTRAINTS = new Property( + "org.eclipse.elk.portConstraints", + PORT_CONSTRAINTS_DEFAULT, + null, + null); + + /** + * The position of a node, port, or label. This is used by the 'Fixed Layout' algorithm to + * specify a pre-defined position. + */ + public static final IProperty POSITION = new Property( + "org.eclipse.elk.position"); + + /** + * Defines the priority of an object; its meaning depends on the specific layout algorithm + * and the context where it is used. + */ + public static final IProperty PRIORITY = new Property( + "org.eclipse.elk.priority"); + + /** + * Seed used for pseudo-random number generators to control the layout algorithm. If the + * value is 0, the seed shall be determined pseudo-randomly (e.g. from the system time). + */ + public static final IProperty RANDOM_SEED = new Property( + "org.eclipse.elk.randomSeed"); + + /** + * Whether each connected component should be processed separately. + */ + public static final IProperty SEPARATE_CONNECTED_COMPONENTS = new Property( + "org.eclipse.elk.separateConnectedComponents"); + + /** + * Default value for {@link #JUNCTION_POINTS}. + */ + private static final KVectorChain JUNCTION_POINTS_DEFAULT = new KVectorChain(); + + /** + * This option is not used as option, but as output of the layout algorithms. It is + * attached to edges and determines the points where junction symbols should be drawn in + * order to represent hyperedges with orthogonal routing. Whether such points are computed + * depends on the chosen layout algorithm and edge routing style. The points are put into + * the vector chain with no specific order. + */ + public static final IProperty JUNCTION_POINTS = new Property( + "org.eclipse.elk.junctionPoints", + JUNCTION_POINTS_DEFAULT, + null, + null); + + /** + * Default value for {@link #COMMENT_BOX}. + */ + private static final boolean COMMENT_BOX_DEFAULT = false; + + /** + * Whether the node should be regarded as a comment box instead of a regular node. In that + * case its placement should be similar to how labels are handled. Any edges incident to a + * comment box specify to which graph elements the comment is related. + */ + public static final IProperty COMMENT_BOX = new Property( + "org.eclipse.elk.commentBox", + COMMENT_BOX_DEFAULT, + null, + null); + + /** + * Default value for {@link #HYPERNODE}. + */ + private static final boolean HYPERNODE_DEFAULT = false; + + /** + * Whether the node should be handled as a hypernode. + */ + public static final IProperty HYPERNODE = new Property( + "org.eclipse.elk.hypernode", + HYPERNODE_DEFAULT, + null, + null); + + /** + * Label managers can shorten labels upon a layout algorithm's request. + */ + public static final IProperty LABEL_MANAGER = new Property( + "org.eclipse.elk.labelManager"); + + /** + * Default value for {@link #SOFTWRAPPING_FUZZINESS}. + */ + private static final double SOFTWRAPPING_FUZZINESS_DEFAULT = 0.0; + + /** + * Determines the amount of fuzziness to be used when performing softwrapping on labels. + * The value expresses the percent of overhang that is permitted for each line. + * If the next line would take up less space than this threshold, it is appended to the + * current line instead of being placed in a new line. + */ + public static final IProperty SOFTWRAPPING_FUZZINESS = new Property( + "org.eclipse.elk.softwrappingFuzziness", + SOFTWRAPPING_FUZZINESS_DEFAULT, + null, + null); + + /** + * Default value for {@link #MARGINS}. + */ + private static final ElkMargin MARGINS_DEFAULT = new ElkMargin(); + + /** + * Margins define additional space around the actual bounds of a graph element. For instance, + * ports or labels being placed on the outside of a node's border might introduce such a + * margin. The margin is used to guarantee non-overlap of other graph elements with those + * ports or labels. + */ + public static final IProperty MARGINS = new Property( + "org.eclipse.elk.margins", + MARGINS_DEFAULT, + null, + null); + + /** + * Default value for {@link #NO_LAYOUT}. + */ + private static final boolean NO_LAYOUT_DEFAULT = false; + + /** + * No layout is done for the associated element. This is used to mark parts of a diagram to + * avoid their inclusion in the layout graph, or to mark parts of the layout graph to + * prevent layout engines from processing them. If you wish to exclude the contents of a + * compound node from automatic layout, while the node itself is still considered on its own + * layer, use the 'Fixed Layout' algorithm for that node. + */ + public static final IProperty NO_LAYOUT = new Property( + "org.eclipse.elk.noLayout", + NO_LAYOUT_DEFAULT, + null, + null); + + /** + * Default value for {@link #SCALE_FACTOR}. + */ + private static final double SCALE_FACTOR_DEFAULT = 1; + + /** + * Lower bound value for {@link #SCALE_FACTOR}. + */ + private static final Comparable SCALE_FACTOR_LOWER_BOUND = ExclusiveBounds.greaterThan(0); + + /** + * The scaling factor to be applied to the corresponding node in recursive layout. It causes + * the corresponding node's size to be adjusted, and its ports and labels to be sized and + * placed accordingly after the layout of that node has been determined (and before the node + * itself and its siblings are arranged). The scaling is not reverted afterwards, so the + * resulting layout graph contains the adjusted size and position data. This option is + * currently not supported if 'Layout Hierarchy' is set. + */ + public static final IProperty SCALE_FACTOR = new Property( + "org.eclipse.elk.scaleFactor", + SCALE_FACTOR_DEFAULT, + SCALE_FACTOR_LOWER_BOUND, + null); + + /** + * The width of the area occupied by the laid out children of a node. + */ + public static final IProperty CHILD_AREA_WIDTH = new Property( + "org.eclipse.elk.childAreaWidth"); + + /** + * The height of the area occupied by the laid out children of a node. + */ + public static final IProperty CHILD_AREA_HEIGHT = new Property( + "org.eclipse.elk.childAreaHeight"); + + /** + * Default value for {@link #TOPDOWN_LAYOUT}. + */ + private static final boolean TOPDOWN_LAYOUT_DEFAULT = false; + + /** + * Turns topdown layout on and off. If this option is enabled, hierarchical layout will be computed first for + * the root node and then for its children recursively. Layouts are then scaled down to fit the area provided by + * their parents. Graphs must follow a certain structure for topdown layout to work properly. + * {@link TopdownNodeTypes.PARALLEL_NODE} nodes must have children of type + * {@link TopdownNodeTypes.HIERARCHICAL_NODE} and must define {@link topdown.hierarchicalNodeWidth} and + * {@link topdown.hierarchicalNodeAspectRatio} for their children. Furthermore they need to be laid out using an + * algorithm that is a {@link TopdownLayoutProvider}. Hierarchical nodes can also be parents of other hierarchical + * nodes and can optionally use a {@link TopdownSizeApproximator} to dynamically set sizes during topdown layout. + * In this case {@link topdown.hierarchicalNodeWidth} and {@link topdown.hierarchicalNodeAspectRatio} should be set + * on the node itself rather than the parent. The values are then used by the size approximator as base values. + * Hierarchical nodes require the layout option {@link nodeSize.fixedGraphSize} to be true to prevent the algorithm + * used there from resizing the hierarchical node. This option is not supported if 'Hierarchy Handling' is set to + * 'INCLUDE_CHILDREN' + */ + public static final IProperty TOPDOWN_LAYOUT = new Property( + "org.eclipse.elk.topdownLayout", + TOPDOWN_LAYOUT_DEFAULT, + null, + null); + + /** + * Default value for {@link #ANIMATE}. + */ + private static final boolean ANIMATE_DEFAULT = true; + + /** + * Whether the shift from the old layout to the new computed layout shall be animated. + */ + public static final IProperty ANIMATE = new Property( + "org.eclipse.elk.animate", + ANIMATE_DEFAULT, + null, + null); + + /** + * Default value for {@link #ANIM_TIME_FACTOR}. + */ + private static final int ANIM_TIME_FACTOR_DEFAULT = 100; + + /** + * Lower bound value for {@link #ANIM_TIME_FACTOR}. + */ + private static final Comparable ANIM_TIME_FACTOR_LOWER_BOUND = Integer.valueOf(0); + + /** + * Factor for computation of animation time. The higher the value, the longer the animation + * time. If the value is 0, the resulting time is always equal to the minimum defined by + * 'Minimal Animation Time'. + */ + public static final IProperty ANIM_TIME_FACTOR = new Property( + "org.eclipse.elk.animTimeFactor", + ANIM_TIME_FACTOR_DEFAULT, + ANIM_TIME_FACTOR_LOWER_BOUND, + null); + + /** + * Default value for {@link #LAYOUT_ANCESTORS}. + */ + private static final boolean LAYOUT_ANCESTORS_DEFAULT = false; + + /** + * Whether the hierarchy levels on the path from the selected element to the root of the + * diagram shall be included in the layout process. + */ + public static final IProperty LAYOUT_ANCESTORS = new Property( + "org.eclipse.elk.layoutAncestors", + LAYOUT_ANCESTORS_DEFAULT, + null, + null); + + /** + * Default value for {@link #MAX_ANIM_TIME}. + */ + private static final int MAX_ANIM_TIME_DEFAULT = 4000; + + /** + * Lower bound value for {@link #MAX_ANIM_TIME}. + */ + private static final Comparable MAX_ANIM_TIME_LOWER_BOUND = Integer.valueOf(0); + + /** + * The maximal time for animations, in milliseconds. + */ + public static final IProperty MAX_ANIM_TIME = new Property( + "org.eclipse.elk.maxAnimTime", + MAX_ANIM_TIME_DEFAULT, + MAX_ANIM_TIME_LOWER_BOUND, + null); + + /** + * Default value for {@link #MIN_ANIM_TIME}. + */ + private static final int MIN_ANIM_TIME_DEFAULT = 400; + + /** + * Lower bound value for {@link #MIN_ANIM_TIME}. + */ + private static final Comparable MIN_ANIM_TIME_LOWER_BOUND = Integer.valueOf(0); + + /** + * The minimal time for animations, in milliseconds. + */ + public static final IProperty MIN_ANIM_TIME = new Property( + "org.eclipse.elk.minAnimTime", + MIN_ANIM_TIME_DEFAULT, + MIN_ANIM_TIME_LOWER_BOUND, + null); + + /** + * Default value for {@link #PROGRESS_BAR}. + */ + private static final boolean PROGRESS_BAR_DEFAULT = false; + + /** + * Whether a progress bar shall be displayed during layout computations. + */ + public static final IProperty PROGRESS_BAR = new Property( + "org.eclipse.elk.progressBar", + PROGRESS_BAR_DEFAULT, + null, + null); + + /** + * Default value for {@link #VALIDATE_GRAPH}. + */ + private static final boolean VALIDATE_GRAPH_DEFAULT = false; + + /** + * Whether the graph shall be validated before any layout algorithm is applied. If this + * option is enabled and at least one error is found, the layout process is aborted and a message + * is shown to the user. + */ + public static final IProperty VALIDATE_GRAPH = new Property( + "org.eclipse.elk.validateGraph", + VALIDATE_GRAPH_DEFAULT, + null, + null); + + /** + * Default value for {@link #VALIDATE_OPTIONS}. + */ + private static final boolean VALIDATE_OPTIONS_DEFAULT = true; + + /** + * Whether layout options shall be validated before any layout algorithm is applied. If this + * option is enabled and at least one error is found, the layout process is aborted and a message + * is shown to the user. + */ + public static final IProperty VALIDATE_OPTIONS = new Property( + "org.eclipse.elk.validateOptions", + VALIDATE_OPTIONS_DEFAULT, + null, + null); + + /** + * Default value for {@link #ZOOM_TO_FIT}. + */ + private static final boolean ZOOM_TO_FIT_DEFAULT = false; + + /** + * Whether the zoom level shall be set to view the whole diagram after layout. + */ + public static final IProperty ZOOM_TO_FIT = new Property( + "org.eclipse.elk.zoomToFit", + ZOOM_TO_FIT_DEFAULT, + null, + null); + + /** + * Default value for {@link #BOX_PACKING_MODE}. + */ + private static final BoxLayoutProvider.PackingMode BOX_PACKING_MODE_DEFAULT = BoxLayoutProvider.PackingMode.SIMPLE; + + /** + * Configures the packing mode used by the {@link BoxLayoutProvider}. + * If SIMPLE is not required (neither priorities are used nor the interactive mode), + * GROUP_DEC can improve the packing and decrease the area. + * GROUP_MIXED and GROUP_INC may, in very specific scenarios, work better. + */ + public static final IProperty BOX_PACKING_MODE = new Property( + "org.eclipse.elk.box.packingMode", + BOX_PACKING_MODE_DEFAULT, + null, + null); + + /** + * Default value for {@link #JSON_SHAPE_COORDS}. + */ + private static final ShapeCoords JSON_SHAPE_COORDS_DEFAULT = ShapeCoords.INHERIT; + + /** + * For layouts transferred into JSON graphs, specify the coordinate system + * to be used for nodes, ports, and labels of nodes and ports. + */ + public static final IProperty JSON_SHAPE_COORDS = new Property( + "org.eclipse.elk.json.shapeCoords", + JSON_SHAPE_COORDS_DEFAULT, + null, + null); + + /** + * Default value for {@link #JSON_EDGE_COORDS}. + */ + private static final EdgeCoords JSON_EDGE_COORDS_DEFAULT = EdgeCoords.INHERIT; + + /** + * For layouts transferred into JSON graphs, specify the coordinate system + * to be used for edge route points and edge labels. + */ + public static final IProperty JSON_EDGE_COORDS = new Property( + "org.eclipse.elk.json.edgeCoords", + JSON_EDGE_COORDS_DEFAULT, + null, + null); + + /** + * Default value for {@link #SPACING_COMMENT_COMMENT}. + */ + private static final double SPACING_COMMENT_COMMENT_DEFAULT = 10; + + /** + * Lower bound value for {@link #SPACING_COMMENT_COMMENT}. + */ + private static final Comparable SPACING_COMMENT_COMMENT_LOWER_BOUND = Double.valueOf(0.0); + + /** + * Spacing to be preserved between a comment box and other comment boxes connected to the same node. + * The space left between comment boxes of different nodes is controlled by the node-node spacing. + */ + public static final IProperty SPACING_COMMENT_COMMENT = new Property( + "org.eclipse.elk.spacing.commentComment", + SPACING_COMMENT_COMMENT_DEFAULT, + SPACING_COMMENT_COMMENT_LOWER_BOUND, + null); + + /** + * Default value for {@link #SPACING_COMMENT_NODE}. + */ + private static final double SPACING_COMMENT_NODE_DEFAULT = 10; + + /** + * Lower bound value for {@link #SPACING_COMMENT_NODE}. + */ + private static final Comparable SPACING_COMMENT_NODE_LOWER_BOUND = Double.valueOf(0.0); + + /** + * Spacing to be preserved between a node and its connected comment boxes. The space left between a node + * and the comments of another node is controlled by the node-node spacing. + */ + public static final IProperty SPACING_COMMENT_NODE = new Property( + "org.eclipse.elk.spacing.commentNode", + SPACING_COMMENT_NODE_DEFAULT, + SPACING_COMMENT_NODE_LOWER_BOUND, + null); + + /** + * Default value for {@link #SPACING_COMPONENT_COMPONENT}. + */ + private static final double SPACING_COMPONENT_COMPONENT_DEFAULT = 20f; + + /** + * Lower bound value for {@link #SPACING_COMPONENT_COMPONENT}. + */ + private static final Comparable SPACING_COMPONENT_COMPONENT_LOWER_BOUND = Double.valueOf(0.0); + + /** + * Spacing to be preserved between pairs of connected components. + * This option is only relevant if 'separateConnectedComponents' is activated. + */ + public static final IProperty SPACING_COMPONENT_COMPONENT = new Property( + "org.eclipse.elk.spacing.componentComponent", + SPACING_COMPONENT_COMPONENT_DEFAULT, + SPACING_COMPONENT_COMPONENT_LOWER_BOUND, + null); + + /** + * Default value for {@link #SPACING_EDGE_EDGE}. + */ + private static final double SPACING_EDGE_EDGE_DEFAULT = 10; + + /** + * Lower bound value for {@link #SPACING_EDGE_EDGE}. + */ + private static final Comparable SPACING_EDGE_EDGE_LOWER_BOUND = Double.valueOf(0.0); + + /** + * Spacing to be preserved between any two edges. Note that while this can somewhat easily be satisfied + * for the segments of orthogonally drawn edges, it is harder for general polylines or splines. + */ + public static final IProperty SPACING_EDGE_EDGE = new Property( + "org.eclipse.elk.spacing.edgeEdge", + SPACING_EDGE_EDGE_DEFAULT, + SPACING_EDGE_EDGE_LOWER_BOUND, + null); + + /** + * Default value for {@link #SPACING_EDGE_LABEL}. + */ + private static final double SPACING_EDGE_LABEL_DEFAULT = 2; + + /** + * Lower bound value for {@link #SPACING_EDGE_LABEL}. + */ + private static final Comparable SPACING_EDGE_LABEL_LOWER_BOUND = Double.valueOf(0.0); + + /** + * The minimal distance to be preserved between a label and the edge it is associated with. + * Note that the placement of a label is influenced by the 'edgelabels.placement' option. + */ + public static final IProperty SPACING_EDGE_LABEL = new Property( + "org.eclipse.elk.spacing.edgeLabel", + SPACING_EDGE_LABEL_DEFAULT, + SPACING_EDGE_LABEL_LOWER_BOUND, + null); + + /** + * Default value for {@link #SPACING_EDGE_NODE}. + */ + private static final double SPACING_EDGE_NODE_DEFAULT = 10; + + /** + * Lower bound value for {@link #SPACING_EDGE_NODE}. + */ + private static final Comparable SPACING_EDGE_NODE_LOWER_BOUND = Double.valueOf(0.0); + + /** + * Spacing to be preserved between nodes and edges. + */ + public static final IProperty SPACING_EDGE_NODE = new Property( + "org.eclipse.elk.spacing.edgeNode", + SPACING_EDGE_NODE_DEFAULT, + SPACING_EDGE_NODE_LOWER_BOUND, + null); + + /** + * Default value for {@link #SPACING_LABEL_LABEL}. + */ + private static final double SPACING_LABEL_LABEL_DEFAULT = 0; + + /** + * Lower bound value for {@link #SPACING_LABEL_LABEL}. + */ + private static final Comparable SPACING_LABEL_LABEL_LOWER_BOUND = Double.valueOf(0.0); + + /** + * Determines the amount of space to be left between two labels + * of the same graph element. + */ + public static final IProperty SPACING_LABEL_LABEL = new Property( + "org.eclipse.elk.spacing.labelLabel", + SPACING_LABEL_LABEL_DEFAULT, + SPACING_LABEL_LABEL_LOWER_BOUND, + null); + + /** + * Default value for {@link #SPACING_LABEL_NODE}. + */ + private static final double SPACING_LABEL_NODE_DEFAULT = 5; + + /** + * Lower bound value for {@link #SPACING_LABEL_NODE}. + */ + private static final Comparable SPACING_LABEL_NODE_LOWER_BOUND = Double.valueOf(0.0); + + /** + * Spacing to be preserved between labels and the border of node they are associated with. + * Note that the placement of a label is influenced by the 'nodelabels.placement' option. + */ + public static final IProperty SPACING_LABEL_NODE = new Property( + "org.eclipse.elk.spacing.labelNode", + SPACING_LABEL_NODE_DEFAULT, + SPACING_LABEL_NODE_LOWER_BOUND, + null); + + /** + * Default value for {@link #SPACING_LABEL_PORT_HORIZONTAL}. + */ + private static final double SPACING_LABEL_PORT_HORIZONTAL_DEFAULT = 1; + + /** + * Horizontal spacing to be preserved between labels and the ports they are associated with. + * Note that the placement of a label is influenced by the 'portlabels.placement' option. + */ + public static final IProperty SPACING_LABEL_PORT_HORIZONTAL = new Property( + "org.eclipse.elk.spacing.labelPortHorizontal", + SPACING_LABEL_PORT_HORIZONTAL_DEFAULT, + null, + null); + + /** + * Default value for {@link #SPACING_LABEL_PORT_VERTICAL}. + */ + private static final double SPACING_LABEL_PORT_VERTICAL_DEFAULT = 1; + + /** + * Vertical spacing to be preserved between labels and the ports they are associated with. + * Note that the placement of a label is influenced by the 'portlabels.placement' option. + */ + public static final IProperty SPACING_LABEL_PORT_VERTICAL = new Property( + "org.eclipse.elk.spacing.labelPortVertical", + SPACING_LABEL_PORT_VERTICAL_DEFAULT, + null, + null); + + /** + * Default value for {@link #SPACING_NODE_NODE}. + */ + private static final double SPACING_NODE_NODE_DEFAULT = 20; + + /** + * Lower bound value for {@link #SPACING_NODE_NODE}. + */ + private static final Comparable SPACING_NODE_NODE_LOWER_BOUND = Double.valueOf(0.0); + + /** + * The minimal distance to be preserved between each two nodes. + */ + public static final IProperty SPACING_NODE_NODE = new Property( + "org.eclipse.elk.spacing.nodeNode", + SPACING_NODE_NODE_DEFAULT, + SPACING_NODE_NODE_LOWER_BOUND, + null); + + /** + * Default value for {@link #SPACING_NODE_SELF_LOOP}. + */ + private static final double SPACING_NODE_SELF_LOOP_DEFAULT = 10; + + /** + * Lower bound value for {@link #SPACING_NODE_SELF_LOOP}. + */ + private static final Comparable SPACING_NODE_SELF_LOOP_LOWER_BOUND = Double.valueOf(0.0); + + /** + * Spacing to be preserved between a node and its self loops. + */ + public static final IProperty SPACING_NODE_SELF_LOOP = new Property( + "org.eclipse.elk.spacing.nodeSelfLoop", + SPACING_NODE_SELF_LOOP_DEFAULT, + SPACING_NODE_SELF_LOOP_LOWER_BOUND, + null); + + /** + * Default value for {@link #SPACING_PORT_PORT}. + */ + private static final double SPACING_PORT_PORT_DEFAULT = 10; + + /** + * Lower bound value for {@link #SPACING_PORT_PORT}. + */ + private static final Comparable SPACING_PORT_PORT_LOWER_BOUND = Double.valueOf(0.0); + + /** + * Spacing between pairs of ports of the same node. + */ + public static final IProperty SPACING_PORT_PORT = new Property( + "org.eclipse.elk.spacing.portPort", + SPACING_PORT_PORT_DEFAULT, + SPACING_PORT_PORT_LOWER_BOUND, + null); + + /** + * Allows to specify individual spacing values for graph elements that shall be different from + * the value specified for the element's parent. + */ + public static final IProperty SPACING_INDIVIDUAL = new Property( + "org.eclipse.elk.spacing.individual"); + + /** + * Default value for {@link #SPACING_PORTS_SURROUNDING}. + */ + private static final ElkMargin SPACING_PORTS_SURROUNDING_DEFAULT = new ElkMargin(0); + + /** + * Additional space around the sets of ports on each node side. For each side of a node, + * this option can reserve additional space before and after the ports on each side. For + * example, a top spacing of 20 makes sure that the first port on the western and eastern + * side is 20 units away from the northern border. + */ + public static final IProperty SPACING_PORTS_SURROUNDING = new Property( + "org.eclipse.elk.spacing.portsSurrounding", + SPACING_PORTS_SURROUNDING_DEFAULT, + null, + null); + + /** + * Partition to which the node belongs. This requires Layout Partitioning to be active. Nodes with lower + * partition IDs will appear to the left of nodes with higher partition IDs (assuming a left-to-right layout + * direction). + */ + public static final IProperty PARTITIONING_PARTITION = new Property( + "org.eclipse.elk.partitioning.partition"); + + /** + * Default value for {@link #PARTITIONING_ACTIVATE}. + */ + private static final Boolean PARTITIONING_ACTIVATE_DEFAULT = Boolean.valueOf(false); + + /** + * Whether to activate partitioned layout. This will allow to group nodes through the Layout Partition option. + * a pair of nodes with different partition indices is then placed such that the node with lower index is + * placed to the left of the other node (with left-to-right layout direction). Depending on the layout + * algorithm, this may only be guaranteed to work if all nodes have a layout partition configured, or at least + * if edges that cross partitions are not part of a partition-crossing cycle. + */ + public static final IProperty PARTITIONING_ACTIVATE = new Property( + "org.eclipse.elk.partitioning.activate", + PARTITIONING_ACTIVATE_DEFAULT, + null, + null); + + /** + * Default value for {@link #NODE_LABELS_PADDING}. + */ + private static final ElkPadding NODE_LABELS_PADDING_DEFAULT = new ElkPadding(5); + + /** + * Define padding for node labels that are placed inside of a node. + */ + public static final IProperty NODE_LABELS_PADDING = new Property( + "org.eclipse.elk.nodeLabels.padding", + NODE_LABELS_PADDING_DEFAULT, + null, + null); + + /** + * Default value for {@link #NODE_LABELS_PLACEMENT}. + */ + private static final EnumSet NODE_LABELS_PLACEMENT_DEFAULT = NodeLabelPlacement.fixed(); + + /** + * Hints for where node labels are to be placed; if empty, the node label's position is not + * modified. + */ + public static final IProperty> NODE_LABELS_PLACEMENT = new Property>( + "org.eclipse.elk.nodeLabels.placement", + NODE_LABELS_PLACEMENT_DEFAULT, + null, + null); + + /** + * Default value for {@link #PORT_ALIGNMENT_DEFAULT}. + */ + private static final PortAlignment PORT_ALIGNMENT_DEFAULT_DEFAULT = PortAlignment.DISTRIBUTED; + + /** + * Defines the default port distribution for a node. May be overridden for each side individually. + */ + public static final IProperty PORT_ALIGNMENT_DEFAULT = new Property( + "org.eclipse.elk.portAlignment.default", + PORT_ALIGNMENT_DEFAULT_DEFAULT, + null, + null); + + /** + * Defines how ports on the northern side are placed, overriding the node's general port alignment. + */ + public static final IProperty PORT_ALIGNMENT_NORTH = new Property( + "org.eclipse.elk.portAlignment.north"); + + /** + * Defines how ports on the southern side are placed, overriding the node's general port alignment. + */ + public static final IProperty PORT_ALIGNMENT_SOUTH = new Property( + "org.eclipse.elk.portAlignment.south"); + + /** + * Defines how ports on the western side are placed, overriding the node's general port alignment. + */ + public static final IProperty PORT_ALIGNMENT_WEST = new Property( + "org.eclipse.elk.portAlignment.west"); + + /** + * Defines how ports on the eastern side are placed, overriding the node's general port alignment. + */ + public static final IProperty PORT_ALIGNMENT_EAST = new Property( + "org.eclipse.elk.portAlignment.east"); + + /** + * Default value for {@link #NODE_SIZE_CONSTRAINTS}. + */ + private static final EnumSet NODE_SIZE_CONSTRAINTS_DEFAULT = EnumSet.noneOf(SizeConstraint.class); + + /** + * What should be taken into account when calculating a node's size. Empty size constraints + * specify that a node's size is already fixed and should not be changed. + */ + public static final IProperty> NODE_SIZE_CONSTRAINTS = new Property>( + "org.eclipse.elk.nodeSize.constraints", + NODE_SIZE_CONSTRAINTS_DEFAULT, + null, + null); + + /** + * Default value for {@link #NODE_SIZE_OPTIONS}. + */ + private static final EnumSet NODE_SIZE_OPTIONS_DEFAULT = EnumSet.of(SizeOptions.DEFAULT_MINIMUM_SIZE); + + /** + * Options modifying the behavior of the size constraints set on a node. Each member of the + * set specifies something that should be taken into account when calculating node sizes. + * The empty set corresponds to no further modifications. + */ + public static final IProperty> NODE_SIZE_OPTIONS = new Property>( + "org.eclipse.elk.nodeSize.options", + NODE_SIZE_OPTIONS_DEFAULT, + null, + null); + + /** + * Default value for {@link #NODE_SIZE_MINIMUM}. + */ + private static final KVector NODE_SIZE_MINIMUM_DEFAULT = new KVector(0, 0); + + /** + * The minimal size to which a node can be reduced. + */ + public static final IProperty NODE_SIZE_MINIMUM = new Property( + "org.eclipse.elk.nodeSize.minimum", + NODE_SIZE_MINIMUM_DEFAULT, + null, + null); + + /** + * Default value for {@link #NODE_SIZE_FIXED_GRAPH_SIZE}. + */ + private static final boolean NODE_SIZE_FIXED_GRAPH_SIZE_DEFAULT = false; + + /** + * By default, the fixed layout provider will enlarge a graph until it is large enough to contain + * its children. If this option is set, it won't do so. + */ + public static final IProperty NODE_SIZE_FIXED_GRAPH_SIZE = new Property( + "org.eclipse.elk.nodeSize.fixedGraphSize", + NODE_SIZE_FIXED_GRAPH_SIZE_DEFAULT, + null, + null); + + /** + * Default value for {@link #EDGE_LABELS_PLACEMENT}. + */ + private static final EdgeLabelPlacement EDGE_LABELS_PLACEMENT_DEFAULT = EdgeLabelPlacement.CENTER; + + /** + * Gives a hint on where to put edge labels. + */ + public static final IProperty EDGE_LABELS_PLACEMENT = new Property( + "org.eclipse.elk.edgeLabels.placement", + EDGE_LABELS_PLACEMENT_DEFAULT, + null, + null); + + /** + * Default value for {@link #EDGE_LABELS_INLINE}. + */ + private static final boolean EDGE_LABELS_INLINE_DEFAULT = false; + + /** + * If true, an edge label is placed directly on its edge. May only apply to center edge labels. + * This kind of label placement is only advisable if the label's rendering is such that it is not + * crossed by its edge and thus stays legible. + */ + public static final IProperty EDGE_LABELS_INLINE = new Property( + "org.eclipse.elk.edgeLabels.inline", + EDGE_LABELS_INLINE_DEFAULT, + null, + null); + + /** + * Font name used for a label. + */ + public static final IProperty FONT_NAME = new Property( + "org.eclipse.elk.font.name"); + + /** + * Lower bound value for {@link #FONT_SIZE}. + */ + private static final Comparable FONT_SIZE_LOWER_BOUND = Integer.valueOf(1); + + /** + * Font size used for a label. + */ + public static final IProperty FONT_SIZE = new Property( + "org.eclipse.elk.font.size", + null, + FONT_SIZE_LOWER_BOUND, + null); + + /** + * The offset to the port position where connections shall be attached. + */ + public static final IProperty PORT_ANCHOR = new Property( + "org.eclipse.elk.port.anchor"); + + /** + * The index of a port in the fixed order around a node. The order is assumed as clockwise, + * starting with the leftmost port on the top side. This option must be set if 'Port + * Constraints' is set to FIXED_ORDER and no specific positions are given for the ports. + * Additionally, the option 'Port Side' must be defined in this case. + */ + public static final IProperty PORT_INDEX = new Property( + "org.eclipse.elk.port.index"); + + /** + * Default value for {@link #PORT_SIDE}. + */ + private static final PortSide PORT_SIDE_DEFAULT = PortSide.UNDEFINED; + + /** + * The side of a node on which a port is situated. This option must be set if 'Port + * Constraints' is set to FIXED_SIDE or FIXED_ORDER and no specific positions are given + * for the ports. + */ + public static final IProperty PORT_SIDE = new Property( + "org.eclipse.elk.port.side", + PORT_SIDE_DEFAULT, + null, + null); + + /** + * The offset of ports on the node border. With a positive offset the port is moved outside + * of the node, while with a negative offset the port is moved towards the inside. An offset + * of 0 means that the port is placed directly on the node border, i.e. + * if the port side is north, the port's south border touches the nodes's north border; + * if the port side is east, the port's west border touches the nodes's east border; + * if the port side is south, the port's north border touches the node's south border; + * if the port side is west, the port's east border touches the node's west border. + */ + public static final IProperty PORT_BORDER_OFFSET = new Property( + "org.eclipse.elk.port.borderOffset"); + + /** + * Default value for {@link #PORT_LABELS_PLACEMENT}. + */ + private static final EnumSet PORT_LABELS_PLACEMENT_DEFAULT = PortLabelPlacement.outside(); + + /** + * Decides on a placement method for port labels; if empty, the node label's position is not + * modified. + */ + public static final IProperty> PORT_LABELS_PLACEMENT = new Property>( + "org.eclipse.elk.portLabels.placement", + PORT_LABELS_PLACEMENT_DEFAULT, + null, + null); + + /** + * Default value for {@link #PORT_LABELS_NEXT_TO_PORT_IF_POSSIBLE}. + */ + private static final boolean PORT_LABELS_NEXT_TO_PORT_IF_POSSIBLE_DEFAULT = false; + + /** + * Use 'portLabels.placement': NEXT_TO_PORT_OF_POSSIBLE. + */ + @Deprecated + public static final IProperty PORT_LABELS_NEXT_TO_PORT_IF_POSSIBLE = new Property( + "org.eclipse.elk.portLabels.nextToPortIfPossible", + PORT_LABELS_NEXT_TO_PORT_IF_POSSIBLE_DEFAULT, + null, + null); + + /** + * Default value for {@link #PORT_LABELS_TREAT_AS_GROUP}. + */ + private static final boolean PORT_LABELS_TREAT_AS_GROUP_DEFAULT = true; + + /** + * If this option is true (default), the labels of a port will be treated as a group when + * it comes to centering them next to their port. If this option is false, only the first label will + * be centered next to the port, with the others being placed below. This only applies to labels of + * eastern and western ports and will have no effect if labels are not placed next to their port. + */ + public static final IProperty PORT_LABELS_TREAT_AS_GROUP = new Property( + "org.eclipse.elk.portLabels.treatAsGroup", + PORT_LABELS_TREAT_AS_GROUP_DEFAULT, + null, + null); + + /** + * Default value for {@link #TOPDOWN_SIZE_CATEGORIES}. + */ + private static final int TOPDOWN_SIZE_CATEGORIES_DEFAULT = 3; + + /** + * Lower bound value for {@link #TOPDOWN_SIZE_CATEGORIES}. + */ + private static final Comparable TOPDOWN_SIZE_CATEGORIES_LOWER_BOUND = Integer.valueOf(1); + + /** + * Defines the number of categories to use for the FIXED_INTEGER_RATIO_BOXES size approximator. + */ + public static final IProperty TOPDOWN_SIZE_CATEGORIES = new Property( + "org.eclipse.elk.topdown.sizeCategories", + TOPDOWN_SIZE_CATEGORIES_DEFAULT, + TOPDOWN_SIZE_CATEGORIES_LOWER_BOUND, + null); + + /** + * Default value for {@link #TOPDOWN_SIZE_CATEGORIES_HIERARCHICAL_NODE_WEIGHT}. + */ + private static final int TOPDOWN_SIZE_CATEGORIES_HIERARCHICAL_NODE_WEIGHT_DEFAULT = 4; + + /** + * Lower bound value for {@link #TOPDOWN_SIZE_CATEGORIES_HIERARCHICAL_NODE_WEIGHT}. + */ + private static final Comparable TOPDOWN_SIZE_CATEGORIES_HIERARCHICAL_NODE_WEIGHT_LOWER_BOUND = Integer.valueOf(1); + + /** + * When determining the graph size for the size categorisation, this value determines how many times a node + * containing children is weighted more than a simple node. For example setting this value to four would + * result in a graph containing a simple node and a hierarchical node to be counted as having a size of five. + */ + public static final IProperty TOPDOWN_SIZE_CATEGORIES_HIERARCHICAL_NODE_WEIGHT = new Property( + "org.eclipse.elk.topdown.sizeCategoriesHierarchicalNodeWeight", + TOPDOWN_SIZE_CATEGORIES_HIERARCHICAL_NODE_WEIGHT_DEFAULT, + TOPDOWN_SIZE_CATEGORIES_HIERARCHICAL_NODE_WEIGHT_LOWER_BOUND, + null); + + /** + * Default value for {@link #TOPDOWN_SCALE_FACTOR}. + */ + private static final double TOPDOWN_SCALE_FACTOR_DEFAULT = 1; + + /** + * Lower bound value for {@link #TOPDOWN_SCALE_FACTOR}. + */ + private static final Comparable TOPDOWN_SCALE_FACTOR_LOWER_BOUND = ExclusiveBounds.greaterThan(0); + + /** + * The scaling factor to be applied to the nodes laid out within the node in recursive topdown + * layout. The difference to 'Scale Factor' is that the node itself is not scaled. This value has to be set on + * hierarchical nodes. + */ + public static final IProperty TOPDOWN_SCALE_FACTOR = new Property( + "org.eclipse.elk.topdown.scaleFactor", + TOPDOWN_SCALE_FACTOR_DEFAULT, + TOPDOWN_SCALE_FACTOR_LOWER_BOUND, + null); + + /** + * Default value for {@link #TOPDOWN_SIZE_APPROXIMATOR}. + */ + private static final ITopdownSizeApproximator TOPDOWN_SIZE_APPROXIMATOR_DEFAULT = null; + + /** + * The size approximator to be used to set sizes of hierarchical nodes during topdown layout. The default + * value is null, which results in nodes keeping whatever size is defined for them e.g. through parent + * parallel node or by manually setting the size. + */ + public static final IProperty TOPDOWN_SIZE_APPROXIMATOR = new Property( + "org.eclipse.elk.topdown.sizeApproximator", + TOPDOWN_SIZE_APPROXIMATOR_DEFAULT, + null, + null); + + /** + * Default value for {@link #TOPDOWN_HIERARCHICAL_NODE_WIDTH}. + */ + private static final double TOPDOWN_HIERARCHICAL_NODE_WIDTH_DEFAULT = 150; + + /** + * The fixed size of a hierarchical node when using topdown layout. If this value is set on a parallel + * node it applies to its children, when set on a hierarchical node it applies to the node itself. + */ + public static final IProperty TOPDOWN_HIERARCHICAL_NODE_WIDTH = new Property( + "org.eclipse.elk.topdown.hierarchicalNodeWidth", + TOPDOWN_HIERARCHICAL_NODE_WIDTH_DEFAULT, + null, + null); + + /** + * Default value for {@link #TOPDOWN_HIERARCHICAL_NODE_ASPECT_RATIO}. + */ + private static final double TOPDOWN_HIERARCHICAL_NODE_ASPECT_RATIO_DEFAULT = 1.414; + + /** + * The fixed aspect ratio of a hierarchical node when using topdown layout. Default is 1/sqrt(2). If this + * value is set on a parallel node it applies to its children, when set on a hierarchical node it applies to + * the node itself. + */ + public static final IProperty TOPDOWN_HIERARCHICAL_NODE_ASPECT_RATIO = new Property( + "org.eclipse.elk.topdown.hierarchicalNodeAspectRatio", + TOPDOWN_HIERARCHICAL_NODE_ASPECT_RATIO_DEFAULT, + null, + null); + + /** + * Default value for {@link #TOPDOWN_NODE_TYPE}. + */ + private static final TopdownNodeTypes TOPDOWN_NODE_TYPE_DEFAULT = null; + + /** + * The different node types used for topdown layout. If the node type is set + * to {@link TopdownNodeTypes.PARALLEL_NODE} the algorithm must be set to a {@link TopdownLayoutProvider} such + * as {@link TopdownPacking}. The {@link nodeSize.fixedGraphSize} option is technically only required for + * hierarchical nodes. + */ + public static final IProperty TOPDOWN_NODE_TYPE = new Property( + "org.eclipse.elk.topdown.nodeType", + TOPDOWN_NODE_TYPE_DEFAULT, + null, + null); + + /** + * Default value for {@link #TOPDOWN_SCALE_CAP}. + */ + private static final double TOPDOWN_SCALE_CAP_DEFAULT = 1; + + /** + * Determines the upper limit for the topdown scale factor. The default value is 1.0 which ensures + * that nested children never end up appearing larger than their parents in terms of unit sizes such + * as the font size. If the limit is larger, nodes will fully utilize the available space, but it is + * counteriniuitive for inner nodes to have a larger scale than outer nodes. + */ + public static final IProperty TOPDOWN_SCALE_CAP = new Property( + "org.eclipse.elk.topdown.scaleCap", + TOPDOWN_SCALE_CAP_DEFAULT, + null, + null); + + /** + * Default value for {@link #INSIDE_SELF_LOOPS_ACTIVATE}. + */ + private static final boolean INSIDE_SELF_LOOPS_ACTIVATE_DEFAULT = false; + + /** + * Whether this node allows to route self loops inside of it instead of around it. If set to true, + * this will make the node a compound node if it isn't already, and will require the layout algorithm + * to support compound nodes with hierarchical ports. + */ + public static final IProperty INSIDE_SELF_LOOPS_ACTIVATE = new Property( + "org.eclipse.elk.insideSelfLoops.activate", + INSIDE_SELF_LOOPS_ACTIVATE_DEFAULT, + null, + null); + + /** + * Default value for {@link #INSIDE_SELF_LOOPS_YO}. + */ + private static final boolean INSIDE_SELF_LOOPS_YO_DEFAULT = false; + + /** + * Whether a self loop should be routed inside a node instead of around that node. + */ + public static final IProperty INSIDE_SELF_LOOPS_YO = new Property( + "org.eclipse.elk.insideSelfLoops.yo", + INSIDE_SELF_LOOPS_YO_DEFAULT, + null, + null); + + /** + * Default value for {@link #EDGE_THICKNESS}. + */ + private static final double EDGE_THICKNESS_DEFAULT = 1; + + /** + * The thickness of an edge. This is a hint on the line width used to draw an edge, possibly + * requiring more space to be reserved for it. + */ + public static final IProperty EDGE_THICKNESS = new Property( + "org.eclipse.elk.edge.thickness", + EDGE_THICKNESS_DEFAULT, + null, + null); + + /** + * Default value for {@link #EDGE_TYPE}. + */ + private static final EdgeType EDGE_TYPE_DEFAULT = EdgeType.NONE; + + /** + * The type of an edge. This is usually used for UML class diagrams, where associations must + * be handled differently from generalizations. + */ + public static final IProperty EDGE_TYPE = new Property( + "org.eclipse.elk.edge.type", + EDGE_TYPE_DEFAULT, + null, + null); + + /** + * Required value for dependency between {@link #PARTITIONING_PARTITION} and {@link #PARTITIONING_ACTIVATE}. + */ + private static final Boolean PARTITIONING_PARTITION_DEP_PARTITIONING_ACTIVATE_0 = Boolean.valueOf(true); + + /** + * Required value for dependency between {@link #TOPDOWN_SIZE_CATEGORIES} and {@link #TOPDOWN_SIZE_APPROXIMATOR}. + */ + private static final ITopdownSizeApproximator TOPDOWN_SIZE_CATEGORIES_DEP_TOPDOWN_SIZE_APPROXIMATOR_0 = TopdownSizeApproximator.FIXED_INTEGER_RATIO_BOXES; + + /** + * Required value for dependency between {@link #TOPDOWN_SCALE_FACTOR} and {@link #TOPDOWN_NODE_TYPE}. + */ + private static final TopdownNodeTypes TOPDOWN_SCALE_FACTOR_DEP_TOPDOWN_NODE_TYPE_0 = TopdownNodeTypes.HIERARCHICAL_NODE; + + /** + * Required value for dependency between {@link #TOPDOWN_SIZE_APPROXIMATOR} and {@link #TOPDOWN_NODE_TYPE}. + */ + private static final TopdownNodeTypes TOPDOWN_SIZE_APPROXIMATOR_DEP_TOPDOWN_NODE_TYPE_0 = TopdownNodeTypes.HIERARCHICAL_NODE; + + /** + * Required value for dependency between {@link #TOPDOWN_SCALE_CAP} and {@link #TOPDOWN_NODE_TYPE}. + */ + private static final TopdownNodeTypes TOPDOWN_SCALE_CAP_DEP_TOPDOWN_NODE_TYPE_0 = TopdownNodeTypes.HIERARCHICAL_NODE; + + public void apply(final org.eclipse.elk.core.data.ILayoutMetaDataProvider.Registry registry) { + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.algorithm") + .group("") + .name("Layout Algorithm") + .description("Select a specific layout algorithm.") + .type(LayoutOptionData.Type.STRING) + .optionClass(String.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.resolvedAlgorithm") + .group("") + .name("Resolved Layout Algorithm") + .description("Meta data associated with the selected algorithm.") + .type(LayoutOptionData.Type.OBJECT) + .optionClass(LayoutAlgorithmData.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.HIDDEN) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.alignment") + .group("") + .name("Alignment") + .description("Alignment of the selected node relative to other nodes; the exact meaning depends on the used algorithm.") + .defaultValue(ALIGNMENT_DEFAULT) + .type(LayoutOptionData.Type.ENUM) + .optionClass(Alignment.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.aspectRatio") + .group("") + .name("Aspect Ratio") + .description("The desired aspect ratio of the drawing, that is the quotient of width by height.") + .lowerBound(ASPECT_RATIO_LOWER_BOUND) + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.bendPoints") + .group("") + .name("Bend Points") + .description("A fixed list of bend points for the edge. This is used by the \'Fixed Layout\' algorithm to specify a pre-defined routing for an edge. The vector chain must include the source point, any bend points, and the target point, so it must have at least two points.") + .type(LayoutOptionData.Type.OBJECT) + .optionClass(KVectorChain.class) + .targets(EnumSet.of(LayoutOptionData.Target.EDGES)) + .visibility(LayoutOptionData.Visibility.HIDDEN) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.contentAlignment") + .group("") + .name("Content Alignment") + .description("Specifies how the content of a node are aligned. Each node can individually control the alignment of its contents. I.e. if a node should be aligned top left in its parent node, the parent node should specify that option.") + .defaultValue(CONTENT_ALIGNMENT_DEFAULT) + .type(LayoutOptionData.Type.ENUMSET) + .optionClass(ContentAlignment.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.debugMode") + .group("") + .name("Debug Mode") + .description("Whether additional debug information shall be generated.") + .defaultValue(DEBUG_MODE_DEFAULT) + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.direction") + .group("") + .name("Direction") + .description("Overall direction of edges: horizontal (right / left) or vertical (down / up).") + .defaultValue(DIRECTION_DEFAULT) + .type(LayoutOptionData.Type.ENUM) + .optionClass(Direction.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.edgeRouting") + .group("") + .name("Edge Routing") + .description("What kind of edge routing style should be applied for the content of a parent node. Algorithms may also set this option to single edges in order to mark them as splines. The bend point list of edges with this option set to SPLINES must be interpreted as control points for a piecewise cubic spline.") + .defaultValue(EDGE_ROUTING_DEFAULT) + .type(LayoutOptionData.Type.ENUM) + .optionClass(EdgeRouting.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.expandNodes") + .group("") + .name("Expand Nodes") + .description("If active, nodes are expanded to fill the area of their parent.") + .defaultValue(EXPAND_NODES_DEFAULT) + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.hierarchyHandling") + .group("") + .name("Hierarchy Handling") + .description("Determines whether separate layout runs are triggered for different compound nodes in a hierarchical graph. Setting a node\'s hierarchy handling to `INCLUDE_CHILDREN` will lay out that node and all of its descendants in a single layout run, until a descendant is encountered which has its hierarchy handling set to `SEPARATE_CHILDREN`. In general, `SEPARATE_CHILDREN` will ensure that a new layout run is triggered for a node with that setting. Including multiple levels of hierarchy in a single layout run may allow cross-hierarchical edges to be laid out properly. If the root node is set to `INHERIT` (or not set at all), the default behavior is `SEPARATE_CHILDREN`.") + .defaultValue(HIERARCHY_HANDLING_DEFAULT) + .type(LayoutOptionData.Type.ENUM) + .optionClass(HierarchyHandling.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS, LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.padding") + .group("") + .name("Padding") + .description("The padding to be left to a parent element\'s border when placing child elements. This can also serve as an output option of a layout algorithm if node size calculation is setup appropriately.") + .defaultValue(PADDING_DEFAULT) + .type(LayoutOptionData.Type.OBJECT) + .optionClass(ElkPadding.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS, LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.interactive") + .group("") + .name("Interactive") + .description("Whether the algorithm should be run in interactive mode for the content of a parent node. What this means exactly depends on how the specific algorithm interprets this option. Usually in the interactive mode algorithms try to modify the current layout as little as possible.") + .defaultValue(INTERACTIVE_DEFAULT) + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.interactiveLayout") + .group("") + .name("interactive Layout") + .description("Whether the graph should be changeable interactively and by setting constraints") + .defaultValue(INTERACTIVE_LAYOUT_DEFAULT) + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.omitNodeMicroLayout") + .group("") + .name("Omit Node Micro Layout") + .description("Node micro layout comprises the computation of node dimensions (if requested), the placement of ports and their labels, and the placement of node labels. The functionality is implemented independent of any specific layout algorithm and shouldn\'t have any negative impact on the layout algorithm\'s performance itself. Yet, if any unforeseen behavior occurs, this option allows to deactivate the micro layout.") + .defaultValue(OMIT_NODE_MICRO_LAYOUT_DEFAULT) + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.portConstraints") + .group("") + .name("Port Constraints") + .description("Defines constraints of the position of the ports of a node.") + .defaultValue(PORT_CONSTRAINTS_DEFAULT) + .type(LayoutOptionData.Type.ENUM) + .optionClass(PortConstraints.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.position") + .group("") + .name("Position") + .description("The position of a node, port, or label. This is used by the \'Fixed Layout\' algorithm to specify a pre-defined position.") + .type(LayoutOptionData.Type.OBJECT) + .optionClass(KVector.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES, LayoutOptionData.Target.PORTS, LayoutOptionData.Target.LABELS)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.priority") + .group("") + .name("Priority") + .description("Defines the priority of an object; its meaning depends on the specific layout algorithm and the context where it is used.") + .type(LayoutOptionData.Type.INT) + .optionClass(Integer.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES, LayoutOptionData.Target.EDGES)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.randomSeed") + .group("") + .name("Randomization Seed") + .description("Seed used for pseudo-random number generators to control the layout algorithm. If the value is 0, the seed shall be determined pseudo-randomly (e.g. from the system time).") + .type(LayoutOptionData.Type.INT) + .optionClass(Integer.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.separateConnectedComponents") + .group("") + .name("Separate Connected Components") + .description("Whether each connected component should be processed separately.") + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.junctionPoints") + .group("") + .name("Junction Points") + .description("This option is not used as option, but as output of the layout algorithms. It is attached to edges and determines the points where junction symbols should be drawn in order to represent hyperedges with orthogonal routing. Whether such points are computed depends on the chosen layout algorithm and edge routing style. The points are put into the vector chain with no specific order.") + .defaultValue(JUNCTION_POINTS_DEFAULT) + .type(LayoutOptionData.Type.OBJECT) + .optionClass(KVectorChain.class) + .targets(EnumSet.of(LayoutOptionData.Target.EDGES)) + .visibility(LayoutOptionData.Visibility.HIDDEN) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.commentBox") + .group("") + .name("Comment Box") + .description("Whether the node should be regarded as a comment box instead of a regular node. In that case its placement should be similar to how labels are handled. Any edges incident to a comment box specify to which graph elements the comment is related.") + .defaultValue(COMMENT_BOX_DEFAULT) + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.hypernode") + .group("") + .name("Hypernode") + .description("Whether the node should be handled as a hypernode.") + .defaultValue(HYPERNODE_DEFAULT) + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.HIDDEN) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.labelManager") + .group("") + .name("Label Manager") + .description("Label managers can shorten labels upon a layout algorithm\'s request.") + .type(LayoutOptionData.Type.OBJECT) + .optionClass(ILabelManager.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS, LayoutOptionData.Target.LABELS)) + .visibility(LayoutOptionData.Visibility.HIDDEN) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.softwrappingFuzziness") + .group("") + .name("Softwrapping Fuzziness") + .description("Determines the amount of fuzziness to be used when performing softwrapping on labels. The value expresses the percent of overhang that is permitted for each line. If the next line would take up less space than this threshold, it is appended to the current line instead of being placed in a new line.") + .defaultValue(SOFTWRAPPING_FUZZINESS_DEFAULT) + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.LABELS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.margins") + .group("") + .name("Margins") + .description("Margins define additional space around the actual bounds of a graph element. For instance, ports or labels being placed on the outside of a node\'s border might introduce such a margin. The margin is used to guarantee non-overlap of other graph elements with those ports or labels.") + .defaultValue(MARGINS_DEFAULT) + .type(LayoutOptionData.Type.OBJECT) + .optionClass(ElkMargin.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.noLayout") + .group("") + .name("No Layout") + .description("No layout is done for the associated element. This is used to mark parts of a diagram to avoid their inclusion in the layout graph, or to mark parts of the layout graph to prevent layout engines from processing them. If you wish to exclude the contents of a compound node from automatic layout, while the node itself is still considered on its own layer, use the \'Fixed Layout\' algorithm for that node.") + .defaultValue(NO_LAYOUT_DEFAULT) + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES, LayoutOptionData.Target.EDGES, LayoutOptionData.Target.PORTS, LayoutOptionData.Target.LABELS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.scaleFactor") + .group("") + .name("Scale Factor") + .description("The scaling factor to be applied to the corresponding node in recursive layout. It causes the corresponding node\'s size to be adjusted, and its ports and labels to be sized and placed accordingly after the layout of that node has been determined (and before the node itself and its siblings are arranged). The scaling is not reverted afterwards, so the resulting layout graph contains the adjusted size and position data. This option is currently not supported if \'Layout Hierarchy\' is set.") + .defaultValue(SCALE_FACTOR_DEFAULT) + .lowerBound(SCALE_FACTOR_LOWER_BOUND) + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.HIDDEN) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.childAreaWidth") + .group("") + .name("Child Area Width") + .description("The width of the area occupied by the laid out children of a node.") + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.HIDDEN) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.childAreaHeight") + .group("") + .name("Child Area Height") + .description("The height of the area occupied by the laid out children of a node.") + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.HIDDEN) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.topdownLayout") + .group("") + .name("Topdown Layout") + .description("Turns topdown layout on and off. If this option is enabled, hierarchical layout will be computed first for the root node and then for its children recursively. Layouts are then scaled down to fit the area provided by their parents. Graphs must follow a certain structure for topdown layout to work properly. {@link TopdownNodeTypes.PARALLEL_NODE} nodes must have children of type {@link TopdownNodeTypes.HIERARCHICAL_NODE} and must define {@link topdown.hierarchicalNodeWidth} and {@link topdown.hierarchicalNodeAspectRatio} for their children. Furthermore they need to be laid out using an algorithm that is a {@link TopdownLayoutProvider}. Hierarchical nodes can also be parents of other hierarchical nodes and can optionally use a {@link TopdownSizeApproximator} to dynamically set sizes during topdown layout. In this case {@link topdown.hierarchicalNodeWidth} and {@link topdown.hierarchicalNodeAspectRatio} should be set on the node itself rather than the parent. The values are then used by the size approximator as base values. Hierarchical nodes require the layout option {@link nodeSize.fixedGraphSize} to be true to prevent the algorithm used there from resizing the hierarchical node. This option is not supported if \'Hierarchy Handling\' is set to \'INCLUDE_CHILDREN\'") + .defaultValue(TOPDOWN_LAYOUT_DEFAULT) + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.addDependency( + "org.eclipse.elk.topdownLayout", + "org.eclipse.elk.topdown.nodeType", + null + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.animate") + .group("") + .name("Animate") + .description("Whether the shift from the old layout to the new computed layout shall be animated.") + .defaultValue(ANIMATE_DEFAULT) + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.HIDDEN) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.animTimeFactor") + .group("") + .name("Animation Time Factor") + .description("Factor for computation of animation time. The higher the value, the longer the animation time. If the value is 0, the resulting time is always equal to the minimum defined by \'Minimal Animation Time\'.") + .defaultValue(ANIM_TIME_FACTOR_DEFAULT) + .lowerBound(ANIM_TIME_FACTOR_LOWER_BOUND) + .type(LayoutOptionData.Type.INT) + .optionClass(Integer.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.HIDDEN) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.layoutAncestors") + .group("") + .name("Layout Ancestors") + .description("Whether the hierarchy levels on the path from the selected element to the root of the diagram shall be included in the layout process.") + .defaultValue(LAYOUT_ANCESTORS_DEFAULT) + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.HIDDEN) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.maxAnimTime") + .group("") + .name("Maximal Animation Time") + .description("The maximal time for animations, in milliseconds.") + .defaultValue(MAX_ANIM_TIME_DEFAULT) + .lowerBound(MAX_ANIM_TIME_LOWER_BOUND) + .type(LayoutOptionData.Type.INT) + .optionClass(Integer.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.HIDDEN) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.minAnimTime") + .group("") + .name("Minimal Animation Time") + .description("The minimal time for animations, in milliseconds.") + .defaultValue(MIN_ANIM_TIME_DEFAULT) + .lowerBound(MIN_ANIM_TIME_LOWER_BOUND) + .type(LayoutOptionData.Type.INT) + .optionClass(Integer.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.HIDDEN) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.progressBar") + .group("") + .name("Progress Bar") + .description("Whether a progress bar shall be displayed during layout computations.") + .defaultValue(PROGRESS_BAR_DEFAULT) + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.HIDDEN) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.validateGraph") + .group("") + .name("Validate Graph") + .description("Whether the graph shall be validated before any layout algorithm is applied. If this option is enabled and at least one error is found, the layout process is aborted and a message is shown to the user.") + .defaultValue(VALIDATE_GRAPH_DEFAULT) + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.HIDDEN) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.validateOptions") + .group("") + .name("Validate Options") + .description("Whether layout options shall be validated before any layout algorithm is applied. If this option is enabled and at least one error is found, the layout process is aborted and a message is shown to the user.") + .defaultValue(VALIDATE_OPTIONS_DEFAULT) + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.HIDDEN) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.zoomToFit") + .group("") + .name("Zoom to Fit") + .description("Whether the zoom level shall be set to view the whole diagram after layout.") + .defaultValue(ZOOM_TO_FIT_DEFAULT) + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.HIDDEN) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.box.packingMode") + .group("box") + .name("Box Layout Mode") + .description("Configures the packing mode used by the {@link BoxLayoutProvider}. If SIMPLE is not required (neither priorities are used nor the interactive mode), GROUP_DEC can improve the packing and decrease the area. GROUP_MIXED and GROUP_INC may, in very specific scenarios, work better.") + .defaultValue(BOX_PACKING_MODE_DEFAULT) + .type(LayoutOptionData.Type.ENUM) + .optionClass(BoxLayoutProvider.PackingMode.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.json.shapeCoords") + .group("json") + .name("Shape Coords") + .description("For layouts transferred into JSON graphs, specify the coordinate system to be used for nodes, ports, and labels of nodes and ports.") + .defaultValue(JSON_SHAPE_COORDS_DEFAULT) + .type(LayoutOptionData.Type.ENUM) + .optionClass(ShapeCoords.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.json.edgeCoords") + .group("json") + .name("Edge Coords") + .description("For layouts transferred into JSON graphs, specify the coordinate system to be used for edge route points and edge labels.") + .defaultValue(JSON_EDGE_COORDS_DEFAULT) + .type(LayoutOptionData.Type.ENUM) + .optionClass(EdgeCoords.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.spacing.commentComment") + .group("spacing") + .name("Comment Comment Spacing") + .description("Spacing to be preserved between a comment box and other comment boxes connected to the same node. The space left between comment boxes of different nodes is controlled by the node-node spacing.") + .defaultValue(SPACING_COMMENT_COMMENT_DEFAULT) + .lowerBound(SPACING_COMMENT_COMMENT_LOWER_BOUND) + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.spacing.commentNode") + .group("spacing") + .name("Comment Node Spacing") + .description("Spacing to be preserved between a node and its connected comment boxes. The space left between a node and the comments of another node is controlled by the node-node spacing.") + .defaultValue(SPACING_COMMENT_NODE_DEFAULT) + .lowerBound(SPACING_COMMENT_NODE_LOWER_BOUND) + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.spacing.componentComponent") + .group("spacing") + .name("Components Spacing") + .description("Spacing to be preserved between pairs of connected components. This option is only relevant if \'separateConnectedComponents\' is activated.") + .defaultValue(SPACING_COMPONENT_COMPONENT_DEFAULT) + .lowerBound(SPACING_COMPONENT_COMPONENT_LOWER_BOUND) + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.spacing.edgeEdge") + .group("spacing") + .name("Edge Spacing") + .description("Spacing to be preserved between any two edges. Note that while this can somewhat easily be satisfied for the segments of orthogonally drawn edges, it is harder for general polylines or splines.") + .defaultValue(SPACING_EDGE_EDGE_DEFAULT) + .lowerBound(SPACING_EDGE_EDGE_LOWER_BOUND) + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.spacing.edgeLabel") + .group("spacing") + .name("Edge Label Spacing") + .description("The minimal distance to be preserved between a label and the edge it is associated with. Note that the placement of a label is influenced by the \'edgelabels.placement\' option.") + .defaultValue(SPACING_EDGE_LABEL_DEFAULT) + .lowerBound(SPACING_EDGE_LABEL_LOWER_BOUND) + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.spacing.edgeNode") + .group("spacing") + .name("Edge Node Spacing") + .description("Spacing to be preserved between nodes and edges.") + .defaultValue(SPACING_EDGE_NODE_DEFAULT) + .lowerBound(SPACING_EDGE_NODE_LOWER_BOUND) + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.spacing.labelLabel") + .group("spacing") + .name("Label Spacing") + .description("Determines the amount of space to be left between two labels of the same graph element.") + .defaultValue(SPACING_LABEL_LABEL_DEFAULT) + .lowerBound(SPACING_LABEL_LABEL_LOWER_BOUND) + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.spacing.labelNode") + .group("spacing") + .name("Label Node Spacing") + .description("Spacing to be preserved between labels and the border of node they are associated with. Note that the placement of a label is influenced by the \'nodelabels.placement\' option.") + .defaultValue(SPACING_LABEL_NODE_DEFAULT) + .lowerBound(SPACING_LABEL_NODE_LOWER_BOUND) + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.spacing.labelPortHorizontal") + .group("spacing") + .name("Horizontal spacing between Label and Port") + .description("Horizontal spacing to be preserved between labels and the ports they are associated with. Note that the placement of a label is influenced by the \'portlabels.placement\' option.") + .defaultValue(SPACING_LABEL_PORT_HORIZONTAL_DEFAULT) + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.spacing.labelPortVertical") + .group("spacing") + .name("Vertical spacing between Label and Port") + .description("Vertical spacing to be preserved between labels and the ports they are associated with. Note that the placement of a label is influenced by the \'portlabels.placement\' option.") + .defaultValue(SPACING_LABEL_PORT_VERTICAL_DEFAULT) + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.spacing.nodeNode") + .group("spacing") + .name("Node Spacing") + .description("The minimal distance to be preserved between each two nodes.") + .defaultValue(SPACING_NODE_NODE_DEFAULT) + .lowerBound(SPACING_NODE_NODE_LOWER_BOUND) + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.spacing.nodeSelfLoop") + .group("spacing") + .name("Node Self Loop Spacing") + .description("Spacing to be preserved between a node and its self loops.") + .defaultValue(SPACING_NODE_SELF_LOOP_DEFAULT) + .lowerBound(SPACING_NODE_SELF_LOOP_LOWER_BOUND) + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.spacing.portPort") + .group("spacing") + .name("Port Spacing") + .description("Spacing between pairs of ports of the same node.") + .defaultValue(SPACING_PORT_PORT_DEFAULT) + .lowerBound(SPACING_PORT_PORT_LOWER_BOUND) + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS, LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.spacing.individual") + .group("spacing") + .name("Individual Spacing") + .description("Allows to specify individual spacing values for graph elements that shall be different from the value specified for the element\'s parent.") + .type(LayoutOptionData.Type.OBJECT) + .optionClass(IndividualSpacings.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES, LayoutOptionData.Target.EDGES, LayoutOptionData.Target.PORTS, LayoutOptionData.Target.LABELS)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.spacing.portsSurrounding") + .group("spacing") + .name("Additional Port Space") + .description("Additional space around the sets of ports on each node side. For each side of a node, this option can reserve additional space before and after the ports on each side. For example, a top spacing of 20 makes sure that the first port on the western and eastern side is 20 units away from the northern border.") + .defaultValue(SPACING_PORTS_SURROUNDING_DEFAULT) + .type(LayoutOptionData.Type.OBJECT) + .optionClass(ElkMargin.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.partitioning.partition") + .group("partitioning") + .name("Layout Partition") + .description("Partition to which the node belongs. This requires Layout Partitioning to be active. Nodes with lower partition IDs will appear to the left of nodes with higher partition IDs (assuming a left-to-right layout direction).") + .type(LayoutOptionData.Type.INT) + .optionClass(Integer.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS, LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.addDependency( + "org.eclipse.elk.partitioning.partition", + "org.eclipse.elk.partitioning.activate", + PARTITIONING_PARTITION_DEP_PARTITIONING_ACTIVATE_0 + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.partitioning.activate") + .group("partitioning") + .name("Layout Partitioning") + .description("Whether to activate partitioned layout. This will allow to group nodes through the Layout Partition option. a pair of nodes with different partition indices is then placed such that the node with lower index is placed to the left of the other node (with left-to-right layout direction). Depending on the layout algorithm, this may only be guaranteed to work if all nodes have a layout partition configured, or at least if edges that cross partitions are not part of a partition-crossing cycle.") + .defaultValue(PARTITIONING_ACTIVATE_DEFAULT) + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.nodeLabels.padding") + .group("nodeLabels") + .name("Node Label Padding") + .description("Define padding for node labels that are placed inside of a node.") + .defaultValue(NODE_LABELS_PADDING_DEFAULT) + .type(LayoutOptionData.Type.OBJECT) + .optionClass(ElkPadding.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.nodeLabels.placement") + .group("nodeLabels") + .name("Node Label Placement") + .description("Hints for where node labels are to be placed; if empty, the node label\'s position is not modified.") + .defaultValue(NODE_LABELS_PLACEMENT_DEFAULT) + .type(LayoutOptionData.Type.ENUMSET) + .optionClass(NodeLabelPlacement.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES, LayoutOptionData.Target.LABELS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.portAlignment.default") + .group("portAlignment") + .name("Port Alignment") + .description("Defines the default port distribution for a node. May be overridden for each side individually.") + .defaultValue(PORT_ALIGNMENT_DEFAULT_DEFAULT) + .type(LayoutOptionData.Type.ENUM) + .optionClass(PortAlignment.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.portAlignment.north") + .group("portAlignment") + .name("Port Alignment (North)") + .description("Defines how ports on the northern side are placed, overriding the node\'s general port alignment.") + .type(LayoutOptionData.Type.ENUM) + .optionClass(PortAlignment.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.portAlignment.south") + .group("portAlignment") + .name("Port Alignment (South)") + .description("Defines how ports on the southern side are placed, overriding the node\'s general port alignment.") + .type(LayoutOptionData.Type.ENUM) + .optionClass(PortAlignment.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.portAlignment.west") + .group("portAlignment") + .name("Port Alignment (West)") + .description("Defines how ports on the western side are placed, overriding the node\'s general port alignment.") + .type(LayoutOptionData.Type.ENUM) + .optionClass(PortAlignment.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.portAlignment.east") + .group("portAlignment") + .name("Port Alignment (East)") + .description("Defines how ports on the eastern side are placed, overriding the node\'s general port alignment.") + .type(LayoutOptionData.Type.ENUM) + .optionClass(PortAlignment.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.nodeSize.constraints") + .group("nodeSize") + .name("Node Size Constraints") + .description("What should be taken into account when calculating a node\'s size. Empty size constraints specify that a node\'s size is already fixed and should not be changed.") + .defaultValue(NODE_SIZE_CONSTRAINTS_DEFAULT) + .type(LayoutOptionData.Type.ENUMSET) + .optionClass(SizeConstraint.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.nodeSize.options") + .group("nodeSize") + .name("Node Size Options") + .description("Options modifying the behavior of the size constraints set on a node. Each member of the set specifies something that should be taken into account when calculating node sizes. The empty set corresponds to no further modifications.") + .defaultValue(NODE_SIZE_OPTIONS_DEFAULT) + .type(LayoutOptionData.Type.ENUMSET) + .optionClass(SizeOptions.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.nodeSize.minimum") + .group("nodeSize") + .name("Node Size Minimum") + .description("The minimal size to which a node can be reduced.") + .defaultValue(NODE_SIZE_MINIMUM_DEFAULT) + .type(LayoutOptionData.Type.OBJECT) + .optionClass(KVector.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.nodeSize.fixedGraphSize") + .group("nodeSize") + .name("Fixed Graph Size") + .description("By default, the fixed layout provider will enlarge a graph until it is large enough to contain its children. If this option is set, it won\'t do so.") + .defaultValue(NODE_SIZE_FIXED_GRAPH_SIZE_DEFAULT) + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.edgeLabels.placement") + .group("edgeLabels") + .name("Edge Label Placement") + .description("Gives a hint on where to put edge labels.") + .defaultValue(EDGE_LABELS_PLACEMENT_DEFAULT) + .type(LayoutOptionData.Type.ENUM) + .optionClass(EdgeLabelPlacement.class) + .targets(EnumSet.of(LayoutOptionData.Target.LABELS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.edgeLabels.inline") + .group("edgeLabels") + .name("Inline Edge Labels") + .description("If true, an edge label is placed directly on its edge. May only apply to center edge labels. This kind of label placement is only advisable if the label\'s rendering is such that it is not crossed by its edge and thus stays legible.") + .defaultValue(EDGE_LABELS_INLINE_DEFAULT) + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.LABELS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.font.name") + .group("font") + .name("Font Name") + .description("Font name used for a label.") + .type(LayoutOptionData.Type.STRING) + .optionClass(String.class) + .targets(EnumSet.of(LayoutOptionData.Target.LABELS)) + .visibility(LayoutOptionData.Visibility.HIDDEN) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.font.size") + .group("font") + .name("Font Size") + .description("Font size used for a label.") + .lowerBound(FONT_SIZE_LOWER_BOUND) + .type(LayoutOptionData.Type.INT) + .optionClass(Integer.class) + .targets(EnumSet.of(LayoutOptionData.Target.LABELS)) + .visibility(LayoutOptionData.Visibility.HIDDEN) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.port.anchor") + .group("port") + .name("Port Anchor Offset") + .description("The offset to the port position where connections shall be attached.") + .type(LayoutOptionData.Type.OBJECT) + .optionClass(KVector.class) + .targets(EnumSet.of(LayoutOptionData.Target.PORTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.port.index") + .group("port") + .name("Port Index") + .description("The index of a port in the fixed order around a node. The order is assumed as clockwise, starting with the leftmost port on the top side. This option must be set if \'Port Constraints\' is set to FIXED_ORDER and no specific positions are given for the ports. Additionally, the option \'Port Side\' must be defined in this case.") + .type(LayoutOptionData.Type.INT) + .optionClass(Integer.class) + .targets(EnumSet.of(LayoutOptionData.Target.PORTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.port.side") + .group("port") + .name("Port Side") + .description("The side of a node on which a port is situated. This option must be set if \'Port Constraints\' is set to FIXED_SIDE or FIXED_ORDER and no specific positions are given for the ports.") + .defaultValue(PORT_SIDE_DEFAULT) + .type(LayoutOptionData.Type.ENUM) + .optionClass(PortSide.class) + .targets(EnumSet.of(LayoutOptionData.Target.PORTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.port.borderOffset") + .group("port") + .name("Port Border Offset") + .description("The offset of ports on the node border. With a positive offset the port is moved outside of the node, while with a negative offset the port is moved towards the inside. An offset of 0 means that the port is placed directly on the node border, i.e. if the port side is north, the port\'s south border touches the nodes\'s north border; if the port side is east, the port\'s west border touches the nodes\'s east border; if the port side is south, the port\'s north border touches the node\'s south border; if the port side is west, the port\'s east border touches the node\'s west border.") + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.PORTS)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.portLabels.placement") + .group("portLabels") + .name("Port Label Placement") + .description("Decides on a placement method for port labels; if empty, the node label\'s position is not modified.") + .defaultValue(PORT_LABELS_PLACEMENT_DEFAULT) + .type(LayoutOptionData.Type.ENUMSET) + .optionClass(PortLabelPlacement.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.portLabels.nextToPortIfPossible") + .group("portLabels") + .name("Port Labels Next to Port") + .description("Use \'portLabels.placement\': NEXT_TO_PORT_OF_POSSIBLE.") + .defaultValue(PORT_LABELS_NEXT_TO_PORT_IF_POSSIBLE_DEFAULT) + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.portLabels.treatAsGroup") + .group("portLabels") + .name("Treat Port Labels as Group") + .description("If this option is true (default), the labels of a port will be treated as a group when it comes to centering them next to their port. If this option is false, only the first label will be centered next to the port, with the others being placed below. This only applies to labels of eastern and western ports and will have no effect if labels are not placed next to their port.") + .defaultValue(PORT_LABELS_TREAT_AS_GROUP_DEFAULT) + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.VISIBLE) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.topdown.sizeCategories") + .group("topdown") + .name("Number of size categories") + .description("Defines the number of categories to use for the FIXED_INTEGER_RATIO_BOXES size approximator.") + .defaultValue(TOPDOWN_SIZE_CATEGORIES_DEFAULT) + .lowerBound(TOPDOWN_SIZE_CATEGORIES_LOWER_BOUND) + .type(LayoutOptionData.Type.INT) + .optionClass(Integer.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.addDependency( + "org.eclipse.elk.topdown.sizeCategories", + "org.eclipse.elk.topdown.sizeApproximator", + TOPDOWN_SIZE_CATEGORIES_DEP_TOPDOWN_SIZE_APPROXIMATOR_0 + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.topdown.sizeCategoriesHierarchicalNodeWeight") + .group("topdown") + .name("Weight of a node containing children for determining the graph size") + .description("When determining the graph size for the size categorisation, this value determines how many times a node containing children is weighted more than a simple node. For example setting this value to four would result in a graph containing a simple node and a hierarchical node to be counted as having a size of five.") + .defaultValue(TOPDOWN_SIZE_CATEGORIES_HIERARCHICAL_NODE_WEIGHT_DEFAULT) + .lowerBound(TOPDOWN_SIZE_CATEGORIES_HIERARCHICAL_NODE_WEIGHT_LOWER_BOUND) + .type(LayoutOptionData.Type.INT) + .optionClass(Integer.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.addDependency( + "org.eclipse.elk.topdown.sizeCategoriesHierarchicalNodeWeight", + "org.eclipse.elk.topdown.sizeCategories", + null + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.topdown.scaleFactor") + .group("topdown") + .name("Topdown Scale Factor") + .description("The scaling factor to be applied to the nodes laid out within the node in recursive topdown layout. The difference to \'Scale Factor\' is that the node itself is not scaled. This value has to be set on hierarchical nodes.") + .defaultValue(TOPDOWN_SCALE_FACTOR_DEFAULT) + .lowerBound(TOPDOWN_SCALE_FACTOR_LOWER_BOUND) + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.HIDDEN) + .create() + ); + registry.addDependency( + "org.eclipse.elk.topdown.scaleFactor", + "org.eclipse.elk.topdown.nodeType", + TOPDOWN_SCALE_FACTOR_DEP_TOPDOWN_NODE_TYPE_0 + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.topdown.sizeApproximator") + .group("topdown") + .name("Topdown Size Approximator") + .description("The size approximator to be used to set sizes of hierarchical nodes during topdown layout. The default value is null, which results in nodes keeping whatever size is defined for them e.g. through parent parallel node or by manually setting the size.") + .defaultValue(TOPDOWN_SIZE_APPROXIMATOR_DEFAULT) + .type(LayoutOptionData.Type.OBJECT) + .optionClass(ITopdownSizeApproximator.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.addDependency( + "org.eclipse.elk.topdown.sizeApproximator", + "org.eclipse.elk.topdown.nodeType", + TOPDOWN_SIZE_APPROXIMATOR_DEP_TOPDOWN_NODE_TYPE_0 + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.topdown.hierarchicalNodeWidth") + .group("topdown") + .name("Topdown Hierarchical Node Width") + .description("The fixed size of a hierarchical node when using topdown layout. If this value is set on a parallel node it applies to its children, when set on a hierarchical node it applies to the node itself.") + .defaultValue(TOPDOWN_HIERARCHICAL_NODE_WIDTH_DEFAULT) + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS, LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.addDependency( + "org.eclipse.elk.topdown.hierarchicalNodeWidth", + "org.eclipse.elk.topdown.nodeType", + null + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.topdown.hierarchicalNodeAspectRatio") + .group("topdown") + .name("Topdown Hierarchical Node Aspect Ratio") + .description("The fixed aspect ratio of a hierarchical node when using topdown layout. Default is 1/sqrt(2). If this value is set on a parallel node it applies to its children, when set on a hierarchical node it applies to the node itself.") + .defaultValue(TOPDOWN_HIERARCHICAL_NODE_ASPECT_RATIO_DEFAULT) + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS, LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.addDependency( + "org.eclipse.elk.topdown.hierarchicalNodeAspectRatio", + "org.eclipse.elk.topdown.nodeType", + null + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.topdown.nodeType") + .group("topdown") + .name("Topdown Node Type") + .description("The different node types used for topdown layout. If the node type is set to {@link TopdownNodeTypes.PARALLEL_NODE} the algorithm must be set to a {@link TopdownLayoutProvider} such as {@link TopdownPacking}. The {@link nodeSize.fixedGraphSize} option is technically only required for hierarchical nodes.") + .defaultValue(TOPDOWN_NODE_TYPE_DEFAULT) + .type(LayoutOptionData.Type.ENUM) + .optionClass(TopdownNodeTypes.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.addDependency( + "org.eclipse.elk.topdown.nodeType", + "org.eclipse.elk.nodeSize.fixedGraphSize", + null + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.topdown.scaleCap") + .group("topdown") + .name("Topdown Scale Cap") + .description("Determines the upper limit for the topdown scale factor. The default value is 1.0 which ensures that nested children never end up appearing larger than their parents in terms of unit sizes such as the font size. If the limit is larger, nodes will fully utilize the available space, but it is counteriniuitive for inner nodes to have a larger scale than outer nodes.") + .defaultValue(TOPDOWN_SCALE_CAP_DEFAULT) + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.PARENTS)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.addDependency( + "org.eclipse.elk.topdown.scaleCap", + "org.eclipse.elk.topdown.nodeType", + TOPDOWN_SCALE_CAP_DEP_TOPDOWN_NODE_TYPE_0 + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.insideSelfLoops.activate") + .group("insideSelfLoops") + .name("Activate Inside Self Loops") + .description("Whether this node allows to route self loops inside of it instead of around it. If set to true, this will make the node a compound node if it isn\'t already, and will require the layout algorithm to support compound nodes with hierarchical ports.") + .defaultValue(INSIDE_SELF_LOOPS_ACTIVATE_DEFAULT) + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.NODES)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.insideSelfLoops.yo") + .group("insideSelfLoops") + .name("Inside Self Loop") + .description("Whether a self loop should be routed inside a node instead of around that node.") + .defaultValue(INSIDE_SELF_LOOPS_YO_DEFAULT) + .type(LayoutOptionData.Type.BOOLEAN) + .optionClass(Boolean.class) + .targets(EnumSet.of(LayoutOptionData.Target.EDGES)) + .visibility(LayoutOptionData.Visibility.ADVANCED) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.edge.thickness") + .group("edge") + .name("Edge Thickness") + .description("The thickness of an edge. This is a hint on the line width used to draw an edge, possibly requiring more space to be reserved for it.") + .defaultValue(EDGE_THICKNESS_DEFAULT) + .type(LayoutOptionData.Type.DOUBLE) + .optionClass(Double.class) + .targets(EnumSet.of(LayoutOptionData.Target.EDGES)) + .visibility(LayoutOptionData.Visibility.HIDDEN) + .create() + ); + registry.register(new LayoutOptionData.Builder() + .id("org.eclipse.elk.edge.type") + .group("edge") + .name("Edge Type") + .description("The type of an edge. This is usually used for UML class diagrams, where associations must be handled differently from generalizations.") + .defaultValue(EDGE_TYPE_DEFAULT) + .type(LayoutOptionData.Type.ENUM) + .optionClass(EdgeType.class) + .targets(EnumSet.of(LayoutOptionData.Target.EDGES)) + .visibility(LayoutOptionData.Visibility.HIDDEN) + .create() + ); + registry.register(new LayoutCategoryData.Builder() + .id("org.eclipse.elk.layered") + .name("Layered") + .description("The layer-based method was introduced by Sugiyama, Tagawa and Toda in 1981. It emphasizes the direction of edges by pointing as many edges as possible into the same direction. The nodes are arranged in layers, which are sometimes called \"hierarchies\", and then reordered such that the number of edge crossings is minimized. Afterwards, concrete coordinates are computed for the nodes and edge bend points.") + .create() + ); + registry.register(new LayoutCategoryData.Builder() + .id("org.eclipse.elk.orthogonal") + .name("Orthogonal") + .description("Orthogonal methods that follow the \"topology-shape-metrics\" approach by Batini, Nardelli and Tamassia \'86. The first phase determines the topology of the drawing by applying a planarization technique, which results in a planar representation of the graph. The orthogonal shape is computed in the second phase, which aims at minimizing the number of edge bends, and is called orthogonalization. The third phase leads to concrete coordinates for nodes and edge bend points by applying a compaction method, thus defining the metrics.") + .create() + ); + registry.register(new LayoutCategoryData.Builder() + .id("org.eclipse.elk.force") + .name("Force") + .description("Layout algorithms that follow physical analogies by simulating a system of attractive and repulsive forces. The first successful method of this kind was proposed by Eades in 1984.") + .create() + ); + registry.register(new LayoutCategoryData.Builder() + .id("org.eclipse.elk.circle") + .name("Circle") + .description("Circular layout algorithms emphasize cycles or biconnected components of a graph by arranging them in circles. This is useful if a drawing is desired where such components are clearly grouped, or where cycles are shown as prominent OPTIONS of the graph.") + .create() + ); + registry.register(new LayoutCategoryData.Builder() + .id("org.eclipse.elk.tree") + .name("Tree") + .description("Specialized layout methods for trees, i.e. acyclic graphs. The regular structure of graphs that have no undirected cycles can be emphasized using an algorithm of this type.") + .create() + ); + registry.register(new LayoutCategoryData.Builder() + .id("org.eclipse.elk.planar") + .name("Planar") + .description("Algorithms that require a planar or upward planar graph. Most of these algorithms are theoretically interesting, but not practically usable.") + .create() + ); + registry.register(new LayoutCategoryData.Builder() + .id("org.eclipse.elk.radial") + .name("Radial") + .description("Radial layout algorithms usually position the nodes of the graph on concentric circles.") + .create() + ); + new org.eclipse.elk.core.options.FixedLayouterOptions().apply(registry); + new org.eclipse.elk.core.options.BoxLayouterOptions().apply(registry); + new org.eclipse.elk.core.options.RandomLayouterOptions().apply(registry); + } +} diff --git a/screenshots/01-dashboard.png b/screenshots/01-dashboard.png new file mode 100644 index 00000000..cbd03294 Binary files /dev/null and b/screenshots/01-dashboard.png differ diff --git a/screenshots/02-dashboard-detail-panel.png b/screenshots/02-dashboard-detail-panel.png new file mode 100644 index 00000000..7f2fb923 Binary files /dev/null and b/screenshots/02-dashboard-detail-panel.png differ diff --git a/screenshots/03-exchange-detail.png b/screenshots/03-exchange-detail.png new file mode 100644 index 00000000..04b9a378 Binary files /dev/null and b/screenshots/03-exchange-detail.png differ diff --git a/screenshots/04-routes-metrics.png b/screenshots/04-routes-metrics.png new file mode 100644 index 00000000..24a8b801 Binary files /dev/null and b/screenshots/04-routes-metrics.png differ diff --git a/screenshots/05-agents.png b/screenshots/05-agents.png new file mode 100644 index 00000000..afd3c08f Binary files /dev/null and b/screenshots/05-agents.png differ diff --git a/screenshots/06-agent-instance.png b/screenshots/06-agent-instance.png new file mode 100644 index 00000000..9980c682 Binary files /dev/null and b/screenshots/06-agent-instance.png differ diff --git a/screenshots/07-admin-rbac.png b/screenshots/07-admin-rbac.png new file mode 100644 index 00000000..d55b639d Binary files /dev/null and b/screenshots/07-admin-rbac.png differ diff --git a/screenshots/08-admin-audit.png b/screenshots/08-admin-audit.png new file mode 100644 index 00000000..2e4b95b5 Binary files /dev/null and b/screenshots/08-admin-audit.png differ diff --git a/screenshots/09-admin-oidc.png b/screenshots/09-admin-oidc.png new file mode 100644 index 00000000..d6ef175c Binary files /dev/null and b/screenshots/09-admin-oidc.png differ diff --git a/screenshots/10-admin-database.png b/screenshots/10-admin-database.png new file mode 100644 index 00000000..c760bb20 Binary files /dev/null and b/screenshots/10-admin-database.png differ diff --git a/screenshots/11-admin-opensearch.png b/screenshots/11-admin-opensearch.png new file mode 100644 index 00000000..83aa203c Binary files /dev/null and b/screenshots/11-admin-opensearch.png differ diff --git a/screenshots/12-command-palette.png b/screenshots/12-command-palette.png new file mode 100644 index 00000000..91f6e838 Binary files /dev/null and b/screenshots/12-command-palette.png differ diff --git a/screenshots/13-dashboard-dark-mode.png b/screenshots/13-dashboard-dark-mode.png new file mode 100644 index 00000000..f3668356 Binary files /dev/null and b/screenshots/13-dashboard-dark-mode.png differ diff --git a/screenshots/14-login-page.png b/screenshots/14-login-page.png new file mode 100644 index 00000000..e4fef351 Binary files /dev/null and b/screenshots/14-login-page.png differ diff --git a/screenshots/appconfig-overview.png b/screenshots/appconfig-overview.png new file mode 100644 index 00000000..91213e3f Binary files /dev/null and b/screenshots/appconfig-overview.png differ diff --git a/screenshots/appconfig-slidein-v2.png b/screenshots/appconfig-slidein-v2.png new file mode 100644 index 00000000..561396b4 Binary files /dev/null and b/screenshots/appconfig-slidein-v2.png differ diff --git a/screenshots/appconfig-slidein-v3.png b/screenshots/appconfig-slidein-v3.png new file mode 100644 index 00000000..e41b4d1d Binary files /dev/null and b/screenshots/appconfig-slidein-v3.png differ diff --git a/screenshots/appconfig-slidein-v4.png b/screenshots/appconfig-slidein-v4.png new file mode 100644 index 00000000..824b4837 Binary files /dev/null and b/screenshots/appconfig-slidein-v4.png differ diff --git a/screenshots/appconfig-slidein.png b/screenshots/appconfig-slidein.png new file mode 100644 index 00000000..691e2cd0 Binary files /dev/null and b/screenshots/appconfig-slidein.png differ diff --git a/screenshots/complex-fulfillment-broken.png b/screenshots/complex-fulfillment-broken.png new file mode 100644 index 00000000..af950b4b Binary files /dev/null and b/screenshots/complex-fulfillment-broken.png differ diff --git a/screenshots/error-handling-test.png b/screenshots/error-handling-test.png new file mode 100644 index 00000000..4754900d Binary files /dev/null and b/screenshots/error-handling-test.png differ diff --git a/screenshots/exchanges-800h.png b/screenshots/exchanges-800h.png new file mode 100644 index 00000000..2d70b483 Binary files /dev/null and b/screenshots/exchanges-800h.png differ diff --git a/screenshots/exchanges-scroll-check.png b/screenshots/exchanges-scroll-check.png new file mode 100644 index 00000000..e08f63c5 Binary files /dev/null and b/screenshots/exchanges-scroll-check.png differ diff --git a/screenshots/process-diagram-after-fix.png b/screenshots/process-diagram-after-fix.png new file mode 100644 index 00000000..25af53f4 Binary files /dev/null and b/screenshots/process-diagram-after-fix.png differ diff --git a/screenshots/process-diagram-dev.png b/screenshots/process-diagram-dev.png new file mode 100644 index 00000000..54feeada Binary files /dev/null and b/screenshots/process-diagram-dev.png differ diff --git a/screenshots/trace-indicator-check.png b/screenshots/trace-indicator-check.png new file mode 100644 index 00000000..e488cb7d Binary files /dev/null and b/screenshots/trace-indicator-check.png differ diff --git a/ui/org/eclipse/elk/core/options/PortAlignment.java b/ui/org/eclipse/elk/core/options/PortAlignment.java new file mode 100644 index 00000000..8dbb9b09 --- /dev/null +++ b/ui/org/eclipse/elk/core/options/PortAlignment.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2015 Kiel University and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.elk.core.options; + +/** + * Defines the distribution of ports. + * + * @author csp + */ +public enum PortAlignment { + + /** Ports are evenly distributed, with the same amount of space between and around them. */ + DISTRIBUTED, + + /** Ports are justified and use up all the space except for the surrounding ports spacing. */ + JUSTIFIED, + + /** Ports are placed at the most top respectively left position with minimal spacing. */ + BEGIN, + + /** Ports are centered with minimal spacing. */ + CENTER, + + /** Ports are placed at the most top respectively left position with minimal spacing. */ + END; + +} diff --git a/ui/src/components/ProcessDiagram/CompoundNode.tsx b/ui/src/components/ProcessDiagram/CompoundNode.tsx index 00850621..aa7e0a30 100644 --- a/ui/src/components/ProcessDiagram/CompoundNode.tsx +++ b/ui/src/components/ProcessDiagram/CompoundNode.tsx @@ -65,8 +65,8 @@ export function CompoundNode({ onNodeClick, onNodeDoubleClick, onNodeEnter, onNodeLeave, }; - // _TRY_BODY / _CB_MAIN: transparent wrapper — no header, no border, just layout - if (node.type === '_TRY_BODY' || node.type === '_CB_MAIN') { + // _TRY_BODY: transparent wrapper — no header, no border, just layout + if (node.type === '_TRY_BODY') { return ( {renderInternalEdges(internalEdges, absX, absY, executionOverlay)} @@ -75,24 +75,6 @@ export function CompoundNode({ ); } - // _CB_FALLBACK: section styling with EIP purple - if (node.type === '_CB_FALLBACK') { - const fallbackColor = '#7C3AED'; // EIP purple - return ( - - - - - fallback - - {renderInternalEdges(internalEdges, absX, absY, executionOverlay)} - {renderChildren(node, absX, absY, childProps)} - - ); - } - // DO_CATCH / DO_FINALLY: section-like styling (tinted bg, thin border, label) if (node.type === 'DO_CATCH' || node.type === 'DO_FINALLY') { const sectionLabel = node.type === 'DO_CATCH' diff --git a/ui/src/components/ProcessDiagram/node-colors.ts b/ui/src/components/ProcessDiagram/node-colors.ts index 78488fc1..f14c1db6 100644 --- a/ui/src/components/ProcessDiagram/node-colors.ts +++ b/ui/src/components/ProcessDiagram/node-colors.ts @@ -64,7 +64,6 @@ const COMPOUND_TYPES = new Set([ 'EIP_LOOP', 'EIP_MULTICAST', 'EIP_AGGREGATE', 'ON_EXCEPTION', 'ERROR_HANDLER', 'ON_COMPLETION', - 'EIP_CIRCUIT_BREAKER', '_CB_MAIN', '_CB_FALLBACK', ]); const ERROR_COMPOUND_TYPES = new Set([