diff --git a/src/constants/dictionary.ts b/src/constants/dictionary.ts index 83c77bf8f..d15bbcc5c 100644 --- a/src/constants/dictionary.ts +++ b/src/constants/dictionary.ts @@ -515,6 +515,10 @@ const dictionary: Dictionary = { fr: 'Retrouver dans le questionnaire', en: 'Retrieve in the questionnaire', }, + allowArbitraryResponse: { + fr: 'Autoriser une réponse libre', + en: 'Allow an arbitrary response', + }, list: { fr: 'Liste', en: 'List', diff --git a/src/model/formToState/component-new-edit/collected-variable.jsx b/src/model/formToState/component-new-edit/collected-variable.jsx index abaa4b46f..aafbd92d5 100644 --- a/src/model/formToState/component-new-edit/collected-variable.jsx +++ b/src/model/formToState/component-new-edit/collected-variable.jsx @@ -47,6 +47,7 @@ export function formToState(form) { y, z, mesureLevel, + arbitraryVariableOfVariableId, codeListReference, codeListReferenceLabel, isCollected, @@ -61,6 +62,7 @@ export function formToState(form) { x, y, z, + arbitraryVariableOfVariableId, isCollected, alternativeLabel, mesureLevel, @@ -94,6 +96,7 @@ export function storeToForm(currentStore) { x, y, z, + arbitraryVariableOfVariableId, isCollected = '1', alternativeLabel, mesureLevel, @@ -107,6 +110,7 @@ export function storeToForm(currentStore) { x, y, z, + arbitraryVariableOfVariableId, isCollected, alternativeLabel, mesureLevel, diff --git a/src/model/formToState/component-new-edit/response-format-single.jsx b/src/model/formToState/component-new-edit/response-format-single.jsx index 08436f739..7cf3acb61 100644 --- a/src/model/formToState/component-new-edit/response-format-single.jsx +++ b/src/model/formToState/component-new-edit/response-format-single.jsx @@ -10,12 +10,14 @@ import { const { RADIO } = DATATYPE_VIS_HINT; export const defaultState = { + allowArbitraryResponse: false, mandatory: false, visHint: RADIO, // [DEFAULT_CODES_LIST_SELECTOR_PATH]: cloneDeep(CodesListDefaultState), }; export const defaultForm = { + allowArbitraryResponse: false, mandatory: false, visHint: RADIO, // [DEFAULT_CODES_LIST_SELECTOR_PATH]: cloneDeep(CodesListDefaultForm), @@ -24,6 +26,7 @@ export const defaultForm = { export function formToState(form, transformers) { const { id, + allowArbitraryResponse, mandatory, visHint, [DEFAULT_CODES_LIST_SELECTOR_PATH]: codesListForm, @@ -31,6 +34,7 @@ export function formToState(form, transformers) { return { id, + allowArbitraryResponse, mandatory, visHint, [DEFAULT_CODES_LIST_SELECTOR_PATH]: @@ -39,10 +43,11 @@ export function formToState(form, transformers) { } export function stateToForm(currentState, transformers) { - const { id, visHint, mandatory } = currentState; + const { id, allowArbitraryResponse, visHint, mandatory } = currentState; return { id, + allowArbitraryResponse, mandatory, visHint, [DEFAULT_CODES_LIST_SELECTOR_PATH]: diff --git a/src/model/formToState/component-new-edit/response-format-table.jsx b/src/model/formToState/component-new-edit/response-format-table.jsx index f43dc3df0..6b14f61ac 100644 --- a/src/model/formToState/component-new-edit/response-format-table.jsx +++ b/src/model/formToState/component-new-edit/response-format-table.jsx @@ -75,6 +75,7 @@ export const defaultMeasureForm = { type: SIMPLE, [SIMPLE]: defaultMeasureSimpleState, [SINGLE_CHOICE]: { + allowArbitraryResponse: false, [DEFAULT_CODES_LIST_SELECTOR_PATH]: cloneDeep(CodesListDefaultForm), visHint: RADIO, }, diff --git a/src/model/remote-to-stores.jsx b/src/model/remote-to-stores.jsx index 59f7a0162..186dc9dd4 100644 --- a/src/model/remote-to-stores.jsx +++ b/src/model/remote-to-stores.jsx @@ -44,6 +44,12 @@ export function questionnaireRemoteToStores(remote, currentStores = {}) { remote.Child, collectedVariables, ); + + const arbitraryVariables = Component.getArbitraryVariablesFromRemote( + remote.Child, + collectedVariables, + ); + const codesListsStore = CodesList.remoteToStore( codesLists, variableclarification, @@ -56,6 +62,7 @@ export function questionnaireRemoteToStores(remote, currentStores = {}) { responsesByVariable, codesListsStore, variableclarification, + arbitraryVariables, ), }; // Components store diff --git a/src/model/transformations/collected-variable.jsx b/src/model/transformations/collected-variable.jsx index 33277d005..2b7ab3e81 100644 --- a/src/model/transformations/collected-variable.jsx +++ b/src/model/transformations/collected-variable.jsx @@ -20,6 +20,7 @@ export function remoteToStore( responsesByVariable, codesListsStore, variableclarification, + arbitraryVariables, ) { remote.forEach((variable) => { if (variableclarification) { @@ -45,9 +46,26 @@ export function remoteToStore( } } } + if (arbitraryVariables) { + const extendedArbitraryVariable = arbitraryVariables.find( + (arbitraryVariable) => + arbitraryVariable.CollectedVariableReference === variable.id, + ); + if (extendedArbitraryVariable) { + variable.arbitraryVariableOfVariableId = + extendedArbitraryVariable.arbitraryVariableOfVariableId; + } + } }); return remote.reduce((acc, ev) => { - const { Name: name, Label: label, CodeListReference, z, mesureLevel } = ev; + const { + Name: name, + Label: label, + CodeListReference, + z, + mesureLevel, + arbitraryVariableOfVariableId, + } = ev; const id = ev.id || uuid(); const formatSingleRemote = remoteToStateFormatSimple({ @@ -69,6 +87,7 @@ export function remoteToStore( ...responsesByVariable[id], z, mesureLevel, + arbitraryVariableOfVariableId, }, }; }, {}); diff --git a/src/model/transformations/collected-variable.spec.jsx b/src/model/transformations/collected-variable.spec.jsx index b636126dd..cd2218cb3 100644 --- a/src/model/transformations/collected-variable.spec.jsx +++ b/src/model/transformations/collected-variable.spec.jsx @@ -218,6 +218,86 @@ describe('collected variable tranformations', () => { output, ); }); + + test('should add the arbitrary variables to the collected', () => { + const input = [ + { + id: 'm6aty8by', + Name: 'SUGGESTER', + type: 'CollectedVariableType', + Label: 'SUGGESTER label', + Datatype: { + type: 'TextDatatypeType', + Pattern: '', + typeName: 'TEXT', + MaxLength: 1, + }, + CodeListReference: 'id', + }, + { + id: 'm6atzjnb', + Name: 'SUGGESTER_ARBITRARY', + type: 'CollectedVariableType', + Label: 'SUGGESTER_ARBITRARY label', + Datatype: { + type: 'TextDatatypeType', + typeName: 'TEXT', + MaxLength: 249, + }, + arbitraryVariableOfVariableId: 'm6aty8by', + }, + ]; + const arbitraryVariables = [ + { + Datatype: { + type: 'TextDatatypeType', + typeName: 'TEXT', + MaxLength: 249, + }, + mandatory: false, + CollectedVariableReference: 'm6atzjnb', + arbitraryVariableOfVariableId: 'm6aty8by', + }, + ]; + const responsesByVariable = { m6aty8by: {} }; + const codesListStore = { id: { label: 'label' } }; + const variableclarification = []; + const output = { + m6aty8by: { + id: 'm6aty8by', + name: 'SUGGESTER', + label: 'SUGGESTER label', + type: TEXT, + codeListReference: 'id', + codeListReferenceLabel: 'label', + TEXT: { + maxLength: 1, + pattern: '', + }, + }, + m6atzjnb: { + id: 'm6atzjnb', + name: 'SUGGESTER_ARBITRARY', + label: 'SUGGESTER_ARBITRARY label', + type: TEXT, + codeListReferenceLabel: '', + TEXT: { + maxLength: 249, + }, + arbitraryVariableOfVariableId: 'm6aty8by', + }, + }; + + expect( + remoteToStore( + input, + responsesByVariable, + codesListStore, + variableclarification, + arbitraryVariables, + ), + ).toEqual(output); + }); }); describe('remoteToComponentState', () => { test('should return the state representation of a collected variable', () => { diff --git a/src/model/transformations/component.jsx b/src/model/transformations/component.jsx index 7822ec03b..e0ee412e1 100644 --- a/src/model/transformations/component.jsx +++ b/src/model/transformations/component.jsx @@ -174,6 +174,61 @@ export const getClarificarionfromremote = (Children, collectedVariables) => { return variableClarification; }; +/* + * Get the list of questions containing an attribute "ArbitraryResponse". + * Currently we only look at single response questions. + */ +const getArbitraryQuestions = (Children) => { + const arbitraryQuestions = []; + const childr = Children.filter((children) => children.Child?.length !== 0); + childr.forEach((item) => { + item.Child?.forEach((component) => { + // component is a subsequence + if (component.type === 'SequenceType') { + component.Child.forEach((question) => { + if ( + // single choice question + question.questionType === SINGLE_CHOICE && + question.ArbitraryResponse !== undefined + ) { + arbitraryQuestions.push(question); + } + }); + } else if ( + // component is a single choice question + component.questionType === SINGLE_CHOICE && + component.ArbitraryResponse !== undefined + ) { + arbitraryQuestions.push(component); + } + }); + }); + return arbitraryQuestions; +}; + +/* + * Get the list of arbitrary variables. + * An arbitrary variable is the "ArbitraryResponse" object of a question, + * extented with "arbitraryVariableOfVariableId" which is the corresponding Response variable id. + */ +export const getArbitraryVariablesFromRemote = (Children) => { + const arbitraryVariables = []; + const arbitraryQuestions = getArbitraryQuestions(Children); + + arbitraryQuestions.forEach((question) => { + // a question with arbitrary is a singleReponse question so it has only one Response + const responseVariableId = question.Response[0].CollectedVariableReference; + + const arbitraryVariable = { + ...question.ArbitraryResponse, + arbitraryVariableOfVariableId: responseVariableId, + }; + arbitraryVariables.push(arbitraryVariable); + }); + + return arbitraryVariables; +}; + function remoteToVariableResponseNested(children = [], acc = {}) { children.forEach((child) => { const { @@ -226,6 +281,7 @@ function remoteToState(remote, componentGroup, codesListsStore) { Control: controls, Response: responses, ClarificationQuestion: responsesClarification, + ArbitraryResponse: arbitraryResponse, ResponseStructure: responseStructure, Child: children, parent, @@ -250,6 +306,10 @@ function remoteToState(remote, componentGroup, codesListsStore) { responseFinal = responseFinal.concat(clar.Response); }); } + if (arbitraryResponse !== undefined) { + responseFinal.push(arbitraryResponse); + } + const state = { id, name, @@ -629,6 +689,37 @@ function getClarificationResponseTableQuestion( }; } +function getArbitraryResponse(collectedVariablesStore, collectedVariables) { + const collectedVariableQuestions = []; + Object.values(collectedVariablesStore).forEach((collec) => { + if (collectedVariables !== undefined) { + collectedVariables.forEach((variables) => { + if (collec.id === variables) { + collectedVariableQuestions.push(collec); + } + }); + } + }); + + for (const collected of collectedVariableQuestions) { + const isArbitraryVariable = + collected.arbitraryVariableOfVariableId !== undefined; + // we can have only one collected variable that is an arbitrary variable + if (isArbitraryVariable) { + const responseModel = { + mandatory: false, + typeName: collected.type, + maxLength: collected.TEXT.maxLength, + collectedVariable: collected.id, + }; + const arbitraryResponse = Response.stateToRemote(responseModel); + return arbitraryResponse; + } + } + + return undefined; +} + function storeToRemoteNested( state, store, @@ -686,8 +777,15 @@ function storeToRemoteNested( responsesClarification, flowControl, ); + remote.FlowControl = remoteclarification.flowcontrolefinal; remote.ClarificationQuestion = remoteclarification.ClarificationQuestion; + + const remoteArbitrary = getArbitraryResponse( + collectedVariablesStore, + collectedVariables, + ); + remote.ArbitraryResponse = remoteArbitrary; } if ( responseFormat.type === MULTIPLE_CHOICE && diff --git a/src/model/transformations/component.spec.jsx b/src/model/transformations/component.spec.jsx index e8c4c121d..54bca51e9 100644 --- a/src/model/transformations/component.spec.jsx +++ b/src/model/transformations/component.spec.jsx @@ -38,6 +38,43 @@ describe('component tranformations', () => { questionType: 'SIMPLE', type: 'QuestionType', }, + { + Control: [], + Declaration: [], + FlowControl: [], + Label: ['question'], + Name: 'QUESTION', + Response: [ + { + CollectedVariableReference: 'm6awmxim', + CodeListReference: 'listId', + Datatype: { + typeName: 'TEXT', + type: 'TextDatatypeType', + MaxLength: 1, + allowArbitraryResponse: true, + visualizationHint: 'SUGGESTER', + }, + id: 'm5qyf09t', + mandatory: false, + }, + ], + ArbitraryResponse: { + id: 'm6awrflv', + Datatype: { + type: 'TextDatatypeType', + typeName: 'TEXT', + MaxLength: 249, + }, + mandatory: false, + CollectedVariableReference: 'm6awei7a', + }, + TargetMode: ['CAWI'], + depth: 2, + id: 'm5qy1yf9', + questionType: 'SINGLE_CHOICE', + type: 'QuestionType', + }, ], Control: [], Declaration: [], @@ -64,7 +101,7 @@ describe('component tranformations', () => { type: 'SequenceType', }, ], - CodeLists: { CodeList: [] }, + CodeLists: { CodeList: [{ id: 'listId', Label: 'listLabel' }] }, ComponentGroup: [ { Label: ['Components for page 1'], @@ -98,6 +135,30 @@ describe('component tranformations', () => { id: 'khj4uvok', type: 'CollectedVariableType', }, + { + id: 'm6awmxim', + Name: 'SUGGESTER', + type: 'CollectedVariableType', + Label: 'SUGGESTER label', + Datatype: { + type: 'TextDatatypeType', + Pattern: '', + typeName: 'TEXT', + MaxLength: 1, + }, + CodeListReference: 'L_PRODEAP_EAU_2024', + }, + { + id: 'm6awei7a', + Name: 'SUGGESTER_ARBITRARY', + type: 'CollectedVariableType', + Label: 'SUGGESTER_ARBITRARY label', + Datatype: { + type: 'TextDatatypeType', + typeName: 'TEXT', + MaxLength: 249, + }, + }, ], }, agency: 'fr.insee', @@ -109,7 +170,7 @@ describe('component tranformations', () => { owner: 'FAKEPERMISSION', }; const questionnaireId = 'khj4mf0r'; - const codesListsStore = {}; + const codesListsStore = { id: { label: 'label' } }; const iterations = []; const filters = []; @@ -156,6 +217,35 @@ describe('component tranformations', () => { type: 'QUESTION', weight: 0, }, + m5qy1yf9: { + TargetMode: ['CAWI'], + children: [], + collectedVariables: ['m6awmxim', 'm6awei7a'], + controls: {}, + declarations: {}, + flowControl: [], + dynamiqueSpecified: 'Redirections', + id: 'm5qy1yf9', + label: 'question', + name: 'QUESTION', + parent: 'khj54mjm', + redirections: {}, + responseFormat: { + type: 'SINGLE_CHOICE', + SINGLE_CHOICE: { + visHint: 'SUGGESTER', + allowArbitraryResponse: true, + id: 'm5qyf09t', + mandatory: false, + CodesList: { + id: 'listId', + }, + }, + }, + responsesClarification: undefined, + type: 'QUESTION', + weight: 1, + }, khj4mf0r: { TargetMode: ['CAWI'], children: ['khj54mjm'], @@ -174,7 +264,7 @@ describe('component tranformations', () => { }, khj54mjm: { TargetMode: ['CAWI'], - children: ['khj4le7i'], + children: ['khj4le7i', 'm5qy1yf9'], controls: {}, declarations: {}, flowControl: [], diff --git a/src/model/transformations/response-format-single.jsx b/src/model/transformations/response-format-single.jsx index 7321d4eb8..fbce6748b 100644 --- a/src/model/transformations/response-format-single.jsx +++ b/src/model/transformations/response-format-single.jsx @@ -11,7 +11,7 @@ export function remoteToState(remote) { const { responses: [ { - Datatype: { visualizationHint: visHint }, + Datatype: { allowArbitraryResponse, visualizationHint: visHint }, mandatory, CodeListReference, id, @@ -24,6 +24,7 @@ export function remoteToState(remote) { CodeList.remoteToState(CodeListReference), id, mandatory, + allowArbitraryResponse, visHint, }; } @@ -31,6 +32,7 @@ export function remoteToState(remote) { export function stateToRemote(state, collectedVariables) { const { [DEFAULT_CODES_LIST_SELECTOR_PATH]: { id: codesListId }, + allowArbitraryResponse, visHint, mandatory, id, @@ -40,6 +42,7 @@ export function stateToRemote(state, collectedVariables) { Response.stateToRemote({ id, mandatory, + allowArbitraryResponse, visHint, codesListId, typeName: TEXT, diff --git a/src/model/transformations/response.jsx b/src/model/transformations/response.jsx index 934c35c24..a4edfa07a 100644 --- a/src/model/transformations/response.jsx +++ b/src/model/transformations/response.jsx @@ -1,4 +1,7 @@ -import { DATATYPE_TYPE_FROM_NAME } from '../../constants/pogues-constants'; +import { + DATATYPE_TYPE_FROM_NAME, + DATATYPE_VIS_HINT, +} from '../../constants/pogues-constants'; import { uuid } from '../../utils/utils'; export function stateToRemote(state, response) { @@ -23,6 +26,7 @@ export function stateToRemote(state, response) { mayears: Mayears, mamonths: Mamonths, codesListId: CodeListReference, + allowArbitraryResponse, visHint: visualizationHint, collectedVariable: CollectedVariableReference, } = state; @@ -47,6 +51,12 @@ export function stateToRemote(state, response) { model.CodeListReference = CodeListReference; if (mandatory !== undefined) model.mandatory = mandatory === '' ? false : mandatory; + if (allowArbitraryResponse !== undefined) + // we keep allowArbitraryResponse value only for suggester + model.Datatype.allowArbitraryResponse = + visualizationHint === DATATYPE_VIS_HINT.SUGGESTER + ? allowArbitraryResponse + : undefined; if (visualizationHint !== undefined) model.Datatype.visualizationHint = visualizationHint; if (MaxLength !== undefined) model.Datatype.MaxLength = MaxLength; diff --git a/src/model/transformations/response.spec.jsx b/src/model/transformations/response.spec.jsx index cca8afab2..1e2d7b7ed 100644 --- a/src/model/transformations/response.spec.jsx +++ b/src/model/transformations/response.spec.jsx @@ -1,7 +1,10 @@ import { format } from 'url'; import { describe, expect, test } from 'vitest'; -import { DATATYPE_TYPE_FROM_NAME } from '../../constants/pogues-constants'; +import { + DATATYPE_TYPE_FROM_NAME, + DATATYPE_VIS_HINT, +} from '../../constants/pogues-constants'; import { stateToRemote } from './response'; describe('response tranformations', () => { @@ -166,6 +169,39 @@ describe('response tranformations', () => { expect(result.Datatype.Unit).toEqual(unit); }); + test('when allowArbitraryResponse is defined', () => { + const typeName = 'TEXT'; + const allowArbitraryResponse = true; + + // Get all values of DATATYPE_VIS_HINT except 'SUGGESTER' + const nonSuggesterVisHints = Object.values(DATATYPE_VIS_HINT).filter( + (visHint) => visHint !== DATATYPE_VIS_HINT.SUGGESTER, + ); + + const resultSuggester = stateToRemote({ + typeName, + id: '1', + visHint: DATATYPE_VIS_HINT.SUGGESTER, + allowArbitraryResponse, + }); + + expect(resultSuggester.Datatype.allowArbitraryResponse).toEqual( + allowArbitraryResponse, + ); + + // Test for all non-SUGGESTER visHint values + nonSuggesterVisHints.forEach((visHint) => { + const result = stateToRemote({ + typeName, + id: '1', + visHint, + allowArbitraryResponse, + }); + + expect(result.Datatype.allowArbitraryResponse).toEqual(undefined); + }); + }); + test('when Format is defined', () => { const typeName = 'DATE'; const result = stateToRemote({ diff --git a/src/utils/variables/collected-variables-utils.jsx b/src/utils/variables/collected-variables-utils.jsx index 922d38aac..8d0562e7a 100644 --- a/src/utils/variables/collected-variables-utils.jsx +++ b/src/utils/variables/collected-variables-utils.jsx @@ -1,6 +1,7 @@ import { COMPONENT_TYPE, DATATYPE_NAME, + DATATYPE_VIS_HINT, DEFAULT_CODES_LIST_SELECTOR_PATH, DIMENSION_FORMATS, DIMENSION_TYPE, @@ -86,6 +87,7 @@ export function getCollectedVariable( coordinates, reponseFormatValues = {}, alternativeLabel = '', + arbitraryVariableOfVariableId = undefined, ) { let collectedVariable = { ...reponseFormatValues, @@ -97,6 +99,11 @@ export function getCollectedVariable( if (coordinates) collectedVariable = { ...collectedVariable, ...coordinates }; if (alternativeLabel) collectedVariable = { ...collectedVariable, ...alternativeLabel }; + if (arbitraryVariableOfVariableId) + collectedVariable = { + ...collectedVariable, + arbitraryVariableOfVariableId: arbitraryVariableOfVariableId, + }; return collectedVariable; } @@ -168,8 +175,12 @@ export function getCollectedVariablesMultiple( export function getCollectedVariablesSingle(questionName, form) { const collectedVariables = []; - collectedVariables.push( - getCollectedVariable(questionName, `${questionName} label`, undefined, { + + const mainCollectedVariable = getCollectedVariable( + questionName, + `${questionName} label`, + undefined, + { codeListReference: form.CodesList.id, codeListReferenceLabel: form.CodesList.label, type: TEXT, @@ -177,9 +188,35 @@ export function getCollectedVariablesSingle(questionName, form) { maxLength: 1, pattern: '', }, - }), + }, ); + collectedVariables.push(mainCollectedVariable); + + // get arbitrary variable for suggester + if ( + form.allowArbitraryResponse && + form.visHint === DATATYPE_VIS_HINT.SUGGESTER + ) { + const arbitraryResponseName = `${questionName}_ARBITRARY`; + collectedVariables.push( + getCollectedVariable( + arbitraryResponseName, + `${arbitraryResponseName} label`, + undefined, + { + type: TEXT, + [TEXT]: { + maxLength: 249, + }, + }, + undefined, + mainCollectedVariable.id, + ), + ); + } + + // get clarification variables for codes lists form.CodesList.codes?.forEach((code) => { if (code.precisionid && code.precisionid !== '') { collectedVariables.push( diff --git a/src/utils/variables/collected-variables-utils.spec.jsx b/src/utils/variables/collected-variables-utils.spec.jsx index 8bcae0407..e15460374 100644 --- a/src/utils/variables/collected-variables-utils.spec.jsx +++ b/src/utils/variables/collected-variables-utils.spec.jsx @@ -39,7 +39,7 @@ describe('generateCollectedVariables', () => { }); describe('getCollectedVariablesSingle', () => { - test('should return collected variables for QCM without precision in codesList', () => { + test('should return collected variables for QCU without precision in codesList', () => { const questionName = 'questionName'; const form = { CodesList: { @@ -89,7 +89,7 @@ describe('getCollectedVariablesSingle', () => { ]); }); - test('should return collected variables for QCM with precision in codesList', () => { + test('should return collected variables for QCU with precision in codesList', () => { const questionName = 'questionName'; const form = { CodesList: { @@ -150,6 +150,37 @@ describe('getCollectedVariablesSingle', () => { }, ]); }); + + test('should return suggester arbitrary variable if allowArbitraryResponse', () => { + const questionName = 'questionName'; + const form = { + allowArbitraryResponse: true, + visHint: 'SUGGESTER', + CodesList: { id: 'id', label: 'label', codes: [] }, + }; + + const result = getCollectedVariablesSingle(questionName, form); + + expect(result).toEqual([ + { + id: result[0].id, + name: 'questionName', + label: 'questionName label', + codeListReference: form.CodesList.id, + codeListReferenceLabel: form.CodesList.label, + type: 'TEXT', + TEXT: { maxLength: 1, pattern: '' }, + }, + { + id: result[1].id, + name: 'questionName_ARBITRARY', + label: 'questionName_ARBITRARY label', + type: 'TEXT', + TEXT: { maxLength: 249 }, + arbitraryVariableOfVariableId: result[0].id, + }, + ]); + }); }); describe('getCollectedVariablesTable', () => { diff --git a/src/widgets/component-new-edit/components/response-format/single/response-format-single.jsx b/src/widgets/component-new-edit/components/response-format/single/response-format-single.jsx index ff46711de..bc7a272ce 100644 --- a/src/widgets/component-new-edit/components/response-format/single/response-format-single.jsx +++ b/src/widgets/component-new-edit/components/response-format/single/response-format-single.jsx @@ -37,6 +37,7 @@ function ResponseFormatSingle({ path, formName, allowPrecision, + disableSetArbitrary, }) { const selectorPath = responseFormatType; @@ -168,7 +169,24 @@ function ResponseFormatSingle({ )} {visHint === SUGGESTER ? ( - + <> + + {!disableSetArbitrary && ( + value === 'true'} + // Convert true/false/undefined to string "true"/"false" when displaying the form + format={(value) => (value === true ? 'true' : 'false')} + > + {Dictionary.yes} + {Dictionary.no} + + )} + ) : ( { @@ -212,6 +232,7 @@ const mapStateToProps = (state, { selectorPathParent, responseFormatType }) => { componentsStore: state.appState.activeComponentsById, collectedVariablesStore: state.appState.collectedVariableByQuestion, visHint: selector(state, `${path}visHint`), + allowArbitraryResponse: selector(state, `${path}allowArbitraryResponse`), path, }; }; diff --git a/src/widgets/component-new-edit/components/response-format/table/input-measure.jsx b/src/widgets/component-new-edit/components/response-format/table/input-measure.jsx index 54a835595..dd23b2d8b 100644 --- a/src/widgets/component-new-edit/components/response-format/table/input-measure.jsx +++ b/src/widgets/component-new-edit/components/response-format/table/input-measure.jsx @@ -44,6 +44,7 @@ function InputMeasure({ selectorPath }) { selectorPathParent={selectorPath} showMandatory={false} allowPrecision={false} + disableSetArbitrary={true} />