diff --git a/builder-api/src/main/java/org/acme/service/InputSchemaService.java b/builder-api/src/main/java/org/acme/service/InputSchemaService.java index 40431db1..ab1df2b9 100644 --- a/builder-api/src/main/java/org/acme/service/InputSchemaService.java +++ b/builder-api/src/main/java/org/acme/service/InputSchemaService.java @@ -44,9 +44,11 @@ public Set extractAllInputPaths(List benefits) { /** * Transforms a CheckConfig's inputDefinition JSON Schema by applying all schema transformations. * Currently applies: - * 1. People transformation: converts people array to object keyed by personId + * 1. People transformation: converts people array to object keyed by personId(s) * 2. Enrollments transformation: moves enrollments under people.{personId}.enrollments * + * Supports both single personId (String) and multiple peopleIds (List) parameters. + * * @param checkConfig The CheckConfig containing inputDefinition and parameters * @return A new JsonNode with all transformations applied */ @@ -57,30 +59,68 @@ public JsonNode transformInputDefinitionSchema(CheckConfig checkConfig) { return inputDefinition != null ? inputDefinition.deepCopy() : objectMapper.createObjectNode(); } - // Extract personId from parameters + // Extract personId(s) from parameters - supports both single personId and multiple peopleIds Map parameters = checkConfig.getParameters(); - String personId = parameters != null ? (String) parameters.get("personId") : null; + List personIds = extractPersonIds(parameters); // Apply each transformation in sequence JsonNode schema = inputDefinition.deepCopy(); - schema = transformPeopleSchema(schema, personId); - schema = transformEnrollmentsSchema(schema, personId); + schema = transformPeopleSchema(schema, personIds); + schema = transformEnrollmentsSchema(schema, personIds); return schema; } + /** + * Extracts person IDs from parameters, supporting both: + * - personId: a single String ID + * - peopleIds: a List of String IDs + * + * @param parameters The parameters map from CheckConfig + * @return List of person IDs (may be empty if neither parameter is set) + */ + private List extractPersonIds(Map parameters) { + if (parameters == null) { + return Collections.emptyList(); + } + + List personIds = new ArrayList<>(); + + // Check for single personId + Object personId = parameters.get("personId"); + if (personId instanceof String && !((String) personId).isEmpty()) { + personIds.add((String) personId); + } + + // Check for multiple peopleIds + Object peopleIds = parameters.get("peopleIds"); + if (peopleIds instanceof List) { + for (Object id : (List) peopleIds) { + if (id instanceof String && !((String) id).isEmpty()) { + personIds.add((String) id); + } + } + } + + return personIds; + } + /** * Transforms the `people` array property into an object with personId-keyed properties. * - * Example: + * Example (single ID): * Input: { people: { type: "array", items: { properties: { dateOfBirth: ... } } } } * Output: { people: { type: "object", properties: { [personId]: { properties: { dateOfBirth: ... } } } } } * + * Example (multiple IDs): + * Input: { people: { type: "array", items: { properties: { dateOfBirth: ... } } } } + * Output: { people: { type: "object", properties: { [id1]: {...}, [id2]: {...} } } } + * * @param schema The JSON Schema to transform - * @param personId The personId to use as the key under people + * @param personIds List of personIds to use as keys under people * @return A new JsonNode with `people` transformed, or the original if no transformation needed */ - public JsonNode transformPeopleSchema(JsonNode schema, String personId) { + public JsonNode transformPeopleSchema(JsonNode schema, List personIds) { if (schema == null || !schema.has("properties")) { return schema != null ? schema.deepCopy() : objectMapper.createObjectNode(); } @@ -93,8 +133,8 @@ public JsonNode transformPeopleSchema(JsonNode schema, String personId) { return schema.deepCopy(); } - // If people property exists but no personId, return original (can't transform) - if (personId == null || personId.isEmpty()) { + // If people property exists but no personIds, return original (can't transform) + if (personIds == null || personIds.isEmpty()) { return schema.deepCopy(); } @@ -105,12 +145,14 @@ public JsonNode transformPeopleSchema(JsonNode schema, String personId) { // Get the items schema from the people array JsonNode itemsSchema = peopleProperty.get("items"); - // Transform people from array to object with personId as a nested property + // Transform people from array to object with personIds as nested properties ObjectNode newPeopleSchema = objectMapper.createObjectNode(); newPeopleSchema.put("type", "object"); ObjectNode newPeopleProperties = objectMapper.createObjectNode(); if (itemsSchema != null) { - newPeopleProperties.set(personId, itemsSchema.deepCopy()); + for (String personId : personIds) { + newPeopleProperties.set(personId, itemsSchema.deepCopy()); + } } newPeopleSchema.set("properties", newPeopleProperties); @@ -122,15 +164,19 @@ public JsonNode transformPeopleSchema(JsonNode schema, String personId) { * Transforms the `enrollments` array property by moving it under people.{personId}.enrollments * as an array of strings (benefit names). * - * Example: + * Example (single ID): * Input: { enrollments: { type: "array", items: { properties: { personId: ..., benefit: ... } } } } * Output: { people: { type: "object", properties: { [personId]: { properties: { enrollments: { type: "array", items: { type: "string" } } } } } } } * + * Example (multiple IDs): + * Input: { enrollments: { type: "array", ... } } + * Output: { people: { type: "object", properties: { [id1]: { properties: { enrollments: ... } }, [id2]: { properties: { enrollments: ... } } } } } + * * @param schema The JSON Schema to transform - * @param personId The personId to use as the key under people + * @param personIds List of personIds to use as keys under people * @return A new JsonNode with `enrollments` transformed, or the original if no transformation needed */ - public JsonNode transformEnrollmentsSchema(JsonNode schema, String personId) { + public JsonNode transformEnrollmentsSchema(JsonNode schema, List personIds) { if (schema == null || !schema.has("properties")) { return schema != null ? schema.deepCopy() : objectMapper.createObjectNode(); } @@ -143,8 +189,8 @@ public JsonNode transformEnrollmentsSchema(JsonNode schema, String personId) { return schema.deepCopy(); } - // If enrollments property exists but no personId, return original (can't transform) - if (personId == null || personId.isEmpty()) { + // If enrollments property exists but no personIds, return original (can't transform) + if (personIds == null || personIds.isEmpty()) { return schema.deepCopy(); } @@ -180,27 +226,30 @@ public JsonNode transformEnrollmentsSchema(JsonNode schema, String personId) { transformedProperties.set("people", peopleSchema); } - // Get or create the personId property under people - JsonNode existingPersonId = peopleProps.get(personId); - ObjectNode personIdSchema; - ObjectNode personIdProps; + // Add enrollments under each personId + for (String personId : personIds) { + // Get or create the personId property under people + JsonNode existingPersonId = peopleProps.get(personId); + ObjectNode personIdSchema; + ObjectNode personIdProps; + + if (existingPersonId != null && existingPersonId.has("properties")) { + // PersonId already exists + personIdSchema = (ObjectNode) existingPersonId; + personIdProps = (ObjectNode) personIdSchema.get("properties"); + } else { + // Create new personId structure + personIdSchema = objectMapper.createObjectNode(); + personIdSchema.put("type", "object"); + personIdProps = objectMapper.createObjectNode(); + personIdSchema.set("properties", personIdProps); + peopleProps.set(personId, personIdSchema); + } - if (existingPersonId != null && existingPersonId.has("properties")) { - // PersonId already exists - personIdSchema = (ObjectNode) existingPersonId; - personIdProps = (ObjectNode) personIdSchema.get("properties"); - } else { - // Create new personId structure - personIdSchema = objectMapper.createObjectNode(); - personIdSchema.put("type", "object"); - personIdProps = objectMapper.createObjectNode(); - personIdSchema.set("properties", personIdProps); - peopleProps.set(personId, personIdSchema); + // Add enrollments under the personId + personIdProps.set("enrollments", enrollmentsSchema.deepCopy()); } - // Add enrollments under the personId - personIdProps.set("enrollments", enrollmentsSchema); - return transformedSchema; } diff --git a/builder-api/src/main/java/org/acme/service/KieDmnService.java b/builder-api/src/main/java/org/acme/service/KieDmnService.java index 85af4db1..5e1bcc75 100644 --- a/builder-api/src/main/java/org/acme/service/KieDmnService.java +++ b/builder-api/src/main/java/org/acme/service/KieDmnService.java @@ -171,6 +171,9 @@ public EvaluationResult evaluateDmn( Map inputs, Map parameters ) throws Exception { + Log.info(inputs); + Log.info(parameters); + Log.info("Evaluating Simple DMN: " + dmnFilePath + " Model: " + dmnModelName); Optional dmnXmlOpt = storageService.getStringFromStorage(dmnFilePath); diff --git a/builder-api/src/test/java/org/acme/service/InputSchemaServiceTest.java b/builder-api/src/test/java/org/acme/service/InputSchemaServiceTest.java index 45f64096..8487899d 100644 --- a/builder-api/src/test/java/org/acme/service/InputSchemaServiceTest.java +++ b/builder-api/src/test/java/org/acme/service/InputSchemaServiceTest.java @@ -6,6 +6,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -26,7 +27,7 @@ void setUp() { // ==== transformPeopleSchema tests ==== @Test - void transformPeopleSchema_withPeopleArrayAndPersonId_transformsToObject() throws Exception { + void transformPeopleSchema_withPeopleArrayAndSinglePersonId_transformsToObject() throws Exception { String schemaJson = """ { "type": "object", @@ -45,7 +46,7 @@ void transformPeopleSchema_withPeopleArrayAndPersonId_transformsToObject() throw """; JsonNode schema = objectMapper.readTree(schemaJson); - JsonNode result = service.transformPeopleSchema(schema, "applicant"); + JsonNode result = service.transformPeopleSchema(schema, List.of("applicant")); // Verify people is now an object with personId key assertTrue(result.has("properties")); @@ -59,7 +60,65 @@ void transformPeopleSchema_withPeopleArrayAndPersonId_transformsToObject() throw } @Test - void transformPeopleSchema_withoutPersonId_returnsOriginal() throws Exception { + void transformPeopleSchema_withMultiplePersonIds_transformsToObjectWithMultipleKeys() throws Exception { + String schemaJson = """ + { + "type": "object", + "properties": { + "people": { + "type": "array", + "items": { + "type": "object", + "properties": { + "dateOfBirth": { "type": "string", "format": "date" } + } + } + } + } + } + """; + JsonNode schema = objectMapper.readTree(schemaJson); + + JsonNode result = service.transformPeopleSchema(schema, List.of("applicant", "spouse", "child")); + + // Verify people is now an object with all personId keys + assertTrue(result.has("properties")); + JsonNode people = result.get("properties").get("people"); + assertEquals("object", people.get("type").asText()); + assertTrue(people.has("properties")); + + // Verify all three personIds are present + assertTrue(people.get("properties").has("applicant")); + assertTrue(people.get("properties").get("applicant").get("properties").has("dateOfBirth")); + assertTrue(people.get("properties").has("spouse")); + assertTrue(people.get("properties").get("spouse").get("properties").has("dateOfBirth")); + assertTrue(people.get("properties").has("child")); + assertTrue(people.get("properties").get("child").get("properties").has("dateOfBirth")); + } + + @Test + void transformPeopleSchema_withoutPersonIds_returnsOriginal() throws Exception { + String schemaJson = """ + { + "type": "object", + "properties": { + "people": { + "type": "array", + "items": { "type": "object", "properties": { "dateOfBirth": { "type": "string" } } } + } + } + } + """; + JsonNode schema = objectMapper.readTree(schemaJson); + + JsonNode result = service.transformPeopleSchema(schema, Collections.emptyList()); + + // Should return a copy of the original + assertEquals("array", result.get("properties").get("people").get("type").asText()); + } + + @Test + void transformPeopleSchema_withNullPersonIds_returnsOriginal() throws Exception { String schemaJson = """ { "type": "object", @@ -91,7 +150,7 @@ void transformPeopleSchema_withoutPeopleProperty_returnsOriginal() throws Except """; JsonNode schema = objectMapper.readTree(schemaJson); - JsonNode result = service.transformPeopleSchema(schema, "applicant"); + JsonNode result = service.transformPeopleSchema(schema, List.of("applicant")); // Should return a copy of the original assertTrue(result.get("properties").has("income")); @@ -101,7 +160,7 @@ void transformPeopleSchema_withoutPeopleProperty_returnsOriginal() throws Except // ==== transformEnrollmentsSchema tests ==== @Test - void transformEnrollmentsSchema_withEnrollmentsAndPersonId_movesUnderPeople() throws Exception { + void transformEnrollmentsSchema_withEnrollmentsAndSinglePersonId_movesUnderPeople() throws Exception { String schemaJson = """ { "type": "object", @@ -121,7 +180,7 @@ void transformEnrollmentsSchema_withEnrollmentsAndPersonId_movesUnderPeople() th """; JsonNode schema = objectMapper.readTree(schemaJson); - JsonNode result = service.transformEnrollmentsSchema(schema, "applicant"); + JsonNode result = service.transformEnrollmentsSchema(schema, List.of("applicant")); // Verify top-level enrollments is removed assertFalse(result.get("properties").has("enrollments")); @@ -141,6 +200,52 @@ void transformEnrollmentsSchema_withEnrollmentsAndPersonId_movesUnderPeople() th assertEquals("string", enrollments.get("items").get("type").asText()); } + @Test + void transformEnrollmentsSchema_withMultiplePersonIds_movesUnderAllPeople() throws Exception { + String schemaJson = """ + { + "type": "object", + "properties": { + "enrollments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "personId": { "type": "string" }, + "benefit": { "type": "string" } + } + } + } + } + } + """; + JsonNode schema = objectMapper.readTree(schemaJson); + + JsonNode result = service.transformEnrollmentsSchema(schema, List.of("applicant", "spouse")); + + // Verify top-level enrollments is removed + assertFalse(result.get("properties").has("enrollments")); + + // Verify people structure exists + assertTrue(result.get("properties").has("people")); + JsonNode people = result.get("properties").get("people"); + assertEquals("object", people.get("type").asText()); + + // Verify both personIds have enrollments + assertTrue(people.get("properties").has("applicant")); + assertTrue(people.get("properties").has("spouse")); + + JsonNode applicant = people.get("properties").get("applicant"); + JsonNode spouse = people.get("properties").get("spouse"); + + assertTrue(applicant.get("properties").has("enrollments")); + assertTrue(spouse.get("properties").has("enrollments")); + + // Verify enrollments is array of strings for both + assertEquals("array", applicant.get("properties").get("enrollments").get("type").asText()); + assertEquals("array", spouse.get("properties").get("enrollments").get("type").asText()); + } + @Test void transformEnrollmentsSchema_withExistingPeopleStructure_mergesEnrollments() throws Exception { // Simulate a schema that already has people transformed (e.g., from transformPeopleSchema) @@ -174,7 +279,7 @@ void transformEnrollmentsSchema_withExistingPeopleStructure_mergesEnrollments() """; JsonNode schema = objectMapper.readTree(schemaJson); - JsonNode result = service.transformEnrollmentsSchema(schema, "applicant"); + JsonNode result = service.transformEnrollmentsSchema(schema, List.of("applicant")); // Verify top-level enrollments is removed assertFalse(result.get("properties").has("enrollments")); @@ -186,7 +291,28 @@ void transformEnrollmentsSchema_withExistingPeopleStructure_mergesEnrollments() } @Test - void transformEnrollmentsSchema_withoutPersonId_returnsOriginal() throws Exception { + void transformEnrollmentsSchema_withoutPersonIds_returnsOriginal() throws Exception { + String schemaJson = """ + { + "type": "object", + "properties": { + "enrollments": { + "type": "array", + "items": { "type": "object", "properties": { "benefit": { "type": "string" } } } + } + } + } + """; + JsonNode schema = objectMapper.readTree(schemaJson); + + JsonNode result = service.transformEnrollmentsSchema(schema, Collections.emptyList()); + + // Should return a copy of the original + assertTrue(result.get("properties").has("enrollments")); + } + + @Test + void transformEnrollmentsSchema_withNullPersonIds_returnsOriginal() throws Exception { String schemaJson = """ { "type": "object", @@ -218,7 +344,7 @@ void transformEnrollmentsSchema_withoutEnrollmentsProperty_returnsOriginal() thr """; JsonNode schema = objectMapper.readTree(schemaJson); - JsonNode result = service.transformEnrollmentsSchema(schema, "applicant"); + JsonNode result = service.transformEnrollmentsSchema(schema, List.of("applicant")); // Should return a copy of the original assertTrue(result.get("properties").has("income")); @@ -228,7 +354,7 @@ void transformEnrollmentsSchema_withoutEnrollmentsProperty_returnsOriginal() thr // ==== transformInputDefinitionSchema composition tests ==== @Test - void transformInputDefinitionSchema_withPeopleAndEnrollments_appliesBothTransforms() throws Exception { + void transformInputDefinitionSchema_withPersonId_appliesBothTransforms() throws Exception { String schemaJson = """ { "type": "object", @@ -275,6 +401,125 @@ void transformInputDefinitionSchema_withPeopleAndEnrollments_appliesBothTransfor assertEquals("string", applicant.get("properties").get("enrollments").get("items").get("type").asText()); } + @Test + void transformInputDefinitionSchema_withPeopleIds_appliesBothTransformsForAllIds() throws Exception { + String schemaJson = """ + { + "type": "object", + "properties": { + "people": { + "type": "array", + "items": { + "type": "object", + "properties": { + "dateOfBirth": { "type": "string", "format": "date" } + } + } + }, + "enrollments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "personId": { "type": "string" }, + "benefit": { "type": "string" } + } + } + } + } + } + """; + JsonNode inputDefinition = objectMapper.readTree(schemaJson); + + CheckConfig checkConfig = new CheckConfig(); + checkConfig.setInputDefinition(inputDefinition); + Map params = new HashMap<>(); + params.put("peopleIds", List.of("applicant", "spouse", "child")); + checkConfig.setParameters(params); + + JsonNode result = service.transformInputDefinitionSchema(checkConfig); + + // Verify top-level enrollments is removed + assertFalse(result.get("properties").has("enrollments")); + + // Verify all three personIds exist under people and have both dateOfBirth and enrollments + JsonNode peopleProps = result.get("properties").get("people").get("properties"); + for (String personId : List.of("applicant", "spouse", "child")) { + assertTrue(peopleProps.has(personId)); + JsonNode person = peopleProps.get(personId); + assertTrue(person.get("properties").has("dateOfBirth"), personId + " should have dateOfBirth"); + assertTrue(person.get("properties").has("enrollments"), personId + " should have enrollments"); + } + } + + @Test + void transformInputDefinitionSchema_withBothPersonIdAndPeopleIds_combinesBoth() throws Exception { + String schemaJson = """ + { + "type": "object", + "properties": { + "people": { + "type": "array", + "items": { + "type": "object", + "properties": { + "dateOfBirth": { "type": "string", "format": "date" } + } + } + } + } + } + """; + JsonNode inputDefinition = objectMapper.readTree(schemaJson); + + CheckConfig checkConfig = new CheckConfig(); + checkConfig.setInputDefinition(inputDefinition); + Map params = new HashMap<>(); + params.put("personId", "applicant"); + params.put("peopleIds", List.of("spouse", "child")); + checkConfig.setParameters(params); + + JsonNode result = service.transformInputDefinitionSchema(checkConfig); + + // Verify all three personIds exist (personId + peopleIds combined) + JsonNode peopleProps = result.get("properties").get("people").get("properties"); + assertTrue(peopleProps.has("applicant")); + assertTrue(peopleProps.has("spouse")); + assertTrue(peopleProps.has("child")); + } + + @Test + void transformInputDefinitionSchema_withNoPersonParams_returnsOriginalStructure() throws Exception { + String schemaJson = """ + { + "type": "object", + "properties": { + "people": { + "type": "array", + "items": { + "type": "object", + "properties": { + "dateOfBirth": { "type": "string", "format": "date" } + } + } + } + } + } + """; + JsonNode inputDefinition = objectMapper.readTree(schemaJson); + + CheckConfig checkConfig = new CheckConfig(); + checkConfig.setInputDefinition(inputDefinition); + Map params = new HashMap<>(); + params.put("minAge", 65); // Some other parameter, not personId/peopleIds + checkConfig.setParameters(params); + + JsonNode result = service.transformInputDefinitionSchema(checkConfig); + + // Should return people as array (no transformation) + assertEquals("array", result.get("properties").get("people").get("type").asText()); + } + // ==== extractJsonSchemaPaths tests ==== @Test @@ -341,4 +586,40 @@ void extractJsonSchemaPaths_withEnrollmentOnlySchema_extractsCorrectPath() throw assertTrue(paths.contains("people.applicant.enrollments")); assertEquals(1, paths.size()); } + + @Test + void extractJsonSchemaPaths_withMultiplePersonIds_extractsPathsForAll() throws Exception { + // This tests the result after transformation with multiple peopleIds + String schemaJson = """ + { + "type": "object", + "properties": { + "people": { + "type": "object", + "properties": { + "applicant": { + "type": "object", + "properties": { + "dateOfBirth": { "type": "string", "format": "date" } + } + }, + "spouse": { + "type": "object", + "properties": { + "dateOfBirth": { "type": "string", "format": "date" } + } + } + } + } + } + } + """; + JsonNode schema = objectMapper.readTree(schemaJson); + + List paths = service.extractJsonSchemaPaths(schema); + + assertTrue(paths.contains("people.applicant.dateOfBirth")); + assertTrue(paths.contains("people.spouse.dateOfBirth")); + assertEquals(2, paths.size()); + } } diff --git a/builder-frontend/src/components/homeScreen/eligibilityCheckList/eligibilityCheckDetail/modals/ParameterModal.tsx b/builder-frontend/src/components/homeScreen/eligibilityCheckList/eligibilityCheckDetail/modals/ParameterModal.tsx index fe4f99cd..b4899b57 100644 --- a/builder-frontend/src/components/homeScreen/eligibilityCheckList/eligibilityCheckDetail/modals/ParameterModal.tsx +++ b/builder-frontend/src/components/homeScreen/eligibilityCheckList/eligibilityCheckDetail/modals/ParameterModal.tsx @@ -1,13 +1,13 @@ import { createStore } from "solid-js/store" -import type { ParameterDefinition } from "@/types"; +import type { ParameterDefinition, ParameterType } from "@/types"; type ParamValues = { key: string; label: string; required: boolean; - type: "string" | "number" | "boolean" | "date"; + type: ParameterType; } const ParameterModal = ( { actionTitle, modalAction, closeModal, initialData }: @@ -55,12 +55,13 @@ const ParameterModal = (
diff --git a/builder-frontend/src/components/project/manageBenefits/configureBenefit/modals/ConfigureCheckModal.tsx b/builder-frontend/src/components/project/manageBenefits/configureBenefit/modals/ConfigureCheckModal.tsx index fb35b334..a7d7027f 100644 --- a/builder-frontend/src/components/project/manageBenefits/configureBenefit/modals/ConfigureCheckModal.tsx +++ b/builder-frontend/src/components/project/manageBenefits/configureBenefit/modals/ConfigureCheckModal.tsx @@ -1,17 +1,13 @@ -import { Accessor, For } from "solid-js"; +import { Accessor, For, createSignal } from "solid-js"; import { createStore, SetStoreFunction } from "solid-js/store"; import { titleCase } from "@/utils/title_case"; import type { CheckConfig, - EligibilityCheck, ParameterDefinition, ParameterValues, BooleanParameter, - NumberParameter, - StringParameter, - DateParameter, } from "@/types"; const ConfigureCheckModal = ({ @@ -57,11 +53,19 @@ const ConfigureCheckModal = ({ {(parameter) => { return ( - tempCheck} - setTempCheck={setTempCheck} - parameter={() => parameter} - /> +
+
+ {titleCase(parameter.key)}{" "} + {parameter.required && *} +
+
+ tempCheck} + setTempCheck={setTempCheck} + parameter={() => parameter} + /> +
+
); }}
@@ -102,7 +106,6 @@ const ParameterInput = ({ return ( } currentValue={() => tempCheck().parameters[parameterKey()]} /> ); @@ -110,7 +113,6 @@ const ParameterInput = ({ return ( } currentValue={() => tempCheck().parameters[parameterKey()]} /> ); @@ -126,67 +128,60 @@ const ParameterInput = ({ return ( } currentValue={() => tempCheck().parameters[parameterKey()]} /> ); + } else if (parameterType() === "array") { + /* TODO: Support arrays of other types besides String */ + return ( + tempCheck().parameters[parameterKey()] as string[] | undefined} + /> + ); } return
Unsupported parameter type: {parameterType()}
; }; const ParameterNumberInput = ({ onParameterChange, - parameter, currentValue, }: { onParameterChange: (value: any) => void; - parameter: Accessor; currentValue: Accessor; }) => { return ( -
-
- {titleCase(parameter().key)}{" "} - {parameter().required && *} -
-
{parameter().label}
+ <> { onParameterChange(Number(e.target.value)); }} value={currentValue()} type="number" - class="form-input" + class="form-input-custom" /> -
+ ); }; const ParameterStringInput = ({ onParameterChange, - parameter, currentValue, }: { onParameterChange: (value: any) => void; - parameter: Accessor; currentValue: Accessor; }) => { return ( -
-
- {titleCase(parameter().key)}{" "} - {parameter().required && *} -
-
{parameter().label}
+ <> { onParameterChange(e.target.value); }} type="text" value={currentValue() ?? ""} - class="form-input" + class="form-input-custom" /> -
+ ); }; @@ -200,12 +195,7 @@ const ParameterBooleanInput = ({ currentValue: Accessor; }) => { return ( -
-
- {titleCase(parameter().key)}{" "} - {parameter().required && *} -
-
{parameter().label}
+ <>
Not set )}
-
+ ); }; const ParameterDateInput = ({ onParameterChange, - parameter, currentValue, }: { onParameterChange: (value: any) => void; - parameter: Accessor; currentValue: Accessor; }) => { return ( -
-
- {titleCase(parameter().key)}{" "} - {parameter().required && *} -
-
{parameter().label}
+ <> { onParameterChange(e.target.value); }} type="date" value={currentValue() ?? ""} - class="form-input" + class="form-input-custom" /> -
+ + ); +}; + +const ParameterMultiStringInput = ({ + onParameterChange, + currentValue, +}: { + onParameterChange: (value: string[]) => void; + currentValue: Accessor; +}) => { + const [inputValue, setInputValue] = createSignal(""); + + const values = () => currentValue() ?? []; + + const addValue = () => { + const trimmed = inputValue().trim(); + if (trimmed && !values().includes(trimmed)) { + onParameterChange([...values(), trimmed]); + setInputValue(""); + } + }; + + const removeValue = (index: number) => { + onParameterChange(values().filter((_, i) => i !== index)); + }; + + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === "Enter" || e.key === ",") { + e.preventDefault(); + addValue(); + } + }; + + return ( + <> + {/* Chip display */} +
+ + {(value, index) => ( + + {value} + + + )} + +
+ + {/* Input for adding new values */} +
+ setInputValue(e.target.value)} + onKeyDown={handleKeyDown} + placeholder="Type and press Enter to add" + class="form-input-custom flex-1" + /> +
+ Add +
+
+ ); }; diff --git a/builder-frontend/src/index.css b/builder-frontend/src/index.css index 3baf52d0..275781f7 100644 --- a/builder-frontend/src/index.css +++ b/builder-frontend/src/index.css @@ -30,6 +30,9 @@ .eligibility-check-table-cell { @apply px-4 py-3 border-gray-300; } + .form-input-custom { + @apply rounded-sm border-gray-400 border-2 py-2 px-3 h-9; + } } @layer utilities { .no-scrollbar::-webkit-scrollbar { diff --git a/builder-frontend/src/types.ts b/builder-frontend/src/types.ts index 47ab8f62..964566e0 100644 --- a/builder-frontend/src/types.ts +++ b/builder-frontend/src/types.ts @@ -63,10 +63,10 @@ export interface UpdateCheckRequest { } // Parameter Types +export type ParameterType = "string" | "number" | "boolean" | "date" | "array"; export type ParameterDefinition = | StringParameter - // StringSelectParameter | - // StringMultiInputParameter | + | StringMultiInputParameter | NumberParameter | BooleanParameter | DateParameter; @@ -75,13 +75,9 @@ interface BaseParameter { label: string; required: boolean; } -// export interface StringSelectParameter extends BaseParameter { -// type: "select"; -// options?: string; -// } -// export interface StringMultiInputParameter extends BaseParameter { -// type: "multi_input_string"; -// } +export interface StringMultiInputParameter extends BaseParameter { + type: "array"; +} export interface StringParameter extends BaseParameter { type: "string"; }