process group step detail toggler
frdel committed
Jan 26, 2026 at 14:11 UTC
93419f910645dfd6b843f873502256c8f945c8fd
3 files changed
+17
-79
webui/components/messages/process-group/process-group-dom.js
+7
-69
@@ -8,81 +8,19 @@ export function applyModeSteps(detailMode, showUtils) {
8
detailMode ||
9
preferencesStore.detailMode ||
10
"current";
11
- const showUtilsFlag =
12
- typeof showUtils === "boolean"
13
- ? showUtils
14
- : preferencesStore.showUtils || false;
11
12
const chatHistory = document.getElementById("chat-history");
13
if (!chatHistory) return;
14
19
- const shouldExpandGroup = mode !== "collapsed";
20
- const shouldExpandError = mode === "current" || mode === "expanded";
15
+ const shouldExpand = mode !== "collapsed";
16
+ const messages = chatHistory.querySelectorAll(".process-group");
17
+ for (let i = 0; i < messages.length; i += 1) {
18
+ messages[i].classList.toggle("expanded", shouldExpand);
19
22
- // Walk DOM once (reverse to match message traversal patterns)
23
- const groups = chatHistory.children;
24
- for (let gi = groups.length - 1; gi >= 0; gi -= 1) {
25
- const messageGroup = groups[gi];
26
- const containers = messageGroup.children;
27
- for (let ci = containers.length - 1; ci >= 0; ci -= 1) {
28
- const container = containers[ci];
29
-
30
- if (container.classList.contains("has-process-group")) {
31
- const processGroup = container.querySelector(".process-group");
32
- if (processGroup) {
33
- applyModeToProcessGroup(processGroup, mode, showUtilsFlag, shouldExpandGroup);
34
- }
35
- }
36
-
37
- const errorGroups = container.getElementsByClassName("error-group");
38
- if (errorGroups.length) {
39
- for (let ei = 0; ei < errorGroups.length; ei += 1) {
40
- errorGroups[ei].classList.toggle("expanded", shouldExpandError);
41
- }
42
- }
20
+ const steps = messages[i].querySelectorAll(".process-step");
21
+ for (let si = 0; si < steps.length; si += 1) {
22
+ steps[si].classList.toggle("expanded", mode === "expanded");
23
}
24
}
25
}
26
47
-function applyModeToProcessGroup(group, mode, showUtilsFlag, shouldExpandGroup) {
48
- group.classList.toggle("expanded", shouldExpandGroup);
49
-
50
- const isActiveGroup = group.classList.contains("active");
51
- const isGroupCompleted = group.classList.contains("process-group-completed");
52
- const steps = group.getElementsByClassName("process-step");
53
- if (!steps.length) return;
54
-
55
- let lastVisibleStep = null;
56
- const shouldFindLastVisible = mode === "current" && isActiveGroup && !isGroupCompleted;
57
-
58
- for (let i = steps.length - 1; i >= 0; i -= 1) {
59
- const step = steps[i];
60
-
61
- if (shouldFindLastVisible && !lastVisibleStep) {
62
- if (showUtilsFlag || !step.classList.contains("message-util")) {
63
- lastVisibleStep = step;
64
- }
65
- }
66
-
67
- let shouldExpand = false;
68
- if (mode === "expanded") {
69
- shouldExpand = true;
70
- } else if (mode === "current" && isActiveGroup) {
71
- shouldExpand = step === lastVisibleStep;
72
- }
73
-
74
- if (shouldExpand) {
75
- step.classList.add("step-expanded");
76
- } else {
77
- const shouldDefer =
78
- mode === "current" &&
79
- isActiveGroup &&
80
- lastVisibleStep &&
81
- step !== lastVisibleStep;
82
- if (!shouldDefer) {
83
- step.classList.remove("step-expanded");
84
- step.removeAttribute("data-user-pinned");
85
- }
86
- }
87
- }
88
-}
webui/components/messages/process-group/process-group.css
+8
-8
@@ -437,7 +437,7 @@
437
}
438
439
/* Use direct child selector to prevent affecting nested steps */
440
-.process-step.step-expanded > .process-step-header > .step-expand-icon {
440
+.process-step.expanded > .process-step-header > .step-expand-icon {
441
transform: rotate(90deg);
442
}
443
@@ -455,11 +455,11 @@
455
overscroll-behavior: contain; /* avoid scroll chaining */
456
}
457
458
-.process-step:not(.step-expanded) > .process-step-detail {
458
+.process-step:not(.expanded) > .process-step-detail {
459
margin-top: 0;
460
}
461
462
-.process-step:not(.step-expanded) > .process-step-detail > .process-step-detail-scroll {
462
+.process-step:not(.expanded) > .process-step-detail > .process-step-detail-scroll {
463
padding: 0;
464
margin-top: 0;
465
max-height: 0;
@@ -483,19 +483,19 @@
483
}
484
485
/* Use direct child selector (>) to prevent cascading to nested steps */
486
-.process-step.step-expanded > .process-step-detail {
486
+.process-step.expanded > .process-step-detail {
487
/* grid-template-rows: 1fr; */
488
opacity: 1;
489
overflow: visible;
490
margin-top: var(--spacing-xs);
491
}
492
493
-.process-step.step-expanded > .process-step-detail > .process-step-detail-scroll {
493
+.process-step.expanded > .process-step-detail > .process-step-detail-scroll {
494
max-height: 40em;
495
overflow-y: auto;
496
}
497
498
-.process-step.step-expanded > .process-step-detail > .process-step-detail-scroll > .process-step-detail-scroll {
498
+.process-step.expanded > .process-step-detail > .process-step-detail-scroll > .process-step-detail-scroll {
499
}
500
501
.process-step-detail-scroll {
@@ -741,7 +741,7 @@
741
}
742
743
/* Only show nested container when parent step is expanded */
744
-.process-step.step-expanded > .process-nested-container {
744
+.process-step.expanded > .process-nested-container {
745
grid-template-rows: 1fr;
746
opacity: 1;
747
margin-top: 2px;
@@ -826,7 +826,7 @@
826
}
827
828
/* Hide View Details button when step is collapsed */
829
-.process-step:not(.step-expanded) > .process-step-detail > .step-detail-actions {
829
+.process-step:not(.expanded) > .process-step-detail > .step-detail-actions {
830
display: none;
831
}
832
webui/js/messages.js
+2
-2
@@ -460,7 +460,7 @@ function drawProcessStep({
460
if (isActiveGroup && !isGroupCompleted) {
461
step.classList.add("step-expanded");
462
const allExpandedSteps = stepsContainer.querySelectorAll(
463
- ".process-step.step-expanded",
463
+ ".process-step.expanded",
464
);
465
allExpandedSteps.forEach((expandedStep) => {
466
if (expandedStep.id !== stepId) {
@@ -2584,7 +2584,7 @@ function markProcessGroupComplete(group, responseTitle) {
2584
if (detailMode === "current") {
2585
// Schedule collapse for all expanded steps (deterministic)
2586
const allExpandedSteps = group.querySelectorAll(
2587
- ".process-step.step-expanded",
2587
+ ".process-step.expanded",
2588
);
2589
allExpandedSteps.forEach((expandedStep) => {
2590
scheduleStepCollapse(expandedStep, FINAL_STEP_COLLAPSE_DELAY_MS);