Skip to content

Commit 395b212

Browse files
authored
Seven querystringWidget (#8017)
1 parent 78e90ad commit 395b212

11 files changed

Lines changed: 1409 additions & 0 deletions

File tree

Lines changed: 386 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,386 @@
1+
import { useMemo } from 'react';
2+
import type { Meta, StoryObj } from '@storybook/react-vite';
3+
import {
4+
RouterProvider,
5+
createMemoryRouter,
6+
type LoaderFunctionArgs,
7+
} from 'react-router';
8+
import { fn } from 'storybook/test';
9+
import type { QuerystringValue } from './QuerystringWidgetContext';
10+
import { QuerystringWidget } from './QuerystringWidget';
11+
12+
interface QuerystringWidgetStoryProps {
13+
label?: string;
14+
description?: string;
15+
errorMessage?: string;
16+
value?: QuerystringValue;
17+
defaultValue?: QuerystringValue;
18+
onChange?: (value: QuerystringValue) => void;
19+
onPatchFormData?: (partial: Record<string, unknown>) => void;
20+
}
21+
22+
const createQuerystringLoader = () => {
23+
return ({ request }: LoaderFunctionArgs) => {
24+
return {
25+
content: {
26+
'@id': '/Test/Document',
27+
},
28+
};
29+
};
30+
};
31+
32+
const createQuerystringRouter = (props: QuerystringWidgetStoryProps) =>
33+
createMemoryRouter(
34+
[
35+
{
36+
id: 'root',
37+
path: '/',
38+
loader: createQuerystringLoader(),
39+
element: (
40+
<div className="min-h-screen bg-white p-8">
41+
<div className="max-w-2xl">
42+
<QuerystringWidget {...(props as any)} />
43+
</div>
44+
</div>
45+
),
46+
},
47+
{
48+
path: '/@queryStringOptions',
49+
loader: () => ({
50+
indexes: {
51+
Creator: {
52+
title: 'Creator',
53+
description: 'The person that created an item',
54+
enabled: true,
55+
sortable: true,
56+
group: 'Metadata',
57+
operators: {
58+
is: { title: 'Is', description: null, widget: null },
59+
},
60+
},
61+
Title: {
62+
title: 'Title',
63+
description: "Text search of an item's title",
64+
enabled: true,
65+
sortable: false,
66+
group: 'Text',
67+
operators: {
68+
has: { title: 'Contains', description: null, widget: null },
69+
},
70+
},
71+
Subject: {
72+
title: 'Tag',
73+
description: 'Tags are used for organization of content',
74+
enabled: true,
75+
sortable: false,
76+
group: 'Text',
77+
operators: {
78+
is: { title: 'Is', description: null, widget: null },
79+
},
80+
},
81+
path: {
82+
title: 'Location',
83+
description: 'The location of an item',
84+
enabled: true,
85+
sortable: false,
86+
group: 'Metadata',
87+
operators: {
88+
is: {
89+
title: 'Navigation path',
90+
description: null,
91+
widget: null,
92+
},
93+
},
94+
},
95+
modified: {
96+
title: 'Modification date',
97+
description: 'The time and date an item was last modified',
98+
enabled: true,
99+
sortable: true,
100+
group: 'Dates',
101+
operators: {
102+
before: {
103+
title: 'Before date',
104+
description: null,
105+
widget: null,
106+
},
107+
after: { title: 'After date', description: null, widget: null },
108+
},
109+
},
110+
created: {
111+
title: 'Creation date',
112+
description: 'The date an item was created',
113+
enabled: true,
114+
sortable: true,
115+
group: 'Dates',
116+
operators: {
117+
before: {
118+
title: 'Before date',
119+
description: null,
120+
widget: null,
121+
},
122+
after: { title: 'After date', description: null, widget: null },
123+
},
124+
},
125+
review_state: {
126+
title: 'Review state',
127+
description: "An item's workflow state (e.g.published)",
128+
enabled: true,
129+
sortable: true,
130+
group: 'Metadata',
131+
operators: {
132+
is: { title: 'Is', description: null, widget: null },
133+
},
134+
values: {
135+
published: { title: 'Published' },
136+
pending: { title: 'Pending review' },
137+
private: { title: 'Private' },
138+
},
139+
},
140+
portal_type: {
141+
title: 'Type',
142+
description: "An item's type (e.g. Event)",
143+
enabled: true,
144+
sortable: false,
145+
group: 'Metadata',
146+
operators: {
147+
is: { title: 'Is', description: null, widget: null },
148+
},
149+
values: {
150+
Document: { title: 'Page' },
151+
Folder: { title: 'Folder' },
152+
Image: { title: 'Image' },
153+
File: { title: 'File' },
154+
Event: { title: 'Event' },
155+
},
156+
},
157+
},
158+
}),
159+
},
160+
{
161+
path: '/@querystringSearch',
162+
loader: () => ({
163+
items: [
164+
{
165+
'@id': '/Test/example-news-item',
166+
'@type': 'News Item',
167+
title: 'Example news item',
168+
description: 'A sample result for the query-string search.',
169+
},
170+
{
171+
'@id': '/Test/example-page',
172+
'@type': 'Document',
173+
title: 'Example page',
174+
description: 'Another sample result.',
175+
},
176+
],
177+
items_total: 2,
178+
}),
179+
},
180+
],
181+
{
182+
initialEntries: ['/'],
183+
},
184+
);
185+
186+
const StoryRouter = (props: QuerystringWidgetStoryProps) => {
187+
const router = useMemo(() => createQuerystringRouter(props), [props]);
188+
return <RouterProvider router={router} />;
189+
};
190+
191+
const meta = {
192+
component: QuerystringWidget,
193+
parameters: {
194+
layout: 'fullscreen',
195+
backgrounds: { disable: true },
196+
},
197+
tags: ['autodocs'],
198+
args: {
199+
label: 'Search Criteria',
200+
description: 'Define search criteria to filter content',
201+
onChange: fn(),
202+
onPatchFormData: fn(),
203+
},
204+
} satisfies Meta<QuerystringWidgetStoryProps>;
205+
206+
export default meta;
207+
type Story = StoryObj<typeof meta>;
208+
209+
/**
210+
* Default empty state of the QuerystringWidget with no criteria
211+
*/
212+
export const Default: Story = {
213+
render: (args) => <StoryRouter {...(args as any)} />,
214+
};
215+
216+
/**
217+
* QuerystringWidget with a single criterion
218+
*/
219+
export const WithSingleCriterion: Story = {
220+
render: (args) => <StoryRouter {...(args as any)} />,
221+
args: {
222+
value: {
223+
query: [
224+
{
225+
i: 'Creator',
226+
o: 'is',
227+
v: 'admin',
228+
},
229+
],
230+
sort_on: 'Title',
231+
sort_order: 'ascending',
232+
limit: 100,
233+
b_size: 50,
234+
} as QuerystringValue,
235+
},
236+
};
237+
238+
/**
239+
* QuerystringWidget with multiple criteria
240+
*/
241+
export const WithMultipleCriteria: Story = {
242+
render: (args) => <StoryRouter {...(args as any)} />,
243+
args: {
244+
value: {
245+
query: [
246+
{
247+
i: 'Creator',
248+
o: 'is',
249+
v: 'admin',
250+
},
251+
{
252+
i: 'Title',
253+
o: 'has',
254+
v: 'Document',
255+
},
256+
{
257+
i: 'modified',
258+
o: 'before',
259+
v: '2024-12-31',
260+
},
261+
],
262+
sort_on: 'modified',
263+
sort_order: 'descending',
264+
limit: 50,
265+
b_size: 25,
266+
} as QuerystringValue,
267+
},
268+
};
269+
270+
/**
271+
* QuerystringWidget with path criterion (shows depth field)
272+
*/
273+
export const WithPathCriterionAndDepth: Story = {
274+
render: (args) => <StoryRouter {...(args as any)} />,
275+
args: {
276+
value: {
277+
query: [
278+
{
279+
i: 'path',
280+
o: 'is',
281+
v: '/Test/Folder',
282+
},
283+
{
284+
i: 'review_state',
285+
o: 'is',
286+
v: 'published',
287+
},
288+
],
289+
depth: 2,
290+
sort_on: 'Title',
291+
sort_order: 'ascending',
292+
limit: 100,
293+
b_size: 50,
294+
} as QuerystringValue,
295+
},
296+
};
297+
298+
/**
299+
* QuerystringWidget in error state
300+
*/
301+
export const WithError: Story = {
302+
render: (args) => <StoryRouter {...(args as any)} />,
303+
args: {
304+
label: 'Search Criteria',
305+
description: 'Define search criteria to filter content',
306+
errorMessage: 'Please check your search criteria',
307+
value: {
308+
query: [
309+
{
310+
i: 'Creator',
311+
o: 'is',
312+
v: '',
313+
},
314+
],
315+
} as QuerystringValue,
316+
},
317+
};
318+
319+
/**
320+
* QuerystringWidget with all options configured
321+
*/
322+
export const FullyConfigured: Story = {
323+
render: (args) => <StoryRouter {...(args as any)} />,
324+
args: {
325+
label: 'Advanced Search',
326+
description:
327+
'Build complex search queries by adding multiple criteria. Criteria are combined with AND logic.',
328+
value: {
329+
query: [
330+
{
331+
i: 'Title',
332+
o: 'has',
333+
v: 'news',
334+
},
335+
{
336+
i: 'Creator',
337+
o: 'is',
338+
v: 'site_owner',
339+
},
340+
{
341+
i: 'modified',
342+
o: 'after',
343+
v: '2024-01-01',
344+
},
345+
{
346+
i: 'review_state',
347+
o: 'is',
348+
v: 'published',
349+
},
350+
],
351+
sort_on: 'modified',
352+
sort_order: 'descending',
353+
limit: 200,
354+
b_size: 25,
355+
} as QuerystringValue,
356+
},
357+
};
358+
359+
/**
360+
* QuerystringWidget with complex date-based criteria
361+
*/
362+
export const WithDateCriteria: Story = {
363+
render: (args) => <StoryRouter {...(args as any)} />,
364+
args: {
365+
label: 'Date-based Search',
366+
description: 'Filter content by creation and modification dates',
367+
value: {
368+
query: [
369+
{
370+
i: 'created',
371+
o: 'after',
372+
v: '2024-01-01',
373+
},
374+
{
375+
i: 'modified',
376+
o: 'before',
377+
v: '2024-12-31',
378+
},
379+
],
380+
sort_on: 'created',
381+
sort_order: 'descending',
382+
limit: 50,
383+
b_size: 10,
384+
} as QuerystringValue,
385+
},
386+
};

0 commit comments

Comments
 (0)