diff --git a/app/components/RuleManager/RuleManager.tsx b/app/components/RuleManager/RuleManager.tsx index 7f92e39..9d5abfc 100644 --- a/app/components/RuleManager/RuleManager.tsx +++ b/app/components/RuleManager/RuleManager.tsx @@ -23,14 +23,14 @@ const RuleViewerEditor = dynamic(() => import("../RuleViewerEditor"), { ssr: fal interface RuleManagerProps { ruleInfo: RuleInfo; initialRuleContent?: DecisionGraphType; - editing?: string | boolean; + version: RULE_VERSION | boolean; showAllScenarioTabs?: boolean; } export default function RuleManager({ ruleInfo, initialRuleContent = DEFAULT_RULE_CONTENT, - editing = false, + version, showAllScenarioTabs = true, }: RuleManagerProps) { const { _id: ruleId, filepath: jsonFile } = ruleInfo; @@ -56,8 +56,8 @@ export default function RuleManager({ const [simulationContext, setSimulationContext] = useState>(); const [resultsOfSimulation, setResultsOfSimulation] = useState | null>(); const { setHasUnsavedChanges } = useLeaveScreenPopup(); - const canEditGraph = editing === RULE_VERSION.draft || editing === true; - const canEditScenarios = editing === RULE_VERSION.draft || editing === RULE_VERSION.inReview || editing === true; + const canEditGraph = version === RULE_VERSION.draft || version === true; + const canEditScenarios = version === RULE_VERSION.draft || version === RULE_VERSION.inReview || version === true; const updateRuleContent = (updatedRuleContent: DecisionGraphType) => { if (ruleContent !== updatedRuleContent) { @@ -146,21 +146,21 @@ export default function RuleManager({ ); } - const versionColour = getVersionColor(editing.toString()); + const versionColour = getVersionColor(version.toString()); return (
- {editing !== false && ( + {version !== false && ( - + setHasUnsavedChanges(false)} /> @@ -188,6 +188,7 @@ export default function RuleManager({ {scenarios && rulemap && ( )} diff --git a/app/components/RuleViewerEditor/subcomponents/LinkRuleComponent.tsx b/app/components/RuleViewerEditor/subcomponents/LinkRuleComponent.tsx index 8f8d61c..b5f7e5e 100644 --- a/app/components/RuleViewerEditor/subcomponents/LinkRuleComponent.tsx +++ b/app/components/RuleViewerEditor/subcomponents/LinkRuleComponent.tsx @@ -92,7 +92,7 @@ export default function LinkRuleComponent({ specification, id, isSelected, name, )} diff --git a/app/components/ScenariosManager/ScenarioCSV/NewScenarioCSV.tsx b/app/components/ScenariosManager/ScenarioCSV/NewScenarioCSV.tsx index eaf4027..7183086 100644 --- a/app/components/ScenariosManager/ScenarioCSV/NewScenarioCSV.tsx +++ b/app/components/ScenariosManager/ScenarioCSV/NewScenarioCSV.tsx @@ -43,6 +43,14 @@ export default function NewScenarioCSV({ setUploadedFile(false); }; + const handleOk = () => { + file && confirmAddingNewCSVFile(file); + }; + + const handleCancel = () => { + cancelAddingCSVFile(); + }; + useEffect(() => { if (openNewCSVModal) { deleteCurrentCSV(); @@ -53,8 +61,16 @@ export default function NewScenarioCSV({ file && confirmAddingNewCSVFile(file)} - onCancel={() => cancelAddingCSVFile()} + onOk={handleOk} + onCancel={handleCancel} + footer={[ + , + , + ]} >
    diff --git a/app/components/ScenariosManager/ScenarioCSV/ScenarioCSV.tsx b/app/components/ScenariosManager/ScenarioCSV/ScenarioCSV.tsx index db0cade..a0c7edb 100644 --- a/app/components/ScenariosManager/ScenarioCSV/ScenarioCSV.tsx +++ b/app/components/ScenariosManager/ScenarioCSV/ScenarioCSV.tsx @@ -5,21 +5,22 @@ import { App, Button, Flex, Spin, Table, TableProps } from "antd"; import { CheckCircleFilled, CloseCircleFilled } from "@ant-design/icons"; import { DecisionGraphType } from "@gorules/jdm-editor"; import { logError } from "@/app/utils/logger"; +import { RuleInfo } from "@/app/types/ruleInfo"; import { CSVRow, CSVRowData } from "@/app/types/csv"; +import { RULE_VERSION } from "@/app/constants/ruleVersion"; import { uploadCSVAndProcess } from "@/app/utils/api"; import { getCSVTestFilesFromBranch, addCSVTestFileToReview, removeCSVTestFileFromReview } from "@/app/utils/githubApi"; import NewScenarioCSV from "./NewScenarioCSV"; import styles from "./ScenarioCSV.module.css"; interface ScenarioCSVProps { + ruleInfo: RuleInfo; jsonFile: string; ruleContent?: DecisionGraphType; - branchName?: string; - pathName: string; - isInReviewMode: boolean; + version: RULE_VERSION | boolean; } -export default function ScenarioCSV({ jsonFile, ruleContent, branchName, pathName, isInReviewMode }: ScenarioCSVProps) { +export default function ScenarioCSV({ ruleInfo, jsonFile, ruleContent, version }: ScenarioCSVProps) { const { message } = App.useApp(); const [openNewCSVModal, setOpenNewCSVModal] = useState(false); const [isLoadingInTestFiles, setIsLoadingInTestFiles] = useState(true); @@ -29,6 +30,9 @@ export default function ScenarioCSV({ jsonFile, ruleContent, branchName, pathNam const [scenarioRunResults, setScenarioRunResults] = useState>({}); const [currentlySelectedRows, setCurrentlySelectedRows] = useState([]); + const { filepath, reviewBranch } = ruleInfo; + const branchName = version === RULE_VERSION.inReview ? reviewBranch : version === RULE_VERSION.inDev ? "dev" : "main"; + /** * Create a new row for the table */ @@ -43,7 +47,7 @@ export default function ScenarioCSV({ jsonFile, ruleContent, branchName, pathNam actions: ( - {isInReviewMode && + {version === RULE_VERSION.inReview && (isLocal ? ( ) : ( @@ -126,7 +130,7 @@ export default function ScenarioCSV({ jsonFile, ruleContent, branchName, pathNam if (!(downloadFile instanceof File)) { throw new Error("No local file to add to review"); } - const csvPathName = pathName.replace(/[^/]+$/, filename || ""); // Get csv path name from json file name + const csvPathName = filepath.replace(/[^/]+$/, filename || ""); // Get csv path name from json file name const reader = new FileReader(); // Use FileReader to encode file to base64 reader.onload = async () => { const base64Content = reader.result?.toString().split(",")[1]; @@ -158,7 +162,7 @@ export default function ScenarioCSV({ jsonFile, ruleContent, branchName, pathNam if (!branchName) { throw new Error("No branch name exists"); } - const csvPathName = pathName.replace(/[^/]+$/, filenameToRemove); + const csvPathName = filepath.replace(/[^/]+$/, filenameToRemove); await removeCSVTestFileFromReview(branchName, csvPathName); const githubFilesWithoutRemovedOne = githubCSVTestsData.filter(({ filename }) => filenameToRemove != filename); setGithubCSVTestsData(githubFilesWithoutRemovedOne); @@ -191,7 +195,7 @@ export default function ScenarioCSV({ jsonFile, ruleContent, branchName, pathNam useEffect(() => { const getGithubCSVTestFiles = async () => { try { - const testFiles: CSVRowData[] = await getCSVTestFilesFromBranch(branchName || "main", "/tests/util"); + const testFiles: CSVRowData[] = await getCSVTestFilesFromBranch(branchName || "main", "tests/util"); setGithubCSVTestsData(testFiles); setIsLoadingInTestFiles(false); } catch (error: any) { @@ -200,6 +204,7 @@ export default function ScenarioCSV({ jsonFile, ruleContent, branchName, pathNam } }; getGithubCSVTestFiles(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); /** @@ -235,7 +240,7 @@ export default function ScenarioCSV({ jsonFile, ruleContent, branchName, pathNam })); // Sets the updated data setCSVTableData(updatedCSVTableDataWithRunResults); - }, [localTestFiles, githubCSVTestsData, scenarioRunResults]); + }, [createRow, localTestFiles, githubCSVTestsData, scenarioRunResults]); const handleCancelAddingCSVFile = () => { setOpenNewCSVModal(false); @@ -252,7 +257,12 @@ export default function ScenarioCSV({ jsonFile, ruleContent, branchName, pathNam return (
    - +

    - The scenario's saved inputs for the rule are shown in the 'Inputs' window, and the final results - will be processed in real time through the current visible version of the rule, and returned in the - 'Decision' window. + The scenario's saved inputs for the rule are shown in the 'Inputs' window, and the + final results will be processed in real time through the current visible version of the rule, and + returned in the 'Decision' window.

    By running rules individually, you can track their progress as the scenario is processed by the @@ -102,8 +102,8 @@ export default function ScenariosHelper({ section }: ScenariosHelperProps) { scenario inputs, or delete a scenario.

    - Clicking on the edit button will redirect you to the 'Simulate manual inputs' tab to update the - inputs and expected results for a scenario. + Clicking on the edit button will redirect you to the 'Simulate manual inputs' tab to + update the inputs and expected results for a scenario.

    @@ -212,8 +212,8 @@ export default function ScenariosHelper({ section }: ScenariosHelperProps) {

    The simulate button runs your current inputs through the rule to generate results.

    - After a successful simulation, you'll have the option to save these inputs as a new scenario. This - includes a field to name your scenario and a save button to store it for future use. + After a successful simulation, you'll have the option to save these inputs as a new scenario. + This includes a field to name your scenario and a save button to store it for future use.

    @@ -296,8 +296,8 @@ export default function ScenariosHelper({ section }: ScenariosHelperProps) {

    1. Re-Run Scenarios

    - The 'Re-Run Scenarios' button allows you to run all saved scenarios against the current version of - the rule in view. + The 'Re-Run Scenarios' button allows you to run all saved scenarios against the current + version of the rule in view.

    This is particularly useful when making changes to a rule, as it allows you to verify that all @@ -318,7 +318,9 @@ export default function ScenariosHelper({ section }: ScenariosHelperProps) {

  1. No expected results were specified (default pass state)
  2. -
  3. A red X (✗) indicates the scenario's actual results don't match the expected results
  4. +
  5. + A red X (✗) indicates the scenario's actual results don't match the expected results +
  6. @@ -340,15 +342,22 @@ export default function ScenariosHelper({ section }: ScenariosHelperProps) {

    The table provides several controls for managing the view of your scenarios:

      -
    • 'Show Error Scenarios' - Instantly filters the list to display only scenarios with errors
    • -
    • 'Clear Filters and Sorters' - Resets all active filters and sorting to their default state
    • +
    • + 'Show Error Scenarios' - Instantly filters the list to display only scenarios with + errors +
    • +
    • + 'Clear Filters and Sorters' - Resets all active filters and sorting to their default + state +

    Additional filtering and sorting options:

    • Each column can be filtered based on its content
    • Columns can be sorted in ascending or descending order
    • - All filtering and sorting is visual only and doesn't affect the underlying scenarios or results + All filtering and sorting is visual only and doesn't affect the underlying scenarios or + results
    @@ -359,7 +368,22 @@ export default function ScenariosHelper({ section }: ScenariosHelperProps) { case ScenariosManagerTabs.CSVTab: return (
    -

    Follow the instructions within this tab to utilize CSV tests.

    +

    + Scenario CSV test files will show up in the table below. It will list both test files that are stored on + GitHub as well as locally uploaded ones. +

    +

    + You can run the scenarios for those test files by clicking the 'Run Scenarios' button in the + table. +

    +

    + To add a new CSV test file, click the '+ Create new CSV test file' button and follow the + instructions there. +

    +

    + When you are doing a review, the 'Add to Review' button will appear in the table and you can use + that to add your local test files to the review and have them stored in GitHub. +

    Specific details about the CSV Tests tab are available on The Hive:{" "} ) => void; runSimulation: (newContext?: Record) => void; resultsOfSimulation?: Record | null; - branchName?: string; - pathName: string; - isInReviewMode: boolean; + version: RULE_VERSION | boolean; } export enum ScenariosManagerTabs { @@ -41,6 +42,7 @@ export enum ScenariosManagerTabs { export default function ScenariosManager({ ruleId, + ruleInfo, jsonFile, ruleContent, rulemap, @@ -53,9 +55,7 @@ export default function ScenariosManager({ setSimulationContext, runSimulation, resultsOfSimulation, - branchName, - pathName, - isInReviewMode, + version, }: ScenariosManagerProps) { const [resetTrigger, setResetTrigger] = useState(false); const [activeTabKey, setActiveTabKey] = useState( @@ -133,13 +133,7 @@ export default function ScenariosManager({ const csvTab = ( - + ); @@ -199,6 +193,7 @@ export default function ScenariosManager({ scenarios, rulemap, ruleId, + ruleInfo, jsonFile, setSimulationContext, resultsOfSimulation, @@ -213,6 +208,7 @@ export default function ScenariosManager({ handleReset, scenarioName, setScenarios, + version, ]); return ( diff --git a/app/rule/[ruleId]/embedded/page.tsx b/app/rule/[ruleId]/embedded/page.tsx index a0f0660..b0ba615 100644 --- a/app/rule/[ruleId]/embedded/page.tsx +++ b/app/rule/[ruleId]/embedded/page.tsx @@ -11,6 +11,6 @@ export default async function Rule({ params: { ruleId } }: { params: { ruleId: s } return ( - + ); } diff --git a/app/rule/[ruleId]/page.tsx b/app/rule/[ruleId]/page.tsx index 5409059..cfdf3ad 100644 --- a/app/rule/[ruleId]/page.tsx +++ b/app/rule/[ruleId]/page.tsx @@ -45,7 +45,7 @@ export default async function Rule({ params: { ruleId }, searchParams }: Props)

    diff --git a/app/rule/new/NewRule.tsx b/app/rule/new/NewRule.tsx index d21da26..5b08a07 100644 --- a/app/rule/new/NewRule.tsx +++ b/app/rule/new/NewRule.tsx @@ -81,7 +81,7 @@ export default function NewRule() {
    {ruleInfo.filepath && ( - + )}
    diff --git a/app/utils/githubApi.ts b/app/utils/githubApi.ts index c55500d..69010cd 100644 --- a/app/utils/githubApi.ts +++ b/app/utils/githubApi.ts @@ -300,8 +300,12 @@ export const getCSVTestFilesFromBranch = async (branchName: string, filePath: st ); return fileDetails; } catch (error: any) { - logError(`Error getting ${filePath} as JSON for ${branchName}`, error); - throw error; + if (error.status == 404) { + return []; + } else { + logError(`Error getting ${filePath} as CSV for ${branchName}`, error); + throw error; + } } };