Skip to content

Commit 4b0338c

Browse files
committed
fix check ordering
1 parent c8e9b8c commit 4b0338c

2 files changed

Lines changed: 53 additions & 11 deletions

File tree

frontend/src/components/panels/AnalysisPanel.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ export function AnalysisPanel({ onSelectCompiledTab }: AnalysisPanelProps) {
4747

4848
// Fetch analysis applicability when game changes
4949
const fetchApplicability = usePluginStore((state) => state.fetchApplicability);
50-
const getApplicability = usePluginStore((state) => state.getApplicability);
50+
// Subscribe to the actual state to trigger re-renders when applicability changes
51+
const applicabilityByGame = usePluginStore((state) => state.applicabilityByGame);
52+
const loadingApplicability = usePluginStore((state) => state.loadingApplicability);
5153

5254
useEffect(() => {
5355
if (currentGameId) {
@@ -58,7 +60,15 @@ export function AnalysisPanel({ onSelectCompiledTab }: AnalysisPanelProps) {
5860
// Helper to get applicability for an analysis
5961
const getAnalysisApplicability = (analysisName: string) => {
6062
if (!currentGameId) return { applicable: true };
61-
return getApplicability(currentGameId, analysisName);
63+
64+
const isLoading = !!loadingApplicability[currentGameId];
65+
const gameApplicability = applicabilityByGame[currentGameId];
66+
67+
if (isLoading || !gameApplicability) {
68+
// Still loading or not yet fetched - disable until we know for sure
69+
return { applicable: false, loading: true, reason: 'Checking...' };
70+
}
71+
return gameApplicability[analysisName] || { applicable: true };
6272
};
6373

6474
// Track which sections are expanded

frontend/src/stores/pluginStore.ts

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import type { PluginStatus, CompileTarget, CompiledCode } from '../types';
55
export interface AnalysisApplicability {
66
applicable: boolean;
77
reason?: string;
8+
/** True while applicability check is in progress */
9+
loading?: boolean;
810
}
911

1012
interface PluginStore {
@@ -14,6 +16,9 @@ interface PluginStore {
1416
/** Analysis applicability per game: gameId -> analysisName -> status */
1517
applicabilityByGame: Record<string, Record<string, AnalysisApplicability>>;
1618

19+
/** Games currently being checked for applicability: gameId -> true */
20+
loadingApplicability: Record<string, boolean>;
21+
1722
/** Compiled code per game: gameId -> targetId -> CompiledCode */
1823
compiledCodeByGame: Record<string, Record<string, CompiledCode>>;
1924

@@ -26,6 +31,7 @@ interface PluginStore {
2631
// Actions
2732
fetchPluginStatus: () => Promise<void>;
2833
fetchApplicability: (gameId: string) => Promise<void>;
34+
isApplicabilityLoading: (gameId: string) => boolean;
2935
getApplicability: (gameId: string, analysisName: string) => AnalysisApplicability;
3036
compile: (gameId: string, sourceCode: string, pluginName: string, target: CompileTarget) => Promise<void>;
3137
clearCompiledCode: (gameId: string, targetId?: string) => void;
@@ -35,6 +41,7 @@ interface PluginStore {
3541
export const usePluginStore = create<PluginStore>((set, get) => ({
3642
plugins: [],
3743
applicabilityByGame: {},
44+
loadingApplicability: {},
3845
compiledCodeByGame: {},
3946
compilingByGame: {},
4047
compileErrorByGame: {},
@@ -54,29 +61,54 @@ export const usePluginStore = create<PluginStore>((set, get) => ({
5461
},
5562

5663
fetchApplicability: async (gameId: string) => {
64+
// Mark as loading
65+
set((state) => ({
66+
loadingApplicability: { ...state.loadingApplicability, [gameId]: true },
67+
}));
68+
5769
try {
5870
const response = await fetch(`/api/plugins/check-applicable/${gameId}`);
5971
if (!response.ok) {
6072
console.error('Failed to fetch applicability:', response.status);
73+
// On error, remove loading state but don't set data (will use fallback)
74+
set((state) => {
75+
const { [gameId]: _, ...rest } = state.loadingApplicability;
76+
return { loadingApplicability: rest };
77+
});
6178
return;
6279
}
6380
const data = await response.json();
64-
set((state) => ({
65-
applicabilityByGame: {
66-
...state.applicabilityByGame,
67-
[gameId]: data.analyses || {},
68-
},
69-
}));
81+
set((state) => {
82+
const { [gameId]: _, ...restLoading } = state.loadingApplicability;
83+
return {
84+
applicabilityByGame: {
85+
...state.applicabilityByGame,
86+
[gameId]: data.analyses || {},
87+
},
88+
loadingApplicability: restLoading,
89+
};
90+
});
7091
} catch (error) {
7192
console.error('Failed to fetch applicability:', error);
93+
// On error, remove loading state
94+
set((state) => {
95+
const { [gameId]: _, ...rest } = state.loadingApplicability;
96+
return { loadingApplicability: rest };
97+
});
7298
}
7399
},
74100

101+
isApplicabilityLoading: (gameId: string) => {
102+
return !!get().loadingApplicability[gameId];
103+
},
104+
75105
getApplicability: (gameId: string, analysisName: string) => {
106+
const isLoading = !!get().loadingApplicability[gameId];
76107
const gameApplicability = get().applicabilityByGame[gameId];
77-
if (!gameApplicability) {
78-
// Not yet fetched, assume applicable
79-
return { applicable: true };
108+
109+
if (isLoading || !gameApplicability) {
110+
// Still loading or not yet fetched - disable until we know for sure
111+
return { applicable: false, loading: true, reason: 'Checking...' };
80112
}
81113
return gameApplicability[analysisName] || { applicable: true };
82114
},

0 commit comments

Comments
 (0)