-
Notifications
You must be signed in to change notification settings - Fork 95
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
[Nu-1890] hide categories from a scenarios list and more scenario details when only one category is available #7183
Changes from 3 commits
e7d988a
b519119
022b1a2
495e87c
dbfd5d7
28de0bd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ import i18next from "i18next"; | |
import { capitalize, startCase } from "lodash"; | ||
import { getProcessingModeVariantName } from "../toolbars/scenarioDetails/getProcessingModeVariantName"; | ||
import NuLogoIcon from "../../assets/img/nussknacker-logo-icon.svg"; | ||
import { useGetAllCombinations } from "../useGetAllCombinations"; | ||
|
||
const ItemWrapperStyled = styled("div")({ display: "grid", gridAutoColumns: "minmax(0, 1fr)", gridAutoFlow: "column" }); | ||
|
||
|
@@ -38,6 +39,11 @@ function MoreScenarioDetailsDialog(props: WindowContentProps<WindowKind, Props>) | |
], | ||
[props, t], | ||
); | ||
const { isAllCombinationsLoading, isCategoryFieldVisible } = useGetAllCombinations({ | ||
processCategory: scenario.processCategory, | ||
processingMode: scenario.processingMode, | ||
processEngine: scenario.engineSetupName, | ||
}); | ||
|
||
const displayStatus = !scenario.isArchived && !scenario.isFragment; | ||
const displayLabels = scenario.labels.length !== 0; | ||
|
@@ -73,10 +79,12 @@ function MoreScenarioDetailsDialog(props: WindowContentProps<WindowKind, Props>) | |
<ItemLabelStyled>{i18next.t("scenarioDetails.label.processingMode", "Processing mode")}</ItemLabelStyled> | ||
<Typography variant={"caption"}>{getProcessingModeVariantName(scenario.processingMode)}</Typography> | ||
</ItemWrapperStyled> | ||
<ItemWrapperStyled> | ||
<ItemLabelStyled>{i18next.t("scenarioDetails.label.category", "Category")}</ItemLabelStyled> | ||
<Typography variant={"caption"}>{scenario.processCategory}</Typography> | ||
</ItemWrapperStyled> | ||
{isAllCombinationsLoading && isCategoryFieldVisible && ( | ||
<ItemWrapperStyled> | ||
<ItemLabelStyled>{i18next.t("scenarioDetails.label.category", "Category")}</ItemLabelStyled> | ||
<Typography variant={"caption"}>{scenario.processCategory}</Typography> | ||
</ItemWrapperStyled> | ||
)} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification Loading state should not affect category visibility The review comment is correct. After examining the
The current condition 🔗 Analysis chainSimplify category visibility condition The category visibility should depend solely on Apply this change: - {isAllCombinationsLoading && isCategoryFieldVisible && (
+ {isCategoryFieldVisible && (
<ItemWrapperStyled>
<ItemLabelStyled>{i18next.t("scenarioDetails.label.category", "Category")}</ItemLabelStyled>
<Typography variant={"caption"}>{scenario.processCategory}</Typography>
</ItemWrapperStyled>
)} Let's verify the behavior of 🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Search for the implementation and usage of useGetAllCombinations
ast-grep --pattern 'export function useGetAllCombinations' -A 20
Length of output: 66 Script: #!/bin/bash
# Let's try searching for any usage of useGetAllCombinations
rg "useGetAllCombinations" -A 3
# Also search for any hooks related to combinations
rg "useCombinations?" -A 3
# Let's also check the component's implementation
fd "MoreScenarioDetailsDialog" --exec cat {}
Length of output: 9311 Script: #!/bin/bash
# Let's check the implementation of useGetAllCombinations hook
cat designer/client/src/components/useGetAllCombinations.ts
Length of output: 1512 |
||
<ItemWrapperStyled> | ||
<ItemLabelStyled>{i18next.t("scenarioDetails.label.engine", "Engine")}</ItemLabelStyled> | ||
<Typography variant={"caption"}>{scenario.engineSetupName}</Typography> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,15 @@ | ||
import React, { useEffect, useState } from "react"; | ||
import { useProcessFormDataOptions } from "../../useProcessFormDataOptions"; | ||
import HttpService, { ScenarioParametersCombination } from "../../../http/HttpService"; | ||
import React from "react"; | ||
import { Skeleton, Typography } from "@mui/material"; | ||
import { Scenario } from "../../Process/types"; | ||
import { useGetAllCombinations } from "../../useGetAllCombinations"; | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification Hook requires test coverage for critical functionality The
Currently, there are no dedicated tests for this hook. Given its critical role in:
Test coverage should be added to ensure reliability. Key areas to test:
🔗 Analysis chainVerify test coverage for useGetAllCombinations hook The component now relies on this hook for critical functionality. Ensure comprehensive test coverage exists for the hook, especially for edge cases around category visibility determination. 🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Description: Check for test coverage of the useGetAllCombinations hook
# Look for test files related to the hook
fd -e test.tsx -e test.ts -e spec.tsx -e spec.ts useGetAllCombinations
# Search for test cases covering visibility logic
rg -l "describe.*useGetAllCombinations|test.*useGetAllCombinations|it.*useGetAllCombinations"
Length of output: 168 Script: #!/bin/bash
# Let's try a broader search to locate the hook file first and any potential test files
fd useGetAllCombinations
# Also search for any test files in the same directory as the component
fd -e test.tsx -e test.ts -e spec.tsx -e spec.ts . designer/client/src/components/
# Look for any test assertions or descriptions containing "combinations" which might be related
rg -l "describe.*combination|test.*combination|it.*combination" designer/client/src/
Length of output: 621 Script: #!/bin/bash
# Let's examine the hook implementation to understand its complexity and test requirements
cat designer/client/src/components/useGetAllCombinations.ts
# Check if there are any existing tests that might cover this hook indirectly
rg -A 5 -B 5 "useGetAllCombinations" designer/client/src/components/toolbars/scenarioDetails/CategoryDetails.test.tsx
# Look for any integration tests that might cover this functionality
rg -A 5 "CategoryDetails" designer/client/src/components/toolbars/scenarioDetails/__tests__
Length of output: 1949 |
||
export const CategoryDetails = ({ scenario }: { scenario: Scenario }) => { | ||
const [allCombinations, setAllCombinations] = useState<ScenarioParametersCombination[]>([]); | ||
const [isAllCombinationsLoading, setIsAllCombinationsLoading] = useState<boolean>(false); | ||
|
||
const { isCategoryFieldVisible } = useProcessFormDataOptions({ | ||
allCombinations, | ||
value: { | ||
processCategory: scenario.processCategory, | ||
processingMode: scenario.processingMode, | ||
processEngine: scenario.engineSetupName, | ||
}, | ||
const { isAllCombinationsLoading, isCategoryFieldVisible } = useGetAllCombinations({ | ||
processCategory: scenario.processCategory, | ||
processingMode: scenario.processingMode, | ||
processEngine: scenario.engineSetupName, | ||
}); | ||
|
||
useEffect(() => { | ||
setIsAllCombinationsLoading(true); | ||
HttpService.fetchScenarioParametersCombinations() | ||
.then((response) => { | ||
setAllCombinations(response.data.combinations); | ||
}) | ||
.finally(() => { | ||
setIsAllCombinationsLoading(false); | ||
}); | ||
}, []); | ||
|
||
return ( | ||
<> | ||
{isAllCombinationsLoading ? ( | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,37 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { useEffect, useState } from "react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import HttpService, { ProcessingMode, ScenarioParametersCombination } from "../http/HttpService"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { useProcessFormDataOptions } from "./useProcessFormDataOptions"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
interface Props { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
processCategory: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
processingMode: ProcessingMode; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
processEngine: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export const useGetAllCombinations = ({ processCategory, processingMode, processEngine }: Props) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const [allCombinations, setAllCombinations] = useState<ScenarioParametersCombination[]>([]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const [engineSetupErrors, setEngineSetupErrors] = useState<Record<string, string[]>>({}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const [isAllCombinationsLoading, setIsAllCombinationsLoading] = useState<boolean>(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const { isCategoryFieldVisible } = useProcessFormDataOptions({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
allCombinations, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
value: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
processCategory, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
processingMode, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
processEngine, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setIsAllCombinationsLoading(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
HttpService.fetchScenarioParametersCombinations() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.then((response) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setAllCombinations(response.data.combinations); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setEngineSetupErrors(response.data.engineSetupErrors); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.finally(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setIsAllCombinationsLoading(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, []); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+24
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling and cleanup to the fetch effect The current implementation lacks error handling and cleanup for the fetch request. Consider these improvements: useEffect(() => {
+ const abortController = new AbortController();
setIsAllCombinationsLoading(true);
- HttpService.fetchScenarioParametersCombinations()
+ HttpService.fetchScenarioParametersCombinations({ signal: abortController.signal })
.then((response) => {
setAllCombinations(response.data.combinations);
setEngineSetupErrors(response.data.engineSetupErrors);
})
+ .catch((error) => {
+ if (!error.name === 'AbortError') {
+ console.error('Failed to fetch scenario parameters:', error);
+ setEngineSetupErrors(prev => ({
+ ...prev,
+ fetch: ['Failed to load scenario parameters']
+ }));
+ }
+ })
.finally(() => {
setIsAllCombinationsLoading(false);
});
+ return () => {
+ abortController.abort();
+ };
}, []); 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return { allCombinations, isAllCombinationsLoading, isCategoryFieldVisible, engineSetupErrors }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -2,13 +2,15 @@ import { UserData } from "nussknackerUi/common/models/User"; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { useContext, useEffect, useMemo } from "react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { NkApiContext } from "../settings/nkApiProvider"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { Scenario, StatusDefinitionType } from "nussknackerUi/components/Process/types"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { StatusesType } from "nussknackerUi/HttpService"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { ScenarioParametersCombinations, StatusesType } from "nussknackerUi/HttpService"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { useQuery, useQueryClient } from "react-query"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { AvailableScenarioLabels } from "nussknackerUi/components/Labels/types"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { UseQueryResult } from "react-query/types/react/types"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { DateTime } from "luxon"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { groupBy } from "lodash"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const scenarioStatusesQueryKey = "scenariosStatuses"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const scenarioParametersCombinationsQueryKey = "scenarioParametersCombinations"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
function useScenariosQuery(): UseQueryResult<Scenario[]> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const api = useContext(NkApiContext); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -53,6 +55,22 @@ export function useScenariosStatusesQuery(): UseQueryResult<StatusesType> { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export function useScenarioParametersCombinationsQuery(): UseQueryResult<ScenarioParametersCombinations> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const api = useContext(NkApiContext); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return useQuery({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
queryKey: [scenarioParametersCombinationsQueryKey], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
queryFn: async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const { data } = await api.fetchScenarioParametersCombinations(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return data; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
enabled: !!api, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
refetchInterval: 15000, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// We have to define staleTime because we set cache manually via queryClient.setQueryData during fetching scenario | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// details (because we want to avoid unnecessary refetch) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
staleTime: 10000, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export function useStatusDefinitions(): UseQueryResult<StatusDefinitionType[]> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const api = useContext(NkApiContext); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return useQuery({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -102,8 +120,22 @@ export function useScenariosWithStatus(): UseQueryResult<Scenario[]> { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data: data.map((scenario) => ({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
...scenario, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
state: statuses?.data?.[scenario.name] || scenario.state, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
id: scenario.name, // required by DataGrid when table=true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
id: scenario.name, // required by DataGrid when table=true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
})), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} as UseQueryResult<Scenario[]>; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, [scenarios, statuses]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export function useScenariosWithCategoryVisible(): { withCategoriesVisible: boolean } { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const parametersCombinations = useScenarioParametersCombinationsQuery(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return useMemo(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const { data } = parametersCombinations; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const combinations = data?.combinations || []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const withCategoriesVisible = Object.keys(groupBy(combinations, (combination) => combination.category)).length > 1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
withCategoriesVisible, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, [parametersCombinations]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+129
to
+141
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider exposing loading and error states for better UX handling. While the implementation is functionally correct, consider these improvements for better error handling and loading state management: -export function useScenariosWithCategoryVisible(): { withCategoriesVisible: boolean } {
+export function useScenariosWithCategoryVisible(): {
+ withCategoriesVisible: boolean;
+ isLoading: boolean;
+ error: Error | null;
+} {
const parametersCombinations = useScenarioParametersCombinationsQuery();
return useMemo(() => {
- const { data } = parametersCombinations;
+ const { data, isLoading, error } = parametersCombinations;
const combinations = data?.combinations || [];
- const withCategoriesVisible = Object.keys(groupBy(combinations, (combination) => combination.category)).length > 1;
+ const MINIMUM_CATEGORIES_FOR_VISIBILITY = 1;
+ const withCategoriesVisible = Object.keys(groupBy(combinations, (combination) => combination.category)).length > MINIMUM_CATEGORIES_FOR_VISIBILITY;
return {
withCategoriesVisible,
+ isLoading,
+ error,
};
}, [parametersCombinations]);
} This change will:
📝 Committable suggestion
Suggested change
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix incorrect visibility logic
The current implementation shows the category when
isAllCombinationsLoading
is true, which seems incorrect for two reasons:Consider updating the logic to: