Repository navigation
fix(workspace): calm sidebar first load; rail tabs reordered, Asks always present (#3672, ent#892) - #3682
Merged
Conversation
…l tabs, Asks always present (#3672, ent#892) #3672 — the Workspace sidebar's agent and chat lists jumped on a cold load. The roster, the chat list and the asks feed land at different times, and each re-laid the list: agent rows re-sorted and grew a subtitle when chats arrived, an asked agent was appended past the collapse limit when asks arrived, chat groups popped in, and the Projects link (its capability rides the roster) pushed the search box and both lists down. - `sidebarSettled` (portalUtils, pure): bootstrap placed the caller AND the asks feed has a verdict (loaded / 404-403 / failed) — state, never a timer. Portal.vue latches it (`sidebarReady`), resetting only when the session ends. - PortalSidebar: both sections hold skeleton rows (new PortalSkeleton `sidebar-agents` / `sidebar-chats` variants) until settled, then render in one pass inside one `.ws-fade-in` (180ms opacity, off under reduced motion). A platform session holds the Projects link's slot (`sidebar-link`). An empty chat list keeps a stable "No chats yet" state. - Measured (Playwright, cold /workspace, 3 runs, fast and with staggered latency): CLS 0.008 -> 0.0003; the residual is in the Inbox pane header. Mutation check: with PortalSidebar.vue reverted, 5 of the 11 tests in portalSidebarCalmLoad.mount.spec.js go red; restored byte-identical. trinity-enterprise#892 — the agent rail's tabs read Info, Canvas, Files, Projects, Asks, Work, Loops. Asks is always present (operator ruling 2026-10-13): ent#836's presence rule and `asksTabPresent` are removed, the registry entry declares an empty state ("No asks" / "Open the Inbox"), and PortalRailAsks owns all four states via `railAsksView` (skeleton before a verdict, LoadFailed, empty, rows). Default tab stays Work; a remembered tab still wins; ⌥. walks the new order. With portalRail.js reverted, 5 of 14 portalRailAsks.spec.js tests go red. Order-pin specs updated per the issue; two source-text pins moved to the new sidebar gate; PortalSidebar's raw-gray ratchet entry lowered 35 -> 29. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The `sidebar-link` skeleton held a 36px slot for a platform session until the sidebar settled, then vanished on every install not entitled to Projects (all OSS installs) - a new layout shift to spare a late pop-in on the few entitled ones. Operator ruling: no hold. The link renders once the roster says `projectsAvailable`; the unused `sidebar-link` variant is removed, the spec asserts nothing sits between New chat and the search box before the verdict, and the feature flow no longer promises a held slot. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When the first `fetchAllSessions` fails, the store returns its last good list - `[]` - and the sidebar told the person they had no chats. Portal.vue now passes `:threads-failed="store.sessionsFailed"` (the same signal the Inbox reads) to both sidebars. The empty copy renders only for a trusted list; a failed read shows an InlineError instead (the stale banner over rows, "Couldn't load your chats" over none) with a retry wired to `refreshThreads`, dismissible and back on the next failure. Mount tests cover all four cases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PortalRailAsks read `view.state` but never `view.stale`, so a failed asks
refresh left the last list (or the empty state) on screen with no word of
it. It now raises the stale InlineError the way PortalRailCanvas,
PortalRailFiles and PortalLoops do ("Couldn't refresh your asks - showing
data from ..."), with a retry and a dismiss that re-arms on the next
failure. The two `./portalUtils` imports are merged into one. Mount tests
cover the banner over rows, over the empty state, and its absence.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…3672) Binding `:settled="true"` in Portal.vue left the suite green: the calm-load spec mounts PortalSidebar alone. portalSidebarLatch.mount.spec.js mounts the shell (shallow, the portalAgentLandingStage harness) with the asks read held open and checks both sidebars hold `settled=false` until the verdict, latch once, stay latched when the verdict's inputs drop on a later refresh, and reset on sign-out so the next session's first load holds again. Mutation check: `:settled="true"` -> 3 of 4 red; dropping the sign-out reset -> 1 red; replacing the latch with a plain mirror -> 1 red; restored byte-identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
|
merge-train: pushed four mechanical commits to this branch (head
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #3672. Implements abilityai/trinity-enterprise#892 (private tracker; closing keywords don't cross repos, so close it manually at release).
#3672 — the Workspace sidebar holds its layout while it loads
Cause. The roster, the chat list and the asks feed land at different times, and each one re-laid the list:
Fix.
sidebarSettled(pure,portalUtils.js) is true once bootstrap has read the roster and the chats (success or failure) and the asks feed has a verdict (loaded, 404/403, or failed). It is keyed on state, never a timer, and can't hang.Portal.vuelatches it assidebarReadyand resets it only when the session ends, so a background refresh never brings the skeleton back.PortalSkeletonvariantssidebar-agents/sidebar-chats). A platform session also holds the Projects link's 36px slot (sidebar-link)..ws-fade-in: a 180ms opacity fade, off underprefers-reduced-motion.Measured with Playwright, cold
/workspaceload, 3 runs each, fast and with roster, chats and asks delayed by different amounts:dev)The remaining 0.0003 is in the Inbox pane header, not the sidebar. Layout-shift entries only count existing elements that move, not content that pops in, so the "before" number understates the jump people actually see.
ent#892 — rail tabs reordered; Asks always present
RAIL_TAB_ORDER), and its comment states the new reason.asksTabPresentare removed, andtabPassesDoorno longer has a presence check.PortalRailAsksowns all four states viarailAsksView: a skeleton before a verdict, LoadFailed for a failed first read, the empty state, and the rows. The "needs you" mark still appears only when an ask is waiting.Behaviour notes for the reviewer
Tests
portalSidebarCalmLoad.mount.spec.js(11 tests; mounted, jsdom).portalRailAsks.spec.jsandportalRailAsks.mount.spec.js(always present, order, empty copy, ⌥. walk, the verdict, the empty / skeleton / failed states mounted).portalRail.spec.jsupdated as the issue asks. Two source-text pins (portalRosterRow.spec.js,portalSidebarSearch.spec.js) now point at the new sidebar gate.PortalSidebar.vuereverted, 5 of the 11 new sidebar tests go red. WithportalRail.jsreverted, 5 of 14portalRailAsks.spec.jstests go red. Both files were restored byte-identical.npm run test:unit: 5772 passed.vite buildOK.PortalSidebar.vue's gray count dropped 35 → 29; its baseline entry was lowered by hand so the bug(ci): the raw-colour ratchet is documented as enforced but nothing runs it, and the tree has drifted past its baseline #2605 re-freeze record stays intact.Verification
/verify-local --skip-agent --skip-unit:The one failure is
integration/test_circuit_breaker.py:395, a timing assertion (expected a ≥0.4s gap, measured 0.19s) on a host running several other test jobs. This PR changes no backend code.Backend unit suite not verified. On the first attempt it froze at 97% on a backend test, so it was skipped on the rerun.
Production frontend image served against the local dev stack and checked by eye:
Docs
requirements/core-agent.md: the order line, plus a new AC-11 for ent#892.feature-flows/workspace-rail.md: an ent#892 section.feature-flows/workspace-sidebar-ia.md: a first-load section for Workspace: the sidebar's agent and chat lists jump as they load — hold the layout and fade content in #3672.🤖 Generated with Claude Code