mirror of https://github.com/buster-so/buster.git
mange shortcuts
This commit is contained in:
parent
a53c850388
commit
b19936e3b3
|
@ -1,29 +1,24 @@
|
|||
import type { ListShortcutsResponse } from '@buster/server-shared/shortcuts';
|
||||
import type { GetSuggestedPromptsResponse } from '@buster/server-shared/user';
|
||||
import omit from 'lodash/omit';
|
||||
import sampleSize from 'lodash/sampleSize';
|
||||
import React, { useMemo, useRef, useState } from 'react';
|
||||
import {
|
||||
useCreateShortcutsMentionsSuggestions,
|
||||
useShortcutsSuggestions,
|
||||
} from '@/components/features/input/Mentions/ShortcutsSuggestions/ShortcutsSuggestions';
|
||||
import CircleQuestion from '@/components/ui/icons/NucleoIconOutlined/circle-question';
|
||||
import FileSparkle from '@/components/ui/icons/NucleoIconOutlined/file-sparkle';
|
||||
import type {
|
||||
MentionArrayItem,
|
||||
MentionSuggestionExtension,
|
||||
} from '@/components/ui/inputs/MentionInput';
|
||||
import type {
|
||||
MentionInputSuggestionsDropdownItem,
|
||||
MentionInputSuggestionsProps,
|
||||
MentionInputSuggestionsRef,
|
||||
} from '@/components/ui/inputs/MentionInputSuggestions';
|
||||
import { MentionInputSuggestions } from '@/components/ui/inputs/MentionInputSuggestions';
|
||||
import { useMemoizedFn } from '@/hooks/useMemoizedFn';
|
||||
import { useMount } from '@/hooks/useMount';
|
||||
import { ASSET_ICONS } from '../../icons/assetIcons';
|
||||
import { NewShortcutModal } from '../../modals/NewShortcutModal';
|
||||
import { BusterChatInputButtons, type BusterChatInputMode } from './BusterChatInputButtons';
|
||||
import { useUniqueSuggestions } from './useUniqueSuggestions';
|
||||
|
||||
export type BusterChatInputProps = {
|
||||
defaultValue: string;
|
||||
|
@ -151,55 +146,3 @@ export const BusterChatInputBase: React.FC<BusterChatInputProps> = React.memo(
|
|||
);
|
||||
|
||||
BusterChatInputBase.displayName = 'BusterChatInputBase';
|
||||
|
||||
const iconRecord: Record<keyof GetSuggestedPromptsResponse['suggestedPrompts'], React.ReactNode> = {
|
||||
report: <FileSparkle />,
|
||||
dashboard: <ASSET_ICONS.dashboards />,
|
||||
visualization: <ASSET_ICONS.metrics />,
|
||||
help: <CircleQuestion />,
|
||||
};
|
||||
|
||||
const useUniqueSuggestions = (
|
||||
suggestedPrompts: GetSuggestedPromptsResponse['suggestedPrompts']
|
||||
): MentionInputSuggestionsProps['suggestionItems'] => {
|
||||
return useMemo(() => {
|
||||
const filteredSuggestedPrompts = omit(suggestedPrompts, ['help']);
|
||||
const allSuggestions: { type: keyof typeof suggestedPrompts; value: string }[] = Object.entries(
|
||||
filteredSuggestedPrompts
|
||||
).flatMap(([key, value]) => {
|
||||
return value.map((prompt) => {
|
||||
return {
|
||||
type: key as keyof typeof suggestedPrompts,
|
||||
value: prompt,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
// Ensure we have at least 4 suggestions
|
||||
if (allSuggestions.length < 4) {
|
||||
throw new Error('Not enough suggestions available - need at least 4');
|
||||
}
|
||||
|
||||
const fourUniqueSuggestions = sampleSize(allSuggestions, 4);
|
||||
|
||||
const items: MentionInputSuggestionsDropdownItem[] = fourUniqueSuggestions.map((suggestion) => {
|
||||
const icon = iconRecord[suggestion.type] || <ASSET_ICONS.metircsAdd />;
|
||||
return {
|
||||
type: 'item',
|
||||
value: suggestion.type + suggestion.value,
|
||||
label: suggestion.value,
|
||||
icon,
|
||||
};
|
||||
});
|
||||
|
||||
return [
|
||||
{
|
||||
type: 'group',
|
||||
label: 'Suggestions',
|
||||
suggestionItems: items,
|
||||
addValueToInput: true,
|
||||
closeOnSelect: true,
|
||||
},
|
||||
] satisfies MentionInputSuggestionsProps['suggestionItems'];
|
||||
}, [suggestedPrompts]);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
import type { GetSuggestedPromptsResponse } from '@buster/server-shared/user';
|
||||
import omit from 'lodash/omit';
|
||||
import sampleSize from 'lodash/sampleSize';
|
||||
import type React from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import CircleQuestion from '@/components/ui/icons/NucleoIconOutlined/circle-question';
|
||||
import FileSparkle from '@/components/ui/icons/NucleoIconOutlined/file-sparkle';
|
||||
import type {
|
||||
MentionInputSuggestionsDropdownItem,
|
||||
MentionInputSuggestionsProps,
|
||||
} from '@/components/ui/inputs/MentionInputSuggestions';
|
||||
import { ASSET_ICONS } from '../../icons/assetIcons';
|
||||
|
||||
const iconRecord: Record<keyof GetSuggestedPromptsResponse['suggestedPrompts'], React.ReactNode> = {
|
||||
report: <FileSparkle />,
|
||||
dashboard: <ASSET_ICONS.dashboards />,
|
||||
visualization: <ASSET_ICONS.metrics />,
|
||||
help: <CircleQuestion />,
|
||||
};
|
||||
|
||||
export const useUniqueSuggestions = (
|
||||
suggestedPrompts: GetSuggestedPromptsResponse['suggestedPrompts']
|
||||
): MentionInputSuggestionsProps['suggestionItems'] => {
|
||||
return useMemo(() => {
|
||||
const filteredSuggestedPrompts = omit(suggestedPrompts, ['help']);
|
||||
const allSuggestions: { type: keyof typeof suggestedPrompts; value: string }[] = Object.entries(
|
||||
filteredSuggestedPrompts
|
||||
).flatMap(([key, value]) => {
|
||||
return value.map((prompt) => {
|
||||
return {
|
||||
type: key as keyof typeof suggestedPrompts,
|
||||
value: prompt,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
// Ensure we have at least 4 suggestions
|
||||
if (allSuggestions.length < 4) {
|
||||
throw new Error('Not enough suggestions available - need at least 4');
|
||||
}
|
||||
|
||||
const fourUniqueSuggestions = sampleSize(allSuggestions, 4);
|
||||
|
||||
const items: MentionInputSuggestionsDropdownItem[] = fourUniqueSuggestions.map((suggestion) => {
|
||||
const icon = iconRecord[suggestion.type] || <ASSET_ICONS.metircsAdd />;
|
||||
return {
|
||||
type: 'item',
|
||||
value: suggestion.type + suggestion.value,
|
||||
label: suggestion.value,
|
||||
icon,
|
||||
};
|
||||
});
|
||||
|
||||
return [
|
||||
{
|
||||
type: 'group',
|
||||
label: 'Suggestions',
|
||||
suggestionItems: items,
|
||||
addValueToInput: true,
|
||||
closeOnSelect: true,
|
||||
},
|
||||
] satisfies MentionInputSuggestionsProps['suggestionItems'];
|
||||
}, [suggestedPrompts]);
|
||||
};
|
|
@ -4,7 +4,7 @@ import type { Editor } from '@tiptap/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';
|
||||
import { Pencil, Trash } from '@/components/ui/icons';
|
||||
import PenWriting from '@/components/ui/icons/NucleoIconOutlined/pen-writing';
|
||||
import Plus from '@/components/ui/icons/NucleoIconOutlined/plus';
|
||||
import {
|
||||
|
@ -126,59 +126,76 @@ export const useCreateShortcutForMention = () => {
|
|||
return createShortcutForMention;
|
||||
};
|
||||
export const useShortcutsSuggestions = (
|
||||
shortcuts: ListShortcutsResponse['shortcuts'],
|
||||
_shortcuts: ListShortcutsResponse['shortcuts'],
|
||||
setOpenCreateShortcutModal: (open: boolean) => void,
|
||||
mentionInputSuggestionsRef: React.RefObject<MentionInputSuggestionsRef | null>
|
||||
): MentionInputSuggestionsProps['suggestionItems'] => {
|
||||
const createShortcutForMention = useCreateShortcutForMention();
|
||||
const navigate = useNavigate();
|
||||
return useMemo(() => {
|
||||
const shortcutsItems = shortcuts.map<MentionInputSuggestionsDropdownItem>((shortcut) => {
|
||||
return {
|
||||
const shortcutsItems: MentionInputSuggestionsProps['suggestionItems'] = [
|
||||
{
|
||||
type: 'item',
|
||||
value: shortcut.name,
|
||||
label: shortcut.name,
|
||||
popoverContent: <ShortcutSuggestionsPopoverContent shortcut={shortcut} />,
|
||||
icon: SHORTCUT_MENTION_TRIGGER,
|
||||
inputValue: `${SHORTCUT_MENTION_TRIGGER} ${shortcut.name}`,
|
||||
value: 'manageShortcuts',
|
||||
label: 'Manage shortcuts',
|
||||
keywords: ['/', 'manage', 'shortcuts'],
|
||||
icon: <PenWriting />,
|
||||
onClick: () => {
|
||||
const addMentionToInput = mentionInputSuggestionsRef.current?.addMentionToInput;
|
||||
if (!addMentionToInput) {
|
||||
console.warn('addMentionToInput is not defined', mentionInputSuggestionsRef.current);
|
||||
return;
|
||||
}
|
||||
const shortcutForMention = createShortcutForMention(shortcut);
|
||||
addMentionToInput?.({
|
||||
...shortcutForMention,
|
||||
trigger: SHORTCUT_MENTION_TRIGGER,
|
||||
navigate({
|
||||
to: '/app/home/shortcuts',
|
||||
});
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
shortcutsItems.push({
|
||||
type: 'item',
|
||||
value: 'createShortcut',
|
||||
label: 'Create shortcut',
|
||||
keywords: ['create', 'shortcut'],
|
||||
icon: <Plus />,
|
||||
inputValue: `${SHORTCUT_MENTION_TRIGGER} Create shortcut`,
|
||||
onClick: () => {
|
||||
setOpenCreateShortcutModal(true);
|
||||
},
|
||||
closeOnSelect: false,
|
||||
addValueToInput: false,
|
||||
});
|
||||
|
||||
return [
|
||||
{
|
||||
type: 'group',
|
||||
label: 'Shortcuts',
|
||||
suggestionItems: shortcutsItems,
|
||||
closeOnSelect: false,
|
||||
addValueToInput: false,
|
||||
},
|
||||
{
|
||||
type: 'item',
|
||||
value: 'createShortcut',
|
||||
label: 'Create shortcut',
|
||||
keywords: ['/', 'create', 'shortcut'],
|
||||
icon: <Plus />,
|
||||
onClick: () => {
|
||||
setOpenCreateShortcutModal(true);
|
||||
},
|
||||
closeOnSelect: false,
|
||||
addValueToInput: false,
|
||||
closeOnSelect: true,
|
||||
},
|
||||
];
|
||||
}, [shortcuts, setOpenCreateShortcutModal, mentionInputSuggestionsRef]);
|
||||
// const shortcutsItems = shortcuts.map<MentionInputSuggestionsDropdownItem>((shortcut) => {
|
||||
// return {
|
||||
// type: 'item',
|
||||
// value: shortcut.name,
|
||||
// label: shortcut.name,
|
||||
// popoverContent: <ShortcutSuggestionsPopoverContent shortcut={shortcut} />,
|
||||
// icon: SHORTCUT_MENTION_TRIGGER,
|
||||
// inputValue: `${SHORTCUT_MENTION_TRIGGER} ${shortcut.name}`,
|
||||
// onClick: () => {
|
||||
// const addMentionToInput = mentionInputSuggestionsRef.current?.addMentionToInput;
|
||||
// if (!addMentionToInput) {
|
||||
// console.warn('addMentionToInput is not defined', mentionInputSuggestionsRef.current);
|
||||
// return;
|
||||
// }
|
||||
// const shortcutForMention = createShortcutForMention(shortcut);
|
||||
// addMentionToInput?.({
|
||||
// ...shortcutForMention,
|
||||
// trigger: SHORTCUT_MENTION_TRIGGER,
|
||||
// });
|
||||
// },
|
||||
// };
|
||||
// });
|
||||
|
||||
return shortcutsItems;
|
||||
|
||||
// return [
|
||||
// {
|
||||
// type: 'group',
|
||||
// label: 'Shortcuts',
|
||||
// suggestionItems: shortcutsItems,
|
||||
// addValueToInput: false,
|
||||
// closeOnSelect: true,
|
||||
// },
|
||||
// ];
|
||||
}, [setOpenCreateShortcutModal, mentionInputSuggestionsRef]);
|
||||
};
|
||||
|
||||
const ShortcutSuggestionsPopoverContent = ({ shortcut }: { shortcut: Shortcut }) => {
|
||||
|
|
Loading…
Reference in New Issue