From 309fad86059449e20ced5b22c40e5ae86ed4a4e6 Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Tue, 7 May 2024 18:39:31 +0100 Subject: [PATCH 1/8] - Prefix option added for website compnent - Replaced URI validation with domain validation because URI validation needs user to input https://, since we are adding a prefix so we do not need URI validation but domain validaiton e.g. www.gov.uk --- designer/client/ComponentTypeEdit.tsx | 2 + .../__tests__/website-field-edit.jest.tsx | 32 +++++++++++ .../FieldEditors/website-field-edit.tsx | 56 +++++++++++++++++++ .../i18n/translations/en.translation.json | 6 ++ model/src/components/types.ts | 1 + .../plugins/engine/components/WebsiteField.ts | 14 ++++- .../server/views/partials/summary-row.html | 2 +- .../engine/components/WebsiteField.test.ts | 13 +++++ 8 files changed, 122 insertions(+), 4 deletions(-) create mode 100644 designer/client/components/FieldEditors/__tests__/website-field-edit.jest.tsx create mode 100644 designer/client/components/FieldEditors/website-field-edit.tsx diff --git a/designer/client/ComponentTypeEdit.tsx b/designer/client/ComponentTypeEdit.tsx index 7c36d3ec02..82a2d81257 100644 --- a/designer/client/ComponentTypeEdit.tsx +++ b/designer/client/ComponentTypeEdit.tsx @@ -9,6 +9,7 @@ import { MultilineTextFieldEdit } from "./multiline-text-field-edit"; import { FreeTextFieldEdit } from "./free-text-field-edit"; import { FileUploadFieldEdit } from "./file-upload-field-edit"; import { NumberFieldEdit } from "./components/FieldEditors/number-field-edit"; +import { WebsiteFieldEdit } from "./components/FieldEditors/website-field-edit"; import { DateFieldEdit } from "./components/FieldEditors/date-field-edit"; import { ParaEdit } from "./components/FieldEditors/para-edit"; import DetailsEdit from "./components/FieldEditors/details-edit"; @@ -22,6 +23,7 @@ const componentTypeEditors = { FreeTextField: FreeTextFieldEdit, ClientSideFileUploadField: ClientSideFileUploadFieldEdit, NumberField: NumberFieldEdit, + WebsiteField: WebsiteFieldEdit, AutocompleteField: ListFieldEdit, SelectField: SelectFieldEdit, RadiosField: ListFieldEdit, diff --git a/designer/client/components/FieldEditors/__tests__/website-field-edit.jest.tsx b/designer/client/components/FieldEditors/__tests__/website-field-edit.jest.tsx new file mode 100644 index 0000000000..0194763cd1 --- /dev/null +++ b/designer/client/components/FieldEditors/__tests__/website-field-edit.jest.tsx @@ -0,0 +1,32 @@ +import React from "react"; +import { render } from "@testing-library/react"; +import { WebsiteFieldEdit } from "../website-field-edit"; +import { RenderWithContext } from "../../../__tests__/helpers/renderers"; + +describe("Website field edit", () => { + describe("Website field edit fields", () => { + let stateProps; + let textFieldEditPage; + + beforeEach(() => { + stateProps = { + component: { + type: "websiteFieldEdit", + name: "websiteFieldEditClass", + options: {}, + }, + }; + + textFieldEditPage = render( + + + + ); + }); + + test("should display prefix help text ", () => { + const text = "Specifies the prefix of the field."; + expect(textFieldEditPage.getByText(text)).toBeInTheDocument(); + }); + }); +}); diff --git a/designer/client/components/FieldEditors/website-field-edit.tsx b/designer/client/components/FieldEditors/website-field-edit.tsx new file mode 100644 index 0000000000..2f825b9d70 --- /dev/null +++ b/designer/client/components/FieldEditors/website-field-edit.tsx @@ -0,0 +1,56 @@ +import React, { useContext } from "react"; +import { ComponentContext } from "../../reducers/component/componentReducer"; +import { Actions } from "../../reducers/component/types"; + +import { CssClasses } from "../CssClasses"; +import { i18n } from "../../i18n"; + +type Props = { + context: any; // TODO +}; + +export function WebsiteFieldEdit({ context = ComponentContext }: Props) { + // If you are editing a component, the default context will be ComponentContext because props.context is undefined, + // but if you editing a component which is a children of a list based component, then the props.context is the ListContext. + const { state, dispatch } = useContext(context); + const { selectedComponent } = state; + const { options = {} } = selectedComponent; + + return ( +
+ + + {i18n("common.detailsLink.title")} + + + +
+ + + {i18n("websiteFieldEditComponent.prefixField.helpText")} + + + dispatch({ + type: Actions.EDIT_OPTIONS_PREFIX, + payload: e.target.value, + }) + } + /> +
+ + +
+ ); +} diff --git a/designer/client/i18n/translations/en.translation.json b/designer/client/i18n/translations/en.translation.json index 7d651f0189..4cd458b5b3 100644 --- a/designer/client/i18n/translations/en.translation.json +++ b/designer/client/i18n/translations/en.translation.json @@ -435,5 +435,11 @@ "downloadCrashReport": "download your crash report", "createIssue": "create an issue on GitHub", "createIssueHint": "with details of what you were doing when this error occurred, and your crash report as an attachment" + }, + "websiteFieldEditComponent": { + "prefixField": { + "helpText": "Specifies the prefix of the field.", + "title": "Prefix" + } } } diff --git a/model/src/components/types.ts b/model/src/components/types.ts index 58a5fcc91a..1e17de055d 100644 --- a/model/src/components/types.ts +++ b/model/src/components/types.ts @@ -87,6 +87,7 @@ interface TextFieldBase { allow?: string; autocomplete?: string; noReturnUrlOnSummaryPage?: boolean; + prefix?: string; }; schema: { max?: number; diff --git a/runner/src/server/plugins/engine/components/WebsiteField.ts b/runner/src/server/plugins/engine/components/WebsiteField.ts index 27834784ed..a29f9ec82e 100644 --- a/runner/src/server/plugins/engine/components/WebsiteField.ts +++ b/runner/src/server/plugins/engine/components/WebsiteField.ts @@ -7,7 +7,7 @@ import { FormData, FormSubmissionErrors } from "../types"; export class WebsiteField extends TextField { private defaultMessage = - "Enter website address in the correct format, starting with 'https://'"; + "Enter website address in the correct format, e.g. 'www.gov.uk'"; formSchema: StringSchema; options: WebsiteFieldComponent["options"]; @@ -31,7 +31,7 @@ export class WebsiteField extends TextField { this.formSchema = this.formSchema .label(def.title) - .uri() + .domain() .message(def.options?.customValidationMessage ?? this.defaultMessage); if (schema.max) { @@ -59,8 +59,16 @@ export class WebsiteField extends TextField { getViewModel(formData: FormData, errors: FormSubmissionErrors) { const options: any = this.options; + const { prefix } = options; + const viewModelPrefix = { prefix: { text: prefix } }; const schema: any = this.schema; - const viewModel = super.getViewModel(formData, errors); + const viewModel = { + ...super.getViewModel(formData, errors), + type: "website", + // ...False returns nothing, so only adds content when + // the given options are present. + ...(options.prefix && viewModelPrefix), + }; if (options.hideTitle) { viewModel.label = { text: "", html: viewModel.hint?.html!, classes: "" }; diff --git a/runner/src/server/views/partials/summary-row.html b/runner/src/server/views/partials/summary-row.html index 958d0d123c..634eed3ce8 100644 --- a/runner/src/server/views/partials/summary-row.html +++ b/runner/src/server/views/partials/summary-row.html @@ -9,7 +9,7 @@ {% for itemValue in item.value%} {{itemValue}}
{% endfor %} - {% elif item.type == 'NumberField' %} + {% elif item.type == 'NumberField' or item.type == 'WebsiteField' %} {{item.prefix}}{{item.value}} {% elif item.type == 'ClientSideFileUploadField' %} {% if item.value.files|length == 0 %} diff --git a/runner/test/cases/server/plugins/engine/components/WebsiteField.test.ts b/runner/test/cases/server/plugins/engine/components/WebsiteField.test.ts index 358bac4f20..4e7f1137c9 100644 --- a/runner/test/cases/server/plugins/engine/components/WebsiteField.test.ts +++ b/runner/test/cases/server/plugins/engine/components/WebsiteField.test.ts @@ -153,3 +153,16 @@ suite("Website field", () => { expect(formSchema.validate(null).error).to.be.undefined(); }); }); + +test("Prefix are passed to view model", () => { + const def = { + ...baseDef, + options: { prefix: "@£%" }, + }; + const websiteFieldPrefix = new WebsiteField(def); + const { schema } = websiteFieldPrefix; + + expect(websiteFieldPrefix.getViewModel({})).to.contain({ + prefix: { text: "@£%" }, + }); +}); From 15d8b0c0b53cce785733a631d8f2e42af8e1b4b9 Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Tue, 7 May 2024 18:52:39 +0100 Subject: [PATCH 2/8] - version bumped --- version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version b/version index 8c34c02f57..44fb316be7 100644 --- a/version +++ b/version @@ -1 +1 @@ -VERSION=0.1.262 +VERSION=0.1.263 From 282d68039d4bd0ddc6fba9c796d634bac9116540 Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Tue, 7 May 2024 19:40:53 +0100 Subject: [PATCH 3/8] - Failing tests fixed --- .../plugins/engine/components/WebsiteField.test.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/runner/test/cases/server/plugins/engine/components/WebsiteField.test.ts b/runner/test/cases/server/plugins/engine/components/WebsiteField.test.ts index 4e7f1137c9..f42acca2ef 100644 --- a/runner/test/cases/server/plugins/engine/components/WebsiteField.test.ts +++ b/runner/test/cases/server/plugins/engine/components/WebsiteField.test.ts @@ -43,7 +43,7 @@ suite("Website field", () => { const { formSchema } = new WebsiteField(def, model); - expect(formSchema.validate("https://www.gov.uk").error).to.be.undefined(); + expect(formSchema.validate("www.gov.uk").error).to.be.undefined(); expect( formSchema.validate("http://www.gov.uk/test?id=ABC").error ).to.be.undefined(); @@ -66,7 +66,7 @@ suite("Website field", () => { const { formSchema } = new WebsiteField(def, model); - expect(formSchema.validate("www.gov.uk").error?.message).to.contain( + expect(formSchema.validate("gov").error?.message).to.contain( "Invalid address entered" ); }); @@ -85,7 +85,7 @@ suite("Website field", () => { const { formSchema } = new WebsiteField(def, model); - expect(formSchema.validate("http://www.gov.uk").error).to.be.undefined(); + expect(formSchema.validate("uk").error).to.be.undefined(); expect(formSchema.validate("https://www.gov.uk").error?.message).to.contain( `"My component" length must be less than or equal to 17 characters long` @@ -106,7 +106,7 @@ suite("Website field", () => { const { formSchema } = new WebsiteField(def, model); - expect(formSchema.validate("https://www.gov.uk").error).to.be.undefined(); + expect(formSchema.validate("www.gov.uk").error).to.be.undefined(); expect(formSchema.validate("http://www.gov.uk").error?.message).to.contain( `"My component" length must be at least 18 characters long` @@ -156,7 +156,10 @@ suite("Website field", () => { test("Prefix are passed to view model", () => { const def = { - ...baseDef, + name: "myComponent", + title: "My component", + schema: {}, + type: "WebsiteField", options: { prefix: "@£%" }, }; const websiteFieldPrefix = new WebsiteField(def); From 7dbac2ac1b20c47189ebe3598f18086b1f91beee Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Tue, 7 May 2024 20:06:08 +0100 Subject: [PATCH 4/8] - Test fix --- .../plugins/engine/components/WebsiteField.test.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/runner/test/cases/server/plugins/engine/components/WebsiteField.test.ts b/runner/test/cases/server/plugins/engine/components/WebsiteField.test.ts index f42acca2ef..8061b86222 100644 --- a/runner/test/cases/server/plugins/engine/components/WebsiteField.test.ts +++ b/runner/test/cases/server/plugins/engine/components/WebsiteField.test.ts @@ -43,9 +43,9 @@ suite("Website field", () => { const { formSchema } = new WebsiteField(def, model); - expect(formSchema.validate("www.gov.uk").error).to.be.undefined(); + expect(formSchema.validate("https://www.gov.uk").error).to.be.undefined(); expect( - formSchema.validate("http://www.gov.uk/test?id=ABC").error + formSchema.validate("www.gov.uk/test?id=ABC").error ).to.be.undefined(); expect(formSchema.validate("1").error!.message).to.contain( `Enter website address in the correct format` @@ -85,7 +85,7 @@ suite("Website field", () => { const { formSchema } = new WebsiteField(def, model); - expect(formSchema.validate("uk").error).to.be.undefined(); + expect(formSchema.validate("www.gov.uk").error).to.be.undefined(); expect(formSchema.validate("https://www.gov.uk").error?.message).to.contain( `"My component" length must be less than or equal to 17 characters long` @@ -106,7 +106,9 @@ suite("Website field", () => { const { formSchema } = new WebsiteField(def, model); - expect(formSchema.validate("www.gov.uk").error).to.be.undefined(); + expect( + formSchema.validate("www.legislation.gov.uk").error + ).to.be.undefined(); expect(formSchema.validate("http://www.gov.uk").error?.message).to.contain( `"My component" length must be at least 18 characters long` From a361f6411e07dde488f3cee76d55a0fe8ca693ce Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Tue, 7 May 2024 20:14:03 +0100 Subject: [PATCH 5/8] - Tests fix --- .../server/plugins/engine/components/WebsiteField.test.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/runner/test/cases/server/plugins/engine/components/WebsiteField.test.ts b/runner/test/cases/server/plugins/engine/components/WebsiteField.test.ts index 8061b86222..720c780703 100644 --- a/runner/test/cases/server/plugins/engine/components/WebsiteField.test.ts +++ b/runner/test/cases/server/plugins/engine/components/WebsiteField.test.ts @@ -43,7 +43,7 @@ suite("Website field", () => { const { formSchema } = new WebsiteField(def, model); - expect(formSchema.validate("https://www.gov.uk").error).to.be.undefined(); + expect(formSchema.validate("www.gov.uk").error).to.be.undefined(); expect( formSchema.validate("www.gov.uk/test?id=ABC").error ).to.be.undefined(); @@ -87,7 +87,9 @@ suite("Website field", () => { expect(formSchema.validate("www.gov.uk").error).to.be.undefined(); - expect(formSchema.validate("https://www.gov.uk").error?.message).to.contain( + expect( + formSchema.validate("www.legislation.gov.uk").error?.message + ).to.contain( `"My component" length must be less than or equal to 17 characters long` ); }); @@ -110,7 +112,7 @@ suite("Website field", () => { formSchema.validate("www.legislation.gov.uk").error ).to.be.undefined(); - expect(formSchema.validate("http://www.gov.uk").error?.message).to.contain( + expect(formSchema.validate("www.gov.uk").error?.message).to.contain( `"My component" length must be at least 18 characters long` ); }); From ac5aa691d9466cf01b78a5a32198486c7442f7b1 Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Wed, 8 May 2024 03:12:04 +0100 Subject: [PATCH 6/8] - Test fix - Validation from URI to Pattern --- runner/src/server/plugins/engine/components/WebsiteField.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/runner/src/server/plugins/engine/components/WebsiteField.ts b/runner/src/server/plugins/engine/components/WebsiteField.ts index a29f9ec82e..588fbae38f 100644 --- a/runner/src/server/plugins/engine/components/WebsiteField.ts +++ b/runner/src/server/plugins/engine/components/WebsiteField.ts @@ -4,6 +4,7 @@ import { FormModel } from "../models"; import { TextField } from "./TextField"; import { addClassOptionIfNone } from "./helpers"; import { FormData, FormSubmissionErrors } from "../types"; +import { tr } from "date-fns/locale"; export class WebsiteField extends TextField { private defaultMessage = @@ -31,7 +32,9 @@ export class WebsiteField extends TextField { this.formSchema = this.formSchema .label(def.title) - .domain() + .pattern( + /^(www\.)?[a-zA-Z0-9]{2,}(\.[a-zA-Z0-9]{2,})(\.[a-zA-Z0-9]{2,})?/ + ) .message(def.options?.customValidationMessage ?? this.defaultMessage); if (schema.max) { From 2a7c62adca815cdf932fcf5ae4d2428e44c7244f Mon Sep 17 00:00:00 2001 From: Nuwan Samarassinghe Date: Wed, 8 May 2024 08:40:41 +0100 Subject: [PATCH 7/8] FS-4380 fix vacant property title (#523) merging since got approval --- .../form_jsons/hsra_r1/vacant-property-details-hsra.json | 5 +++-- version | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/fsd_config/form_jsons/hsra_r1/vacant-property-details-hsra.json b/fsd_config/form_jsons/hsra_r1/vacant-property-details-hsra.json index 9a4e277a56..142ab6f42a 100644 --- a/fsd_config/form_jsons/hsra_r1/vacant-property-details-hsra.json +++ b/fsd_config/form_jsons/hsra_r1/vacant-property-details-hsra.json @@ -110,11 +110,12 @@ "acceptedFiles": "image/jpeg,image/png,application/pdf,text/plain,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.oasis.opendocument.text,text/csv,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.oasis.opendocument.spreadsheet" }, "showNoScriptWarning": false, - "minimumRequiredFiles": 1 + "minimumRequiredFiles": 1, + "hideTitle": true }, "type": "ClientSideFileUploadField", "title": "Upload the initial notice you served the landlord", - "hint": "Tell us about all attempts to make contact, even if they were unsuccessful" + "hint": "Upload a file" } ], "next": [ diff --git a/version b/version index 8c34c02f57..44fb316be7 100644 --- a/version +++ b/version @@ -1 +1 @@ -VERSION=0.1.262 +VERSION=0.1.263 From 55a13e27fbbd3eb6b30fa4d1b1bbeb63bd06fc33 Mon Sep 17 00:00:00 2001 From: Nuwan Samarassinghe Date: Wed, 8 May 2024 09:21:17 +0100 Subject: [PATCH 8/8] fix prefix of the number field (#526) merging since got approval --- fsd_config/form_jsons/hsra_r1/total-expected-cost-hsra.json | 4 +++- version | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/fsd_config/form_jsons/hsra_r1/total-expected-cost-hsra.json b/fsd_config/form_jsons/hsra_r1/total-expected-cost-hsra.json index 351e4d4511..6ade4916a4 100644 --- a/fsd_config/form_jsons/hsra_r1/total-expected-cost-hsra.json +++ b/fsd_config/form_jsons/hsra_r1/total-expected-cost-hsra.json @@ -26,7 +26,9 @@ { "name": "lfXuaP", "options": { - "hideTitle": true + "hideTitle": true, + "prefix": "£", + "classes": "govuk-!-width-one-quarter" }, "type": "NumberField", "hint": "This includes any costs you expect to recover from the tenant or through matched funding", diff --git a/version b/version index 44fb316be7..57adeb975f 100644 --- a/version +++ b/version @@ -1 +1 @@ -VERSION=0.1.263 +VERSION=0.1.264