Skip to content

Commit 965299f

Browse files
Added Create Parameter and Create Check functionalities
1 parent 8add832 commit 965299f

9 files changed

Lines changed: 207 additions & 57 deletions

File tree

builder-api/src/main/java/org/acme/controller/EligibilityCheckResource.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ public Response getCheck(@Context SecurityIdentity identity, @PathParam("checkId
6060
return Response.status(Response.Status.UNAUTHORIZED).build();
6161
}
6262
return Response.ok(check, MediaType.APPLICATION_JSON).build();
63-
6463
}
6564

6665
// Utility endpoint to create an Eligibility check
@@ -106,7 +105,6 @@ public Response updateCheck(@Context SecurityIdentity identity,
106105
@Consumes(MediaType.APPLICATION_JSON)
107106
@Path("/save-check-dmn")
108107
public Response updateCheckDmn(@Context SecurityIdentity identity, SaveDmnRequest saveDmnRequest){
109-
110108
String checkId = saveDmnRequest.id;
111109
String dmnModel = saveDmnRequest.dmnModel;
112110
if (checkId == null || checkId.isBlank()){
@@ -138,7 +136,7 @@ public Response updateCheckDmn(@Context SecurityIdentity identity, SaveDmnReques
138136
storageService.writeStringToStorage(filePath, dmnModel, "application/xml");
139137
Log.info("Saved DMN model of check " + checkId + " to storage");
140138

141-
//TODO: Need to figure out if we are allowing DMN versions to be mutable. If so, we need to update a
139+
// TODO: Need to figure out if we are allowing DMN versions to be mutable. If so, we need to update a
142140
// last_saved field so that we know the check was updated and needs to be recompiled on evaluation
143141

144142
return Response.ok().build();

builder-frontend/src/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import Project from "./components/project/Project";
44
import AuthForm from "./components/auth/AuthForm";
55
import { useAuth } from "./context/AuthContext";
66
import HomeScreen from "./components/homeScreen/HomeScreen";
7-
import EligibilityCheckDetail from "./components/eligibilityCheck/EligibilityCheckDetail";
7+
import EligibilityCheckDetail from "./components/homeScreen/eligibilityCheckList/eligibilityCheckDetail/EligibilityCheckDetail";
88

99

1010
function App() {

builder-frontend/src/api/check.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,29 @@ export const addCheck = async (check: EligibilityCheck) => {
7272
}
7373
};
7474

75+
export const updateCheck = async (check: EligibilityCheck) => {
76+
const url = apiUrl + "/check";
77+
try {
78+
const response = await authFetch(url, {
79+
method: "PUT",
80+
headers: {
81+
"Content-Type": "application/json",
82+
Accept: "application/json",
83+
},
84+
body: JSON.stringify(check),
85+
});
86+
87+
if (!response.ok) {
88+
throw new Error(`Update failed with status: ${response.status}`);
89+
}
90+
const data = await response.json();
91+
return data;
92+
} catch (error) {
93+
console.error("Error updating check:", error);
94+
throw error; // rethrow so you can handle it in your component if needed
95+
}
96+
};
97+
7598
export const fetchUserDefinedChecks = async (): Promise<EligibilityCheck[]> => {
7699
// Simulate an API call delay -- TODO: update to greater than 1ms delay
77100
await new Promise((resolve) => setTimeout(resolve, 1000));

builder-frontend/src/components/homeScreen/eligibilityCheckList/EligibilityChecksList.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { createSignal, For, Show } from "solid-js";
22
import { useNavigate } from "@solidjs/router";
33

44
import Loading from "@/components/Loading";
5-
import AddNewCheckModal from "./modals/AddNewCheckModal";
5+
import CheckModal from "./modals/CheckModal";
66
import eligibilityCheckResource from "./eligibilityCheckResource";
77

88
import type { EligibilityCheck } from "@/types";
@@ -19,14 +19,15 @@ const EligibilityChecksList = () => {
1919
}
2020

2121
return (
22-
<div class="p-4">
22+
<div class="px-12 py-8">
2323
<Show when={initialLoadStatus.loading() || actionInProgress()}>
2424
<Loading/>
2525
</Show>
2626
<div class="text-3xl font-bold mb-2 tracking-wide">
2727
Eligibility Checks
2828
</div>
29-
<div class="text-lg mb-3"> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
29+
<div class="text-lg mb-3">
30+
Manage your eligibility checks here. Click on a check to view or edit its details.
3031
</div>
3132
<div
3233
class="btn-default btn-blue mb-3 mr-1"
@@ -49,9 +50,9 @@ const EligibilityChecksList = () => {
4950
</div>
5051
{
5152
addingNewCheck() &&
52-
<AddNewCheckModal
53+
<CheckModal
5354
closeModal={() => setAddingNewCheck(false)}
54-
addNewCheck={actions.addNewCheck}
55+
modalAction={actions.addNewCheck}
5556
/>
5657
}
5758
</div>

builder-frontend/src/components/eligibilityCheck/EligibilityCheckDetail.tsx renamed to builder-frontend/src/components/homeScreen/eligibilityCheckList/eligibilityCheckDetail/EligibilityCheckDetail.tsx

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
import { Accessor, createSignal, For, Match, Show, Switch } from "solid-js";
22
import { useParams } from "@solidjs/router";
33

4-
import Header from "../Header";
5-
import Loading from "../Loading";
6-
import eligibilityCheckResource from "./eligibilityCheckResource";
4+
import Header from "../../../Header";
5+
import Loading from "../../../Loading";
6+
import eligibilityCheckDetailResource from "./eligibilityCheckDetailResource";
77

8-
import type { EligibilityCheck } from "@/types";
8+
import type { EligibilityCheck, ParameterDefinition } from "@/types";
9+
import ParameterModal from "./modals/ParameterModal";
910

1011

1112
const EligibilityCheckDetail = () => {
1213
const { checkId } = useParams();
1314

1415
const [screenMode, setScreenMode] = createSignal<"inputs_params" | "dmn">("inputs_params");
1516

16-
const { eligibilityCheck, actions, actionInProgress, initialLoadStatus } = eligibilityCheckResource(() => checkId);
17+
const { eligibilityCheck, actions, actionInProgress, initialLoadStatus } = (
18+
eligibilityCheckDetailResource(() => checkId)
19+
);
1720

1821
return (
1922
<div>
@@ -39,7 +42,7 @@ const EligibilityCheckDetail = () => {
3942
<Show when={eligibilityCheck().id !== undefined && !initialLoadStatus.loading()}>
4043
<Switch>
4144
<Match when={screenMode() === "inputs_params"}>
42-
<InputsParams eligibilityCheck={eligibilityCheck}/>
45+
<ParametersScreen eligibilityCheck={eligibilityCheck} addParameter={actions.addParameter}/>
4346
</Match>
4447
<Match when={screenMode() === "dmn"}>
4548
<div class="p-2">
@@ -52,31 +55,24 @@ const EligibilityCheckDetail = () => {
5255
);
5356
};
5457

55-
const InputsParams = ({eligibilityCheck}: {eligibilityCheck: Accessor<EligibilityCheck>}) => {
58+
const ParametersScreen = (
59+
{eligibilityCheck, addParameter}:
60+
{eligibilityCheck: Accessor<EligibilityCheck>; addParameter: (parameter: ParameterDefinition) => Promise<void>}
61+
) => {
62+
const [addingParameter, setAddingParameter] = createSignal<boolean>(false);
63+
5664
return (
5765
<div class="p-12">
5866
<div class="text-3xl font-bold tracking-wide mb-2">{eligibilityCheck().name}</div>
5967
<p class="text-xl mb-4">{eligibilityCheck().description}</p>
6068
<div class="p-2">
61-
<h2 class="text-xl font-semibold mb-2">Inputs</h2>
62-
<Show when={eligibilityCheck().inputs.length > 0} fallback={<p>No inputs defined.</p>}>
63-
<ul class="list-disc list-inside">
64-
<For each={eligibilityCheck().inputs}>
65-
{(input) => (
66-
<div
67-
class="border-2 border-gray-200 rounded p-4 w-80 hover:shadow-lg hover:bg-gray-200 cursor-pointer"
68-
onClick={() => {}}
69-
>
70-
<div class="text-lg font-bold text-gray-800 mb-2">{input.key}</div>
71-
<div><span class="font-bold">Type:</span> {input.type}</div>
72-
<div><span class="font-bold">Prompt:</span> {input.prompt}</div>
73-
</div>
74-
)}
75-
</For>
76-
</ul>
77-
</Show>
78-
7969
<h2 class="text-xl font-semibold mb-2">Parameters</h2>
70+
<div
71+
class="btn-default btn-blue mb-3 mr-1"
72+
onClick={() => {setAddingParameter(true)}}
73+
>
74+
Create New Parameter
75+
</div>
8076
<Show when={eligibilityCheck().parameters.length > 0} fallback={<p>No parameters defined.</p>}>
8177
<ul class="list-disc list-inside">
8278
<For each={eligibilityCheck().parameters}>
@@ -95,6 +91,14 @@ const InputsParams = ({eligibilityCheck}: {eligibilityCheck: Accessor<Eligibilit
9591
</ul>
9692
</Show>
9793
</div>
94+
{
95+
addingParameter() &&
96+
<ParameterModal
97+
actionTitle="Add Parameter"
98+
closeModal={() => setAddingParameter(false)}
99+
modalAction={addParameter}
100+
/>
101+
}
98102
</div>
99103
);
100104
}

builder-frontend/src/components/eligibilityCheck/eligibilityCheckResource.ts renamed to builder-frontend/src/components/homeScreen/eligibilityCheckList/eligibilityCheckDetail/eligibilityCheckDetailResource.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import { createResource, createEffect, Accessor, createSignal } from "solid-js";
22
import { createStore } from "solid-js/store";
33

4-
import { fetchCheck } from "../../api/check";
4+
import { fetchCheck, updateCheck } from "@/api/check";
55

66
import type { EligibilityCheck, ParameterDefinition } from "@/types";
77

88

9-
export interface ScreenerBenefitsResource {
9+
export interface EligibilityCheckDetailResource {
1010
eligibilityCheck: () => EligibilityCheck;
1111
actions: {
12-
addParameter: (parameterDef: ParameterDefinition) => void;
12+
addParameter: (parameterDef: ParameterDefinition) => Promise<void>;
1313
};
1414
actionInProgress: Accessor<boolean>;
1515
initialLoadStatus: {
@@ -18,7 +18,7 @@ export interface ScreenerBenefitsResource {
1818
};
1919
}
2020

21-
const createScreenerBenefits = (checkId: Accessor<string>): ScreenerBenefitsResource => {
21+
const eligibilityCheckDetailResource = (checkId: Accessor<string>): EligibilityCheckDetailResource => {
2222
const [eligibilityCheckResource, { refetch }] = createResource(() => checkId(), fetchCheck);
2323
const [actionInProgress, setActionInProgress] = createSignal<boolean>(false);
2424

@@ -32,21 +32,21 @@ const createScreenerBenefits = (checkId: Accessor<string>): ScreenerBenefitsReso
3232
}
3333
});
3434

35-
const addParameter = (parameterDef: ParameterDefinition) => {
36-
if (!eligibilityCheck) return;
35+
const addParameter = async (parameterDef: ParameterDefinition) => {
36+
const updatedCheck: EligibilityCheck = { ...eligibilityCheck, parameters: [...eligibilityCheck.parameters, parameterDef] };
3737
setActionInProgress(true);
38-
setTimeout(() => {
39-
// Simulate async action
40-
setEligibilityCheck("parameters", (params) => [...params, parameterDef]);
41-
setActionInProgress(false);
42-
}, 500);
38+
try {
39+
await updateCheck(updatedCheck);
40+
await refetch();
41+
} catch (e) {
42+
console.error("Failed to add parameter", e);
43+
}
44+
setActionInProgress(false);
4345
};
4446

4547
return {
4648
eligibilityCheck: () => eligibilityCheck,
47-
actions: {
48-
addParameter,
49-
},
49+
actions: { addParameter },
5050
actionInProgress,
5151
initialLoadStatus: {
5252
loading: () => eligibilityCheckResource.loading,
@@ -55,4 +55,4 @@ const createScreenerBenefits = (checkId: Accessor<string>): ScreenerBenefitsReso
5555
};
5656
};
5757

58-
export default createScreenerBenefits;
58+
export default eligibilityCheckDetailResource;
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import { createStore } from "solid-js/store"
2+
3+
import type { EligibilityCheck, ParameterDefinition } from "@/types";
4+
import { Accessor } from "solid-js";
5+
6+
7+
type ParamValues = {
8+
key: string;
9+
label: string;
10+
required: boolean;
11+
type: "string" | "number" | "boolean";
12+
}
13+
const ParameterModal = (
14+
{ actionTitle, modalAction, closeModal }:
15+
{ actionTitle: string, modalAction: (parameter: ParameterDefinition) => Promise<void>; closeModal: () => void }
16+
) => {
17+
const [newParam, setNewParam] = createStore<ParamValues>({ key: "", type: "string", label: "", required: undefined });
18+
19+
// Styling for the Add button based on whether fields are filled
20+
const isAddDisabled = () => {
21+
return (
22+
newParam.key.trim() === "" ||
23+
newParam.label.trim() === ""
24+
);
25+
}
26+
const addButtonClasses = () => {
27+
return isAddDisabled() ? "opacity-50 cursor-not-allowed" : "hover:bg-sky-700";
28+
}
29+
30+
return (
31+
<div class="fixed inset-0 bg-black/40 flex items-center justify-center z-50">
32+
<div class="bg-white px-12 py-8 rounded-xl max-w-140 w-1/2 min-w-80 min-h-96">
33+
<div class="text-2xl font-bold mb-4">{actionTitle}</div>
34+
<div class="mb-4">
35+
<label class="block font-bold mb-2">Key:</label>
36+
<input
37+
type="text"
38+
class="w-full border border-gray-300 rounded px-3 py-2"
39+
value={newParam.key}
40+
onInput={(e) => setNewParam("key", e.currentTarget.value)}
41+
placeholder="Enter parameter key"
42+
/>
43+
</div>
44+
<div class="mb-4">
45+
<label class="block font-bold mb-2">Label:</label>
46+
<input
47+
type="text"
48+
class="w-full border border-gray-300 rounded px-3 py-2"
49+
value={newParam.label}
50+
onInput={(e) => setNewParam("label", e.currentTarget.value)}
51+
placeholder="Enter parameter label"
52+
/>
53+
</div>
54+
<div class="mb-4">
55+
<label class="block font-bold mb-2">Type:</label>
56+
<select
57+
class="w-full border border-gray-300 rounded px-3 py-2"
58+
value={newParam.type}
59+
onChange={(e) => setNewParam("type", e.currentTarget.value as "string" | "number" | "boolean")}
60+
>
61+
<option value="string">String</option>
62+
<option value="number">Number</option>
63+
<option value="boolean">Boolean</option>
64+
</select>
65+
</div>
66+
<div class="mb-4">
67+
<label class="block font-bold mb-2">Required:</label>
68+
<div class="flex items-center gap-3">
69+
<div class="flex items-center gap-2">
70+
<input
71+
type="radio"
72+
name={`param-required`}
73+
checked={newParam.required === true}
74+
onInput={() => setNewParam("required", true)}
75+
/>
76+
True
77+
</div>
78+
<div class="flex items-center gap-2">
79+
<input
80+
type="radio"
81+
name={`param-required`}
82+
checked={newParam.required === false}
83+
onInput={() => setNewParam("required", false)}
84+
/>
85+
False
86+
</div>
87+
{
88+
newParam.required === undefined &&
89+
<span class="ml-2 text-gray-500">Not set</span>
90+
}
91+
</div>
92+
</div>
93+
<div class="flex justify-end space-x-2">
94+
<div
95+
class="btn-default hover:bg-gray-200"
96+
onClick={() => { closeModal(); }}
97+
>
98+
Cancel
99+
</div>
100+
<div
101+
class={"btn-default bg-sky-600 text-white " + addButtonClasses()}
102+
onClick={async () => {
103+
if (isAddDisabled()) {
104+
console.log("Please fill in all fields.");
105+
return;
106+
}
107+
const parameter: ParameterDefinition = {
108+
key: newParam.key,
109+
label: newParam.label,
110+
type: newParam.type,
111+
required: newParam.required
112+
};
113+
await modalAction(parameter);
114+
closeModal();
115+
}}
116+
>
117+
{actionTitle}
118+
</div>
119+
</div>
120+
</div>
121+
</div>
122+
);
123+
}
124+
export default ParameterModal;

0 commit comments

Comments
 (0)