fix: CMDK freeze (#11440)

* fix: CMDK freeze

* fix: Cannot ssearch folder

* fix: Cannot ssearch folder

* fix: Update translation
This commit is contained in:
René Wang
2026-01-12 20:03:37 +08:00
committed by GitHub
parent 9daacde1d8
commit e0db55b75f
27 changed files with 172 additions and 71 deletions

View File

@@ -134,6 +134,8 @@
"cmdk.search.communityAgent": "وكيل المجتمع",
"cmdk.search.file": "ملف",
"cmdk.search.files": "ملفات",
"cmdk.search.folder": "مجلد",
"cmdk.search.folders": "مجلدات",
"cmdk.search.loading": "يتم البحث...",
"cmdk.search.market": "المجتمع",
"cmdk.search.mcp": "خادم MCP",
@@ -389,4 +391,4 @@
"userPanel.setting": "الإعدادات",
"userPanel.usages": "إحصائيات الاستخدام",
"version": "الإصدار"
}
}

View File

@@ -12,9 +12,9 @@
"interests.area.writing": "إنشاء المحتوى",
"interests.hint": "يمكنك تغيير هذا في أي وقت من الإعدادات",
"interests.placeholder": "أدخل اهتماماتك...",
"interests.title": "هل يمكنك إخباري بالمجالات التي تهمك؟",
"interests.title2": "سيساعدني هذا في تكوين انطباع أولي عنك~",
"interests.title3": "خذ وقتك، وسأتعرف عليك أكثر فأكثر",
"interests.title": "ما هي المجالات التي تهمك؟",
"interests.title2": "سيساعدني هذا على التعرف عليك بشكل أفضل",
"interests.title3": "خذ وقتك، سأتعرف عليك أكثر",
"modeSelection.desc": "اختر الوضع الذي يناسبك",
"modeSelection.hint": "يمكنك تغييره في أي وقت من الإعدادات",
"modeSelection.lite.desc": "مثالي للمحادثات اليومية، الأسئلة والأجوبة، الإنتاجية الخفيفة، وتجربة النماذج",
@@ -63,4 +63,4 @@
"username.title": "بالمناسبة، ماذا يجب أن أُسميك؟",
"username.title2": "دعنا نتعرف على بعضنا أولاً!",
"username.title3": "هكذا يمكننا التحدث بشكل طبيعي أكثر من الآن فصاعدًا~"
}
}

View File

@@ -12,9 +12,9 @@
"interests.area.writing": "Създаване на съдържание",
"interests.hint": "Можете да го промените по всяко време в настройките",
"interests.placeholder": "Въведете вашите интереси...",
"interests.title": "Може ли да ми кажете в кои области се интересувате?",
"interests.title2": "Това ще ми помогне да добия първо впечатление за вас~",
"interests.title3": "Отделете си време, ще ви опознавам все по-добре",
"interests.title": "В какви области се интересуваш?",
"interests.title2": "Това ще ми помогне да те опозная по-добре",
"interests.title3": "Не бързай, ще те опозная постепенно",
"modeSelection.desc": "Изберете режима, който най-добре ви подхожда",
"modeSelection.hint": "Можете да го промените по всяко време в настройките",
"modeSelection.lite.desc": "Идеален за ежедневни разговори, въпроси и отговори, лека продуктивност и тестване на модели",
@@ -63,4 +63,4 @@
"username.title": "Между другото, как да ви наричам?",
"username.title2": "Нека първо се опознаем!",
"username.title3": "Така ще можем да си говорим по-естествено оттук нататък~"
}
}

View File

@@ -12,9 +12,6 @@
"interests.area.writing": "Texterstellung",
"interests.hint": "Du kannst das jederzeit in den Einstellungen ändern",
"interests.placeholder": "Gib deine Interessen ein...",
"interests.title": "Wofür interessierst du dich?",
"interests.title2": "So bekomme ich einen ersten Eindruck von dir~",
"interests.title3": "Nimm dir Zeit ich lerne dich immer besser kennen",
"modeSelection.desc": "Wähle den Modus, der am besten zu dir passt",
"modeSelection.hint": "Du kannst das jederzeit in den Einstellungen ändern",
"modeSelection.lite.desc": "Ideal für alltägliche Gespräche, Fragen & Antworten, leichte Produktivität und zum Ausprobieren von Modellen",

