Skip to content

feat(plugin-chatbot): Airtable-style floating chatbot FAB widget with console integration#1156

Merged
hotlong merged 4 commits intomainfrom
copilot/add-floating-chatbot-widget
Mar 31, 2026
Merged

feat(plugin-chatbot): Airtable-style floating chatbot FAB widget with console integration#1156
hotlong merged 4 commits intomainfrom
copilot/add-floating-chatbot-widget

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 31, 2026

Adds a floating action button (FAB) chatbot widget that renders as a fixed-position trigger button opening a chat panel overlay via React portal — enabling chatbot access from any page without occupying layout space. Integrated into the console application so the FAB is available on every authenticated page with metadata-aware context.

Types (@object-ui/types)

  • Extended ChatbotSchema with displayMode: 'inline' | 'floating' and floatingConfig: FloatingChatbotConfig
  • New FloatingChatbotConfig interface: position, defaultOpen, panelWidth, panelHeight, title, triggerIcon, triggerSize

Components (@object-ui/plugin-chatbot)

  • FloatingChatbotProvider — React context managing isOpen/isFullscreen state; exposes useFloatingChatbot() hook for programmatic control
  • FloatingChatbotTrigger — Fixed-position circular FAB with configurable corner and size
  • FloatingChatbotPanel — Overlay panel with header (title, fullscreen toggle, close), role="dialog", configurable dimensions
  • FloatingChatbot — Orchestrator rendering via ReactDOM.createPortal to #floating-chatbot-portal to avoid z-index conflicts; wraps ChatbotEnhanced
  • Registered as chatbot-floating in ComponentRegistry

Console Integration (@object-ui/console)

  • Added ConsoleFloatingChatbot to ConsoleLayout.tsx inside AppShell, making the FAB available on every authenticated page
  • Wired with useObjectChat for metadata-aware auto-responses — injects current app name and object list into chatbot context
  • Demo auto-response mode by default; switchable to API streaming when an api endpoint is configured

Usage

Schema-driven:

const schema: ChatbotSchema = {
  type: 'chatbot',
  displayMode: 'floating',
  floatingConfig: {
    position: 'bottom-right',
    defaultOpen: false,
    panelWidth: 400,
    panelHeight: 520,
    title: 'Assistant',
  },
  messages: [],
  autoResponse: true,
};

Composable:

<FloatingChatbotProvider defaultOpen={false}>
  <FloatingChatbotTrigger position="bottom-right" />
  <FloatingChatbotPanel title="Assistant" width={400} height={520}>
    <ChatbotEnhanced {...chatProps} />
  </FloatingChatbotPanel>
</FloatingChatbotProvider>

Tests

  • 21 new tests (7 provider state/hook, 14 trigger+panel interaction/a11y)
  • All 66 plugin-chatbot tests pass

Other

  • Added react/jsx-runtime to vite externals for SSR compatibility

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 31, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
objectui-demo Ready Ready Preview, Comment Mar 31, 2026 7:55am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectui Ignored Ignored Mar 31, 2026 7:55am

Request Review

…trigger, panel, and portal rendering

Agent-Logs-Url: https://github.com/objectstack-ai/objectui/sessions/923bf2a3-3b00-4623-bcf5-7b90c8feaa6b

Co-authored-by: xuyushun441-sys <255036401+xuyushun441-sys@users.noreply.github.com>
Copilot AI changed the title [WIP] Add Airtable-style floating chatbot widget feat(plugin-chatbot): Airtable-style floating chatbot FAB widget Mar 31, 2026
Copilot AI requested a review from xuyushun441-sys March 31, 2026 07:45
@hotlong
Copy link
Copy Markdown
Contributor

hotlong commented Mar 31, 2026

@copilot 评估是否已经完成了任务中要求和所有开发,并且已经集成到console 控制台中?

… metadata-aware context

Agent-Logs-Url: https://github.com/objectstack-ai/objectui/sessions/e0efdafc-aeb8-4dcc-859c-f5d6d07a2879

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 31, 2026

@copilot 评估是否已经完成了任务中要求和所有开发,并且已经集成到console 控制台中?

The floating chatbot is now integrated into the console application in commit 219ff3f.

What was done:

  • Plugin layer (@object-ui/plugin-chatbot): FloatingChatbot, FloatingChatbotPanel, FloatingChatbotTrigger, FloatingChatbotProvider components + useFloatingChatbot hook + chatbot-floating ComponentRegistry entry + 21 tests
  • Types (@object-ui/types): ChatbotSchema.displayMode + FloatingChatbotConfig interface
  • Console integration (apps/console/src/components/ConsoleLayout.tsx): Added ConsoleFloatingChatbot using useObjectChat — the FAB appears on every authenticated page with metadata-aware context (app name and object list injected into auto-responses)

