import type { Meta, StoryObj } from '@storybook/nextjs-vite'; import type React from 'react'; import { ApprovalBatchMessage } from '../components/chat/approval-batch-message'; import type { ApprovalBatchData, PendingToolCallData } from '../components/chat/types'; /** * CLIENT (end-user Fae desktop app) variant of the approval block — Figma * node 203-11947 ("fae-approval-block"). * * Same component and props as the Admin card, driven by `variant="client"`. * The end client sees ONLY the BE-generated title plus the Approve/Reject * buttons, or the full-text resolved pill ("Approved by Michael Johnson"). * Commands, scripts, expandable args/results and execution icons are never * rendered in this variant. */ const LONG_COMMAND = `Get-CimInstance Win32_Process | Select-Object ProcessId, Name, Path, CommandLine | Where-Object { $_.Path -like 'C:\\Users\\Public\\*' }`; const REQUEST_ID = 'req-1'; const toolCall: PendingToolCallData = { toolExecutionRequestId: REQUEST_ID, toolName: 'run_script', toolTitle: 'Run Script', // BE-generated human-readable title — the ONLY content the client sees. toolExplanation: "Collects today's system, application, and security event logs and exports them to a CSV file.", toolType: 'OPENFRAME_RMM', requiresApproval: true, approvalType: 'CLIENT', toolCallArguments: { command: LONG_COMMAND, RunAsUser: 'False', timeoutSeconds: 60, }, }; const makeData = (): ApprovalBatchData => ({ approvalRequestId: 'batch-1', approvalType: 'CLIENT', toolCalls: [toolCall], }); const plainDecorator = (width?: number) => // Named function expression: Storybook renders decorators as components, so // the name is what shows up in the React tree instead of `Anonymous`. function PlainDecorator(Story: React.ComponentType) { return (
); }; const meta = { title: 'Chat/Client/ApprovalBatchMessage', component: ApprovalBatchMessage, tags: ['autodocs'], args: { variant: 'client' }, parameters: { docs: { description: { component: "CLIENT (Fae end-user) approval block — title-only card with Approve/Reject or a full-text status pill. Commands/scripts are never shown. Gated by variant='client' (Figma 203-11947).", }, }, }, decorators: [plainDecorator()], } satisfies Meta; export default meta; type Story = StoryObj; /** Pending — title + Approve / Reject buttons. No expandable command. */ export const Pending: Story = { args: { data: makeData(), status: 'pending', onApprove: () => {}, onReject: () => {}, }, }; /** Approved — full-text green status pill. */ export const Approved: Story = { args: { data: makeData(), status: 'approved', resolvedByName: 'Michael Johnson', }, }; /** Rejected by a user — full-text red status pill. */ export const Rejected: Story = { args: { data: makeData(), status: 'rejected', resolvedByName: 'Michael Johnson', }, }; /** Cancelled — full-text grey status pill. */ export const Cancelled: Story = { args: { data: makeData(), status: 'cancelled', resolvedByName: 'Michael Johnson', }, }; /** * All states side by side — mirrors the Figma CLIENT approval-block frames * (1-6575 / 1-6621 / 1-6637 / 1-6653). */ export const AllStates: Story = { decorators: [plainDecorator(420)], render: () => { const states = [ { data: makeData(), status: 'pending' as const, onApprove: () => {}, onReject: () => {} }, { data: makeData(), status: 'approved' as const, resolvedByName: 'Michael Johnson' }, { data: makeData(), status: 'rejected' as const, resolvedByName: 'Michael Johnson' }, { data: makeData(), status: 'cancelled' as const, resolvedByName: 'Michael Johnson' }, ]; return (
{states.map((s, i) => ( ))}
); }, };