View File

@@ -134,6 +134,8 @@
"cmdk.search.communityAgent": "Community Agent",
"cmdk.search.file": "File",
"cmdk.search.files": "Files",
"cmdk.search.folder": "Folder",
"cmdk.search.folders": "Folders",
"cmdk.search.loading": "Searching...",
"cmdk.search.market": "Community",
"cmdk.search.mcp": "MCP Server",

View File

@@ -12,9 +12,9 @@
"interests.area.writing": "Content Creation",
"interests.hint": "You can change this anytime in settings",
"interests.placeholder": "Enter your interests...",
"interests.title": "Could you tell me what areas you're interested in?",
"interests.title2": "This will help me get a first impression of you~",
"interests.title3": "Take your time, I'll get to know you better and better",
"interests.title": "What areas you're interested in?",
"interests.title2": "This will help me know you better",
"interests.title3": "Take your time, I'll get to know you better",
"modeSelection.desc": "Choose the mode that suits you best",
"modeSelection.hint": "You can change this anytime in settings",
"modeSelection.lite.desc": "Ideal for everyday conversations, Q&A, light productivity, and trying out models",

View File

@@ -12,9 +12,6 @@
"interests.area.writing": "Creación de Contenido",
"interests.hint": "Puedes cambiar esto en cualquier momento desde la configuración",
"interests.placeholder": "Escribe tus intereses...",
"interests.title": "¿Podrías decirme en qué áreas estás interesado?",
"interests.title2": "Esto me ayudará a tener una primera impresión de ti~",
"interests.title3": "Tómate tu tiempo, te iré conociendo cada vez mejor",
"modeSelection.desc": "Elige el modo que mejor se adapte a ti",
"modeSelection.hint": "Puedes cambiar esto en cualquier momento desde la configuración",
"modeSelection.lite.desc": "Ideal para conversaciones cotidianas, preguntas y respuestas, productividad ligera y probar modelos",

View File

@@ -12,9 +12,6 @@
"interests.area.writing": "تولید محتوا",
"interests.hint": "می‌توانید هر زمان از تنظیمات این را تغییر دهید",
"interests.placeholder": "علایق خود را وارد کنید...",
"interests.title": "می‌تونی بهم بگی به چه حوزه‌هایی علاقه‌مندی؟",
"interests.title2": "این کمکم می‌کنه یه دید اولیه ازت داشته باشم~",
"interests.title3": "عجله نکن، کم‌کم بیشتر باهات آشنا می‌شم",
"modeSelection.desc": "حالت کاری‌ای که برات مناسب‌تره رو انتخاب کن",
"modeSelection.hint": "می‌تونی هر زمان از تنظیمات تغییرش بدی",
"modeSelection.lite.desc": "مناسب برای گفتگوهای روزمره، پرسش و پاسخ، بهره‌وری سبک و تست مدل‌ها",

View File

@@ -12,9 +12,6 @@
"interests.area.writing": "Création de Contenu",
"interests.hint": "Vous pouvez modifier cela à tout moment dans les paramètres",
"interests.placeholder": "Indiquez vos centres dintérêt...",
"interests.title": "Pourriez-vous me dire quels sont vos domaines dintérêt ?",
"interests.title2": "Cela maidera à me faire une première idée de vous~",
"interests.title3": "Prenez votre temps, je vais apprendre à mieux vous connaître",
"modeSelection.desc": "Choisissez le mode qui vous convient le mieux",
"modeSelection.hint": "Vous pouvez modifier cela à tout moment dans les paramètres",
"modeSelection.lite.desc": "Idéal pour les conversations quotidiennes, les questions-réponses, la productivité légère et lexploration de modèles",

View File

@@ -12,9 +12,6 @@
"interests.area.writing": "Creazione di Contenuti",
"interests.hint": "Puoi modificarlo in qualsiasi momento nelle impostazioni",
"interests.placeholder": "Inserisci i tuoi interessi...",
"interests.title": "Mi diresti in quali ambiti sei interessato?",
"interests.title2": "Questo mi aiuterà a farmi una prima impressione di te~",
"interests.title3": "Prenditi il tuo tempo, ti conoscerò sempre meglio",
"modeSelection.desc": "Scegli la modalità che fa più per te",
"modeSelection.hint": "Puoi modificarla in qualsiasi momento nelle impostazioni",
"modeSelection.lite.desc": "Ideale per conversazioni quotidiane, domande e risposte, produttività leggera e test dei modelli",

