Skip to content

Commit 7944f5e

Browse files
limshyunyomybabyclaude
authored
docs(FR-1978): add Storybook stories for fragment modal/button components (#5218)
Co-authored-by: Jong Eun Lee <jongeun@lablup.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 54fc950 commit 7944f5e

9 files changed

Lines changed: 2504 additions & 5 deletions
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
import { BAIActivateArtifactsModalStoriesQuery } from '../../__generated__/BAIActivateArtifactsModalStoriesQuery.graphql';
2+
import RelayResolver from '../../tests/RelayResolver';
3+
import BAIButton from '../BAIButton';
4+
import BAIFlex from '../BAIFlex';
5+
import BAIActivateArtifactsModal from './BAIActivateArtifactsModal';
6+
import type { Meta, StoryObj } from '@storybook/react-vite';
7+
import { App } from 'antd';
8+
import { useState } from 'react';
9+
import { graphql, useLazyLoadQuery } from 'react-relay';
10+
11+
/**
12+
* BAIActivateArtifactsModal is a confirmation modal for activating (restoring) artifacts.
13+
*
14+
* Key features:
15+
* - GraphQL fragment-based artifact data
16+
* - Relay mutation for activating artifacts
17+
* - Different messages for single vs multiple artifacts
18+
* - Success/error message handling
19+
* - Loading state during activation
20+
*
21+
* @see BAIActivateArtifactsModal.tsx for implementation details
22+
*/
23+
const meta: Meta<typeof BAIActivateArtifactsModal> = {
24+
title: 'Fragments/BAIActivateArtifactsModal',
25+
component: BAIActivateArtifactsModal,
26+
tags: ['autodocs'],
27+
parameters: {
28+
layout: 'centered',
29+
docs: {
30+
description: {
31+
component: `
32+
**BAIActivateArtifactsModal** is a confirmation modal for activating (restoring) archived artifacts with GraphQL mutation integration.
33+
34+
## BAI-Specific Props
35+
| Prop | Type | Default | Description |
36+
|------|------|---------|-------------|
37+
| \`selectedArtifactsFragment\` | \`BAIActivateArtifactsModalArtifactsFragment$key\` | - | GraphQL fragment reference for selected artifacts (required) |
38+
| \`onOk\` | \`(e: React.MouseEvent) => void\` | - | Called after successful mutation completion (not on button click) |
39+
| \`onCancel\` | \`(e: React.MouseEvent) => void\` | - | Called when modal is cancelled |
40+
41+
## Features
42+
- **Confirmation Message**: Shows different messages for single artifact ("artifact name") vs multiple artifacts ("N artifacts")
43+
- **Mutation Integration**: Uses \`restoreArtifacts\` mutation to activate selected artifacts
44+
- **Success/Error Handling**: Displays success/error messages via Ant Design message component
45+
- **Loading State**: OK button shows loading state during mutation execution
46+
47+
## Usage Pattern
48+
The modal is typically used with a table selection:
49+
1. User selects one or more archived artifacts
50+
2. Clicks "Activate" button
51+
3. Modal shows confirmation with artifact names/count
52+
4. On OK, mutation executes and modal closes on success
53+
54+
For other props, refer to [Ant Design Modal](https://ant.design/components/modal).
55+
56+
## Storybook
57+
Mutation is mocked and will execute successfully, closing the modal on completion.
58+
`,
59+
},
60+
},
61+
},
62+
argTypes: {
63+
selectedArtifactsFragment: {
64+
control: false,
65+
description: 'GraphQL fragment reference for selected artifacts',
66+
table: {
67+
type: { summary: 'BAIActivateArtifactsModalArtifactsFragment$key' },
68+
},
69+
},
70+
open: {
71+
control: false,
72+
description: 'Whether the modal is visible (managed by parent component)',
73+
table: {
74+
type: { summary: 'boolean' },
75+
defaultValue: { summary: 'false' },
76+
},
77+
},
78+
onOk: {
79+
control: false,
80+
description: 'Called after successful mutation completion',
81+
table: {
82+
type: { summary: '(e: React.MouseEvent) => void' },
83+
},
84+
},
85+
onCancel: {
86+
control: false,
87+
description: 'Called when modal is cancelled',
88+
table: {
89+
type: { summary: '(e: React.MouseEvent) => void' },
90+
},
91+
},
92+
},
93+
decorators: [
94+
(Story) => (
95+
<App>
96+
<Story />
97+
</App>
98+
),
99+
],
100+
};
101+
102+
export default meta;
103+
type Story = StoryObj<typeof BAIActivateArtifactsModal>;
104+
105+
interface QueryResolverProps {
106+
defaultOpen?: boolean;
107+
}
108+
109+
const QueryResolver = ({ defaultOpen = false }: QueryResolverProps) => {
110+
const [open, setOpen] = useState(defaultOpen);
111+
112+
const { artifacts } = useLazyLoadQuery<BAIActivateArtifactsModalStoriesQuery>(
113+
graphql`
114+
query BAIActivateArtifactsModalStoriesQuery {
115+
artifacts(offset: 0, first: 10) {
116+
edges {
117+
node {
118+
...BAIActivateArtifactsModalArtifactsFragment
119+
}
120+
}
121+
}
122+
}
123+
`,
124+
{},
125+
);
126+
127+
const artifactNodes = artifacts?.edges?.map((edge: any) => edge.node);
128+
129+
return (
130+
artifactNodes &&
131+
artifactNodes.length > 0 && (
132+
<BAIFlex direction="column" gap="md">
133+
<BAIButton onClick={() => setOpen(true)}>Open Modal</BAIButton>
134+
<BAIActivateArtifactsModal
135+
selectedArtifactsFragment={artifactNodes}
136+
open={open}
137+
onOk={() => setOpen(false)}
138+
onCancel={() => setOpen(false)}
139+
/>
140+
</BAIFlex>
141+
)
142+
);
143+
};
144+
145+
/**
146+
* Single artifact activation
147+
*/
148+
export const Default: Story = {
149+
name: 'Basic',
150+
parameters: {
151+
docs: {
152+
description: {
153+
story:
154+
'Activate a single artifact. The modal displays the artifact name in the confirmation message.',
155+
},
156+
},
157+
},
158+
render: () => (
159+
<RelayResolver
160+
mockResolvers={{
161+
ArtifactConnection: () => ({
162+
edges: [
163+
{
164+
node: {
165+
id: 'QXJ0aWZhY3Q6YXJ0aWZhY3QtMQ==',
166+
name: 'my-model-v1.0',
167+
},
168+
},
169+
],
170+
}),
171+
RestoreArtifactsPayload: () => ({
172+
artifacts: [
173+
{
174+
id: 'QXJ0aWZhY3Q6YXJ0aWZhY3QtMQ==',
175+
availability: 'AVAILABLE',
176+
},
177+
],
178+
}),
179+
}}
180+
>
181+
<QueryResolver />
182+
</RelayResolver>
183+
),
184+
};

0 commit comments

Comments
 (0)