Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated frontend to use our own API implementation #6

Merged
merged 8 commits into from
Jun 18, 2024
3 changes: 0 additions & 3 deletions .github/workflows/build-and-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,6 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
build-args: |
"NEXT_PUBLIC_API_URL=${{ github.ref == 'refs/heads/main' && secrets.NEXT_PUBLIC_API_URL_PROD || secrets.NEXT_PUBLIC_API_URL_DEV }}"
"NEXT_PUBLIC_GO_RULES_PROJECT_ID=${{ secrets.NEXT_PUBLIC_GO_RULES_PROJECT_ID }}"
"NEXT_PUBLIC_GO_RULES_BEARER_PAT=${{ secrets.NEXT_PUBLIC_GO_RULES_BEARER_PAT }}"
"NEXT_PUBLIC_GO_RULES_ACCESS_TOKEN=${{ secrets.NEXT_PUBLIC_GO_RULES_ACCESS_TOKEN }}"

outputs:
image_tag: ${{ steps.meta.outputs.tags }}
Expand Down
6 changes: 0 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,6 @@ FROM registry.access.redhat.com/ubi9/nodejs-20:latest
# Set the environment variables
ARG NEXT_PUBLIC_API_URL
ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}
ARG NEXT_PUBLIC_GO_RULES_PROJECT_ID
ENV NEXT_PUBLIC_GO_RULES_PROJECT_ID=${NEXT_PUBLIC_GO_RULES_PROJECT_ID}
ARG NEXT_PUBLIC_GO_RULES_BEARER_PAT
ENV NEXT_PUBLIC_GO_RULES_BEARER_PAT=${NEXT_PUBLIC_GO_RULES_BEARER_PAT}
ARG NEXT_PUBLIC_GO_RULES_ACCESS_TOKEN
ENV NEXT_PUBLIC_GO_RULES_ACCESS_TOKEN=${NEXT_PUBLIC_GO_RULES_ACCESS_TOKEN}

# Set the working directory
WORKDIR /opt/app-root/src
Expand Down
35 changes: 25 additions & 10 deletions app/admin/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { useState, useEffect } from "react";
import Link from "next/link";
import { Table, Input, Button, Flex } from "antd";
import { ColumnsType } from "antd/es/table";
import { HomeOutlined } from "@ant-design/icons";
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",
Expand All @@ -18,9 +19,18 @@ export default function Admin() {
const [rules, setRules] = useState<RuleInfo[]>([]);

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);
};

