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.
This commit is contained in:
Phantom 2025-12-28 15:30:01 +08:00 committed by GitHub
parent c13dc6eab5
commit b78df05f28
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 55 additions and 18 deletions

View File

@ -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": {

View File

@ -420,6 +420,9 @@
},
"delete": {
"content": "删除助手会删除所有该助手下的话题和文件,确定要继续吗?",
"error": {
"remain_one": "不允许删除最后一个助手"
},
"title": "删除助手"
},
"edit": {

View File

@ -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": "訂閱來源新增失敗",

View File

@ -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",

View File

@ -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": "Η προσθήκη της ροής συνδρομής απέτυχε",

View File

@ -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",

View File

@ -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",

View File

@ -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": "購読ソースの追加に失敗しました",

View File

@ -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",

View File

@ -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": "Не удалось добавить источник подписки",

View File

@ -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<AssistantsTabProps> = (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<AssistantsTabProps> = (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(