From b9a267d95885ea1f2ef071fc1d18b2aeb764e352 Mon Sep 17 00:00:00 2001 From: azeeee05 Date: Mon, 31 Aug 2026 22:55:32 +0530 Subject: [PATCH 1/3] feat: implement ActionBuilder and PolicyEngine API services and scaffold the AddPolicyEngine component. --- .../actionBuilder/ActionBuilderApi.ts | 3 ++- src/app/policyEngine/PolicyEngineApi.ts | 4 ++-- .../components/AddPolicyEngine.tsx | 22 +++++++++++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/app/configuration/actionBuilder/ActionBuilderApi.ts b/src/app/configuration/actionBuilder/ActionBuilderApi.ts index dd08187..a8f0ad2 100644 --- a/src/app/configuration/actionBuilder/ActionBuilderApi.ts +++ b/src/app/configuration/actionBuilder/ActionBuilderApi.ts @@ -68,7 +68,8 @@ export function deleteActionType(id: string): Promise { // ─── Field Definition Endpoints ────────────────────────────────────────────── export function getFieldDefinitions(actionTypeId: string): Promise { - return ApiClient.get(`/master-data/action-types/${actionTypeId}/fields`); + return ApiClient.get(`/master-data/action-types/${actionTypeId}/fields`) + .then(res => Array.isArray(res) ? res.sort((a, b) => (a.displayOrder ?? 0) - (b.displayOrder ?? 0)) : []); } export function createFieldDefinition(actionTypeId: string, payload: FieldDefinitionFormData): Promise { diff --git a/src/app/policyEngine/PolicyEngineApi.ts b/src/app/policyEngine/PolicyEngineApi.ts index 1101d9c..ff1f773 100644 --- a/src/app/policyEngine/PolicyEngineApi.ts +++ b/src/app/policyEngine/PolicyEngineApi.ts @@ -210,7 +210,7 @@ export function getOperatorOptions(): Promise { export function getActionTypeFields(actionTypeId: string): Promise { if (!actionTypeId) return Promise.resolve([]); return ApiClient.get(`/master-data/action-types/${actionTypeId}/fields`) - .then((res) => (Array.isArray(res) ? res.filter((f) => f.isActive !== false) : [])) + .then((res) => (Array.isArray(res) ? res.filter((f) => f.isActive !== false).sort((a, b) => (a.displayOrder ?? 0) - (b.displayOrder ?? 0)) : [])) .catch(() => []); } @@ -321,7 +321,7 @@ export function getConditionGroupsForCategory(categoryCodeOrId: string): Promise export function getConditionFieldsForGroup(groupIdOrCode: string): Promise { if (!groupIdOrCode) return Promise.resolve([]); return ApiClient.get(`/master-data/condition-groups/${groupIdOrCode}/fields`) - .then((res) => (Array.isArray(res) ? res.filter((f) => f.isActive !== false) : [])) + .then((res) => (Array.isArray(res) ? res.filter((f) => f.isActive !== false).sort((a, b) => (a.displayOrder ?? 0) - (b.displayOrder ?? 0)) : [])) .catch(() => []); } diff --git a/src/app/policyEngine/components/AddPolicyEngine.tsx b/src/app/policyEngine/components/AddPolicyEngine.tsx index ae5ba7d..d656bb1 100644 --- a/src/app/policyEngine/components/AddPolicyEngine.tsx +++ b/src/app/policyEngine/components/AddPolicyEngine.tsx @@ -396,6 +396,17 @@ export default function AddPolicyEngine() { const fields = await getActionTypeFields(selectedTypeId); setActionTypeFieldsMap((prev) => ({ ...prev, [selectedTypeId]: fields })); + // Pre-populate default values for the new action + const initialFieldValues: Record = {}; + fields.forEach((f) => { + const defaultVal = f.defaultValue ?? (f as any).default_value ?? (f as any).defaultValueJson ?? (f as any).default_value_json; + if (defaultVal !== undefined && defaultVal !== null && defaultVal !== '') { + initialFieldValues[f.fieldCode] = defaultVal; + } + }); + + handleUpdateAction(ruleId, actionId, { fieldValues: initialFieldValues }); + // Pre-fetch lookup options for fields requiring lookupSource const sourcesToFetch = new Set(); fields.forEach((f) => { @@ -413,6 +424,17 @@ export default function AddPolicyEngine() { } finally { setLoadingActionFields((prev) => ({ ...prev, [selectedTypeId]: false })); } + } else { + // Fields already loaded in map, just pre-populate default values + const fields = actionTypeFieldsMap[selectedTypeId] || []; + const initialFieldValues: Record = {}; + fields.forEach((f) => { + const defaultVal = f.defaultValue ?? (f as any).default_value ?? (f as any).defaultValueJson ?? (f as any).default_value_json; + if (defaultVal !== undefined && defaultVal !== null && defaultVal !== '') { + initialFieldValues[f.fieldCode] = defaultVal; + } + }); + handleUpdateAction(ruleId, actionId, { fieldValues: initialFieldValues }); } }; From 1ea8ce5522bd9ccac0d43c0ff76f70ce9bb3d4d8 Mon Sep 17 00:00:00 2001 From: azeeee05 Date: Mon, 31 Aug 2026 23:00:40 +0530 Subject: [PATCH 2/3] feat: implement ActionBuilder page and AddPolicyEngine component for configuration management --- src/app/configuration/actionBuilder/index.tsx | 6 +++--- src/app/policyEngine/components/AddPolicyEngine.tsx | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/configuration/actionBuilder/index.tsx b/src/app/configuration/actionBuilder/index.tsx index 3b459b5..0a25a86 100644 --- a/src/app/configuration/actionBuilder/index.tsx +++ b/src/app/configuration/actionBuilder/index.tsx @@ -95,7 +95,7 @@ export default function ActionBuilderPage() { placeholder: '', helpText: '', width: 'full', - section: 'General Information', + section: '', displayOrder: 1, isActive: true, validationJson: { min: undefined, max: undefined, regex: '' }, @@ -387,7 +387,7 @@ export default function ActionBuilderPage() { placeholder: '', helpText: '', width: 'full', - section: 'General Information', + section: '', displayOrder: fields.length + 1, isActive: true, validationJson: { min: undefined, max: undefined, regex: '' }, @@ -409,7 +409,7 @@ export default function ActionBuilderPage() { placeholder: f.placeholder || '', helpText: f.helpText || '', width: f.width || 'full', - section: f.section || 'General Information', + section: f.section || '', displayOrder: f.displayOrder || 1, isActive: f.isActive !== false, validationJson: f.validationJson || { min: undefined, max: undefined, regex: '' }, diff --git a/src/app/policyEngine/components/AddPolicyEngine.tsx b/src/app/policyEngine/components/AddPolicyEngine.tsx index d656bb1..ce5126d 100644 --- a/src/app/policyEngine/components/AddPolicyEngine.tsx +++ b/src/app/policyEngine/components/AddPolicyEngine.tsx @@ -400,7 +400,7 @@ export default function AddPolicyEngine() { const initialFieldValues: Record = {}; fields.forEach((f) => { const defaultVal = f.defaultValue ?? (f as any).default_value ?? (f as any).defaultValueJson ?? (f as any).default_value_json; - if (defaultVal !== undefined && defaultVal !== null && defaultVal !== '') { + if (defaultVal !== undefined && defaultVal !== null) { initialFieldValues[f.fieldCode] = defaultVal; } }); @@ -1444,7 +1444,7 @@ export default function AddPolicyEngine() { (field as any).default_value_json; const effectiveVal = - rawVal !== undefined && rawVal !== null && rawVal !== '' + rawVal !== undefined && rawVal !== null ? rawVal : defaultVal; From c7f2760abd2328ba9a4948a15c1cb1cca70eed47 Mon Sep 17 00:00:00 2001 From: azeeee05 Date: Tue, 1 Sep 2026 11:01:27 +0530 Subject: [PATCH 3/3] feat: implement AddPolicyEngine component for dynamic policy creation and rule management --- .../components/AddPolicyEngine.tsx | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/app/policyEngine/components/AddPolicyEngine.tsx b/src/app/policyEngine/components/AddPolicyEngine.tsx index ce5126d..2d92e59 100644 --- a/src/app/policyEngine/components/AddPolicyEngine.tsx +++ b/src/app/policyEngine/components/AddPolicyEngine.tsx @@ -822,8 +822,8 @@ export default function AddPolicyEngine() { // ─── Handlers ────────────────────────────────────────────────────────────── // Returns the lowest priority (1-10) not already used by an existing rule. - const findFreePriority = () => { - const taken = rules.map(r => r.priority); + const findFreePriority = (currentRules: Rule[]) => { + const taken = currentRules.map(r => r.priority); for (let p = 1; p <= 10; p++) { if (!taken.includes(p)) return p; } @@ -831,21 +831,21 @@ export default function AddPolicyEngine() { }; const handleAddRule = () => { - setRules([...rules, { + setRules(prevRules => [...prevRules, { id: crypto.randomUUID(), category: '', - priority: findFreePriority(), + priority: findFreePriority(prevRules), conditions: [{ id: crypto.randomUUID(), condition: '', operator: '', value: '', logic: 'AND' }], actions: [{ id: crypto.randomUUID(), actionCategoryId: '', actionTypeId: '', logic: 'AND', fieldValues: {} }] }]); }; const handleDeleteRule = (ruleId: string) => { - setRules(rules.filter(r => r.id !== ruleId)); + setRules(prevRules => prevRules.filter(r => r.id !== ruleId)); }; const handleUpdateRule = (ruleId: string, updates: Partial) => { - setRules(rules.map(r => r.id === ruleId ? { ...r, ...updates } : r)); + setRules(prevRules => prevRules.map(r => r.id === ruleId ? { ...r, ...updates } : r)); }; // Priorities used by every OTHER rule — a rule may never land on one of these. @@ -871,7 +871,7 @@ export default function AddPolicyEngine() { }; const handleAddCondition = (ruleId: string) => { - setRules(rules.map(r => { + setRules(prevRules => prevRules.map(r => { if (r.id === ruleId) { return { ...r, @@ -883,7 +883,7 @@ export default function AddPolicyEngine() { }; const handleUpdateCondition = (ruleId: string, conditionId: string, updates: Partial) => { - setRules(rules.map(r => { + setRules(prevRules => prevRules.map(r => { if (r.id === ruleId) { return { ...r, @@ -895,7 +895,7 @@ export default function AddPolicyEngine() { }; const handleDeleteCondition = (ruleId: string, conditionId: string) => { - setRules(rules.map(r => { + setRules(prevRules => prevRules.map(r => { if (r.id === ruleId) { return { ...r, conditions: r.conditions.filter(c => c.id !== conditionId) }; } @@ -904,7 +904,7 @@ export default function AddPolicyEngine() { }; const handleAddAction = (ruleId: string) => { - setRules(rules.map(r => { + setRules(prevRules => prevRules.map(r => { if (r.id === ruleId) { return { ...r, @@ -916,7 +916,7 @@ export default function AddPolicyEngine() { }; const handleUpdateAction = (ruleId: string, actionId: string, updates: Partial) => { - setRules(rules.map(r => { + setRules(prevRules => prevRules.map(r => { if (r.id === ruleId) { return { ...r, @@ -928,7 +928,7 @@ export default function AddPolicyEngine() { }; const handleDeleteAction = (ruleId: string, actionId: string) => { - setRules(rules.map(r => { + setRules(prevRules => prevRules.map(r => { if (r.id === ruleId) { return { ...r, actions: r.actions.filter(a => a.id !== actionId) }; }