From 0affc9bf9d23846dd86f288dfb85f2571d85f675 Mon Sep 17 00:00:00 2001 From: "Jason L. Wright" Date: Tue, 14 Jul 2026 10:21:14 -0600 Subject: [PATCH 1/2] Remove hardcoded problemType=NPC from frontend The backend now makes problemType optional across visualizations, verifiers, and solvers, so the frontend no longer needs to hardcode and thread "NPC" through every ProblemProvider hook and Redux API call. problemType was dead state (initialized once, never set). Closes #120 Co-Authored-By: Claude Sonnet 5 --- components/hooks/ProblemProvider/Problem.js | 1 - components/hooks/ProblemProvider/Reducer.js | 24 +++++++++---------- components/hooks/ProblemProvider/Solver.js | 10 ++++---- components/hooks/ProblemProvider/Verifier.js | 10 ++++---- .../hooks/ProblemProvider/Visualization.js | 10 ++++---- components/hooks/ProblemProvider/index.js | 10 ++++---- components/redux/index.js | 20 ++++++++-------- 7 files changed, 42 insertions(+), 43 deletions(-) diff --git a/components/hooks/ProblemProvider/Problem.js b/components/hooks/ProblemProvider/Problem.js index 2a54074..70f2736 100644 --- a/components/hooks/ProblemProvider/Problem.js +++ b/components/hooks/ProblemProvider/Problem.js @@ -8,7 +8,6 @@ export function useProblem(url) { const state = {}; [state.problemInfoMap] = useProblemInfoMap(url); [state.problemNameMap] = useProblemNameMap(state.problemInfoMap); - [state.problemType, state.setProblemType] = useState("NPC"); [state.problemName, state.setProblemName] = useProblemName(state.problemNameMap); [state.problemInstance, state.setProblemInstance] = useState("{{1,2,3},{1,2},GENERIC}"); // Careful about changing this value, the application boot up sequence is dependent on having a default value. return state; diff --git a/components/hooks/ProblemProvider/Reducer.js b/components/hooks/ProblemProvider/Reducer.js index 4e07278..0964856 100644 --- a/components/hooks/ProblemProvider/Reducer.js +++ b/components/hooks/ProblemProvider/Reducer.js @@ -8,12 +8,12 @@ const DEFAULT_CLIQUE_CHOSEN_REDUCTION_TYPE = "SipserReduceToCliqueStandard"; const DEFAULT_CLIQUE_CHOSEN_REDUCE_TO = "VERTEXCOVER"; const DEFAULT_VERTEXCOVER_CHOSEN_REDUCTION_TYPE = "sipserReduceToVC"; -export function useReducer(url, problemName, problemType, problemInstance) { +export function useReducer(url, problemName, problemInstance) { const state = {}; - [state.reduceToOptions] = useReduceToOptions(url, problemName, problemType); + [state.reduceToOptions] = useReduceToOptions(url, problemName); [state.chosenReduceTo, state.setChosenReduceTo] = useChosenReduceTo(problemName, state.reduceToOptions); [state.reductionNameMap] = useReductionNameMap(url, problemName, state.chosenReduceTo); - [state.reductionTypeOptions] = useReductionTypeOptions(url, problemName, problemType, state.chosenReduceTo); + [state.reductionTypeOptions] = useReductionTypeOptions(url, problemName, state.chosenReduceTo); [state.chosenReductionType, state.setChosenReductionType] = useChosenReductionType( problemName, state.chosenReduceTo, @@ -84,36 +84,36 @@ function useReductionVisualization(url, chosenReduceTo) { return [reductionVisualization, setReductionVisualization]; } -function useReduceToOptions(url, problemName, problemType) { +function useReduceToOptions(url, problemName) { const [reduceToOptions, setReduceToOptions] = useState([]); useEffect(() => { (async () => { setReduceToOptions( - (problemName && problemType ? (await requestReductionOptions(url, problemName, problemType)) ?? [] : []).sort() + (problemName ? (await requestReductionOptions(url, problemName)) ?? [] : []).sort() ); })(); - }, [problemName, problemType, url]); + }, [problemName, url]); return [reduceToOptions, setReduceToOptions]; } -function useReductionTypeOptions(url, problemName, problemType, chosenReduceTo) { +function useReductionTypeOptions(url, problemName, chosenReduceTo) { const [reductionTypeOptions, setReductionTypeOptions] = useState([]); useEffect(() => { (async () => { setReductionTypeOptions( - (problemName && problemType && chosenReduceTo - ? (await requestPreparedReductions(url, problemName, chosenReduceTo, problemType)) ?? [] + (problemName && chosenReduceTo + ? (await requestPreparedReductions(url, problemName, chosenReduceTo)) ?? [] : [] ).sort() ); })(); - }, [problemType, chosenReduceTo, url, problemName]); + }, [chosenReduceTo, url, problemName]); - async function requestPreparedReductions(url, problemName, chosenReduceTo, problemType) { - const reductions = (await requestReductions(url, problemName, chosenReduceTo, problemType)) ?? []; + async function requestPreparedReductions(url, problemName, chosenReduceTo) { + const reductions = (await requestReductions(url, problemName, chosenReduceTo)) ?? []; let path = ""; for (const reduction of reductions) { path += reduction[0] + "-"; diff --git a/components/hooks/ProblemProvider/Solver.js b/components/hooks/ProblemProvider/Solver.js index 8ec4fff..e53d78f 100644 --- a/components/hooks/ProblemProvider/Solver.js +++ b/components/hooks/ProblemProvider/Solver.js @@ -2,11 +2,11 @@ import { useGenericInfo } from "../ProblemProvider"; import { requestInfo, requestSolvers } from "../../redux"; import React, { useEffect, useState, useRef } from "react"; -export function useSolver(url, problemName, problemType, problemNameMap, problemInfoMap, problemInstance) { +export function useSolver(url, problemName, problemNameMap, problemInfoMap, problemInstance) { const state = {}; /// Maps each problem name to its default solver name. [state.defaultSolverMap] = useDefaultSolverMap(url, problemInfoMap); - [state.solverOptions] = useSolverOptions(url, problemName, problemType); + [state.solverOptions] = useSolverOptions(url, problemName); [state.chosenSolver, state.setChosenSolver] = useChosenSolver(problemName, state.defaultSolverMap); [state.solverNameMap] = useSolverNameMap(url, problemNameMap); [state.solvedInstance, state.setSolvedInstance] = useSolvedInstance(problemInstance, state.chosenSolver); @@ -86,14 +86,14 @@ function useDefaultSolverMap(url, problemInfoMap) { return [defaultSolverMap, setDefaultSolverMap]; } -function useSolverOptions(url, problemName, problemType) { +function useSolverOptions(url, problemName) { const [solverOptions, setSolverOptions] = useState([]); useEffect(() => { (async () => { - setSolverOptions(problemName && problemType ? (await requestSolvers(url, problemName, problemType)) ?? [] : []); + setSolverOptions(problemName ? (await requestSolvers(url, problemName)) ?? [] : []); })(); - }, [problemName, problemType, url]); + }, [problemName, url]); return [solverOptions, setSolverOptions]; } diff --git a/components/hooks/ProblemProvider/Verifier.js b/components/hooks/ProblemProvider/Verifier.js index 85d6f66..cd2e65a 100644 --- a/components/hooks/ProblemProvider/Verifier.js +++ b/components/hooks/ProblemProvider/Verifier.js @@ -2,10 +2,10 @@ import { useGenericInfo } from "../ProblemProvider"; import { requestInfo, requestVerifiers } from "../../redux"; import React, { useEffect, useState, useRef } from "react"; -export function useVerifier(url, problemName, problemType, problemNameMap, problemInfoMap) { +export function useVerifier(url, problemName, problemNameMap, problemInfoMap) { const state = {}; [state.defaultVerifierMap] = useDefaultVerifierMap(url, problemInfoMap); - [state.verifierOptions] = useVerifierOptions(url, problemName, problemType); + [state.verifierOptions] = useVerifierOptions(url, problemName); [state.chosenVerifier, state.setChosenVerifier] = useChosenVerifier(problemName, state.defaultVerifierMap); [state.verifierNameMap] = useVerifierNameMap(url, problemNameMap); return state; @@ -45,16 +45,16 @@ function useDefaultVerifierMap(url, problemInfoMap) { return [defaultVerifierMap, setDefaultVerifierMap]; } -function useVerifierOptions(url, problemName, problemType) { +function useVerifierOptions(url, problemName) { const [verifierOptions, setVerifierOptions] = useState([]); useEffect(() => { (async () => { setVerifierOptions( - problemName && problemType ? (await requestVerifiers(url, problemName, problemType)) ?? [] : [] + problemName ? (await requestVerifiers(url, problemName)) ?? [] : [] ); })(); - }, [problemName, problemType, url]); + }, [problemName, url]); return [verifierOptions, setVerifierOptions]; } diff --git a/components/hooks/ProblemProvider/Visualization.js b/components/hooks/ProblemProvider/Visualization.js index 5530654..ffd7ba0 100644 --- a/components/hooks/ProblemProvider/Visualization.js +++ b/components/hooks/ProblemProvider/Visualization.js @@ -2,10 +2,10 @@ import { useGenericInfo } from "../ProblemProvider"; import { requestInfo, requestVisualizations } from "../../redux"; import React, { useEffect, useState, useRef } from "react"; -export function useVisualization(url, problemName, problemType, problemNameMap, problemInfoMap) { +export function useVisualization(url, problemName, problemNameMap, problemInfoMap) { const state = {}; [state.defaultVisualizationMap] = useDefaultVisualizationMap(url, problemInfoMap); - [state.VisualizationOptions] = useVisualizationOptions(url, problemName, problemType); + [state.VisualizationOptions] = useVisualizationOptions(url, problemName); [state.chosenVisualization, state.setChosenVisualization] = useChosenVisualization(problemName, state.defaultVisualizationMap); [state.VisualizationNameMap] = useVisualizationNameMap(url, problemNameMap); return state; @@ -45,16 +45,16 @@ function useDefaultVisualizationMap(url, problemInfoMap) { return [defaultVisualizationMap, setDefaultVisualizationMap]; } -function useVisualizationOptions(url, problemName, problemType) { +function useVisualizationOptions(url, problemName) { const [VisualizationOptions, setVisualizationOptions] = useState([]); useEffect(() => { (async () => { setVisualizationOptions( - problemName && problemType ? (await requestVisualizations(url, problemName, problemType)) ?? [] : [] + problemName ? (await requestVisualizations(url, problemName)) ?? [] : [] ); })(); - }, [problemName, problemType, url]); + }, [problemName, url]); return [VisualizationOptions, setVisualizationOptions]; } diff --git a/components/hooks/ProblemProvider/index.js b/components/hooks/ProblemProvider/index.js index db77db6..9cceac4 100644 --- a/components/hooks/ProblemProvider/index.js +++ b/components/hooks/ProblemProvider/index.js @@ -15,13 +15,13 @@ import { useVisualization} from "./Visualization"; export function useProblemProvider(url) { const problem = useProblem(url); - const { problemName, problemType, problemNameMap, problemInfoMap, problemInstance } = problem; + const { problemName, problemNameMap, problemInfoMap, problemInstance } = problem; return { problem: problem, - reducer: useReducer(url, problemName, problemType, problemInstance), - solver: useSolver(url, problemName, problemType, problemNameMap, problemInfoMap, problemInstance), - verifier: useVerifier(url, problemName, problemType, problemNameMap, problemInfoMap), - visualization: useVisualization(url, problemName, problemType, problemNameMap, problemInfoMap), + reducer: useReducer(url, problemName, problemInstance), + solver: useSolver(url, problemName, problemNameMap, problemInfoMap, problemInstance), + verifier: useVerifier(url, problemName, problemNameMap, problemInfoMap), + visualization: useVisualization(url, problemName, problemNameMap, problemInfoMap), }; } diff --git a/components/redux/index.js b/components/redux/index.js index 2b6aaad..eea49d7 100644 --- a/components/redux/index.js +++ b/components/redux/index.js @@ -271,9 +271,9 @@ export async function requestReductionInfo(url, apiCall) { * @returns an array of problems that have implemented reductions from `problem`. * @returns `undefined` on failure and logs the error. */ -export async function requestReductionOptions(url, problem, problemType = "NPC") { +export async function requestReductionOptions(url, problem) { return await fetchJson( - `${url}Navigation/NPC_NavGraph/availableReductions/?chosenProblem=${problem}&problemType=${problemType}`, + `${url}Navigation/NPC_NavGraph/availableReductions/?chosenProblem=${problem}`, () => `${problem} REDUCTION OPTIONS REQUEST FAILED` ); } @@ -315,9 +315,9 @@ export async function requestProblemGenericInstance(url, problem, instance) { * @returns an array of arrays of reductions implemented for reducing a problem to another problem. * @returns `undefined` on failure and logs the error. */ -export async function requestReductions(url, problemFrom, problemTo, problemType = "NPC") { +export async function requestReductions(url, problemFrom, problemTo) { return await fetchJson( - `${url}Navigation/NPC_NavGraph/reductionPath/?reducingFrom=${problemFrom}&reducingTo=${problemTo}&problemType=${problemType}`, + `${url}Navigation/NPC_NavGraph/reductionPath/?reducingFrom=${problemFrom}&reducingTo=${problemTo}`, () => `${problemFrom} TO ${problemTo} REDUCTIONS REQUEST FAILED` ); } @@ -338,9 +338,9 @@ export async function requestSolvedInstance(url, solver, instance) { * @returns an array of solvers implemented for the `problem`. * @returns `undefined` on failure and logs the error. */ -export async function requestSolvers(url, problem, problemType = "NPC") { +export async function requestSolvers(url, problem) { return await fetchJson( - `${url}Navigation/Problem_SolversRefactor/?chosenProblem=${problem}&problemType=${problemType}`, + `${url}Navigation/Problem_SolversRefactor/?chosenProblem=${problem}`, () => `${problem} SOLVERS REQUEST FAILED` ); } @@ -349,9 +349,9 @@ export async function requestSolvers(url, problem, problemType = "NPC") { * @returns an array of verifiers implemented for the `problem`. * @returns `undefined` on failure and logs the error. */ -export async function requestVerifiers(url, problem, problemType = "NPC") { +export async function requestVerifiers(url, problem) { return await fetchJson( - `${url}Navigation/Problem_VerifiersRefactor/?chosenProblem=${problem}&problemType=${problemType}`, + `${url}Navigation/Problem_VerifiersRefactor/?chosenProblem=${problem}`, () => `${problem} VERIFIERS REQUEST FAILED` ); } @@ -389,9 +389,9 @@ export async function requestVisualization(url, visualization, instance) { * @returns an array of visualizations implemented for the `problem`. * @returns `undefined` on failure and logs the error. */ -export async function requestVisualizations(url, problem, problemType = "NPC") { +export async function requestVisualizations(url, problem) { return await fetchJson( - `${url}Navigation/Problem_VisualizationsRefactor/?chosenProblem=${problem}&problemType=${problemType}`, + `${url}Navigation/Problem_VisualizationsRefactor/?chosenProblem=${problem}`, () => `${problem} VISUALIZATIONS REQUEST FAILED` ); } From 083beacf1fb4595c6e875876466cd326070920c3 Mon Sep 17 00:00:00 2001 From: "Jason L. Wright" Date: Tue, 14 Jul 2026 10:51:22 -0600 Subject: [PATCH 2/2] Fix react-hooks/immutability: hoist requestPreparedReductions above use GitHub Advanced Security's ESLint check flagged this as a new alert because these lines were touched while removing problemType. Declaring the helper before the effect that calls it resolves it. Co-Authored-By: Claude Sonnet 5 --- components/hooks/ProblemProvider/Reducer.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/hooks/ProblemProvider/Reducer.js b/components/hooks/ProblemProvider/Reducer.js index 0964856..ae30f7e 100644 --- a/components/hooks/ProblemProvider/Reducer.js +++ b/components/hooks/ProblemProvider/Reducer.js @@ -101,6 +101,15 @@ function useReduceToOptions(url, problemName) { function useReductionTypeOptions(url, problemName, chosenReduceTo) { const [reductionTypeOptions, setReductionTypeOptions] = useState([]); + async function requestPreparedReductions(url, problemName, chosenReduceTo) { + const reductions = (await requestReductions(url, problemName, chosenReduceTo)) ?? []; + let path = ""; + for (const reduction of reductions) { + path += reduction[0] + "-"; + } + return path !== "" ? [path.slice(0, -1)] : []; + } + useEffect(() => { (async () => { setReductionTypeOptions( @@ -112,15 +121,6 @@ function useReductionTypeOptions(url, problemName, chosenReduceTo) { })(); }, [chosenReduceTo, url, problemName]); - async function requestPreparedReductions(url, problemName, chosenReduceTo) { - const reductions = (await requestReductions(url, problemName, chosenReduceTo)) ?? []; - let path = ""; - for (const reduction of reductions) { - path += reduction[0] + "-"; - } - return path !== "" ? [path.slice(0, -1)] : []; - } - return [reductionTypeOptions, setReductionTypeOptions]; }