View File

@@ -12,9 +12,6 @@
"interests.area.writing": "コンテンツ制作",
"interests.hint": "設定からいつでも変更できます",
"interests.placeholder": "興味のある分野を入力してください...",
"interests.title": "興味のある分野を教えてもらえますか?",
"interests.title2": "あなたの第一印象をつかむ手助けをさせてください~",
"interests.title3": "ゆっくりで大丈夫、もっとあなたを理解していきます",
"modeSelection.desc": "あなたに合った使用モードを選択してください",
"modeSelection.hint": "設定からいつでも変更できます",
"modeSelection.lite.desc": "日常会話やQ&A、軽作業のサポートやモデル体験に最適",

View File

@@ -12,9 +12,6 @@
"interests.area.writing": "콘텐츠 제작",
"interests.hint": "설정에서 언제든지 수정할 수 있어요",
"interests.placeholder": "관심 있는 분야를 입력해 주세요...",
"interests.title": "관심 있는 분야를 알려주실 수 있나요?",
"interests.title2": "당신에 대한 첫인상을 형성하는 데 도움이 돼요~",
"interests.title3": "천천히 해요, 점점 더 잘 알게 될 거예요",
"modeSelection.desc": "당신에게 맞는 사용 모드를 선택하세요",
"modeSelection.hint": "설정에서 언제든지 변경할 수 있어요",
"modeSelection.lite.desc": "일상 대화, Q&A, 가벼운 업무 보조 및 모델 체험에 적합",

View File

@@ -12,9 +12,6 @@
"interests.area.writing": "Contentcreatie",
"interests.hint": "Je kunt dit op elk moment aanpassen in de instellingen",
"interests.placeholder": "Voer je interesses in...",
"interests.title": "Kun je me vertellen waar je in geïnteresseerd bent?",
"interests.title2": "Zo krijg ik alvast een eerste indruk van je~",
"interests.title3": "Neem je tijd, ik leer je steeds beter kennen",
"modeSelection.desc": "Kies de modus die het beste bij je past",
"modeSelection.hint": "Je kunt dit op elk moment aanpassen in de instellingen",
"modeSelection.lite.desc": "Ideaal voor dagelijkse gesprekken, Q&A, lichte productiviteit en het uitproberen van modellen",

View File

@@ -12,9 +12,6 @@
"interests.area.writing": "Tworzenie treści",
"interests.hint": "Możesz to zmienić w każdej chwili w ustawieniach",
"interests.placeholder": "Wpisz swoje zainteresowania...",
"interests.title": "Powiesz mi, czym się interesujesz?",
"interests.title2": "To pomoże mi wyrobić sobie o Tobie pierwsze wrażenie~",
"interests.title3": "Nie spiesz się, z czasem poznam Cię coraz lepiej",
"modeSelection.desc": "Wybierz tryb pracy, który najbardziej Ci odpowiada",
"modeSelection.hint": "Możesz to zmienić w każdej chwili w ustawieniach",
"modeSelection.lite.desc": "Idealny do codziennych rozmów, pytań i odpowiedzi, lekkiej pracy i testowania modeli",

View File

@@ -12,9 +12,6 @@
"interests.area.writing": "Criação de Conteúdo",
"interests.hint": "Você pode mudar isso a qualquer momento nas configurações",
"interests.placeholder": "Digite seus interesses...",
"interests.title": "Você pode me contar em quais áreas tem interesse?",
"interests.title2": "Isso vai me ajudar a ter uma primeira impressão sobre você~",
"interests.title3": "Sem pressa, vou te conhecer cada vez melhor",
"modeSelection.desc": "Escolha o modo que combina mais com você",
"modeSelection.hint": "Você pode mudar isso a qualquer momento nas configurações",
"modeSelection.lite.desc": "Ideal para conversas do dia a dia, perguntas e respostas, produtividade leve e testes de modelos",

View File

