Skip to content

Commit

Permalink
Merge pull request #31 from bcgov/feature/klamm-connection-warnings
Browse files Browse the repository at this point in the history
New warnings when editing a file that show missing Klamm connections
  • Loading branch information
timwekkenbc authored Sep 24, 2024
2 parents 69ed3da + 6f38903 commit 387e546
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 2 deletions.
13 changes: 13 additions & 0 deletions app/components/SavePublish/SavePublish.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,17 @@
.savePublishWrapper {
justify-content: start !important;
}
}

.notificationWarningList {
list-style: none;
padding: 0;
border-top: 1px solid #EEE;
}
.notificationWarningList li {
padding: 4px 0;
border-bottom: 1px solid #EEE;
}
.notificationWarningList li span {
opacity: 0.7;
}
8 changes: 6 additions & 2 deletions app/components/SavePublish/SavePublish.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import React, { useState } from "react";
import { Modal, Button, Flex, message, App } from "antd";
import { Modal, Button, Flex, App } from "antd";
import { SaveOutlined, UploadOutlined } from "@ant-design/icons";
import { DecisionGraphType } from "@gorules/jdm-editor";
import { RuleInfo } from "@/app/types/ruleInfo";
import { updateRuleData } from "@/app/utils/api";
import { sendRuleForReview } from "@/app/utils/githubApi";
import NewReviewForm from "./NewReviewForm";
import SavePublishWarnings from "./SavePublishWarnings";
import styles from "./SavePublish.module.css";

interface SavePublishProps {
ruleInfo: RuleInfo;
ruleContent: object;
ruleContent: DecisionGraphType;
setHasSaved: () => void;
}

export default function SavePublish({ ruleInfo, ruleContent, setHasSaved }: SavePublishProps) {
const { _id: ruleId, goRulesJSONFilename: filePath, reviewBranch } = ruleInfo;

const { message } = App.useApp();
const [openNewReviewModal, setOpenNewReviewModal] = useState(false);
const [currReviewBranch, setCurrReviewBranch] = useState(reviewBranch);
const [isSaving, setIsSaving] = useState(false);
Expand Down Expand Up @@ -97,6 +100,7 @@ export default function SavePublish({ ruleInfo, ruleContent, setHasSaved }: Save
Send for Review <UploadOutlined />
</Button>
</Flex>
<SavePublishWarnings filePath={filePath} ruleContent={ruleContent} isSaving={isSaving} />
</>
);
}
107 changes: 107 additions & 0 deletions app/components/SavePublish/SavePublishWarnings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React, { useState, useEffect } from "react";
import { Tag, App, FloatButton } from "antd";
import { WarningFilled } from "@ant-design/icons";
import { DecisionGraphType } from "@gorules/jdm-editor";
import { getRuleMap, generateSchemaFromRuleContent } from "@/app/utils/api";
import styles from "./SavePublish.module.css";

interface SavePublishProps {
filePath: string;
ruleContent: DecisionGraphType;
isSaving: boolean;
}

interface MisconnectedField {
field: string;
describer: string;
}

export default function SavePublishWarnings({ filePath, ruleContent, isSaving }: SavePublishProps) {
const { notification } = App.useApp();
const [misconnectedFields, setMisconnectedFields] = useState<MisconnectedField[]>([]);
const [misconnectedFieldsPanelOpen, setMisconnectedFieldsPanelOpen] = useState(false);

const getMisconnectedFields = async () => {
// TODO: Move these API calls locally to reduce strain on server (if this solution is working well)
// Get map from input/output nodes
const inputOutputSchemaMap = await getRuleMap(filePath, ruleContent);
const existingKlammInputs = inputOutputSchemaMap.inputs.map(({ field }) => field as string);
const existingKlammOutputs = inputOutputSchemaMap.resultOutputs.map(({ field }) => field as string);

// Get map the old way for comparrison
const generatedSchemaMap = await generateSchemaFromRuleContent(ruleContent);
const generatedInputs = generatedSchemaMap.inputs.map(({ field }) => field as string);
const generatedOutputs = generatedSchemaMap.resultOutputs.map(({ field }) => field as string);

const updatedMisconnectedFields: MisconnectedField[] = [];

// Helper function to find missing or unused fields
const findMisconnectedFields = (sourceFields: string[], targetFields: string[], describer: string) => {
sourceFields.forEach((field) => {
if (field && !targetFields.includes(field)) {
updatedMisconnectedFields.push({ describer, field });
}
});
};

// Check if there are fields unlinked to Klamm input/output field
findMisconnectedFields(generatedInputs, existingKlammInputs, "MISSING INPUT");
findMisconnectedFields(generatedOutputs, existingKlammOutputs, "MISSING OUTPUT");

// Check if there are fields in input/output schema that are unused
findMisconnectedFields(existingKlammInputs, generatedInputs, "UNUSED INPUT");
findMisconnectedFields(existingKlammOutputs, generatedOutputs, "UNUSED OUTPUT");

setMisconnectedFields(updatedMisconnectedFields);
};

const warnOfMisconnectedFields = async () => {
notification.warning({
key: "klamm-warning",
message: "Misconnected Klamm Fields",
description: (
<ul className={styles.notificationWarningList}>
{misconnectedFields.map(({ describer, field }) => (
<li key={`${describer}:${field}`}>
<Tag color={describer.includes("UNUSED") ? "orange" : "red"}>
<small>{describer}</small>
</Tag>
{field}
</li>
))}
</ul>
),
placement: "bottomRight",
duration: 0,
onClose: () => setMisconnectedFieldsPanelOpen(false),
});
};

useEffect(() => {
getMisconnectedFields();
}, [ruleContent]);

useEffect(() => {
if (isSaving) {
setMisconnectedFieldsPanelOpen(true);
}
}, [isSaving]);

useEffect(() => {
if (misconnectedFieldsPanelOpen) {
warnOfMisconnectedFields();
}
}, [misconnectedFields, misconnectedFieldsPanelOpen]);

return (
<>
{!misconnectedFieldsPanelOpen && (
<FloatButton
icon={<WarningFilled style={{ color: "orange" }} />}
badge={{ count: misconnectedFields.length, color: "orange" }}
onClick={() => setMisconnectedFieldsPanelOpen(true)}
/>
)}
</>
);
}
18 changes: 18 additions & 0 deletions app/utils/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,24 @@ export const getRuleRunSchema = async (ruleResponse: unknown) => {
}
};

/**
* Genererates a rule map from just the rule content
* @param ruleContent The rule decision graph to evaluate.
* @returns The rule map.
* @throws If an error occurs while retrieving the rule data.
*/
export const generateSchemaFromRuleContent = async (ruleContent: DecisionGraphType): Promise<RuleMap> => {
try {
const { data } = await axiosAPIInstance.post("/rulemap/generateFromRuleContent", {
ruleContent,
});
return data;
} catch (error) {
console.error(`Error getting rule data: ${error}`);
throw error;
}
};

/**
* Retrieves the scenarios for a rule from the API based on the provided filename
* @param goRulesJSONFilename The name of the rule data to retrieve.
Expand Down

0 comments on commit 387e546

Please sign in to comment.