fix(extensions): tighten plugin catalog fallback state
This commit is contained in:
parent
afad52f506
commit
09b5b4626f
2 changed files with 36 additions and 3 deletions
|
|
@ -237,15 +237,19 @@ export const createExtensionsSlice: StateCreator<AppState, [], [], ExtensionsSli
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
set(() => {
|
set((prev) => {
|
||||||
if (requestSeq !== pluginCatalogRequestSeq) {
|
if (requestSeq !== pluginCatalogRequestSeq) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const nextProjectPath = projectPath ?? null;
|
||||||
|
const isSameProjectContext = prev.pluginCatalogProjectPath === nextProjectPath;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
pluginCatalog: isSameProjectContext ? prev.pluginCatalog : [],
|
||||||
pluginCatalogLoading: false,
|
pluginCatalogLoading: false,
|
||||||
pluginCatalogError: err instanceof Error ? err.message : 'Failed to load plugins',
|
pluginCatalogError: err instanceof Error ? err.message : 'Failed to load plugins',
|
||||||
pluginCatalogProjectPath: projectPath ?? null,
|
pluginCatalogProjectPath: nextProjectPath,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -263,7 +267,13 @@ export const createExtensionsSlice: StateCreator<AppState, [], [], ExtensionsSli
|
||||||
fetchPluginReadme: (pluginId: string) => {
|
fetchPluginReadme: (pluginId: string) => {
|
||||||
if (!api.plugins) return;
|
if (!api.plugins) return;
|
||||||
const state = get();
|
const state = get();
|
||||||
if (pluginId in state.pluginReadmes || state.pluginReadmeLoading[pluginId]) return;
|
const cachedReadme = state.pluginReadmes[pluginId];
|
||||||
|
if (
|
||||||
|
(cachedReadme !== undefined && cachedReadme !== null) ||
|
||||||
|
state.pluginReadmeLoading[pluginId]
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
set((prev) => ({
|
set((prev) => ({
|
||||||
pluginReadmeLoading: { ...prev.pluginReadmeLoading, [pluginId]: true },
|
pluginReadmeLoading: { ...prev.pluginReadmeLoading, [pluginId]: true },
|
||||||
|
|
|
||||||
|
|
@ -167,6 +167,20 @@ describe('extensionsSlice', () => {
|
||||||
expect(store.getState().pluginCatalogLoading).toBe(false);
|
expect(store.getState().pluginCatalogLoading).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('clears stale catalog when a different project fetch fails', async () => {
|
||||||
|
store.setState({
|
||||||
|
pluginCatalog: [makePlugin({ pluginId: 'project-a@m' })],
|
||||||
|
pluginCatalogProjectPath: '/tmp/project-a',
|
||||||
|
});
|
||||||
|
(api.plugins!.getAll as ReturnType<typeof vi.fn>).mockRejectedValue(new Error('boom'));
|
||||||
|
|
||||||
|
await store.getState().fetchPluginCatalog('/tmp/project-b');
|
||||||
|
|
||||||
|
expect(store.getState().pluginCatalog).toEqual([]);
|
||||||
|
expect(store.getState().pluginCatalogProjectPath).toBe('/tmp/project-b');
|
||||||
|
expect(store.getState().pluginCatalogError).toBe('boom');
|
||||||
|
});
|
||||||
|
|
||||||
it('dedups concurrent requests for the same project key', async () => {
|
it('dedups concurrent requests for the same project key', async () => {
|
||||||
let resolveFetch!: (plugins: EnrichedPlugin[]) => void;
|
let resolveFetch!: (plugins: EnrichedPlugin[]) => void;
|
||||||
const inFlight = new Promise<EnrichedPlugin[]>((resolve) => {
|
const inFlight = new Promise<EnrichedPlugin[]>((resolve) => {
|
||||||
|
|
@ -243,6 +257,15 @@ describe('extensionsSlice', () => {
|
||||||
|
|
||||||
expect(api.plugins!.getReadme).not.toHaveBeenCalled();
|
expect(api.plugins!.getReadme).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('retries README fetch when the cached value is null', () => {
|
||||||
|
store.setState({ pluginReadmes: { 'test@m': null } });
|
||||||
|
(api.plugins!.getReadme as ReturnType<typeof vi.fn>).mockResolvedValue(null);
|
||||||
|
|
||||||
|
store.getState().fetchPluginReadme('test@m');
|
||||||
|
|
||||||
|
expect(api.plugins!.getReadme).toHaveBeenCalledWith('test@m');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('mcpBrowse', () => {
|
describe('mcpBrowse', () => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue