From 4ae9ee262949d237a200ad125711a3ddb35c78b8 Mon Sep 17 00:00:00 2001 From: cstns Date: Wed, 19 Nov 2025 10:36:26 +0200 Subject: [PATCH 01/45] refactor(expert): resource handling and add dynamic component mapping in `Expert` component --- frontend/src/components/expert/Expert.vue | 21 +++++++++++-------- .../src/components/expert/ExpertRichGuide.vue | 11 +++++++--- .../components/expert/ExpertRichResources.vue | 11 +++++++--- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/frontend/src/components/expert/Expert.vue b/frontend/src/components/expert/Expert.vue index 28345293b5..cb3b3a33b7 100644 --- a/frontend/src/components/expert/Expert.vue +++ b/frontend/src/components/expert/Expert.vue @@ -29,15 +29,13 @@ :message="message" :is-streaming="isStreaming(index)" > - - - - - + + diff --git a/frontend/src/components/expert/ExpertRichResources.vue b/frontend/src/components/expert/ExpertRichResources.vue index 053acc79cd..1e32d243f3 100644 --- a/frontend/src/components/expert/ExpertRichResources.vue +++ b/frontend/src/components/expert/ExpertRichResources.vue @@ -7,47 +7,104 @@ -
+ + + + + + +
+
    +
  • + +
  • +