Remaining items not yet implemented (could be follow-up issues):

  • Drag-to-reposition panel
  • Panel conversation history button
  • Storybook stories
  • Full documentation page

Copilot AI changed the title feat(plugin-chatbot): Airtable-style floating chatbot FAB widget feat(plugin-chatbot): Airtable-style floating chatbot FAB widget with console integration Mar 31, 2026
Copilot AI requested a review from hotlong March 31, 2026 07:57
@hotlong hotlong marked this pull request as ready for review March 31, 2026 08:00
Copilot AI review requested due to automatic review settings March 31, 2026 08:00
@hotlong hotlong merged commit b202027 into main Mar 31, 2026
5 checks passed
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a floating (FAB-triggered) chatbot experience to @object-ui/plugin-chatbot, exposes related schema/types in @object-ui/types, and integrates the floating chatbot globally into the Console app layout.

Changes:

  • Extends ChatbotSchema with floating-related fields and exports FloatingChatbotConfig.
  • Implements floating chatbot UI (provider/trigger/panel + portal-based orchestrator) and registers a new chatbot-floating component type.
  • Integrates the floating chatbot into apps/console and updates build config / changelog / tests.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
packages/types/src/index.ts Re-exports FloatingChatbotConfig from types package entrypoint.
packages/types/src/complex.ts Extends ChatbotSchema with floating mode fields and defines FloatingChatbotConfig.
packages/plugin-chatbot/vite.config.ts Updates Rollup externals to include react/jsx-runtime.
packages/plugin-chatbot/src/renderer.tsx Registers chatbot-floating in the ComponentRegistry and defines its manifest metadata.
packages/plugin-chatbot/src/index.tsx Exports floating chatbot components/hooks from the plugin package.
packages/plugin-chatbot/src/FloatingChatbotTrigger.tsx Adds FAB trigger button component.
packages/plugin-chatbot/src/FloatingChatbotProvider.tsx Adds context provider + useFloatingChatbot() hook for open/fullscreen state.
packages/plugin-chatbot/src/FloatingChatbotPanel.tsx Adds floating dialog-like panel UI with header controls.
packages/plugin-chatbot/src/FloatingChatbot.tsx Adds portal-based orchestrator wrapping ChatbotEnhanced in floating UI.
packages/plugin-chatbot/src/tests/FloatingChatbotWidgets.test.tsx Adds trigger/panel interaction and basic a11y assertions.
packages/plugin-chatbot/src/tests/FloatingChatbotProvider.test.tsx Adds provider/hook state tests.
CHANGELOG.md Documents new floating chatbot capability and schema fields.
apps/console/src/components/ConsoleLayout.tsx Integrates floating chatbot globally for authenticated console pages.
Comments suppressed due to low confidence (1)

