mirror of https://github.com/buster-so/buster.git
use a ref for shortcuts
This commit is contained in:
parent
7ab328abb5
commit
12b534db2a
|
@ -1,6 +1,6 @@
|
|||
import type { ListShortcutsResponse, Shortcut } from '@buster/server-shared/shortcuts';
|
||||
import { useNavigate } from '@tanstack/react-router';
|
||||
import { useMemo } from 'react';
|
||||
import { useMemo, useRef } from 'react';
|
||||
import { useDeleteShortcut, useGetShortcut } from '@/api/buster_rest/shortcuts/queryRequests';
|
||||
import { ErrorCard } from '@/components/ui/error/ErrorCard';
|
||||
import { Trash } from '@/components/ui/icons';
|
||||
|
@ -16,7 +16,6 @@ import type {
|
|||
MentionInputSuggestionsProps,
|
||||
MentionInputSuggestionsRef,
|
||||
} from '@/components/ui/inputs/MentionInputSuggestions';
|
||||
import { CircleSpinnerLoader } from '@/components/ui/loaders';
|
||||
import { ShortcutPopoverContent } from './ShortcutPopoverContent';
|
||||
|
||||
export const SHORTCUT_MENTION_TRIGGER = '/';
|
||||
|
@ -28,34 +27,42 @@ export const useCreateShortcutsMentionsSuggestions = (
|
|||
const navigate = useNavigate();
|
||||
const createShortcutForMention = useCreateShortcutForMention();
|
||||
|
||||
const currentItemsRef = useRef(shortcuts);
|
||||
|
||||
currentItemsRef.current = shortcuts;
|
||||
|
||||
return useMemo(
|
||||
() =>
|
||||
createMentionSuggestionExtension({
|
||||
trigger: SHORTCUT_MENTION_TRIGGER,
|
||||
items: [
|
||||
...shortcuts.map(createShortcutForMention),
|
||||
{ type: 'separator' as const },
|
||||
{
|
||||
value: 'manageShortcuts',
|
||||
label: 'Manage shortcuts',
|
||||
icon: <PenWriting />,
|
||||
doNotAddPipeOnSelect: true,
|
||||
onSelect: () => {
|
||||
navigate({
|
||||
to: '/app/home/shortcuts',
|
||||
});
|
||||
items: ({ defaultQueryMentionsFilter, query }) => {
|
||||
const shortcuts = currentItemsRef.current;
|
||||
const allItems = [
|
||||
...shortcuts.map(createShortcutForMention),
|
||||
{ type: 'separator' as const },
|
||||
{
|
||||
value: 'manageShortcuts',
|
||||
label: 'Manage shortcuts',
|
||||
icon: <PenWriting />,
|
||||
doNotAddPipeOnSelect: true,
|
||||
onSelect: () => {
|
||||
navigate({
|
||||
to: '/app/home/shortcuts',
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
value: 'createShortcut',
|
||||
label: 'Create shortcut',
|
||||
icon: <Plus />,
|
||||
doNotAddPipeOnSelect: true,
|
||||
onSelect: () => {
|
||||
setOpenCreateShortcutModal(true);
|
||||
{
|
||||
value: 'createShortcut',
|
||||
label: 'Create shortcut',
|
||||
icon: <Plus />,
|
||||
doNotAddPipeOnSelect: true,
|
||||
onSelect: () => {
|
||||
setOpenCreateShortcutModal(true);
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
];
|
||||
return defaultQueryMentionsFilter(query, allItems);
|
||||
},
|
||||
popoverContent: ShortcutPopoverContent,
|
||||
onChangeTransform: (v) => {
|
||||
const foundShortcut = shortcuts.find((shortcut) => shortcut.name === v.label);
|
||||
|
@ -97,8 +104,8 @@ export const useCreateShortcutForMention = () => {
|
|||
label: 'Delete',
|
||||
icon: <Trash />,
|
||||
value: 'delete',
|
||||
onClick: () => {
|
||||
deleteShortcut({ id: shortcut.id });
|
||||
onClick: async () => {
|
||||
await deleteShortcut({ id: shortcut.id });
|
||||
},
|
||||
},
|
||||
]}
|
||||
|
|
|
@ -3,7 +3,6 @@ import type { Meta, StoryObj } from '@storybook/react-vite';
|
|||
import { useMemo, useRef, useState } from 'react';
|
||||
import { fn } from 'storybook/test';
|
||||
import { createMentionSuggestionExtension } from './createMentionSuggestionOption';
|
||||
import { defaultQueryMentionsFilter } from './defaultQueryMentionsFilter';
|
||||
import { MentionInput } from './MentionInput';
|
||||
import type { MentionInputRef, MentionInputTriggerItem } from './MentionInput.types';
|
||||
|
||||
|
@ -329,6 +328,10 @@ export const DynamicItems: Story = {
|
|||
{ value: 'Initial Item 2', label: 'Initial Item 2' },
|
||||
]);
|
||||
const mentionInputRef = useRef<MentionInputRef>(null);
|
||||
const currentItemsRef = useRef(dynamicItems);
|
||||
|
||||
// Always keep the ref updated with the latest items
|
||||
currentItemsRef.current = dynamicItems;
|
||||
|
||||
const addRandomItem = () => {
|
||||
const randomNames = [
|
||||
|
@ -384,11 +387,15 @@ export const DynamicItems: Story = {
|
|||
setDynamicItems([]);
|
||||
};
|
||||
|
||||
// Create a stable function that always uses the current items from the ref
|
||||
const dynamicSuggestions = useMemo(
|
||||
() =>
|
||||
createMentionSuggestionExtension({
|
||||
trigger: '!',
|
||||
items: dynamicItems,
|
||||
items: ({ query, defaultQueryMentionsFilter }) => {
|
||||
const latestItems = currentItemsRef.current;
|
||||
return defaultQueryMentionsFilter(query, latestItems);
|
||||
},
|
||||
pillStyling: {
|
||||
className: () => {
|
||||
return 'bg-gradient-to-r from-purple-100 to-pink-100 border-purple-300 text-purple-700 hover:from-purple-200 hover:to-pink-200';
|
||||
|
@ -403,7 +410,7 @@ export const DynamicItems: Story = {
|
|||
);
|
||||
},
|
||||
}),
|
||||
[dynamicItems]
|
||||
[dynamicItems] // Empty dependency array since we're using the ref for fresh data
|
||||
);
|
||||
|
||||
return (
|
||||
|
|
|
@ -20,14 +20,24 @@ export const createMentionSuggestionExtension = ({
|
|||
pillStyling,
|
||||
}: {
|
||||
trigger: string;
|
||||
items: MentionInputTriggerItem[] | ((props: { query: string }) => MentionInputTriggerItem[]); //if no function is provided we will use a literal string match
|
||||
items:
|
||||
| MentionInputTriggerItem[]
|
||||
| ((props: {
|
||||
query: string;
|
||||
defaultQueryMentionsFilter: typeof defaultQueryMentionsFilter;
|
||||
}) => MentionInputTriggerItem[]); //if no function is provided we will use a literal string match
|
||||
popoverContent?: MentionPopoverContentCallback;
|
||||
pillStyling?: MentionStylePillProps;
|
||||
onChangeTransform?: MentionSuggestionExtension['onChangeTransform'];
|
||||
}): MentionSuggestionExtension => ({
|
||||
char: trigger,
|
||||
items:
|
||||
typeof items === 'function' ? items : ({ query }) => defaultQueryMentionsFilter(query, items),
|
||||
//beware of stale closures here. We should use a ref to get the latest items
|
||||
typeof items === 'function'
|
||||
? (props) => {
|
||||
return items({ ...props, defaultQueryMentionsFilter });
|
||||
}
|
||||
: ({ query }) => defaultQueryMentionsFilter(query, items),
|
||||
render: () => {
|
||||
let component: ReactRenderer<MentionListImperativeHandle, MentionListProps<string>>;
|
||||
|
||||
|
|
Loading…
Reference in New Issue