@@ -12,9 +12,6 @@
"interests.area.writing": "Создание контента",
"interests.hint": "Вы можете изменить это в любое время в настройках",
"interests.placeholder": "Введите ваши интересы...",
"interests.title": "Расскажите, пожалуйста, какие области вам интересны?",
"interests.title2": "Это поможет мне составить первое впечатление о вас~",
"interests.title3": "Не спешите, я буду узнавать вас всё лучше и лучше",
"modeSelection.desc": "Выберите режим, который вам больше подходит",
"modeSelection.hint": "Вы можете изменить это в любое время в настройках",
"modeSelection.lite.desc": "Идеально для повседневного общения, вопросов и ответов, лёгкой продуктивности и тестирования моделей",

View File

@@ -12,9 +12,6 @@
"interests.area.writing": "İçerik Üretimi",
"interests.hint": "Bunu ayarlardan istediğiniz zaman değiştirebilirsiniz",
"interests.placeholder": "İlgi alanlarınızı girin...",
"interests.title": "Hangi alanlara ilgi duyduğunuzu söyler misiniz?",
"interests.title2": "Bu, sizinle ilgili ilk izlenimi edinmeme yardımcı olacak~",
"interests.title3": "Acelemiz yok, sizi zamanla daha iyi tanıyacağım",
"modeSelection.desc": "Size en uygun modu seçin",
"modeSelection.hint": "Bunu ayarlardan istediğiniz zaman değiştirebilirsiniz",
"modeSelection.lite.desc": "Günlük sohbetler, soru-cevap, hafif işler ve modelleri denemek için ideal",

View File

@@ -12,9 +12,6 @@
"interests.area.writing": "Sáng tạo nội dung",
"interests.hint": "Bạn có thể thay đổi điều này bất cứ lúc nào trong cài đặt",
"interests.placeholder": "Nhập sở thích của bạn...",
"interests.title": "Bạn có thể cho tôi biết bạn quan tâm đến lĩnh vực nào không?",
"interests.title2": "Điều này sẽ giúp tôi có ấn tượng đầu tiên về bạn~",
"interests.title3": "Cứ từ từ nhé, tôi sẽ hiểu bạn rõ hơn theo thời gian",
"modeSelection.desc": "Chọn chế độ làm việc phù hợp với bạn nhất",
"modeSelection.hint": "Bạn có thể thay đổi điều này bất cứ lúc nào trong cài đặt",
"modeSelection.lite.desc": "Phù hợp cho trò chuyện hàng ngày, hỏi đáp, làm việc nhẹ và thử nghiệm mô hình",

View File

@@ -134,6 +134,8 @@
"cmdk.search.communityAgent": "社区助理",
"cmdk.search.file": "文件",
"cmdk.search.files": "文件",
"cmdk.search.folder": "文件夹",
"cmdk.search.folders": "文件夹",
"cmdk.search.loading": "搜索中…",
"cmdk.search.market": "社区",
"cmdk.search.mcp": "MCP 服务器",

View File

@@ -12,9 +12,6 @@
"interests.area.writing": "内容创作",
"interests.hint": "可随时在设置中修改",
"interests.placeholder": "搜索或输入领域…",
"interests.title": "能告诉我你感兴趣的领域吗?",
"interests.title2": "帮我建立对你的初步印象",
"interests.title3": "慢慢来,我会越来越懂你",
"modeSelection.desc": "选择适合你的工作方式",
"modeSelection.hint": "可随时在设置中切换",
"modeSelection.lite.desc": "适合日常对话、问答与轻量任务",

View File

@@ -12,9 +12,6 @@
"interests.area.writing": "內容創作",
"interests.hint": "你可以隨時在設定中修改",
"interests.placeholder": "請輸入你感興趣的領域...",
"interests.title": "可以告訴我你感興趣的領域嗎?",
"interests.title2": "幫助我建立對你的初步印象~",
"interests.title3": "慢慢來,我會越來越了解你",
"modeSelection.desc": "選擇適合你的使用模式",
"modeSelection.hint": "你可以隨時在設定中修改",
"modeSelection.lite.desc": "適合日常對話與問答、輕度工作輔助與模型體驗",

View File

