From 49c1da372b887ecd74fa0438d7c5cff4acccd7f8 Mon Sep 17 00:00:00 2001 From: zachary Date: Wed, 27 May 2026 09:10:47 +0100 Subject: [PATCH 01/16] add: baseURL option for dynamic http question --- .../db_patches/0209_addBaseulrtodynamiccs.sql | 16 +++ .../db_seeds/0005_ProposalQuestions.sql | 4 +- apps/backend/src/config/updateOIDCSettings.ts | 5 + .../datasources/mockups/TemplateDataSource.ts | 17 +++ apps/backend/src/models/Settings.ts | 1 + .../questionTypes/DynamicMultipleChoice.ts | 1 + .../src/queries/TemplateQueries.spec.ts | 29 ++++ apps/backend/src/queries/TemplateQueries.ts | 13 +- .../src/resolvers/types/FieldConfig.ts | 3 + .../QuestionDynamicMultipleChoiceForm.tsx | 125 +++++++++++++++-- ...plateRelationDynamicMultipleChoiceForm.tsx | 132 ++++++++++++++++-- .../template/fragment.fieldConfig.graphql | 1 + 12 files changed, 316 insertions(+), 31 deletions(-) create mode 100644 apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql diff --git a/apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql b/apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql new file mode 100644 index 0000000000..b8d6b71115 --- /dev/null +++ b/apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql @@ -0,0 +1,16 @@ +DO +$$ +BEGIN + IF register_patch('addBaseulrtodynamiccs.sql', 'Zachary Hankin', 'dfkljafkld', '2026-5-21') THEN + UPDATE duo.public.questions + SET default_config = jsonb_set( + default_config::jsonb, + '{useBaseDomain}', + 'false'::jsonb, + true + ) + WHERE data_type = 'DYNAMIC_MULTIPLE_CHOICE'; + END IF; +END; +$$ +LANGUAGE plpgsql; diff --git a/apps/backend/db_patches/db_seeds/0005_ProposalQuestions.sql b/apps/backend/db_patches/db_seeds/0005_ProposalQuestions.sql index ac01b60896..e7d0313c39 100644 --- a/apps/backend/db_patches/db_seeds/0005_ProposalQuestions.sql +++ b/apps/backend/db_patches/db_seeds/0005_ProposalQuestions.sql @@ -376,7 +376,7 @@ VALUES ( 'dynamic_multiple_choice_question', 'DYNAMIC_MULTIPLE_CHOICE', 'Dynamic multiple choice question from seeds', - '{"variant":"dropdown", "url":"", "jsonPath":"","isMultipleSelect":true, "apiCallRequestHeaders":[], "readPermissions":[]}', + '{"variant":"dropdown", "url":"", "jsonPath":"","isMultipleSelect":true, "apiCallRequestHeaders":[], "readPermissions":[], "useBaseDomain":"false",}', '2023-02-08 10:23:10.285415+00', '2023-02-08 10:23:10.285415+00', 'dynamic_multiple_choice_question', @@ -389,7 +389,7 @@ INSERT INTO templates_has_questions( VALUES ( 'dynamic_multiple_choice_question', - proposal_template_id_var, proposal_topic_id_var, 10, '{"variant":"dropdown", "url":"", "jsonPath":"","isMultipleSelect":true, "apiCallRequestHeaders":[],"readPermissions":[]}' + proposal_template_id_var, proposal_topic_id_var, 10, '{"useBaseDomain":"false", "variant":"dropdown", "url":"", "jsonPath":"","isMultipleSelect":true, "apiCallRequestHeaders":[],"readPermissions":[]}' ); INSERT INTO answers( questionary_id, question_id, answer diff --git a/apps/backend/src/config/updateOIDCSettings.ts b/apps/backend/src/config/updateOIDCSettings.ts index 9ba272f745..7392d45391 100644 --- a/apps/backend/src/config/updateOIDCSettings.ts +++ b/apps/backend/src/config/updateOIDCSettings.ts @@ -23,4 +23,9 @@ export async function updateOIDCSettings() { settingsId: SettingsId.EXTERNAL_AUTH_LOGOUT_URL, settingsValue: logoutUrl, }); + + await db.updateSettings({ + settingsId: SettingsId.BASE_URL, + settingsValue: process.env.BASE_URL, + }); } diff --git a/apps/backend/src/datasources/mockups/TemplateDataSource.ts b/apps/backend/src/datasources/mockups/TemplateDataSource.ts index c65f132d48..025ff05186 100644 --- a/apps/backend/src/datasources/mockups/TemplateDataSource.ts +++ b/apps/backend/src/datasources/mockups/TemplateDataSource.ts @@ -126,6 +126,20 @@ const dummyTemplateStepsFactory = () => { config: { url: '', jsonPath: '', + useBaseDomain: false, + } as DynamicMultipleChoiceConfig, + }), + }); + + const dmcQuestionWithBaseDomain = dummyQuestionTemplateRelationFactory({ + question: dummyQuestionFactory({ + id: 'dmcQuestionWithBaseDomain', + naturalKey: 'dmcQuestionWithBaseDomain', + dataType: DataType.DYNAMIC_MULTIPLE_CHOICE, + config: { + url: 'getListOfCountries', + useBaseDomain: true, + jsonPath: '', } as DynamicMultipleChoiceConfig, }), }); @@ -138,6 +152,7 @@ const dummyTemplateStepsFactory = () => { config: { url: 'api-url', jsonPath: '', + useBaseDomain: false, apiCallRequestHeaders: [ { name: 'header1', @@ -160,6 +175,7 @@ const dummyTemplateStepsFactory = () => { config: { url: 'api-url', jsonPath: '$..option', + useBaseDomain: false, } as DynamicMultipleChoiceConfig, }), }); @@ -175,6 +191,7 @@ const dummyTemplateStepsFactory = () => { dmcQuestionEmptyUrl, dmcQuestionEmptyJsonPath, dmcQuestionWithUrlAndJsonPath, + dmcQuestionWithBaseDomain, ]), ]; }; diff --git a/apps/backend/src/models/Settings.ts b/apps/backend/src/models/Settings.ts index 36f79caa11..6ad7708520 100644 --- a/apps/backend/src/models/Settings.ts +++ b/apps/backend/src/models/Settings.ts @@ -45,4 +45,5 @@ export enum SettingsId { ORGANISATION_NAME = 'ORGANISATION_NAME', INVITE_VALIDITY_PERIOD_DAYS = 'INVITE_VALIDITY_PERIOD_DAYS', INVITE_REMINDERS_SEND_DELAY_DAYS = 'INVITE_REMINDERS_SEND_DELAY_DAYS', + BASE_URL = 'BASE_URL', } diff --git a/apps/backend/src/models/questionTypes/DynamicMultipleChoice.ts b/apps/backend/src/models/questionTypes/DynamicMultipleChoice.ts index 4d4ed3d602..f51d72f950 100644 --- a/apps/backend/src/models/questionTypes/DynamicMultipleChoice.ts +++ b/apps/backend/src/models/questionTypes/DynamicMultipleChoice.ts @@ -29,6 +29,7 @@ export const dynamicMultipleChoiceDefinition: Question { expect(options).toEqual(['option1', 'option2']); }); + + it('Should return options if selected useBaseDomain', async () => { + process.env = { + ...process.env, + BASE_URL: 'mocked.example.com', + }; + + jest + .spyOn(global, 'fetch') + .mockImplementation((input: RequestInfo | URL) => { + const url = typeof input === 'string' ? input : input.toString(); + + if (url === 'http://mocked.example.com/getListOfCountries') { + return Promise.resolve({ + json: () => Promise.resolve(['option1', 'option2']), + ok: true, + } as Response); + } else { + return Promise.reject(new Error('Unknown URL')); + } + }); + + const options = await templateQueries.getDynamicMultipleChoiceOptions( + dummyUserWithRole, + 'dmcQuestionWithBaseDomain' + ); + + expect(options).toEqual(['option1', 'option2']); + }); }); diff --git a/apps/backend/src/queries/TemplateQueries.ts b/apps/backend/src/queries/TemplateQueries.ts index a3cd77b33b..80139d77ea 100644 --- a/apps/backend/src/queries/TemplateQueries.ts +++ b/apps/backend/src/queries/TemplateQueries.ts @@ -100,10 +100,11 @@ export default class TemplateQueries { if (!question) return []; const config = question.config as DynamicMultipleChoiceConfig; - if (config.url === '') return []; + const dynamicURL = constructDynamicURL(config.url, config.useBaseDomain); + if (dynamicURL === '') return []; try { - const response = await fetch(config.url, { + const response = await fetch(dynamicURL, { headers: config.apiCallRequestHeaders?.reduce( (acc, header) => ({ ...acc, @@ -140,3 +141,11 @@ export default class TemplateQueries { return []; } } + +function constructDynamicURL(url: string, useBaseURL: boolean): string { + if (useBaseURL) { + return `http://${process.env.BASE_URL}/${url}`; + } + + return url; +} diff --git a/apps/backend/src/resolvers/types/FieldConfig.ts b/apps/backend/src/resolvers/types/FieldConfig.ts index 044b609d38..dd845a0bbe 100644 --- a/apps/backend/src/resolvers/types/FieldConfig.ts +++ b/apps/backend/src/resolvers/types/FieldConfig.ts @@ -156,6 +156,9 @@ export class DynamicMultipleChoiceConfig extends ConfigBase { @Field(() => String) jsonPath: string; + @Field(() => Boolean) + useBaseDomain: boolean; + @Field(() => Boolean) isMultipleSelect: boolean; diff --git a/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx b/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx index a453e0c2ee..d478067085 100644 --- a/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx +++ b/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx @@ -21,7 +21,7 @@ import InputLabel from '@mui/material/InputLabel'; import { SelectChangeEvent } from '@mui/material/Select'; import { styled } from '@mui/material/styles'; import { Field } from 'formik'; -import React, { useState } from 'react'; +import React, { useState, useContext } from 'react'; import * as Yup from 'yup'; import CheckboxWithLabel from 'components/common/FormikUICheckboxWithLabel'; @@ -30,7 +30,9 @@ import Select from 'components/common/FormikUISelect'; import TextField from 'components/common/FormikUITextField'; import TitledContainer from 'components/common/TitledContainer'; import { QuestionFormProps } from 'components/questionary/QuestionaryComponentRegistry'; +import { SettingsContext } from 'context/SettingsContextProvider'; import { + SettingsId, ApiCallRequestHeader, DynamicMultipleChoiceConfig, } from 'generated/sdk'; @@ -83,6 +85,14 @@ const jsonPathFieldsDocRows = [ }, ]; +const pathNameValidationSchema = Yup.string() + .matches( + /^(?!http|www)/i, + 'Provide a valid pathname, the base domain is already provided' + ) + .matches(/^(?!\/).+$/, 'Leading slash should not be included') + .required('Pathname is required'); + const CustomizedTableCell = styled(TableCell)(({ theme }) => ({ [`&.${tableCellClasses.head}`]: { background: theme.palette.common.black, @@ -110,6 +120,9 @@ export const QuestionDynamicMultipleChoiceForm = (props: QuestionFormProps) => { const urlValidation = urlValidationSchema(); const [showIsMultipleSelectCheckbox, setShowIsMultipleSelectCheckbox] = useState(config.variant === 'dropdown'); + const [useBaseDomain, setUseBaseDomain] = useState( + config.useBaseDomain ?? false + ); const availableVariantOptions = [ { label: 'Radio', value: 'radio' }, @@ -119,6 +132,11 @@ export const QuestionDynamicMultipleChoiceForm = (props: QuestionFormProps) => { const [isJsonPathFieldDocPopupOpen, setIsJsonPathFieldDocPopupOpen] = useState(false); + const [isBaseURLCheckBoxPopupOpen, setIsBaseURLCheckBoxPopupOpen] = + useState(false); + + const { settingsMap } = useContext(SettingsContext); + return ( { config: Yup.object({ required: Yup.bool(), variant: Yup.string().required('Variant is required'), - url: urlValidation, + url: Yup.string().when('useBaseDomain', (useBaseDomain, schema) => + useBaseDomain + ? schema.concat(pathNameValidationSchema) + : schema.concat(urlValidation) + ), + useBaseDomain: Yup.bool(), jsonPath: Yup.string(), apiRequestHeaders: Yup.array(), }), })} > - {() => ( + {({ setFieldValue }) => ( <> { Link - - - - +
+ {useBaseDomain && ( + + {`http://${settingsMap.get(SettingsId.BASE_URL)?.settingsValue}/`} + + )} + + +
+
+ ) => { + const checked = e.target.checked; + setUseBaseDomain(checked); + setFieldValue('config.useBaseDomain', checked); + }} + /> + + setIsBaseURLCheckBoxPopupOpen(true)} + > + + + setIsBaseURLCheckBoxPopupOpen(false)} + aria-labelledby="customized-dialog-title" + > + +
+ Instead of providing a full URL to retrieve a list for + your question, this option allows you to use the current + server's domain and specify only the relative path. +
+
+ This is particularly useful for GraphQL queries that + access the UOS database. Please note that while the + domain displayed in the UI reflects the current + deployment, it is not stored. At runtime, the system + will automatically resolve and apply the current servers + domain. +
+
+ + + +
+
+
+
+ + JsonPath { const config = props.questionRel.config as DynamicMultipleChoiceConfig; const [showIsMultipleSelectCheckbox, setShowIsMultipleSelectCheckbox] = useState(config.variant === 'dropdown'); + const [useBaseDomain, setUseBaseDomain] = useState( + config.useBaseDomain ?? false + ); + const [isBaseURLCheckBoxPopupOpen, setIsBaseURLCheckBoxPopupOpen] = + useState(false); const availableVariantOptions = [ { label: 'Radio', value: 'radio' }, @@ -38,6 +62,7 @@ export const QuestionTemplateRelationDynamicMultipleChoiceForm = ( ]; const urlValidation = urlValidationSchema(); + const { settingsMap } = useContext(SettingsContext); return ( + useBaseDomain + ? schema.concat(pathNameValidationSchema) + : schema.concat(urlValidation) + ), }), })} > - {() => ( + {({ setFieldValue }) => ( <> @@ -103,17 +132,94 @@ export const QuestionTemplateRelationDynamicMultipleChoiceForm = ( Link - + +
+ {useBaseDomain && ( + + {`http://${settingsMap.get(SettingsId.BASE_URL)?.settingsValue}/`} + + )} + + +
+ +
+ ) => { + const checked = e.target.checked; + setUseBaseDomain(checked); + setFieldValue('config.useBaseDomain', checked); + }} + /> + + setIsBaseURLCheckBoxPopupOpen(true)} + > + + + setIsBaseURLCheckBoxPopupOpen(false)} + aria-labelledby="customized-dialog-title" + > + +
+ Instead of providing a full URL to retrieve a list for + your question, this option allows you to use the current + server's domain and specify only the relative path. +
+
+ This is particularly useful for GraphQL queries that + access the UOS database. Please note that while the + domain displayed in the UI reflects the current + deployment, it is not stored. At runtime, the system + will automatically resolve and apply the current servers + domain. +
+
+ + + +
+
+
- - + + + JsonPath Date: Wed, 27 May 2026 10:39:49 +0100 Subject: [PATCH 02/16] add better title for covnersion --- apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql b/apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql index b8d6b71115..d0c13ac839 100644 --- a/apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql +++ b/apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql @@ -1,7 +1,7 @@ DO $$ BEGIN - IF register_patch('addBaseulrtodynamiccs.sql', 'Zachary Hankin', 'dfkljafkld', '2026-5-21') THEN + IF register_patch('addBaseulrtodynamiccs.sql', 'Zachary Hankin', 'Adds an option to the dynamic HTTP question type allowing use of base domain', '2026-5-21') THEN UPDATE duo.public.questions SET default_config = jsonb_set( default_config::jsonb, From 3f7ec07c52f0892391a0b8718c9db1c92d4bc3fd Mon Sep 17 00:00:00 2001 From: zachary Date: Mon, 1 Jun 2026 11:32:47 +0100 Subject: [PATCH 03/16] do not change existing rows --- apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql b/apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql index d0c13ac839..2c67fbe0b8 100644 --- a/apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql +++ b/apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql @@ -9,7 +9,8 @@ BEGIN 'false'::jsonb, true ) - WHERE data_type = 'DYNAMIC_MULTIPLE_CHOICE'; + WHERE data_type = 'DYNAMIC_MULTIPLE_CHOICE' + AND NOT (default_config::jsonb ? 'useBaseDomain'); END IF; END; $$ From 0d004051c4d79ac853ed11c645f3177b62739485 Mon Sep 17 00:00:00 2001 From: zachary Date: Tue, 2 Jun 2026 09:14:49 +0100 Subject: [PATCH 04/16] fix syntax --- apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql b/apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql index 2c67fbe0b8..e9541fb21d 100644 --- a/apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql +++ b/apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql @@ -2,7 +2,7 @@ DO $$ BEGIN IF register_patch('addBaseulrtodynamiccs.sql', 'Zachary Hankin', 'Adds an option to the dynamic HTTP question type allowing use of base domain', '2026-5-21') THEN - UPDATE duo.public.questions + UPDATE questions SET default_config = jsonb_set( default_config::jsonb, '{useBaseDomain}', From 3ad04766d25f897cd995c82a406df488bfef6c2a Mon Sep 17 00:00:00 2001 From: zachary Date: Thu, 4 Jun 2026 10:23:43 +0100 Subject: [PATCH 05/16] fix syntax error --- apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql b/apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql index e9541fb21d..92d71c1933 100644 --- a/apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql +++ b/apps/backend/db_patches/0209_addBaseulrtodynamiccs.sql @@ -9,8 +9,7 @@ BEGIN 'false'::jsonb, true ) - WHERE data_type = 'DYNAMIC_MULTIPLE_CHOICE' - AND NOT (default_config::jsonb ? 'useBaseDomain'); + WHERE data_type = 'DYNAMIC_MULTIPLE_CHOICE'; END IF; END; $$ From 1afff76f445f7e3b8b069979dda3ec1330845442 Mon Sep 17 00:00:00 2001 From: zachary Date: Thu, 4 Jun 2026 11:19:15 +0100 Subject: [PATCH 06/16] remove UOS --- .../QuestionDynamicMultipleChoiceForm.tsx | 9 ++++----- ...QuestionTemplateRelationDynamicMultipleChoiceForm.tsx | 9 ++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx b/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx index d478067085..068b107f73 100644 --- a/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx +++ b/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx @@ -292,11 +292,10 @@ export const QuestionDynamicMultipleChoiceForm = (props: QuestionFormProps) => {
This is particularly useful for GraphQL queries that - access the UOS database. Please note that while the - domain displayed in the UI reflects the current - deployment, it is not stored. At runtime, the system - will automatically resolve and apply the current servers - domain. + access the database. Please note that while the domain + displayed in the UI reflects the current deployment, it + is not stored. At runtime, the system will automatically + resolve and apply the current servers domain.
diff --git a/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionTemplateRelationDynamicMultipleChoiceForm.tsx b/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionTemplateRelationDynamicMultipleChoiceForm.tsx index 3bd61e4e4e..78b879116d 100644 --- a/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionTemplateRelationDynamicMultipleChoiceForm.tsx +++ b/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionTemplateRelationDynamicMultipleChoiceForm.tsx @@ -194,11 +194,10 @@ export const QuestionTemplateRelationDynamicMultipleChoiceForm = (
This is particularly useful for GraphQL queries that - access the UOS database. Please note that while the - domain displayed in the UI reflects the current - deployment, it is not stored. At runtime, the system - will automatically resolve and apply the current servers - domain. + access the database. Please note that while the domain + displayed in the UI reflects the current deployment, it + is not stored. At runtime, the system will automatically + resolve and apply the current servers domain.
From c3d420b3fcc907ff605444dfbe47e1d9cfe97124 Mon Sep 17 00:00:00 2001 From: zachary Date: Fri, 5 Jun 2026 15:31:00 +0100 Subject: [PATCH 07/16] fix seed --- apps/backend/db_patches/db_seeds/0005_ProposalQuestions.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/backend/db_patches/db_seeds/0005_ProposalQuestions.sql b/apps/backend/db_patches/db_seeds/0005_ProposalQuestions.sql index e7d0313c39..00d33f8448 100644 --- a/apps/backend/db_patches/db_seeds/0005_ProposalQuestions.sql +++ b/apps/backend/db_patches/db_seeds/0005_ProposalQuestions.sql @@ -376,7 +376,7 @@ VALUES ( 'dynamic_multiple_choice_question', 'DYNAMIC_MULTIPLE_CHOICE', 'Dynamic multiple choice question from seeds', - '{"variant":"dropdown", "url":"", "jsonPath":"","isMultipleSelect":true, "apiCallRequestHeaders":[], "readPermissions":[], "useBaseDomain":"false",}', + '{"variant":"dropdown", "url":"", "jsonPath":"","isMultipleSelect":true, "apiCallRequestHeaders":[], "readPermissions":[], "useBaseDomain":false}', '2023-02-08 10:23:10.285415+00', '2023-02-08 10:23:10.285415+00', 'dynamic_multiple_choice_question', @@ -389,7 +389,7 @@ INSERT INTO templates_has_questions( VALUES ( 'dynamic_multiple_choice_question', - proposal_template_id_var, proposal_topic_id_var, 10, '{"useBaseDomain":"false", "variant":"dropdown", "url":"", "jsonPath":"","isMultipleSelect":true, "apiCallRequestHeaders":[],"readPermissions":[]}' + proposal_template_id_var, proposal_topic_id_var, 10, '{"useBaseDomain":false, "variant":"dropdown", "url":"", "jsonPath":"","isMultipleSelect":true, "apiCallRequestHeaders":[],"readPermissions":[]}' ); INSERT INTO answers( questionary_id, question_id, answer From 1c39381b7e9cc1c7fd6ffaf18f9a56150fa2f931 Mon Sep 17 00:00:00 2001 From: zachary Date: Mon, 8 Jun 2026 08:30:02 +0100 Subject: [PATCH 08/16] fix tests --- apps/e2e/cypress/e2e/templateContext.ts | 1 + apps/e2e/cypress/e2e/templatesBasic.cy.ts | 5 +++++ apps/e2e/cypress/types/template.d.ts | 1 + 3 files changed, 7 insertions(+) diff --git a/apps/e2e/cypress/e2e/templateContext.ts b/apps/e2e/cypress/e2e/templateContext.ts index 95f08ec547..2095f43550 100644 --- a/apps/e2e/cypress/e2e/templateContext.ts +++ b/apps/e2e/cypress/e2e/templateContext.ts @@ -66,6 +66,7 @@ const dynamicMultipleChoiceQuestion = { title: faker.lorem.words(2), url: 'http://localhost:9000', jsonPath: '$.*.item', + useBaseDomain: false, answers: { arrayString: [ faker.lorem.words(3), diff --git a/apps/e2e/cypress/e2e/templatesBasic.cy.ts b/apps/e2e/cypress/e2e/templatesBasic.cy.ts index f8e65633ba..ae9c77d252 100644 --- a/apps/e2e/cypress/e2e/templatesBasic.cy.ts +++ b/apps/e2e/cypress/e2e/templatesBasic.cy.ts @@ -323,6 +323,7 @@ context('Template Basic tests', () => { { url: dynamicMultipleChoiceQuestion.url, isMultipleSelect: true, + useBaseDomain: false, } ); @@ -1547,6 +1548,7 @@ context('Template Basic tests', () => { jsonPath: '$.[*].item', isMultipleSelect: true, firstTopic: true, + useBaseDomain: false, } ); @@ -1567,6 +1569,7 @@ context('Template Basic tests', () => { jsonPath: dynamicMultipleChoiceQuestion.jsonPath, isMultipleSelect: true, firstTopic: true, + useBaseDomain: false, } ); createProposalAndClickDropdownBehavior(); @@ -1589,6 +1592,7 @@ context('Template Basic tests', () => { url: dynamicMultipleChoiceQuestion.url, isMultipleSelect: true, firstTopic: true, + useBaseDomain: false, } ); createProposalAndClickDropdownBehavior(); @@ -1614,6 +1618,7 @@ context('Template Basic tests', () => { isMultipleSelect: true, firstTopic: true, headers: { Authorization: 'Bearer 1234', 'Content-Type': 'text/' }, + useBaseDomain: false, } ); diff --git a/apps/e2e/cypress/types/template.d.ts b/apps/e2e/cypress/types/template.d.ts index 5e16ceb86a..88a1966d0b 100644 --- a/apps/e2e/cypress/types/template.d.ts +++ b/apps/e2e/cypress/types/template.d.ts @@ -185,6 +185,7 @@ declare global { options?: { url?: string; jsonPath?: string; + useBaseDomain: boolean; isMultipleSelect?: boolean; type?: 'radio' | 'dropdown'; firstTopic?: boolean; From afd026b4db33926258a0d53c21e2606112f0a700 Mon Sep 17 00:00:00 2001 From: zachary Date: Mon, 8 Jun 2026 10:10:52 +0100 Subject: [PATCH 09/16] use graphQL for be to fe talk --- apps/backend/src/config/updateOIDCSettings.ts | 5 ---- apps/backend/src/models/Settings.ts | 1 - .../resolvers/queries/ServerConfigQuery.ts | 11 +++++++++ .../src/resolvers/types/ServerConfig.ts | 7 ++++++ .../QuestionDynamicMultipleChoiceForm.tsx | 23 ++++++++++++++---- ...plateRelationDynamicMultipleChoiceForm.tsx | 24 +++++++++++++++---- .../src/graphql/admin/getServerConfig.graphql | 5 ++++ 7 files changed, 60 insertions(+), 16 deletions(-) create mode 100644 apps/backend/src/resolvers/queries/ServerConfigQuery.ts create mode 100644 apps/backend/src/resolvers/types/ServerConfig.ts create mode 100644 apps/frontend/src/graphql/admin/getServerConfig.graphql diff --git a/apps/backend/src/config/updateOIDCSettings.ts b/apps/backend/src/config/updateOIDCSettings.ts index 7392d45391..9ba272f745 100644 --- a/apps/backend/src/config/updateOIDCSettings.ts +++ b/apps/backend/src/config/updateOIDCSettings.ts @@ -23,9 +23,4 @@ export async function updateOIDCSettings() { settingsId: SettingsId.EXTERNAL_AUTH_LOGOUT_URL, settingsValue: logoutUrl, }); - - await db.updateSettings({ - settingsId: SettingsId.BASE_URL, - settingsValue: process.env.BASE_URL, - }); } diff --git a/apps/backend/src/models/Settings.ts b/apps/backend/src/models/Settings.ts index 6ad7708520..36f79caa11 100644 --- a/apps/backend/src/models/Settings.ts +++ b/apps/backend/src/models/Settings.ts @@ -45,5 +45,4 @@ export enum SettingsId { ORGANISATION_NAME = 'ORGANISATION_NAME', INVITE_VALIDITY_PERIOD_DAYS = 'INVITE_VALIDITY_PERIOD_DAYS', INVITE_REMINDERS_SEND_DELAY_DAYS = 'INVITE_REMINDERS_SEND_DELAY_DAYS', - BASE_URL = 'BASE_URL', } diff --git a/apps/backend/src/resolvers/queries/ServerConfigQuery.ts b/apps/backend/src/resolvers/queries/ServerConfigQuery.ts new file mode 100644 index 0000000000..8b83ba2fc0 --- /dev/null +++ b/apps/backend/src/resolvers/queries/ServerConfigQuery.ts @@ -0,0 +1,11 @@ +import { Query, Resolver } from 'type-graphql'; + +import { ServerConfig } from '../types/ServerConfig'; + +@Resolver() +export class ServerConfigQuery { + @Query(() => ServerConfig, { nullable: false }) + ServerConfig() { + return { baseURL: process.env.BASE_URL }; + } +} diff --git a/apps/backend/src/resolvers/types/ServerConfig.ts b/apps/backend/src/resolvers/types/ServerConfig.ts new file mode 100644 index 0000000000..2ea09058e9 --- /dev/null +++ b/apps/backend/src/resolvers/types/ServerConfig.ts @@ -0,0 +1,7 @@ +import { ObjectType, Field } from 'type-graphql'; + +@ObjectType() +export class ServerConfig { + @Field(() => String) + public baseURL: string; +} diff --git a/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx b/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx index 068b107f73..262d139533 100644 --- a/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx +++ b/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx @@ -21,7 +21,7 @@ import InputLabel from '@mui/material/InputLabel'; import { SelectChangeEvent } from '@mui/material/Select'; import { styled } from '@mui/material/styles'; import { Field } from 'formik'; -import React, { useState, useContext } from 'react'; +import React, { useState, useEffect } from 'react'; import * as Yup from 'yup'; import CheckboxWithLabel from 'components/common/FormikUICheckboxWithLabel'; @@ -30,12 +30,11 @@ import Select from 'components/common/FormikUISelect'; import TextField from 'components/common/FormikUITextField'; import TitledContainer from 'components/common/TitledContainer'; import { QuestionFormProps } from 'components/questionary/QuestionaryComponentRegistry'; -import { SettingsContext } from 'context/SettingsContextProvider'; import { - SettingsId, ApiCallRequestHeader, DynamicMultipleChoiceConfig, } from 'generated/sdk'; +import { useDataApi } from 'hooks/common/useDataApi'; import { urlValidationSchema } from 'utils/helperFunctions'; import { useNaturalKeySchema } from 'utils/userFieldValidationSchema'; @@ -135,7 +134,21 @@ export const QuestionDynamicMultipleChoiceForm = (props: QuestionFormProps) => { const [isBaseURLCheckBoxPopupOpen, setIsBaseURLCheckBoxPopupOpen] = useState(false); - const { settingsMap } = useContext(SettingsContext); + const api = useDataApi(); + const [serverConfig, setServerConfig] = useState(null); + + useEffect(() => { + const fetchConfig = async () => { + try { + const { ServerConfig } = await api().getServerConfig(); + setServerConfig(ServerConfig.baseURL); + } catch (err) { + console.error('Failed to fetch server config', err); + } + }; + + fetchConfig(); + }, [api]); return ( { paddingTop: '20px', }} > - {`http://${settingsMap.get(SettingsId.BASE_URL)?.settingsValue}/`} + {`http://${serverConfig}/`} )} diff --git a/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionTemplateRelationDynamicMultipleChoiceForm.tsx b/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionTemplateRelationDynamicMultipleChoiceForm.tsx index 78b879116d..bf3eb235fd 100644 --- a/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionTemplateRelationDynamicMultipleChoiceForm.tsx +++ b/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionTemplateRelationDynamicMultipleChoiceForm.tsx @@ -11,7 +11,7 @@ import FormControl from '@mui/material/FormControl'; import InputLabel from '@mui/material/InputLabel'; import { SelectChangeEvent } from '@mui/material/Select'; import { Field } from 'formik'; -import React, { useState, useContext } from 'react'; +import React, { useState, useEffect } from 'react'; import * as Yup from 'yup'; import CheckboxWithLabel from 'components/common/FormikUICheckboxWithLabel'; @@ -20,12 +20,11 @@ import Select from 'components/common/FormikUISelect'; import TextField from 'components/common/FormikUITextField'; import TitledContainer from 'components/common/TitledContainer'; import { QuestionTemplateRelationFormProps } from 'components/questionary/QuestionaryComponentRegistry'; -import { SettingsContext } from 'context/SettingsContextProvider'; import { ApiCallRequestHeader, DynamicMultipleChoiceConfig, - SettingsId, } from 'generated/sdk'; +import { useDataApi } from 'hooks/common/useDataApi'; import { urlValidationSchema } from 'utils/helperFunctions'; import { QuestionExcerpt } from '../QuestionExcerpt'; @@ -62,7 +61,22 @@ export const QuestionTemplateRelationDynamicMultipleChoiceForm = ( ]; const urlValidation = urlValidationSchema(); - const { settingsMap } = useContext(SettingsContext); + + const api = useDataApi(); + const [serverConfig, setServerConfig] = useState(null); + + useEffect(() => { + const fetchConfig = async () => { + try { + const { ServerConfig } = await api().getServerConfig(); + setServerConfig(ServerConfig.baseURL); + } catch (err) { + console.error('Failed to fetch server config', err); + } + }; + + fetchConfig(); + }, [api]); return ( - {`http://${settingsMap.get(SettingsId.BASE_URL)?.settingsValue}/`} + {`http://${serverConfig}/`} )} diff --git a/apps/frontend/src/graphql/admin/getServerConfig.graphql b/apps/frontend/src/graphql/admin/getServerConfig.graphql new file mode 100644 index 0000000000..3ba4de9d1a --- /dev/null +++ b/apps/frontend/src/graphql/admin/getServerConfig.graphql @@ -0,0 +1,5 @@ +query getServerConfig { + ServerConfig { + baseURL + } +} \ No newline at end of file From 681242e570f115874f979eb677472a454977cbdc Mon Sep 17 00:00:00 2001 From: zachary Date: Mon, 8 Jun 2026 16:15:39 +0100 Subject: [PATCH 10/16] fix edge cases --- .../QuestionDynamicMultipleChoiceForm.tsx | 13 ++++++++----- ...ionTemplateRelationDynamicMultipleChoiceForm.tsx | 11 ++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx b/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx index 262d139533..7e7638982d 100644 --- a/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx +++ b/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx @@ -159,11 +159,13 @@ export const QuestionDynamicMultipleChoiceForm = (props: QuestionFormProps) => { config: Yup.object({ required: Yup.bool(), variant: Yup.string().required('Variant is required'), - url: Yup.string().when('useBaseDomain', (useBaseDomain, schema) => - useBaseDomain - ? schema.concat(pathNameValidationSchema) - : schema.concat(urlValidation) - ), + + url: Yup.string().when('useBaseDomain', { + is: true, + then: (schema) => schema.concat(pathNameValidationSchema), + otherwise: (schema) => schema.concat(urlValidation), + }), + useBaseDomain: Yup.bool(), jsonPath: Yup.string(), apiRequestHeaders: Yup.array(), @@ -275,6 +277,7 @@ export const QuestionDynamicMultipleChoiceForm = (props: QuestionFormProps) => { component={CheckboxWithLabel} Label={{ label: 'Use base domain for dynamic URL' }} data-cy="use-base-domain" + checked={useBaseDomain} onChange={(e: React.ChangeEvent) => { const checked = e.target.checked; setUseBaseDomain(checked); diff --git a/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionTemplateRelationDynamicMultipleChoiceForm.tsx b/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionTemplateRelationDynamicMultipleChoiceForm.tsx index bf3eb235fd..6c28998262 100644 --- a/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionTemplateRelationDynamicMultipleChoiceForm.tsx +++ b/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionTemplateRelationDynamicMultipleChoiceForm.tsx @@ -85,11 +85,11 @@ export const QuestionTemplateRelationDynamicMultipleChoiceForm = ( config: Yup.object({ required: Yup.bool(), variant: Yup.string().required('Variant is required'), - url: Yup.string().when('useBaseDomain', (useBaseDomain, schema) => - useBaseDomain - ? schema.concat(pathNameValidationSchema) - : schema.concat(urlValidation) - ), + url: Yup.string().when('useBaseDomain', { + is: true, + then: (schema) => schema.concat(pathNameValidationSchema), + otherwise: (schema) => schema.concat(urlValidation), + }), }), })} > @@ -177,6 +177,7 @@ export const QuestionTemplateRelationDynamicMultipleChoiceForm = ( type="checkbox" component={CheckboxWithLabel} Label={{ label: 'Use base domain for dynamic URL' }} + checked={useBaseDomain} data-cy="use-base-domain" onChange={(e: React.ChangeEvent) => { const checked = e.target.checked; From eb41c3903afb645127081f2ed47ce0267a91b97c Mon Sep 17 00:00:00 2001 From: zachary Date: Tue, 9 Jun 2026 08:29:03 +0100 Subject: [PATCH 11/16] fix: test --- apps/e2e/cypress/fixtures/template_export.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/e2e/cypress/fixtures/template_export.json b/apps/e2e/cypress/fixtures/template_export.json index 51f43d8e65..2a26a88279 100644 --- a/apps/e2e/cypress/fixtures/template_export.json +++ b/apps/e2e/cypress/fixtures/template_export.json @@ -447,6 +447,7 @@ "variant": "dropdown", "url": "", "jsonPath": "", + "useBaseDomain": false, "isMultipleSelect": true, "apiCallRequestHeaders": [], "readPermissions": [] @@ -461,6 +462,7 @@ "variant": "dropdown", "url": "", "jsonPath": "", + "useBaseDomain": false, "isMultipleSelect": true, "apiCallRequestHeaders": [], "readPermissions": [] @@ -771,6 +773,7 @@ "variant": "dropdown", "url": "", "jsonPath": "", + "useBaseDomain": false, "isMultipleSelect": true, "apiCallRequestHeaders": [], "readPermissions": [] @@ -1149,6 +1152,7 @@ "variant": "dropdown", "url": "", "jsonPath": "", + "useBaseDomain": false, "isMultipleSelect": true, "apiCallRequestHeaders": [], "readPermissions": [] @@ -1163,6 +1167,7 @@ "variant": "dropdown", "url": "", "jsonPath": "", + "useBaseDomain": false, "isMultipleSelect": true, "apiCallRequestHeaders": [], "readPermissions": [] @@ -1379,6 +1384,7 @@ "variant": "dropdown", "url": "", "jsonPath": "", + "useBaseDomain": false, "isMultipleSelect": true, "apiCallRequestHeaders": [], "readPermissions": [] From 2c96ed7814798075530524632169311c131e0334 Mon Sep 17 00:00:00 2001 From: zachary Date: Mon, 29 Jun 2026 13:37:55 +0100 Subject: [PATCH 12/16] remove http from name --- apps/backend/src/queries/TemplateQueries.ts | 2 +- .../DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx | 2 +- .../QuestionTemplateRelationDynamicMultipleChoiceForm.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/backend/src/queries/TemplateQueries.ts b/apps/backend/src/queries/TemplateQueries.ts index 80139d77ea..96a98edb93 100644 --- a/apps/backend/src/queries/TemplateQueries.ts +++ b/apps/backend/src/queries/TemplateQueries.ts @@ -144,7 +144,7 @@ export default class TemplateQueries { function constructDynamicURL(url: string, useBaseURL: boolean): string { if (useBaseURL) { - return `http://${process.env.BASE_URL}/${url}`; + return `${process.env.BASE_URL}/${url}`; } return url; diff --git a/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx b/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx index 7e7638982d..25d6ff7978 100644 --- a/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx +++ b/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx @@ -256,7 +256,7 @@ export const QuestionDynamicMultipleChoiceForm = (props: QuestionFormProps) => { paddingTop: '20px', }} > - {`http://${serverConfig}/`} + {`${serverConfig}/`} )} diff --git a/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionTemplateRelationDynamicMultipleChoiceForm.tsx b/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionTemplateRelationDynamicMultipleChoiceForm.tsx index 6c28998262..d96434f2a5 100644 --- a/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionTemplateRelationDynamicMultipleChoiceForm.tsx +++ b/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionTemplateRelationDynamicMultipleChoiceForm.tsx @@ -156,7 +156,7 @@ export const QuestionTemplateRelationDynamicMultipleChoiceForm = ( paddingTop: '20px', }} > - {`http://${serverConfig}/`} + {`${serverConfig}/`} )} From 221bd42075dffd00a499483224504aceaa67340a Mon Sep 17 00:00:00 2001 From: zachary Date: Mon, 29 Jun 2026 13:57:01 +0100 Subject: [PATCH 13/16] update variable examples --- apps/backend/example.development.env | 2 +- docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/backend/example.development.env b/apps/backend/example.development.env index dde1b439b0..60b944e96f 100644 --- a/apps/backend/example.development.env +++ b/apps/backend/example.development.env @@ -44,7 +44,7 @@ NODE_ENV=development # DEPENDENCY_CONFIG= PING_PUBLIC_CRT=dummypingsecret DATABASE_URL=postgres://duouser:duopassword@127.0.0.1:5432/duo -BASE_URL=localhost:3000 +BASE_URL=http://localhost:3000 JWT_TOKEN_LIFE=7d JWT_SECRET=qMyLZALzs229ybdQXNyzYRdju7X784TH # SPARKPOST_TOKEN=insertokenhere diff --git a/docker-compose.yml b/docker-compose.yml index 9d91c6c72d..bb09972f57 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -62,7 +62,7 @@ services: DATABASE_URL: postgres://duouser:duopassword@db:5432/duo JWT_SECRET: qMyLZALzs229ybdQXNyzYRdju7X784TH JWT_TOKEN_LIFE: 7d - BASE_URL: localhost:33000 + BASE_URL: http://localhost:33000 NODE_ENV: development USER_OFFICE_FACTORY_ENDPOINT: http://factory:4500/generate AUTH_DISCOVERY_URL: http://host.docker.internal:5001/.well-known/openid-configuration From 3e827be7394546ab33b076f05360630f4f58ecb5 Mon Sep 17 00:00:00 2001 From: zachary Date: Thu, 2 Jul 2026 09:37:41 +0100 Subject: [PATCH 14/16] fix: tests/default --- apps/backend/src/queries/TemplateQueries.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/backend/src/queries/TemplateQueries.spec.ts b/apps/backend/src/queries/TemplateQueries.spec.ts index dbc6f4e641..59dab835ea 100644 --- a/apps/backend/src/queries/TemplateQueries.spec.ts +++ b/apps/backend/src/queries/TemplateQueries.spec.ts @@ -156,7 +156,7 @@ describe('getDynamicMultipleChoiceOptions', () => { it('Should return options if selected useBaseDomain', async () => { process.env = { ...process.env, - BASE_URL: 'mocked.example.com', + BASE_URL: 'http://mocked.example.com', }; jest From 203724ca8a38addf28931262825483d2df3229c2 Mon Sep 17 00:00:00 2001 From: zachary Date: Thu, 2 Jul 2026 11:35:03 +0100 Subject: [PATCH 15/16] fix merge conflict --- apps/backend/src/queries/TemplateQueries.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/backend/src/queries/TemplateQueries.spec.ts b/apps/backend/src/queries/TemplateQueries.spec.ts index 4a312c9ff2..a1fcf1d355 100644 --- a/apps/backend/src/queries/TemplateQueries.spec.ts +++ b/apps/backend/src/queries/TemplateQueries.spec.ts @@ -180,6 +180,7 @@ describe('getDynamicMultipleChoiceOptions', () => { ); expect(options).toEqual(['option1', 'option2']); + }); it('should use the question template relation if a template ID is supplied', async () => { const templateDataSource = container.resolve( Tokens.TemplateDataSource From 379601b461adab5f0860647ee5b95da73f7a9753 Mon Sep 17 00:00:00 2001 From: zachary Date: Mon, 6 Jul 2026 10:20:55 +0100 Subject: [PATCH 16/16] simplify regex --- .../DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx | 2 +- .../QuestionTemplateRelationDynamicMultipleChoiceForm.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx b/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx index 25d6ff7978..68222bb28b 100644 --- a/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx +++ b/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionDynamicMultipleChoiceForm.tsx @@ -89,7 +89,7 @@ const pathNameValidationSchema = Yup.string() /^(?!http|www)/i, 'Provide a valid pathname, the base domain is already provided' ) - .matches(/^(?!\/).+$/, 'Leading slash should not be included') + .matches(/^(?!\/)/, 'Leading slash should not be included') .required('Pathname is required'); const CustomizedTableCell = styled(TableCell)(({ theme }) => ({ diff --git a/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionTemplateRelationDynamicMultipleChoiceForm.tsx b/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionTemplateRelationDynamicMultipleChoiceForm.tsx index d96434f2a5..2405dc1ce3 100644 --- a/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionTemplateRelationDynamicMultipleChoiceForm.tsx +++ b/apps/frontend/src/components/questionary/questionaryComponents/DynamicMultipleChoice/QuestionTemplateRelationDynamicMultipleChoiceForm.tsx @@ -40,7 +40,7 @@ const pathNameValidationSchema = Yup.string() /^(?!http|www)/i, 'Provide a valid pathname, the base domain is already provided' ) - .matches(/^(?!\/).+$/, 'Leading slash should not be included') + .matches(/^(?!\/)/, 'Leading slash should not be included') .required('Pathname is required'); export const QuestionTemplateRelationDynamicMultipleChoiceForm = (