fix(site): hide slash skills menu when user has no personal skills (#26953)

This commit is contained in:
Michael Suchacz
2026-07-06 20:35:35 +02:00
committed by GitHub
parent 2ec7f5c69b
commit 6e0bbb5fff
2 changed files with 38 additions and 5 deletions
@@ -79,10 +79,26 @@ export const EmptySkills: Story = {
},
play: async ({ canvasElement, args }) => {
const editor = await typeInEditor(canvasElement, "/");
expect(await findVisibleText("No personal skills found.")).toBeDefined();
// "/" is plain text when the skills list is empty.
expectNoVisibleTextImmediately("No personal skills found.");
await userEvent.keyboard("{Enter}");
expect(args.onEnter).toHaveBeenCalledTimes(1);
expect(editor.textContent).toBe("/");
},
};
export const FilteredEmptyKeepsMenuOpen: Story = {
args: {
onEnter: fn(),
},
play: async ({ canvasElement, args }) => {
const editor = await typeInEditor(canvasElement, "/zzzz");
expect(
await findVisibleText("No personal skills match that query."),
).toBeDefined();
await userEvent.keyboard("{Enter}");
expect(args.onEnter).not.toHaveBeenCalled();
expect(editor.textContent).toBe("/");
expect(editor.textContent).toBe("/zzzz");
},
};
@@ -595,12 +595,25 @@ const ChatMessageInput = ({
useState<ActiveSkillsTrigger | null>(null);
const suppressedSkillsTriggerRef = useRef<SkillsTriggerLocation | null>(null);
const [skillsMenuSelectedIndex, setSkillsMenuSelectedIndex] = useState(0);
const skillsMenuOpen = Boolean(skillsTrigger);
const hasSkillsTrigger = Boolean(skillsTrigger);
const hasPersonalSkillsOverride = personalSkillsOverride !== undefined;
const skillsQuery = useQuery({
...userSkills(),
enabled: skillsMenuOpen && personalSkillsOverride === undefined,
enabled: hasSkillsTrigger && !hasPersonalSkillsOverride,
// Avoid refetching on each trigger toggle from caret movement.
staleTime: 60_000,
});
const personalSkills = personalSkillsOverride ?? skillsQuery.data ?? [];
// A stale empty cache with a refetch in flight must not dismiss the menu.
const isResolvedEmptySkillsList = hasPersonalSkillsOverride
? personalSkills.length === 0
: skillsQuery.isSuccess &&
!skillsQuery.isFetching &&
personalSkills.length === 0;
// When the loaded skills list is empty, "/" is plain text. When only
// the filtered result is empty, keep the menu open for the no-match
// message.
const skillsMenuOpen = hasSkillsTrigger && !isResolvedEmptySkillsList;
const filteredPersonalSkills = skillsTrigger
? filterPersonalSkills(personalSkills, skillsTrigger.query)
: [];
@@ -890,7 +903,11 @@ const ChatMessageInput = ({
anchorRect={skillsTrigger?.anchorRect ?? null}
query={skillsTrigger?.query ?? ""}
skills={filteredPersonalSkills}
isLoading={skillsMenuOpen && skillsQuery.isLoading}
isLoading={
skillsMenuOpen &&
personalSkills.length === 0 &&
skillsQuery.isFetching
}
onSelectedIndexChange={setSkillsMenuSelectedIndex}
isError={skillsMenuOpen && skillsQuery.isError}
selectedIndex={selectedSkillIndex}