diff --git a/web/app/components/goto-anything/command-selector.tsx b/web/app/components/goto-anything/command-selector.tsx new file mode 100644 index 000000000..169f377c3 --- /dev/null +++ b/web/app/components/goto-anything/command-selector.tsx @@ -0,0 +1,51 @@ +import type { FC } from 'react' +import { Command } from 'cmdk' +import { useTranslation } from 'react-i18next' +import type { ActionItem } from './actions/types' + +type Props = { + actions: Record + onCommandSelect: (commandKey: string) => void +} + +const CommandSelector: FC = ({ actions, onCommandSelect }) => { + const { t } = useTranslation() + + return ( +
+
+ {t('app.gotoAnything.selectSearchType')} +
+ + {Object.values(actions).map(action => ( + onCommandSelect(action.shortcut)} + > + + {action.shortcut} + + + {(() => { + const keyMap: Record = { + '@app': 'app.gotoAnything.actions.searchApplicationsDesc', + '@plugin': 'app.gotoAnything.actions.searchPluginsDesc', + '@knowledge': 'app.gotoAnything.actions.searchKnowledgeBasesDesc', + '@node': 'app.gotoAnything.actions.searchWorkflowNodesDesc', + } + return t(keyMap[action.key]) + })()} + + + ))} + +
+ ) +} + +export default CommandSelector diff --git a/web/app/components/goto-anything/index.tsx b/web/app/components/goto-anything/index.tsx index d9b3958eb..02c4667d8 100644 --- a/web/app/components/goto-anything/index.tsx +++ b/web/app/components/goto-anything/index.tsx @@ -17,6 +17,7 @@ import { useTranslation } from 'react-i18next' import InstallFromMarketplace from '../plugins/install-plugin/install-from-marketplace' import type { Plugin } from '../plugins/types' import { Command } from 'cmdk' +import CommandSelector from './command-selector' type Props = { onHide?: () => void @@ -81,11 +82,15 @@ const GotoAnything: FC = ({ wait: 300, }) + const isCommandsMode = searchQuery.trim() === '@' + const searchMode = useMemo(() => { + if (isCommandsMode) return 'commands' + const query = searchQueryDebouncedValue.toLowerCase() const action = matchAction(query, Actions) return action ? action.key : 'general' - }, [searchQueryDebouncedValue, Actions]) + }, [searchQueryDebouncedValue, Actions, isCommandsMode]) const { data: searchResults = [], isLoading, isError, error } = useQuery( { @@ -103,12 +108,20 @@ const GotoAnything: FC = ({ const action = matchAction(query, Actions) return await searchAnything(defaultLocale, query, action) }, - enabled: !!searchQueryDebouncedValue, + enabled: !!searchQueryDebouncedValue && !isCommandsMode, staleTime: 30000, gcTime: 300000, }, ) + const handleCommandSelect = useCallback((commandKey: string) => { + setSearchQuery(`${commandKey} `) + setCmdVal('') + setTimeout(() => { + inputRef.current?.focus() + }, 0) + }, []) + // Handle navigation to selected result const handleNavigate = useCallback((result: SearchResult) => { setShow(false) @@ -141,7 +154,7 @@ const GotoAnything: FC = ({ [searchResults]) const emptyResult = useMemo(() => { - if (searchResults.length || !searchQueryDebouncedValue.trim() || isLoading) + if (searchResults.length || !searchQuery.trim() || isLoading || isCommandsMode) return null const isCommandSearch = searchMode !== 'general' @@ -186,34 +199,22 @@ const GotoAnything: FC = ({ ) - }, [searchResults, searchQueryDebouncedValue, Actions, searchMode, isLoading, isError]) + }, [searchResults, searchQuery, Actions, searchMode, isLoading, isError, isCommandsMode]) const defaultUI = useMemo(() => { - if (searchQueryDebouncedValue.trim()) + if (searchQuery.trim()) return null - return (
+ return (
{t('app.gotoAnything.searchTitle')}
-
- {Object.values(Actions).map(action => ( -
- {action.shortcut} - {(() => { - const keyMap: Record = { - '@app': 'app.gotoAnything.actions.searchApplicationsDesc', - '@plugin': 'app.gotoAnything.actions.searchPluginsDesc', - '@knowledge': 'app.gotoAnything.actions.searchKnowledgeBasesDesc', - '@node': 'app.gotoAnything.actions.searchWorkflowNodesDesc', - } - return t(keyMap[action.key]) - })()} -
- ))} +
+
{t('app.gotoAnything.searchHint')}
+
{t('app.gotoAnything.commandHint')}
) - }, [searchQueryDebouncedValue, Actions]) + }, [searchQuery, Actions]) useEffect(() => { if (show) { @@ -296,7 +297,13 @@ const GotoAnything: FC = ({ )} {!isLoading && !isError && ( <> - {Object.entries(groupedResults).map(([type, results], groupIndex) => ( + {isCommandsMode ? ( + + ) : ( + Object.entries(groupedResults).map(([type, results], groupIndex) => ( { const typeMap: Record = { 'app': 'app.gotoAnything.groups.apps', @@ -330,9 +337,10 @@ const GotoAnything: FC = ({ ))} - ))} - {emptyResult} - {defaultUI} + )) + )} + {!isCommandsMode && emptyResult} + {!isCommandsMode && defaultUI} )} diff --git a/web/i18n/de-DE/app.ts b/web/i18n/de-DE/app.ts index 0b5cbb07f..40478711c 100644 --- a/web/i18n/de-DE/app.ts +++ b/web/i18n/de-DE/app.ts @@ -288,6 +288,9 @@ const translation = { useAtForSpecific: 'Verwenden von @ für bestimmte Typen', searchTitle: 'Suchen Sie nach irgendetwas', searching: 'Suche...', + selectSearchType: 'Wählen Sie aus, wonach gesucht werden soll', + commandHint: 'Geben Sie @ ein, um nach Kategorie zu suchen', + searchHint: 'Beginnen Sie mit der Eingabe, um alles sofort zu durchsuchen', }, } diff --git a/web/i18n/en-US/app.ts b/web/i18n/en-US/app.ts index 722d591eb..eb4f3c404 100644 --- a/web/i18n/en-US/app.ts +++ b/web/i18n/en-US/app.ts @@ -266,6 +266,9 @@ const translation = { inScope: 'in {{scope}}s', clearToSearchAll: 'Clear @ to search all', useAtForSpecific: 'Use @ for specific types', + selectSearchType: 'Choose what to search for', + searchHint: 'Start typing to search everything instantly', + commandHint: 'Type @ to browse by category', actions: { searchApplications: 'Search Applications', searchApplicationsDesc: 'Search and navigate to your applications', diff --git a/web/i18n/es-ES/app.ts b/web/i18n/es-ES/app.ts index 1f50ae2a4..9ad9a9055 100644 --- a/web/i18n/es-ES/app.ts +++ b/web/i18n/es-ES/app.ts @@ -286,6 +286,9 @@ const translation = { searchTitle: 'Busca cualquier cosa', someServicesUnavailable: 'Algunos servicios de búsqueda no están disponibles', servicesUnavailableMessage: 'Algunos servicios de búsqueda pueden estar experimentando problemas. Inténtalo de nuevo en un momento.', + searchHint: 'Empieza a escribir para buscar todo al instante', + commandHint: 'Escriba @ para buscar por categoría', + selectSearchType: 'Elige qué buscar', }, } diff --git a/web/i18n/fa-IR/app.ts b/web/i18n/fa-IR/app.ts index e7d06e946..586631e2c 100644 --- a/web/i18n/fa-IR/app.ts +++ b/web/i18n/fa-IR/app.ts @@ -286,6 +286,9 @@ const translation = { searchTemporarilyUnavailable: 'جستجو به طور موقت در دسترس نیست', servicesUnavailableMessage: 'برخی از سرویس های جستجو ممکن است با مشکل مواجه شوند. یک لحظه دیگر دوباره امتحان کنید.', someServicesUnavailable: 'برخی از سرویس های جستجو دردسترس نیستند', + selectSearchType: 'انتخاب کنید چه چیزی را جستجو کنید', + commandHint: '@ را برای مرور بر اساس دسته بندی تایپ کنید', + searchHint: 'شروع به تایپ کنید تا فورا همه چیز را جستجو کنید', }, } diff --git a/web/i18n/fr-FR/app.ts b/web/i18n/fr-FR/app.ts index 1aa7c2a4d..1e4ff9f12 100644 --- a/web/i18n/fr-FR/app.ts +++ b/web/i18n/fr-FR/app.ts @@ -286,6 +286,9 @@ const translation = { searchPlaceholder: 'Recherchez ou tapez @ pour les commandes...', searchFailed: 'Echec de la recherche', noResults: 'Aucun résultat trouvé', + commandHint: 'Tapez @ pour parcourir par catégorie', + selectSearchType: 'Choisissez les éléments de recherche', + searchHint: 'Commencez à taper pour tout rechercher instantanément', }, } diff --git a/web/i18n/hi-IN/app.ts b/web/i18n/hi-IN/app.ts index c97d4e255..21c93d9ed 100644 --- a/web/i18n/hi-IN/app.ts +++ b/web/i18n/hi-IN/app.ts @@ -286,6 +286,9 @@ const translation = { searchPlaceholder: 'कमांड के लिए खोजें या टाइप करें @...', searchTemporarilyUnavailable: 'खोज अस्थायी रूप से उपलब्ध नहीं है', servicesUnavailableMessage: 'कुछ खोज सेवाएँ समस्याओं का सामना कर सकती हैं। थोड़ी देर बाद फिर से प्रयास करें।', + commandHint: '@ का उपयोग कर श्रेणी के अनुसार ब्राउज़ करें', + selectSearchType: 'खोजने के लिए क्या चुनें', + searchHint: 'सब कुछ तुरंत खोजने के लिए टाइप करना शुरू करें', }, } diff --git a/web/i18n/it-IT/app.ts b/web/i18n/it-IT/app.ts index 926bd4551..91e5f2007 100644 --- a/web/i18n/it-IT/app.ts +++ b/web/i18n/it-IT/app.ts @@ -292,6 +292,9 @@ const translation = { noResults: 'Nessun risultato trovato', useAtForSpecific: 'Utilizzare @ per tipi specifici', clearToSearchAll: 'Cancella @ per cercare tutto', + selectSearchType: 'Scegli cosa cercare', + commandHint: 'Digita @ per sfogliare per categoria', + searchHint: 'Inizia a digitare per cercare tutto all\'istante', }, } diff --git a/web/i18n/ja-JP/app.ts b/web/i18n/ja-JP/app.ts index ea391c79f..ac30d9126 100644 --- a/web/i18n/ja-JP/app.ts +++ b/web/i18n/ja-JP/app.ts @@ -265,6 +265,9 @@ const translation = { inScope: '{{scope}}s 内', clearToSearchAll: '@ をクリアしてすべてを検索', useAtForSpecific: '特定のタイプには @ を使用', + selectSearchType: '検索対象を選択', + searchHint: '入力を開始してすべてを瞬時に検索', + commandHint: '@ を入力してカテゴリ別に参照', actions: { searchApplications: 'アプリケーションを検索', searchApplicationsDesc: 'アプリケーションを検索してナビゲート', diff --git a/web/i18n/ko-KR/app.ts b/web/i18n/ko-KR/app.ts index 821072ed7..c1f60222f 100644 --- a/web/i18n/ko-KR/app.ts +++ b/web/i18n/ko-KR/app.ts @@ -306,6 +306,9 @@ const translation = { searchFailed: '검색 실패', searchPlaceholder: '명령을 검색하거나 @를 입력합니다...', clearToSearchAll: '@를 지우면 모두 검색됩니다.', + selectSearchType: '검색할 항목 선택', + commandHint: '@를 입력하여 카테고리별로 찾아봅니다.', + searchHint: '즉시 모든 것을 검색하려면 입력을 시작하세요.', }, } diff --git a/web/i18n/pl-PL/app.ts b/web/i18n/pl-PL/app.ts index eeadf1985..09602c001 100644 --- a/web/i18n/pl-PL/app.ts +++ b/web/i18n/pl-PL/app.ts @@ -287,6 +287,9 @@ const translation = { searchTemporarilyUnavailable: 'Wyszukiwanie chwilowo niedostępne', servicesUnavailableMessage: 'W przypadku niektórych usług wyszukiwania mogą występować problemy. Spróbuj ponownie za chwilę.', searchFailed: 'Wyszukiwanie nie powiodło się', + searchHint: 'Zacznij pisać, aby natychmiast wszystko przeszukać', + commandHint: 'Wpisz @, aby przeglądać według kategorii', + selectSearchType: 'Wybierz, czego chcesz szukać', }, } diff --git a/web/i18n/pt-BR/app.ts b/web/i18n/pt-BR/app.ts index cfda16e9a..f26549819 100644 --- a/web/i18n/pt-BR/app.ts +++ b/web/i18n/pt-BR/app.ts @@ -286,6 +286,9 @@ const translation = { useAtForSpecific: 'Use @ para tipos específicos', clearToSearchAll: 'Desmarque @ para pesquisar tudo', searchFailed: 'Falha na pesquisa', + searchHint: 'Comece a digitar para pesquisar tudo instantaneamente', + commandHint: 'Digite @ para navegar por categoria', + selectSearchType: 'Escolha o que pesquisar', }, } diff --git a/web/i18n/ro-RO/app.ts b/web/i18n/ro-RO/app.ts index 09bda641a..ad6cba2d1 100644 --- a/web/i18n/ro-RO/app.ts +++ b/web/i18n/ro-RO/app.ts @@ -286,6 +286,9 @@ const translation = { servicesUnavailableMessage: 'Este posibil ca unele servicii de căutare să întâmpine probleme. Încercați din nou într-o clipă.', someServicesUnavailable: 'Unele servicii de căutare nu sunt disponibile', clearToSearchAll: 'Ștergeți @ pentru a căuta toate', + selectSearchType: 'Alegeți ce să căutați', + commandHint: 'Tastați @ pentru a naviga după categorie', + searchHint: 'Începeți să tastați pentru a căuta totul instantaneu', }, } diff --git a/web/i18n/ru-RU/app.ts b/web/i18n/ru-RU/app.ts index 933f48747..28641956f 100644 --- a/web/i18n/ru-RU/app.ts +++ b/web/i18n/ru-RU/app.ts @@ -286,6 +286,9 @@ const translation = { searchPlaceholder: 'Найдите или введите @ для команд...', someServicesUnavailable: 'Некоторые поисковые сервисы недоступны', servicesUnavailableMessage: 'В некоторых поисковых службах могут возникать проблемы. Повторите попытку через мгновение.', + searchHint: 'Начните печатать, чтобы мгновенно искать все', + commandHint: 'Введите @ для просмотра по категориям', + selectSearchType: 'Выберите, что искать', }, } diff --git a/web/i18n/sl-SI/app.ts b/web/i18n/sl-SI/app.ts index 29cc9b805..598bb4578 100644 --- a/web/i18n/sl-SI/app.ts +++ b/web/i18n/sl-SI/app.ts @@ -286,6 +286,9 @@ const translation = { searchFailed: 'Iskanje ni uspelo', useAtForSpecific: 'Uporaba znaka @ za določene vrste', servicesUnavailableMessage: 'Pri nekaterih iskalnih storitvah se morda pojavljajo težave. Poskusite znova čez trenutek.', + commandHint: 'Vnesite @ za brskanje po kategoriji', + selectSearchType: 'Izberite, kaj želite iskati', + searchHint: 'Začnite tipkati, da takoj preiščete vse', }, } diff --git a/web/i18n/th-TH/app.ts b/web/i18n/th-TH/app.ts index 3831a3829..32f42be5f 100644 --- a/web/i18n/th-TH/app.ts +++ b/web/i18n/th-TH/app.ts @@ -282,6 +282,9 @@ const translation = { searchPlaceholder: 'ค้นหาหรือพิมพ์ @ สําหรับคําสั่ง...', servicesUnavailableMessage: 'บริการค้นหาบางบริการอาจประสบปัญหา ลองอีกครั้งในอีกสักครู่', searching: 'กำลังค้นหา...', + searchHint: 'เริ่มพิมพ์เพื่อค้นหาทุกอย่างได้ทันที', + selectSearchType: 'เลือกสิ่งที่จะค้นหา', + commandHint: 'พิมพ์ @ เพื่อเรียกดูตามหมวดหมู่', }, } diff --git a/web/i18n/tr-TR/app.ts b/web/i18n/tr-TR/app.ts index 61203684d..9ef6e28a3 100644 --- a/web/i18n/tr-TR/app.ts +++ b/web/i18n/tr-TR/app.ts @@ -282,6 +282,9 @@ const translation = { noResults: 'Sonuç bulunamadı', servicesUnavailableMessage: 'Bazı arama hizmetlerinde sorunlar yaşanıyor olabilir. Kısa bir süre sonra tekrar deneyin.', searching: 'Araştırıcı...', + selectSearchType: 'Ne arayacağınızı seçin', + searchHint: 'Her şeyi anında aramak için yazmaya başlayın', + commandHint: 'Kategoriye göre göz atmak için @ yazın', }, } diff --git a/web/i18n/uk-UA/app.ts b/web/i18n/uk-UA/app.ts index 4f3e60082..a9f7121f9 100644 --- a/web/i18n/uk-UA/app.ts +++ b/web/i18n/uk-UA/app.ts @@ -286,6 +286,9 @@ const translation = { useAtForSpecific: 'Використовуйте @ для конкретних типів', someServicesUnavailable: 'Деякі пошукові сервіси недоступні', servicesUnavailableMessage: 'У деяких пошукових службах можуть виникати проблеми. Повторіть спробу за мить.', + selectSearchType: 'Виберіть, що шукати', + commandHint: 'Введіть @ для навігації за категоріями', + searchHint: 'Почніть вводити текст, щоб миттєво шукати все', }, } diff --git a/web/i18n/vi-VN/app.ts b/web/i18n/vi-VN/app.ts index 45d43d36e..3d11a2e18 100644 --- a/web/i18n/vi-VN/app.ts +++ b/web/i18n/vi-VN/app.ts @@ -286,6 +286,9 @@ const translation = { useAtForSpecific: 'Sử dụng @ cho các loại cụ thể', someServicesUnavailable: 'Một số dịch vụ tìm kiếm không khả dụng', servicesUnavailableMessage: 'Một số dịch vụ tìm kiếm có thể gặp sự cố. Thử lại trong giây lát.', + searchHint: 'Bắt đầu nhập để tìm kiếm mọi thứ ngay lập tức', + commandHint: 'Nhập @ để duyệt theo danh mục', + selectSearchType: 'Chọn nội dung để tìm kiếm', }, } diff --git a/web/i18n/zh-Hans/app.ts b/web/i18n/zh-Hans/app.ts index 5acc4c13c..6bb4837a6 100644 --- a/web/i18n/zh-Hans/app.ts +++ b/web/i18n/zh-Hans/app.ts @@ -265,6 +265,9 @@ const translation = { inScope: '在 {{scope}}s 中', clearToSearchAll: '清除 @ 以搜索全部', useAtForSpecific: '使用 @ 进行特定类型搜索', + selectSearchType: '选择搜索内容', + searchHint: '开始输入即可立即搜索所有内容', + commandHint: '输入 @ 按类别浏览', actions: { searchApplications: '搜索应用程序', searchApplicationsDesc: '搜索并导航到您的应用程序', diff --git a/web/i18n/zh-Hant/app.ts b/web/i18n/zh-Hant/app.ts index 1164db0ad..e009f07df 100644 --- a/web/i18n/zh-Hant/app.ts +++ b/web/i18n/zh-Hant/app.ts @@ -285,6 +285,9 @@ const translation = { someServicesUnavailable: '某些搜索服務不可用', useAtForSpecific: '對特定類型使用 @', searchTemporarilyUnavailable: '搜索暫時不可用', + selectSearchType: '選擇要搜索的內容', + commandHint: '鍵入 @ 按類別流覽', + searchHint: '開始輸入以立即搜索所有內容', }, }