Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…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 评估是否已经完成了任务中要求和所有开发,并且已经集成到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>
…ny casts 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>
The floating chatbot is now integrated into the console application in commit What was done:
Remaining items not yet implemented (could be follow-up issues):
|
There was a problem hiding this comment.
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
ChatbotSchemawith floating-related fields and exportsFloatingChatbotConfig. - Implements floating chatbot UI (provider/trigger/panel + portal-based orchestrator) and registers a new
chatbot-floatingcomponent type. - Integrates the floating chatbot into
apps/consoleand 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.externalnow includesreact/jsx-runtime, butoutput.globalsdoesn’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 aglobalsentry forreact/jsx-runtime(consistent with other packages) or switchexternalto a function that matchesreact*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',
},
},
| /** | ||
| * 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; |
There was a problem hiding this comment.
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.
| 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; |
There was a problem hiding this comment.
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.
| { name: 'className', type: 'string', label: 'CSS Class' }, | ||
| ], | ||
| defaultProps: { | ||
| displayMode: 'floating', |
There was a problem hiding this comment.
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.
| displayMode: 'floating', |
| const { | ||
| position = "bottom-right", | ||
| defaultOpen = false, | ||
| panelWidth = 400, | ||
| panelHeight = 520, | ||
| title = "Chat", | ||
| triggerSize = 56, | ||
| } = floatingConfig ?? {} |
There was a problem hiding this comment.
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.
| 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) | ||
| } | ||
| } | ||
| }, []) |
There was a problem hiding this comment.
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.
| 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" /> | ||
| )} |
There was a problem hiding this comment.
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.
| <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" | ||
| > |
There was a problem hiding this comment.
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.
| */ | ||
|
|
||
| import '@testing-library/jest-dom'; | ||
| import { describe, it, expect, vi } from 'vitest'; |
There was a problem hiding this comment.
Unused import: vi is imported but never referenced in this test file. Remove it to avoid lint/TypeScript unused-import failures in stricter configurations.
| import { describe, it, expect, vi } from 'vitest'; | |
| import { describe, it, expect } from 'vitest'; |
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)ChatbotSchemawithdisplayMode: 'inline' | 'floating'andfloatingConfig: FloatingChatbotConfigFloatingChatbotConfiginterface:position,defaultOpen,panelWidth,panelHeight,title,triggerIcon,triggerSizeComponents (
@object-ui/plugin-chatbot)FloatingChatbotProvider— React context managingisOpen/isFullscreenstate; exposesuseFloatingChatbot()hook for programmatic controlFloatingChatbotTrigger— Fixed-position circular FAB with configurable corner and sizeFloatingChatbotPanel— Overlay panel with header (title, fullscreen toggle, close),role="dialog", configurable dimensionsFloatingChatbot— Orchestrator rendering viaReactDOM.createPortalto#floating-chatbot-portalto avoid z-index conflicts; wrapsChatbotEnhancedchatbot-floatinginComponentRegistryConsole Integration (
@object-ui/console)ConsoleFloatingChatbottoConsoleLayout.tsxinsideAppShell, making the FAB available on every authenticated pageuseObjectChatfor metadata-aware auto-responses — injects current app name and object list into chatbot contextapiendpoint is configuredUsage
Schema-driven:
Composable:
Tests
Other
react/jsx-runtimeto vite externals for SSR compatibility