Storybook visual stories for the `EmbeddableChat` component, covering new-user, returning-user, loading, error, and agent-mode states using mocked runtimes and NATS chat adapters. ## Key Components | Export / Identifier | Purpose | |---|---| | `createMockRuntime()` | Builds a minimal `ChatRuntime` with stub endpoints (no real server calls) | | `createMockMingoConfig()` | Base NATS adapter config; `getNatsWsUrl` returns `null` to keep WS idle | | `createMockMingoConfigWithDialogs()` | Extends base config with a paginated dialog history, rename/archive callbacks, and archived dialog support | | `createMockMingoConfigChatsLoading()` | Pins `isDialogsLoading: true` via a never-settling `fetchDialogs` promise | | `createMockMingoConfigChatLoading()` | Resolves the dialog list but pins message loading via a never-settling `fetchDialogMessages` | | `createMockMingoConfigChatsError()` | Rejects `fetchDialogs` to exercise the load-error + retry UI path | | `createMockMingoConfigArchiveEmpty()` | Resolves an empty archived dialogs page to render the archive empty state | | `SAMPLE_DIALOGS` | Eight canned `DialogItem` entries representing a returning user's chat history | | `SAMPLE_QUICK_ACTIONS` | Five `MingoQuickAction` chips passed to `EmbeddableChat` for the welcome view | | `FAE_AGENT_CONFIG` | Mocked `/api/ai-agents/fae` response for agent-mode quick-action chip rendering | | `COMMANDS_URL` / `COMMANDS_PREFIX` | Constants shared between the runtime mock and the `fetch` shim for slash-command stubs | ## Usage Example ```typescript // Wrap EmbeddableChat in the required providers for a story function MemoizedRuntime({ children }: { children: React.ReactNode }) { const runtime = useMemo(() => createMockRuntime(), []) const queryClient = useMemo(() => new QueryClient(), []) return ( {children} ) } // Returning-user story with dialog history export const ReturningUser: StoryObj = { render: () => ( ), play: async ({ canvasElement }) => { const canvas = within(canvasElement) await userEvent.click(canvas.getByRole('button', { name: /history/i })) }, } ``` ## Notes - The `pending()` helper (`new Promise(() => {})`) is the idiomatic way to freeze a loading state in Storybook without fake timers. - The `fetch` shim intercepts `COMMANDS_URL` and `AI_AGENT_CONFIG_PREFIX` requests so agent-mode and slash-command UI renders without a live backend. - Source: [`EmbeddableChat.stories.tsx`](https://github.com/flamingo-stack/openframe-oss-lib/blob/main/EmbeddableChat.stories.tsx)