+
@@ -235,58 +177,6 @@ export default { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 0.5rem; } - - .package-card { - display: flex; - align-items: center; - gap: 0.5rem; - padding: 0.75rem; - background-color: white; - border: 1px solid $ff-grey-200; - border-radius: 0.5rem; - text-decoration: none; - color: $ff-grey-900; - transition: all 0.2s ease; - height: 4rem; - - &:hover { - border-color: $ff-indigo-300; - background-color: $ff-grey-50; - } - } - - .package-favicon { - flex-shrink: 0; - width: 1rem; - height: 1rem; - } - - .package-info { - flex: 1; - min-width: 0; - display: flex; - flex-direction: column; - gap: 0.25rem; - } - - .package-name { - font-size: 0.875rem; - font-weight: 500; - font-family: monospace; - color: $ff-grey-900; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - .package-url { - font-size: 0.75rem; - color: $ff-grey-500; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - margin: 0; - } } .guide-resources { @@ -295,57 +185,5 @@ export default { flex-direction: column; gap: 0.5rem; } - - .resource-card { - display: flex; - align-items: flex-start; - gap: 0.5rem; - padding: 0.75rem; - background-color: white; - border: 1px solid $ff-grey-200; - border-radius: 0.5rem; - text-decoration: none; - color: $ff-grey-900; - transition: all 0.2s ease; - - &:hover { - border-color: $ff-indigo-300; - background-color: $ff-grey-50; - } - } - - .resource-icon { - flex-shrink: 0; - width: 1rem; - height: 1rem; - margin-top: 0.125rem; - object-fit: contain; - } - - .resource-info { - flex: 1; - display: flex; - flex-direction: column; - gap: 0.25rem; - min-width: 0; - } - - .resource-title { - font-size: 0.875rem; - font-weight: 500; - color: $ff-grey-900; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - .resource-url { - font-size: 0.75rem; - color: $ff-grey-500; - margin: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } } diff --git a/frontend/src/components/expert/ExpertRichResources.vue b/frontend/src/components/expert/ExpertRichResources.vue index 1e32d243f3..c2b78f232a 100644 --- a/frontend/src/components/expert/ExpertRichResources.vue +++ b/frontend/src/components/expert/ExpertRichResources.vue @@ -9,50 +9,14 @@
@@ -60,7 +24,7 @@
@@ -69,11 +33,12 @@ diff --git a/frontend/src/components/expert/ExpertRichResourceFlow.vue b/frontend/src/components/expert/resources/FlowResourceCard.vue similarity index 97% rename from frontend/src/components/expert/ExpertRichResourceFlow.vue rename to frontend/src/components/expert/resources/FlowResourceCard.vue index cf2ddb03cd..2f01a03181 100644 --- a/frontend/src/components/expert/ExpertRichResourceFlow.vue +++ b/frontend/src/components/expert/resources/FlowResourceCard.vue @@ -50,10 +50,10 @@ + + diff --git a/frontend/src/components/expert/resources/StandardResourceCard.vue b/frontend/src/components/expert/resources/StandardResourceCard.vue new file mode 100644 index 0000000000..ebefa24863 --- /dev/null +++ b/frontend/src/components/expert/resources/StandardResourceCard.vue @@ -0,0 +1,113 @@ + + + + + From b831d5812de1f704d2fc615ba23e49b7f1bd371b Mon Sep 17 00:00:00 2001 From: cstns Date: Wed, 19 Nov 2025 18:41:25 +0200 Subject: [PATCH 06/45] improve guide spacing --- .../src/components/expert/ExpertRichGuide.vue | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/frontend/src/components/expert/ExpertRichGuide.vue b/frontend/src/components/expert/ExpertRichGuide.vue index 92891516eb..5d13ca57fd 100644 --- a/frontend/src/components/expert/ExpertRichGuide.vue +++ b/frontend/src/components/expert/ExpertRichGuide.vue @@ -25,29 +25,31 @@ - -
-

Required Node Packages

-
- > +
+ +
+

Required Node Packages

+
+ +
-
- -
-

Related Resources

-
- + +
+

Related Resources

+
+ +
-
- -
-

Related Flows

-
- + +
+

Related Flows

+
+ +
-
+
From 603505e1afaeea466f033dfaefec44cb4c67ee03 Mon Sep 17 00:00:00 2001 From: cstns Date: Wed, 19 Nov 2025 18:57:33 +0200 Subject: [PATCH 07/45] refactor(expert): replace custom copy button with `TextCopier` in `FlowResourceCard` component --- .../expert/resources/FlowResourceCard.vue | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/frontend/src/components/expert/resources/FlowResourceCard.vue b/frontend/src/components/expert/resources/FlowResourceCard.vue index 2f01a03181..0d78bd8835 100644 --- a/frontend/src/components/expert/resources/FlowResourceCard.vue +++ b/frontend/src/components/expert/resources/FlowResourceCard.vue @@ -25,14 +25,7 @@ - +

@@ -50,11 +43,12 @@ From 6880d20ee10cf6a0064007f533ec58c7a728e6c9 Mon Sep 17 00:00:00 2001 From: cstns Date: Wed, 19 Nov 2025 19:04:05 +0200 Subject: [PATCH 08/45] enhance(ui): add copy confirmation animation and replace "Copied" text with `CheckIcon` in `TextCopier` component --- frontend/src/components/TextCopier.vue | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/TextCopier.vue b/frontend/src/components/TextCopier.vue index 272e18892a..58988b58c4 100644 --- a/frontend/src/components/TextCopier.vue +++ b/frontend/src/components/TextCopier.vue @@ -5,19 +5,21 @@ {{ text }} - - Copied! + + + + @@ -90,6 +162,27 @@ export default { flex-direction: column; overflow: hidden; // Changed from auto to hidden - let child components handle their own scrolling + .resize-bar { + position: absolute; + left: -3px; + top: 0; + bottom: 0; + width: 6px; + cursor: ew-resize; + background: $ff-grey-400; + z-index: 1001; + + &:hover { + background: $ff-grey-600; + width: 8px; + left: -4px; + } + + &:active { + background: $ff-indigo-600; + } + } + .header { background: white; flex-shrink: 0; @@ -117,6 +210,8 @@ export default { &.fixed { position: initial; height: 100%; + transition: none; // Disable transition in fixed mode for smooth resizing + box-shadow: none; // Remove shadow when pinned } } diff --git a/frontend/src/components/drawers/expert/ExpertDrawer.vue b/frontend/src/components/drawers/expert/ExpertDrawer.vue index 0883d74786..1dbd6a81a3 100644 --- a/frontend/src/components/drawers/expert/ExpertDrawer.vue +++ b/frontend/src/components/drawers/expert/ExpertDrawer.vue @@ -7,24 +7,55 @@

Expert

+
+ + +
@@ -212,6 +228,9 @@ export default { height: 100%; transition: none; // Disable transition in fixed mode for smooth resizing box-shadow: none; // Remove shadow when pinned + flex-shrink: 0; // Prevent flex from shrinking the drawer below its set width + min-width: unset; // Remove responsive min-width constraint + max-width: none; // Remove responsive max-width constraint } } diff --git a/frontend/src/components/drawers/expert/ExpertDrawer.vue b/frontend/src/components/drawers/expert/ExpertDrawer.vue index 1dbd6a81a3..febab16491 100644 --- a/frontend/src/components/drawers/expert/ExpertDrawer.vue +++ b/frontend/src/components/drawers/expert/ExpertDrawer.vue @@ -45,6 +45,7 @@ export default { LockClosedIcon, LockOpenIcon }, + inject: ['togglePinWithWidth'], data () { return { // Future: Add expert state here @@ -65,12 +66,12 @@ export default { // Example: document.removeEventListener('expert:open', this.handleOpenEvent) }, methods: { - ...mapActions('ux/drawers', ['closeRightDrawer', 'togglePinDrawer']), + ...mapActions('ux/drawers', ['closeRightDrawer']), closeDrawer () { this.closeRightDrawer() }, togglePin () { - this.togglePinDrawer() + this.togglePinWithWidth() } // Future: Handle event-based triggers // handleOpenEvent(event) { From 2c4ed60b9e08619f56d38cf1a3ff2ad5115b44d4 Mon Sep 17 00:00:00 2001 From: dimitrieh Date: Thu, 20 Nov 2025 01:02:02 +0100 Subject: [PATCH 13/45] fix(expert): fix hover state for expert button gradient border The previous hover state tried to change the background gradient but was being overridden by the continuous animation. Changed to increase border width from 1px to 2px on hover with negative margin compensation to prevent button shifting. --- frontend/src/components/ExpertButton.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/ExpertButton.vue b/frontend/src/components/ExpertButton.vue index 9d1161bd93..9accc37ebb 100644 --- a/frontend/src/components/ExpertButton.vue +++ b/frontend/src/components/ExpertButton.vue @@ -45,8 +45,8 @@ export default { animation: gradient-border-rotate 4s linear infinite; &:hover { - background: linear-gradient($ff-grey-100, $ff-grey-100) padding-box, - linear-gradient(135deg, $ff-red-700, #4038d5, $ff-red-700) border-box; + border: 2px solid transparent; + margin: -1px; } } From 8c6f6d4e76e4df7de898e812906525c3c854ebc6 Mon Sep 17 00:00:00 2001 From: dimitrieh Date: Thu, 20 Nov 2025 01:14:28 +0100 Subject: [PATCH 14/45] fix(drawers): enable resizing in both overlay and pinned modes Fixed two issues with drawer resizing: - Resizing now works in overlay mode by removing CSS width constraints during drag - Eliminated grey box at top in pinned mode by resetting top offset to 0 Changes: - Remove conditional rendering of resize handle to show in both modes - Apply custom width when drawer is open, not just when pinned - Add resizing class to disable transitions and width constraints during drag - Change position from initial to relative in fixed mode for proper resize bar positioning - Reset top offset in fixed mode to prevent unwanted gap --- frontend/src/components/drawers/RightDrawer.vue | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/drawers/RightDrawer.vue b/frontend/src/components/drawers/RightDrawer.vue index bc87af57d6..2c08f22333 100644 --- a/frontend/src/components/drawers/RightDrawer.vue +++ b/frontend/src/components/drawers/RightDrawer.vue @@ -2,12 +2,11 @@
@@ -75,7 +74,7 @@ export default { }) }, drawerStyle () { - if (this.rightDrawer.fixed && this.rightDrawer.state) { + if (this.rightDrawer.state) { return { width: `${this.drawerWidth}px` } @@ -224,13 +223,20 @@ export default { } &.fixed { - position: initial; + position: relative; // Changed from initial to relative for resize bar positioning height: 100%; + top: 0; // Reset top offset to prevent gap at top transition: none; // Disable transition in fixed mode for smooth resizing box-shadow: none; // Remove shadow when pinned flex-shrink: 0; // Prevent flex from shrinking the drawer below its set width min-width: unset; // Remove responsive min-width constraint max-width: none; // Remove responsive max-width constraint } + + &.resizing { + transition: none; // Disable transition while actively resizing for smooth dragging + max-width: none !important; // Remove max-width constraint to allow free resizing + min-width: unset !important; // Remove min-width constraint to allow free resizing + } } From 70496d870b59298b4eeec89724ec2ba29f218a6d Mon Sep 17 00:00:00 2001 From: dimitrieh Date: Thu, 20 Nov 2025 01:22:36 +0100 Subject: [PATCH 15/45] enhance(drawers): add transparent resize handle and persistent width - Make resize handle transparent while maintaining functionality - Add width persistence across drawer close/reopen cycles in both modes - Track manual resize state to preserve custom widths - Remove visible hover/active states from resize handle - Apply width constraint removal when manually resized --- .../src/components/drawers/RightDrawer.vue | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/frontend/src/components/drawers/RightDrawer.vue b/frontend/src/components/drawers/RightDrawer.vue index 2c08f22333..fdcf181d2a 100644 --- a/frontend/src/components/drawers/RightDrawer.vue +++ b/frontend/src/components/drawers/RightDrawer.vue @@ -2,7 +2,7 @@
@@ -58,7 +58,8 @@ export default { data () { return { drawerWidth: DRAWER_DEFAULT_WIDTH, - isResizing: false + isResizing: false, + hasManuallyResized: false } }, computed: { @@ -91,7 +92,11 @@ export default { this.closeRightDrawer() } } - isOpen ? window.addEventListener('keydown', onEsc) : window.removeEventListener('keydown', onEsc) + if (isOpen) { + window.addEventListener('keydown', onEsc) + } else { + window.removeEventListener('keydown', onEsc) + } } }, 'rightDrawer.fixed': { @@ -128,6 +133,7 @@ export default { }, startResize (event) { this.isResizing = true + this.hasManuallyResized = true document.addEventListener('mousemove', this.handleResize) document.addEventListener('mouseup', this.stopResize) event.preventDefault() @@ -184,18 +190,13 @@ export default { bottom: 0; width: 6px; cursor: ew-resize; - background: $ff-grey-400; + background: transparent; z-index: 1001; &:hover { - background: $ff-grey-600; width: 8px; left: 0; } - - &:active { - background: $ff-indigo-600; - } } .header { @@ -238,5 +239,10 @@ export default { max-width: none !important; // Remove max-width constraint to allow free resizing min-width: unset !important; // Remove min-width constraint to allow free resizing } + + &.manually-resized { + max-width: none !important; // Keep custom width after manual resize + min-width: unset !important; // Keep custom width after manual resize + } } From a0d93bc4ed3b2fabce938b215ccd23b90c685b9d Mon Sep 17 00:00:00 2001 From: dimitrieh Date: Thu, 20 Nov 2025 01:25:51 +0100 Subject: [PATCH 16/45] fix(drawers): prevent height flash when unpinning Only transition specific properties (right, width, max-width, min-width, box-shadow) instead of all properties. This prevents height, top, and position from animating during unpinning, which was causing the drawer to briefly extend beyond viewport. --- frontend/src/components/drawers/RightDrawer.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/drawers/RightDrawer.vue b/frontend/src/components/drawers/RightDrawer.vue index fdcf181d2a..a74674cd77 100644 --- a/frontend/src/components/drawers/RightDrawer.vue +++ b/frontend/src/components/drawers/RightDrawer.vue @@ -177,7 +177,7 @@ export default { width: 100%; max-width: 0; min-width: 0; - transition: ease-in-out .3s; + transition: right .3s ease-in-out, width .3s ease-in-out, max-width .3s ease-in-out, min-width .3s ease-in-out, box-shadow .3s ease-in-out; box-shadow: -5px 0px 8px rgba(0, 0, 0, 0.1); display: flex; flex-direction: column; From 331778c825df0ce1262e16cfcc43a3faf00449ea Mon Sep 17 00:00:00 2001 From: dimitrieh Date: Thu, 20 Nov 2025 01:28:06 +0100 Subject: [PATCH 17/45] fix(drawers): prevent shadow from bleeding at top of drawer Adjusted box-shadow to use vertical offset and negative spread radius to prevent shadow from appearing at the top of the drawer element while maintaining left-side shadow effect. --- frontend/src/components/drawers/RightDrawer.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/drawers/RightDrawer.vue b/frontend/src/components/drawers/RightDrawer.vue index a74674cd77..949eaa28d1 100644 --- a/frontend/src/components/drawers/RightDrawer.vue +++ b/frontend/src/components/drawers/RightDrawer.vue @@ -178,7 +178,7 @@ export default { max-width: 0; min-width: 0; transition: right .3s ease-in-out, width .3s ease-in-out, max-width .3s ease-in-out, min-width .3s ease-in-out, box-shadow .3s ease-in-out; - box-shadow: -5px 0px 8px rgba(0, 0, 0, 0.1); + box-shadow: -5px 4px 8px -4px rgba(0, 0, 0, 0.1); display: flex; flex-direction: column; overflow: hidden; // Changed from auto to hidden - let child components handle their own scrolling From 49beb5cec49ef6153dda3d709bfec6c3b737f485 Mon Sep 17 00:00:00 2001 From: dimitrieh Date: Thu, 20 Nov 2025 01:43:41 +0100 Subject: [PATCH 18/45] fix(drawers): fix grey box when closing pinned drawer Root cause: closeRightDrawer action had 100ms delay before removing .open class, causing drawer to stay visible as grey box when closing a pinned drawer. Fixes: - Immediately set state.rightDrawer.state = false to remove .open class - Add CSS to hide border when drawer is closed - Add CSS rules for .fixed:not(.open) to hide drawer with width: 0, opacity: 0 - Keep 100ms timeout for full cleanup to allow transitions Tested with Playwright - drawer now closes instantly with no grey box artifact. --- frontend/src/components/drawers/RightDrawer.vue | 17 ++++++++++++++++- frontend/src/store/modules/ux/drawers/index.js | 6 +++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/drawers/RightDrawer.vue b/frontend/src/components/drawers/RightDrawer.vue index 949eaa28d1..248ddb6cb7 100644 --- a/frontend/src/components/drawers/RightDrawer.vue +++ b/frontend/src/components/drawers/RightDrawer.vue @@ -177,12 +177,17 @@ export default { width: 100%; max-width: 0; min-width: 0; - transition: right .3s ease-in-out, width .3s ease-in-out, max-width .3s ease-in-out, min-width .3s ease-in-out, box-shadow .3s ease-in-out; + transition: right .3s ease-in-out, width .3s ease-in-out, max-width .3s ease-in-out, min-width .3s ease-in-out, box-shadow .3s ease-in-out, border-color .3s ease-in-out; box-shadow: -5px 4px 8px -4px rgba(0, 0, 0, 0.1); display: flex; flex-direction: column; overflow: hidden; // Changed from auto to hidden - let child components handle their own scrolling + // Hide border when closed to prevent visible grey line + &:not(.open) { + border-left-color: transparent; + } + .resize-bar { position: absolute; left: 0; @@ -232,6 +237,16 @@ export default { flex-shrink: 0; // Prevent flex from shrinking the drawer below its set width min-width: unset; // Remove responsive min-width constraint max-width: none; // Remove responsive max-width constraint + + // Hide drawer when pinned but closed to prevent grey block + &:not(.open) { + width: 0 !important; + min-width: 0 !important; + max-width: 0 !important; + overflow: hidden; + opacity: 0; + pointer-events: none; + } } &.resizing { diff --git a/frontend/src/store/modules/ux/drawers/index.js b/frontend/src/store/modules/ux/drawers/index.js index b6c3e3ad9f..4d6c5cef59 100644 --- a/frontend/src/store/modules/ux/drawers/index.js +++ b/frontend/src/store/modules/ux/drawers/index.js @@ -138,7 +138,11 @@ const actions = { openDrawer() } }, - closeRightDrawer ({ commit, rootState }) { + closeRightDrawer ({ commit, state, rootState }) { + // Immediately set state to false to hide the drawer + state.rightDrawer.state = false + + // Then wait before full cleanup to allow transition setTimeout(() => { commit('closeRightDrawer') From 784ea277cfc99f56c42d20ce580a5dc54f822b6b Mon Sep 17 00:00:00 2001 From: dimitrieh Date: Thu, 20 Nov 2025 01:46:11 +0100 Subject: [PATCH 19/45] fix(drawers): remove setTimeout from closeRightDrawer action Simplified the close action by removing the 100ms delay and direct state mutation. Now properly commits the mutation immediately, which sets both state and fixed to false, preventing the drawer from reappearing. This follows Vuex best practices and ensures clean, immediate closing. --- frontend/src/store/modules/ux/drawers/index.js | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/frontend/src/store/modules/ux/drawers/index.js b/frontend/src/store/modules/ux/drawers/index.js index 4d6c5cef59..2aa6e58769 100644 --- a/frontend/src/store/modules/ux/drawers/index.js +++ b/frontend/src/store/modules/ux/drawers/index.js @@ -138,18 +138,12 @@ const actions = { openDrawer() } }, - closeRightDrawer ({ commit, state, rootState }) { - // Immediately set state to false to hide the drawer - state.rightDrawer.state = false - - // Then wait before full cleanup to allow transition - setTimeout(() => { - commit('closeRightDrawer') + closeRightDrawer ({ commit, rootState }) { + commit('closeRightDrawer') - if (rootState.ux.overlay) { - commit('ux/closeOverlay', null, { root: true }) - } - }, 100) + if (rootState.ux.overlay) { + commit('ux/closeOverlay', null, { root: true }) + } }, /** From a73e9296b721a6ee989d88e4feaf1f814d2ec841 Mon Sep 17 00:00:00 2001 From: dimitrieh Date: Thu, 20 Nov 2025 02:20:59 +0100 Subject: [PATCH 20/45] fix(drawers): attempt to fix pinned drawer close bug with closing flag BUG STILL PRESENT: When closing a pinned and resized Expert drawer (e.g., 600px wide), the drawer automatically reopens shortly after clicking the close button. The drawer reopens with the large resized width, suggesting something is triggering openRightDrawer/openAssistantDrawer during the 300ms closing transition. This commit attempts to fix by: - Adding a 'closing' flag to prevent drawer opens during transition - Using two-step close: immediate state=false, then delayed full cleanup - Preserving .fixed class during transition for CSS rule .fixed:not(.open) The closeRightDrawer guard should block reopens, but the bug persists in both overlay and pinned modes. Root cause of what triggers the reopen is still unknown and needs further investigation. Suspected triggers: - Route watcher in App.vue calling updateRoute - Component lifecycle hooks (unmount/mount) - Event bubbling or click handlers - Vuex subscription or plugin side effects --- .../src/store/modules/ux/drawers/index.js | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/frontend/src/store/modules/ux/drawers/index.js b/frontend/src/store/modules/ux/drawers/index.js index 2aa6e58769..fe7304ccdd 100644 --- a/frontend/src/store/modules/ux/drawers/index.js +++ b/frontend/src/store/modules/ux/drawers/index.js @@ -20,6 +20,7 @@ const initialState = () => ({ fixed: false, closeOnClickOutside: true, pinned: false, + closing: false, props: {}, on: {}, bind: {} @@ -51,6 +52,11 @@ const mutations = { state.rightDrawer.on = on state.rightDrawer.bind = bind }, + closeRightDrawerImmediate (state) { + // ONLY set state to false - keep everything else for CSS transition + // This matches the original working version from commit 49beb5cec + state.rightDrawer.state = false + }, closeRightDrawer (state) { state.rightDrawer.state = false state.rightDrawer.wider = false @@ -112,6 +118,9 @@ const actions = { bind = {}, overlay = false }) { + // Don't allow opening while drawer is currently closing + if (state.rightDrawer.closing) return + if (state.rightDrawer.state && component.name === state.rightDrawer.component.name) return const openDrawer = () => { @@ -138,12 +147,28 @@ const actions = { openDrawer() } }, - closeRightDrawer ({ commit, rootState }) { - commit('closeRightDrawer') + closeRightDrawer ({ commit, state, rootState }) { + // Set closing flag to prevent reopens during transition + state.rightDrawer.closing = true + // Immediately hide drawer by removing .open class + commit('closeRightDrawerImmediate') + + // Close overlay if present if (rootState.ux.overlay) { commit('ux/closeOverlay', null, { root: true }) } + + // Wait for CSS transition (300ms) before full cleanup + // This allows .fixed:not(.open) CSS rule to apply for pinned drawers + setTimeout(() => { + // Only do full cleanup if drawer is still closed + if (!state.rightDrawer.state) { + commit('closeRightDrawer') + } + // Clear closing flag + state.rightDrawer.closing = false + }, 300) }, /** From 79de97e34c24f83e32232f073763017ca8e3fcbc Mon Sep 17 00:00:00 2001 From: cstns Date: Thu, 20 Nov 2025 10:30:37 +0200 Subject: [PATCH 21/45] qf lint import order --- frontend/src/components/drawers/expert/ExpertDrawer.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/drawers/expert/ExpertDrawer.vue b/frontend/src/components/drawers/expert/ExpertDrawer.vue index febab16491..2e05625b65 100644 --- a/frontend/src/components/drawers/expert/ExpertDrawer.vue +++ b/frontend/src/components/drawers/expert/ExpertDrawer.vue @@ -33,8 +33,9 @@ diff --git a/frontend/src/components/expert/resources/PackageResourceCard.vue b/frontend/src/components/expert/resources/PackageResourceCard.vue index 9621014af8..ab24622e1f 100644 --- a/frontend/src/components/expert/resources/PackageResourceCard.vue +++ b/frontend/src/components/expert/resources/PackageResourceCard.vue @@ -29,12 +29,12 @@ export default { }, methods: { getPackageName (pkg) { - // Handle both object format {name: "..."} and string format - return typeof pkg === 'object' ? pkg.name : pkg + // Handle both object format {id: "..." or name: "..."} and string format + return typeof pkg === 'object' ? (pkg.id || pkg.name) : pkg }, getPackageUrl (pkg) { const packageName = this.getPackageName(pkg) - return `https://flows.nodered.org/node/${packageName}` + return `https://flows.nodered.org/package/${packageName}` }, addUTMTracking (url) { try { From f1ff71ef73066152349403e198c7ba4648b8256e Mon Sep 17 00:00:00 2001 From: dimitrieh Date: Thu, 20 Nov 2025 13:26:50 +0100 Subject: [PATCH 33/45] feat(expert): align package icon positioning with resource cards Match PackageResourceCard icon alignment to StandardResourceCard by using flex-start alignment with top margin offset. --- .../src/components/expert/resources/PackageResourceCard.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/expert/resources/PackageResourceCard.vue b/frontend/src/components/expert/resources/PackageResourceCard.vue index ab24622e1f..5c8b5c4132 100644 --- a/frontend/src/components/expert/resources/PackageResourceCard.vue +++ b/frontend/src/components/expert/resources/PackageResourceCard.vue @@ -59,7 +59,7 @@ export default { diff --git a/frontend/src/components/expert/resources/PackageResourceCard.vue b/frontend/src/components/expert/resources/PackageResourceCard.vue index 5c8b5c4132..fe4a6ccb72 100644 --- a/frontend/src/components/expert/resources/PackageResourceCard.vue +++ b/frontend/src/components/expert/resources/PackageResourceCard.vue @@ -68,7 +68,6 @@ export default { text-decoration: none; color: $ff-grey-900; transition: all 0.2s ease; - height: 4rem; &:hover { border-color: $ff-indigo-300; From 7078d000ef856bc470d2071556898f842996c37c Mon Sep 17 00:00:00 2001 From: dimitrieh Date: Thu, 20 Nov 2025 14:02:22 +0100 Subject: [PATCH 35/45] fix(expert): correct badge colors to match website styling - Use $ff-indigo-100 instead of #EEF2FF (which was indigo-50) - Use $ff-indigo-700 variable for consistency - Aligns Setup Guide badge colors with website implementation --- frontend/src/components/expert/ExpertRichGuide.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/expert/ExpertRichGuide.vue b/frontend/src/components/expert/ExpertRichGuide.vue index aae912cc49..66974c7737 100644 --- a/frontend/src/components/expert/ExpertRichGuide.vue +++ b/frontend/src/components/expert/ExpertRichGuide.vue @@ -93,8 +93,8 @@ export default { span { display: inline-block; padding: 0.5rem 0.75rem; // py-2 px-3 - background-color: #EEF2FF; // bg-indigo-100 - color: #4338CA; // text-indigo-700 + background-color: $ff-indigo-100; + color: $ff-indigo-700; font-size: 0.875rem; // text-sm border-radius: 9999px; // rounded-full } From 696287698dcacb9469b9b05b44eb33247acaa251 Mon Sep 17 00:00:00 2001 From: dimitrieh Date: Thu, 20 Nov 2025 14:17:54 +0100 Subject: [PATCH 36/45] feat(expert): hide expert button when drawer is open - Add isExpertDrawerOpen computed property to detect when expert drawer is active - Use v-if to completely remove button from DOM when drawer is open - Prevents navigation divider artifact by removing element entirely --- frontend/src/components/ExpertButton.vue | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/ExpertButton.vue b/frontend/src/components/ExpertButton.vue index 9accc37ebb..90a4485f46 100644 --- a/frontend/src/components/ExpertButton.vue +++ b/frontend/src/components/ExpertButton.vue @@ -1,5 +1,5 @@