From b78df05f288bf85ad6bd15cf448c2645a7bc9c57 Mon Sep 17 00:00:00 2001 From: Phantom Date: Sun, 28 Dec 2025 15:30:01 +0800 Subject: [PATCH] fix(AssistantsTab): prevent deleting last assistant and add error message (#12162) feat(AssistantsTab): prevent deleting last assistant and add error message Add validation to prevent deleting the last assistant and show an error message when attempted. Also simplify the active assistant assignment logic when deleting an assistant. --- src/renderer/src/i18n/locales/en-us.json | 3 +++ src/renderer/src/i18n/locales/zh-cn.json | 3 +++ src/renderer/src/i18n/locales/zh-tw.json | 7 +++++-- src/renderer/src/i18n/translate/de-de.json | 7 +++++-- src/renderer/src/i18n/translate/el-gr.json | 7 +++++-- src/renderer/src/i18n/translate/es-es.json | 7 +++++-- src/renderer/src/i18n/translate/fr-fr.json | 7 +++++-- src/renderer/src/i18n/translate/ja-jp.json | 7 +++++-- src/renderer/src/i18n/translate/pt-pt.json | 7 +++++-- src/renderer/src/i18n/translate/ru-ru.json | 7 +++++-- src/renderer/src/pages/home/Tabs/AssistantsTab.tsx | 11 +++++++++-- 11 files changed, 55 insertions(+), 18 deletions(-) diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index 9528b4cd6b..9e60f31f00 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -420,6 +420,9 @@ }, "delete": { "content": "Deleting an assistant will delete all topics and files under the assistant. Are you sure you want to delete it?", + "error": { + "remain_one": "Not allowed to delete the last one assistant" + }, "title": "Delete Assistant" }, "edit": { diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index 524f32c338..b9b07a596c 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -420,6 +420,9 @@ }, "delete": { "content": "删除助手会删除所有该助手下的话题和文件,确定要继续吗?", + "error": { + "remain_one": "不允许删除最后一个助手" + }, "title": "删除助手" }, "edit": { diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index fe30018ac5..3d613f00f4 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -420,6 +420,9 @@ }, "delete": { "content": "刪除助手會刪除所有該助手下的話題和檔案,確定要繼續嗎?", + "error": { + "remain_one": "不允許刪除最後一個助手" + }, "title": "刪除助手" }, "edit": { @@ -4805,7 +4808,7 @@ "content_limit_tooltip": "限制搜尋結果的內容長度;超過限制的內容將被截斷。", "default_provider": "預設搜尋引擎", "free": "免費", - "is_default": "[to be translated]:Default", + "is_default": "預設", "local_provider": { "hint": "登入網站以獲得更佳搜尋結果並個人化您的搜尋設定。", "open_settings": "開啟 {{provider}} 設定", @@ -4822,7 +4825,7 @@ "search_provider": "搜尋供應商", "search_provider_placeholder": "選擇一個搜尋供應商", "search_with_time": "搜尋包含日期", - "set_as_default": "[to be translated]:Set as Default", + "set_as_default": "設為預設", "subscribe": "黑名單訂閱", "subscribe_add": "新增訂閱", "subscribe_add_failed": "訂閱來源新增失敗", diff --git a/src/renderer/src/i18n/translate/de-de.json b/src/renderer/src/i18n/translate/de-de.json index e77b9dede1..402437f1e8 100644 --- a/src/renderer/src/i18n/translate/de-de.json +++ b/src/renderer/src/i18n/translate/de-de.json @@ -420,6 +420,9 @@ }, "delete": { "content": "Das Löschen des Assistenten löscht alle Themen und Dateien unter diesem Assistenten. Möchten Sie fortfahren?", + "error": { + "remain_one": "Man darf den letzten Assistenten nicht löschen." + }, "title": "Assistent löschen" }, "edit": { @@ -4805,7 +4808,7 @@ "content_limit_tooltip": "Begrenzen Sie die Länge der Suchergebnisse, überschreitende Inhalte werden abgeschnitten", "default_provider": "Standardanbieter", "free": "Kostenlos", - "is_default": "[to be translated]:Default", + "is_default": "Standard", "local_provider": { "hint": "Melden Sie sich auf der Website an, um bessere Suchergebnisse zu erhalten und Ihre Sucheinstellungen zu personalisieren.", "open_settings": "{{provider}}-Einstellungen öffnen", @@ -4822,7 +4825,7 @@ "search_provider": "Suchanbieter", "search_provider_placeholder": "Einen Suchanbieter auswählen", "search_with_time": "Suche mit Datum", - "set_as_default": "[to be translated]:Set as Default", + "set_as_default": "Als Standard festlegen", "subscribe": "Schwarze Liste-Abonnement", "subscribe_add": "Abonnement hinzufügen", "subscribe_add_failed": "Abonnement-Quelle hinzufügen fehlgeschlagen", diff --git a/src/renderer/src/i18n/translate/el-gr.json b/src/renderer/src/i18n/translate/el-gr.json index 1593099707..1fb0b08abb 100644 --- a/src/renderer/src/i18n/translate/el-gr.json +++ b/src/renderer/src/i18n/translate/el-gr.json @@ -420,6 +420,9 @@ }, "delete": { "content": "Η διαγραφή του βοηθού θα διαγράψει όλα τα θέματα και τα αρχεία που είναι συνδεδεμένα με αυτόν. Είστε σίγουροι πως θέλετε να συνεχίσετε;", + "error": { + "remain_one": "Δεν επιτρέπεται η διαγραφή του τελευταίου βοηθού" + }, "title": "Διαγραφή βοηθού" }, "edit": { @@ -4805,7 +4808,7 @@ "content_limit_tooltip": "Περιορίζει το μήκος του περιεχομένου των αποτελεσμάτων αναζήτησης, το περιεχόμενο πέραν του ορίου θα περικοπεί", "default_provider": "Προεπιλεγμένος Πάροχος", "free": "Δωρεάν", - "is_default": "[to be translated]:Default", + "is_default": "Προεπιλογή", "local_provider": { "hint": "Συνδεθείτε στην ιστοσελίδα για να λάβετε καλύτερα αποτελέσματα αναζήτησης και να εξατομικεύσετε τις ρυθμίσεις αναζήτησής σας.", "open_settings": "Άνοιγμα Ρυθμίσεων {{provider}}", @@ -4822,7 +4825,7 @@ "search_provider": "Πάροχος αναζήτησης", "search_provider_placeholder": "Επιλέξτε έναν πάροχο αναζήτησης", "search_with_time": "Αναζήτηση με ημερομηνία", - "set_as_default": "[to be translated]:Set as Default", + "set_as_default": "Ορισμός ως προεπιλογή", "subscribe": "Εγγραφή σε μαύρη λίστα", "subscribe_add": "Προσθήκη εγγραφής", "subscribe_add_failed": "Η προσθήκη της ροής συνδρομής απέτυχε", diff --git a/src/renderer/src/i18n/translate/es-es.json b/src/renderer/src/i18n/translate/es-es.json index 56f06b1b53..1aa78e82dd 100644 --- a/src/renderer/src/i18n/translate/es-es.json +++ b/src/renderer/src/i18n/translate/es-es.json @@ -420,6 +420,9 @@ }, "delete": { "content": "Eliminar el asistente borrará todos los temas y archivos asociados. ¿Está seguro de que desea continuar?", + "error": { + "remain_one": "No se puede eliminar el último asistente" + }, "title": "Eliminar Asistente" }, "edit": { @@ -4805,7 +4808,7 @@ "content_limit_tooltip": "Limita la longitud del contenido en los resultados de búsqueda; el contenido que exceda el límite será truncado", "default_provider": "Proveedor Predeterminado", "free": "Gratis", - "is_default": "[to be translated]:Default", + "is_default": "Por defecto", "local_provider": { "hint": "Inicia sesión en el sitio web para obtener mejores resultados de búsqueda y personalizar tu configuración de búsqueda.", "open_settings": "Abrir configuración de {{provider}}", @@ -4822,7 +4825,7 @@ "search_provider": "Proveedor de búsqueda", "search_provider_placeholder": "Seleccione un proveedor de búsqueda", "search_with_time": "Buscar con fecha", - "set_as_default": "[to be translated]:Set as Default", + "set_as_default": "Establecer como predeterminado", "subscribe": "Suscripción a lista negra", "subscribe_add": "Añadir suscripción", "subscribe_add_failed": "Error al agregar la fuente de suscripción", diff --git a/src/renderer/src/i18n/translate/fr-fr.json b/src/renderer/src/i18n/translate/fr-fr.json index 4e8f2ac8e6..4906109228 100644 --- a/src/renderer/src/i18n/translate/fr-fr.json +++ b/src/renderer/src/i18n/translate/fr-fr.json @@ -420,6 +420,9 @@ }, "delete": { "content": "La suppression de l'aide supprimera tous les sujets et fichiers sous l'aide. Êtes-vous sûr de vouloir la supprimer ?", + "error": { + "remain_one": "Interdiction de supprimer le dernier assistant" + }, "title": "Supprimer l'Aide" }, "edit": { @@ -4805,7 +4808,7 @@ "content_limit_tooltip": "Limiter la longueur du contenu des résultats de recherche ; le contenu dépassant cette limite sera tronqué", "default_provider": "Fournisseur par défaut", "free": "Gratuit", - "is_default": "[to be translated]:Default", + "is_default": "Défaut", "local_provider": { "hint": "Connectez-vous au site Web pour obtenir de meilleurs résultats de recherche et personnaliser vos paramètres de recherche.", "open_settings": "Ouvrir les paramètres de {{provider}}", @@ -4822,7 +4825,7 @@ "search_provider": "Fournisseur de recherche", "search_provider_placeholder": "Sélectionnez un fournisseur de recherche", "search_with_time": "Rechercher avec date", - "set_as_default": "[to be translated]:Set as Default", + "set_as_default": "Définir par défaut", "subscribe": "Abonnement à la liste noire", "subscribe_add": "Ajouter un abonnement", "subscribe_add_failed": "Échec de l'ajout de la source d'abonnement", diff --git a/src/renderer/src/i18n/translate/ja-jp.json b/src/renderer/src/i18n/translate/ja-jp.json index 58ee184061..950fef7130 100644 --- a/src/renderer/src/i18n/translate/ja-jp.json +++ b/src/renderer/src/i18n/translate/ja-jp.json @@ -420,6 +420,9 @@ }, "delete": { "content": "アシスタントを削除すると、そのアシスタントのすべてのトピックとファイルが削除されます。削除しますか?", + "error": { + "remain_one": "最後の1人のアシスタントは削除できません" + }, "title": "アシスタントを削除" }, "edit": { @@ -4805,7 +4808,7 @@ "content_limit_tooltip": "検索結果のコンテンツの長さを制限します。制限を超えるコンテンツは切り捨てられます。", "default_provider": "デフォルトプロバイダー", "free": "無料", - "is_default": "[to be translated]:Default", + "is_default": "デフォルト", "local_provider": { "hint": "ウェブサイトにログインして、より良い検索結果を得て、検索設定をパーソナライズしてください。", "open_settings": "{{provider}}設定を開く", @@ -4822,7 +4825,7 @@ "search_provider": "検索サービスプロバイダー", "search_provider_placeholder": "検索サービスプロバイダーを選択する", "search_with_time": "日付を含む検索", - "set_as_default": "[to be translated]:Set as Default", + "set_as_default": "既定として設定", "subscribe": "ブラックリスト購読", "subscribe_add": "購読を追加", "subscribe_add_failed": "購読ソースの追加に失敗しました", diff --git a/src/renderer/src/i18n/translate/pt-pt.json b/src/renderer/src/i18n/translate/pt-pt.json index 553795f6b3..73c8e28e4d 100644 --- a/src/renderer/src/i18n/translate/pt-pt.json +++ b/src/renderer/src/i18n/translate/pt-pt.json @@ -420,6 +420,9 @@ }, "delete": { "content": "Excluir o assistente removerá todos os tópicos e arquivos sob esse assistente. Tem certeza de que deseja continuar?", + "error": { + "remain_one": "Não é permitido apagar o último assistente." + }, "title": "Excluir Assistente" }, "edit": { @@ -4805,7 +4808,7 @@ "content_limit_tooltip": "Limita o comprimento do conteúdo dos resultados de pesquisa; o conteúdo excedente será truncado", "default_provider": "Provedor Padrão", "free": "Grátis", - "is_default": "[to be translated]:Default", + "is_default": "Padrão", "local_provider": { "hint": "Faça login no site para obter melhores resultados de pesquisa e personalizar suas configurações de busca.", "open_settings": "Abrir Configurações do {{provider}}", @@ -4822,7 +4825,7 @@ "search_provider": "Provedor de pesquisa", "search_provider_placeholder": "Selecione um provedor de pesquisa", "search_with_time": "Pesquisar com data", - "set_as_default": "[to be translated]:Set as Default", + "set_as_default": "Definir como Padrão", "subscribe": "Assinatura de lista negra", "subscribe_add": "Adicionar assinatura", "subscribe_add_failed": "Falha ao adicionar a fonte de subscrição", diff --git a/src/renderer/src/i18n/translate/ru-ru.json b/src/renderer/src/i18n/translate/ru-ru.json index 489e8b4695..200b03e6c1 100644 --- a/src/renderer/src/i18n/translate/ru-ru.json +++ b/src/renderer/src/i18n/translate/ru-ru.json @@ -420,6 +420,9 @@ }, "delete": { "content": "Удаление ассистента удалит все топики и файлы под ассистентом. Вы уверены, что хотите удалить его?", + "error": { + "remain_one": "Нельзя удалить последнего помощника" + }, "title": "Удалить ассистента" }, "edit": { @@ -4805,7 +4808,7 @@ "content_limit_tooltip": "Ограничить длину контента в результатах поиска; контент, превышающий лимит, будет усечен.", "default_provider": "Поставщик по умолчанию", "free": "Бесплатно", - "is_default": "[to be translated]:Default", + "is_default": "По умолчанию", "local_provider": { "hint": "Войдите на сайт, чтобы получать более точные результаты поиска и настроить параметры поиска под себя.", "open_settings": "Открыть настройки {{provider}}", @@ -4822,7 +4825,7 @@ "search_provider": "поиск сервисного провайдера", "search_provider_placeholder": "Выберите поставщика поисковых услуг", "search_with_time": "Поиск, содержащий дату", - "set_as_default": "[to be translated]:Set as Default", + "set_as_default": "Установить по умолчанию", "subscribe": "Подписка на черный список", "subscribe_add": "Добавить подписку", "subscribe_add_failed": "Не удалось добавить источник подписки", diff --git a/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx b/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx index 3c0c9cf802..79d7f64d7a 100644 --- a/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx +++ b/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx @@ -9,6 +9,7 @@ import { useTags } from '@renderer/hooks/useTags' import type { Assistant, AssistantsSortType, Topic } from '@renderer/types' import type { FC } from 'react' import { useCallback, useRef, useState } from 'react' +import { useTranslation } from 'react-i18next' import styled from 'styled-components' import UnifiedAddButton from './components/UnifiedAddButton' @@ -32,6 +33,7 @@ const AssistantsTab: FC = (props) => { const { apiServerConfig } = useApiServer() const apiServerEnabled = apiServerConfig.enabled const { chat } = useRuntime() + const { t } = useTranslation() // Agent related hooks const { agents, deleteAgent, isLoading: agentsLoading, error: agentsError } = useAgents() @@ -75,13 +77,18 @@ const AssistantsTab: FC = (props) => { const onDeleteAssistant = useCallback( (assistant: Assistant) => { const remaining = assistants.filter((a) => a.id !== assistant.id) + if (remaining.length === 0) { + window.toast.error(t('assistants.delete.error.remain_one')) + return + } + if (assistant.id === activeAssistant?.id) { const newActive = remaining[remaining.length - 1] - newActive ? setActiveAssistant(newActive) : onCreateDefaultAssistant() + setActiveAssistant(newActive) } removeAssistant(assistant.id) }, - [activeAssistant, assistants, removeAssistant, setActiveAssistant, onCreateDefaultAssistant] + [assistants, activeAssistant?.id, removeAssistant, t, setActiveAssistant] ) const handleSortByChange = useCallback(