diff --git a/ui/storybook/stories/issue-privacy-actions.stories.tsx b/ui/storybook/stories/issue-privacy-actions.stories.tsx new file mode 100644 index 00000000000..7d490f28adb --- /dev/null +++ b/ui/storybook/stories/issue-privacy-actions.stories.tsx @@ -0,0 +1,109 @@ +import { useMemo } from "react"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import type { Meta, StoryObj } from "@storybook/react-vite"; +import type { Issue } from "@paperclipai/shared"; +import { IssuePrivacyActions } from "@/components/IssuePrivacyActions"; +import { ToggleSwitch } from "@/components/ui/toggle-switch"; +import { queryKeys } from "@/lib/queryKeys"; + +const COMPANY_ID = "company-storybook"; + +function makeClient() { + const client = new QueryClient({ + defaultOptions: { queries: { staleTime: Infinity, retry: false, gcTime: Infinity } }, + }); + // Seed empty grants so opening Share… from the menu lands on the empty state + // rather than a spinner. + client.setQueryData(queryKeys.issues.accessGrants("issue-menu-1"), []); + return client; +} + +/** + * Renders the privacy `⋯`-menu items inside a faux DropdownMenu surface so the + * spacing/hover/destructive treatment reads the way it will in the real popover. + */ +function MenuHost({ + visibility, + canManage, +}: { + visibility: Issue["visibility"]; + canManage: boolean; +}) { + const client = useMemo(() => makeClient(), []); + const issue = { + id: "issue-menu-1", + identifier: "PAP-4242", + visibility, + } as Pick; + return ( + +
+
+
+ Privacy +
+ {}} + /> +
+
+
+ ); +} + +const meta: Meta = { + title: "Privacy/IssuePrivacyActions", + component: MenuHost, + parameters: { layout: "fullscreen" }, +}; +export default meta; + +type Story = StoryObj; + +/** Private task, setter: Share… + destructive Make public. */ +export const PrivateTaskSetter: Story = { + args: { visibility: "private", canManage: true }, +}; + +/** Public task, setter: single Make private (no confirm). */ +export const PublicTaskSetter: Story = { + args: { visibility: "open", canManage: true }, +}; + +/** Non-setter: items disabled; tooltip explains why (hover to reveal). */ +export const NonSetter: Story = { + args: { visibility: "private", canManage: false }, +}; + +/** + * The create-dialog "Private task" toggle row, lifted verbatim from + * NewIssueDialog so its resting on/off states are screenshot-documented. + */ +function PrivateToggleRow({ checked }: { checked: boolean }) { + return ( +
+
+
+
+
Private task
+
+ Only you and people you share with can read it. Subtasks stay private too. +
+
+ {}} aria-label="Private task" /> +
+
+
+ ); +} + +export const CreateDialogToggleOff: StoryObj = { + render: () => , +}; + +export const CreateDialogToggleOn: StoryObj = { + render: () => , +};