Skip to content

Commit

Permalink
Pattern constructors (#142)
Browse files Browse the repository at this point in the history
* Fix route parsing in form filler view.

* Create new pattern constructor that validates the config data, and wire up to the external PDF parsing library.

Context: we haven't been validating input from the PDF parsing process, and there were hard to debug issues. A remaining issue that this identified is the presence of spaces in some option IDs. These, and other errors, are currently being logged to the console, and the corresponding pattern is ignored (not added to the form blueprint). Follow-up work should include fixes this issue, and also presentation of these validation errors to the user.

* Split api call and api response processing

* Fix test

* Add mock-response.ts
  • Loading branch information
danielnaab authored May 29, 2024
1 parent 765a74c commit ffdcb85
Show file tree
Hide file tree
Showing 16 changed files with 1,404 additions and 126 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export const Error: StoryObj<typeof CheckboxPatternEdit> = {
optionId.blur();

await expect(
await canvas.findByText('Invalid option ID')
await canvas.findByText('Option ID may not contain spaces')
).toBeInTheDocument();

await userEvent.clear(optionLabel);
Expand Down
11 changes: 11 additions & 0 deletions packages/design/src/FormManager/FormInspect/FormInspect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { useFormManagerStore } from '../store';
import React from 'react';

export const FormInspect = () => {
const form = useFormManagerStore(state => state.session.form);
return (
<pre>
<code>{JSON.stringify(form, null, 2)}</code>
</pre>
);
};
1 change: 1 addition & 0 deletions packages/design/src/FormManager/FormInspect/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { FormInspect } from './FormInspect';
25 changes: 25 additions & 0 deletions packages/design/src/FormManager/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import FormDelete from './FormDelete';
import { FormDocumentImport } from './FormDocumentImport';
import FormEdit from './FormEdit';
import { type EditComponentForPattern } from './FormEdit/types';
import { FormInspect } from './FormInspect';
import FormList from './FormList';
import { FormManagerLayout } from './FormManagerLayout';
import { NavPage } from './FormManagerLayout/TopNavigation';
Expand Down Expand Up @@ -52,6 +53,30 @@ export default function FormManager({ context }: FormManagerProps) {
);
}}
/>
<Route
path={AppRoutes.Inspect.path}
Component={() => {
const { formId } = useParams();
if (formId === undefined) {
return <div>formId is undefined</div>;
}
const formResult = context.formService.getForm(formId);
if (!formResult.success) {
return <div>Error loading form preview</div>;
}
return (
<FormManagerProvider
context={context}
formId={formId}
session={createFormSession(formResult.data)}
>
<FormManagerLayout>
<FormInspect />
</FormManagerLayout>
</FormManagerProvider>
);
}}
/>
<Route
path={AppRoutes.Preview.path}
Component={() => {
Expand Down
5 changes: 5 additions & 0 deletions packages/design/src/FormManager/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ export const MyForms: Route<[]> = {
getUrl: () => `#`,
};

export const Inspect: Route = {
path: '/:formId/inspect',
getUrl: (formId: string) => `#/${formId}/inspect`,
};

export const Preview: Route = {
path: '/:formId/preview',
getUrl: (formId: string) => `#/${formId}/preview`,
Expand Down
10 changes: 6 additions & 4 deletions packages/forms/src/builder/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ import {
addDocument,
addPageToPageSet,
addPatternToPage,
createPattern,
createDefaultPattern,
getPattern,
nullBlueprint,
removePatternFromBlueprint,
updateFormSummary,
updatePatternFromFormData,
Expand Down Expand Up @@ -44,14 +43,17 @@ export class BlueprintBuilder {
}

addPage() {
const newPage = createPattern(this.config, 'page');
const newPage = createDefaultPattern(this.config, 'page');
this.bp = addPageToPageSet(this.form, newPage);
return newPage;
}

addPatternToFirstPage(patternType: string) {
const pattern = createPattern(this.config, patternType);
const pattern = createDefaultPattern(this.config, patternType);
const root = this.form.patterns[this.form.root] as PageSetPattern;
if (root.type !== 'page-set') {
throw new Error('expected root to be a page-set');
}
const firstPagePatternId = root.data.pages[0];
this.bp = addPatternToPage(this.form, firstPagePatternId, pattern);
return pattern;
Expand Down
50 changes: 50 additions & 0 deletions packages/forms/src/documents/__tests__/document.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* @vitest-environment jsdom
*/
import { describe, expect, it } from 'vitest';

import { getPattern } from '../..';
import { BlueprintBuilder } from '../../builder';
import { defaultFormConfig } from '../../patterns';
import { type PageSetPattern } from '../../patterns/page-set/config';
import { type PagePattern } from '../../patterns/page/config';

import { addDocument } from '../document';
import { loadSamplePDF } from './sample-data';

describe('addDocument document processing', () => {
it('creates expected blueprint', async () => {
const builder = new BlueprintBuilder(defaultFormConfig);
const pdfBytes = await loadSamplePDF(
'doj-pardon-marijuana/application_for_certificate_of_pardon_for_simple_marijuana_possession.pdf'
);
const { updatedForm, errors } = await addDocument(
builder.form,
{
name: 'test.pdf',
data: new Uint8Array(pdfBytes),
},
{
fetchPdfApiResponse: async () => {
const { mockResponse } = await import('../pdf/mock-response');
return mockResponse;
},
}
);
const rootPattern = getPattern<PageSetPattern>(
updatedForm,
updatedForm.root
);

console.error(JSON.stringify(errors, null, 2)); // Fix these
expect(rootPattern).toEqual(expect.objectContaining({ type: 'page-set' }));
expect(rootPattern.data.pages.length).toEqual(1);
const pagePattern = getPattern<PagePattern>(
updatedForm,
rootPattern.data.pages[0]
);

// As a sanity check, just confirm that there is content on the first page.
expect(pagePattern.data.patterns.length).toBeGreaterThan(1);
});
});
9 changes: 0 additions & 9 deletions packages/forms/src/documents/__tests__/suggestions.test.ts

This file was deleted.

15 changes: 12 additions & 3 deletions packages/forms/src/documents/document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import {
import { InputPattern } from '../patterns/input';
import { SequencePattern } from '../patterns/sequence';
import { PDFDocument, getDocumentFieldData } from './pdf';
import { getSuggestedPatterns } from './suggestions';
import {
type FetchPdfApiResponse,
processApiResponse,
fetchPdfApiResponse,
} from './pdf/parsing-api';
import { DocumentFieldMap } from './types';

export type DocumentTemplate = PDFDocument;
Expand All @@ -19,10 +23,14 @@ export const addDocument = async (
fileDetails: {
name: string;
data: Uint8Array;
}
},
context: {
fetchPdfApiResponse: FetchPdfApiResponse;
} = { fetchPdfApiResponse }
) => {
const fields = await getDocumentFieldData(fileDetails.data);
const parsedPdf = await getSuggestedPatterns(fileDetails.data);
const json = await context.fetchPdfApiResponse(fileDetails.data);
const parsedPdf = await processApiResponse(json);

if (parsedPdf) {
form = updateFormSummary(form, {
Expand All @@ -43,6 +51,7 @@ export const addDocument = async (
return {
newFields: fields,
updatedForm,
errors: parsedPdf.errors,
};
} else {
const formWithFields = addDocumentFieldsToForm(form, fields);
Expand Down
1 change: 0 additions & 1 deletion packages/forms/src/documents/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export * from './document';
export * from './pdf';
export * from './suggestions';
export * from './types';

export const SAMPLE_DOCUMENTS = [
Expand Down
1,127 changes: 1,127 additions & 0 deletions packages/forms/src/documents/pdf/mock-response.ts

Large diffs are not rendered by default.

Loading

0 comments on commit ffdcb85

Please sign in to comment.