From 874b6c25a42f55b95ca9f7017a262cf9bb00d5bc Mon Sep 17 00:00:00 2001
From: Bryan Robitaille
Date: Wed, 4 Jan 2023 11:02:51 -0500
Subject: [PATCH] Release v2.0.0 (#1449)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Tim Arney
Co-authored-by: Paul Craig
Co-authored-by: James Eberhardt
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Clément JANIN
Co-authored-by: Dave Samojlenko
Co-authored-by: sre-read-write[bot] <92993749+sre-read-write[bot]@users.noreply.github.com>
Co-authored-by: Tim Arney
Co-authored-by: Omar Nasr
Co-authored-by: Peter Thiessen
Co-authored-by: samsadasivan
Co-authored-by: Matt
Co-authored-by: Pete <107579368+thiessenp-cds@users.noreply.github.com>
Co-authored-by: Pat Heard
---
.devcontainer/Dockerfile | 2 +-
.devcontainer/docker-compose.yml | 4 +-
.env.example | 11 +-
.eslintrc.js | 7 +-
.../workflows/build-and-deploy-storybooks.yml | 18 +-
.github/workflows/codeql-analysis.yml | 17 +-
.github/workflows/cypress.yml | 17 +-
.github/workflows/eslint.yml | 12 +-
.github/workflows/generate-sbom.yml | 4 +-
.github/workflows/jest.yml | 2 +-
.../workflows/prod-build-push-container.yml | 27 +-
.github/workflows/s3-backup.yml | 4 +-
.../staging-build-push-container.yml | 33 +-
.github/workflows/staging-deploy.yml | 10 +-
.../test-container-build-production.yml | 29 +
.../test-container-build-staging.yml | 28 +
.idea/.name | 1 +
.storybook/Layout.js | 4 +-
.storybook/preview.js | 2 +-
CHANGELOG.md | 96 +-
Dockerfile | 30 +-
README.md | 36 +-
VERSION | 2 +-
__fixtures__/accessibilityTestForm.json | 329 +
__fixtures__/attestationTestForm.json | 47 +
__fixtures__/brokenFormTemplate.json | 646 +
.../cdsIntakeTestForm.json | 13 +-
__fixtures__/duplicateElementIds.json | 384 +
.../dynamicRowsTestForm.json | 13 +-
__fixtures__/invalidLayoutIds.json | 644 +
__fixtures__/invalidSubElementIds.json | 177 +
.../platformIntakeTestForm.json | 13 +-
__fixtures__/testData.json | 303 +
.../textFieldTestForm.json | 0
.../tsbContactTestForm.json | 13 +-
.../tsbDisableFooterGCBranding.json | 10 +-
__fixtures__/validFormTemplate.json | 644 +
...validFormTemplateWithHTMLInDynamicRow.json | 644 +
__tests__/api/acceptable-use.test.ts | 88 +
__tests__/api/account/confirmpassword.test.ts | 166 +
__tests__/api/account/forgotpassword.test.ts | 159 +
__tests__/api/flags.test.ts | 251 +
__tests__/api/id/form/apiUsers.test.ts | 1218 ++
__tests__/api/id/form/bearer.test.ts | 420 +
.../api/id/form/retrieval.test.ts | 448 +-
{tests => __tests__}/api/log.test.ts | 10 +-
.../api/notify-callbacks.test.js | 3 +
__tests__/api/request/publish.test.ts | 148 +
__tests__/api/request/support.test.ts | 186 +
__tests__/api/signup/confirm.test.ts | 161 +
__tests__/api/signup/register.test.ts | 188 +
.../api/signup/resendconfirmation.test.ts | 157 +
__tests__/api/templates.test.ts | 507 +
__tests__/api/token/temporary.test.ts | 225 +
__tests__/api/users.test.ts | 356 +
__tests__/id/[form]/settings.test.js | 106 +
__utils__/index.ts | 2 +
__utils__/jestShim.ts | 4 +
{lib => __utils__}/jestUtils.ts | 0
__utils__/mocks/middleware.ts | 17 +
__utils__/permissions.ts | 70 +
__utils__/prismaConnector.ts | 32 +
{lib/tests => __utils__}/setupTests.ts | 4 +-
.../BearerRefresh/BearerRefresh.stories.tsx | 2 +-
.../admin/BearerRefresh/BearerRefresh.tsx | 11 +-
.../admin/FormAccess/FormAccess.stories.tsx | 2 +-
.../admin/FormAccess/FormAccess.test.js | 44 +-
components/admin/FormAccess/FormAccess.tsx | 16 +-
.../admin/JsonUpload/JsonUpload.stories.tsx | 42 +-
.../admin/JsonUpload/JsonUpload.test.js | 52 +-
components/admin/JsonUpload/JsonUpload.tsx | 133 +-
components/admin/TemplateDelete/Settings.tsx | 96 +
components/auth/AcceptableUse.test.js | 44 +
components/auth/AcceptableUse.tsx | 79 +
.../auth/Confirmation/Confirmation.test.js | 72 +
components/auth/Confirmation/Confirmation.tsx | 160 +
components/auth/LoginMenu.test.js | 15 +
components/auth/LoginMenu.tsx | 43 +
.../__tests__/useActivePathname.tsx | 11 +
.../__tests__/useAllowPublish.test.tsx | 678 +
.../__tests__/useModalStore.test.tsx | 110 +
.../__tests__/useTemplateStore.test.tsx | 378 +
.../form-builder/__tests__/util.test.js | 108 +
components/form-builder/app/Preview.tsx | 168 +
components/form-builder/app/Publish.tsx | 149 +
components/form-builder/app/PublishNoAuth.tsx | 20 +
components/form-builder/app/Published.tsx | 81 +
components/form-builder/app/Settings.tsx | 249 +
components/form-builder/app/Start.tsx | 136 +
components/form-builder/app/Template.tsx | 99 +
.../app/edit/ConfirmationDescription.tsx | 17 +
components/form-builder/app/edit/Edit.tsx | 142 +
.../form-builder/app/edit/ElementDropDown.tsx | 43 +
.../form-builder/app/edit/ElementPanel.tsx | 90 +
.../form-builder/app/edit/ElementRequired.tsx | 33 +
components/form-builder/app/edit/Modal.tsx | 201 +
.../form-builder/app/edit/ModalForm.tsx | 141 +
.../form-builder/app/edit/PanelActions.tsx | 237 +
.../app/edit/PanelActionsLocked.tsx | 37 +
.../form-builder/app/edit/PanelBody.tsx | 55 +
.../form-builder/app/edit/PanelBodyRoot.tsx | 97 +
.../app/edit/PrivacyDescription.tsx | 12 +
.../form-builder/app/edit/SelectedElement.tsx | 92 +
.../app/edit/elements/BulkAdd.tsx | 54 +
.../app/edit/elements/DropDown.tsx | 68 +
.../form-builder/app/edit/elements/Option.tsx | 115 +
.../app/edit/elements/Options.tsx | 152 +
.../app/edit/elements/RichText.tsx | 38 +
.../app/edit/elements/RichTextLocked.tsx | 48 +
.../app/edit/elements/ShortAnswer.tsx | 9 +
.../form-builder/app/edit/elements/index.ts | 9 +
.../edit/elements/lexical-editor/Editor.tsx | 108 +
.../lexical-editor/RichTextEditor.tsx | 63 +
.../edit/elements/lexical-editor/ToolTip.tsx | 23 +
.../edit/elements/lexical-editor/Toolbar.tsx | 386 +
.../edit/elements/lexical-editor/config.ts | 83 +
.../FloatingLinkEditorPlugin/index.tsx | 286 +
.../lexical-editor/plugins/FocusEditor.tsx | 16 +
.../plugins/ListMaxIndentPlugin.tsx | 81 +
.../lexical-editor/useEditorFocus.tsx | 37 +
.../lexical-editor/utils/getSelectedNode.ts | 25 +
.../utils/setFloatingElemPosition.ts | 46 +
.../edit/elements/lexical-editor/utils/url.ts | 32 +
.../app/edit/elements/question/Question.tsx | 48 +
.../edit/elements/question/QuestionInput.tsx | 74 +
.../edit/elements/question/QuestionNumber.tsx | 38 +
.../app/edit/elements/tests/Dropdown.test.js | 46 +
.../app/edit/elements/tests/Option.test.js | 34 +
.../app/edit/elements/tests/Options.test.js | 59 +
.../app/edit/elements/tests/RichText.test.js | 46 +
.../elements/tests/RichTextLocked.test.js | 16 +
.../edit/elements/tests/ShortAnswer.test.js | 17 +
components/form-builder/app/edit/index.ts | 13 +
.../app/edit/tests/ElementDropDown.test.js | 33 +
.../app/edit/tests/ElementPanel.test.js | 120 +
.../app/edit/tests/ElementRequired.test.js | 33 +
.../form-builder/app/edit/tests/Modal.test.js | 75 +
components/form-builder/app/index.ts | 11 +
.../app/navigation/EditNavigation.tsx | 24 +
.../form-builder/app/navigation/Header.tsx | 57 +
.../app/navigation/LeftNavLink.tsx | 30 +
.../app/navigation/LeftNavigation.tsx | 54 +
.../app/navigation/PreviewNavigation.tsx | 12 +
.../app/navigation/SubNavLink.tsx | 31 +
components/form-builder/app/shared/Button.tsx | 144 +
.../app/shared/ConfirmFormDeleteDialog.tsx | 71 +
.../app/shared/CopyToClipboard.tsx | 26 +
components/form-builder/app/shared/Dialog.tsx | 77 +
.../app/shared/DownloadFileButton.tsx | 135 +
components/form-builder/app/shared/Input.tsx | 68 +
.../form-builder/app/shared/LangSwitcher.tsx | 70 +
.../app/shared/MultipleChoice.tsx | 67 +
components/form-builder/app/shared/Output.tsx | 8 +
.../app/shared/ResumeEditingForm.tsx | 37 +
.../form-builder/app/shared/SaveButton.tsx | 72 +
.../form-builder/app/shared/TextArea.tsx | 39 +
components/form-builder/app/shared/index.ts | 9 +
.../app/translate/Description.tsx | 102 +
.../app/translate/DownloadCSV.tsx | 109 +
.../app/translate/FieldsetLegend.tsx | 9 +
.../app/translate/LanguageLabel.tsx | 25 +
.../form-builder/app/translate/Options.tsx | 93 +
.../form-builder/app/translate/RichText.tsx | 78 +
.../app/translate/SectionTitle.tsx | 10 +
.../form-builder/app/translate/Title.tsx | 94 +
.../form-builder/app/translate/Translate.tsx | 331 +
.../form-builder/app/translate/index.ts | 3 +
components/form-builder/example-form.json | 248 +
components/form-builder/hooks/index.ts | 7 +
.../form-builder/hooks/useActivePathname.tsx | 24 +
.../form-builder/hooks/useAllowPublish.tsx | 124 +
components/form-builder/hooks/useDelete.tsx | 24 +
.../form-builder/hooks/useElementOptions.tsx | 31 +
components/form-builder/hooks/usePublish.tsx | 51 +
.../form-builder/hooks/useTemplateApi.tsx | 57 +
.../form-builder/hooks/useTemplateStatus.tsx | 54 +
.../form-builder/icons/BackArrowIcon.tsx | 16 +
components/form-builder/icons/BoldIcon.tsx | 16 +
.../form-builder/icons/BulletListIcon.tsx | 16 +
.../form-builder/icons/BulletedListIcon.tsx | 16 +
.../form-builder/icons/CalendarIcon.tsx | 17 +
components/form-builder/icons/CancelIcon.tsx | 16 +
.../form-builder/icons/CheckBoxEmptyIcon.tsx | 19 +
components/form-builder/icons/CheckIcon.tsx | 20 +
components/form-builder/icons/ChevronDown.tsx | 16 +
components/form-builder/icons/ChevronUp.tsx | 16 +
.../form-builder/icons/CircleCheckIcon.tsx | 16 +
components/form-builder/icons/Close.tsx | 16 +
components/form-builder/icons/DesignIcon.tsx | 16 +
components/form-builder/icons/Duplicate.tsx | 16 +
components/form-builder/icons/EditIcon.tsx | 16 +
components/form-builder/icons/EmailIcon.tsx | 17 +
.../form-builder/icons/ExternalLinkIcon.tsx | 16 +
components/form-builder/icons/FolderIcon.tsx | 16 +
components/form-builder/icons/GearIcon.tsx | 16 +
components/form-builder/icons/GlobeIcon.tsx | 16 +
components/form-builder/icons/H2Icon.tsx | 16 +
components/form-builder/icons/H3Icon.tsx | 16 +
components/form-builder/icons/InfoIcon.tsx | 20 +
components/form-builder/icons/ItalicIcon.tsx | 16 +
components/form-builder/icons/LinkIcon.tsx | 16 +
components/form-builder/icons/LockIcon.tsx | 20 +
.../form-builder/icons/MenuOpenIcon.tsx | 16 +
.../form-builder/icons/NumberedListIcon.tsx | 16 +
.../form-builder/icons/NumericFieldIcon.tsx | 17 +
components/form-builder/icons/PageIcon.tsx | 16 +
.../form-builder/icons/ParagraphIcon.tsx | 17 +
components/form-builder/icons/PhoneIcon.tsx | 17 +
components/form-builder/icons/PreviewIcon.tsx | 16 +
components/form-builder/icons/PublishIcon.tsx | 16 +
.../form-builder/icons/RadioEmptyIcon.tsx | 20 +
components/form-builder/icons/RadioIcon.tsx | 19 +
components/form-builder/icons/RocketIcon.tsx | 26 +
components/form-builder/icons/SaveIcon.tsx | 16 +
.../form-builder/icons/SelectMenuIcon.tsx | 20 +
components/form-builder/icons/ShareIcon.tsx | 16 +
.../form-builder/icons/ShortAnswerIcon.tsx | 17 +
.../form-builder/icons/ThreeDotsIcon.tsx | 17 +
components/form-builder/icons/ToggleLeft.tsx | 16 +
components/form-builder/icons/ToggleRight.tsx | 16 +
components/form-builder/icons/WarningIcon.tsx | 27 +
components/form-builder/icons/index.ts | 44 +
components/form-builder/notes.md | 8 +
components/form-builder/store/index.ts | 2 +
.../form-builder/store/useModalStore.tsx | 51 +
.../form-builder/store/useTemplateStore.tsx | 327 +
.../form-builder/test-utils/Providers.js | 26 +
.../form-builder/test-utils/defaultStore.json | 46 +
components/form-builder/test-utils/index.ts | 3 +
components/form-builder/types/index.ts | 92 +
components/form-builder/util.ts | 161 +
components/form-builder/validate.ts | 36 +
components/forms/Alert/Alert.stories.js | 61 +
components/forms/Alert/Alert.stories.tsx | 96 -
components/forms/Alert/Alert.tsx | 27 +-
components/forms/Button/Button.stories.tsx | 2 +-
components/forms/Button/Button.test.js | 6 +-
components/forms/Button/Button.tsx | 2 -
components/forms/Button/DeleteButton.tsx | 6 +-
components/forms/Checkbox/Checkbox.test.js | 6 +-
components/forms/Checkbox/Checkbox.tsx | 4 +-
.../forms/Description/Description.test.js | 2 +-
components/forms/Description/Description.tsx | 2 -
components/forms/Dropdown/Dropdown.test.js | 6 +-
components/forms/Dropdown/Dropdown.tsx | 4 +-
.../forms/DynamicRow/DynamicRow.test.js | 65 +-
components/forms/DynamicRow/DynamicRow.tsx | 5 +-
.../ErrorListItem/ErrorListItem.stories.tsx | 2 +-
.../ErrorListItem/ErrorListItem.test.tsx | 2 +-
.../forms/ErrorListItem/ErrorListItem.tsx | 4 +-
.../forms/ErrorMessage/ErrorMessage.test.js | 2 +-
.../forms/ErrorMessage/ErrorMessage.tsx | 2 -
.../forms/FileInput/FileInput.stories.tsx | 6 +-
components/forms/FileInput/FileInput.test.tsx | 2 +-
components/forms/FileInput/FileInput.tsx | 4 +-
components/forms/Form/Form.test.js | 99 +-
components/forms/Form/Form.tsx | 169 +-
components/forms/FormGroup/FormGroup.test.js | 2 +-
components/forms/FormGroup/FormGroup.tsx | 2 -
components/forms/Heading/Heading.stories.tsx | 28 -
components/forms/Heading/Heading.test.js | 23 -
components/forms/Heading/Heading.tsx | 28 -
components/forms/Label/Label.test.js | 2 +-
components/forms/Label/Label.tsx | 2 -
.../MultipleChoiceGroup.tsx | 6 +-
components/forms/Radio/Radio.test.js | 2 +-
components/forms/Radio/Radio.tsx | 4 +-
components/forms/RichText/RichText.test.js | 18 +-
components/forms/RichText/RichText.tsx | 61 +-
components/forms/TextArea/TextArea.test.js | 20 +-
components/forms/TextArea/TextArea.tsx | 4 +-
components/forms/TextInput/TextInput.test.js | 14 +-
components/forms/TextInput/TextInput.tsx | 39 +-
components/forms/TextPage/TextPage.tsx | 22 +-
components/forms/index.ts | 2 +-
components/globals/AdminNav.tsx | 57 +-
.../globals/Attention/Attention.test.tsx | 30 +
components/globals/Attention/Attention.tsx | 38 +
components/globals/Base.js | 58 -
components/globals/Base.test.js | 55 -
components/globals/Fip.js | 50 -
components/globals/Fip.tsx | 52 +
components/globals/Footer.js | 36 -
components/globals/Footer.tsx | 41 +
components/globals/LanguageToggle.js | 50 +-
components/globals/PhaseBanner.js | 20 -
.../globals/StyledLink/StyledLink.test.js | 70 +
components/globals/StyledLink/StyledLink.tsx | 69 +
components/globals/layouts/AdminNavLayout.tsx | 42 +
components/globals/layouts/BaseLayout.test.js | 20 +
components/globals/layouts/BaseLayout.tsx | 40 +
.../globals/layouts/FormDisplayLayout.tsx | 45 +
components/globals/layouts/UserNavLayout.tsx | 55 +
components/myforms/Card/Card.test.js | 95 +
components/myforms/Card/Card.tsx | 116 +
components/myforms/CardGrid/CardGrid.test.js | 43 +
components/myforms/CardGrid/CardGrid.tsx | 34 +
components/myforms/LeftNav/LeftNavLink.tsx | 27 +
.../myforms/LeftNav/LeftNavigation.test.js | 32 +
components/myforms/LeftNav/LeftNavigation.tsx | 56 +
components/myforms/LeftNav/index.ts | 2 +
components/myforms/MenuDropdown/Menu.ts | 200 +
.../myforms/MenuDropdown/MenuDropdown.test.js | 77 +
.../myforms/MenuDropdown/MenuDropdown.tsx | 129 +
components/myforms/Tabs/Tab.tsx | 42 +
components/myforms/Tabs/TabPanel.tsx | 23 +
components/myforms/Tabs/Tabs.test.js | 86 +
components/myforms/Tabs/TabsKeynav.ts | 97 +
components/myforms/Tabs/TabsList.tsx | 47 +
cypress.config.js | 9 +
cypress.json | 1 -
cypress/e2e/acceptable_use.cy.js | 62 +
cypress/e2e/accessibility.cy.js | 20 +
.../attestation.cy.js} | 2 +-
.../cds_intake.cy.js} | 2 +-
.../character_limit.cy.js} | 4 +-
.../dynamic_rows.cy.js} | 2 +-
.../forms_functionality.cy.js} | 10 +-
cypress/e2e/login_page.cy.js | 94 +
cypress/e2e/logout.cy.js | 22 +
.../platform_intake.cy.js} | 2 +-
cypress/e2e/register_page.cy.js | 144 +
.../terms_conditions_page.cy.js} | 2 +-
.../tsb_contact.cy.js} | 2 +-
.../tsb_contact_remove_footer_gc_word.cy.js} | 2 +-
cypress/integration/accessibility.spec.js | 41 -
cypress/integration/form-builder.spec.js | 85 +
cypress/integration/welcome_page.spec.js | 13 -
cypress/support/commands.js | 17 +-
cypress/support/{index.js => e2e.js} | 0
cypress/tsconfig.json | 7 -
docker-compose.yml | 4 +-
documentation/Forms/FormDBSchema.stories.mdx | 1 -
documentation/Forms/FormViewer.stories.mdx | 9 +-
email.domains.json | 24 -
.../default_flag_settings.json | 7 +-
flag_initialization/index.js | 61 +-
flag_initialization/package.json | 4 +-
flag_initialization/yarn.lock | 60 +-
jest.config.js | 12 +-
lib/acceptableUseCache.ts | 28 +
lib/adminLogs.ts | 45 +-
lib/auth.ts | 168 +-
lib/cache/flags.ts | 71 +
lib/{cache.ts => cache/formCache.ts} | 61 +-
lib/cache/privilegeCache.ts | 89 +
lib/fileAttachments.ts | 41 +
lib/flags.ts | 60 -
lib/formBuilder.tsx | 18 +-
lib/{integration => }/helpers.ts | 38 +-
lib/hooks/index.ts | 2 +
lib/hooks/useAccessControl.tsx | 38 +
lib/hooks/useAuth.ts | 436 +
...xternalScript.tsx => useExternalScript.ts} | 0
lib/hooks/{useFlag.tsx => useFlag.ts} | 0
.../{useFormTimer.tsx => useFormTimer.ts} | 0
lib/hooks/{useRefresh.tsx => useRefresh.ts} | 2 +-
lib/integration/crud.ts | 329 -
lib/integration/dbConnector.ts | 11 -
lib/integration/prismaConnector.ts | 44 +
lib/integration/queryManager.ts | 18 -
lib/lockout.ts | 90 +
lib/logger.ts | 2 +-
lib/markdown.ts | 4 +-
lib/middleware/csrfProtected.ts | 2 +-
lib/middleware/index.ts | 1 -
lib/middleware/jsonIDValidator.ts | 140 +
lib/middleware/jsonValidator.ts | 41 +-
lib/middleware/middleware.ts | 4 +-
lib/middleware/schemas/templates.schema.json | 353 +-
lib/middleware/sessionExists.ts | 6 +-
lib/middleware/validBearerToken.ts | 51 -
lib/middleware/validTemporaryToken.ts | 53 +-
lib/privileges.ts | 316 +
lib/routeUtils.ts | 4 +-
lib/templates.ts | 505 +
lib/tests/auth.test.ts | 366 +
lib/tests/cors.test.js | 6 +-
lib/tests/crud.test.js | 130 -
lib/tests/csrfProtected.test.js | 23 +-
lib/tests/dbconnector.test.js | 39 -
lib/tests/fileAttachments.test.ts | 35 +
lib/tests/formBuilder.test.js | 5 +-
lib/tests/helpers.test.js | 55 +-
lib/tests/jsonIDValidator.test.js | 144 +
lib/tests/jsonValidator.test.js | 29 +-
lib/tests/lockout.test.ts | 154 +
lib/tests/markdown.test.js | 32 +-
lib/tests/middleware.test.js | 4 +
lib/tests/privileges.test.ts | 116 +
lib/tests/queryManager.test.js | 41 -
lib/tests/sessionExists.test.js | 55 +-
lib/tests/templates.test.ts | 577 +
lib/tests/testData.js | 312 -
lib/tests/useFormTimer.test.js | 20 +-
lib/tests/users.test.js | 59 -
lib/tests/users.test.ts | 139 +
lib/tests/validBearerToken.test.js | 85 -
lib/tests/validation.test.js | 216 +-
lib/types/constants.ts | 4 +
lib/types/form-types.ts | 56 +-
lib/types/index.ts | 30 +-
lib/types/organization-types.ts | 13 -
lib/types/privileges-types.ts | 47 +
lib/types/retrieval-types.ts | 1 +
lib/types/user-types.ts | 2 +-
lib/types/utility-types.ts | 24 +-
lib/users.ts | 153 +-
lib/validation.tsx | 76 +-
migrations/index.js | 26 +-
migrations/migrations/011-next-auth-v4.js | 70 +
migrations/models/User.js | 24 -
migrations/models/index.js | 8 -
next-i18next.config.js | 3 +-
package.json | 142 +-
pages/404.js | 6 +-
pages/_app.tsx | 52 +-
pages/_error.js | 6 +-
pages/admin/flags.tsx | 32 +-
pages/admin/index.tsx | 47 +-
pages/admin/login.tsx | 30 +-
pages/admin/organizations/[id].tsx | 111 -
pages/admin/organizations/create.tsx | 96 -
pages/admin/organizations/index.tsx | 67 -
pages/admin/privileges.tsx | 266 +
pages/admin/unauthorized.tsx | 32 +-
pages/admin/upload.tsx | 39 +-
pages/admin/users.tsx | 278 +-
pages/admin/vault.tsx | 305 -
pages/admin/view-templates.tsx | 235 +-
pages/api/acceptableuse.ts | 23 +
pages/api/account/confirmpassword.ts | 48 +
pages/api/account/forgotpassword.ts | 45 +
pages/api/auth/[...nextauth].js | 43 -
pages/api/auth/[...nextauth].ts | 204 +
pages/api/flags/[key]/check.tsx | 9 +-
pages/api/flags/[key]/disable.tsx | 36 +-
pages/api/flags/[key]/enable.tsx | 35 +-
pages/api/flags/index.tsx | 26 +-
pages/api/id/[form]/apiusers.ts | 248 +
pages/api/id/[form]/bearer.ts | 224 +-
pages/api/id/[form]/owners.ts | 154 -
pages/api/id/[form]/retrieval.ts | 15 +-
pages/api/notify-callback.ts | 2 +-
pages/api/organizations.tsx | 47 -
pages/api/privileges.ts | 110 +
pages/api/request/publish.ts | 62 +
pages/api/request/support.ts | 90 +
pages/api/signup/confirm.ts | 46 +
pages/api/signup/register.ts | 63 +
pages/api/signup/resendconfirmation.ts | 47 +
pages/api/submit.ts | 69 +-
pages/api/templates.ts | 180 +-
pages/api/token/temporary.ts | 183 +-
pages/api/users.ts | 73 +-
pages/api/verify.ts | 2 +-
pages/auth/login.tsx | 205 +
pages/auth/logout.tsx | 51 +
pages/auth/policy.tsx | 53 +
pages/auth/resetpassword.tsx | 351 +
pages/changelog.tsx | 18 +-
pages/form-builder/edit/[[...params]].tsx | 49 +
pages/form-builder/edit/translate.tsx | 24 +
pages/form-builder/index.tsx | 88 +
pages/form-builder/preview/[[...params]].tsx | 24 +
pages/form-builder/publish.tsx | 55 +
pages/form-builder/published.tsx | 31 +
pages/form-builder/settings/[[...params]].tsx | 23 +
.../support/[[...supportType]].tsx | 388 +
pages/id/[form]/[[...step]].tsx | 83 +-
pages/id/[form]/retrieval.tsx | 50 +
pages/id/[form]/settings.tsx | 94 +-
pages/id/[form]/users.tsx | 155 +
pages/id/builder-preview.js | 53 -
pages/index.js | 34 -
pages/index.tsx | 44 +
pages/myforms/[[...path]].tsx | 165 +
pages/sandbox.tsx | 102 -
pages/signup/account-created.tsx | 66 +
pages/signup/register.tsx | 246 +
pages/sla.tsx | 34 +
pages/terms-avis.js | 25 -
pages/terms-avis.tsx | 34 +
pages/unlock-publishing.tsx | 274 +
pages/welcome-bienvenue.js | 53 -
.../20220506182127_initial/migration.sql | 140 +
.../migration.sql | 178 +
.../20220721184312_access_logs/migration.sql | 12 +
.../migration.sql | 12 +
.../20221006181804_permissions/migration.sql | 95 +
.../migration.sql | 2 +
.../migration.sql | 2 +
.../migration.sql | 3 +
prisma/migrations/migration_lock.toml | 3 +
prisma/schema.prisma | 110 +
prisma/seeds/fixtures/privileges.ts | 129 +
prisma/seeds/fixtures/templates.ts | 599 +
prisma/seeds/seed.ts | 84 +
public/img/form-builder-delete-dialog.svg | 7 +
public/img/form-builder-download.svg | 36 +
public/static/content/en/sla.md | 129 +
public/static/content/en/terms-of-use.md | 9 +
public/static/content/en/terms.md | 32 +-
public/static/content/fr/sla.md | 129 +
public/static/content/fr/terms-of-use.md | 14 +
public/static/content/fr/terms.md | 37 +-
public/static/locales/en/admin-flags.json | 16 +-
.../static/locales/en/admin-privileges.json | 7 +
public/static/locales/en/admin-templates.json | 11 +-
public/static/locales/en/admin-users.json | 10 +-
public/static/locales/en/cognito-errors.json | 19 +
public/static/locales/en/common.json | 43 +-
public/static/locales/en/form-builder.json | 256 +
.../locales/en/forms-responses-retrieval.json | 5 +
public/static/locales/en/login.json | 20 +
public/static/locales/en/logout.json | 6 +
public/static/locales/en/my-forms.json | 39 +
public/static/locales/en/organizations.json | 9 -
public/static/locales/en/policy.json | 3 +
public/static/locales/en/reset-password.json | 45 +
public/static/locales/en/signup.json | 83 +
public/static/locales/en/sla.json | 3 +
public/static/locales/en/terms.json | 3 +
.../static/locales/en/unlock-publishing.json | 30 +
public/static/locales/en/welcome.json | 29 -
public/static/locales/fr/admin-flags.json | 16 +-
.../static/locales/fr/admin-privileges.json | 7 +
public/static/locales/fr/admin-templates.json | 19 +-
public/static/locales/fr/admin-users.json | 10 +-
public/static/locales/fr/cognito-errors.json | 13 +
public/static/locales/fr/common.json | 46 +-
public/static/locales/fr/form-builder.json | 256 +
.../locales/fr/forms-responses-retrieval.json | 5 +
public/static/locales/fr/login.json | 20 +
public/static/locales/fr/logout.json | 5 +
public/static/locales/fr/my-forms.json | 39 +
public/static/locales/fr/organizations.json | 9 -
public/static/locales/fr/policy.json | 3 +
public/static/locales/fr/reset-password.json | 45 +
public/static/locales/fr/signup.json | 80 +
public/static/locales/fr/sla.json | 3 +
public/static/locales/fr/terms.json | 3 +
.../static/locales/fr/unlock-publishing.json | 30 +
public/static/locales/fr/welcome.json | 29 -
renovate.json | 40 +
styles/_base.scss | 116 +-
styles/_form-builder.scss | 419 +
styles/_forms.scss | 64 +-
styles/_header.scss | 29 +-
styles/app.scss | 1 +
tailwind.config.js | 222 +-
tests/Settings.test.js | 65 -
tests/api/flags.test.js | 108 -
tests/api/id/[form]/bearer.test.js | 378 -
tests/api/id/[form]/owners.test.js | 527 -
tests/api/templates.test.js | 177 -
tests/api/token/temporary.test.js | 143 -
tests/api/users.test.js | 273 -
tests/data/attestationTestForm.json | 50 -
tests/data/brokenFormTemplate.json | 673 -
tests/data/validFormTemplate.json | 671 -
tsconfig.json | 9 +-
types/i18next.d.ts | 7 +
types/next_auth/index.d.ts | 32 +-
types/react-app-polyfill/index.d.ts | 1 +
utils/cognitoBackup/.env_example | 3 +
utils/cognitoBackup/README.md | 21 +
utils/cognitoBackup/package.json | 22 +
utils/cognitoBackup/restoreUsers.ts | 153 +
utils/cognitoBackup/retrieveUsers.ts | 105 +
utils/cognitoBackup/tsconfig.json | 103 +
utils/cognitoBackup/yarn.lock | 1170 ++
utils/retrievalAPI/package.json | 4 +-
utils/retrievalAPI/yarn.lock | 16 +-
yarn.lock | 10882 +++++++++-------
575 files changed, 42298 insertions(+), 13511 deletions(-)
create mode 100644 .github/workflows/test-container-build-production.yml
create mode 100644 .github/workflows/test-container-build-staging.yml
create mode 100644 .idea/.name
create mode 100644 __fixtures__/accessibilityTestForm.json
create mode 100644 __fixtures__/attestationTestForm.json
create mode 100644 __fixtures__/brokenFormTemplate.json
rename {tests/data => __fixtures__}/cdsIntakeTestForm.json (96%)
create mode 100644 __fixtures__/duplicateElementIds.json
rename {tests/data => __fixtures__}/dynamicRowsTestForm.json (99%)
create mode 100644 __fixtures__/invalidLayoutIds.json
create mode 100644 __fixtures__/invalidSubElementIds.json
rename {tests/data => __fixtures__}/platformIntakeTestForm.json (97%)
create mode 100644 __fixtures__/testData.json
rename {tests/data => __fixtures__}/textFieldTestForm.json (100%)
rename {tests/data => __fixtures__}/tsbContactTestForm.json (98%)
rename {tests/data => __fixtures__}/tsbDisableFooterGCBranding.json (95%)
create mode 100644 __fixtures__/validFormTemplate.json
create mode 100644 __fixtures__/validFormTemplateWithHTMLInDynamicRow.json
create mode 100644 __tests__/api/acceptable-use.test.ts
create mode 100644 __tests__/api/account/confirmpassword.test.ts
create mode 100644 __tests__/api/account/forgotpassword.test.ts
create mode 100644 __tests__/api/flags.test.ts
create mode 100644 __tests__/api/id/form/apiUsers.test.ts
create mode 100644 __tests__/api/id/form/bearer.test.ts
rename tests/api/id/[form]/retrieval.test.js => __tests__/api/id/form/retrieval.test.ts (66%)
rename {tests => __tests__}/api/log.test.ts (96%)
rename {tests => __tests__}/api/notify-callbacks.test.js (99%)
create mode 100644 __tests__/api/request/publish.test.ts
create mode 100644 __tests__/api/request/support.test.ts
create mode 100644 __tests__/api/signup/confirm.test.ts
create mode 100644 __tests__/api/signup/register.test.ts
create mode 100644 __tests__/api/signup/resendconfirmation.test.ts
create mode 100644 __tests__/api/templates.test.ts
create mode 100644 __tests__/api/token/temporary.test.ts
create mode 100644 __tests__/api/users.test.ts
create mode 100644 __tests__/id/[form]/settings.test.js
create mode 100644 __utils__/index.ts
create mode 100644 __utils__/jestShim.ts
rename {lib => __utils__}/jestUtils.ts (100%)
create mode 100644 __utils__/mocks/middleware.ts
create mode 100644 __utils__/permissions.ts
create mode 100644 __utils__/prismaConnector.ts
rename {lib/tests => __utils__}/setupTests.ts (81%)
create mode 100644 components/admin/TemplateDelete/Settings.tsx
create mode 100644 components/auth/AcceptableUse.test.js
create mode 100644 components/auth/AcceptableUse.tsx
create mode 100644 components/auth/Confirmation/Confirmation.test.js
create mode 100644 components/auth/Confirmation/Confirmation.tsx
create mode 100644 components/auth/LoginMenu.test.js
create mode 100644 components/auth/LoginMenu.tsx
create mode 100644 components/form-builder/__tests__/useActivePathname.tsx
create mode 100644 components/form-builder/__tests__/useAllowPublish.test.tsx
create mode 100644 components/form-builder/__tests__/useModalStore.test.tsx
create mode 100644 components/form-builder/__tests__/useTemplateStore.test.tsx
create mode 100644 components/form-builder/__tests__/util.test.js
create mode 100644 components/form-builder/app/Preview.tsx
create mode 100644 components/form-builder/app/Publish.tsx
create mode 100644 components/form-builder/app/PublishNoAuth.tsx
create mode 100644 components/form-builder/app/Published.tsx
create mode 100644 components/form-builder/app/Settings.tsx
create mode 100644 components/form-builder/app/Start.tsx
create mode 100644 components/form-builder/app/Template.tsx
create mode 100644 components/form-builder/app/edit/ConfirmationDescription.tsx
create mode 100644 components/form-builder/app/edit/Edit.tsx
create mode 100644 components/form-builder/app/edit/ElementDropDown.tsx
create mode 100644 components/form-builder/app/edit/ElementPanel.tsx
create mode 100644 components/form-builder/app/edit/ElementRequired.tsx
create mode 100644 components/form-builder/app/edit/Modal.tsx
create mode 100644 components/form-builder/app/edit/ModalForm.tsx
create mode 100644 components/form-builder/app/edit/PanelActions.tsx
create mode 100644 components/form-builder/app/edit/PanelActionsLocked.tsx
create mode 100644 components/form-builder/app/edit/PanelBody.tsx
create mode 100644 components/form-builder/app/edit/PanelBodyRoot.tsx
create mode 100644 components/form-builder/app/edit/PrivacyDescription.tsx
create mode 100644 components/form-builder/app/edit/SelectedElement.tsx
create mode 100644 components/form-builder/app/edit/elements/BulkAdd.tsx
create mode 100644 components/form-builder/app/edit/elements/DropDown.tsx
create mode 100644 components/form-builder/app/edit/elements/Option.tsx
create mode 100644 components/form-builder/app/edit/elements/Options.tsx
create mode 100644 components/form-builder/app/edit/elements/RichText.tsx
create mode 100644 components/form-builder/app/edit/elements/RichTextLocked.tsx
create mode 100644 components/form-builder/app/edit/elements/ShortAnswer.tsx
create mode 100644 components/form-builder/app/edit/elements/index.ts
create mode 100644 components/form-builder/app/edit/elements/lexical-editor/Editor.tsx
create mode 100644 components/form-builder/app/edit/elements/lexical-editor/RichTextEditor.tsx
create mode 100644 components/form-builder/app/edit/elements/lexical-editor/ToolTip.tsx
create mode 100644 components/form-builder/app/edit/elements/lexical-editor/Toolbar.tsx
create mode 100644 components/form-builder/app/edit/elements/lexical-editor/config.ts
create mode 100644 components/form-builder/app/edit/elements/lexical-editor/plugins/FloatingLinkEditorPlugin/index.tsx
create mode 100644 components/form-builder/app/edit/elements/lexical-editor/plugins/FocusEditor.tsx
create mode 100644 components/form-builder/app/edit/elements/lexical-editor/plugins/ListMaxIndentPlugin.tsx
create mode 100644 components/form-builder/app/edit/elements/lexical-editor/useEditorFocus.tsx
create mode 100644 components/form-builder/app/edit/elements/lexical-editor/utils/getSelectedNode.ts
create mode 100644 components/form-builder/app/edit/elements/lexical-editor/utils/setFloatingElemPosition.ts
create mode 100644 components/form-builder/app/edit/elements/lexical-editor/utils/url.ts
create mode 100644 components/form-builder/app/edit/elements/question/Question.tsx
create mode 100644 components/form-builder/app/edit/elements/question/QuestionInput.tsx
create mode 100644 components/form-builder/app/edit/elements/question/QuestionNumber.tsx
create mode 100644 components/form-builder/app/edit/elements/tests/Dropdown.test.js
create mode 100644 components/form-builder/app/edit/elements/tests/Option.test.js
create mode 100644 components/form-builder/app/edit/elements/tests/Options.test.js
create mode 100644 components/form-builder/app/edit/elements/tests/RichText.test.js
create mode 100644 components/form-builder/app/edit/elements/tests/RichTextLocked.test.js
create mode 100644 components/form-builder/app/edit/elements/tests/ShortAnswer.test.js
create mode 100644 components/form-builder/app/edit/index.ts
create mode 100644 components/form-builder/app/edit/tests/ElementDropDown.test.js
create mode 100644 components/form-builder/app/edit/tests/ElementPanel.test.js
create mode 100644 components/form-builder/app/edit/tests/ElementRequired.test.js
create mode 100644 components/form-builder/app/edit/tests/Modal.test.js
create mode 100644 components/form-builder/app/index.ts
create mode 100644 components/form-builder/app/navigation/EditNavigation.tsx
create mode 100644 components/form-builder/app/navigation/Header.tsx
create mode 100644 components/form-builder/app/navigation/LeftNavLink.tsx
create mode 100644 components/form-builder/app/navigation/LeftNavigation.tsx
create mode 100644 components/form-builder/app/navigation/PreviewNavigation.tsx
create mode 100644 components/form-builder/app/navigation/SubNavLink.tsx
create mode 100644 components/form-builder/app/shared/Button.tsx
create mode 100644 components/form-builder/app/shared/ConfirmFormDeleteDialog.tsx
create mode 100644 components/form-builder/app/shared/CopyToClipboard.tsx
create mode 100644 components/form-builder/app/shared/Dialog.tsx
create mode 100644 components/form-builder/app/shared/DownloadFileButton.tsx
create mode 100644 components/form-builder/app/shared/Input.tsx
create mode 100644 components/form-builder/app/shared/LangSwitcher.tsx
create mode 100644 components/form-builder/app/shared/MultipleChoice.tsx
create mode 100644 components/form-builder/app/shared/Output.tsx
create mode 100644 components/form-builder/app/shared/ResumeEditingForm.tsx
create mode 100644 components/form-builder/app/shared/SaveButton.tsx
create mode 100644 components/form-builder/app/shared/TextArea.tsx
create mode 100644 components/form-builder/app/shared/index.ts
create mode 100644 components/form-builder/app/translate/Description.tsx
create mode 100644 components/form-builder/app/translate/DownloadCSV.tsx
create mode 100644 components/form-builder/app/translate/FieldsetLegend.tsx
create mode 100644 components/form-builder/app/translate/LanguageLabel.tsx
create mode 100644 components/form-builder/app/translate/Options.tsx
create mode 100644 components/form-builder/app/translate/RichText.tsx
create mode 100644 components/form-builder/app/translate/SectionTitle.tsx
create mode 100644 components/form-builder/app/translate/Title.tsx
create mode 100644 components/form-builder/app/translate/Translate.tsx
create mode 100644 components/form-builder/app/translate/index.ts
create mode 100644 components/form-builder/example-form.json
create mode 100644 components/form-builder/hooks/index.ts
create mode 100644 components/form-builder/hooks/useActivePathname.tsx
create mode 100644 components/form-builder/hooks/useAllowPublish.tsx
create mode 100644 components/form-builder/hooks/useDelete.tsx
create mode 100644 components/form-builder/hooks/useElementOptions.tsx
create mode 100644 components/form-builder/hooks/usePublish.tsx
create mode 100644 components/form-builder/hooks/useTemplateApi.tsx
create mode 100644 components/form-builder/hooks/useTemplateStatus.tsx
create mode 100644 components/form-builder/icons/BackArrowIcon.tsx
create mode 100644 components/form-builder/icons/BoldIcon.tsx
create mode 100644 components/form-builder/icons/BulletListIcon.tsx
create mode 100644 components/form-builder/icons/BulletedListIcon.tsx
create mode 100644 components/form-builder/icons/CalendarIcon.tsx
create mode 100644 components/form-builder/icons/CancelIcon.tsx
create mode 100644 components/form-builder/icons/CheckBoxEmptyIcon.tsx
create mode 100644 components/form-builder/icons/CheckIcon.tsx
create mode 100644 components/form-builder/icons/ChevronDown.tsx
create mode 100644 components/form-builder/icons/ChevronUp.tsx
create mode 100644 components/form-builder/icons/CircleCheckIcon.tsx
create mode 100644 components/form-builder/icons/Close.tsx
create mode 100644 components/form-builder/icons/DesignIcon.tsx
create mode 100644 components/form-builder/icons/Duplicate.tsx
create mode 100644 components/form-builder/icons/EditIcon.tsx
create mode 100644 components/form-builder/icons/EmailIcon.tsx
create mode 100644 components/form-builder/icons/ExternalLinkIcon.tsx
create mode 100644 components/form-builder/icons/FolderIcon.tsx
create mode 100644 components/form-builder/icons/GearIcon.tsx
create mode 100644 components/form-builder/icons/GlobeIcon.tsx
create mode 100644 components/form-builder/icons/H2Icon.tsx
create mode 100644 components/form-builder/icons/H3Icon.tsx
create mode 100644 components/form-builder/icons/InfoIcon.tsx
create mode 100644 components/form-builder/icons/ItalicIcon.tsx
create mode 100644 components/form-builder/icons/LinkIcon.tsx
create mode 100644 components/form-builder/icons/LockIcon.tsx
create mode 100644 components/form-builder/icons/MenuOpenIcon.tsx
create mode 100644 components/form-builder/icons/NumberedListIcon.tsx
create mode 100644 components/form-builder/icons/NumericFieldIcon.tsx
create mode 100644 components/form-builder/icons/PageIcon.tsx
create mode 100644 components/form-builder/icons/ParagraphIcon.tsx
create mode 100644 components/form-builder/icons/PhoneIcon.tsx
create mode 100644 components/form-builder/icons/PreviewIcon.tsx
create mode 100644 components/form-builder/icons/PublishIcon.tsx
create mode 100644 components/form-builder/icons/RadioEmptyIcon.tsx
create mode 100644 components/form-builder/icons/RadioIcon.tsx
create mode 100644 components/form-builder/icons/RocketIcon.tsx
create mode 100644 components/form-builder/icons/SaveIcon.tsx
create mode 100644 components/form-builder/icons/SelectMenuIcon.tsx
create mode 100644 components/form-builder/icons/ShareIcon.tsx
create mode 100644 components/form-builder/icons/ShortAnswerIcon.tsx
create mode 100644 components/form-builder/icons/ThreeDotsIcon.tsx
create mode 100644 components/form-builder/icons/ToggleLeft.tsx
create mode 100644 components/form-builder/icons/ToggleRight.tsx
create mode 100644 components/form-builder/icons/WarningIcon.tsx
create mode 100644 components/form-builder/icons/index.ts
create mode 100644 components/form-builder/notes.md
create mode 100644 components/form-builder/store/index.ts
create mode 100644 components/form-builder/store/useModalStore.tsx
create mode 100644 components/form-builder/store/useTemplateStore.tsx
create mode 100644 components/form-builder/test-utils/Providers.js
create mode 100644 components/form-builder/test-utils/defaultStore.json
create mode 100644 components/form-builder/test-utils/index.ts
create mode 100644 components/form-builder/types/index.ts
create mode 100644 components/form-builder/util.ts
create mode 100644 components/form-builder/validate.ts
create mode 100644 components/forms/Alert/Alert.stories.js
delete mode 100644 components/forms/Alert/Alert.stories.tsx
delete mode 100644 components/forms/Heading/Heading.stories.tsx
delete mode 100644 components/forms/Heading/Heading.test.js
delete mode 100644 components/forms/Heading/Heading.tsx
create mode 100644 components/globals/Attention/Attention.test.tsx
create mode 100644 components/globals/Attention/Attention.tsx
delete mode 100644 components/globals/Base.js
delete mode 100644 components/globals/Base.test.js
delete mode 100644 components/globals/Fip.js
create mode 100644 components/globals/Fip.tsx
delete mode 100644 components/globals/Footer.js
create mode 100644 components/globals/Footer.tsx
delete mode 100644 components/globals/PhaseBanner.js
create mode 100644 components/globals/StyledLink/StyledLink.test.js
create mode 100644 components/globals/StyledLink/StyledLink.tsx
create mode 100644 components/globals/layouts/AdminNavLayout.tsx
create mode 100644 components/globals/layouts/BaseLayout.test.js
create mode 100644 components/globals/layouts/BaseLayout.tsx
create mode 100644 components/globals/layouts/FormDisplayLayout.tsx
create mode 100644 components/globals/layouts/UserNavLayout.tsx
create mode 100644 components/myforms/Card/Card.test.js
create mode 100644 components/myforms/Card/Card.tsx
create mode 100644 components/myforms/CardGrid/CardGrid.test.js
create mode 100644 components/myforms/CardGrid/CardGrid.tsx
create mode 100644 components/myforms/LeftNav/LeftNavLink.tsx
create mode 100644 components/myforms/LeftNav/LeftNavigation.test.js
create mode 100644 components/myforms/LeftNav/LeftNavigation.tsx
create mode 100644 components/myforms/LeftNav/index.ts
create mode 100644 components/myforms/MenuDropdown/Menu.ts
create mode 100644 components/myforms/MenuDropdown/MenuDropdown.test.js
create mode 100644 components/myforms/MenuDropdown/MenuDropdown.tsx
create mode 100644 components/myforms/Tabs/Tab.tsx
create mode 100644 components/myforms/Tabs/TabPanel.tsx
create mode 100644 components/myforms/Tabs/Tabs.test.js
create mode 100644 components/myforms/Tabs/TabsKeynav.ts
create mode 100644 components/myforms/Tabs/TabsList.tsx
create mode 100644 cypress.config.js
delete mode 100644 cypress.json
create mode 100644 cypress/e2e/acceptable_use.cy.js
create mode 100644 cypress/e2e/accessibility.cy.js
rename cypress/{integration/attestation.spec.js => e2e/attestation.cy.js} (94%)
rename cypress/{integration/cds_intake.spec.js => e2e/cds_intake.cy.js} (95%)
rename cypress/{integration/character_limit.spec.js => e2e/character_limit.cy.js} (88%)
rename cypress/{integration/dynamic_rows.spec.js => e2e/dynamic_rows.cy.js} (98%)
rename cypress/{integration/forms_functionality.spec.js => e2e/forms_functionality.cy.js} (86%)
create mode 100644 cypress/e2e/login_page.cy.js
create mode 100644 cypress/e2e/logout.cy.js
rename cypress/{integration/platform_intake.spec.js => e2e/platform_intake.cy.js} (94%)
create mode 100644 cypress/e2e/register_page.cy.js
rename cypress/{integration/terms_conditions_page.spec.js => e2e/terms_conditions_page.cy.js} (89%)
rename cypress/{integration/tsb_contact.spec.js => e2e/tsb_contact.cy.js} (95%)
rename cypress/{integration/tsb_contact_remove_footer_gc_word.spec.js => e2e/tsb_contact_remove_footer_gc_word.cy.js} (84%)
delete mode 100644 cypress/integration/accessibility.spec.js
create mode 100644 cypress/integration/form-builder.spec.js
delete mode 100644 cypress/integration/welcome_page.spec.js
rename cypress/support/{index.js => e2e.js} (100%)
delete mode 100644 cypress/tsconfig.json
delete mode 100644 email.domains.json
create mode 100644 lib/acceptableUseCache.ts
create mode 100644 lib/cache/flags.ts
rename lib/{cache.ts => cache/formCache.ts} (56%)
create mode 100644 lib/cache/privilegeCache.ts
create mode 100644 lib/fileAttachments.ts
delete mode 100644 lib/flags.ts
rename lib/{integration => }/helpers.ts (92%)
create mode 100644 lib/hooks/useAccessControl.tsx
create mode 100644 lib/hooks/useAuth.ts
rename lib/hooks/{useExternalScript.tsx => useExternalScript.ts} (100%)
rename lib/hooks/{useFlag.tsx => useFlag.ts} (100%)
rename lib/hooks/{useFormTimer.tsx => useFormTimer.ts} (100%)
rename lib/hooks/{useRefresh.tsx => useRefresh.ts} (96%)
delete mode 100644 lib/integration/crud.ts
delete mode 100644 lib/integration/dbConnector.ts
create mode 100644 lib/integration/prismaConnector.ts
delete mode 100644 lib/integration/queryManager.ts
create mode 100644 lib/lockout.ts
create mode 100644 lib/middleware/jsonIDValidator.ts
delete mode 100644 lib/middleware/validBearerToken.ts
create mode 100644 lib/privileges.ts
create mode 100644 lib/templates.ts
create mode 100644 lib/tests/auth.test.ts
delete mode 100644 lib/tests/crud.test.js
delete mode 100644 lib/tests/dbconnector.test.js
create mode 100644 lib/tests/fileAttachments.test.ts
create mode 100644 lib/tests/jsonIDValidator.test.js
create mode 100644 lib/tests/lockout.test.ts
create mode 100644 lib/tests/privileges.test.ts
delete mode 100644 lib/tests/queryManager.test.js
create mode 100644 lib/tests/templates.test.ts
delete mode 100644 lib/tests/testData.js
delete mode 100644 lib/tests/users.test.js
create mode 100644 lib/tests/users.test.ts
delete mode 100644 lib/tests/validBearerToken.test.js
create mode 100644 lib/types/constants.ts
delete mode 100644 lib/types/organization-types.ts
create mode 100644 lib/types/privileges-types.ts
create mode 100644 migrations/migrations/011-next-auth-v4.js
delete mode 100644 migrations/models/User.js
delete mode 100644 migrations/models/index.js
delete mode 100644 pages/admin/organizations/[id].tsx
delete mode 100644 pages/admin/organizations/create.tsx
delete mode 100644 pages/admin/organizations/index.tsx
create mode 100644 pages/admin/privileges.tsx
delete mode 100644 pages/admin/vault.tsx
create mode 100644 pages/api/acceptableuse.ts
create mode 100644 pages/api/account/confirmpassword.ts
create mode 100644 pages/api/account/forgotpassword.ts
delete mode 100644 pages/api/auth/[...nextauth].js
create mode 100644 pages/api/auth/[...nextauth].ts
create mode 100644 pages/api/id/[form]/apiusers.ts
delete mode 100644 pages/api/id/[form]/owners.ts
delete mode 100644 pages/api/organizations.tsx
create mode 100644 pages/api/privileges.ts
create mode 100644 pages/api/request/publish.ts
create mode 100644 pages/api/request/support.ts
create mode 100644 pages/api/signup/confirm.ts
create mode 100644 pages/api/signup/register.ts
create mode 100644 pages/api/signup/resendconfirmation.ts
create mode 100644 pages/auth/login.tsx
create mode 100644 pages/auth/logout.tsx
create mode 100644 pages/auth/policy.tsx
create mode 100644 pages/auth/resetpassword.tsx
create mode 100644 pages/form-builder/edit/[[...params]].tsx
create mode 100644 pages/form-builder/edit/translate.tsx
create mode 100644 pages/form-builder/index.tsx
create mode 100644 pages/form-builder/preview/[[...params]].tsx
create mode 100644 pages/form-builder/publish.tsx
create mode 100644 pages/form-builder/published.tsx
create mode 100644 pages/form-builder/settings/[[...params]].tsx
create mode 100644 pages/form-builder/support/[[...supportType]].tsx
create mode 100644 pages/id/[form]/retrieval.tsx
create mode 100644 pages/id/[form]/users.tsx
delete mode 100644 pages/id/builder-preview.js
delete mode 100644 pages/index.js
create mode 100644 pages/index.tsx
create mode 100644 pages/myforms/[[...path]].tsx
delete mode 100644 pages/sandbox.tsx
create mode 100644 pages/signup/account-created.tsx
create mode 100644 pages/signup/register.tsx
create mode 100644 pages/sla.tsx
delete mode 100644 pages/terms-avis.js
create mode 100644 pages/terms-avis.tsx
create mode 100644 pages/unlock-publishing.tsx
delete mode 100644 pages/welcome-bienvenue.js
create mode 100644 prisma/migrations/20220506182127_initial/migration.sql
create mode 100644 prisma/migrations/20220506200853_prisma_conversion/migration.sql
create mode 100644 prisma/migrations/20220721184312_access_logs/migration.sql
create mode 100644 prisma/migrations/20220817190507_add_user_roles/migration.sql
create mode 100644 prisma/migrations/20221006181804_permissions/migration.sql
create mode 100644 prisma/migrations/20221031124445_add_ttl_to_template/migration.sql
create mode 100644 prisma/migrations/20221031175512_add_ispublished_to_template/migration.sql
create mode 100644 prisma/migrations/20221104174253_template_updated_at/migration.sql
create mode 100644 prisma/migrations/migration_lock.toml
create mode 100644 prisma/schema.prisma
create mode 100644 prisma/seeds/fixtures/privileges.ts
create mode 100644 prisma/seeds/fixtures/templates.ts
create mode 100644 prisma/seeds/seed.ts
create mode 100644 public/img/form-builder-delete-dialog.svg
create mode 100644 public/img/form-builder-download.svg
create mode 100644 public/static/content/en/sla.md
create mode 100644 public/static/content/en/terms-of-use.md
create mode 100644 public/static/content/fr/sla.md
create mode 100644 public/static/content/fr/terms-of-use.md
create mode 100644 public/static/locales/en/admin-privileges.json
create mode 100644 public/static/locales/en/cognito-errors.json
create mode 100644 public/static/locales/en/form-builder.json
create mode 100644 public/static/locales/en/forms-responses-retrieval.json
create mode 100644 public/static/locales/en/login.json
create mode 100644 public/static/locales/en/logout.json
create mode 100644 public/static/locales/en/my-forms.json
delete mode 100644 public/static/locales/en/organizations.json
create mode 100644 public/static/locales/en/policy.json
create mode 100644 public/static/locales/en/reset-password.json
create mode 100644 public/static/locales/en/signup.json
create mode 100644 public/static/locales/en/sla.json
create mode 100644 public/static/locales/en/terms.json
create mode 100644 public/static/locales/en/unlock-publishing.json
delete mode 100644 public/static/locales/en/welcome.json
create mode 100644 public/static/locales/fr/admin-privileges.json
create mode 100644 public/static/locales/fr/cognito-errors.json
create mode 100644 public/static/locales/fr/form-builder.json
create mode 100644 public/static/locales/fr/forms-responses-retrieval.json
create mode 100644 public/static/locales/fr/login.json
create mode 100644 public/static/locales/fr/logout.json
create mode 100644 public/static/locales/fr/my-forms.json
delete mode 100644 public/static/locales/fr/organizations.json
create mode 100644 public/static/locales/fr/policy.json
create mode 100644 public/static/locales/fr/reset-password.json
create mode 100644 public/static/locales/fr/signup.json
create mode 100644 public/static/locales/fr/sla.json
create mode 100644 public/static/locales/fr/terms.json
create mode 100644 public/static/locales/fr/unlock-publishing.json
delete mode 100644 public/static/locales/fr/welcome.json
create mode 100644 renovate.json
create mode 100644 styles/_form-builder.scss
delete mode 100644 tests/Settings.test.js
delete mode 100644 tests/api/flags.test.js
delete mode 100644 tests/api/id/[form]/bearer.test.js
delete mode 100644 tests/api/id/[form]/owners.test.js
delete mode 100644 tests/api/templates.test.js
delete mode 100644 tests/api/token/temporary.test.js
delete mode 100644 tests/api/users.test.js
delete mode 100644 tests/data/attestationTestForm.json
delete mode 100644 tests/data/brokenFormTemplate.json
delete mode 100644 tests/data/validFormTemplate.json
create mode 100644 types/i18next.d.ts
create mode 100644 types/react-app-polyfill/index.d.ts
create mode 100644 utils/cognitoBackup/.env_example
create mode 100644 utils/cognitoBackup/README.md
create mode 100644 utils/cognitoBackup/package.json
create mode 100644 utils/cognitoBackup/restoreUsers.ts
create mode 100644 utils/cognitoBackup/retrieveUsers.ts
create mode 100644 utils/cognitoBackup/tsconfig.json
create mode 100644 utils/cognitoBackup/yarn.lock
diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index 1b72bd20f3..3ccc4c1608 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -1,4 +1,4 @@
-ARG VARIANT=16
+ARG VARIANT=16@sha256:1bbd8b82f5a78b6461d3285b62293db99ad60cf4eca35c715636d7143abb057c@sha256:b35e76ba744a975b9a5428b6c3cde1a1cf0be53b246e1e9a4874f87034222b5a@sha256:b35e76ba744a975b9a5428b6c3cde1a1cf0be53b246e1e9a4874f87034222b5a
FROM node:${VARIANT}
diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml
index 3f60372a50..6b7edb2d42 100644
--- a/.devcontainer/docker-compose.yml
+++ b/.devcontainer/docker-compose.yml
@@ -14,7 +14,7 @@ services:
- 3000
db:
- image: postgres:11.2
+ image: postgres:11.16@sha256:5d2aa4a7b5f9bdadeddcf87cf7f90a176737a02a30d917de4ab2e6a329bd2d45
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
@@ -30,7 +30,7 @@ services:
redis:
restart: unless-stopped
- image: redis:latest
+ image: redis:latest@sha256:fdaa0102e0c66802845aa5c961cb89a091a188056811802383660cd9e10889da
ports:
- "6379:6379"
expose:
diff --git a/.env.example b/.env.example
index bd980fff2f..f8a7bbd04c 100644
--- a/.env.example
+++ b/.env.example
@@ -9,7 +9,7 @@ RECAPTCHA_V3_SITE_KEY=
# The secret key authorizes communication between your application backend
# and the reCAPTCHA server to verify the user's response
-RECAPTACHA_V3_SECRET_KEY=
+RECAPTCHA_V3_SECRET_KEY=
# Used by /api/notify-callback to authorize request
GC_NOTIFY_CALLBACK_BEARER_TOKEN=
@@ -33,11 +33,10 @@ GOOGLE_CLIENT_ID=[retrieve from lastpass]
GOOGLE_CLIENT_SECRET=[retrieve from lastpass]
# Local dev
-# Temporary token templateID
-TEMPORAY_TOKEN_TEMPLATE_ID=b6kdhaud-d10a-422a-973f-05e274d9aa86
-
-# An ID of the template to send a form's response
-TEMPLATE_ID=8pa6247s75-a1d6-4e3c-8421-042a2b4158b7
+# Temporary token template ID
+TEMPORARY_TOKEN_TEMPLATE_ID=something
+# Form response template ID
+TEMPLATE_ID=something
# Used when no Redis instance or Database is available
# The application returns all default flags values when this variable is set.
diff --git a/.eslintrc.js b/.eslintrc.js
index 510e8ff9c1..ce2d5bf9ba 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -11,9 +11,12 @@ module.exports = {
parser: "@typescript-eslint/parser",
parserOptions: {
- project: "./tsconfig.json",
+ project: ["./tsconfig.json", "cypress/tsconfig.json"],
},
plugins: ["@typescript-eslint", "jsx-a11y", "prettier"],
+ rules: {
+ "@typescript-eslint/await-thenable": "error",
+ },
},
],
env: {
@@ -44,9 +47,9 @@ module.exports = {
},
},
plugins: ["react", "jsx-a11y", "prettier", "cypress"],
- ignorePatterns: ["**/storybook-static/*.*"],
rules: {
"prettier/prettier": "error",
"no-console": "error",
+ "no-await-in-loop": "error",
},
};
diff --git a/.github/workflows/build-and-deploy-storybooks.yml b/.github/workflows/build-and-deploy-storybooks.yml
index 0c210061a7..9f8c304330 100644
--- a/.github/workflows/build-and-deploy-storybooks.yml
+++ b/.github/workflows/build-and-deploy-storybooks.yml
@@ -1,15 +1,25 @@
name: Build and Deploy Storybooks
on:
pull_request:
+ paths-ignore:
+ # Ignore all files and folders that start with '.'
+ - ".**"
+ # Ignore all files and folder in fixtures, tests, utils, etc.
+ - "__*/**"
push:
branches: [main]
+ paths-ignore:
+ # Ignore all files and folders that start with '.'
+ - ".**"
+ # Ignore all files and folder in fixtures, tests, utils, etc.
+ - "__*/**"
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout 🛎️
- uses: actions/checkout@v2.3.1 # If you're using actions/checkout@v2 you must set persist-credentials to false in most cases for the deployment to work correctly.
+ uses: actions/checkout@dc323e67f16fb5f7663d20ff7941f27f5809e9b6 # v2.6.0 # If you're using actions/checkout@v2 you must set persist-credentials to false in most cases for the deployment to work correctly.
- name: Install 🔧 # This example project is built using yarn and outputs the result to the 'build' folder. Replace with the commands required to build your project, or remove this step entirely if your site is pre-built.
run: yarn install
@@ -23,7 +33,7 @@ jobs:
id: extract_branch
- name: Deploy 🚀
- uses: JamesIves/github-pages-deploy-action@3.6.2
+ uses: JamesIves/github-pages-deploy-action@e80c869f0057899fc2cd28819b5bbe9de890524a # tag=3.6.2
with:
TARGET_FOLDER: ${{ steps.extract_branch.outputs.branch }}
BRANCH: gh-pages # The branch the action should deploy to.
@@ -32,7 +42,7 @@ jobs:
- name: Find Comment
if: ${{ github.event_name == 'pull_request' }}
- uses: peter-evans/find-comment@v1
+ uses: peter-evans/find-comment@d2dae40ed151c634e4189471272b57e76ec19ba8 # v1.3.0
id: fc
with:
issue-number: ${{ github.event.pull_request.number }}
@@ -43,7 +53,7 @@ jobs:
- name: Create or update comment # comment in pull request storybooks link
if: ${{ github.event_name == 'pull_request' }}
- uses: peter-evans/create-or-update-comment@v1
+ uses: peter-evans/create-or-update-comment@a35cf36e5301d70b76f316e867e7788a55a31dae # v1.4.5
with:
comment-id: ${{ steps.fc.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 3eb1796b12..1ea69a8b52 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -28,20 +28,11 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v3
- with:
- # We must fetch at least the immediate parents so that if this is
- # a pull request then we can checkout the head.
- fetch-depth: 2
-
- # If this run was triggered by a pull request event, then checkout
- # the head of the pull request instead of the merge commit.
- - run: git checkout HEAD^2
- if: ${{ github.event_name == 'pull_request' }}
+ uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@v2
+ uses: github/codeql-action/init@959cbb7472c4d4ad70cdfe6f4976053fe48ab394 # v2.1.37
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -52,7 +43,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
- uses: github/codeql-action/autobuild@v2
+ uses: github/codeql-action/autobuild@959cbb7472c4d4ad70cdfe6f4976053fe48ab394 # v2.1.37
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -66,4 +57,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v2
+ uses: github/codeql-action/analyze@959cbb7472c4d4ad70cdfe6f4976053fe48ab394 # v2.1.37
diff --git a/.github/workflows/cypress.yml b/.github/workflows/cypress.yml
index 7a0a2d69d9..9d293a9535 100644
--- a/.github/workflows/cypress.yml
+++ b/.github/workflows/cypress.yml
@@ -9,23 +9,24 @@ jobs:
name: Cypress
runs-on: ubuntu-latest
env:
- AWS_ACCESS_KEY_ID: ${{ secrets.LAMBDA_AWS_ID }}
- AWS_SECRET_ACCESS_KEY: ${{ secrets.LAMBDA_AWS_SECRET}}
+ # Needed for Next Auth to initialize
NEXTAUTH_URL: http://localhost:3000
+ TOKEN_SECRET: testKey
+ GOOGLE_CLIENT_ID: testClientID
+ GOOGLE_CLIENT_SECRET: testClientSecret
APP_ENV: test
steps:
- name: Checkout
- uses: actions/checkout@v1
- - uses: cypress-io/github-action@v2
+ uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e # v1.2.0
+ - uses: cypress-io/github-action@d79d2d530a66e641eb4a5f227e13bc985c60b964 # v4.2.2
with:
+ browser: chrome
+ headed: false
build: yarn build
start: yarn start:test
wait-on: "http://localhost:3000"
- command: yarn cypress:headless
config: baseUrl=http://localhost:3000
- parallel: false
- group: "Form E2E Tests"
- - uses: actions/upload-artifact@v1
+ - uses: actions/upload-artifact@3446296876d12d4e3a0f3145a3c87e67bf0a16b5 # tag=v1
if: failure()
with:
name: cypress-screenshots
diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml
index 6636830a49..a33d592f56 100644
--- a/.github/workflows/eslint.yml
+++ b/.github/workflows/eslint.yml
@@ -10,9 +10,9 @@ jobs:
runs-on: ubuntu-latest
if: github.event_name == 'push'
steps:
- - uses: actions/checkout@v1
+ - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e # v1.2.0
- name: Node.JS 16
- uses: actions/setup-node@v2
+ uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 # v2.5.1
with:
node-version: 16
- name: Install Node Dependencies
@@ -28,9 +28,9 @@ jobs:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- - uses: actions/checkout@v1
+ - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e # v1.2.0
- name: Node.JS 16
- uses: actions/setup-node@v2
+ uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 # v2.5.1
with:
node-version: 16
- name: Install Node Dependencies
@@ -48,13 +48,13 @@ jobs:
# Continue to the next step even if this fails
continue-on-error: true
- name: Annotate Code Linting Results
- uses: ataylorme/eslint-annotate-action@1.1.2
+ uses: ataylorme/eslint-annotate-action@47568f60ae08ffa4d3b1bab645e21e9ae8266980 # tag=1.1.2
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
report-json: "eslint_report.json"
continue-on-error: true
- name: Upload ESLint report
- uses: actions/upload-artifact@v1
+ uses: actions/upload-artifact@3446296876d12d4e3a0f3145a3c87e67bf0a16b5 # tag=v1
with:
name: eslint_report.json
path: eslint_report.json
diff --git a/.github/workflows/generate-sbom.yml b/.github/workflows/generate-sbom.yml
index d0997d76fb..ad61df5840 100644
--- a/.github/workflows/generate-sbom.yml
+++ b/.github/workflows/generate-sbom.yml
@@ -19,10 +19,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@dc323e67f16fb5f7663d20ff7941f27f5809e9b6 # v2.6.0
- name: Generate app SBOM
- uses: cds-snc/security-tools/.github/actions/generate-sbom@4c6b386722985552f3f008d04279a3f01402cc35 # renovate: tag=v1
+ uses: cds-snc/security-tools/.github/actions/generate-sbom@4368a5486da1f0bb698ffe717687612d4231c6cd # v1.1.7
with:
dependency_track_api_key: ${{ secrets.DEPENDENCY_TRACK_API_KEY }}
project_name: forms-client/app
diff --git a/.github/workflows/jest.yml b/.github/workflows/jest.yml
index 9eb0ddfa62..17b9859665 100644
--- a/.github/workflows/jest.yml
+++ b/.github/workflows/jest.yml
@@ -9,7 +9,7 @@ jobs:
name: Jest
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v1
+ - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e # v1.2.0
- name: "Install dependencies"
run: yarn install
- name: Jest Tests
diff --git a/.github/workflows/prod-build-push-container.yml b/.github/workflows/prod-build-push-container.yml
index 9890c1bf7d..dc5c9abdd9 100644
--- a/.github/workflows/prod-build-push-container.yml
+++ b/.github/workflows/prod-build-push-container.yml
@@ -3,17 +3,26 @@ name: Production — Push container to ECR
on:
push:
branches: [main]
+ paths-ignore:
+ # Ignore all files and folders that start with '.'
+ - ".**"
+ # Ignore all files and folder in fixtures, tests, utils, etc.
+ - "__*/**"
env:
ECR_REPOSITORY: form_viewer_production
GITHUB_SHA: ${{ github.sha }}
+ GOOGLE_CLIENT_SECRET: ${{ secrets.PRODUCTION_GOOGLE_CLIENT_SECRET }}
+ GOOGLE_CLIENT_ID: ${{ secrets.PRODUCTION_GOOGLE_CLIENT_ID }}
+ COGNITO_APP_CLIENT_ID: ${{secrets.PRODUCTION_COGNITO_APP_CLIENT_ID}}
+ COGNITO_USER_POOL_ID: ${{ secrets.PRODUCTION_COGNITO_USER_POOL_ID}}
jobs:
push-production:
runs-on: ubuntu-latest
steps:
- name: Wait for Jest tests to pass
- uses: fountainhead/action-wait-for-check@v1.0.0
+ uses: fountainhead/action-wait-for-check@297be350cf8393728ea4d4b39435c7d7ae167c93 # v1.1.0
id: wait-for-jest-tests
with:
token: ${{ secrets.GITHUB_TOKEN }}
@@ -21,7 +30,7 @@ jobs:
ref: ${{ github.sha }}
- name: Wait for Cypress tests to pass
- uses: fountainhead/action-wait-for-check@v1.0.0
+ uses: fountainhead/action-wait-for-check@297be350cf8393728ea4d4b39435c7d7ae167c93 # v1.1.0
id: wait-for-cypress-tests
with:
token: ${{ secrets.GITHUB_TOKEN }}
@@ -29,7 +38,7 @@ jobs:
ref: ${{ github.sha }}
- name: Wait for ESLint tests to pass
- uses: fountainhead/action-wait-for-check@v1.0.0
+ uses: fountainhead/action-wait-for-check@297be350cf8393728ea4d4b39435c7d7ae167c93 # v1.1.0
id: wait-for-eslint-tests
with:
token: ${{ secrets.GITHUB_TOKEN }}
@@ -37,17 +46,21 @@ jobs:
ref: ${{ github.sha }}
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@dc323e67f16fb5f7663d20ff7941f27f5809e9b6 # v2.6.0
- name: Build Form Viewer
run: |
docker build -t base \
--build-arg PRODUCTION_ENV=true \
- --build-arg GITHUB_SHA_ARG=$GITHUB_SHA .
+ --build-arg GITHUB_SHA_ARG=$GITHUB_SHA \
+ --build-arg GOOGLE_CLIENT_SECRET=$GOOGLE_CLIENT_SECRET \
+ --build-arg GOOGLE_CLIENT_ID=$GOOGLE_CLIENT_ID \
+ --build-arg COGNITO_APP_CLIENT_ID=$COGNITO_APP_CLIENT_ID \
+ --build-arg COGNITO_USER_POOL_ID=$COGNITO_USER_POOL_ID .
- name: Configure Production AWS credentials
id: aws-form-viewer
- uses: aws-actions/configure-aws-credentials@51e2d042f8c5cf77f151685c9338e989dc0b8fc8
+ uses: aws-actions/configure-aws-credentials@3654529dc6db288721684d6c54fefa0c1182728f
with:
aws-access-key-id: ${{ secrets.PROD_AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.PROD_AWS_SECRET_ACCESS_KEY }}
@@ -55,7 +68,7 @@ jobs:
- name: Login to Production Amazon ECR
id: login-ecr-production
- uses: aws-actions/amazon-ecr-login@b9c809dc38d74cd0fde3c13cc4fe4ac72ebecdae
+ uses: aws-actions/amazon-ecr-login@d2897b5335975f749897eb8cb16345b12a17042f
- name: Tag Images for Production
env:
diff --git a/.github/workflows/s3-backup.yml b/.github/workflows/s3-backup.yml
index 18ff6cbfd0..d89ee4033c 100644
--- a/.github/workflows/s3-backup.yml
+++ b/.github/workflows/s3-backup.yml
@@ -10,12 +10,12 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
with:
fetch-depth: 0 # retrieve all history
- name: Configure AWS credentials
- uses: aws-actions/configure-aws-credentials@v1
+ uses: aws-actions/configure-aws-credentials@67fbcbb121271f7775d2e7715933280b06314838 # tag=v1.7.0
with:
aws-access-key-id: ${{ secrets.AWS_S3_BACKUP_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_S3_BACKUP_SECRET_ACCESS_KEY }}
diff --git a/.github/workflows/staging-build-push-container.yml b/.github/workflows/staging-build-push-container.yml
index 24b19bc387..d6baa01dc3 100644
--- a/.github/workflows/staging-build-push-container.yml
+++ b/.github/workflows/staging-build-push-container.yml
@@ -3,17 +3,26 @@ name: "Staging — Push container to ECR"
on:
push:
branches: [develop]
+ paths-ignore:
+ # Ignore all files and folders that start with '.'
+ - ".**"
+ # Ignore all files and folder in fixtures, tests, utils, etc.
+ - "__*/**"
env:
ECR_REPOSITORY: form_viewer_staging
GITHUB_SHA: ${{ github.sha }}
+ GOOGLE_CLIENT_SECRET: ${{ secrets.STAGING_GOOGLE_CLIENT_SECRET }}
+ GOOGLE_CLIENT_ID: ${{ secrets.STAGING_GOOGLE_CLIENT_ID }}
+ COGNITO_APP_CLIENT_ID: ${{secrets.STAGING_COGNITO_APP_CLIENT_ID}}
+ COGNITO_USER_POOL_ID: ${{ secrets.STAGING_COGNITO_USER_POOL_ID}}
jobs:
push-staging:
runs-on: ubuntu-latest
steps:
- name: Wait for Jest tests to pass
- uses: fountainhead/action-wait-for-check@v1.0.0
+ uses: fountainhead/action-wait-for-check@297be350cf8393728ea4d4b39435c7d7ae167c93 # v1.1.0
id: wait-for-jest-tests
with:
token: ${{ secrets.GITHUB_TOKEN }}
@@ -21,7 +30,7 @@ jobs:
ref: ${{ github.sha }}
- name: Wait for Cypress tests to pass
- uses: fountainhead/action-wait-for-check@v1.0.0
+ uses: fountainhead/action-wait-for-check@297be350cf8393728ea4d4b39435c7d7ae167c93 # v1.1.0
id: wait-for-cypress-tests
with:
token: ${{ secrets.GITHUB_TOKEN }}
@@ -29,7 +38,7 @@ jobs:
ref: ${{ github.sha }}
- name: Wait for ESLint tests to pass
- uses: fountainhead/action-wait-for-check@v1.0.0
+ uses: fountainhead/action-wait-for-check@297be350cf8393728ea4d4b39435c7d7ae167c93 # v1.1.0
id: wait-for-eslint-tests
with:
token: ${{ secrets.GITHUB_TOKEN }}
@@ -37,16 +46,20 @@ jobs:
ref: ${{ github.sha }}
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@dc323e67f16fb5f7663d20ff7941f27f5809e9b6 # v2.6.0
- name: Build Form Viewer
run: |
docker build -t base \
- --build-arg GITHUB_SHA_ARG=$GITHUB_SHA .
+ --build-arg GITHUB_SHA_ARG=$GITHUB_SHA \
+ --build-arg GOOGLE_CLIENT_SECRET=$GOOGLE_CLIENT_SECRET \
+ --build-arg GOOGLE_CLIENT_ID=$GOOGLE_CLIENT_ID \
+ --build-arg COGNITO_APP_CLIENT_ID=$COGNITO_APP_CLIENT_ID \
+ --build-arg COGNITO_USER_POOL_ID=$COGNITO_USER_POOL_ID .
- name: Configure Staging AWS credentials
id: aws-form-viewer
- uses: aws-actions/configure-aws-credentials@51e2d042f8c5cf77f151685c9338e989dc0b8fc8
+ uses: aws-actions/configure-aws-credentials@3654529dc6db288721684d6c54fefa0c1182728f
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
@@ -54,7 +67,7 @@ jobs:
- name: Login to Staging Amazon ECR
id: login-ecr-staging
- uses: aws-actions/amazon-ecr-login@b9c809dc38d74cd0fde3c13cc4fe4ac72ebecdae
+ uses: aws-actions/amazon-ecr-login@d2897b5335975f749897eb8cb16345b12a17042f
- name: Tag Images for Staging
env:
@@ -75,11 +88,11 @@ jobs:
run: docker logout ${{ steps.login-ecr-staging.outputs.registry }}
- name: Generate forms-client/app/docker SBOM
- uses: cds-snc/security-tools/.github/actions/generate-sbom@4c6b386722985552f3f008d04279a3f01402cc35 # renovate: tag=v1
+ uses: cds-snc/security-tools/.github/actions/generate-sbom@4368a5486da1f0bb698ffe717687612d4231c6cd # v1.1.7
env:
- ECR_REGISTRY: ${{ steps.login-ecr-staging.outputs.registry }}
+ ECR_REGISTRY: ${{ steps.login-ecr-staging.outputs.registry }}
with:
dependency_track_api_key: ${{ secrets.DEPENDENCY_TRACK_API_KEY }}
docker_image: $ECR_REGISTRY/$ECR_REPOSITORY:$GITHUB_SHA
project_name: forms-client/app/docker
- project_type: docker
+ project_type: docker
diff --git a/.github/workflows/staging-deploy.yml b/.github/workflows/staging-deploy.yml
index 376bb5ed9e..c3b8e010f8 100644
--- a/.github/workflows/staging-deploy.yml
+++ b/.github/workflows/staging-deploy.yml
@@ -22,11 +22,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@dc323e67f16fb5f7663d20ff7941f27f5809e9b6 # v2.6.0
- name: Configure AWS credentials
# v1 as of Jan 28 2021
- uses: aws-actions/configure-aws-credentials@51e2d042f8c5cf77f151685c9338e989dc0b8fc8
+ uses: aws-actions/configure-aws-credentials@3654529dc6db288721684d6c54fefa0c1182728f
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
@@ -35,7 +35,7 @@ jobs:
- name: Login to Amazon ECR
id: login-ecr
# v1 as of Jan 28 2021
- uses: aws-actions/amazon-ecr-login@b9c809dc38d74cd0fde3c13cc4fe4ac72ebecdae
+ uses: aws-actions/amazon-ecr-login@d2897b5335975f749897eb8cb16345b12a17042f
- name: Get Cluster Name
id: cluster
@@ -51,7 +51,7 @@ jobs:
- name: Render image for form viewer service
id: taskdef-form-viewer
# v1.0.10
- uses: aws-actions/amazon-ecs-render-task-definition@9666dc9d3bf790a3a6a49737b240f17fa599a5f2
+ uses: aws-actions/amazon-ecs-render-task-definition@aeae8fb93c2ca0168fe4fc6e8d35607b1ddd8876
with:
task-definition: form_viewer.json
container-name: ${{ steps.download-taskdef-form-viewer.outputs.container_name }}
@@ -67,7 +67,7 @@ jobs:
- name: Deploy image for Form Viewer
timeout-minutes: 10
# v1.4.2
- uses: aws-actions/amazon-ecs-deploy-task-definition@c74a8ca2cd0dd04d25f469715e23cb6c2fe0f01a
+ uses: aws-actions/amazon-ecs-deploy-task-definition@67f6f62a733c5de6ba4ba69fc2a2bb8802945a7f
with:
task-definition: ${{ steps.taskdef-form-viewer.outputs.task-definition }}
service: form-viewer
diff --git a/.github/workflows/test-container-build-production.yml b/.github/workflows/test-container-build-production.yml
new file mode 100644
index 0000000000..b20180b454
--- /dev/null
+++ b/.github/workflows/test-container-build-production.yml
@@ -0,0 +1,29 @@
+name: "Test Production Container Build"
+
+on:
+ pull_request:
+ branches: [main]
+
+env:
+ GITHUB_SHA: ${{ github.sha }}
+ GOOGLE_CLIENT_SECRET: ${{ secrets.PRODUCTION_GOOGLE_CLIENT_SECRET }}
+ GOOGLE_CLIENT_ID: ${{ secrets.PRODUCTION_GOOGLE_CLIENT_ID }}
+ COGNITO_APP_CLIENT_ID: ${{secrets.PRODUCTION_COGNITO_APP_CLIENT_ID}}
+ COGNITO_USER_POOL_ID: ${{ secrets.PRODUCTION_COGNITO_USER_POOL_ID}}
+
+jobs:
+ test-container:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@dc323e67f16fb5f7663d20ff7941f27f5809e9b6 # v2.6.0
+
+ - name: Build Container
+ run: |
+ docker build -t base \
+ --build-arg PRODUCTION_ENV=true \
+ --build-arg GITHUB_SHA_ARG=$GITHUB_SHA \
+ --build-arg GOOGLE_CLIENT_SECRET=$GOOGLE_CLIENT_SECRET \
+ --build-arg GOOGLE_CLIENT_ID=$GOOGLE_CLIENT_ID \
+ --build-arg COGNITO_APP_CLIENT_ID=$COGNITO_APP_CLIENT_ID \
+ --build-arg COGNITO_USER_POOL_ID=$COGNITO_USER_POOL_ID .
\ No newline at end of file
diff --git a/.github/workflows/test-container-build-staging.yml b/.github/workflows/test-container-build-staging.yml
new file mode 100644
index 0000000000..a0395542dd
--- /dev/null
+++ b/.github/workflows/test-container-build-staging.yml
@@ -0,0 +1,28 @@
+name: "Test Staging Container Build"
+
+on:
+ pull_request:
+ branches: [develop]
+
+env:
+ GITHUB_SHA: ${{ github.sha }}
+ GOOGLE_CLIENT_SECRET: ${{ secrets.STAGING_GOOGLE_CLIENT_SECRET }}
+ GOOGLE_CLIENT_ID: ${{ secrets.STAGING_GOOGLE_CLIENT_ID }}
+ COGNITO_APP_CLIENT_ID: ${{secrets.STAGING_COGNITO_APP_CLIENT_ID}}
+ COGNITO_USER_POOL_ID: ${{ secrets.STAGING_COGNITO_USER_POOL_ID}}
+
+jobs:
+ test-container:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@dc323e67f16fb5f7663d20ff7941f27f5809e9b6 # v2.6.0
+
+ - name: Build Container
+ run: |
+ docker build -t base \
+ --build-arg GITHUB_SHA_ARG=$GITHUB_SHA \
+ --build-arg GOOGLE_CLIENT_SECRET=$GOOGLE_CLIENT_SECRET \
+ --build-arg GOOGLE_CLIENT_ID=$GOOGLE_CLIENT_ID \
+ --build-arg COGNITO_APP_CLIENT_ID=$COGNITO_APP_CLIENT_ID \
+ --build-arg COGNITO_USER_POOL_ID=$COGNITO_USER_POOL_ID .
\ No newline at end of file
diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000000..23626337e1
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+ElementPanel.test.js
\ No newline at end of file
diff --git a/.storybook/Layout.js b/.storybook/Layout.js
index 5154b5800d..a4d8adf448 100644
--- a/.storybook/Layout.js
+++ b/.storybook/Layout.js
@@ -1,8 +1,6 @@
import React from "react";
import "../styles/app.scss";
-const Layout = ({ children }) => {
+export const Layout = ({ children }) => {
return {children};
};
-
-export default Layout;
diff --git a/.storybook/preview.js b/.storybook/preview.js
index 0d163fbcd3..168de9173b 100644
--- a/.storybook/preview.js
+++ b/.storybook/preview.js
@@ -1,6 +1,6 @@
import React from "react";
import { addDecorator } from "@storybook/react";
-import Layout from "./Layout";
+import { Layout } from "./Layout";
export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e939efd089..ebc6064d05 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,99 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
+## [2.0.0] 2022-12-28
+
+### Added
+
+- Form Builder form creation interface
+- User self registration
+- Validation of a JSON Config to check the IDs of elements [#892](https://github.com/cds-snc/platform-forms-client/pull/892)
+- Added login page [#867](https://github.com/cds-snc/platform-forms-client/issues/867)
+- Added login page for temporary token [#900](https://github.com/cds-snc/platform-forms-client/pull/900)
+- [BREAKING]: Modified the Prisma schema for the "User" table; removing the `admin` column, and adding the `role` column. After migrating, at least one user role will need to manually be set to `administrator` in order to login the Admin portion of the site. [#906](https://github.com/cds-snc/platform-forms-client/pull/906)
+- Added file attachments to retrieval API [#909](https://github.com/cds-snc/platform-forms-client/pull/909)
+- New login lockout mechanism plugged on existing temporary token API [#872](https://github.com/cds-snc/platform-forms-client/issues/872)
+- Logout Page [#847] (https://github.com/cds-snc/platform-forms-client/issues/870)
+- Admin feature to assign users to template [#1203](https://github.com/cds-snc/platform-forms-client/issues/1203)
+- New API path to request publishing permission [#1226](https://github.com/cds-snc/platform-forms-client/issues/1226)
+- Dynamic footer with SLA and Support links on admin and form builder related pages [#1080](https://github.com/cds-snc/platform-forms-client/issues/1080)
+
+### Changed
+
+- Updated Terms and conditions page + text link in the footer [#863](https://github.com/cds-snc/platform-forms-client/issues/863)
+- Modified Role Based to Asset Based Access Control [#1176](https://github.com/cds-snc/platform-forms-client/pull/1176)
+- Form templates are now marked as archived and will stay in the database for 30 more days before being deleted by a Lambda function. [#1166](https://github.com/cds-snc/platform-forms-client/issues/1166)
+- The existing `publishingStatus` field from the form JSON configuration has been replaced by a `isPublished` data field in the database. It can be switch to `true` or `false` using the Template API. A migration process will automatically happen through the Prisma seeding process. [#1181](https://github.com/cds-snc/platform-forms-client/issues/1181)
+- Form builder can only load form if the user has the permission to access it [#1228](https://github.com/cds-snc/platform-forms-client/issues/1228)
+
+### Fixed
+
+- Fix stuck "Loading..." animation after uploading a new JSON config. [#898](https://github.com/cds-snc/platform-forms-client/pull/898)
+- Fix ReCaptcha feature being broken because of missing API Key.
+- Last login time on acceptable use page was not formatted properly. [#949](https://github.com/cds-snc/platform-forms-client/issues/949)
+- Fix logout session end date [#945](https://github.com/cds-snc/platform-forms-client/issues/945)
+- Fix last login date format [#950](https://github.com/cds-snc/platform-forms-client/pull/950)
+- Cleared email input field after successfully adding an email to Form Access [#954](https://github.com/cds-snc/platform-forms-client/pull/954)
+- Returned only public properties for forms [#1038](https://github.com/cds-snc/platform-forms-client/pull/1038)
+- Can't enable/disable user permissions in admin panel
+
+### Removed
+
+- Option to preview form submission email to through Notify [#1021](https://github.com/cds-snc/platform-forms-client/pull/1021)
+
+## [1.3.0] 2022-07-15
+
+### Added
+
+- Make GC Branding in Footer configurable [#847](https://github.com/cds-snc/platform-forms-client/pull/847)
+
+### Fixed
+
+- Added CSRF token requirement to `api/log` endpoint [#835](https://github.com/cds-snc/platform-forms-client/pull/835)
+- Welcome page link to design system (storybook) [#844](https://github.com/cds-snc/platform-forms-client/pull/844)
+- Fix retrieval API [#845](https://github.com/cds-snc/platform-forms-client/pull/845)
+- Fix loading of csp scripts to happen after Dom is loaded [#848](https://github.com/cds-snc/platform-forms-client/pull/848)
+- Fix remaining characters display issue
+
+## [No Release Version] 2022-06-14
+
+### Added
+
+- Validation of a JSON Config to check the IDs of elements [#892](https://github.com/cds-snc/platform-forms-client/pull/892)
+- Added login page [#867](https://github.com/cds-snc/platform-forms-client/issues/867)
+- Added login page for temporary token [#900](https://github.com/cds-snc/platform-forms-client/pull/900)
+- [BREAKING]: Modified the Prisma schema for the "User" table; removing the `admin` column, and adding the `role` column. After migrating, at least one user role will need to manually be set to `administrator` in order to login the Admin portion of the site. [#906](https://github.com/cds-snc/platform-forms-client/pull/906)
+- Added file attachments to retrieval API [#909](https://github.com/cds-snc/platform-forms-client/pull/909)
+- New login lockout mechanism plugged on existing temporary token API [#872](https://github.com/cds-snc/platform-forms-client/issues/872)
+- Logout Page [#847] (https://github.com/cds-snc/platform-forms-client/issues/870)
+- Admin feature to assign users to template [#1203](https://github.com/cds-snc/platform-forms-client/issues/1203)
+- New API path to request publishing permission [#1226](https://github.com/cds-snc/platform-forms-client/issues/1226)
+- Dynamic footer with SLA and Support links on admin and form builder related pages [#1080](https://github.com/cds-snc/platform-forms-client/issues/1080)
+
+### Changed
+
+- Updated Terms and conditions page + text link in the footer [#863](https://github.com/cds-snc/platform-forms-client/issues/863)
+- Modified Role Based to Asset Based Access Control [#1176](https://github.com/cds-snc/platform-forms-client/pull/1176)
+- Form templates are now marked as archived and will stay in the database for 30 more days before being deleted by a Lambda function. [#1166](https://github.com/cds-snc/platform-forms-client/issues/1166)
+- The existing `publishingStatus` field from the form JSON configuration has been replaced by a `isPublished` data field in the database. It can be switch to `true` or `false` using the Template API. A migration process will automatically happen through the Prisma seeding process. [#1181](https://github.com/cds-snc/platform-forms-client/issues/1181)
+- Form builder can only load form if the user has the permission to access it [#1228](https://github.com/cds-snc/platform-forms-client/issues/1228)
+
+### Fixed
+
+- Fix stuck "Loading..." animation after uploading a new JSON config. [#898](https://github.com/cds-snc/platform-forms-client/pull/898)
+- Fix ReCaptcha feature being broken because of missing API Key.
+- Last login time on acceptable use page was not formatted properly. [#949](https://github.com/cds-snc/platform-forms-client/issues/949)
+- Fix logout session end date [#945](https://github.com/cds-snc/platform-forms-client/issues/945)
+- Fix last login date format [#950](https://github.com/cds-snc/platform-forms-client/pull/950)
+- Cleared email input field after successfully adding an email to Form Access [#954](https://github.com/cds-snc/platform-forms-client/pull/954)
+- Returned only public properties for forms [#1038](https://github.com/cds-snc/platform-forms-client/pull/1038)
+- Can't enable/disable user permissions in admin panel
+
+### Removed
+
+- Option to preview form submission email to through Notify [#1021](https://github.com/cds-snc/platform-forms-client/pull/1021)
+- `displayAlphaBanner` property in JSON form template is not supported anymore. [#772](https://github.com/cds-snc/platform-forms-client/issues/772)
+
## [1.3.0] 2022-07-15
### Added
@@ -40,6 +133,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Upgraded NextJS and other associated GCForms dependencies to next major version. [#725](https://github.com/cds-snc/platform-forms-client/pull/725)
- Redesigned file input button [#713](https://github.com/cds-snc/platform-forms-client/issues/713)
- Removed list of published forms from welcome page. [#712](https://github.com/cds-snc/platform-forms-client/issues/712)
+- Upgraded Next-Auth to version 4 & modified backed to use Prisma [#739](https://github.com/cds-snc/platform-forms-client/pull/739)
- Changed ISOLATED_INSTANCE for APP_ENV [#825](https://github.com/cds-snc/platform-forms-client/pull/825)
## [1.2.0] 2022-04-19
@@ -99,7 +193,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Renamed `organisation` to `organization` which has an impact on the API access path
- Modified the middleware functionality and separation of scopes between middlewares
- A user now needs to have an enabled admin flag (user table) to access the Admin Pages
-- An admin user can now add and remove administrative priveleges from other users.
+- An admin user can now add and remove administrative privileges from other users.
### Fixed
diff --git a/Dockerfile b/Dockerfile
index e70bd353d8..a799ad071c 100755
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,32 +1,53 @@
-FROM node:16
+FROM node:16@sha256:1bbd8b82f5a78b6461d3285b62293db99ad60cf4eca35c715636d7143abb057c
ENV NODE_ENV=production
COPY . /src
WORKDIR /src
+ARG GOOGLE_CLIENT_ID
+ARG GOOGLE_CLIENT_SECRET
+ARG COGNITO_REGION="ca-central-1"
+ARG COGNITO_APP_CLIENT_ID
+ARG COGNITO_USER_POOL_ID
+
RUN yarn install --silent --production=false
RUN yarn build
RUN yarn install --production
-FROM node:16
+FROM node:16@sha256:1bbd8b82f5a78b6461d3285b62293db99ad60cf4eca35c715636d7143abb057c
COPY migrations /src
WORKDIR /src
RUN yarn install --silent
-FROM node:16
+FROM node:16@sha256:1bbd8b82f5a78b6461d3285b62293db99ad60cf4eca35c715636d7143abb057c
COPY flag_initialization /src
WORKDIR /src
RUN yarn install --silent
-FROM node:16
+FROM node:16@sha256:1bbd8b82f5a78b6461d3285b62293db99ad60cf4eca35c715636d7143abb057c
LABEL maintainer="-"
+ARG GOOGLE_CLIENT_ID
+ENV GOOGLE_CLIENT_ID=$GOOGLE_CLIENT_ID
+
+ARG GOOGLE_CLIENT_SECRET
+ENV GOOGLE_CLIENT_SECRET=$GOOGLE_CLIENT_SECRET
+
ARG GITHUB_SHA_ARG
ENV GITHUB_SHA=$GITHUB_SHA_ARG
+ARG COGNITO_REGION="ca-central-1"
+ENV COGNITO_REGION=$COGNITO_REGION
+
+ARG COGNITO_APP_CLIENT_ID
+ENV COGNITO_APP_CLIENT_ID=$COGNITO_APP_CLIENT_ID
+
+ARG COGNITO_USER_POOL_ID
+ENV COGNITO_USER_POOL_ID=$COGNITO_USER_POOL_ID
+
ARG TAG_VERSION
ENV TAG_VERSION=$TAG_VERSION
@@ -40,6 +61,7 @@ COPY public ./public
COPY next.config.js .
COPY next-i18next.config.js .
COPY migrations ./migrations
+COPY prisma ./prisma
COPY flag_initialization ./flag_initialization
COPY --from=1 /src/node_modules ./migrations/node_modules
COPY --from=2 /src/node_modules ./flag_initialization/node_modules
diff --git a/README.md b/README.md
index a8b3affab3..359a687c26 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,7 @@ This is a [Next.js](https://nextjs.org/) and is built with:
- Sass (Syntactically Awesome Style Sheets) for reusable styles
- [Tailwindcss](https://tailwindcss.com/) a utility-first css framework for rapidly building custom designs
- [PostCSS](https://postcss.org/)
+- [Prisma](https://www.prisma.io/)
## Running locally
@@ -39,7 +40,6 @@ For local development of the NextJS application but leveraging the AWS backend (
NOTIFY_API_KEY= // Can be found in LastPass
SUBMISSION_API=Submission
TEMPLATES_API=Templates
-ORGANIZATIONS_API=Organizations
AWS_ACCESS_KEY_ID= // Can be found in LastPass
AWS_SECRET_ACCESS_KEY= // Can be found in LastPass
GOOGLE_CLIENT_ID= // Can be found in LastPass
@@ -69,20 +69,9 @@ Run postgres by using the following command
docker-compose up -d db
```
+A GUI manager is installed with prisma and can be launched with `yarn prisma:studio`
You can optionally install a gui manager like PgAdmin if you would like.
-
-in `/migrations`, fill in the separate .env file.
-
-```
-DB_NAME=formsDB
-DB_USERNAME=postgres
-DB_PASSWORD=chummy
-DB_HOST=localhost
-```
-
-Note if running in devcontainers on vscode the DB_HOST should be of value `db`
-
-inside the `/migrations` folder, run `node index.js` to run migrations against the local database.
+For more information about developing with prisma migrate please visit: https://www.prisma.io/docs/guides/database/developing-with-prisma-migrate
In your main forms .env file, DATABASE_URL can be filled in as followed (replace values in {} with the values you used in your migrations env file)
`DATABASE_URL=postgres://{DB_USERNAME}:{DB_PASSWORD}@DB_HOST:5432/{DB_NAME}`
@@ -103,9 +92,23 @@ Browse application on `http://localhost:3000`
There are some environment variables that can optionally be configured. You can see a list in `.env.example`.
### Grant yourself admin access locally
+
+There are 2 ways to connect to the database. Either directly using PGAdmin or a PSQL cli tool or through Prisma Studio. Once the change is made you will need to "Log Out" using the
+
+## Connect to DataBase Directly
+
+- Login using your email via Google SSO
+- Connect to the local database `psql -h db -U postgres -d formsDB`
+- Retrieve your users id from the User table in the formsDB `SELECT * FROM "public"."User" WHERE email='$YOUR_EMAIL';`
+- Update the record to elevate yourself as an admin `UPDATE "public"."User" SET role='ADMINISTRATOR' WHERE id='$YOUR_ID';`
+
+## Prisma Studio
+
- Login using your email via Google SSO
-- Retrieve your users id from the users table in the formsDB `select * from users where email='YOUR_EMAIL'`
-- Update the record to elevate yourself as an admin `UPDATE users SET admin=true WHERE id=YOUR_ID`
+- Launch prisma studio with `yarn prisma:studio` or if you have prisma installed globally `prisma studio`
+- A browser window will open at `localhost:5555`. Open the model `User`
+- A table will appear. Find your username in the list and double-click on the value under the `role` column to modify to "ADMINISTRATOR".
+- Click on "Save Change" button in the top menu bar once completed.
### Notify integration
@@ -171,7 +174,6 @@ Pour le développement local de l'application NextJS mais en s'appuyant sur le b
NOTIFY_API_KEY= // Can be found in LastPass
SUBMISSION_API=Submission
TEMPLATES_API=Templates
-ORGANIZATIONS_API=Organizations
AWS_ACCESS_KEY_ID= // Can be found in LastPass
AWS_SECRET_ACCESS_KEY= // Can be found in LastPass
GOOGLE_CLIENT_ID= // Can be found in LastPass
diff --git a/VERSION b/VERSION
index 1e75430133..6e1f4db18c 100644
--- a/VERSION
+++ b/VERSION
@@ -1,2 +1,2 @@
-1.3.0
+2.0.0
diff --git a/__fixtures__/accessibilityTestForm.json b/__fixtures__/accessibilityTestForm.json
new file mode 100644
index 0000000000..f4edb81108
--- /dev/null
+++ b/__fixtures__/accessibilityTestForm.json
@@ -0,0 +1,329 @@
+{
+ "form": {
+ "layout": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
+ "endPage": {
+ "descriptionEn": "#Your submission has been received \n\r Thank you for your interest. We will contact you within 3-5 business days. \n\r Go back",
+ "descriptionFr": "#[fr] Your submission has been received. \n\r Thank you for your interest. We will contact you within 3-5 business days. \n\r Go back",
+ "referrerUrlEn": "",
+ "referrerUrlFr": ""
+ },
+ "titleEn": "Lemonade Stand Funding",
+ "titleFr": "[fr] Lemonade Stand Funding",
+ "version": 1,
+ "elements": [
+ {
+ "id": 1,
+ "type": "richText",
+ "properties": {
+ "charLimit": 5000,
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "##Contact Information",
+ "descriptionFr": "##[fr] Contact Information"
+ }
+ },
+ {
+ "id": 2,
+ "type": "textField",
+ "properties": {
+ "titleEn": "1. What is your name?",
+ "titleFr": "[fr]1. What is your name?]",
+ "validation": {
+ "type": "text",
+ "required": true,
+ "maxLength": 150
+ },
+ "autoComplete": "name",
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 3,
+ "type": "radio",
+ "properties": {
+ "choices": [
+ {
+ "en": "English",
+ "fr": "Anglais"
+ },
+ {
+ "en": "French",
+ "fr": "Français"
+ }
+ ],
+ "titleEn": "2. What is your preferred language for communications?",
+ "titleFr": "[fr] 2. What is your preferred language for communications?",
+ "validation": {
+ "required": true
+ },
+ "descriptionEn": "",
+ "descriptionFr": ""
+ }
+ },
+ {
+ "id": 4,
+ "type": "richText",
+ "properties": {
+ "charLimit": 5000,
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "**Note:** We are not collecting email addresses or phone numbers through this test form to preserve your privacy \n\r ##Poject Information",
+ "descriptionFr": "[fr] **Note:** We are not collecting email addresses or phone numbers through this test form to preserve your privacy \n\r ##Project Information"
+ }
+ },
+ {
+ "id": 5,
+ "type": "textField",
+ "properties": {
+ "titleEn": "3. What is the name of your lemonade stand?",
+ "titleFr": "[fr]3. What is the name of your lemonade stand?",
+ "validation": {
+ "type": "text",
+ "required": true,
+ "maxLength": 300
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 6,
+ "type": "fileInput",
+ "properties": {
+ "titleEn": "4. Please upload the logo for your lemonade stand.",
+ "titleFr": "[fr]4. Please upload the logo for your lemonade stand.",
+ "fileType": ".png,",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "Please add the .png document provided to you",
+ "descriptionFr": "[fr]Please add the .png document provided to you"
+ }
+ },
+ {
+ "id": 7,
+ "type": "textArea",
+ "properties": {
+ "titleEn": "5. Please describe the taste of your lemonade recipe. ",
+ "titleFr": "[fr] 5. Please describe the taste of your lemonade recipe. ",
+ "validation": {
+ "type": "text",
+ "required": true,
+ "maxLength": 1000
+ },
+ "descriptionEn": "Consider including details about the sweetness or sourness of your lemonade recipe. Maximum characters: 1000",
+ "descriptionFr": "[fr]Consider including details about the sweetness or sourness of your lemonade recipe. Maximum characters: 1000",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 8,
+ "type": "dropdown",
+ "properties": {
+ "choices": [
+ {
+ "en": "Park",
+ "fr": "[fr] Park"
+ },
+ {
+ "en": "Driveway",
+ "fr": "[fr]Driveway"
+ },
+ {
+ "en": "Building lobby",
+ "fr": "[fr]Building lobby"
+ },
+ {
+ "en": "Parking lot",
+ "fr": "[fr]Parking lot"
+ },
+ {
+ "en": "Other",
+ "fr": "[fr]Other"
+ }
+ ],
+ "titleEn": "6. Where is your lemonade stand going to be located?",
+ "titleFr": "[fr]6. Where is your lemonade stand going to be located?",
+ "validation": {
+ "required": true
+ },
+ "descriptionEn": "",
+ "descriptionFr": ""
+ }
+ },
+ {
+ "id": 9,
+ "type": "textField",
+ "properties": {
+ "titleEn": "7. If you checked Other, please specify",
+ "titleFr": "7. Pour d'autre information veuillez spécifier",
+ "validation": {
+ "type": "text",
+ "required": false,
+ "maxLength": 100
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 10,
+ "type": "richText",
+ "properties": {
+ "charLimit": 5000,
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "###Materials and Ingredients",
+ "descriptionFr": "###[fr] Materials and Ingredients"
+ }
+ },
+ {
+ "id": 11,
+ "type": "dynamicRow",
+ "properties": {
+ "titleEn": "8. Which ingredients will you purchase with this funding?",
+ "titleFr": "[fr]8. Which ingredients will you purchase with this funding?",
+ "validation": {
+ "required": false
+ },
+ "subElements": [
+ {
+ "id": 1101,
+ "type": "dropdown",
+ "properties": {
+ "choices": [
+ {
+ "en": "Sugar",
+ "fr": "[fr] Sugar"
+ },
+ {
+ "en": "Lemons",
+ "fr": "[fr]Lemons"
+ }
+ ],
+ "titleEn": "8a. What is the type of ingredient?",
+ "titleFr": "[fr] 8a. What is the type of ingredient?",
+ "validation": {
+ "required": true
+ },
+ "descriptionEn": "",
+ "descriptionFr": ""
+ }
+ },
+ {
+ "id": 1102,
+ "type": "textField",
+ "properties": {
+ "titleEn": "8b. How much of it do you need?",
+ "titleFr": "[fr]8b. How much of it do you need?",
+ "validation": {
+ "type": "text",
+ "required": true,
+ "maxLength": 10
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 1103,
+ "type": "richText",
+ "properties": {
+ "charLimit": 5000,
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "To add another ingredient, select 'Add ingredient' below",
+ "descriptionFr": "[fr] To add another ingredient, select 'Add ingredient' below"
+ }
+ }
+ ],
+ "placeholderEn": "ingredient",
+ "placeholderFr": "[fr]ingredient"
+ }
+ },
+ {
+ "id": 12,
+ "type": "checkbox",
+ "properties": {
+ "choices": [
+ {
+ "en": "Cups",
+ "fr": "[fr] Cups"
+ },
+ {
+ "en": "Napkins",
+ "fr": "[fr]Napkins"
+ },
+ {
+ "en": "Straws",
+ "fr": "[fr]Straws"
+ }
+ ],
+ "titleEn": "9. Which materials will you purchase with this funding? ",
+ "titleFr": "[fr] 9. Which materials will you purchase with this funding? ",
+ "validation": {
+ "required": true
+ },
+ "descriptionEn": "",
+ "descriptionFr": ""
+ }
+ },
+ {
+ "id": 13,
+ "type": "richText",
+ "properties": {
+ "charLimit": 5000,
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "##Submission",
+ "descriptionFr": "##[fr] Submission"
+ }
+ },
+ {
+ "id": 14,
+ "type": "radio",
+ "properties": {
+ "choices": [
+ {
+ "en": "Yes",
+ "fr": "Oui"
+ },
+ {
+ "en": "No",
+ "fr": "Non"
+ }
+ ],
+ "titleEn": "10. Do you attest that the information you are providing is true and correct to your knowledge?",
+ "titleFr": "[fr] 10. Do you attest that the information you are providing is true and correct to your knowledge?",
+ "validation": {
+ "required": true
+ },
+ "descriptionEn": "",
+ "descriptionFr": ""
+ }
+ }
+ ],
+ "emailSubjectEn": "Lemonade Stand Funding Testing Response",
+ "emailSubjectFr": ""
+ },
+ "submission": {
+ "email": "forms-formulaires@cds-snc.ca"
+ },
+ "internalTitleEn": "CDS - Lemonade Stand Funding",
+ "internalTitleFr": "CDS - Lemonade Stand Funding"
+}
diff --git a/__fixtures__/attestationTestForm.json b/__fixtures__/attestationTestForm.json
new file mode 100644
index 0000000000..3e29b9b4e4
--- /dev/null
+++ b/__fixtures__/attestationTestForm.json
@@ -0,0 +1,47 @@
+{
+ "form": {
+ "layout": [1],
+ "titleEn": "Lemonade Stand Funding",
+ "titleFr": "Financement des stands de limonade",
+ "version": 1,
+ "elements": [
+ {
+ "id": 1,
+ "type": "checkbox",
+ "properties": {
+ "titleEn": "Do you attest that the information you are providing is true and correct to your knowledge?",
+ "titleFr": "Attestez-vous que les informations que vous fournissez sont, à votre connaissance, vraies et correctes ?",
+ "choices": [
+ {
+ "en": "I prefer lemons to oranges.",
+ "fr": "Je préfère les citrons aux oranges."
+ },
+ {
+ "en": "I agree to keep my lemonade stand a minimum of 1 metre from the sidewalk.",
+ "fr": "Je m'engage à maintenir mon stand de limonade à un minimum d'un mètre du trottoir."
+ }
+ ],
+ "validation": {
+ "all": true,
+ "required": true
+ },
+ "descriptionEn": "",
+ "descriptionFr": ""
+ }
+ }
+ ],
+ "emailSubjectEn": "Lemonade Stand Funding Testing Response",
+ "emailSubjectFr": ""
+ },
+ "submission": {
+ "vault": true
+ },
+ "endPage": {
+ "descriptionEn": "#Your submission has been received \n\r Thank you for your interest. We will contact you within 3-5 business days. \n\r Go back",
+ "descriptionFr": "#[fr] Your submission has been received. \n\r Thank you for your interest. We will contact you within 3-5 business days. \n\r Go back",
+ "referrerUrlEn": "",
+ "referrerUrlFr": ""
+ },
+ "internalTitleEn": "CDS - Lemonade Stand Funding",
+ "internalTitleFr": "CDS - Lemonade Stand Funding"
+}
diff --git a/__fixtures__/brokenFormTemplate.json b/__fixtures__/brokenFormTemplate.json
new file mode 100644
index 0000000000..5578536e09
--- /dev/null
+++ b/__fixtures__/brokenFormTemplate.json
@@ -0,0 +1,646 @@
+{
+ "forms": {
+ "layout": [
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 27
+ ],
+ "titleEn": "Public Service Award of Excellence 2020 - Nomination form",
+ "titleFr": "Prix d’excellence de la fonction publique 2020 - Formulaire de mise en candidature",
+ "version": 1,
+ "elements": [
+ {
+ "id": 1,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "#### Section 1: Nomination Category",
+ "descriptionFr": "#### Section 1: Catégorie de la nomination"
+ }
+ },
+ {
+ "id": 2,
+ "type": "radio",
+ "properties": {
+ "choices": [
+ {
+ "en": "Team nomination",
+ "fr": "Mise en candidature d’une équipe"
+ },
+ {
+ "en": "Individual Nomination",
+ "fr": "Mise en candidature d’une personne"
+ }
+ ],
+ "titleEn": "Is this a Team or Individual Nomination?",
+ "titleFr": "Is this a Team or Individual Nomination?",
+ "validation": {
+ "required": true
+ },
+ "descriptionEn": "",
+ "descriptionFr": ""
+ }
+ },
+ {
+ "id": 3,
+ "type": "radio",
+ "properties": {
+ "choices": [
+ {
+ "en": "Excellence in Profession",
+ "fr": "Excellence en profession"
+ },
+ {
+ "en": "Exceptional Young Public Servant",
+ "fr": "Jeunes fonctionnaires exceptionnels"
+ },
+ {
+ "en": "Exemplary Contribution Under Extraordinary Circumstances (Team only)",
+ "fr": "Contribution exemplaire dans des circonstances extraordinaires (Équipe seulement)"
+ },
+ {
+ "en": "Joan Atkinson Award for Public Sector Balues in the Workplace",
+ "fr": "Prix Joan Atkinson pour les Valeurs du secteur public en milieu de travail"
+ },
+ {
+ "en": "Outstanding Career (Individual only)",
+ "fr": "Carrière exceptionnelle (Personne seulement)"
+ },
+ {
+ "en": "60 Years of Service Special Award (Individual only)",
+ "fr": "Prix spécial récompensant 60 années de service (Personne seulement)"
+ }
+ ],
+ "titleEn": "Category",
+ "titleFr": "Catégorie",
+ "validation": {
+ "required": true
+ },
+ "descriptionEn": "",
+ "descriptionFr": ""
+ }
+ },
+ {
+ "id": 4,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "#### Section 2: Nominator Information",
+ "descriptionFr": "#### Section 2: Information sur le proposant"
+ }
+ },
+ {
+ "id": 5,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Family name",
+ "titleFr": "Nom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 6,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Given name",
+ "titleFr": "Prénom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 7,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Department or organization",
+ "titleFr": "Ministère ou organisme",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 8,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Title",
+ "titleFr": "Titre",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 9,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Phone number",
+ "titleFr": "Numéro de téléphone",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 10,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Email address",
+ "titleFr": "Adresse de courriel",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 11,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "#### Section 3: Individual Information (For an Individual Nomination)",
+ "descriptionFr": "#### Section 3: Mise en candidature d'une personne (For an Individual Nomination)"
+ }
+ },
+ {
+ "id": 12,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Family name",
+ "titleFr": "Nom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 13,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Given name",
+ "titleFr": "Prénom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 14,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Department or organization",
+ "titleFr": "Ministère ou organisme",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 15,
+ "type": "dropdown",
+ "properties": {
+ "choices": [
+ {
+ "en": "",
+ "fr": ""
+ },
+ {
+ "en": "Alberta",
+ "fr": "Alberta"
+ },
+ {
+ "en": "British Columbia",
+ "fr": "Colombie-Britannique"
+ },
+ {
+ "en": "Manitoba",
+ "fr": "Manitoba"
+ },
+ {
+ "en": "New Brunswick",
+ "fr": "Nouveau-Brunswick"
+ },
+ {
+ "en": "Newfoundland and Labrador",
+ "fr": "Terre-Neuve-et-Labrador"
+ },
+ {
+ "en": "Northwest Territories",
+ "fr": "Territoires du Nord-Ouest"
+ },
+ {
+ "en": "Nova Scotia",
+ "fr": "Nouvelle-Écosse"
+ },
+ {
+ "en": "Nunavut",
+ "fr": "Nunavut"
+ },
+ {
+ "en": "Ontario",
+ "fr": "Ontario"
+ },
+ {
+ "en": "Prince Edward Island",
+ "fr": "Île-du-Prince-Édouard"
+ },
+ {
+ "en": "Quebec",
+ "fr": "Québec"
+ },
+ {
+ "en": "Saskatchewan",
+ "fr": "Saskatchewan"
+ },
+ {
+ "en": "Yukon",
+ "fr": "Yukon"
+ }
+ ],
+ "titleEn": "Province or territory",
+ "titleFr": "Province ou territoire",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 16,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Preferred language",
+ "titleFr": "Langue préférée",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 17,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Group and level",
+ "titleFr": "Groupe et niveau",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 18,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "#### Section 4: Team Nomination (for a Team Nomination)",
+ "descriptionFr": "#### Section 4: Mise en candidature d’une équipe (for a Team Nomination)"
+ }
+ },
+ {
+ "id": 19,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Team name in english",
+ "titleFr": "Nom de l’équipe en anglais",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 20,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Team name in french",
+ "titleFr": "Nom de l’équipe en français",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 21,
+ "type": "richText",
+ "properties": {
+ "titleEn": "Team Members",
+ "titleFr": "Membres de l’équipe",
+ "validation": {
+ "required": false,
+ "maxLength": 5000
+ },
+ "descriptionEn": "You can click Add a row to add more than one team member to your application. Please note that you can only list a maximum of 15 team members.",
+ "descriptionFr": "You can click Add a row to add more than one team member to your application. Please note that you can only list a maximum of 15 team members.",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 22,
+ "type": "dynamicRow",
+ "properties": {
+ "titleEn": "",
+ "titleFr": "",
+ "validation": {
+ "required": false
+ },
+ "subElements": [
+ {
+ "id": 22,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Family name",
+ "titleFr": "Nom",
+ "validation": {
+ "maxLength": 100,
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 22,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Given name",
+ "titleFr": "Prénom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 22,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Department or organization",
+ "titleFr": "Ministère ou organisme",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 22,
+ "type": "dropdown",
+ "properties": {
+ "choices": [
+ {
+ "en": "",
+ "fr": ""
+ },
+ {
+ "en": "Alberta",
+ "fr": "Alberta"
+ },
+ {
+ "en": "British Columbia",
+ "fr": "Colombie-Britannique"
+ },
+ {
+ "en": "Manitoba",
+ "fr": "Manitoba"
+ },
+ {
+ "en": "New Brunswick",
+ "fr": "Nouveau-Brunswick"
+ },
+ {
+ "en": "Newfoundland and Labrador",
+ "fr": "Terre-Neuve-et-Labrador"
+ },
+ {
+ "en": "Northwest Territories",
+ "fr": "Territoires du Nord-Ouest"
+ },
+ {
+ "en": "Nova Scotia",
+ "fr": "Nouvelle-Écosse"
+ },
+ {
+ "en": "Nunavut",
+ "fr": "Nunavut"
+ },
+ {
+ "en": "Ontario",
+ "fr": "Ontario"
+ },
+ {
+ "en": "Prince Edward Island",
+ "fr": "Île-du-Prince-Édouard"
+ },
+ {
+ "en": "Quebec",
+ "fr": "Québec"
+ },
+ {
+ "en": "Saskatchewan",
+ "fr": "Saskatchewan"
+ },
+ {
+ "en": "Yukon",
+ "fr": "Yukon"
+ }
+ ],
+ "titleEn": "Province or territory",
+ "titleFr": "Province ou territoire",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 22,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Preferred language",
+ "titleFr": "Langue préférée",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 22,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Group and level",
+ "titleFr": "Groupe et niveau",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ }
+ ]
+ }
+ },
+ {
+ "id": 23,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "#### Annex A: Achievement Summary",
+ "descriptionFr": "#### Annex A: Résumé des réalisations"
+ }
+ },
+ {
+ "id": 24,
+ "type": "textArea",
+ "properties": {
+ "titleEn": "Briefly describe the achievement for which the nomination is being submitted.",
+ "titleFr": "Décrire brièvement la réalisation pour laquelle la candidature est présentée.",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "Do not include headings or other formatting. Use a maximum of 200 words",
+ "descriptionFr": "Do not include headings or other formatting. Use a maximum of 200 words",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 25,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Name of Nominator",
+ "titleFr": "Nom du proposant",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 26,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Date",
+ "titleFr": "Date",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 27,
+ "type": "checkbox",
+ "properties": {
+ "choices": [
+ {
+ "en": "I hereby certify that, to the best of my knowledge, the information in this form is true and correct.",
+ "fr": "J’atteste par la présente qu’à ma connaissance, les renseignements fournis dans ce formulaire sont véridiques et corrects."
+ }
+ ],
+ "titleEn": "Consent of the Nominator",
+ "titleFr": "Consent of the Nominator",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": ""
+ }
+ }
+ ]
+ },
+ "submission": {
+ "email": "steven.talbot@cds-snc.ca"
+ },
+ "internalTitleEn": "Public Service Award of Excellence 2020",
+ "internalTitleFr": "Prix d’excellence de la fonction publique 2020",
+ "securityAttribute": "Unclassified"
+}
diff --git a/tests/data/cdsIntakeTestForm.json b/__fixtures__/cdsIntakeTestForm.json
similarity index 96%
rename from tests/data/cdsIntakeTestForm.json
rename to __fixtures__/cdsIntakeTestForm.json
index b7b407966f..04d3192c42 100644
--- a/tests/data/cdsIntakeTestForm.json
+++ b/__fixtures__/cdsIntakeTestForm.json
@@ -9,15 +9,7 @@
"logoTitleEn": "Canadian Digital Service",
"logoTitleFr": "Service numérique canadien"
},
- "layout": [
- 1,
- 2,
- 3,
- 4,
- 5,
- 6,
- 7
- ],
+ "layout": [1, 2, 3, 4, 5, 6, 7],
"endPage": {
"descriptionEn": "",
"descriptionFr": "",
@@ -134,6 +126,5 @@
},
"internalTitleEn": "CDS Intake Form",
"internalTitleFr": "SNC Formulaire d'admission",
- "publishingStatus": false,
"securityAttribute": "Unclassified"
-}
\ No newline at end of file
+}
diff --git a/__fixtures__/duplicateElementIds.json b/__fixtures__/duplicateElementIds.json
new file mode 100644
index 0000000000..9caee41f11
--- /dev/null
+++ b/__fixtures__/duplicateElementIds.json
@@ -0,0 +1,384 @@
+{
+ "form": {
+ "layout": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
+ "titleEn": "Public Service Award of Excellence 2020 - Nomination form",
+ "titleFr": "Prix d’excellence de la fonction publique 2020 - Formulaire de mise en candidature",
+ "version": 1,
+ "elements": [
+ {
+ "id": 1,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "#### Section 1: Nomination Category",
+ "descriptionFr": "#### Section 1: Catégorie de la nomination"
+ }
+ },
+ {
+ "id": 1,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "Purposely a duplicate ID",
+ "descriptionFr": "Purposely a duplicate ID"
+ }
+ },
+ {
+ "id": 2,
+ "type": "radio",
+ "properties": {
+ "choices": [
+ {
+ "en": "Team nomination",
+ "fr": "Mise en candidature d’une équipe"
+ },
+ {
+ "en": "Individual Nomination",
+ "fr": "Mise en candidature d’une personne"
+ }
+ ],
+ "titleEn": "Is this a Team or Individual Nomination?",
+ "titleFr": "Is this a Team or Individual Nomination?",
+ "validation": {
+ "required": true
+ },
+ "descriptionEn": "",
+ "descriptionFr": ""
+ }
+ },
+ {
+ "id": 3,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "Purposely a duplicate ID",
+ "descriptionFr": "Purposely a duplicate ID"
+ }
+ },
+ {
+ "id": 3,
+ "type": "radio",
+ "properties": {
+ "choices": [
+ {
+ "en": "Excellence in Profession",
+ "fr": "Excellence en profession"
+ },
+ {
+ "en": "Exceptional Young Public Servant",
+ "fr": "Jeunes fonctionnaires exceptionnels"
+ },
+ {
+ "en": "Exemplary Contribution Under Extraordinary Circumstances (Team only)",
+ "fr": "Contribution exemplaire dans des circonstances extraordinaires (Équipe seulement)"
+ },
+ {
+ "en": "Joan Atkinson Award for Public Sector Balues in the Workplace",
+ "fr": "Prix Joan Atkinson pour les Valeurs du secteur public en milieu de travail"
+ },
+ {
+ "en": "Outstanding Career (Individual only)",
+ "fr": "Carrière exceptionnelle (Personne seulement)"
+ },
+ {
+ "en": "60 Years of Service Special Award (Individual only)",
+ "fr": "Prix spécial récompensant 60 années de service (Personne seulement)"
+ }
+ ],
+ "titleEn": "Category",
+ "titleFr": "Catégorie",
+ "validation": {
+ "required": true
+ },
+ "descriptionEn": "",
+ "descriptionFr": ""
+ }
+ },
+ {
+ "id": 4,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "#### Section 2: Nominator Information",
+ "descriptionFr": "#### Section 2: Information sur le proposant"
+ }
+ },
+ {
+ "id": 5,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Family name",
+ "titleFr": "Nom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 6,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Given name",
+ "titleFr": "Prénom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 7,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Department or organization",
+ "titleFr": "Ministère ou organisme",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 8,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Title",
+ "titleFr": "Titre",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 9,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Phone number",
+ "titleFr": "Numéro de téléphone",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 10,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Email address",
+ "titleFr": "Adresse de courriel",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 10,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "Purposely a duplicate ID",
+ "descriptionFr": "Purposely a duplicate ID"
+ }
+ },
+ {
+ "id": 22,
+ "type": "dynamicRow",
+ "properties": {
+ "titleEn": "",
+ "titleFr": "",
+ "validation": {
+ "required": false
+ },
+ "subElements": [
+ {
+ "id": 2201,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Family name",
+ "titleFr": "Nom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 2202,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Given name",
+ "titleFr": "Prénom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 2203,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Department or organization",
+ "titleFr": "Ministère ou organisme",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 2206,
+ "type": "dropdown",
+ "properties": {
+ "choices": [
+ {
+ "en": "",
+ "fr": ""
+ },
+ {
+ "en": "Alberta",
+ "fr": "Alberta"
+ },
+ {
+ "en": "British Columbia",
+ "fr": "Colombie-Britannique"
+ },
+ {
+ "en": "Manitoba",
+ "fr": "Manitoba"
+ },
+ {
+ "en": "New Brunswick",
+ "fr": "Nouveau-Brunswick"
+ },
+ {
+ "en": "Newfoundland and Labrador",
+ "fr": "Terre-Neuve-et-Labrador"
+ },
+ {
+ "en": "Northwest Territories",
+ "fr": "Territoires du Nord-Ouest"
+ },
+ {
+ "en": "Nova Scotia",
+ "fr": "Nouvelle-Écosse"
+ },
+ {
+ "en": "Nunavut",
+ "fr": "Nunavut"
+ },
+ {
+ "en": "Ontario",
+ "fr": "Ontario"
+ },
+ {
+ "en": "Prince Edward Island",
+ "fr": "Île-du-Prince-Édouard"
+ },
+ {
+ "en": "Quebec",
+ "fr": "Québec"
+ },
+ {
+ "en": "Saskatchewan",
+ "fr": "Saskatchewan"
+ },
+ {
+ "en": "Yukon",
+ "fr": "Yukon"
+ }
+ ],
+ "titleEn": "Province or territory",
+ "titleFr": "Province ou territoire",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 2206,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Preferred language",
+ "titleFr": "Langue préférée",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 2206,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Group and level",
+ "titleFr": "Groupe et niveau",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "submission": {
+ "email": "steven.talbot@cds-snc.ca"
+ },
+ "internalTitleEn": "Public Service Award of Excellence 2020",
+ "internalTitleFr": "Prix d’excellence de la fonction publique 2020",
+ "securityAttribute": "Unclassified"
+}
diff --git a/tests/data/dynamicRowsTestForm.json b/__fixtures__/dynamicRowsTestForm.json
similarity index 99%
rename from tests/data/dynamicRowsTestForm.json
rename to __fixtures__/dynamicRowsTestForm.json
index 5c556df83d..2914256897 100644
--- a/tests/data/dynamicRowsTestForm.json
+++ b/__fixtures__/dynamicRowsTestForm.json
@@ -8,15 +8,7 @@
"logoTitleEn": "Copyright Board of Canada",
"logoTitleFr": "Commission du droit d'auteur du Canada"
},
- "layout": [
- 1,
- 2,
- 3,
- 6,
- 7,
- 11,
- 12
- ],
+ "layout": [1, 2, 3, 6, 7, 11, 12],
"endPage": {
"descriptionEn": "# Thank you for your tariff. \n\r The Proposed Tariff(s) has/have been successfully filed. The Board will inform you when this proposed tariff has/have been published on the Board’s website or if we require additional information. \n\r Go back",
"descriptionFr": "# Merci pour votre entrée. \n\r The Proposed Tariff(s) has/have been successfully filed. The Board will inform you when this proposed tariff has/have been published on the Board’s website or if we require additional information. \n\r Retour",
@@ -412,6 +404,5 @@
},
"internalTitleEn": "Copyright Board of Canada - Proposed Tariff Filing Form",
"internalTitleFr": "FR - Copyright Board of Canada - Proposed Tariff Filing Form",
- "publishingStatus": false,
"securityAttribute": "Unclassified"
-}
\ No newline at end of file
+}
diff --git a/__fixtures__/invalidLayoutIds.json b/__fixtures__/invalidLayoutIds.json
new file mode 100644
index 0000000000..4ee5b388da
--- /dev/null
+++ b/__fixtures__/invalidLayoutIds.json
@@ -0,0 +1,644 @@
+{
+ "form": {
+ "layout": [
+ 100, 200, 300, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27
+ ],
+ "titleEn": "Public Service Award of Excellence 2020 - Nomination form",
+ "titleFr": "Prix d’excellence de la fonction publique 2020 - Formulaire de mise en candidature",
+ "version": 1,
+ "elements": [
+ {
+ "id": 1,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "#### Section 1: Nomination Category",
+ "descriptionFr": "#### Section 1: Catégorie de la nomination"
+ }
+ },
+ {
+ "id": 2,
+ "type": "radio",
+ "properties": {
+ "choices": [
+ {
+ "en": "Team nomination",
+ "fr": "Mise en candidature d’une équipe"
+ },
+ {
+ "en": "Individual Nomination",
+ "fr": "Mise en candidature d’une personne"
+ }
+ ],
+ "titleEn": "Is this a Team or Individual Nomination?",
+ "titleFr": "Is this a Team or Individual Nomination?",
+ "validation": {
+ "required": true
+ },
+ "descriptionEn": "",
+ "descriptionFr": ""
+ }
+ },
+ {
+ "id": 3,
+ "type": "radio",
+ "properties": {
+ "choices": [
+ {
+ "en": "Excellence in Profession",
+ "fr": "Excellence en profession"
+ },
+ {
+ "en": "Exceptional Young Public Servant",
+ "fr": "Jeunes fonctionnaires exceptionnels"
+ },
+ {
+ "en": "Exemplary Contribution Under Extraordinary Circumstances (Team only)",
+ "fr": "Contribution exemplaire dans des circonstances extraordinaires (Équipe seulement)"
+ },
+ {
+ "en": "Joan Atkinson Award for Public Sector Balues in the Workplace",
+ "fr": "Prix Joan Atkinson pour les Valeurs du secteur public en milieu de travail"
+ },
+ {
+ "en": "Outstanding Career (Individual only)",
+ "fr": "Carrière exceptionnelle (Personne seulement)"
+ },
+ {
+ "en": "60 Years of Service Special Award (Individual only)",
+ "fr": "Prix spécial récompensant 60 années de service (Personne seulement)"
+ }
+ ],
+ "titleEn": "Category",
+ "titleFr": "Catégorie",
+ "validation": {
+ "required": true
+ },
+ "descriptionEn": "",
+ "descriptionFr": ""
+ }
+ },
+ {
+ "id": 4,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "#### Section 2: Nominator Information",
+ "descriptionFr": "#### Section 2: Information sur le proposant"
+ }
+ },
+ {
+ "id": 5,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Family name",
+ "titleFr": "Nom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 6,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Given name",
+ "titleFr": "Prénom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 7,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Department or organization",
+ "titleFr": "Ministère ou organisme",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 8,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Title",
+ "titleFr": "Titre",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 9,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Phone number",
+ "titleFr": "Numéro de téléphone",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 10,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Email address",
+ "titleFr": "Adresse de courriel",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 11,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "#### Section 3: Individual Information (For an Individual Nomination)",
+ "descriptionFr": "#### Section 3: Mise en candidature d'une personne (For an Individual Nomination)"
+ }
+ },
+ {
+ "id": 12,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Family name",
+ "titleFr": "Nom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 13,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Given name",
+ "titleFr": "Prénom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 14,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Department or organization",
+ "titleFr": "Ministère ou organisme",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 15,
+ "type": "dropdown",
+ "properties": {
+ "choices": [
+ {
+ "en": "",
+ "fr": ""
+ },
+ {
+ "en": "Alberta",
+ "fr": "Alberta"
+ },
+ {
+ "en": "British Columbia",
+ "fr": "Colombie-Britannique"
+ },
+ {
+ "en": "Manitoba",
+ "fr": "Manitoba"
+ },
+ {
+ "en": "New Brunswick",
+ "fr": "Nouveau-Brunswick"
+ },
+ {
+ "en": "Newfoundland and Labrador",
+ "fr": "Terre-Neuve-et-Labrador"
+ },
+ {
+ "en": "Northwest Territories",
+ "fr": "Territoires du Nord-Ouest"
+ },
+ {
+ "en": "Nova Scotia",
+ "fr": "Nouvelle-Écosse"
+ },
+ {
+ "en": "Nunavut",
+ "fr": "Nunavut"
+ },
+ {
+ "en": "Ontario",
+ "fr": "Ontario"
+ },
+ {
+ "en": "Prince Edward Island",
+ "fr": "Île-du-Prince-Édouard"
+ },
+ {
+ "en": "Quebec",
+ "fr": "Québec"
+ },
+ {
+ "en": "Saskatchewan",
+ "fr": "Saskatchewan"
+ },
+ {
+ "en": "Yukon",
+ "fr": "Yukon"
+ }
+ ],
+ "titleEn": "Province or territory",
+ "titleFr": "Province ou territoire",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 16,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Preferred language",
+ "titleFr": "Langue préférée",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 17,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Group and level",
+ "titleFr": "Groupe et niveau",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 18,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "#### Section 4: Team Nomination (for a Team Nomination)",
+ "descriptionFr": "#### Section 4: Mise en candidature d’une équipe (for a Team Nomination)"
+ }
+ },
+ {
+ "id": 19,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Team name in english",
+ "titleFr": "Nom de l’équipe en anglais",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 20,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Team name in french",
+ "titleFr": "Nom de l’équipe en français",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 21,
+ "type": "richText",
+ "properties": {
+ "titleEn": "Team Members",
+ "titleFr": "Membres de l’équipe",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "You can click Add a row to add more than one team member to your application. Please note that you can only list a maximum of 15 team members.",
+ "descriptionFr": "You can click Add a row to add more than one team member to your application. Please note that you can only list a maximum of 15 team members.",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 22,
+ "type": "dynamicRow",
+ "properties": {
+ "titleEn": "",
+ "titleFr": "",
+ "validation": {
+ "required": false
+ },
+ "subElements": [
+ {
+ "id": 22,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Family name",
+ "titleFr": "Nom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 22,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Given name",
+ "titleFr": "Prénom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 22,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Department or organization",
+ "titleFr": "Ministère ou organisme",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 22,
+ "type": "dropdown",
+ "properties": {
+ "choices": [
+ {
+ "en": "",
+ "fr": ""
+ },
+ {
+ "en": "Alberta",
+ "fr": "Alberta"
+ },
+ {
+ "en": "British Columbia",
+ "fr": "Colombie-Britannique"
+ },
+ {
+ "en": "Manitoba",
+ "fr": "Manitoba"
+ },
+ {
+ "en": "New Brunswick",
+ "fr": "Nouveau-Brunswick"
+ },
+ {
+ "en": "Newfoundland and Labrador",
+ "fr": "Terre-Neuve-et-Labrador"
+ },
+ {
+ "en": "Northwest Territories",
+ "fr": "Territoires du Nord-Ouest"
+ },
+ {
+ "en": "Nova Scotia",
+ "fr": "Nouvelle-Écosse"
+ },
+ {
+ "en": "Nunavut",
+ "fr": "Nunavut"
+ },
+ {
+ "en": "Ontario",
+ "fr": "Ontario"
+ },
+ {
+ "en": "Prince Edward Island",
+ "fr": "Île-du-Prince-Édouard"
+ },
+ {
+ "en": "Quebec",
+ "fr": "Québec"
+ },
+ {
+ "en": "Saskatchewan",
+ "fr": "Saskatchewan"
+ },
+ {
+ "en": "Yukon",
+ "fr": "Yukon"
+ }
+ ],
+ "titleEn": "Province or territory",
+ "titleFr": "Province ou territoire",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 22,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Preferred language",
+ "titleFr": "Langue préférée",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 22,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Group and level",
+ "titleFr": "Groupe et niveau",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ }
+ ]
+ }
+ },
+ {
+ "id": 23,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "#### Annex A: Achievement Summary",
+ "descriptionFr": "#### Annex A: Résumé des réalisations"
+ }
+ },
+ {
+ "id": 24,
+ "type": "textArea",
+ "properties": {
+ "titleEn": "Briefly describe the achievement for which the nomination is being submitted.",
+ "titleFr": "Décrire brièvement la réalisation pour laquelle la candidature est présentée.",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "Do not include headings or other formatting. Use a maximum of 200 words",
+ "descriptionFr": "Do not include headings or other formatting. Use a maximum of 200 words",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 25,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Name of Nominator",
+ "titleFr": "Nom du proposant",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 26,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Date",
+ "titleFr": "Date",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 27,
+ "type": "checkbox",
+ "properties": {
+ "choices": [
+ {
+ "en": "I hereby certify that, to the best of my knowledge, the information in this form is true and correct.",
+ "fr": "J’atteste par la présente qu’à ma connaissance, les renseignements fournis dans ce formulaire sont véridiques et corrects."
+ }
+ ],
+ "titleEn": "Consent of the Nominator",
+ "titleFr": "Consent of the Nominator",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": ""
+ }
+ }
+ ]
+ },
+ "submission": {
+ "email": "steven.talbot@cds-snc.ca"
+ },
+ "internalTitleEn": "Public Service Award of Excellence 2020",
+ "internalTitleFr": "Prix d’excellence de la fonction publique 2020",
+ "securityAttribute": "Unclassified"
+}
diff --git a/__fixtures__/invalidSubElementIds.json b/__fixtures__/invalidSubElementIds.json
new file mode 100644
index 0000000000..4878852767
--- /dev/null
+++ b/__fixtures__/invalidSubElementIds.json
@@ -0,0 +1,177 @@
+{
+ "form": {
+ "layout": [22],
+ "titleEn": "Public Service Award of Excellence 2020 - Nomination form",
+ "titleFr": "Prix d’excellence de la fonction publique 2020 - Formulaire de mise en candidature",
+ "version": 1,
+ "elements": [
+ {
+ "id": 22,
+ "type": "dynamicRow",
+ "properties": {
+ "titleEn": "",
+ "titleFr": "",
+ "validation": {
+ "required": false
+ },
+ "subElements": [
+ {
+ "id": 2201,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Family name",
+ "titleFr": "Nom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 2301,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Given name",
+ "titleFr": "Prénom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 2202,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Department or organization",
+ "titleFr": "Ministère ou organisme",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 2204,
+ "type": "dropdown",
+ "properties": {
+ "choices": [
+ {
+ "en": "",
+ "fr": ""
+ },
+ {
+ "en": "Alberta",
+ "fr": "Alberta"
+ },
+ {
+ "en": "British Columbia",
+ "fr": "Colombie-Britannique"
+ },
+ {
+ "en": "Manitoba",
+ "fr": "Manitoba"
+ },
+ {
+ "en": "New Brunswick",
+ "fr": "Nouveau-Brunswick"
+ },
+ {
+ "en": "Newfoundland and Labrador",
+ "fr": "Terre-Neuve-et-Labrador"
+ },
+ {
+ "en": "Northwest Territories",
+ "fr": "Territoires du Nord-Ouest"
+ },
+ {
+ "en": "Nova Scotia",
+ "fr": "Nouvelle-Écosse"
+ },
+ {
+ "en": "Nunavut",
+ "fr": "Nunavut"
+ },
+ {
+ "en": "Ontario",
+ "fr": "Ontario"
+ },
+ {
+ "en": "Prince Edward Island",
+ "fr": "Île-du-Prince-Édouard"
+ },
+ {
+ "en": "Quebec",
+ "fr": "Québec"
+ },
+ {
+ "en": "Saskatchewan",
+ "fr": "Saskatchewan"
+ },
+ {
+ "en": "Yukon",
+ "fr": "Yukon"
+ }
+ ],
+ "titleEn": "Province or territory",
+ "titleFr": "Province ou territoire",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 2207,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Preferred language",
+ "titleFr": "Langue préférée",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 2208,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Group and level",
+ "titleFr": "Groupe et niveau",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "submission": {
+ "email": "steven.talbot@cds-snc.ca"
+ },
+ "internalTitleEn": "Public Service Award of Excellence 2020",
+ "internalTitleFr": "Prix d’excellence de la fonction publique 2020",
+ "securityAttribute": "Unclassified"
+}
diff --git a/tests/data/platformIntakeTestForm.json b/__fixtures__/platformIntakeTestForm.json
similarity index 97%
rename from tests/data/platformIntakeTestForm.json
rename to __fixtures__/platformIntakeTestForm.json
index eb32564fa5..c224b4adf3 100644
--- a/tests/data/platformIntakeTestForm.json
+++ b/__fixtures__/platformIntakeTestForm.json
@@ -1,14 +1,6 @@
{
"form": {
- "layout": [
- 1,
- 2,
- 3,
- 4,
- 5,
- 6,
- 7
- ],
+ "layout": [1, 2, 3, 4, 5, 6, 7],
"endPage": {
"descriptionEn": "",
"descriptionFr": "",
@@ -138,6 +130,5 @@
},
"internalTitleEn": "Work with CDS on a Digital Form",
"internalTitleFr": "Travailler avec le SNC sur un formulaire numérique",
- "publishingStatus": true,
"securityAttribute": "Unclassified"
-}
\ No newline at end of file
+}
diff --git a/__fixtures__/testData.json b/__fixtures__/testData.json
new file mode 100644
index 0000000000..4525ce4fc2
--- /dev/null
+++ b/__fixtures__/testData.json
@@ -0,0 +1,303 @@
+{
+ "id": "test0form00000id000asdf11",
+ "form": {
+ "version": 1,
+ "titleEn": "Test Form",
+ "titleFr": "Formulaire de test",
+ "layout": [1, 2, 3, 4, 5, 6, 7, 8],
+ "brand": {
+ "name": "cds-snc",
+ "logoEn": "https://digital.canada.ca/img/cds/cds-lockup-ko-en.svg",
+ "logoFr": "https://numerique.canada.ca/img/cds/cds-lockup-ko-fr.svg",
+ "logoTitleEn": "Canadian Digital Service",
+ "logoTitleFr": "Service numérique canadien",
+ "urlEn": "https://digital.canada.ca/",
+ "urlFr": "https://numerique.canada.ca/"
+ },
+ "endPage": {
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "referrerUrlEn": "https://digital.canada.ca/",
+ "referrerUrlFr": "https://numerique.canada.ca/"
+ },
+ "elements": [
+ {
+ "id": 1,
+ "type": "textField",
+ "properties": {
+ "titleEn": "What is your full name?",
+ "titleFr": "Quel est votre nom complet?",
+ "placeholderEn": "I wish I knew",
+ "placeholderFr": "Je ne sais pas",
+ "descriptionEn": "This is a description",
+ "descriptionFr": "Voice une description",
+ "validation": {
+ "required": true
+ }
+ }
+ },
+ {
+ "id": 2,
+ "type": "textArea",
+ "properties": {
+ "titleEn": "What is the problem you are facing",
+ "titleFr": "Quel est le problème auquel vous êtes confronté?",
+ "placeholderEn": "Something difficult",
+ "placeholderFr": "Quelque chose difficile",
+ "descriptionEn": "Here be a description",
+ "descriptionFr": "Pour décrire, ou pas décire..",
+ "validation": {
+ "required": true
+ }
+ }
+ },
+ {
+ "id": 3,
+ "type": "richText",
+ "properties": {
+ "titleEn": "",
+ "titleFr": "",
+ "descriptionEn": "Thank you so much for your interest in the Canadian Digital Service’s Forms product.
Please provide your information below so CDS can contact you about improving, updating, or digitizing a form.",
+ "descriptionFr": "Merci beaucoup de l’intérêt que vous portez au produit de Formulaire du Service Numérique Canadien.
Veuillez fournir vos renseignements ci-dessous afin que le SNC puisse vous contacter pour discuter davantage l'amélioration, la mise à jour ou la numérisation d'un formulaire.",
+ "validation": {
+ "required": false
+ }
+ }
+ },
+ {
+ "id": 4,
+ "type": "dropdown",
+ "properties": {
+ "titleEn": "Province or territory",
+ "titleFr": "Province ou territoire",
+ "placeholderEn": "",
+ "placeholderFr": "",
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "choices": [
+ {
+ "en": "",
+ "fr": ""
+ },
+ {
+ "en": "Alberta",
+ "fr": "Alberta"
+ },
+ {
+ "en": "British Columbia",
+ "fr": "Colombie-Britannique"
+ },
+ {
+ "en": "Manitoba",
+ "fr": "Manitoba"
+ },
+ {
+ "en": "New Brunswick",
+ "fr": "Nouveau-Brunswick"
+ },
+ {
+ "en": "Newfoundland and Labrador",
+ "fr": "Terre-Neuve-et-Labrador"
+ },
+ {
+ "en": "Northwest Territories",
+ "fr": "Territoires du Nord-Ouest"
+ },
+ {
+ "en": "Nova Scotia",
+ "fr": "Nouvelle-Écosse"
+ },
+ {
+ "en": "Nunavut",
+ "fr": "Nunavut"
+ },
+ {
+ "en": "Ontario",
+ "fr": "Ontario"
+ },
+ {
+ "en": "Prince Edward Island",
+ "fr": "Île-du-Prince-Édouard"
+ },
+ {
+ "en": "Quebec",
+ "fr": "Québec"
+ },
+ {
+ "en": "Saskatchewan",
+ "fr": "Saskatchewan"
+ },
+ {
+ "en": "Yukon",
+ "fr": "Yukon"
+ }
+ ],
+ "validation": {
+ "required": false
+ }
+ }
+ },
+ {
+ "id": 5,
+ "type": "radio",
+ "properties": {
+ "titleEn": "Status",
+ "titleFr": "Statut",
+ "description": "",
+ "validation": {
+ "required": false
+ },
+ "choices": [
+ {
+ "en": "Citizen",
+ "fr": "Cityoen"
+ },
+ {
+ "en": "Permanent Resident",
+ "fr": "Permanent Resident"
+ },
+ {
+ "en": "Student",
+ "fr": "Student"
+ },
+ {
+ "en": "Visitor",
+ "fr": "Visitor"
+ },
+ {
+ "en": "Other",
+ "fr": "Autre"
+ }
+ ]
+ }
+ },
+ {
+ "id": 6,
+ "type": "checkbox",
+ "properties": {
+ "titleEn": "Will the project or any of its activities involve or benefit people in English or French linguistic minority communities in Canada, in some way?",
+ "titleFr": " Le projet ou les activités connexes impliquent-ils ou s’adressent-ils d’une façon ou d’une autre aux minorités francophones et anglophones du Canada?",
+ "validation": {
+ "required": false
+ },
+ "choices": [
+ {
+ "en": "Yes",
+ "fr": "Oui"
+ },
+ {
+ "en": "No",
+ "fr": "Non"
+ },
+ {
+ "en": "Not Applicable",
+ "fr": "Non applicable"
+ }
+ ]
+ }
+ },
+ {
+ "id": 7,
+ "type": "dynamicRow",
+ "properties": {
+ "titleEn": "",
+ "titleFr": "",
+ "validation": {
+ "required": false
+ },
+ "subElements": [
+ {
+ "id": 22,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Family name",
+ "titleFr": "Nom",
+ "placeholderEn": "",
+ "placeholderFr": "",
+ "descriptionEn": "",
+ "descriptionFr": "",
+
+ "validation": {
+ "required": false
+ }
+ }
+ },
+ {
+ "id": 22,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Given name",
+ "titleFr": "Prénom",
+ "laceholderEn": "",
+ "placeholderFr": "",
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "validation": {
+ "required": false
+ }
+ }
+ },
+ {
+ "id": 22,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Department or organization",
+ "titleFr": "Ministère ou organisme",
+ "placeholderEn": "",
+ "placeholderFr": "",
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "validation": {
+ "required": false
+ }
+ }
+ },
+ {
+ "id": 22,
+ "type": "checkbox",
+ "properties": {
+ "titleEn": "Will the project or any of its activities involve or benefit people in English or French linguistic minority communities in Canada, in some way?",
+ "titleFr": " Le projet ou les activités connexes impliquent-ils ou s’adressent-ils d’une façon ou d’une autre aux minorités francophones et anglophones du Canada?",
+ "validation": {
+ "required": false
+ },
+ "choices": [
+ {
+ "en": "Yes",
+ "fr": "Oui"
+ },
+ {
+ "en": "No",
+ "fr": "Non"
+ },
+ {
+ "en": "Not Applicable",
+ "fr": "Non applicable"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "id": 8,
+ "type": "textField",
+ "properties": {
+ "titleEn": "This Answer is empty?",
+ "titleFr": "Ce reponse est vide?",
+ "placeholderEn": "yuppers",
+ "placeholderFr": "oui",
+ "descriptionEn": "This is a description",
+ "descriptionFr": "Voice une description",
+ "validation": {
+ "required": false
+ }
+ }
+ }
+ ]
+ },
+ "submission": {
+ "email": "no-reply@cds-snc.ca"
+ }
+}
diff --git a/tests/data/textFieldTestForm.json b/__fixtures__/textFieldTestForm.json
similarity index 100%
rename from tests/data/textFieldTestForm.json
rename to __fixtures__/textFieldTestForm.json
diff --git a/tests/data/tsbContactTestForm.json b/__fixtures__/tsbContactTestForm.json
similarity index 98%
rename from tests/data/tsbContactTestForm.json
rename to __fixtures__/tsbContactTestForm.json
index 69c4209a5d..a4207e5f7e 100644
--- a/tests/data/tsbContactTestForm.json
+++ b/__fixtures__/tsbContactTestForm.json
@@ -9,15 +9,7 @@
"logoTitleEn": "Transportation Safety Board of Canada",
"logoTitleFr": "Bureau de la sécurité des transports du Canada"
},
- "layout": [
- 1,
- 2,
- 3,
- 4,
- 5,
- 6,
- 7
- ],
+ "layout": [1, 2, 3, 4, 5, 6, 7],
"endPage": {
"descriptionEn": "#Thank you for your message \n\r The Transportation Safety Board of Canada will respond to you within a week. \n\r Go back.",
"descriptionFr": "#Merci pour votre message \n\r Le Bureau de la sécurité des transports du Canada vous répondra d’ici une semaine. \n\r Retour."
@@ -184,6 +176,5 @@
},
"internalTitleEn": "Contact Us - TSB",
"internalTitleFr": "Nous joindre - BST",
- "publishingStatus": true,
"securityAttribute": "Unclassified"
-}
\ No newline at end of file
+}
diff --git a/tests/data/tsbDisableFooterGCBranding.json b/__fixtures__/tsbDisableFooterGCBranding.json
similarity index 95%
rename from tests/data/tsbDisableFooterGCBranding.json
rename to __fixtures__/tsbDisableFooterGCBranding.json
index 46ded6bf4c..4b750f0f4a 100644
--- a/tests/data/tsbDisableFooterGCBranding.json
+++ b/__fixtures__/tsbDisableFooterGCBranding.json
@@ -10,10 +10,7 @@
"logoTitleFr": "Bureau de la sécurité des transports du Canada",
"disableGcBranding": true
},
- "layout": [
- 1
-
- ],
+ "layout": [1],
"endPage": {
"descriptionEn": "#Thank you for your message \n\r The Transportation Safety Board of Canada will respond to you within a week. \n\r Go back.",
"descriptionFr": "#Merci pour votre message \n\r Le Bureau de la sécurité des transports du Canada vous répondra d’ici une semaine. \n\r Retour."
@@ -44,6 +41,5 @@
"email": "forms-formulaires@cds-snc.ca"
},
"internalTitleEn": "Contact Us - TSB",
- "internalTitleFr": "Nous joindre - BST",
- "publishingStatus": true
-}
\ No newline at end of file
+ "internalTitleFr": "Nous joindre - BST"
+}
diff --git a/__fixtures__/validFormTemplate.json b/__fixtures__/validFormTemplate.json
new file mode 100644
index 0000000000..45f37e4d0e
--- /dev/null
+++ b/__fixtures__/validFormTemplate.json
@@ -0,0 +1,644 @@
+{
+ "form": {
+ "layout": [
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 27
+ ],
+ "titleEn": "Public Service Award of Excellence 2020 - Nomination form",
+ "titleFr": "Prix d’excellence de la fonction publique 2020 - Formulaire de mise en candidature",
+ "version": 1,
+ "elements": [
+ {
+ "id": 1,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "#### Section 1: Nomination Category",
+ "descriptionFr": "#### Section 1: Catégorie de la nomination"
+ }
+ },
+ {
+ "id": 2,
+ "type": "radio",
+ "properties": {
+ "choices": [
+ {
+ "en": "Team nomination",
+ "fr": "Mise en candidature d’une équipe"
+ },
+ {
+ "en": "Individual Nomination",
+ "fr": "Mise en candidature d’une personne"
+ }
+ ],
+ "titleEn": "Is this a Team or Individual Nomination?",
+ "titleFr": "Is this a Team or Individual Nomination?",
+ "validation": {
+ "required": true
+ },
+ "descriptionEn": "",
+ "descriptionFr": ""
+ }
+ },
+ {
+ "id": 3,
+ "type": "radio",
+ "properties": {
+ "choices": [
+ {
+ "en": "Excellence in Profession",
+ "fr": "Excellence en profession"
+ },
+ {
+ "en": "Exceptional Young Public Servant",
+ "fr": "Jeunes fonctionnaires exceptionnels"
+ },
+ {
+ "en": "Exemplary Contribution Under Extraordinary Circumstances (Team only)",
+ "fr": "Contribution exemplaire dans des circonstances extraordinaires (Équipe seulement)"
+ },
+ {
+ "en": "Joan Atkinson Award for Public Sector Balues in the Workplace",
+ "fr": "Prix Joan Atkinson pour les Valeurs du secteur public en milieu de travail"
+ },
+ {
+ "en": "Outstanding Career (Individual only)",
+ "fr": "Carrière exceptionnelle (Personne seulement)"
+ },
+ {
+ "en": "60 Years of Service Special Award (Individual only)",
+ "fr": "Prix spécial récompensant 60 années de service (Personne seulement)"
+ }
+ ],
+ "titleEn": "Category",
+ "titleFr": "Catégorie",
+ "validation": {
+ "required": true
+ },
+ "descriptionEn": "",
+ "descriptionFr": ""
+ }
+ },
+ {
+ "id": 4,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "#### Section 2: Nominator Information",
+ "descriptionFr": "#### Section 2: Information sur le proposant"
+ }
+ },
+ {
+ "id": 5,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Family name",
+ "titleFr": "Nom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 6,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Given name",
+ "titleFr": "Prénom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 7,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Department or organization",
+ "titleFr": "Ministère ou organisme",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 8,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Title",
+ "titleFr": "Titre",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 9,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Phone number",
+ "titleFr": "Numéro de téléphone",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 10,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Email address",
+ "titleFr": "Adresse de courriel",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 11,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "#### Section 3: Individual Information (For an Individual Nomination)",
+ "descriptionFr": "#### Section 3: Mise en candidature d'une personne (For an Individual Nomination)"
+ }
+ },
+ {
+ "id": 12,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Family name",
+ "titleFr": "Nom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 13,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Given name",
+ "titleFr": "Prénom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 14,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Department or organization",
+ "titleFr": "Ministère ou organisme",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 15,
+ "type": "dropdown",
+ "properties": {
+ "choices": [
+ {
+ "en": "",
+ "fr": ""
+ },
+ {
+ "en": "Alberta",
+ "fr": "Alberta"
+ },
+ {
+ "en": "British Columbia",
+ "fr": "Colombie-Britannique"
+ },
+ {
+ "en": "Manitoba",
+ "fr": "Manitoba"
+ },
+ {
+ "en": "New Brunswick",
+ "fr": "Nouveau-Brunswick"
+ },
+ {
+ "en": "Newfoundland and Labrador",
+ "fr": "Terre-Neuve-et-Labrador"
+ },
+ {
+ "en": "Northwest Territories",
+ "fr": "Territoires du Nord-Ouest"
+ },
+ {
+ "en": "Nova Scotia",
+ "fr": "Nouvelle-Écosse"
+ },
+ {
+ "en": "Nunavut",
+ "fr": "Nunavut"
+ },
+ {
+ "en": "Ontario",
+ "fr": "Ontario"
+ },
+ {
+ "en": "Prince Edward Island",
+ "fr": "Île-du-Prince-Édouard"
+ },
+ {
+ "en": "Quebec",
+ "fr": "Québec"
+ },
+ {
+ "en": "Saskatchewan",
+ "fr": "Saskatchewan"
+ },
+ {
+ "en": "Yukon",
+ "fr": "Yukon"
+ }
+ ],
+ "titleEn": "Province or territory",
+ "titleFr": "Province ou territoire",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 16,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Preferred language",
+ "titleFr": "Langue préférée",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 17,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Group and level",
+ "titleFr": "Groupe et niveau",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 18,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "#### Section 4: Team Nomination (for a Team Nomination)",
+ "descriptionFr": "#### Section 4: Mise en candidature d’une équipe (for a Team Nomination)"
+ }
+ },
+ {
+ "id": 19,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Team name in english",
+ "titleFr": "Nom de l’équipe en anglais",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 20,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Team name in french",
+ "titleFr": "Nom de l’équipe en français",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 21,
+ "type": "richText",
+ "properties": {
+ "titleEn": "Team Members",
+ "titleFr": "Membres de l’équipe",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "You can click Add a row to add more than one team member to your application. Please note that you can only list a maximum of 15 team members.",
+ "descriptionFr": "You can click Add a row to add more than one team member to your application. Please note that you can only list a maximum of 15 team members.",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 22,
+ "type": "dynamicRow",
+ "properties": {
+ "titleEn": "",
+ "titleFr": "",
+ "validation": {
+ "required": false
+ },
+ "subElements": [
+ {
+ "id": 2201,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Family name",
+ "titleFr": "Nom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 2202,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Given name",
+ "titleFr": "Prénom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 2203,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Department or organization",
+ "titleFr": "Ministère ou organisme",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 2204,
+ "type": "dropdown",
+ "properties": {
+ "choices": [
+ {
+ "en": "",
+ "fr": ""
+ },
+ {
+ "en": "Alberta",
+ "fr": "Alberta"
+ },
+ {
+ "en": "British Columbia",
+ "fr": "Colombie-Britannique"
+ },
+ {
+ "en": "Manitoba",
+ "fr": "Manitoba"
+ },
+ {
+ "en": "New Brunswick",
+ "fr": "Nouveau-Brunswick"
+ },
+ {
+ "en": "Newfoundland and Labrador",
+ "fr": "Terre-Neuve-et-Labrador"
+ },
+ {
+ "en": "Northwest Territories",
+ "fr": "Territoires du Nord-Ouest"
+ },
+ {
+ "en": "Nova Scotia",
+ "fr": "Nouvelle-Écosse"
+ },
+ {
+ "en": "Nunavut",
+ "fr": "Nunavut"
+ },
+ {
+ "en": "Ontario",
+ "fr": "Ontario"
+ },
+ {
+ "en": "Prince Edward Island",
+ "fr": "Île-du-Prince-Édouard"
+ },
+ {
+ "en": "Quebec",
+ "fr": "Québec"
+ },
+ {
+ "en": "Saskatchewan",
+ "fr": "Saskatchewan"
+ },
+ {
+ "en": "Yukon",
+ "fr": "Yukon"
+ }
+ ],
+ "titleEn": "Province or territory",
+ "titleFr": "Province ou territoire",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 2205,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Preferred language",
+ "titleFr": "Langue préférée",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 2206,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Group and level",
+ "titleFr": "Groupe et niveau",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ }
+ ]
+ }
+ },
+ {
+ "id": 23,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "#### Annex A: Achievement Summary",
+ "descriptionFr": "#### Annex A: Résumé des réalisations"
+ }
+ },
+ {
+ "id": 24,
+ "type": "textArea",
+ "properties": {
+ "titleEn": "Briefly describe the achievement for which the nomination is being submitted.",
+ "titleFr": "Décrire brièvement la réalisation pour laquelle la candidature est présentée.",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "Do not include headings or other formatting. Use a maximum of 200 words",
+ "descriptionFr": "Do not include headings or other formatting. Use a maximum of 200 words",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 25,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Name of Nominator",
+ "titleFr": "Nom du proposant",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 26,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Date",
+ "titleFr": "Date",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 27,
+ "type": "checkbox",
+ "properties": {
+ "choices": [
+ {
+ "en": "I hereby certify that, to the best of my knowledge, the information in this form is true and correct.",
+ "fr": "J’atteste par la présente qu’à ma connaissance, les renseignements fournis dans ce formulaire sont véridiques et corrects."
+ }
+ ],
+ "titleEn": "Consent of the Nominator",
+ "titleFr": "Consent of the Nominator",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": ""
+ }
+ }
+ ]
+ },
+ "submission": {
+ "email": "steven.talbot@cds-snc.ca"
+ },
+ "internalTitleEn": "Public Service Award of Excellence 2020",
+ "internalTitleFr": "Prix d’excellence de la fonction publique 2020",
+ "securityAttribute": "Unclassified"
+}
diff --git a/__fixtures__/validFormTemplateWithHTMLInDynamicRow.json b/__fixtures__/validFormTemplateWithHTMLInDynamicRow.json
new file mode 100644
index 0000000000..deea864427
--- /dev/null
+++ b/__fixtures__/validFormTemplateWithHTMLInDynamicRow.json
@@ -0,0 +1,644 @@
+{
+ "form": {
+ "layout": [
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 27
+ ],
+ "titleEn": "Public Service Award of Excellence 2020 - Nomination form",
+ "titleFr": "Prix d’excellence de la fonction publique 2020 - Formulaire de mise en candidature",
+ "version": 1,
+ "elements": [
+ {
+ "id": 1,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "#### Section 1: Nomination Category",
+ "descriptionFr": "#### Section 1: Catégorie de la nomination"
+ }
+ },
+ {
+ "id": 2,
+ "type": "radio",
+ "properties": {
+ "choices": [
+ {
+ "en": "Team nomination",
+ "fr": "Mise en candidature d’une équipe"
+ },
+ {
+ "en": "Individual Nomination",
+ "fr": "Mise en candidature d’une personne"
+ }
+ ],
+ "titleEn": "Is this a Team or Individual Nomination?",
+ "titleFr": "Is this a Team or Individual Nomination?",
+ "validation": {
+ "required": true
+ },
+ "descriptionEn": "",
+ "descriptionFr": ""
+ }
+ },
+ {
+ "id": 3,
+ "type": "radio",
+ "properties": {
+ "choices": [
+ {
+ "en": "Excellence in Profession",
+ "fr": "Excellence en profession"
+ },
+ {
+ "en": "Exceptional Young Public Servant",
+ "fr": "Jeunes fonctionnaires exceptionnels"
+ },
+ {
+ "en": "Exemplary Contribution Under Extraordinary Circumstances (Team only)",
+ "fr": "Contribution exemplaire dans des circonstances extraordinaires (Équipe seulement)"
+ },
+ {
+ "en": "Joan Atkinson Award for Public Sector Balues in the Workplace",
+ "fr": "Prix Joan Atkinson pour les Valeurs du secteur public en milieu de travail"
+ },
+ {
+ "en": "Outstanding Career (Individual only)",
+ "fr": "Carrière exceptionnelle (Personne seulement)"
+ },
+ {
+ "en": "60 Years of Service Special Award (Individual only)",
+ "fr": "Prix spécial récompensant 60 années de service (Personne seulement)"
+ }
+ ],
+ "titleEn": "Category",
+ "titleFr": "Catégorie",
+ "validation": {
+ "required": true
+ },
+ "descriptionEn": "",
+ "descriptionFr": ""
+ }
+ },
+ {
+ "id": 4,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "#### Section 2: Nominator Information",
+ "descriptionFr": "#### Section 2: Information sur le proposant"
+ }
+ },
+ {
+ "id": 5,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Family name",
+ "titleFr": "Nom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 6,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Given name",
+ "titleFr": "Prénom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 7,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Department or organization",
+ "titleFr": "Ministère ou organisme",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 8,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Title",
+ "titleFr": "Titre",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 9,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Phone number",
+ "titleFr": "Numéro de téléphone",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 10,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Email address",
+ "titleFr": "Adresse de courriel",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 11,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "#### Section 3: Individual Information (For an Individual Nomination)",
+ "descriptionFr": "#### Section 3: Mise en candidature d'une personne (For an Individual Nomination)"
+ }
+ },
+ {
+ "id": 12,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Family name",
+ "titleFr": "Nom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 13,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Given name",
+ "titleFr": "Prénom",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 14,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Department or organization",
+ "titleFr": "Ministère ou organisme",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 15,
+ "type": "dropdown",
+ "properties": {
+ "choices": [
+ {
+ "en": "",
+ "fr": ""
+ },
+ {
+ "en": "Alberta",
+ "fr": "Alberta"
+ },
+ {
+ "en": "British Columbia",
+ "fr": "Colombie-Britannique"
+ },
+ {
+ "en": "Manitoba",
+ "fr": "Manitoba"
+ },
+ {
+ "en": "New Brunswick",
+ "fr": "Nouveau-Brunswick"
+ },
+ {
+ "en": "Newfoundland and Labrador",
+ "fr": "Terre-Neuve-et-Labrador"
+ },
+ {
+ "en": "Northwest Territories",
+ "fr": "Territoires du Nord-Ouest"
+ },
+ {
+ "en": "Nova Scotia",
+ "fr": "Nouvelle-Écosse"
+ },
+ {
+ "en": "Nunavut",
+ "fr": "Nunavut"
+ },
+ {
+ "en": "Ontario",
+ "fr": "Ontario"
+ },
+ {
+ "en": "Prince Edward Island",
+ "fr": "Île-du-Prince-Édouard"
+ },
+ {
+ "en": "Quebec",
+ "fr": "Québec"
+ },
+ {
+ "en": "Saskatchewan",
+ "fr": "Saskatchewan"
+ },
+ {
+ "en": "Yukon",
+ "fr": "Yukon"
+ }
+ ],
+ "titleEn": "Province or territory",
+ "titleFr": "Province ou territoire",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 16,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Preferred language",
+ "titleFr": "Langue préférée",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 17,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Group and level",
+ "titleFr": "Groupe et niveau",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 18,
+ "type": "richText",
+ "properties": {
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "#### Section 4: Team Nomination (for a Team Nomination)",
+ "descriptionFr": "#### Section 4: Mise en candidature d’une équipe (for a Team Nomination)"
+ }
+ },
+ {
+ "id": 19,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Team name in english",
+ "titleFr": "Nom de l’équipe en anglais",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 20,
+ "type": "textField",
+ "properties": {
+ "titleEn": "Team name in french",
+ "titleFr": "Nom de l’équipe en français",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "",
+ "descriptionFr": "",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 21,
+ "type": "richText",
+ "properties": {
+ "titleEn": "Team Members",
+ "titleFr": "Membres de l’équipe",
+ "validation": {
+ "required": false
+ },
+ "descriptionEn": "You can click Add a row to add more than one team member to your application. Please note that you can only list a maximum of 15 team members.",
+ "descriptionFr": "You can click Add a row to add more than one team member to your application. Please note that you can only list a maximum of 15 team members.",
+ "placeholderEn": "",
+ "placeholderFr": ""
+ }
+ },
+ {
+ "id": 22,
+ "type": "dynamicRow",
+ "properties": {
+ "titleEn": "",
+ "titleFr": "",
+ "validation": {
+ "required": false
+ },
+ "subElements": [
+ {
+ "id": 2201,
+ "type": "textField",
+ "properties": {
+ "titleEn": "