Skip to content

v3.10.1

Choose a tag to compare

@Amrrx Amrrx released this 06 Sep 19:22
· 33 commits to main since this release
1ba8d86
feat(bubble): free-drag button and sidebar layout mode (v3.10.0) (#2)

* feat(bubble): free-drag button and sidebar layout mode (v3.10.0)

Button drag was horizontal-only; extend it to both axes (mouse and
touch) so it can be repositioned anywhere on screen, clamped to the
viewport.

Add an opt-in theme.chatWindow.layout: 'sidebar' mode that docks the
chat panel to the right edge, full height, instead of floating near
the button (default 'floating' behavior is unchanged). Since the
widget renders in a Shadow DOM custom element and cannot resize the
host page itself, it dispatches a `flowise-sidebar-toggle` CustomEvent
on the host element with { open, width } so the embedding page can
push its own layout aside, similar to devtools. Sidebar mode only
applies at >=768px viewport width; narrower screens keep the floating
overlay.

* fix(bubble): flatten sidebar title corners, sync tooltip drag timing

Bot.tsx always rounded its title bar's top corners by 20px unless
isFullPage was passed; Bubble.tsx never passed it, so sidebar mode
inherited the floating-card rounding on its inner title bar even
though the outer panel was already square, leaving a rounded notch
at the top. Reuse the existing isFullPage flag in sidebar mode, and
add a matching left border for a clearer edge against the pushed
page.

Also fix the tooltip visually leading the button during drag: the
button eases position changes via a 200ms transition, but the
tooltip's right/bottom had no transition at all and jumped instantly
on every drag frame. Give it the same 200ms easing.

* feat(bubble): host-controlled launcher, theme color pass-through

Add theme.button.hideLauncher to suppress the built-in floating
button/tooltip entirely, and listen for a 'flowise-toggle' CustomEvent
on the host element so a host page's own trigger (e.g. a native
toolbar icon) can open/close the panel externally. Combined with the
existing 'flowise-sidebar-toggle' event, a host button can both
control and reflect the panel's open state.

Add an optional theme.themeColor: used as a single accent-color
fallback for the button, chat title, user message bubble, and send
button wherever a more specific color isn't set — lets a host app
pass its own brand color instead of needing to duplicate it across
every individual color field.

Also darken the sidebar's left border from a barely-visible
rgba(0,0,0,0.08) to a visible gray, per feedback that it wasn't
noticeable enough as a panel edge.

* feat(bubble): configurable title height and sidebar border/shadow

Add theme.chatWindow.titleHeight so a host app can match the chat
panel's title bar to its own header height (also adjusts the message
list's top padding to keep it in sync); defaults to 56px, unchanged
from before.

Add theme.chatWindow.sidebarBorderWidth/sidebarBorderColor/
sidebarBoxShadow (sidebar-mode only) so a host app can match its own
design system for the panel's left edge instead of the built-in
defaults.

* feat(bubble): sidebar layout mode and host-controlled launcher (v3.10.0)

Adds an opt-in docked layout for the bubble embed, for host apps that want
the assistant to sit beside their content rather than float over it.

Sidebar mode (`chatWindow.layout: 'sidebar'`) pins the panel to the right
edge at full height and emits a `flowise-sidebar-toggle` event carrying the
occupied width, so the host can push its own layout aside. The widget renders
inside a Shadow DOM custom element and cannot reflow the host page itself, so
the width has to cross that boundary as data. The event is dispatched on
`document` rather than the host element: by the time Solid runs cleanup the
element is already detached, and a bubbling event from a detached node would
never reach a document-level listener, leaving the host permanently indented
after `destroy()`. The docked width is clamped to the viewport so the number
the host receives always matches the panel that was drawn. Below 768px the
panel reverts to the floating overlay, since a dock leaves too little room.

`button.hideLauncher` suppresses the built-in button and tooltip for hosts
that supply their own trigger, which they wire up by dispatching a
`flowise-toggle` event on the `<flowise-chatbot>` element. Auto-open moves
from BubbleButton up into Bubble as part of this: it governs Bubble's own
state, and leaving it in a component that gets conditionally unmounted for
presentational reasons silently disabled `autoWindowOpen` whenever the
launcher was hidden.

Square corners in sidebar mode go through a dedicated `squareCorners` prop
rather than reusing `isFullPage`. That flag is not cosmetic — it also hides
the disclaimer's deny button and halves audio preview widths — so a docked,
dismissible panel would have lost its Cancel button.

Theme values are read through accessor functions rather than snapshotted
into consts during setup. `theme` is a reactive prop and `init()` re-assigns
it on an already-mounted element, so a snapshot would leave the panel showing
the first theme forever.

Also adds `themeColor` as a single accent fallback for the launcher and send
button, and `chatWindow.titleHeight` for hosts matching their own header
height. Both leave existing styling untouched when unset.

Covered by tests/sidebar-mode.spec.ts, which drives a host page through the
public embed API with no backend required.

* chore(demo): refresh dev page title and token

Updates the local development page: retitles it for the host app and
refreshes the expired login_as token. The previous token had a stray
non-ASCII character appended to its signature, which made the value
invalid as an HTTP header and stopped the /stream connection from
opening at all.

* fix: reconnect the event stream when the session id changes (v3.10.1)

Reset mints a new session id but the SSE connection stayed bound to the old one.
The reconnect guard in useAgUiStream keyed only on userId, so a reset returned
early, and the id is read from localStorage, which is not reactive -- nothing
could have re-run the effect anyway.

This matters because the server publishes session-scoped events (HITL confirm
cards, progress) on events:{user}:{agent}:{session} and the stream subscribes to
that channel at connect time. After a reset the two no longer match, and Redis
discards a publish that has no subscribers, so confirm cards silently reached
nobody and every gated tool timed out for the rest of the connection.

chatSession now owns a session generation signal bumped by resetSessionId, and
the stream effect tracks it while comparing the connected session id. clearChat
goes through resetSessionId rather than clearing localStorage directly, so the
single owner of the identifier is also the one announcing that it changed.

---------

Co-authored-by: samy <samy.ahmed@afaqy.com>
Co-authored-by: Amrxx <amrahmed2089@gmail.com>