fix(extensions): reset stale codex skill filters

This commit is contained in:
777genius 2026-04-17 21:07:11 +03:00
parent b0c4319ba3
commit 14ee2fc550
2 changed files with 118 additions and 0 deletions

View file

@ -173,6 +173,12 @@ export const SkillsPanel = ({
? (selectedDetail?.item ?? mergedSkills.find((skill) => skill.id === selectedSkillId) ?? null)
: null;
useEffect(() => {
if (quickFilter === 'codex-only' && !showCodexOnlyUi) {
setQuickFilter('all');
}
}, [quickFilter, showCodexOnlyUi]);
useEffect(() => {
if (!selectedSkillId) return;
if (mergedSkills.some((skill) => skill.id === selectedSkillId)) return;

View file

@ -168,6 +168,20 @@ function makeUserSkill(): SkillCatalogItem {
};
}
function makeCodexSkill(): SkillCatalogItem {
return {
...makeUserSkill(),
id: '/Users/me/.codex/skills/codex-helper',
name: 'Codex Helper',
description: 'Helps only Codex sessions',
folderName: 'codex-helper',
rootKind: 'codex',
discoveryRoot: '/Users/me/.codex/skills',
skillDir: '/Users/me/.codex/skills/codex-helper',
skillFile: '/Users/me/.codex/skills/codex-helper/SKILL.md',
};
}
function makeMultimodelStatus(
overrides?: Partial<CliInstallationStatus>
): CliInstallationStatus {
@ -373,4 +387,102 @@ describe('SkillsPanel', () => {
await Promise.resolve();
});
});
it('resets the codex-only quick filter when codex entries disappear', async () => {
storeState.cliStatus = makeMultimodelStatus({
providers: [
...makeMultimodelStatus().providers,
{
providerId: 'codex',
displayName: 'Codex',
supported: true,
authenticated: true,
authMethod: 'api_key',
verificationState: 'verified',
statusMessage: 'Connected',
models: [],
canLoginFromUi: true,
capabilities: {
teamLaunch: true,
oneShot: true,
extensions: {
plugins: { status: 'unsupported', ownership: 'provider', reason: null },
mcp: { status: 'supported', ownership: 'shared', reason: null },
skills: { status: 'supported', ownership: 'shared', reason: null },
apiKeys: { status: 'supported', ownership: 'shared', reason: null },
},
},
connection: null,
backend: null,
},
],
});
storeState.skillsUserCatalog = [makeUserSkill(), makeCodexSkill()];
const host = document.createElement('div');
document.body.appendChild(host);
const root = createRoot(host);
await act(async () => {
root.render(
React.createElement(SkillsPanel, {
projectPath: '/tmp/project-a',
projectLabel: 'Project A',
skillsSearchQuery: '',
setSkillsSearchQuery: vi.fn(),
skillsSort: 'name-asc',
setSkillsSort: vi.fn(),
selectedSkillId: null,
setSelectedSkillId: vi.fn(),
})
);
await Promise.resolve();
await Promise.resolve();
});
const codexOnlyButton = Array.from(host.querySelectorAll('button')).find((button) =>
button.textContent?.includes('Codex only')
);
expect(codexOnlyButton).toBeDefined();
await act(async () => {
(codexOnlyButton as HTMLButtonElement).click();
await Promise.resolve();
});
expect(host.textContent).toContain('Codex Helper');
expect(host.textContent).not.toContain('Review Helper');
storeState.cliStatus = {
...storeState.cliStatus,
providers: storeState.cliStatus.providers.filter((provider) => provider.providerId !== 'codex'),
};
storeState.skillsUserCatalog = [makeUserSkill()];
await act(async () => {
root.render(
React.createElement(SkillsPanel, {
projectPath: '/tmp/project-a',
projectLabel: 'Project A',
skillsSearchQuery: '',
setSkillsSearchQuery: vi.fn(),
skillsSort: 'name-asc',
setSkillsSort: vi.fn(),
selectedSkillId: null,
setSelectedSkillId: vi.fn(),
})
);
await Promise.resolve();
await Promise.resolve();
});
expect(host.textContent).toContain('Review Helper');
expect(host.textContent).not.toContain('Codex Helper');
expect(host.textContent).not.toContain('No skills yet');
await act(async () => {
root.unmount();
await Promise.resolve();
});
});
});