├── .nvmrc ├── .prettierrc.json ├── designer ├── .pa11yci.json ├── snowpack.config.js ├── __mocks__ │ ├── styleMock.js │ └── imageMock.js ├── client │ ├── i18n │ │ ├── index.ts │ │ └── translations │ │ │ └── cy.translation.json │ ├── data │ │ ├── section │ │ │ ├── index.ts │ │ │ ├── addSection.ts │ │ │ └── __tests__ │ │ │ │ └── addSection.jest.ts │ │ ├── list │ │ │ ├── index.ts │ │ │ ├── addList.ts │ │ │ ├── findList.ts │ │ │ └── __tests__ │ │ │ │ ├── findList.jest.ts │ │ │ │ └── addList.jest.ts │ │ ├── component │ │ │ ├── index.ts │ │ │ └── addComponent.ts │ │ ├── condition │ │ │ ├── index.ts │ │ │ ├── hasConditions.ts │ │ │ ├── addCondition.ts │ │ │ ├── removeCondition.ts │ │ │ └── __tests__ │ │ │ │ └── hasConditions.jest.ts │ │ ├── page │ │ │ ├── index.ts │ │ │ ├── addPage.ts │ │ │ ├── allPathsLeadingTo.ts │ │ │ ├── findPage.ts │ │ │ ├── updateLinksTo.ts │ │ │ ├── __tests__ │ │ │ │ └── addPage.jest.ts │ │ │ └── updateLink.ts │ │ └── index.ts │ ├── components │ │ ├── Page │ │ │ └── index.ts │ │ ├── Flyout │ │ │ └── index.ts │ │ ├── BackLink │ │ │ ├── index.ts │ │ │ ├── BackLink.tsx │ │ │ └── BackLink.scss │ │ ├── Menu │ │ │ ├── index.ts │ │ │ ├── useTabs.tsx │ │ │ └── useMenuItem.tsx │ │ ├── CssClasses │ │ │ └── index.ts │ │ ├── FormDetails │ │ │ ├── index.ts │ │ │ ├── FormDetails.scss │ │ │ └── FormDetailsTitle.tsx │ │ ├── PageLinkage │ │ │ └── index.ts │ │ ├── Autocomplete │ │ │ └── index.ts │ │ ├── ErrorMessage │ │ │ ├── index.ts │ │ │ ├── ErrorMessage.tsx │ │ │ └── __tests__ │ │ │ │ └── ErrorMessage.jest.tsx │ │ ├── Visualisation │ │ │ ├── index.ts │ │ │ └── Info.tsx │ │ ├── ComponentCreate │ │ │ ├── index.ts │ │ │ ├── ComponentCreate.scss │ │ │ └── __tests__ │ │ │ │ └── ComponentCreateList.jest.tsx │ │ ├── RenderInPortal │ │ │ ├── index.ts │ │ │ └── RenderInPortal.tsx │ │ ├── CustomValidationMessage │ │ │ └── index.ts │ │ ├── Icons │ │ │ ├── index.ts │ │ │ ├── ChevronRightIcon.tsx │ │ │ ├── MoveUpIcon.tsx │ │ │ ├── MoveDownIcon.tsx │ │ │ └── SearchIcon.tsx │ │ └── FieldEditors │ │ │ ├── email-edit.tsx │ │ │ └── list-field-edit.tsx │ ├── hooks │ │ ├── list │ │ │ └── useListItem │ │ │ │ ├── index.tsx │ │ │ │ └── types.ts │ │ ├── featureToggling.tsx │ │ └── __tests__ │ │ │ └── FeatureTogglingHook.jest.tsx │ ├── pages │ │ ├── ErrorPages │ │ │ ├── index.ts │ │ │ └── ErrorPage.scss │ │ └── LandingPage │ │ │ ├── index.ts │ │ │ └── LandingPage.scss │ ├── styles │ │ ├── colors.scss │ │ └── _utils.scss │ ├── context │ │ ├── index.ts │ │ ├── FlyoutContext.ts │ │ └── DataContext.ts │ ├── FeatureToggle.tsx │ ├── conditions │ │ ├── inline-condition-helpers.js │ │ ├── TextValues.tsx │ │ └── __tests__ │ │ │ └── inline-condition-helpers.jest.ts │ ├── reducers │ │ ├── component │ │ │ └── index.ts │ │ └── listActions.tsx │ ├── __tests__ │ │ ├── page-edit.jest.tsx │ │ ├── helpers │ │ │ └── mocks.ts │ │ └── helpers.jest.tsx │ ├── randomId.ts │ ├── api │ │ ├── toggleApi.ts │ │ └── designerApi.ts │ ├── __mocks__ │ │ └── tabbable.js │ ├── modal.js │ ├── outputs │ │ └── webhook-edit.tsx │ ├── plugins │ │ └── logger.ts │ └── load-form-configurations.js ├── .gitignore ├── postcss.config.js ├── nodemon.json ├── server │ ├── views │ │ ├── split.html │ │ ├── includes │ │ │ ├── home-office-header.html │ │ │ └── home-office-footer.html │ │ └── designer.html │ ├── plugins │ │ ├── routes │ │ │ ├── index.ts │ │ │ └── healthCheck.ts │ │ ├── logging.ts │ │ ├── session.ts │ │ ├── blankie.ts │ │ └── router.ts │ ├── index.ts │ ├── lib │ │ ├── publish │ │ │ └── index.ts │ │ └── persistence │ │ │ ├── blobPersistenceService.ts │ │ │ ├── index.ts │ │ │ └── persistenceService.ts │ └── __tests__ │ │ └── healthCheck.jest.ts ├── jest-server-setup.js ├── bin │ └── symlink-config ├── LICENSE ├── jest-setup.js ├── jest.server.config.js ├── test │ ├── helpers │ │ ├── sub-component-assertions.js │ │ └── react-testing-library-utils.ts │ ├── testServer.js │ └── .setup.js ├── .eslintrc.js ├── tsconfig.json └── new-form.json ├── runner ├── Procfile ├── src │ ├── server │ │ ├── schemas │ │ │ └── index.ts │ │ ├── plugins │ │ │ ├── engine │ │ │ │ ├── models │ │ │ │ │ ├── Section.ts │ │ │ │ │ ├── RepeatingSummaryViewModel.ts │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── summaryViewModel.jest.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── submission │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── SummaryViewModel.detailsTransformationMap.ts │ │ │ │ │ └── FormModel.exitOptions.ts │ │ │ │ ├── components │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── InsetText.ts │ │ │ │ │ ├── RadiosField.ts │ │ │ │ │ ├── Para.ts │ │ │ │ │ ├── Details.ts │ │ │ │ │ ├── SelectField.ts │ │ │ │ │ ├── Html.ts │ │ │ │ │ └── FlashCard.ts │ │ │ │ ├── views │ │ │ │ │ ├── components │ │ │ │ │ │ ├── html.html │ │ │ │ │ │ ├── para.html │ │ │ │ │ │ ├── datefield.html │ │ │ │ │ │ ├── numberfield.html │ │ │ │ │ │ ├── timefield.html │ │ │ │ │ │ ├── datetimefield.html │ │ │ │ │ │ ├── textfield.html │ │ │ │ │ │ ├── websitefield.html │ │ │ │ │ │ ├── yesnofield.html │ │ │ │ │ │ ├── radiosfield.html │ │ │ │ │ │ ├── emailaddressfield.html │ │ │ │ │ │ ├── selectfield.html │ │ │ │ │ │ ├── telephonenumberfield.html │ │ │ │ │ │ ├── checkboxesfield.html │ │ │ │ │ │ ├── datepartsfield.html │ │ │ │ │ │ ├── monthyearfield.html │ │ │ │ │ │ ├── datetimepartsfield.html │ │ │ │ │ │ ├── insettext.html │ │ │ │ │ │ ├── details.html │ │ │ │ │ │ ├── multilinetextfield.html │ │ │ │ │ │ ├── fileuploadfield.html │ │ │ │ │ │ └── list.html │ │ │ │ │ ├── partials │ │ │ │ │ │ ├── conditional-components.html │ │ │ │ │ │ ├── components.html │ │ │ │ │ │ └── heading.html │ │ │ │ │ └── index.html │ │ │ │ ├── feedback │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── helpers.ts │ │ │ │ │ └── FeedbackContextInfo.ts │ │ │ │ ├── pluginHandlers │ │ │ │ │ ├── files │ │ │ │ │ │ └── prehandlers │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── getFiles.ts │ │ │ │ │ └── exit │ │ │ │ │ │ └── prehandlers │ │ │ │ │ │ ├── getBacklink.ts │ │ │ │ │ │ ├── getForm.ts │ │ │ │ │ │ ├── parseExitEmailErrors.ts │ │ │ │ │ │ └── getState.ts │ │ │ │ ├── index.ts │ │ │ │ ├── pageControllers │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── MultiStartPageController.ts │ │ │ │ │ ├── HomePageController.ts │ │ │ │ │ ├── StartPageController.ts │ │ │ │ │ └── StartDatePageController.ts │ │ │ │ └── services │ │ │ │ │ └── configurationService.ts │ │ │ ├── initialiseSession │ │ │ │ ├── index.ts │ │ │ │ ├── configurePlugin.ts │ │ │ │ └── types.ts │ │ │ ├── pulse.ts │ │ │ ├── session.ts │ │ │ ├── applicationStatus │ │ │ │ ├── checkUserCompletedSummary.ts │ │ │ │ └── retryPay.ts │ │ │ ├── logging.ts │ │ │ └── rateLimit.ts │ │ ├── routes │ │ │ ├── index.ts │ │ │ ├── health-check.ts │ │ │ └── public.ts │ │ ├── services │ │ │ ├── upload │ │ │ │ ├── index.ts │ │ │ │ └── mockUploadService.ts │ │ │ ├── payService.nanoid.ts │ │ │ ├── index.ts │ │ │ └── QueueService.ts │ │ ├── config.ts │ │ ├── utils │ │ │ ├── generateCookiePassword.ts │ │ │ └── url.ts │ │ ├── forms │ │ │ └── README.md │ │ ├── templates │ │ │ └── additionalContexts.json │ │ ├── views │ │ │ ├── help │ │ │ │ ├── privacy.html │ │ │ │ └── accessibility-statement.html │ │ │ ├── 500.html │ │ │ ├── application-error.html │ │ │ ├── mini-summary.html │ │ │ ├── partials │ │ │ │ ├── summary-detail.html │ │ │ │ └── summary-row.html │ │ │ └── timeout.html │ │ └── transforms │ │ │ └── summaryDetails │ │ │ ├── index.ts │ │ │ └── types.ts │ ├── client │ │ └── sass │ │ │ ├── _govuk.scss │ │ │ ├── _upload-dialog.scss │ │ │ └── _hmpo.scss │ └── index.ts ├── bin │ ├── build │ ├── build-css │ ├── run │ │ └── check │ │ │ ├── index.js │ │ │ ├── util.js │ │ │ ├── getJsonFiles.js │ │ │ ├── getOutOfDateForms.js │ │ │ └── check.js │ └── symlink-config ├── nodemon.json ├── performance │ └── dummy.pdf ├── public │ └── static │ │ ├── favicon.ico │ │ ├── upload-dialog.js │ │ └── object-from-entries-polyfill.js ├── test │ ├── cases │ │ └── server │ │ │ ├── dummy.pdf │ │ │ ├── forms │ │ │ ├── phase-default.json │ │ │ ├── phase-none.json │ │ │ └── phase-alpha.json │ │ │ ├── utils │ │ │ └── generateCookiePassword.test.ts │ │ │ ├── plugins │ │ │ └── engine │ │ │ │ ├── EmailAddressField.test.ts │ │ │ │ ├── feedback-context-info.test.ts │ │ │ │ └── services │ │ │ │ └── configurationService.test.ts │ │ │ ├── services │ │ │ └── httpService.test.ts │ │ │ └── rate-limit.test.js │ └── html-helper.js ├── config │ ├── development.json │ ├── production.json │ └── test.json ├── .gitignore ├── LICENSE ├── .babelrc └── tsconfig.json ├── .browserslistrc ├── .eslintignore ├── model ├── src │ ├── schema │ │ └── index.ts │ ├── form │ │ ├── index.ts │ │ └── form-configuration.ts │ ├── migration │ │ ├── index.ts │ │ ├── types.ts │ │ ├── __tests__ │ │ │ └── whichMigrations.jest.ts │ │ ├── whichMigrations.ts │ │ └── migration.0-2.ts │ ├── components │ │ ├── index.ts │ │ └── conditional-component-types.ts │ ├── data-model │ │ ├── index.ts │ │ └── __tests__ │ │ │ └── isMultipleApiKey.test.ts │ ├── conditions │ │ ├── helpers.ts │ │ ├── condition-value-registration.ts │ │ ├── index.ts │ │ ├── condition-group-def.ts │ │ ├── types.ts │ │ ├── condition-field.ts │ │ └── condition-value-abstract.ts │ ├── index.ts │ └── utils │ │ ├── logger.ts │ │ └── helpers.ts ├── LICENSE ├── tsconfig.json └── jest.config.js ├── submitter ├── config │ ├── test.json │ ├── custom-environment-variables.json │ └── default.js ├── src │ ├── config.ts │ ├── submission │ │ ├── services │ │ │ └── index.ts │ │ ├── retention │ │ │ └── errors.ts │ │ ├── index.ts │ │ ├── plugins │ │ │ ├── logging.ts │ │ │ ├── retentionCron.ts │ │ │ ├── retention.ts │ │ │ └── poll.ts │ │ ├── types.ts │ │ └── setupDatabase.ts │ └── __mocks__ │ │ └── prismaClient.ts ├── nodemon.json ├── jest.config.js ├── .babelrc └── tsconfig.json ├── e2e ├── cypress │ ├── fixtures │ │ ├── passes.png │ │ ├── fails-ocr.png │ │ ├── example.json │ │ └── image-quality-playback.json │ ├── support │ │ ├── step_definitions │ │ │ ├── common │ │ │ │ ├── i_reload.js │ │ │ │ ├── i_go_back.js │ │ │ │ ├── i_choose_string.js │ │ │ │ ├── i_continue.js │ │ │ │ ├── i_enter_string.js │ │ │ │ ├── i_wait.js │ │ │ │ ├── i_click_the_back_link.js │ │ │ │ ├── i_select_the_option_string.js │ │ │ │ ├── i_click_the_link_string.js │ │ │ │ ├── i_see_the_heading_string.js │ │ │ │ ├── i_submit_the_form.js │ │ │ │ ├── i_see_the_path_is_string.js │ │ │ │ ├── i_dont_see_the_page_string.js │ │ │ │ ├── i_select_string_for_string.js │ │ │ │ ├── i_have_read_the_disclaimer.js │ │ │ │ ├── i_dont_see_string.js │ │ │ │ ├── i_enter_string_for_string.js │ │ │ │ ├── i_expand_string_to_see_string.js │ │ │ │ ├── i_select.js │ │ │ │ ├── i_see_string.js │ │ │ │ ├── i_choose_string_for_string.js │ │ │ │ ├── i_see_the_error_string_for_string.js │ │ │ │ ├── i_edit_page_string.js │ │ │ │ └── i_enter_the_date_string_in_parts_for_string.js │ │ │ ├── runner │ │ │ │ ├── i_am_redirected_to_string.js │ │ │ │ ├── i_am_viewing_the_runner_at_string.js │ │ │ │ ├── i_navigate_to_string.js │ │ │ │ ├── i_navigate_to_the_string_form.js │ │ │ │ ├── i_upload_a_file_that_string.js │ │ │ │ ├── the_field_string_contains_string.js │ │ │ │ ├── i_see_the_string_page.js │ │ │ │ ├── i_see_a_summary_list_with_the_values.js │ │ │ │ └── the_form_string_exists.js │ │ │ └── designer │ │ │ │ ├── i_am_viewing_the_designer.js │ │ │ │ ├── i_navigate_away_from_the_designer.js │ │ │ │ ├── i_delete_the_page.js │ │ │ │ ├── i_see_the_section_title_string_is_displayed_in_the_preview.js │ │ │ │ ├── i_am_on_the_new_configuration_page.js │ │ │ │ ├── i_change_the_page_path_to_string.js │ │ │ │ ├── i_will_see_an_alert_warning_me_that_string.js │ │ │ │ ├── i_change_the_page_title_to_string.js │ │ │ │ ├── i_create_a_section_titled_string.js │ │ │ │ └── i_preview_the_page_string.js │ │ └── e2e.js │ └── e2e │ │ ├── runner │ │ ├── files.js │ │ ├── backLinkFallback.js │ │ ├── htmlTemplating.feature │ │ ├── repeatField │ │ │ ├── confirmationTimeout.feature │ │ │ ├── samePageSummary.feature │ │ │ └── separatePageSummary.feature │ │ ├── redirect.feature │ │ ├── backLinkFallback.feature │ │ ├── files.feature │ │ ├── MiniSummaryPageController.feature │ │ ├── exit.js │ │ └── getConditionEvaluationContext.feature │ │ └── designer │ │ ├── accessibilityStatement.js │ │ ├── notifyOutput.feature │ │ ├── startPage.js │ │ ├── notifyOutput.js │ │ └── accessibilityStatement.feature └── package.json ├── queue-model ├── migrations │ ├── 20230919102214_use_db_text │ │ └── migration.sql │ ├── 20231107195736_add_allow_retry │ │ └── migration.sql │ ├── migration_lock.toml │ ├── 20231108100812_webhook_url_required │ │ └── migration.sql │ ├── 20230915145048_add_defaults │ │ └── migration.sql │ └── 20230913152003_init │ │ └── migration.sql ├── src │ └── index.ts ├── babel.config.json ├── tsconfig.json └── schema.prisma ├── docs ├── designer │ └── query-param-field.png ├── adr │ └── 0000-state-of-the-union.md ├── runner │ ├── mini-summary-page-controller.md │ └── arkit.json └── model │ └── arkit.json ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ └── feature_request.md └── dependabot.yml ├── .prettierignore ├── .dockerignore ├── .yarnrc.yml ├── babel.config.json ├── GitVersion.yml ├── lighthouserc.js └── .gitignore /.nvmrc: -------------------------------------------------------------------------------- 1 | 12 2 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /designer/.pa11yci.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /designer/snowpack.config.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /runner/Procfile: -------------------------------------------------------------------------------- 1 | web: npm run start 2 | -------------------------------------------------------------------------------- /runner/src/server/schemas/index.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.browserslistrc: -------------------------------------------------------------------------------- 1 | last 1 Chrome versions 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | docker-compose.yml 2 | Dockerfile -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/models/Section.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /designer/__mocks__/styleMock.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | -------------------------------------------------------------------------------- /designer/client/i18n/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./i18n"; 2 | -------------------------------------------------------------------------------- /runner/bin/build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | npm run build:css -------------------------------------------------------------------------------- /designer/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | unit-test.html 3 | coverage 4 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/models/RepeatingSummaryViewModel.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /designer/client/data/section/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./addSection"; 2 | -------------------------------------------------------------------------------- /designer/client/components/Page/index.ts: -------------------------------------------------------------------------------- 1 | export { Page } from "./Page"; 2 | -------------------------------------------------------------------------------- /designer/__mocks__/imageMock.js: -------------------------------------------------------------------------------- 1 | module.exports = "pretend/path/to/image.png"; 2 | -------------------------------------------------------------------------------- /designer/client/components/Flyout/index.ts: -------------------------------------------------------------------------------- 1 | export { Flyout } from "./Flyout"; 2 | -------------------------------------------------------------------------------- /model/src/schema/index.ts: -------------------------------------------------------------------------------- 1 | export { Schema, componentSchema } from "./schema"; 2 | -------------------------------------------------------------------------------- /submitter/config/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": "test", 3 | "isTest": true 4 | } 5 | -------------------------------------------------------------------------------- /submitter/src/config.ts: -------------------------------------------------------------------------------- 1 | import config from "config"; 2 | export default config; 3 | -------------------------------------------------------------------------------- /designer/client/components/BackLink/index.ts: -------------------------------------------------------------------------------- 1 | export { BackLink } from "./BackLink"; 2 | -------------------------------------------------------------------------------- /designer/client/components/Menu/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Menu } from "./Menu"; 2 | -------------------------------------------------------------------------------- /model/src/form/index.ts: -------------------------------------------------------------------------------- 1 | export { FormConfiguration } from "./form-configuration"; 2 | -------------------------------------------------------------------------------- /model/src/migration/index.ts: -------------------------------------------------------------------------------- 1 | export { whichMigrations } from "./whichMigrations"; 2 | -------------------------------------------------------------------------------- /model/src/migration/types.ts: -------------------------------------------------------------------------------- 1 | export type MigrationScript = (data: Object) => Object; 2 | -------------------------------------------------------------------------------- /designer/client/components/CssClasses/index.ts: -------------------------------------------------------------------------------- 1 | export { CssClasses } from "./CssClasses"; 2 | -------------------------------------------------------------------------------- /designer/client/components/FormDetails/index.ts: -------------------------------------------------------------------------------- 1 | export { FormDetails } from "./FormDetails"; 2 | -------------------------------------------------------------------------------- /designer/client/components/PageLinkage/index.ts: -------------------------------------------------------------------------------- 1 | export { PageLinkage } from "./PageLinkage"; 2 | -------------------------------------------------------------------------------- /designer/client/data/list/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./findList"; 2 | export * from "./addList"; 3 | -------------------------------------------------------------------------------- /designer/client/hooks/list/useListItem/index.tsx: -------------------------------------------------------------------------------- 1 | export { useListItem } from "./useListItem"; 2 | -------------------------------------------------------------------------------- /designer/client/pages/ErrorPages/index.ts: -------------------------------------------------------------------------------- 1 | export { default as SaveError } from "./SaveError"; 2 | -------------------------------------------------------------------------------- /designer/client/components/Autocomplete/index.ts: -------------------------------------------------------------------------------- 1 | export { Autocomplete } from "./Autocomplete"; 2 | -------------------------------------------------------------------------------- /designer/client/components/ErrorMessage/index.ts: -------------------------------------------------------------------------------- 1 | export { ErrorMessage } from "./ErrorMessage"; 2 | -------------------------------------------------------------------------------- /designer/client/components/Visualisation/index.ts: -------------------------------------------------------------------------------- 1 | export { Visualisation } from "./Visualisation"; 2 | -------------------------------------------------------------------------------- /designer/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [require("autoprefixer")({})], 3 | }; 4 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/components/constants.ts: -------------------------------------------------------------------------------- 1 | export const optionalText = " (optional)"; 2 | -------------------------------------------------------------------------------- /designer/client/components/ComponentCreate/index.ts: -------------------------------------------------------------------------------- 1 | export { ComponentCreate } from "./ComponentCreate"; 2 | -------------------------------------------------------------------------------- /designer/client/components/RenderInPortal/index.ts: -------------------------------------------------------------------------------- 1 | export { RenderInPortal } from "./RenderInPortal"; 2 | -------------------------------------------------------------------------------- /designer/client/styles/colors.scss: -------------------------------------------------------------------------------- 1 | @import "../../../node_modules/govuk-frontend/govuk/helpers/colour"; 2 | -------------------------------------------------------------------------------- /designer/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "delay": "500", 3 | "watch": ["dist"], 4 | "legacyWatch": true 5 | } 6 | -------------------------------------------------------------------------------- /runner/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "delay": "500", 3 | "watch": ["dist"], 4 | "legacyWatch": true 5 | } 6 | -------------------------------------------------------------------------------- /submitter/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "delay": "500", 3 | "watch": ["dist"], 4 | "legacyWatch": true 5 | } 6 | -------------------------------------------------------------------------------- /runner/src/server/plugins/initialiseSession/index.ts: -------------------------------------------------------------------------------- 1 | export { initialiseSession } from "./initialiseSession"; 2 | -------------------------------------------------------------------------------- /runner/performance/dummy.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XGovFormBuilder/digital-form-builder/HEAD/runner/performance/dummy.pdf -------------------------------------------------------------------------------- /designer/client/components/CustomValidationMessage/index.ts: -------------------------------------------------------------------------------- 1 | export { CustomValidationMessage } from "./CustomValidationMessage"; 2 | -------------------------------------------------------------------------------- /designer/client/context/index.ts: -------------------------------------------------------------------------------- 1 | export { DataContext } from "./DataContext"; 2 | export { FlyoutContext } from "./FlyoutContext"; 3 | -------------------------------------------------------------------------------- /e2e/cypress/fixtures/passes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XGovFormBuilder/digital-form-builder/HEAD/e2e/cypress/fixtures/passes.png -------------------------------------------------------------------------------- /queue-model/migrations/20230919102214_use_db_text/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE `Submission` MODIFY `data` TEXT NULL; 3 | -------------------------------------------------------------------------------- /runner/public/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XGovFormBuilder/digital-form-builder/HEAD/runner/public/static/favicon.ico -------------------------------------------------------------------------------- /runner/src/client/sass/_govuk.scss: -------------------------------------------------------------------------------- 1 | $govuk-global-styles: true; 2 | @import "./../../../node_modules/govuk-frontend/dist/govuk/all"; 3 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/models/__tests__/summaryViewModel.jest.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * TODO: add tests for SummaryViewModel 3 | */ 4 | -------------------------------------------------------------------------------- /designer/client/components/ComponentCreate/ComponentCreate.scss: -------------------------------------------------------------------------------- 1 | .component-create { 2 | .back-link { 3 | margin-top: 0; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /docs/designer/query-param-field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XGovFormBuilder/digital-form-builder/HEAD/docs/designer/query-param-field.png -------------------------------------------------------------------------------- /e2e/cypress/fixtures/fails-ocr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XGovFormBuilder/digital-form-builder/HEAD/e2e/cypress/fixtures/fails-ocr.png -------------------------------------------------------------------------------- /runner/test/cases/server/dummy.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XGovFormBuilder/digital-form-builder/HEAD/runner/test/cases/server/dummy.pdf -------------------------------------------------------------------------------- /designer/client/data/component/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./addComponent"; 2 | export * from "./updateComponent"; 3 | export * from "./inputs"; 4 | -------------------------------------------------------------------------------- /runner/bin/build-css: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | node-sass --output-style=compressed \ 4 | --output=public/build/stylesheets \ 5 | src/client/sass 6 | -------------------------------------------------------------------------------- /runner/config/development.json: -------------------------------------------------------------------------------- 1 | { 2 | "isTest": true, 3 | "previewMode": true, 4 | "enforceCsrf": false, 5 | "env": "development" 6 | } 7 | -------------------------------------------------------------------------------- /submitter/src/submission/services/index.ts: -------------------------------------------------------------------------------- 1 | export { QueueService } from "./queueService"; 2 | export { WebhookService } from "./webhookService"; 3 | -------------------------------------------------------------------------------- /runner/.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log 2 | src/server/public/build 3 | report.html 4 | report.json 5 | unit-test.html 6 | .env 7 | /dist/ 8 | /public/build/ 9 | -------------------------------------------------------------------------------- /runner/config/production.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": "production", 3 | "logPrettyPrint": false, 4 | "enforceCsrf": true, 5 | "previewMode": false 6 | } 7 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/models/index.ts: -------------------------------------------------------------------------------- 1 | export { FormModel } from "./FormModel"; 2 | export { SummaryViewModel } from "./SummaryViewModel"; 3 | -------------------------------------------------------------------------------- /designer/server/views/split.html: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /runner/src/server/plugins/engine/views/components/html.html: -------------------------------------------------------------------------------- 1 | {% macro Html(component) %} 2 | {{ component.model.content | safe }} 3 | {% endmacro %} 4 | -------------------------------------------------------------------------------- /runner/src/server/routes/index.ts: -------------------------------------------------------------------------------- 1 | export { default as publicRoutes } from "./public"; 2 | export { default as healthCheckRoute } from "./health-check"; 3 | -------------------------------------------------------------------------------- /runner/src/server/services/upload/index.ts: -------------------------------------------------------------------------------- 1 | export { UploadService } from "./uploadService"; 2 | export { MockUploadService } from "./mockUploadService"; 3 | -------------------------------------------------------------------------------- /designer/jest-server-setup.js: -------------------------------------------------------------------------------- 1 | import "@testing-library/jest-dom"; 2 | 3 | beforeEach(() => { 4 | jest.resetAllMocks(); 5 | expect.hasAssertions(); 6 | }); 7 | -------------------------------------------------------------------------------- /runner/public/static/upload-dialog.js: -------------------------------------------------------------------------------- 1 | $("input[type='file']").on('change', function () { 2 | $(this).parent().parent().find('.upload-dialog').show(); 3 | }) 4 | -------------------------------------------------------------------------------- /designer/client/components/FormDetails/FormDetails.scss: -------------------------------------------------------------------------------- 1 | .form-details__feedback { 2 | & .govuk-radios__label { 3 | text-transform: capitalize; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /queue-model/migrations/20231107195736_add_allow_retry/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE `Submission` ADD COLUMN `allow_retry` BOOLEAN NOT NULL DEFAULT true; 3 | -------------------------------------------------------------------------------- /queue-model/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "mysql" -------------------------------------------------------------------------------- /runner/src/server/plugins/pulse.ts: -------------------------------------------------------------------------------- 1 | import pulse from "hapi-pulse"; 2 | 3 | export default { 4 | plugin: pulse, 5 | options: { 6 | timeout: 800, 7 | }, 8 | }; 9 | -------------------------------------------------------------------------------- /runner/bin/run/check/index.js: -------------------------------------------------------------------------------- 1 | const { check } = require("./check"); 2 | //NOTE:- the directory looks like this because of how sinon handles stubbing.. apologies. 3 | check(); 4 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/common/i_reload.js: -------------------------------------------------------------------------------- 1 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | When("I reload", () => { 4 | cy.reload(); 5 | }); -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/views/components/para.html: -------------------------------------------------------------------------------- 1 | {% macro Para(component) %} 2 |{{ component.model.content | safe }}
3 | {% endmacro %} 4 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/views/partials/conditional-components.html: -------------------------------------------------------------------------------- 1 | {% from "./components.html" import componentList with context %} 2 | 3 | {{ componentList(components) }} 4 | -------------------------------------------------------------------------------- /designer/client/data/condition/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./removeCondition"; 2 | export * from "./updateCondition"; 3 | export * from "./addCondition"; 4 | export * from "./hasConditions"; 5 | -------------------------------------------------------------------------------- /model/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export { ComponentTypes } from "./component-types"; 2 | export { ConditionalComponentTypes } from "./conditional-component-types"; 3 | export * from "./types"; 4 | -------------------------------------------------------------------------------- /runner/bin/run/check/util.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = { 4 | FORM_PATH: path.join(process.cwd(), "src", "server", "forms"), 5 | CURRENT_SCHEMA_VERSION: 2, 6 | }; 7 | -------------------------------------------------------------------------------- /e2e/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: gitter 4 | url: https://gitter.im/XGovFormBuilder/Public 5 | about: Please ask and answer questions here 6 | -------------------------------------------------------------------------------- /designer/client/data/page/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./allPathsLeadingTo"; 2 | export * from "./addLink"; 3 | export * from "./updateLink"; 4 | export * from "./findPage"; 5 | export * from "./updateLinksTo"; 6 | -------------------------------------------------------------------------------- /queue-model/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as path from "path"; 2 | 3 | export { PrismaClient, Prisma, Submission } from "@prisma/client"; 4 | export const SCHEMA_LOCATION = path.resolve(__dirname, "schema.prisma"); 5 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/views/components/datefield.html: -------------------------------------------------------------------------------- 1 | {% from "./textfield.html" import TextField %} 2 | 3 | {% macro DateField(component) %} 4 | {{ TextField(component) }} 5 | {% endmacro %} 6 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/views/components/numberfield.html: -------------------------------------------------------------------------------- 1 | {% from "./textfield.html" import TextField %} 2 | 3 | {% macro NumberField(component) %} 4 | {{ TextField(component) }} 5 | {% endmacro %} 6 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/views/components/timefield.html: -------------------------------------------------------------------------------- 1 | {% from "./textfield.html" import TextField %} 2 | 3 | {% macro TimeField(component) %} 4 | {{ TextField(component) }} 5 | {% endmacro %} 6 | -------------------------------------------------------------------------------- /designer/client/context/FlyoutContext.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | export const FlyoutContext = createContext({ 4 | count: 0, 5 | increment: () => {}, 6 | decrement: () => {}, 7 | }); 8 | -------------------------------------------------------------------------------- /runner/src/server/config.ts: -------------------------------------------------------------------------------- 1 | import { buildConfig } from "./utils/configSchema"; 2 | import { default as nodeConfig } from "config"; 3 | 4 | const config = buildConfig(nodeConfig); 5 | 6 | export default config; 7 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/views/components/datetimefield.html: -------------------------------------------------------------------------------- 1 | {% from "./textfield.html" import TextField %} 2 | 3 | {% macro DateTimeField(component) %} 4 | {{ TextField(component) }} 5 | {% endmacro %} 6 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/views/components/textfield.html: -------------------------------------------------------------------------------- 1 | {% from "input/macro.njk" import govukInput %} 2 | 3 | {% macro TextField(component) %} 4 | {{ govukInput(component.model) }} 5 | {% endmacro %} 6 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/views/components/websitefield.html: -------------------------------------------------------------------------------- 1 | {% from "input/macro.njk" import govukInput %} 2 | 3 | {% macro WebsiteField(component) %} 4 | {{ govukInput(component.model) }} 5 | {% endmacro %} -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/views/components/yesnofield.html: -------------------------------------------------------------------------------- 1 | {% from "./radiosfield.html" import RadiosField %} 2 | 3 | {% macro YesNoField(component) %} 4 | {{ RadiosField(component) }} 5 | {% endmacro %} 6 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | reviewers: 9 | - jenbutongit 10 | -------------------------------------------------------------------------------- /designer/client/data/condition/hasConditions.ts: -------------------------------------------------------------------------------- 1 | import { FormDefinition } from "@xgovformbuilder/model"; 2 | 3 | export function hasConditions(conditions: any[]): boolean { 4 | return conditions.length > 0; 5 | } 6 | -------------------------------------------------------------------------------- /designer/client/pages/LandingPage/index.ts: -------------------------------------------------------------------------------- 1 | export { default as NewConfig } from "./NewConfig"; 2 | export { default as LandingChoice } from "./Choice"; 3 | export { default as ChooseExisting } from "./ChooseExisting"; 4 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/common/i_go_back.js: -------------------------------------------------------------------------------- 1 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | When("I go back", () => { 4 | cy.findByRole("link", { name: "Back" }).click(); 5 | }); 6 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/feedback/index.ts: -------------------------------------------------------------------------------- 1 | export { RelativeUrl } from "./RelativeUrl"; 2 | export { FeedbackContextInfo } from "./FeedbackContextInfo"; 3 | export { decodeFeedbackContextInfo } from "./helpers"; 4 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/views/components/radiosfield.html: -------------------------------------------------------------------------------- 1 | {% from "radios/macro.njk" import govukRadios %} 2 | 3 | {% macro RadiosField(component) %} 4 | {{ govukRadios(component.model) }} 5 | {% endmacro %} 6 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/views/components/emailaddressfield.html: -------------------------------------------------------------------------------- 1 | {% from "./textfield.html" import TextField %} 2 | 3 | {% macro EmailAddressField(component) %} 4 | {{ TextField(component) }} 5 | {% endmacro %} 6 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/views/components/selectfield.html: -------------------------------------------------------------------------------- 1 | {% from "select/macro.njk" import govukSelect %} 2 | 3 | {% macro SelectField(component) %} 4 | {{ govukSelect(component.model) }} 5 | {% endmacro %} 6 | 7 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore 2 | node_modules 3 | **/node_modules/* 4 | test-coverage 5 | test-results 6 | dist 7 | npm-debug.log 8 | runner/performance 9 | public 10 | .yarn 11 | 12 | # Ignore all HTML files: 13 | *.html 14 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/common/i_choose_string.js: -------------------------------------------------------------------------------- 1 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | When("I choose {string}", (string) => { 4 | cy.findByLabelText(string).check(); 5 | }); 6 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/common/i_continue.js: -------------------------------------------------------------------------------- 1 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | When("I continue", () => { 4 | cy.findByRole("button", { name: /continue/i }).click(); 5 | }); 6 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/common/i_enter_string.js: -------------------------------------------------------------------------------- 1 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | When("I enter {string}", (string) => { 4 | cy.findByRole("textbox").type(string); 5 | }); 6 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/common/i_wait.js: -------------------------------------------------------------------------------- 1 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | When("I wait {int} milliseconds", (milliseconds) => { 4 | cy.wait(Number(milliseconds)); 5 | }); 6 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/views/components/telephonenumberfield.html: -------------------------------------------------------------------------------- 1 | {% from "./textfield.html" import TextField %} 2 | 3 | {% macro TelephoneNumberField(component) %} 4 | {{ TextField(component) }} 5 | {% endmacro %} 6 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .circleci 2 | .idea 3 | */node_modules 4 | .env 5 | .gitignore 6 | */Dockerfile 7 | */README.md 8 | **/node_modules 9 | **/dist 10 | .yarn/build-state.yml 11 | .yarn/install-state.gz 12 | *.jest.* 13 | jest 14 | -------------------------------------------------------------------------------- /model/src/data-model/index.ts: -------------------------------------------------------------------------------- 1 | export { InputWrapper } from "./input-wrapper"; 2 | export { ConditionsWrapper, ConditionRawData } from "./conditions-wrapper"; 3 | export { Page, Item, Section, List, ConfirmationPage } from "./types"; 4 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/pluginHandlers/files/prehandlers/index.ts: -------------------------------------------------------------------------------- 1 | export { getFiles } from "./getFiles"; 2 | export { validateContentTypes } from "./validateContentTypes"; 3 | export { handleUpload } from "./handleUpload"; 4 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/runner/i_am_redirected_to_string.js: -------------------------------------------------------------------------------- 1 | import { Then } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | Then("I am redirected to {string}", (url) => { 4 | cy.url().should("contain", url); 5 | }); 6 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/views/components/checkboxesfield.html: -------------------------------------------------------------------------------- 1 | {% from "checkboxes/macro.njk" import govukCheckboxes %} 2 | 3 | {% macro CheckboxesField(component) %} 4 | {{ govukCheckboxes(component.model) }} 5 | {% endmacro %} 6 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/views/components/datepartsfield.html: -------------------------------------------------------------------------------- 1 | {% from "date-input/macro.njk" import govukDateInput %} 2 | 3 | {% macro DatePartsField(component) %} 4 | {{ govukDateInput(component.model) }} 5 | {% endmacro %} 6 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/views/components/monthyearfield.html: -------------------------------------------------------------------------------- 1 | {% from "date-input/macro.njk" import govukDateInput %} 2 | 3 | {% macro MonthYearField(component) %} 4 | {{ govukDateInput(component.model) }} 5 | {% endmacro %} 6 | -------------------------------------------------------------------------------- /designer/bin/symlink-config: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ENV_LOC=${1} 4 | LINK_TO=${2:-./.env} 5 | 6 | if [ -z "$ENV_LOC" ] 7 | then 8 | echo Where is .env? 9 | read -r ENV_LOC 10 | fi 11 | 12 | ln -s $ENV_LOC $LINK_TO 13 | -------------------------------------------------------------------------------- /designer/client/i18n/translations/cy.translation.json: -------------------------------------------------------------------------------- 1 | { 2 | "Create component": "Create component", 3 | "Edit page": "Golygu tudalen", 4 | "Persona": "Persona", 5 | "Preview": "Rhagolwg", 6 | "Preview page": "Tudalen rhagolwg" 7 | } 8 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/common/i_click_the_back_link.js: -------------------------------------------------------------------------------- 1 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | When("I click the back link", () => { 4 | cy.findByRole("link", { name: "Back" }).click(); 5 | }); 6 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/common/i_select_the_option_string.js: -------------------------------------------------------------------------------- 1 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | When("I select the option {string}", (string) => { 4 | cy.get("select").select(string); 5 | }); 6 | -------------------------------------------------------------------------------- /runner/bin/symlink-config: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ENV_LOC=${1} 4 | LINK_TO=${2:-./.env} 5 | 6 | if [ -z "$ENV_LOC" ] 7 | then 8 | echo Where is .env? 9 | read -r ENV_LOC 10 | fi 11 | 12 | ln -s $ENV_LOC $LINK_TO 13 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/views/components/datetimepartsfield.html: -------------------------------------------------------------------------------- 1 | {% from "date-input/macro.njk" import govukDateInput %} 2 | 3 | {% macro DateTimePartsField(component) %} 4 | {{ govukDateInput(component.model) }} 5 | {% endmacro %} 6 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/models/submission/index.ts: -------------------------------------------------------------------------------- 1 | export { EmailModel } from "./EmailModel"; 2 | export { FeesModel } from "./FeesModel"; 3 | export { NotifyModel } from "./NotifyModel"; 4 | export { WebhookModel } from "./WebhookModel"; 5 | -------------------------------------------------------------------------------- /submitter/jest.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * For a detailed explanation regarding each configuration property, visit: 3 | * https://jestjs.io/docs/en/configuration.html 4 | */ 5 | 6 | module.exports = { 7 | testMatch: ["**/__tests__/**.test.ts"], 8 | }; 9 | -------------------------------------------------------------------------------- /submitter/src/submission/retention/errors.ts: -------------------------------------------------------------------------------- 1 | export const R_ERRORS = { 2 | CONFIG: `R001 - Could not set retention period`, 3 | DELETION_FAILED: `R002 - Could not delete records`, 4 | RUN_ERROR: `R003 - Could not run, caught exception`, 5 | }; 6 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/common/i_click_the_link_string.js: -------------------------------------------------------------------------------- 1 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | When("I click the link {string}", (string) => { 4 | cy.findByRole("link", { name: string }).click(); 5 | }); 6 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/common/i_see_the_heading_string.js: -------------------------------------------------------------------------------- 1 | import { Then } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | Then("I see the heading {string}", (string) => { 4 | cy.findByRole("heading", { name: string }); 5 | }); 6 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/common/i_submit_the_form.js: -------------------------------------------------------------------------------- 1 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | When("I submit the form", () => { 4 | cy.findByRole("button", { name: /submit/i, exact: false }).click(); 5 | }); 6 | -------------------------------------------------------------------------------- /runner/src/server/utils/generateCookiePassword.ts: -------------------------------------------------------------------------------- 1 | const generateCookiePassword = (): String => 2 | Array(32) 3 | .fill(0) 4 | .map(() => Math.random().toString(36).charAt(2)) 5 | .join(""); 6 | 7 | export default generateCookiePassword; 8 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/common/i_see_the_path_is_string.js: -------------------------------------------------------------------------------- 1 | import { Then } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | Then("I see the path is {string}", (string) => { 4 | cy.location("pathname").should("contain", string); 5 | }); 6 | -------------------------------------------------------------------------------- /queue-model/migrations/20231108100812_webhook_url_required/migration.sql: -------------------------------------------------------------------------------- 1 | -- UpdateColumn 2 | UPDATE `Submission` SET `webhook_url`='' WHERE `webhook_url` IS NULL; 3 | 4 | -- AlterTable 5 | ALTER TABLE `Submission` MODIFY `webhook_url` VARCHAR(191) NOT NULL; 6 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/views/components/insettext.html: -------------------------------------------------------------------------------- 1 | {% from "inset-text/macro.njk" import govukInsetText %} 2 | 3 | {% macro InsetText(component) %} 4 | {{ govukInsetText({ 5 | html: component.model.content 6 | }) }} 7 | {% endmacro %} 8 | -------------------------------------------------------------------------------- /designer/server/plugins/routes/index.ts: -------------------------------------------------------------------------------- 1 | import * as newConfig from "./newConfig"; 2 | import * as api from "./api"; 3 | import * as app from "./app"; 4 | import { healthCheckRoute } from "./healthCheck"; 5 | 6 | export { newConfig, api, app, healthCheckRoute }; 7 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/common/i_dont_see_the_page_string.js: -------------------------------------------------------------------------------- 1 | import { Then } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | Then("I don't see the page {string}", (pageTitle) => { 4 | cy.findByText(pageTitle).should("not.exist"); 5 | }); 6 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/common/i_select_string_for_string.js: -------------------------------------------------------------------------------- 1 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | When("I select {string} for {string}", (option, label) => { 4 | cy.findByLabelText(label).select(option); 5 | }); 6 | -------------------------------------------------------------------------------- /runner/src/client/sass/_upload-dialog.scss: -------------------------------------------------------------------------------- 1 | @import "./../../../node_modules/govuk-frontend/dist/govuk/helpers/colour"; 2 | 3 | .upload-dialog { 4 | display: none; 5 | } 6 | 7 | .govuk-border-green { 8 | border-color: govuk-colour("green"); 9 | } 10 | -------------------------------------------------------------------------------- /designer/client/pages/ErrorPages/ErrorPage.scss: -------------------------------------------------------------------------------- 1 | .error-summary { 2 | .back-link { 3 | margin-bottom: 40px; 4 | } 5 | } 6 | 7 | 8 | @media only screen and (min-height: 800px) { 9 | .error-summary { 10 | padding-bottom: 200px; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/designer/i_am_viewing_the_designer.js: -------------------------------------------------------------------------------- 1 | import { Given } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | Given("I am viewing the designer at {string}", (path) => { 4 | cy.visit(`${Cypress.env("DESIGNER_URL")}${path}`); 5 | }); 6 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/views/components/details.html: -------------------------------------------------------------------------------- 1 | {% from "details/macro.njk" import govukDetails %} 2 | 3 | {% macro Details(component) %} 4 | {# {{ getContext(component) | dump | safe }} #} 5 | {{ govukDetails(component.model)}} 6 | {% endmacro %} 7 | 8 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/common/i_have_read_the_disclaimer.js: -------------------------------------------------------------------------------- 1 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | When("I have read the disclaimer", () => { 4 | cy.findByRole("checkbox").click(); 5 | cy.findByRole("button").click(); 6 | }); 7 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/designer/i_navigate_away_from_the_designer.js: -------------------------------------------------------------------------------- 1 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | When("I navigate away from the designer workspace", () => { 4 | cy.window().invoke("history").invoke("back"); 5 | }); 6 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/runner/i_am_viewing_the_runner_at_string.js: -------------------------------------------------------------------------------- 1 | import { Given } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | Given("I am viewing the runner at {string}", (path = "/") => { 4 | cy.visit(`${Cypress.env.RUNNER_URL}${path}`); 5 | }); 6 | -------------------------------------------------------------------------------- /runner/src/index.ts: -------------------------------------------------------------------------------- 1 | import createServer from "./server"; 2 | 3 | createServer({}) 4 | .then((server) => server.start()) 5 | .then(() => process.send && process.send("online")) 6 | .catch((err) => { 7 | console.error(err); 8 | process.exit(1); 9 | }); 10 | -------------------------------------------------------------------------------- /designer/client/FeatureToggle.tsx: -------------------------------------------------------------------------------- 1 | import { useFeatures } from "./hooks/featureToggling"; 2 | 3 | const FeatureToggle = ({ feature, children }) => { 4 | const features = useFeatures(); 5 | return features[feature] ? children : null; 6 | }; 7 | 8 | export default FeatureToggle; 9 | -------------------------------------------------------------------------------- /designer/client/components/Icons/index.ts: -------------------------------------------------------------------------------- 1 | export { ChevronRightIcon } from "./ChevronRightIcon"; 2 | export { EditIcon } from "./EditIcon"; 3 | export { MoveDownIcon } from "./MoveDownIcon"; 4 | export { MoveUpIcon } from "./MoveUpIcon"; 5 | export { SearchIcon } from "./SearchIcon"; 6 | -------------------------------------------------------------------------------- /e2e/cypress/e2e/runner/files.js: -------------------------------------------------------------------------------- 1 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | When("I upload the file {string}", (filename) => { 4 | cy.get("input[type=file]").attachFile(filename); 5 | cy.findByRole("button", { name: /continue/i }).click(); 6 | }); 7 | -------------------------------------------------------------------------------- /queue-model/migrations/20230915145048_add_defaults/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE `Submission` MODIFY `created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), 3 | MODIFY `updated_at` DATETIME(3) NULL, 4 | MODIFY `complete` BOOLEAN NOT NULL DEFAULT false; 5 | -------------------------------------------------------------------------------- /e2e/cypress/e2e/runner/backLinkFallback.js: -------------------------------------------------------------------------------- 1 | import { When, Then } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | Then("The back link href is {string}", (href) => { 4 | cy.findByRole("link", { name: "Back" }) 5 | .should("have.attr", "href") 6 | .and("eq", href); 7 | }); 8 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/designer/i_delete_the_page.js: -------------------------------------------------------------------------------- 1 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | When("I delete the page", () => { 4 | cy.findByRole("button", { name: "Delete" }).click(); 5 | // cy.on("window:confirm", () => true); 6 | }); 7 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/runner/i_navigate_to_string.js: -------------------------------------------------------------------------------- 1 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | When("I navigate to {string}", (url) => { 4 | cy.visit(`${Cypress.env("RUNNER_URL")}${url}`, { 5 | failOnStatusCode: false, 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /designer/server/index.ts: -------------------------------------------------------------------------------- 1 | import { createServer } from "./createServer"; 2 | 3 | createServer() 4 | .then((server) => server.start()) 5 | .then(() => process.send && process.send("online")) 6 | .catch((err) => { 7 | console.error(err); 8 | process.exit(1); 9 | }); 10 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/common/i_dont_see_string.js: -------------------------------------------------------------------------------- 1 | import { Then } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | Then("I don't see {string}", (string) => { 4 | cy.findByText(string, { ignore: ".autocomplete-wrapper option" }).should( 5 | "not.exist" 6 | ); 7 | }); 8 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/common/i_enter_string_for_string.js: -------------------------------------------------------------------------------- 1 | import { nanoid } from "nanoid"; 2 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 3 | 4 | When("I enter {string} for {string}", (answer, label) => { 5 | cy.findByLabelText(label).type(answer); 6 | }); 7 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/common/i_expand_string_to_see_string.js: -------------------------------------------------------------------------------- 1 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | When("I expand {string} to see {string}", (title, content) => { 4 | cy.get(".govuk-details__summary").click(); 5 | cy.findByText(content); 6 | }); 7 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | RelativeUrl, 3 | FeedbackContextInfo, 4 | decodeFeedbackContextInfo, 5 | } from "./feedback"; 6 | export { redirectTo, redirectUrl, nonRelativeRedirectUrl } from "./helpers"; 7 | export { configureEnginePlugin } from "./configureEnginePlugin"; 8 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/models/SummaryViewModel.detailsTransformationMap.ts: -------------------------------------------------------------------------------- 1 | import { SummaryDetailsTransformationMap } from "server/transforms/summaryDetails"; 2 | 3 | export const summaryDetailsTransformationMap: SummaryDetailsTransformationMap = require("../../../transforms/summaryDetails"); 4 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/common/i_select.js: -------------------------------------------------------------------------------- 1 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | When("I select", (table) => { 4 | const values = table.raw()[0]; 5 | 6 | values.forEach((value) => { 7 | cy.findByLabelText(value).check(); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /model/src/conditions/helpers.ts: -------------------------------------------------------------------------------- 1 | export function toPresentationString(condition) { 2 | return `${condition.coordinatorString()}${condition.conditionString()}`; 3 | } 4 | 5 | export function toExpression(condition) { 6 | return `${condition.coordinatorString()}${condition.conditionExpression()}`; 7 | } 8 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/common/i_see_string.js: -------------------------------------------------------------------------------- 1 | import { Then } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | Then("I see {string}", (string) => { 4 | cy.findByText(string, { 5 | exact: false, 6 | ignore: ".govuk-visually-hidden,title,.autocomplete-wrapper option", 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /runner/src/server/utils/url.ts: -------------------------------------------------------------------------------- 1 | export function isUrlSecure(matomoUrl: string) { 2 | try { 3 | const { protocol } = new URL(matomoUrl); 4 | 5 | if (protocol === "https:") { 6 | return true; 7 | } 8 | 9 | return false; 10 | } catch (error) { 11 | return false; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/designer/i_see_the_section_title_string_is_displayed_in_the_preview.js: -------------------------------------------------------------------------------- 1 | import { Then } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | Then( 4 | "I see the section title {string} is displayed in the preview", 5 | (string) => { 6 | cy.findByText(string); 7 | } 8 | ); 9 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | 3 | plugins: 4 | - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs 5 | spec: "@yarnpkg/plugin-workspace-tools" 6 | 7 | logFilters: 8 | - code: "YN0013" 9 | level: discard 10 | 11 | yarnPath: .yarn/releases/yarn-3.2.2.cjs 12 | 13 | nmSelfReferences: false 14 | -------------------------------------------------------------------------------- /designer/server/plugins/logging.ts: -------------------------------------------------------------------------------- 1 | import config from "../config"; 2 | import pino from "hapi-pino"; 3 | 4 | export default { 5 | plugin: pino, 6 | options: { 7 | prettyPrint: config.isDev, 8 | level: config.logLevel, 9 | logEvents: ["onPostStart", "onPostStop", "request-error"], 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/common/i_choose_string_for_string.js: -------------------------------------------------------------------------------- 1 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | When("I choose {string} for {string}", (option, label) => { 4 | cy.findByRole("group", { name: label }).within(() => { 5 | cy.findByLabelText(option).click(); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/designer/i_am_on_the_new_configuration_page.js: -------------------------------------------------------------------------------- 1 | import { Given } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | Given("I am on the new configuration page", () => { 4 | cy.visit(`${Cypress.env("DESIGNER_URL")}/app/new`); 5 | cy.findByText("Enter a name for your form"); 6 | }); 7 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/runner/i_navigate_to_the_string_form.js: -------------------------------------------------------------------------------- 1 | import { Given, When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | Given("I navigate to the {string} form", (formName) => { 4 | cy.visit(`${Cypress.env("RUNNER_URL")}/${formName}`, { 5 | failOnStatusCode: false, 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/views/partials/components.html: -------------------------------------------------------------------------------- 1 | {% macro componentList(components) %} 2 | {% for component in components %} 3 | {% import "../components/" + component.type.toLowerCase() + ".html" as view with context %} 4 | {{ view[component.type](component) }} 5 | {% endfor %} 6 | {% endmacro %} 7 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/designer/i_change_the_page_path_to_string.js: -------------------------------------------------------------------------------- 1 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | When("I change the page path to {string}", (string) => { 4 | cy.findByLabelText("Path").clear().type(string); 5 | cy.findByRole("button", { name: "Save" }).click(); 6 | }); 7 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/designer/i_will_see_an_alert_warning_me_that_string.js: -------------------------------------------------------------------------------- 1 | import { Then } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | Then("I will see an alert warning me that {string}", (string) => { 4 | cy.on("window:confirm", (text) => { 5 | expect(text).to.contain(string); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/runner/i_upload_a_file_that_string.js: -------------------------------------------------------------------------------- 1 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | When("I upload a file that {string}", (result) => { 4 | cy.get("input[type=file]").attachFile(`${result}.png`); 5 | cy.findByRole("button", { name: /continue/i }).click(); 6 | }); 7 | -------------------------------------------------------------------------------- /e2e/cypress/support/step_definitions/designer/i_change_the_page_title_to_string.js: -------------------------------------------------------------------------------- 1 | import { When } from "@badeball/cypress-cucumber-preprocessor"; 2 | 3 | When("I change the page title to {string}", (string) => { 4 | cy.findByLabelText("Page title").clear().type(string); 5 | cy.findByRole("button", { name: "Save" }).click(); 6 | }); 7 | -------------------------------------------------------------------------------- /runner/src/server/plugins/engine/views/partials/heading.html: -------------------------------------------------------------------------------- 1 | {% if sectionTitle and (sectionTitle !== pageTitle) %} 2 |This content is based on answer 1
", 5 | "listItems": "This content is based on answer 2
", 9 | "listItems": "last downloaded at {downloadedAt}
11 |last updated at {updatedAt}
12 |Contact your closest consulate.
10 |Contact your closest consulate.
19 | 20 |You previously uploaded the file ‘{{component.model.value}}’
6 | {% endif %} 7 |9 | Your file was successfully selected 10 |
11 |14 | We have reset your application because you did not do anything for {{ sessionTimeout / 60000 }} minutes. We did this 15 | to keep your information secure. 16 |
17 | Start application again 18 |