From b19936e3b38335664ca59a89b65693197bcaacc6 Mon Sep 17 00:00:00 2001 From: Nate Kelley Date: Tue, 30 Sep 2025 22:13:06 -0600 Subject: [PATCH] mange shortcuts --- .../BusterChatInput/BusterChatInputBase.tsx | 59 +--------- .../BusterChatInput/useUniqueSuggestions.tsx | 64 +++++++++++ .../ShortcutsSuggestions.tsx | 101 ++++++++++-------- 3 files changed, 124 insertions(+), 100 deletions(-) create mode 100644 apps/web/src/components/features/input/BusterChatInput/useUniqueSuggestions.tsx diff --git a/apps/web/src/components/features/input/BusterChatInput/BusterChatInputBase.tsx b/apps/web/src/components/features/input/BusterChatInput/BusterChatInputBase.tsx index b2f8af553..ce5374086 100644 --- a/apps/web/src/components/features/input/BusterChatInput/BusterChatInputBase.tsx +++ b/apps/web/src/components/features/input/BusterChatInput/BusterChatInputBase.tsx @@ -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 = React.memo( ); BusterChatInputBase.displayName = 'BusterChatInputBase'; - -const iconRecord: Record = { - report: , - dashboard: , - visualization: , - help: , -}; - -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] || ; - 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]); -}; diff --git a/apps/web/src/components/features/input/BusterChatInput/useUniqueSuggestions.tsx b/apps/web/src/components/features/input/BusterChatInput/useUniqueSuggestions.tsx new file mode 100644 index 000000000..a4206e2e6 --- /dev/null +++ b/apps/web/src/components/features/input/BusterChatInput/useUniqueSuggestions.tsx @@ -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 = { + report: , + dashboard: , + visualization: , + help: , +}; + +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] || ; + 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]); +}; diff --git a/apps/web/src/components/features/input/Mentions/ShortcutsSuggestions/ShortcutsSuggestions.tsx b/apps/web/src/components/features/input/Mentions/ShortcutsSuggestions/ShortcutsSuggestions.tsx index 075e6c47c..a67295241 100644 --- a/apps/web/src/components/features/input/Mentions/ShortcutsSuggestions/ShortcutsSuggestions.tsx +++ b/apps/web/src/components/features/input/Mentions/ShortcutsSuggestions/ShortcutsSuggestions.tsx @@ -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 ): MentionInputSuggestionsProps['suggestionItems'] => { const createShortcutForMention = useCreateShortcutForMention(); + const navigate = useNavigate(); return useMemo(() => { - const shortcutsItems = shortcuts.map((shortcut) => { - return { + const shortcutsItems: MentionInputSuggestionsProps['suggestionItems'] = [ + { type: 'item', - value: shortcut.name, - label: shortcut.name, - popoverContent: , - icon: SHORTCUT_MENTION_TRIGGER, - inputValue: `${SHORTCUT_MENTION_TRIGGER} ${shortcut.name}`, + value: 'manageShortcuts', + label: 'Manage shortcuts', + keywords: ['/', 'manage', 'shortcuts'], + icon: , 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: , - 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: , + onClick: () => { + setOpenCreateShortcutModal(true); + }, + closeOnSelect: false, addValueToInput: false, - closeOnSelect: true, }, ]; - }, [shortcuts, setOpenCreateShortcutModal, mentionInputSuggestionsRef]); + // const shortcutsItems = shortcuts.map((shortcut) => { + // return { + // type: 'item', + // value: shortcut.name, + // label: shortcut.name, + // popoverContent: , + // 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 }) => {