@@ -9,6 +9,7 @@ export type SearchResultType =
| 'agent'
| 'topic'
| 'file'
| 'folder'
| 'memory'
| 'message'
| 'mcp'
@@ -60,6 +61,12 @@ export interface FileSearchResult extends BaseSearchResult {
url: string | null;
}
export interface FolderSearchResult extends BaseSearchResult {
knowledgeBaseId: string | null;
slug: string | null;
type: 'folder';
}
export interface MessageSearchResult extends BaseSearchResult {
agentId: string | null;
content: string;
@@ -106,6 +113,7 @@ export type SearchResult =
| AgentSearchResult
| TopicSearchResult
| FileSearchResult
| FolderSearchResult
| MessageSearchResult
| MCPSearchResult
| PluginSearchResult
@@ -167,6 +175,9 @@ export class SearchRepo {
if ((!type || type === 'file') && limits.file > 0) {
queries.push(this.buildFileQuery(searchTerm, exactQuery, prefixQuery, limits.file));
}
if ((!type || type === 'folder') && limits.folder > 0) {
queries.push(this.buildFolderQuery(searchTerm, exactQuery, prefixQuery, limits.folder));
}
if ((!type || type === 'page') && limits.page > 0) {
queries.push(this.buildPageQuery(searchTerm, exactQuery, prefixQuery, limits.page));
}
@@ -192,7 +203,7 @@ export class SearchRepo {
* Calculate result limits based on context
* - Agent context: expand topics (6) and messages (6), limit others (3 each)
* - Page context: expand pages (6), limit others (3 each)
* - Resource context: expand files (6), limit others (3 each)
* - Resource context: expand files (6) and folders (6), limit others (3 each)
* - General context: limit all types to 3 each
*/
private calculateLimits(
@@ -203,6 +214,7 @@ export class SearchRepo {
): {
agent: number;
file: number;
folder: number;
message: number;
page: number;
pageContent: number;
@@ -213,6 +225,7 @@ export class SearchRepo {
return {
agent: type === 'agent' ? baseLimit : 0,
file: type === 'file' ? baseLimit : 0,
folder: type === 'folder' ? baseLimit : 0,
message: type === 'message' ? baseLimit : 0,
page: type === 'page' ? baseLimit : 0,
pageContent: type === 'pageContent' ? baseLimit : 0,
@@ -225,6 +238,7 @@ export class SearchRepo {
return {
agent: 3,
file: 3,
folder: 3,
message: 3,
page: 6,
pageContent: 0, // Not available yet
@@ -232,11 +246,12 @@ export class SearchRepo {
};
}
// Resource context: expand files to 6, limit others to 3
// Resource context: expand files and folders to 6, limit others to 3
if (contextType === 'resource') {
return {
agent: 3,
file: 6,
folder: 6,
message: 3,
page: 3,
pageContent: 0, // Not available yet
@@ -249,6 +264,7 @@ export class SearchRepo {
return {
agent: 3,
file: 3,
folder: 3,
message: 6,
page: 3,
pageContent: 0, // Not available yet
@@ -260,6 +276,7 @@ export class SearchRepo {
return {
agent: 3,
file: 3,
folder: 3,
message: 3,
page: 3,
pageContent: 0, // Not available yet
@@ -267,6 +284,20 @@ export class SearchRepo {
};
}
/**
* Truncate content at database level with ellipsis indicator
* Uses SQL LEFT() function for efficient truncation
* Note: This helper is defined for documentation but not currently used.
* Truncation is implemented inline in query methods for better SQL readability.
*/
private truncateContent(columnName: string, maxLength: number): string {
return `CASE
WHEN LENGTH(${columnName}) > ${maxLength}
THEN LEFT(${columnName}, ${maxLength}) || '...'
ELSE ${columnName}
END`;
}
/**
* Build agent search query
* Searches: title, description, slug, tags (JSONB array)
@@ -362,7 +393,10 @@ export class SearchRepo {
t.id,
'topic' as type,
t.title,
t.content as description,
CASE
WHEN length(COALESCE(t.content, '')) > 200 THEN substring(COALESCE(t.content, ''), 1, 200) || '...'
ELSE t.content
END as description,
NULL::varchar(100) as slug,
NULL::text as avatar,
NULL::text as background_color,
@@ -447,7 +481,7 @@ export class SearchRepo {
m.id,
'message' as type,
CASE
WHEN length(m.content) > 100 THEN substring(m.content, 1, 100) || '...'
WHEN length(m.content) > 200 THEN substring(m.content, 1, 200) || '...'
ELSE m.content
END as title,
COALESCE(a.title, 'General Chat') as description,
@@ -492,7 +526,10 @@ export class SearchRepo {
f.id,
'file' as type,
f.name as title,
d.content as description,
CASE
WHEN length(COALESCE(d.content, '')) > 200 THEN substring(COALESCE(d.content, ''), 1, 200) || '...'
ELSE d.content
END as description,
NULL::varchar(100) as slug,
NULL::text as avatar,
NULL::text as background_color,
@@ -520,13 +557,16 @@ export class SearchRepo {
AND f.name ILIKE ${searchTerm}
`;
// Query for standalone documents (not pages and not linked to files)
// Query for standalone documents (not pages, not folders, and not linked to files)
const documentQuery = sql`
SELECT
d.id,
'file' as type,
COALESCE(d.title, d.filename, 'Untitled') as title,
d.content as description,
CASE
WHEN length(COALESCE(d.content, '')) > 200 THEN substring(COALESCE(d.content, ''), 1, 200) || '...'
ELSE d.content
END as description,
NULL::varchar(100) as slug,
NULL::text as avatar,
NULL::text as background_color,
@@ -552,6 +592,7 @@ export class SearchRepo {
WHERE d.user_id = ${this.userId}
AND d.source_type != 'file'
AND d.file_type != 'custom/document'
AND d.file_type != 'custom/folder'
AND (
COALESCE(d.title, '') ILIKE ${searchTerm}
OR COALESCE(d.filename, '') ILIKE ${searchTerm}
@@ -571,6 +612,54 @@ export class SearchRepo {
`;
}
/**
* Build folder search query
* Searches folders in the documents table (file_type='custom/folder')
*/
private buildFolderQuery(
searchTerm: string,
exactQuery: string,
prefixQuery: string,
limit: number,
): ReturnType<typeof sql> {
return sql`
SELECT
d.id,
'folder' as type,
COALESCE(d.title, d.filename, 'Untitled') as title,
d.description,
d.slug,
NULL::text as avatar,
NULL::text as background_color,
NULL::jsonb as tags,
d.created_at,
d.updated_at,
CASE
WHEN COALESCE(d.title, d.filename) ILIKE ${exactQuery} THEN 1
WHEN COALESCE(d.title, d.filename) ILIKE ${prefixQuery} THEN 2
ELSE 3
END as relevance,
NULL::boolean as favorite,
NULL::text as session_id,
NULL::text as agent_id,
COALESCE(d.title, d.filename, 'Untitled') as name,
d.file_type,
NULL::integer as size,
NULL::text as url,
d.knowledge_base_id
FROM ${documents} d
WHERE d.user_id = ${this.userId}
AND d.file_type = 'custom/folder'
AND (
COALESCE(d.title, '') ILIKE ${searchTerm}
OR COALESCE(d.filename, '') ILIKE ${searchTerm}
OR COALESCE(d.description, '') ILIKE ${searchTerm}
)
ORDER BY relevance ASC, updated_at DESC
LIMIT ${limit}
`;
}
/**
* Build page search query
* Fast search on page titles only (no content search for better performance)
@@ -635,7 +724,10 @@ export class SearchRepo {
d.id,
'pageContent' as type,
COALESCE(d.title, d.filename, 'Untitled') as title,
d.content as description,
CASE
WHEN length(COALESCE(d.content, '')) > 200 THEN substring(COALESCE(d.content, ''), 1, 200) || '...'
ELSE d.content
END as description,
NULL::varchar(100) as slug,
NULL::text as avatar,
NULL::text as background_color,
@@ -737,6 +829,14 @@ export class SearchRepo {
url: row.url,
};
}
case 'folder': {
return {
...base,
knowledgeBaseId: row.knowledge_base_id,
slug: row.slug,
type: 'folder' as const,
};
}
case 'message': {
return {
...base,

View File

@@ -4,6 +4,7 @@ import {
Bot,
ChevronRight,
FileText,
Folder,
MessageCircle,
MessageSquare,
Plug,
@@ -75,6 +76,18 @@ const SearchResults = memo<SearchResultsProps>(
}
break;
}
case 'folder': {
// Navigate to folder by slug
if (result.knowledgeBaseId && result.slug) {
navigate(`/resource/library/${result.knowledgeBaseId}/${result.slug}`);
} else if (result.slug) {
navigate(`/resource/library/${result.slug}`);
} else {
// Fallback to library root if no slug
navigate(`/resource/library`);
}
break;
}
case 'page': {
navigate(`/page/${result.id.split('_')[1]}`);
break;
@@ -109,6 +122,9 @@ const SearchResults = memo<SearchResultsProps>(
case 'file': {
return <FileText size={16} />;
}
case 'folder': {
return <Folder size={16} />;
}
case 'page': {
return <FileText size={16} />;
}
@@ -138,6 +154,9 @@ const SearchResults = memo<SearchResultsProps>(
case 'file': {
return t('cmdk.search.file');
}
case 'folder': {
return t('cmdk.search.folder');
}
case 'page': {
return t('cmdk.search.page');
}
@@ -198,6 +217,7 @@ const SearchResults = memo<SearchResultsProps>(
const agentResults = results.filter((r) => r.type === 'agent');
const topicResults = results.filter((r) => r.type === 'topic');
const fileResults = results.filter((r) => r.type === 'file');
const folderResults = results.filter((r) => r.type === 'folder');
const pageResults = results.filter((r) => r.type === 'page');
const mcpResults = results.filter((r) => r.type === 'mcp');
const pluginResults = results.filter((r) => r.type === 'plugin');
@@ -315,6 +335,13 @@ const SearchResults = memo<SearchResultsProps>(
</Command.Group>
)}
{folderResults.length > 0 && (
<Command.Group>
{folderResults.map((result) => renderResultItem(result))}
{renderSearchMore('folder', folderResults.length)}
</Command.Group>
)}
{mcpResults.length > 0 && (
<Command.Group>
{mcpResults.map((result) => renderResultItem(result))}

View File

@@ -16,6 +16,7 @@ const VALID_TYPES = [
'topic',
'message',
'file',
'folder',
'page',
'mcp',
'plugin',

View File

@@ -148,6 +148,8 @@ export default {
'cmdk.search.communityAgent': 'Community Agent',
'cmdk.search.file': 'File',
'cmdk.search.files': 'Files',
'cmdk.search.folder': 'Folder',
'cmdk.search.folders': 'Folders',
'cmdk.search.loading': 'Searching...',
'cmdk.search.market': 'Community',
'cmdk.search.mcp': 'MCP Server',

View File

@@ -12,9 +12,9 @@ export default {
'interests.area.writing': 'Content Creation',
'interests.hint': 'You can change this anytime in settings',
'interests.placeholder': 'Enter your interests...',
'interests.title': "Could you tell me what areas you're interested in?",
'interests.title2': 'This will help me get a first impression of you~',
'interests.title3': "Take your time, I'll get to know you better and better",
'interests.title': "What areas you're interested in?",
'interests.title2': 'This will help me know you better',
'interests.title3': "Take your time, I'll get to know you better",
'modeSelection.desc': 'Choose the mode that suits you best',
'modeSelection.hint': 'You can change this anytime in settings',
'modeSelection.lite.desc':

View File

@@ -45,7 +45,17 @@ export const searchRouter = router({
offset: z.number().optional(),
query: z.string(),
type: z
.enum(['agent', 'topic', 'file', 'message', 'page', 'mcp', 'plugin', 'communityAgent'])
.enum([
'agent',
'topic',
'file',
'folder',
'message',
'page',
'mcp',
'plugin',
'communityAgent',
])
.optional(),
}),
)
@@ -58,8 +68,8 @@ export const searchRouter = router({
// Build search promises based on type filter
const searchPromises: Promise<any>[] = [];
// Database searches (agent, topic, file, message, page)
if (!type || ['agent', 'topic', 'file', 'message', 'page'].includes(type)) {
// Database searches (agent, topic, file, folder, message, page)
if (!type || ['agent', 'topic', 'file', 'folder', 'message', 'page'].includes(type)) {
searchPromises.push(ctx.searchRepo.search(input));
}