Expand Down Expand Up @@ -82,19 +92,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();
Expand All @@ -113,6 +123,7 @@ export default function Admin() {
title: "Title",
dataIndex: "title",
render: renderInputField("title"),
width: "220px"
},
{
title: "GoRules Id",
Expand All @@ -123,6 +134,7 @@ export default function Admin() {
title: "GoRules JSON Filename",
dataIndex: "goRulesJSONFilename",
render: renderInputField("goRulesJSONFilename"),
width: "260px"
},
{
title: "CHEFS Form Id",
Expand Down Expand Up @@ -155,6 +167,9 @@ export default function Admin() {
return (
<>
<Flex justify="space-between" align="center">
<Link href="/">
<HomeOutlined />
</Link>
<h1>Admin</h1>
{!isLoading && (
<Button type="primary" size="large" onClick={saveAllRuleUpdates}>
Expand Down
11 changes: 5 additions & 6 deletions app/components/RulesDecisionGraph/RulesDecisionGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,30 @@ import styles from "./RulesDecisionGraph.module.css";

interface RulesViewerProps {
jsonFile: string;
docId: string;
contextToSimulate?: SubmissionData | null;
setResultsOfSimulation: (results: Record<string, any>) => void;
}

export default function RulesDecisionGraph({
jsonFile,
docId,
contextToSimulate,
setResultsOfSimulation,
}: RulesViewerProps) {
const decisionGraphRef: any = useRef<DecisionGraphRef>();
const [graphJSON, setGraphJSON] = useState<DecisionGraphType>();


useEffect(() => {
const fetchData = async () => {
try {
const data = await getDocument(docId);
const data = await getDocument(jsonFile);
setGraphJSON(data);
} catch (error) {
console.error("Error fetching JSON:", error);
}
};
fetchData();
}, [docId]);
}, [jsonFile]);

// Can set additional react flow options here if we need to change how graph looks when it's loaded in
const reactFlowInit = (reactFlow: ReactFlowInstance) => {
Expand All @@ -47,10 +46,10 @@ export default function RulesDecisionGraph({
decisionGraphRef?.current?.runSimulator(contextToSimulate);
}, [contextToSimulate]);

const simulateRun = async ({ decisionGraph, context }: { decisionGraph: DecisionGraphType; context: unknown }) => {
const simulateRun = async ({ context }: { context: unknown }) => {
if (contextToSimulate) {
console.info("Simulate:", context);
const data = await postDecision(jsonFile, decisionGraph, context);
const data = await postDecision(jsonFile, context);
console.info("Simulation Results:", data, data?.result);
setResultsOfSimulation(data?.result);
return { result: data };
Expand Down
4 changes: 1 addition & 3 deletions app/components/SimulationViewer/SimulationViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<SubmissionData>();
const [contextToSimulate, setContextToSimulate] = useState<SubmissionData | null>();
const [resultsOfSimulation, setResultsOfSimulation] = useState<Record<string, any> | null>();
Expand All @@ -43,7 +42,6 @@ export default function SimulationViewer({ jsonFile, docId, chefsFormId }: Simul
<div className={styles.rulesWrapper}>
<RulesDecisionGraph
jsonFile={jsonFile}
docId={docId}
contextToSimulate={contextToSimulate}
setResultsOfSimulation={setResultsOfSimulation}
/>
Expand Down
14 changes: 7 additions & 7 deletions app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@ export default function Home() {
getRules();
}, []);

const mappedRules = rules.map(({ _id, title, chefsFormId }) => {
const mappedRules = rules.map(({ _id, title, goRulesJSONFilename, chefsFormId }) => {
return {
key: _id,
titleLink: (
<b>
<Link href={`/rule/${_id}`}>{title}</Link>
<Link href={`/rule/${_id}`}>{title || goRulesJSONFilename}</Link>
</b>
),
editRule: (
<a href={`https://sdpr.gorules.io/projects/${process.env.NEXT_PUBLIC_GO_RULES_PROJECT_ID}/documents/${_id}`}>
Edit
downloadRule: (
<a href={`/api/documents?ruleFileName=${encodeURIComponent(goRulesJSONFilename)}`}>
Download JSON
</a>
),
submissionFormLink: <a href={`https://submit.digital.gov.bc.ca/app/form/submit?f=${chefsFormId}`}>Submission</a>,
Expand All @@ -45,8 +45,8 @@ export default function Home() {
dataIndex: "titleLink",
},
{
title: "Edit Rule",
dataIndex: "editRule",
title: "Download Rule",
dataIndex: "downloadRule",
},
{
title: "Submission Form",
Expand Down
2 changes: 1 addition & 1 deletion app/rule/[ruleId]/embedded/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ export default async function RuleEmbedded({ params: { ruleId } }: { params: { r
return <h1>Rule not found</h1>;
}

return <SimulationViewer jsonFile={goRulesJSONFilename} docId={_id} chefsFormId={chefsFormId} />;
return <SimulationViewer jsonFile={goRulesJSONFilename} chefsFormId={chefsFormId} />;
}
4 changes: 2 additions & 2 deletions app/rule/[ruleId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ export default async function Rule({ params: { ruleId } }: { params: { ruleId: s
<Link href="/">
<HomeOutlined />
</Link>
<h1>{title}</h1>
<h1>{title || goRulesJSONFilename}</h1>
</Flex>
<SimulationViewer jsonFile={goRulesJSONFilename} docId={_id} chefsFormId={chefsFormId} />
<SimulationViewer jsonFile={goRulesJSONFilename} chefsFormId={chefsFormId} />
</>
);
}
Loading
Loading