From 19408df400faca57252d2ab5b4b00f97c9ccc628 Mon Sep 17 00:00:00 2001 From: Justin-MacIntosh Date: Sun, 29 Mar 2026 13:51:18 -0400 Subject: [PATCH] - feat: Added ability to define an "alias" name for a CheckConfig in a Benefit. - chore: Removed extra information from Check name/definitions on Published Screener View. --- .../controller/CustomBenefitResource.java | 66 ++++++++++++++++ .../org/acme/controller/DecisionResource.java | 1 + .../org/acme/model/domain/CheckConfig.java | 10 +++ .../UpdateCheckAliasRequest.java | 3 + builder-frontend/src/api/benefit.ts | 18 +++++ .../configureBenefit/ConfigureBenefit.tsx | 8 ++ .../SelectedEligibilityCheck.tsx | 38 ++++++++- .../configureBenefit/benefitResource.ts | 24 +++++- .../modals/EditAliasModal.tsx | 77 +++++++++++++++++++ .../components/project/preview/Results.tsx | 23 ++++-- .../src/components/project/preview/types.ts | 1 + .../screener/EligibilityResults.tsx | 34 +------- builder-frontend/src/types.ts | 3 + 13 files changed, 264 insertions(+), 42 deletions(-) create mode 100644 builder-api/src/main/java/org/acme/model/dto/CustomBenefit/UpdateCheckAliasRequest.java create mode 100644 builder-frontend/src/components/project/manageBenefits/configureBenefit/modals/EditAliasModal.tsx diff --git a/builder-api/src/main/java/org/acme/controller/CustomBenefitResource.java b/builder-api/src/main/java/org/acme/controller/CustomBenefitResource.java index 7134c029..46317fc3 100644 --- a/builder-api/src/main/java/org/acme/controller/CustomBenefitResource.java +++ b/builder-api/src/main/java/org/acme/controller/CustomBenefitResource.java @@ -12,6 +12,7 @@ import org.acme.model.domain.*; import org.acme.model.dto.CustomBenefit.AddCheckRequest; import org.acme.model.dto.CustomBenefit.CreateCustomBenefitRequest; +import org.acme.model.dto.CustomBenefit.UpdateCheckAliasRequest; import org.acme.model.dto.CustomBenefit.UpdateCheckParametersRequest; import org.acme.model.dto.CustomBenefit.UpdateCustomBenefitRequest; import org.acme.persistence.EligibilityCheckRepository; @@ -457,6 +458,71 @@ public Response updateCheckParameters( } } + @PATCH + @Consumes(MediaType.APPLICATION_JSON) + @Path("/screener/{screenerId}/benefit/{benefitId}/check/{checkId}/alias") + public Response updateCheckAlias( + @Context SecurityIdentity identity, + @PathParam("screenerId") String screenerId, + @PathParam("benefitId") String benefitId, + @PathParam("checkId") String checkId, + UpdateCheckAliasRequest request + ) { + String userId = AuthUtils.getUserId(identity); + + if (!isUserAuthorizedForScreener(userId, screenerId)) { + return Response.status(Response.Status.UNAUTHORIZED).build(); + } + + try { + // Get the benefit + Optional benefitOpt = screenerRepository.getCustomBenefit(screenerId, benefitId); + if (benefitOpt.isEmpty()) { + return Response.status(Response.Status.NOT_FOUND) + .entity(Map.of("error", "Benefit not found")) + .build(); + } + + Benefit benefit = benefitOpt.get(); + List checks = benefit.getChecks(); + + if (checks == null || checks.isEmpty()) { + return Response.status(Response.Status.NOT_FOUND) + .entity(Map.of("error", "Check not found in benefit")) + .build(); + } + + // Find and update the check with the matching checkId + Boolean checkUpdated = false; + List checkListAfterUpdate = new ArrayList<>(); + for (CheckConfig check : checks) { + if (check.getCheckId().equals(checkId)) { + check.setAliasName(request.aliasName()); + checkUpdated = true; + } + checkListAfterUpdate.add(check); + } + + if (!checkUpdated) { + return Response.status(Response.Status.NOT_FOUND) + .entity(Map.of("error", "Check not found in benefit")) + .build(); + } + + benefit.setChecks(checkListAfterUpdate); + + // Save the updated benefit + screenerRepository.updateCustomBenefit(screenerId, benefit); + + return Response.ok().build(); + } catch (Exception e) { + Log.error(e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(Map.of("error", "Could not update check alias")) + .build(); + } + } + // ========== Private Helper Methods ========== private boolean isUserAuthorizedForScreener(String userId, String screenerId) { diff --git a/builder-api/src/main/java/org/acme/controller/DecisionResource.java b/builder-api/src/main/java/org/acme/controller/DecisionResource.java index c50edb56..07b760f3 100644 --- a/builder-api/src/main/java/org/acme/controller/DecisionResource.java +++ b/builder-api/src/main/java/org/acme/controller/DecisionResource.java @@ -154,6 +154,7 @@ private Map evaluateBenefit(Benefit benefit, Map String uniqueCheckKey = checkConfig.getCheckId() + checkNum; Map checkResultMap = new HashMap<>(); checkResultMap.put("name", checkConfig.getCheckName()); + checkResultMap.put("aliasName", checkConfig.getAliasName()); checkResultMap.put("result", evaluationResult); checkResultMap.put("module", checkConfig.getCheckModule() != null ? checkConfig.getCheckModule() : ""); checkResultMap.put("version", checkConfig.getCheckVersion() != null ? checkConfig.getCheckVersion() : ""); diff --git a/builder-api/src/main/java/org/acme/model/domain/CheckConfig.java b/builder-api/src/main/java/org/acme/model/domain/CheckConfig.java index aebe9322..b3b5f43e 100644 --- a/builder-api/src/main/java/org/acme/model/domain/CheckConfig.java +++ b/builder-api/src/main/java/org/acme/model/domain/CheckConfig.java @@ -19,6 +19,8 @@ public class CheckConfig { private String evaluationUrl; private JsonNode inputDefinition; private List parameterDefinitions; + // optional alias name for this check instance + private String aliasName; public CheckConfig() { } @@ -116,4 +118,12 @@ public String getSourceCheckId() { public void setSourceCheckId(String sourceCheckId) { this.sourceCheckId = sourceCheckId; } + + public String getAliasName() { + return aliasName; + } + + public void setAliasName(String aliasName) { + this.aliasName = aliasName; + } } diff --git a/builder-api/src/main/java/org/acme/model/dto/CustomBenefit/UpdateCheckAliasRequest.java b/builder-api/src/main/java/org/acme/model/dto/CustomBenefit/UpdateCheckAliasRequest.java new file mode 100644 index 00000000..ab728c96 --- /dev/null +++ b/builder-api/src/main/java/org/acme/model/dto/CustomBenefit/UpdateCheckAliasRequest.java @@ -0,0 +1,3 @@ +package org.acme.model.dto.CustomBenefit; + +public record UpdateCheckAliasRequest(String aliasName) {} diff --git a/builder-frontend/src/api/benefit.ts b/builder-frontend/src/api/benefit.ts index a20deb2b..dca4be91 100644 --- a/builder-frontend/src/api/benefit.ts +++ b/builder-frontend/src/api/benefit.ts @@ -97,3 +97,21 @@ export const updateCheckParameters = async ( throw error; } }; + +export const updateCheckAlias = async ( + screenerId: string, + benefitId: string, + checkId: string, + aliasName: string | null +): Promise => { + const url = apiUrl + "/screener/" + screenerId + "/benefit/" + benefitId + "/check/" + checkId + "/alias"; + try { + const response = await authPatch(url.toString(), { aliasName }); + if (!response.ok) { + throw new Error(`Update alias failed with status: ${response.status}`); + } + } catch (error) { + console.error("Error updating check alias:", error); + throw error; + } +}; diff --git a/builder-frontend/src/components/project/manageBenefits/configureBenefit/ConfigureBenefit.tsx b/builder-frontend/src/components/project/manageBenefits/configureBenefit/ConfigureBenefit.tsx index 7ce1a887..57130819 100644 --- a/builder-frontend/src/components/project/manageBenefits/configureBenefit/ConfigureBenefit.tsx +++ b/builder-frontend/src/components/project/manageBenefits/configureBenefit/ConfigureBenefit.tsx @@ -116,6 +116,14 @@ const ConfigureBenefit = ({ newCheckData, ); }} + updateCheckConfigAlias={( + aliasName: string | null, + ) => { + actions.updateCheckConfigAlias( + checkConfig.checkId, + aliasName, + ); + }} /> ); }} diff --git a/builder-frontend/src/components/project/manageBenefits/configureBenefit/SelectedEligibilityCheck.tsx b/builder-frontend/src/components/project/manageBenefits/configureBenefit/SelectedEligibilityCheck.tsx index 643abe30..18bb0972 100644 --- a/builder-frontend/src/components/project/manageBenefits/configureBenefit/SelectedEligibilityCheck.tsx +++ b/builder-frontend/src/components/project/manageBenefits/configureBenefit/SelectedEligibilityCheck.tsx @@ -1,6 +1,7 @@ import { Accessor, createSignal, For, Show } from "solid-js"; import ConfigureCheckModal from "./modals/ConfigureCheckModal"; +import EditAliasModal from "./modals/EditAliasModal"; import { titleCase } from "@/utils/title_case"; @@ -9,18 +10,25 @@ import type { ParameterDefinition, ParameterValues, } from "@/types"; +import { PencilIcon } from "lucide-solid"; const SelectedEligibilityCheck = ({ checkConfig, onRemove, updateCheckConfigParams, + updateCheckConfigAlias, }: { checkConfig: Accessor; updateCheckConfigParams: (newCheckData: ParameterValues) => void; + updateCheckConfigAlias: (aliasName: string | null) => void; onRemove: () => void | null; }) => { const [configuringCheckModalOpen, setConfiguringCheckModalOpen] = createSignal(false); + const [editAliasModalOpen, setEditAliasModalOpen] = createSignal(false); + + const displayName = () => + checkConfig().aliasName || checkConfig().checkName; const unfilledRequiredParameters = () => { return []; @@ -47,9 +55,25 @@ const SelectedEligibilityCheck = ({ X -
- {titleCase(checkConfig().checkName)} - {checkConfig().checkVersion} +
+ {titleCase(displayName())} + - {checkConfig().checkVersion} +
{ + e.stopPropagation(); + setEditAliasModalOpen(true); + }} + title="Edit alias" + > + +
+ +
+ Original: {checkConfig().checkName} +
+
{checkConfig().checkDescription}
@@ -97,6 +121,16 @@ const SelectedEligibilityCheck = ({ }} /> )} + + {editAliasModalOpen() && ( + { + setEditAliasModalOpen(false); + }} + /> + )} ); }; diff --git a/builder-frontend/src/components/project/manageBenefits/configureBenefit/benefitResource.ts b/builder-frontend/src/components/project/manageBenefits/configureBenefit/benefitResource.ts index 81ae458c..181c391a 100644 --- a/builder-frontend/src/components/project/manageBenefits/configureBenefit/benefitResource.ts +++ b/builder-frontend/src/components/project/manageBenefits/configureBenefit/benefitResource.ts @@ -5,7 +5,8 @@ import { fetchScreenerBenefit, addCheckToBenefit, removeCheckFromBenefit, - updateCheckParameters + updateCheckParameters, + updateCheckAlias } from "@/api/benefit"; import type { Benefit, ParameterValues } from "@/types"; @@ -19,6 +20,10 @@ interface ScreenerBenefitsResource { checkId: string, parameters: ParameterValues ) => void; + updateCheckConfigAlias: ( + checkId: string, + aliasName: string | null + ) => void; }; actionInProgress: Accessor; initialLoadStatus: { @@ -92,12 +97,29 @@ const createScreenerBenefits = ( setActionInProgress(false); }; + const updateCheckConfigAlias = async ( + checkId: string, + aliasName: string | null + ) => { + if (!benefit) return; + setActionInProgress(true); + + try { + await updateCheckAlias(screenerId(), benefitId(), checkId, aliasName); + await refetch(); + } catch (e) { + console.error("Failed to update check alias", e); + } + setActionInProgress(false); + }; + return { benefit: () => benefit, actions: { addCheck, removeCheck, updateCheckConfigParams, + updateCheckConfigAlias, }, actionInProgress, initialLoadStatus: { diff --git a/builder-frontend/src/components/project/manageBenefits/configureBenefit/modals/EditAliasModal.tsx b/builder-frontend/src/components/project/manageBenefits/configureBenefit/modals/EditAliasModal.tsx new file mode 100644 index 00000000..b7c216fe --- /dev/null +++ b/builder-frontend/src/components/project/manageBenefits/configureBenefit/modals/EditAliasModal.tsx @@ -0,0 +1,77 @@ +import { Accessor, createSignal } from "solid-js"; + +import { titleCase } from "@/utils/title_case"; + +import type { CheckConfig } from "@/types"; + +const EditAliasModal = ({ + checkConfig, + updateCheckConfigAlias, + closeModal, +}: { + checkConfig: Accessor; + updateCheckConfigAlias: (aliasName: string | null) => void; + closeModal: () => void; +}) => { + const [aliasValue, setAliasValue] = createSignal( + checkConfig().aliasName ?? "" + ); + + const confirmAndClose = () => { + const trimmedValue = aliasValue().trim(); + updateCheckConfigAlias(trimmedValue === "" ? null : trimmedValue); + closeModal(); + }; + + const clearAlias = () => { + setAliasValue(""); + }; + + return ( +
+
+
+ Edit Alias: {titleCase(checkConfig().checkName)} +
+ +
+
+ Set an alias name to display instead of the check's original name. + Leave empty to use the original name. +
+
+ setAliasValue(e.target.value)} + placeholder={checkConfig().checkName} + class="form-input-custom flex-1" + /> + {aliasValue() && ( + + )} +
+
+ +
+ + +
+
+
+ ); +}; + +export default EditAliasModal; diff --git a/builder-frontend/src/components/project/preview/Results.tsx b/builder-frontend/src/components/project/preview/Results.tsx index b30cc070..c127f048 100644 --- a/builder-frontend/src/components/project/preview/Results.tsx +++ b/builder-frontend/src/components/project/preview/Results.tsx @@ -102,14 +102,23 @@ export default function Results({
-
- {check.name} - - - ({[check.module, check.version].filter(Boolean).join(" v")}) + + {check.name} + + + ({[check.module, check.version].filter(Boolean).join(", v")}) + + +
+ }> +
+ {check.aliasName} + + ({check.name}, {[check.module, check.version].filter(Boolean).join(", v")}) - -
+
+ 0}>
{formatParameters(check.parameters)} diff --git a/builder-frontend/src/components/project/preview/types.ts b/builder-frontend/src/components/project/preview/types.ts index b5982d8f..8f414141 100644 --- a/builder-frontend/src/components/project/preview/types.ts +++ b/builder-frontend/src/components/project/preview/types.ts @@ -13,6 +13,7 @@ interface BenefitResult { } interface CheckResult { name: string; + aliasName?: string; result: OptionalBoolean; module: string; version: string; diff --git a/builder-frontend/src/components/screener/EligibilityResults.tsx b/builder-frontend/src/components/screener/EligibilityResults.tsx index 590748e6..887576d7 100644 --- a/builder-frontend/src/components/screener/EligibilityResults.tsx +++ b/builder-frontend/src/components/screener/EligibilityResults.tsx @@ -65,44 +65,14 @@ function BenefitResult({ benefitResult }: { benefitResult: BenefitResult }) {
-
- {check.name} - - - ({[check.module, check.version].filter(Boolean).join(" v")}) - - -
- 0}> -
- {formatParameters(check.parameters)} -
+ {check.name}
}> +
{check.aliasName}
)} - {/* {benefit.info && ( -
-

Overview

-

{benefit.info}

-
- )} - {benefit.appLink && ( - - )} */} ); } diff --git a/builder-frontend/src/types.ts b/builder-frontend/src/types.ts index 5a7c95d1..53bfff2c 100644 --- a/builder-frontend/src/types.ts +++ b/builder-frontend/src/types.ts @@ -28,6 +28,8 @@ export interface CheckConfig { parameters: ParameterValues; inputDefinition: JSONSchema7; parameterDefinitions: ParameterDefinition[]; + // Optional user-defined alias for display purposes + aliasName?: string; } export interface ParameterValues { [key: string]: string | number | boolean | string[]; @@ -122,6 +124,7 @@ export interface BenefitResult { } export interface CheckResult { name: string; + aliasName?: string; result: OptionalBoolean; module: string; version: string;