diff --git a/app/admin/page.tsx b/app/admin/page.tsx index db2371e..e5c7732 100644 --- a/app/admin/page.tsx +++ b/app/admin/page.tsx @@ -4,7 +4,7 @@ import Link from "next/link"; import { Table, Input, Button, Flex } from "antd"; import { ColumnsType } from "antd/es/table"; import { RuleInfo } from "../types/ruleInfo"; -import { getAllRuleData, postRuleData, updateRuleData, deleteRuleData } from "../utils/api"; +import { getAllRuleData, getAllRuleDocuments, postRuleData, updateRuleData, deleteRuleData } from "../utils/api"; enum ACTION_STATUS { NEW = "new", @@ -18,9 +18,18 @@ export default function Admin() { const [rules, setRules] = useState([]); const getOrRefreshRuleList = async () => { - const data = await getAllRuleData(); - setInitialRules(data); - setRules(JSON.parse(JSON.stringify(data))); // JSON.parse(JSON.stringify(data)) is a hacky way to deep copy the data - needed for comparison later + // Get rules that are already defined in the DB + const existingRules = await getAllRuleData(); + setInitialRules(existingRules); + // Get rules that exist in the rules repository, but aren't yet defined in the DB + const existingRuleDocuments = await getAllRuleDocuments(); + const undefinedRules = existingRuleDocuments + .filter((ruleJSON: string) => { + return !existingRules.find((rule: RuleInfo) => rule.goRulesJSONFilename === ruleJSON); + }) + .map((ruleJSON: string) => ({ goRulesJSONFilename: ruleJSON })); + const ruleData = [...existingRules, ...undefinedRules]; + setRules(JSON.parse(JSON.stringify(ruleData))); // JSON.parse(JSON.stringify(data)) is a hacky way to deep copy the data - needed for comparison later setIsLoading(false); }; @@ -82,19 +91,19 @@ export default function Admin() { const entriesToUpdate = getRulesToUpdate(); await Promise.all( entriesToUpdate.map(async ({ rule, action }) => { - if (rule?._id) { try { if (action === ACTION_STATUS.NEW) { await postRuleData(rule); - } else if (action === ACTION_STATUS.UPDATE) { - await updateRuleData(rule._id, rule); - } else if (action === ACTION_STATUS.DELETE) { - await deleteRuleData(rule._id); + } else if (rule?._id) { + if (action === ACTION_STATUS.UPDATE) { + await updateRuleData(rule._id, rule); + } else if (action === ACTION_STATUS.DELETE) { + await deleteRuleData(rule._id); + } } } catch (error) { console.error(`Error performing action ${action} on rule ${rule._id}: ${error}`); } - } }) ); getOrRefreshRuleList(); @@ -113,6 +122,7 @@ export default function Admin() { title: "Title", dataIndex: "title", render: renderInputField("title"), + width: "220px" }, { title: "GoRules Id", @@ -123,6 +133,7 @@ export default function Admin() { title: "GoRules JSON Filename", dataIndex: "goRulesJSONFilename", render: renderInputField("goRulesJSONFilename"), + width: "260px" }, { title: "CHEFS Form Id", diff --git a/app/components/RulesDecisionGraph/RulesDecisionGraph.tsx b/app/components/RulesDecisionGraph/RulesDecisionGraph.tsx index 477a750..0ea98be 100644 --- a/app/components/RulesDecisionGraph/RulesDecisionGraph.tsx +++ b/app/components/RulesDecisionGraph/RulesDecisionGraph.tsx @@ -11,7 +11,6 @@ import styles from "./RulesDecisionGraph.module.css"; interface RulesViewerProps { jsonFile: string; - docId: string; contextToSimulate?: SubmissionData | null; setResultsOfSimulation: (results: Record) => void; } diff --git a/app/components/SimulationViewer/SimulationViewer.tsx b/app/components/SimulationViewer/SimulationViewer.tsx index 5cfdcbe..0dfeb33 100644 --- a/app/components/SimulationViewer/SimulationViewer.tsx +++ b/app/components/SimulationViewer/SimulationViewer.tsx @@ -14,11 +14,10 @@ const RulesDecisionGraph = dynamic(() => import("../RulesDecisionGraph"), { ssr: interface SimulationViewerProps { jsonFile: string; - docId: string; chefsFormId: string; } -export default function SimulationViewer({ jsonFile, docId, chefsFormId }: SimulationViewerProps) { +export default function SimulationViewer({ jsonFile, chefsFormId }: SimulationViewerProps) { const [selectedSubmissionInputs, setSelectedSubmissionInputs] = useState(); const [contextToSimulate, setContextToSimulate] = useState(); const [resultsOfSimulation, setResultsOfSimulation] = useState | null>(); @@ -43,7 +42,6 @@ export default function SimulationViewer({ jsonFile, docId, chefsFormId }: Simul
diff --git a/app/page.tsx b/app/page.tsx index 0d60245..db52f81 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -27,7 +27,7 @@ export default function Home() { key: _id, titleLink: ( - {title} + {title || goRulesJSONFilename} ), downloadRule: ( diff --git a/app/rule/[ruleId]/page.tsx b/app/rule/[ruleId]/page.tsx index c9abdd2..74b1d6b 100644 --- a/app/rule/[ruleId]/page.tsx +++ b/app/rule/[ruleId]/page.tsx @@ -17,7 +17,7 @@ export default async function Rule({ params: { ruleId } }: { params: { ruleId: s -

{title}

+

{title || goRulesJSONFilename}

diff --git a/app/utils/api.ts b/app/utils/api.ts index aa07867..5cda18e 100644 --- a/app/utils/api.ts +++ b/app/utils/api.ts @@ -11,56 +11,66 @@ const axiosAPIInstance = axios.create({ }); /** - * Retrieves a document from the API based on the provided document ID. - * @param docId The ID of the document to retrieve. - * @returns The content of the document. - * @throws If an error occurs while retrieving the document. + * Retrieves a rule data from the API based on the provided rule ID. + * @param ruleId The ID of the rule data to retrieve. + * @returns The rule data. + * @throws If an error occurs while retrieving the rule data. */ -export const getDocument = async (jsonFile: string): Promise => { +export const getRuleDataById = async (ruleId: string): Promise => { try { - const { data } = await axiosAPIInstance.get(`/documents/${jsonFile}`); - if (!data || !data.nodes || !data.edges) { - throw new Error("Unexpected format of the returned data"); - } + const { data } = await axiosAPIInstance.get(`/ruleData/${ruleId}`); return data; } catch (error) { - console.error(`Error getting the gorules document: ${error}`); + console.error(`Error getting rule data: ${error}`); throw error; } }; /** - * Posts a decision to the API for evaluation. - * @param jsonFile The JSON file to use for the decision. - * @param decisionGraph The decision graph to evaluate. - * @param context The context for the decision evaluation. - * @returns The result of the decision evaluation. - * @throws If an error occurs while simulating the decision. + * Retrieves all rules data from the API. + * @returns The rule data list. + * @throws If an error occurs while fetching the rule data. */ -export const postDecision = async (jsonFile: string, context: unknown) => { +export const getAllRuleData = async (): Promise => { try { - const { data } = await axiosAPIInstance.post(`/decisions/evaluate/${jsonFile}`, { - context, - trace: true, - }); + const { data } = await axiosAPIInstance.get("/ruleData/list"); return data; } catch (error) { - console.error(`Error simulating decision: ${error}`); + console.error(`Error fetching rule data: ${error}`); throw error; } }; /** - * Retrieves submissions from the CHEFS API. - * @returns The submissions data. - * @throws If an error occurs while fetching the submissions. + * Gets list of all rule documents + * @returns The rule documents list. + * @throws If an error occurs while fetching the rule documents list. */ -export const getSubmissionsFromCHEFS = async (formId: string) => { +export const getAllRuleDocuments = async (): Promise => { try { - const { data } = await axiosAPIInstance.get(`/submissions/list/${formId}`); + const { data } = await axiosAPIInstance.get("/documents"); return data; } catch (error) { - console.error(`Error fetching submissions: ${error}`); + console.error(`Error fetching rule data: ${error}`); + throw error; + } +}; + +/** + * Retrieves a document from the API based on the provided document ID. + * @param docId The ID of the document to retrieve. + * @returns The content of the document. + * @throws If an error occurs while retrieving the document. + */ +export const getDocument = async (jsonFilePath: string): Promise => { + try { + const { data } = await axiosAPIInstance.get(`/documents/${encodeURIComponent(jsonFilePath)}`); + if (!data || !data.nodes || !data.edges) { + throw new Error("Unexpected format of the returned data"); + } + return data; + } catch (error) { + console.error(`Error getting the gorules document: ${error}`); throw error; } }; @@ -70,9 +80,9 @@ export const getSubmissionsFromCHEFS = async (formId: string) => { * @returns The submissions data. * @throws If an error occurs while fetching the submissions. */ -export const getSubmissionFromCHEFSById = async (formId: string, id: string) => { +export const getSubmissionsFromCHEFS = async (formId: string) => { try { - const { data } = await axiosAPIInstance.get(`/submissions/${formId}/${id}`); + const { data } = await axiosAPIInstance.get(`/submissions/list/${formId}`); return data; } catch (error) { console.error(`Error fetching submissions: ${error}`); @@ -81,32 +91,37 @@ export const getSubmissionFromCHEFSById = async (formId: string, id: string) => }; /** - * Retrieves a rule data from the API based on the provided rule ID. - * @param ruleId The ID of the rule data to retrieve. - * @returns The rule data. - * @throws If an error occurs while retrieving the rule data. + * Retrieves submissions from the CHEFS API. + * @returns The submissions data. + * @throws If an error occurs while fetching the submissions. */ -export const getRuleDataById = async (ruleId: string): Promise => { +export const getSubmissionFromCHEFSById = async (formId: string, id: string) => { try { - const { data } = await axiosAPIInstance.get(`/ruleData/${ruleId}`); + const { data } = await axiosAPIInstance.get(`/submissions/${formId}/${id}`); return data; } catch (error) { - console.error(`Error getting rule data: ${error}`); + console.error(`Error fetching submissions: ${error}`); throw error; } }; /** - * Retrieves all rules data from the API. - * @returns The rule data list. - * @throws If an error occurs while fetching the rule data. + * Posts a decision to the API for evaluation. + * @param jsonFile The JSON file to use for the decision. + * @param decisionGraph The decision graph to evaluate. + * @param context The context for the decision evaluation. + * @returns The result of the decision evaluation. + * @throws If an error occurs while simulating the decision. */ -export const getAllRuleData = async (): Promise => { +export const postDecision = async (jsonFile: string, context: unknown) => { try { - const { data } = await axiosAPIInstance.get(`/ruleData/list`); + const { data } = await axiosAPIInstance.post(`/decisions/evaluate/${jsonFile}`, { + context, + trace: true, + }); return data; } catch (error) { - console.error(`Error fetching rule data: ${error}`); + console.error(`Error simulating decision: ${error}`); throw error; } };