Skip to content

Commit

Permalink
Add "rules" attribute to page pattern.
Browse files Browse the repository at this point in the history
  • Loading branch information
danielnaab committed Nov 13, 2024
1 parent af7f016 commit 7068890
Show file tree
Hide file tree
Showing 19 changed files with 222 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const Basic: StoryObj<typeof PageSetEdit> = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const pagesetHeaderElement = await canvas.findByText(/Page 1/);
return;
await testUpdateFormFieldOnSubmitByElement(
canvasElement,
pagesetHeaderElement,
Expand Down
3 changes: 3 additions & 0 deletions packages/design/src/test-form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export const createOnePageTwoPatternTestForm = () => {
data: {
title: 'Page 1',
patterns: ['element-1', 'element-2'],
rules: [],
},
} satisfies PagePattern,
{
Expand Down Expand Up @@ -88,6 +89,7 @@ export const createTwoPageTwoPatternTestForm = () => {
data: {
title: 'First page',
patterns: ['element-1', 'element-2'],
rules: [],
},
} satisfies PagePattern,
{
Expand All @@ -96,6 +98,7 @@ export const createTwoPageTwoPatternTestForm = () => {
data: {
title: 'Second page',
patterns: [],
rules: [],
},
} satisfies PagePattern,
{
Expand Down
15 changes: 15 additions & 0 deletions packages/forms/src/builder/builder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ describe('form builder', () => {
data: {
title: 'Page 1',
patterns: ['element-2', 'element-1'],
rules: [],
},
} satisfies PagePattern,
'page-2': {
Expand All @@ -69,6 +70,7 @@ describe('form builder', () => {
data: {
title: 'Page 2',
patterns: ['element-3'],
rules: [],
},
} satisfies PagePattern,
'element-1': {
Expand Down Expand Up @@ -126,6 +128,7 @@ describe('form builder', () => {
data: {
title: 'Page 1',
patterns: ['element-2'],
rules: [],
},
} satisfies PagePattern,
'page-2': {
Expand All @@ -134,6 +137,7 @@ describe('form builder', () => {
data: {
title: 'Page 2',
patterns: ['element-1', 'element-3'],
rules: [],
},
} satisfies PagePattern,
'element-1': {
Expand Down Expand Up @@ -196,6 +200,7 @@ describe('form builder', () => {
data: {
title: 'Page 1',
patterns: ['element-2'],
rules: [],
},
} satisfies PagePattern,
'page-2': {
Expand All @@ -204,6 +209,7 @@ describe('form builder', () => {
data: {
title: 'Page 2',
patterns: ['element-3', 'element-1'],
rules: [],
},
} satisfies PagePattern,
'element-1': {
Expand Down Expand Up @@ -268,6 +274,7 @@ describe('form builder', () => {
'fieldset-1',
'radio-group-1',
],
rules: [],
},
},
'element-1': {
Expand Down Expand Up @@ -349,6 +356,7 @@ describe('form builder', () => {
'fieldset-1',
'radio-group-1',
],
rules: [],
},
},
'element-1': {
Expand Down Expand Up @@ -432,6 +440,7 @@ describe('form builder', () => {
newPattern.id,
'radio-group-1',
],
rules: [],
},
},
'element-1': {
Expand Down Expand Up @@ -511,6 +520,7 @@ describe('form builder', () => {
'radio-group-1',
newPattern.id,
],
rules: [],
},
},
'element-1': {
Expand Down Expand Up @@ -584,6 +594,7 @@ describe('form builder', () => {
data: {
title: 'Page 1',
patterns: ['element-1'],
rules: [],
},
} satisfies PagePattern,
'element-1': {
Expand Down Expand Up @@ -622,6 +633,7 @@ export const createTestBlueprint = () => {
data: {
title: 'Page 1',
patterns: ['element-1', 'element-2'],
rules: [],
},
} satisfies PagePattern,
{
Expand Down Expand Up @@ -671,6 +683,7 @@ export const createTwoPageThreePatternTestForm = () => {
data: {
title: 'Page 1',
patterns: ['element-1', 'element-2'],
rules: [],
},
} satisfies PagePattern,
{
Expand All @@ -679,6 +692,7 @@ export const createTwoPageThreePatternTestForm = () => {
data: {
title: 'Page 2',
patterns: ['element-3'],
rules: [],
},
} satisfies PagePattern,
{
Expand Down Expand Up @@ -743,6 +757,7 @@ export const createTestBlueprintMultipleFieldsets = () => {
'fieldset-1',
'radio-group-1',
],
rules: [],
},
} satisfies PagePattern,
{
Expand Down
1 change: 1 addition & 0 deletions packages/forms/src/documents/pdf/parsing-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ export const processApiResponse = async (json: any): Promise<ParsedPdf> => {
{
title: `${page}`,
patterns,
rules: [],
},
undefined,
idx
Expand Down
9 changes: 8 additions & 1 deletion packages/forms/src/pattern.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,20 @@ type RemoveChildPattern<P extends Pattern> = (
export abstract class PatternBuilder<P extends Pattern> {
public readonly id: PatternId;
public readonly data: P['data'];
public abstract readonly type: P['type'];

constructor(data: P['data'], id?: PatternId) {
this.id = id || generatePatternId();
this.data = data;
}

abstract toPattern(): P;
toPattern(): P {
return {
id: this.id,
type: this.type,
data: this.data,
} as P;
}
}

export const getPattern = <T extends Pattern = Pattern>(
Expand Down
5 changes: 5 additions & 0 deletions packages/forms/src/patterns/checkbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as z from 'zod';

import {
type Pattern,
PatternBuilder,
type PatternConfig,
validatePattern,
} from '../pattern.js';
Expand Down Expand Up @@ -73,3 +74,7 @@ export const checkboxConfig: PatternConfig<CheckboxPattern, PatternOutput> = {
};
},
};

export class Checkbox extends PatternBuilder<CheckboxPattern> {
type = 'checkbox';
}
6 changes: 6 additions & 0 deletions packages/forms/src/patterns/fieldset/builder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { PatternBuilder } from '../../pattern';
import type { FieldsetPattern } from './config';

export class FieldSet extends PatternBuilder<FieldsetPattern> {
type = 'fieldset';
}
8 changes: 1 addition & 7 deletions packages/forms/src/patterns/input/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,5 @@ import { PatternBuilder } from '../../pattern';
import { type InputPattern } from './config';

export class Input extends PatternBuilder<InputPattern> {
toPattern(): InputPattern {
return {
id: this.id,
type: 'input',
data: this.data,
};
}
type = 'input';
}
8 changes: 1 addition & 7 deletions packages/forms/src/patterns/package-download/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,5 @@ import { type PackageDownloadPattern } from '.';
import { PatternBuilder } from '../../pattern';

export class PackageDownload extends PatternBuilder<PackageDownloadPattern> {
toPattern(): PackageDownloadPattern {
return {
id: this.id,
type: 'page-set',
data: this.data,
};
}
type = 'package-download';
}
5 changes: 4 additions & 1 deletion packages/forms/src/patterns/package-download/submit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ const createTestForm = async (): Promise<Blueprint> => {
{ label: 'Input 1', required: true, maxLength: 10 },
'input-1'
);
const page1 = new Page({ title: 'Page 1', patterns: [input1.id] }, 'page-1');
const page1 = new Page(
{ title: 'Page 1', patterns: [input1.id], rules: [] },
'page-1'
);
const pageSet = new PageSet({ pages: [page1.id] }, 'page-set');
return {
summary: {
Expand Down
10 changes: 2 additions & 8 deletions packages/forms/src/patterns/page-set/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,12 @@ export class Form {
}

export class PageSet extends PatternBuilder<PageSetPattern> {
type = 'page-set';

addPage(page: Page) {
return new PageSet({
...this.data,
pages: [...this.data.pages, page.id],
});
}

toPattern(): PageSetPattern {
return {
id: this.id,
type: 'page-set',
data: this.data,
};
}
}
5 changes: 4 additions & 1 deletion packages/forms/src/patterns/page-set/prompt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ const createTestForm = async (): Promise<Blueprint> => {
{ label: 'Input 1', required: true, maxLength: 10 },
'input-1'
);
const page1 = new Page({ title: 'Page 1', patterns: [input1.id] }, 'page-1');
const page1 = new Page(
{ title: 'Page 1', patterns: [input1.id], rules: [] },
'page-1'
);
const pageSet = new PageSet({ pages: [page1.id] }, 'page-set');
return {
summary: {
Expand Down
10 changes: 8 additions & 2 deletions packages/forms/src/patterns/page-set/submit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,14 @@ const createTestSession = () => {
{ label: 'label', required: true, maxLength: 10 },
'input-2'
);
const page1 = new Page({ title: 'Page 1', patterns: [input1.id] }, 'page-1');
const page2 = new Page({ title: 'Page 2', patterns: [input2.id] }, 'page-2');
const page1 = new Page(
{ title: 'Page 1', patterns: [input1.id], rules: [] },
'page-1'
);
const page2 = new Page(
{ title: 'Page 2', patterns: [input2.id], rules: [] },
'page-2'
);
const pageSet = new PageSet({ pages: [page1.id, page2.id] }, 'page-set-1');
const testForm: Blueprint = {
summary: {
Expand Down
23 changes: 21 additions & 2 deletions packages/forms/src/patterns/page-set/submit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,30 @@ export const submitPage: SubmitHandler<PageSetPattern> = async (
opts.data
);

// Increment the page number if there are no errors and this isn't the last page.
// Evaluate page rules
const ruleMatch = pagePattern.data.data.rules
? pagePattern.data.data.rules.find(rule => {
if (rule.condition.operator === '=') {
const value = opts.session.data.values[rule.patternId];
if (value === rule.condition.value) {
return true;
}
} else {
throw new Error(
`Unsupported rule operator: "${rule.condition.operator}"`
);
}
})
: undefined;

// Get the page number for the 1st rule match, or the next page if no rules
// match.
const lastPage = opts.pattern.data.pages.length - 1;
const nextPage =
Object.values(result.errors).length === 0 && pageNumber < lastPage
? pageNumber + 1
? ruleMatch
? pagePattern.data.data.patterns.indexOf(ruleMatch.patternId)
: pageNumber + 1
: pageNumber;

return success({
Expand Down
10 changes: 2 additions & 8 deletions packages/forms/src/patterns/page/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,12 @@ import { PatternBuilder } from '../../pattern';
import { type PagePattern } from './config';

export class Page extends PatternBuilder<PagePattern> {
type = 'page';

setTitle(title: string) {
return new Page({
...this.data,
title,
});
}

toPattern(): PagePattern {
return {
id: this.id,
type: 'page',
data: this.data,
};
}
}
12 changes: 12 additions & 0 deletions packages/forms/src/patterns/page/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@ const configSchema = z.object({
)
.pipe(z.string().array()),
]),
rules: z
.array(
z.object({
patternId: z.string(),
condition: z.object({
operator: z.literal('='),
value: z.string(),
}),
next: z.string(),
})
)
.default([]),
});

type PageConfigSchema = z.infer<typeof configSchema>;
Expand Down
1 change: 1 addition & 0 deletions packages/forms/src/patterns/page/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const pageConfig: PatternConfig<PagePattern> = {
initial: {
title: 'Untitled Page',
patterns: [],
rules: [],
},
createPrompt,
parseConfigData,
Expand Down
Loading

0 comments on commit 7068890

Please sign in to comment.