feat(tangle-cloud): unify app shell with tangle dapp#3264
Conversation
✅ Deploy Preview for tangle-dapp canceled.
|
✅ Deploy Preview for tangle-cloud ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for tangle-leaderboard canceled.
|
❌ Needs Work —
|
| deepseek | glm | aggregate | |
|---|---|---|---|
| Readiness | 47 | 44 | 44 |
| Confidence | 65 | 65 | 65 |
| Correctness | 47 | 44 | 44 |
| Security | 47 | 44 | 44 |
| Testing | 47 | 44 | 44 |
| Architecture | 47 | 44 | 44 |
Full multi-shot audit completed 1/1 planned shots over 5 changed files. Global verifier still owns final merge decision. | Full multi-shot audit completed 1/1 planned shots over 5 changed files. Global verifier still owns final merge decision.
Blocking
🔴 HIGH Blueprint detail pages lose all top-nav controls (breadcrumb, CTA, mode picker) — apps/tangle-cloud/src/components/Header.tsx
The Header left slot that rendered
useTopNavSlotContent()was removed (diff lines -56 to -59). IframeBlueprintLayout.tsx:198 publishes breadcrumb, mode picker, 'Create instance' CTA, Expand button, and Details button viauseTopNavSlot(navContent), with the explicit design note at line 108-110: 'Blueprint identity + primary CTA + Details disclosure live in the global top nav.' With the consumer gone, these elements never render. Blueprint detail pages lose their entire in-header identity bar — no breadcrumb trail, no instance-creation CTA, no mode switching (for multi-mode blueprints), and no Details panel toggle. The IframeBlueprintLayout does no
🔴 HIGH Dual sidebar state: Layout and SideBarCmp manage expanded/collapsed independently — apps/tangle-cloud/src/components/Layout.tsx
Layout.tsx:48-58 reads localStorage key 'tangle-cloud-sidebar-expanded' into
isSidebarExpanded, then passes it asisExpandedByDefaulttoSideBarCmp. But SideBarCmp (libs/ui-components/src/components/SideBar/SideBar.tsx:55-59) uses its ownuseLocalStorageState('isSidebarOpen', { defaultValue: isExpandedByDefault }). When the user toggles the sidebar, SideBarCmp flips its own internal state AND callsonSideBarToggle(), which flips Layout's state. These two sources of truth can diverge because: (1) SideBarCmp's useEffect (line 63-74) re-syncs from a cookie on mount, potentially overwriting theisExpandedByDefaultprop, and (2) the two localSto
Other
🟠 MEDIUM --cloud-sidebar-width variable set to 16rem but SideBarCmp is 18rem (w-72) — apps/tangle-cloud/src/components/Layout.tsx
Layout.tsx:79-80 sets
--cloud-sidebar-width: 16rem(equivalent to Tailwind's w-64) when sidebar is expanded. But the new SideBarCmp from @tangle-network/ui-components usesw-72= 18rem (SideBar.tsx:95). The CSS fallback in styles.css:235 is also16rem. The variable offsets wallet connect modals (and any centered dialog) by half the sidebar width. With 16rem instead of 18rem, every centered dialog is offset by 1rem (16px) to the left of true content-area center when the sidebar is expanded. Fix: change'16rem'to'18rem'on line 80.
🟠 MEDIUM TopNavSlot context is published but never consumed — dead wiring — apps/tangle-cloud/src/components/Layout.tsx
Layout.tsx:94 still wraps the entire app in
<TopNavSlotProvider>. Header.tsx previously calleduseTopNavSlotContent()(removed in this diff, line -48). ButIframeBlueprintLayout.tsx:198still callsuseTopNavSlot(navContent)to publish content into the slot. Since nothing reads fromuseTopNavSlotContent()anymore, that published content silently vanishes — the iframe blueprint page's contextual nav is lost. This is a functional regression. Fix: either restore a consumer in the layout (e.g., render the slot content above the main content area), or remove TopNavSlotProvider from Layout and clean up all publishers.
🟠 MEDIUM isSidebarExpanded desyncs from SideBarCmp internal state on page reload — apps/tangle-cloud/src/components/Layout.tsx
Layout initializes
isSidebarExpandedfrom localStorage keytangle-cloud-sidebar-expanded(lines 48-57), but the newonExpandedChangecallback on line 102 toggles state without persisting to localStorage. Meanwhile,SideBarCmpinternally manages its own state viauseLocalStorageState('isSidebarOpen', ...)(SideBar.tsx:55-59), persisting on every toggle. After first toggle in this new code,tangle-cloud-sidebar-expandedis stale forever. On reload: layout reads stale value → initializesisSidebarExpandedw
🟠 MEDIUM Sidebar onExpandedChange signature narrowed — toggle callback loses expanded state — apps/tangle-cloud/src/components/Sidebar.tsx
Sidebar.tsx:29 changed
onExpandedChangefrom(isExpanded: boolean) => voidto() => void. The callback no longer communicates whether the sidebar is now expanded or collapsed. Layout.tsx:102 works around this with() => setIsSidebarExpanded((value) => !value), but this flips its own state independently of SideBarCmp's actual state, compounding the dual-state issue from the first finding. If SideBarCmp's internal state ever differs (e.g., due to the cookie sync effect), Layout's toggle will flip in the wrong direction.
🟡 LOW Dead code: TopNavSlotProvider and useTopNavSlot with no consumer — apps/tangle-cloud/src/components/Header.tsx
Header.tsx diff removes the only consumer of
useTopNavSlotContent()(the left slot div at old lines 56-59). TopNavSlotProvider still wraps the app tree in Layout.tsx:94, and IframeBlueprintLayout.tsx:198 still computes and publishes nav content viauseTopNavSlot. Both are dead work — the provider adds a context render overhead, and the blueprint detail page computes a useMemo'd JSX fragment that never renders. Fix: either remove TopNavSlotProvider/useTopNavSlot and the orphaned publish call, or restore the consumer.
🟡 LOW MobileSidebar rendered unconditionally on every page load (lg:hidden only) — apps/tangle-cloud/src/components/Layout.tsx
Layout.tsx:120 renders
<MobileSidebar />inside the content area on every page. It uses a Radix Dialog internally, so the trigger button is always in the DOM even on desktop. Thelg:hiddenclass hides it visually, but the component still mounts and initializes state. This is minor but could be wrapped in a lazy import or portal to avoid mounting the Dialog root on desktop viewports.
🟡 LOW AccountStatsCard disconnected state changed from 'sandbox' to 'elevated' Card variant — apps/tangle-cloud/src/pages/instances/AccountStatsCard.tsx
AccountStatsCard.tsx:142 uses
variant="sandbox"for the connected state card, but the disconnected state (line 116) usesvariant="elevated". This creates a visual inconsistency when the wallet connects/disconnects — the card style changes from elevated to sandbox. This may be intentional (to differentiate states) but should be confirmed by design review.
tangletools · 2026-06-08T12:41:54Z · trace
tangletools
left a comment
There was a problem hiding this comment.
❌ 2 Blocking Findings — d3787b16
Full multi-shot audit completed 1/1 planned shots over 5 changed files. Global verifier still owns final merge decision. | Full multi-shot audit completed 1/1 planned shots over 5 changed files. Global verifier still owns final merge decision.
Full immutable report for this review: trace
Summary comment for this run: full summary
tangletools · 2026-06-08T12:41:54Z · immutable trace
✅ No Blockers —
|
| deepseek | glm | aggregate | |
|---|---|---|---|
| Readiness | 72 | 72 | 72 |
| Confidence | 65 | 65 | 65 |
| Correctness | 72 | 72 | 72 |
| Security | 72 | 72 | 72 |
| Testing | 72 | 72 | 72 |
| Architecture | 72 | 72 | 72 |
Full multi-shot audit completed 1/1 planned shots over 6 changed files. Global verifier still owns final merge decision. | Full multi-shot audit completed 1/1 planned shots over 6 changed files. Global verifier still owns final merge decision.
🟠 MEDIUM Dual theme management: useDarkMode + manual DOM sync — apps/tangle-cloud/src/components/Layout.tsx
Lines 40–41 and 54–61: Layout reads theme via
useDarkMode('dark')(which internally togglesdocument.documentElement.classListand persists to localStoragethemekey), then the useEffect on lines 54–61 redundantly re-appliesclassList.toggle('dark'),colorScheme, anddata-sandbox-*attributes. TheclassListand localStorage writes are now duplicated —useDarkModealready manages both. Thedata-sandbox-theme/data-sandbox-uiattributes andcolorSchemestill need the effect, but thedarkclas
🟠 MEDIUM Sidebar expanded state tracked with different localStorage key than shared SideBarCmp — apps/tangle-cloud/src/components/Layout.tsx
Layout.tsx:47-51 initializes isSidebarExpanded from 'tangle-cloud-sidebar-expanded' key. SideBarCmp (libs/ui-components/src/components/SideBar/SideBar.tsx:55-60) manages its own internal state via useLocalStorageState(SIDEBAR_OPEN_KEY='isSidebarOpen'). These are two different keys that can hold different values on first load. After first toggle, both flips synchronize via the onSideBarToggle callback. However the --cloud-sidebar-width CSS variable (Layout.tsx:71-74) reads Layout's local state, and could reflect a wrong value initially if the keys diverge, causing Radix-portaled dialogs to be offset incorrectly.
🟠 MEDIUM Stale sidebar-expand localStorage key — apps/tangle-cloud/src/components/Layout.tsx
Lines 47–51: Layout initializes
isSidebarExpandedby reading the legacy keytangle-cloud-sidebar-expanded, but the newSideBarCmpcomponent (libs/ui-components SideBar.tsx:55) persists its own expand state underSIDEBAR_OPEN_KEY = 'isSidebarOpen'. The two keys diverge after first toggle — Layout's state reads the old key once, then toggles in-memory only, while SideBarCmp writes to the new key. ThesetIsSidebarExpandedin Layout'sonExpandedChange(line 95) updates Layout's own useState but does NOT write t
🟠 MEDIUM TopNavSlot provider wraps entire app with zero consumers — apps/tangle-cloud/src/components/Layout.tsx
Layout.tsx:87 wraps children in . Header.tsx removed its useTopNavSlotContent() call (the reader side). useTopNavSlot is still called in IframeBlueprintLayout.tsx:198 (the writer), but nothing reads the published content — useTopNavSlotContent and useTopNavEntity have zero consumers across the entire workspace. The context tree is dead weight, and any nav content published by detail pages is silently discarded. Remove the TopNavSlotProvider wrapper and the TopNavSlot.tsx module if no reader will be restored.
🟡 LOW Breadcrumb trail and theme toggle removed with no migration path — apps/tangle-cloud/src/components/Header.tsx
The entire
getHeaderTrail,HeaderTrail, andThemeTogglecomponents were deleted.ThemeToggleis now handled by the sharedSideBarCmp(SideBar.tsx:182 renders<ThemeToggle />). Breadcrumb navigation is removed entirely — the header is now only action buttons. If any page relied onuseTopNavSlotfor contextual breadcrumb content, it still compiles (the provider still exists in Layout.tsx:87) but the content is never rendered.IframeBlueprintLayout.tsx:198still callsuseTopNavSlot(navContent)which silently publishes to a now-unused slot. This is dead code, not a bug, but worth noting for cleanup.
🟡 LOW Removed OS-level color-scheme preference fallback at app init — apps/tangle-cloud/src/main.tsx
main.tsx:34 sets initialTheme = storedTheme ?? legacyTheme ?? 'dark', always defaulting to 'dark'. The old code (removed) checked window.matchMedia('(prefers-color-scheme: light)') to default to 'light' for users with light OS preference and no stored theme. The shared useDarkMode hook (libs/ui-components/src/hooks/useDarkMode.ts) also defaults to 'dark' but does check prefers-color-scheme in its DOM effect — creating a potential flash: main.tsx sets 'dark' class, then React/useDarkMode effect may remove it for light-preference users. Low impact since most users will have a stored theme after migration.
tangletools · 2026-06-08T12:53:23Z · trace
Superseded by re-review — no blocking findings on latest commit.
tangletools
left a comment
There was a problem hiding this comment.
✅ Approved — 6 non-blocking findings — 40abbb00
Full multi-shot audit completed 1/1 planned shots over 6 changed files. Global verifier still owns final merge decision. | Full multi-shot audit completed 1/1 planned shots over 6 changed files. Global verifier still owns final merge decision.
Full immutable report for this review: trace
Summary comment for this run: full summary
tangletools · 2026-06-08T12:53:23Z · immutable trace
Summary
Why
The app looked unlike the Tangle dapp because the Blueprints page had been partially restored, but the shell, navigation, topbar, footer, and homepage/operator surfaces were still Cloud-specific chrome built on sandbox primitives. This makes the shared Tangle dapp shell the default frame again and leaves Cloud-specific code for behavior/data.
Verification