packages/plugin-chatbot/vite.config.ts:46

  • rollupOptions.external now includes react/jsx-runtime, but output.globals doesn’t map it. If this package emits a UMD build, consumers loading it via script tags may hit an undefined global for the JSX runtime. Add a globals entry for react/jsx-runtime (consistent with other packages) or switch external to a function that matches react* subpath imports and relies on ESM-only output.
    rollupOptions: {
      external: ['react', 'react/jsx-runtime', 'react-dom', '@object-ui/components', '@object-ui/core', '@object-ui/react', 'lucide-react'],
      output: {
        globals: {
          react: 'React',
          'react-dom': 'ReactDOM',
          '@object-ui/components': 'ObjectUIComponents',
          '@object-ui/core': 'ObjectUICore',
          '@object-ui/react': 'ObjectUIReact',
          'lucide-react': 'LucideReact',
        },
      },

Comment on lines +544 to +555
/**
* Display mode for the chatbot.
* - `'inline'` (default): Embedded in the page flow.
* - `'floating'`: Rendered as a floating action button (FAB) that opens a panel overlay.
*/
displayMode?: 'inline' | 'floating';

/**
* Configuration for floating display mode.
* Only used when `displayMode` is `'floating'`.
*/
floatingConfig?: FloatingChatbotConfig;
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

displayMode/floatingConfig are added to ChatbotSchema, but there’s no implementation that uses displayMode to select floating vs inline rendering (a repo-wide search only finds this field in type/manifest metadata). Either wire displayMode === 'floating' into the existing 'chatbot' renderer/component selection, or remove displayMode to avoid a misleading public API.

Copilot uses AI. Check for mistakes.
Comment on lines +586 to +596
title?: string;
/**
* Custom icon name for the FAB trigger (Lucide icon name).
* @default 'MessageCircle'
*/
triggerIcon?: string;
/**
* Custom size for the FAB trigger button in pixels.
* @default 56
*/
triggerSize?: number;
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FloatingChatbotConfig.triggerIcon is documented as configurable (Lucide icon name), but there is no usage of triggerIcon anywhere in @object-ui/plugin-chatbot (the trigger always renders MessageCircle). Either implement support for triggerIcon (and validate/limit allowed values) or remove it from the public config to keep the types/docs accurate.

Copilot uses AI. Check for mistakes.
{ name: 'className', type: 'string', label: 'CSS Class' },
],
defaultProps: {
displayMode: 'floating',
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The chatbot-floating manifest exposes a displayMode input/default, but the component type is already specific to the floating variant and displayMode is not used in rendering. This is likely to confuse schema authors and tooling. Consider removing displayMode from the chatbot-floating manifest inputs/defaultProps, or (preferably) making displayMode functional in the base chatbot renderer and deprecating the separate type.

Suggested change
displayMode: 'floating',

Copilot uses AI. Check for mistakes.
Comment on lines +33 to +40
const {
position = "bottom-right",
defaultOpen = false,
panelWidth = 400,
panelHeight = 520,
title = "Chat",
triggerSize = 56,
} = floatingConfig ?? {}
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FloatingChatbotConfig includes triggerIcon, but FloatingChatbot doesn’t read or pass any icon configuration down to the trigger. As a result, schema-driven triggerIcon changes will have no effect. Either plumb triggerIcon through to FloatingChatbotTrigger (and render the selected icon), or drop the option from the config.

Copilot uses AI. Check for mistakes.
Comment on lines +44 to +60
React.useEffect(() => {
// Create a portal root so the floating UI sits outside the normal DOM tree
let container = document.getElementById("floating-chatbot-portal")
if (!container) {
container = document.createElement("div")
container.id = "floating-chatbot-portal"
document.body.appendChild(container)
}
setPortalContainer(container)

return () => {
// Only remove if we created it and it's still in the DOM
if (container && container.parentNode && !container.hasChildNodes()) {
container.parentNode.removeChild(container)
}
}
}, [])
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The portal root creation/removal logic is a key behavior of FloatingChatbot (DOM insertion into #floating-chatbot-portal, cleanup on unmount), but there are no unit tests covering it. Add tests asserting that the portal container is created when missing, that content renders inside it, and that the container is not removed while still hosting children.

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +52
import { Button } from "@object-ui/components"
import { MessageCircle, X } from "lucide-react"
import { useFloatingChatbot } from "./FloatingChatbotProvider"

export interface FloatingChatbotTriggerProps {
/** Position of the FAB */
position?: "bottom-right" | "bottom-left"
/** Size of the trigger button in pixels */
size?: number
/** Custom className */
className?: string
}

/**
* Floating Action Button (FAB) trigger for the chatbot.
* Renders a circular button fixed to the viewport corner.
*/
export function FloatingChatbotTrigger({
position = "bottom-right",
size = 56,
className,
}: FloatingChatbotTriggerProps) {
const { isOpen, toggle } = useFloatingChatbot()

return (
<Button
onClick={toggle}
className={cn(
"fixed z-50 rounded-full shadow-lg transition-transform hover:scale-105",
position === "bottom-right" ? "right-6 bottom-6" : "left-6 bottom-6",
className
)}
style={{ width: size, height: size }}
size="icon"
aria-label={isOpen ? "Close chat" : "Open chat"}
data-testid="floating-chatbot-trigger"
>
{isOpen ? (
<X className="h-6 w-6" />
) : (
<MessageCircle className="h-6 w-6" />
)}
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The trigger currently hardcodes the open-state icon to MessageCircle/X and doesn’t accept any icon prop. This makes FloatingChatbotConfig.triggerIcon (and future customization) impossible to implement without changing this component API. Consider adding a triggerIcon/icon prop (e.g., React.ReactNode or a constrained icon-name union) and using it here.

Copilot uses AI. Check for mistakes.
Comment on lines +52 to +66
<div
className={cn(
"fixed z-50 flex flex-col rounded-lg border bg-background shadow-xl overflow-hidden transition-all",
isFullscreen
? "inset-0 rounded-none"
: position === "bottom-right"
? "right-6 bottom-20"
: "left-6 bottom-20",
className
)}
style={panelStyle}
role="dialog"
aria-label={title}
data-testid="floating-chatbot-panel"
>
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This panel is presented as a dialog (role="dialog") but is missing common modal dialog accessibility hooks (e.g., aria-modal="true", focus management, and an Escape-key close handler). Consider using the existing Radix/Shadcn Dialog/Sheet primitives (or replicating their behavior) so keyboard and screen-reader users can reliably interact with the overlay.

Copilot uses AI. Check for mistakes.
*/

import '@testing-library/jest-dom';
import { describe, it, expect, vi } from 'vitest';
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import: vi is imported but never referenced in this test file. Remove it to avoid lint/TypeScript unused-import failures in stricter configurations.

Suggested change
import { describe, it, expect, vi } from 'vitest';
import { describe, it, expect } from 'vitest';

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: Airtable-style Floating Chatbot (FAB Widget)

4 participants