feat(playground): add chat history clearing
- add a toolbar action that is enabled only when saved playground messages exist. - confirm destructive clears before removing browser-stored conversation state. - add localized strings for the action, dialog, and completion toast.
This commit is contained in:
+81
-41
@@ -16,9 +16,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
For commercial licensing, please contact support@quantumnous.com
|
||||
*/
|
||||
import { GlobeIcon, PaperclipIcon } from 'lucide-react'
|
||||
import { GlobeIcon, PaperclipIcon, Trash2Icon } from 'lucide-react'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { toast } from 'sonner'
|
||||
import { ConfirmDialog } from '@/components/confirm-dialog'
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
@@ -37,10 +39,17 @@ import {
|
||||
|
||||
type PlaygroundInputToolsProps = {
|
||||
disabled?: boolean
|
||||
hasMessages?: boolean
|
||||
onClearMessages?: () => void
|
||||
}
|
||||
|
||||
export function PlaygroundInputTools({ disabled }: PlaygroundInputToolsProps) {
|
||||
export function PlaygroundInputTools({
|
||||
disabled,
|
||||
hasMessages = false,
|
||||
onClearMessages,
|
||||
}: PlaygroundInputToolsProps) {
|
||||
const { t } = useTranslation()
|
||||
const [clearConfirmOpen, setClearConfirmOpen] = useState(false)
|
||||
|
||||
const handleFileAction = (action: string) => {
|
||||
const notice = getAttachmentActionNotice(action)
|
||||
@@ -54,45 +63,76 @@ export function PlaygroundInputTools({ disabled }: PlaygroundInputToolsProps) {
|
||||
toast.info(t(notice.title))
|
||||
}
|
||||
|
||||
return (
|
||||
<PromptInputTools>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger
|
||||
render={
|
||||
<PromptInputButton
|
||||
className='border font-medium'
|
||||
disabled={disabled}
|
||||
variant='outline'
|
||||
/>
|
||||
}
|
||||
>
|
||||
<PaperclipIcon size={16} />
|
||||
<span className='hidden sm:inline'>{t('Attach')}</span>
|
||||
<span className='sr-only sm:hidden'>{t('Attach')}</span>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align='start'>
|
||||
{ATTACHMENT_ACTIONS.map(({ action, icon: Icon, label }) => (
|
||||
<DropdownMenuItem
|
||||
key={action}
|
||||
onClick={() => handleFileAction(action)}
|
||||
>
|
||||
<Icon className='mr-2' size={16} />
|
||||
{t(label)}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
const handleClearMessages = () => {
|
||||
onClearMessages?.()
|
||||
setClearConfirmOpen(false)
|
||||
toast.success(t('Conversation cleared'))
|
||||
}
|
||||
|
||||
<PromptInputButton
|
||||
className='border font-medium'
|
||||
disabled={disabled}
|
||||
onClick={handleSearchAction}
|
||||
variant='outline'
|
||||
>
|
||||
<GlobeIcon size={16} />
|
||||
<span className='hidden sm:inline'>{t('Search')}</span>
|
||||
<span className='sr-only sm:hidden'>{t('Search')}</span>
|
||||
</PromptInputButton>
|
||||
</PromptInputTools>
|
||||
return (
|
||||
<>
|
||||
<PromptInputTools>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger
|
||||
render={
|
||||
<PromptInputButton
|
||||
className='border font-medium'
|
||||
disabled={disabled}
|
||||
variant='outline'
|
||||
/>
|
||||
}
|
||||
>
|
||||
<PaperclipIcon size={16} />
|
||||
<span className='hidden sm:inline'>{t('Attach')}</span>
|
||||
<span className='sr-only sm:hidden'>{t('Attach')}</span>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align='start'>
|
||||
{ATTACHMENT_ACTIONS.map(({ action, icon: Icon, label }) => (
|
||||
<DropdownMenuItem
|
||||
key={action}
|
||||
onClick={() => handleFileAction(action)}
|
||||
>
|
||||
<Icon className='mr-2' size={16} />
|
||||
{t(label)}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
<PromptInputButton
|
||||
className='border font-medium'
|
||||
disabled={disabled}
|
||||
onClick={handleSearchAction}
|
||||
variant='outline'
|
||||
>
|
||||
<GlobeIcon size={16} />
|
||||
<span className='hidden sm:inline'>{t('Search')}</span>
|
||||
<span className='sr-only sm:hidden'>{t('Search')}</span>
|
||||
</PromptInputButton>
|
||||
|
||||
<PromptInputButton
|
||||
className='border font-medium text-muted-foreground hover:text-destructive'
|
||||
disabled={disabled || !hasMessages || !onClearMessages}
|
||||
onClick={() => setClearConfirmOpen(true)}
|
||||
variant='outline'
|
||||
>
|
||||
<Trash2Icon size={16} />
|
||||
<span className='hidden sm:inline'>{t('Clear chat history')}</span>
|
||||
<span className='sr-only sm:hidden'>{t('Clear chat history')}</span>
|
||||
</PromptInputButton>
|
||||
</PromptInputTools>
|
||||
|
||||
<ConfirmDialog
|
||||
destructive
|
||||
desc={t(
|
||||
'All playground messages saved in this browser will be removed. This cannot be undone.'
|
||||
)}
|
||||
confirmText={t('Clear')}
|
||||
handleConfirm={handleClearMessages}
|
||||
open={clearConfirmOpen}
|
||||
onOpenChange={setClearConfirmOpen}
|
||||
title={t('Clear chat history?')}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -42,6 +42,8 @@ interface PlaygroundInputProps {
|
||||
groups: GroupOption[]
|
||||
groupValue: string
|
||||
onGroupChange: (value: string) => void
|
||||
hasMessages?: boolean
|
||||
onClearMessages?: () => void
|
||||
}
|
||||
|
||||
export function PlaygroundInput({
|
||||
@@ -56,6 +58,8 @@ export function PlaygroundInput({
|
||||
groups,
|
||||
groupValue,
|
||||
onGroupChange,
|
||||
hasMessages = false,
|
||||
onClearMessages,
|
||||
}: PlaygroundInputProps) {
|
||||
const { t } = useTranslation()
|
||||
const [text, setText] = useState('')
|
||||
@@ -96,7 +100,13 @@ export function PlaygroundInput({
|
||||
onModelChange={onModelChange}
|
||||
onStop={onStop}
|
||||
text={text}
|
||||
tools={<PlaygroundInputTools disabled={disabled} />}
|
||||
tools={
|
||||
<PlaygroundInputTools
|
||||
disabled={disabled}
|
||||
hasMessages={hasMessages}
|
||||
onClearMessages={onClearMessages}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PromptInputFooter>
|
||||
</PromptInput>
|
||||
|
||||
@@ -36,6 +36,7 @@ export function Playground() {
|
||||
setModels,
|
||||
setGroups,
|
||||
updateConfig,
|
||||
clearMessages,
|
||||
} = usePlaygroundState()
|
||||
|
||||
const { sendChat, stopGeneration, isGenerating } = useChatHandler({
|
||||
@@ -58,6 +59,11 @@ export function Playground() {
|
||||
sendChat,
|
||||
})
|
||||
|
||||
const handleClearMessages = () => {
|
||||
handleEditOpenChange(false)
|
||||
clearMessages()
|
||||
}
|
||||
|
||||
const { isLoadingModels } = usePlaygroundOptions({
|
||||
currentGroup: config.group,
|
||||
currentModel: config.model,
|
||||
@@ -95,9 +101,11 @@ export function Playground() {
|
||||
modelValue={config.model}
|
||||
models={models}
|
||||
onGroupChange={(value) => updateConfig('group', value)}
|
||||
onClearMessages={handleClearMessages}
|
||||
onModelChange={(value) => updateConfig('model', value)}
|
||||
onStop={stopGeneration}
|
||||
onSubmit={handleSendMessage}
|
||||
hasMessages={messages.length > 0}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Vendored
+4
@@ -253,6 +253,7 @@
|
||||
"All conditions must match before this tier is used.": "All conditions must match before this tier is used.",
|
||||
"All edits are overwrite operations. Leave fields empty to keep current values unchanged.": "All edits are overwrite operations. Leave fields empty to keep current values unchanged.",
|
||||
"All files exceed the maximum size.": "All files exceed the maximum size.",
|
||||
"All playground messages saved in this browser will be removed. This cannot be undone.": "All playground messages saved in this browser will be removed. This cannot be undone.",
|
||||
"All Groups": "All Groups",
|
||||
"All Models": "All Models",
|
||||
"All models in use are properly configured.": "All models in use are properly configured.",
|
||||
@@ -726,6 +727,8 @@
|
||||
"Clear All Cache": "Clear All Cache",
|
||||
"Clear all filters": "Clear all filters",
|
||||
"Clear cache for this rule": "Clear cache for this rule",
|
||||
"Clear chat history": "Clear chat history",
|
||||
"Clear chat history?": "Clear chat history?",
|
||||
"Clear filters": "Clear filters",
|
||||
"Clear Mapping": "Clear Mapping",
|
||||
"Clear mode flags in prompts": "Clear mode flags in prompts",
|
||||
@@ -918,6 +921,7 @@
|
||||
"Continue with Telegram": "Continue with Telegram",
|
||||
"Continue with WeChat": "Continue with WeChat",
|
||||
"Contract review, compliance, summarisation": "Contract review, compliance, summarisation",
|
||||
"Conversation cleared": "Conversation cleared",
|
||||
"Control which models are exposed and which groups may use them.": "Control which models are exposed and which groups may use them.",
|
||||
"Controls how much the model thinks before answering": "Controls how much the model thinks before answering",
|
||||
"Controls whether user verification (biometrics/PIN) is required during Passkey flows.": "Controls whether user verification (biometrics/PIN) is required during Passkey flows.",
|
||||
|
||||
Vendored
+4
@@ -253,6 +253,7 @@
|
||||
"All conditions must match before this tier is used.": "Toutes les conditions doivent correspondre avant que ce palier soit utilisé.",
|
||||
"All edits are overwrite operations. Leave fields empty to keep current values unchanged.": "Toutes les modifications sont des opérations d'écrasement. Laissez les champs vides pour conserver les valeurs actuelles inchangées.",
|
||||
"All files exceed the maximum size.": "Tous les fichiers dépassent la taille maximale.",
|
||||
"All playground messages saved in this browser will be removed. This cannot be undone.": "Tous les messages du Playground enregistrés dans ce navigateur seront supprimés. Cette action est irréversible.",
|
||||
"All Groups": "Tous les groupes",
|
||||
"All Models": "Tous les modèles",
|
||||
"All models in use are properly configured.": "Tous les modèles utilisés sont correctement configurés.",
|
||||
@@ -726,6 +727,8 @@
|
||||
"Clear All Cache": "Vider tout le cache",
|
||||
"Clear all filters": "Effacer tous les filtres",
|
||||
"Clear cache for this rule": "Vider le cache de cette règle",
|
||||
"Clear chat history": "Effacer l'historique du chat",
|
||||
"Clear chat history?": "Effacer l'historique du chat ?",
|
||||
"Clear filters": "Effacer les filtres",
|
||||
"Clear Mapping": "Effacer le mappage",
|
||||
"Clear mode flags in prompts": "Effacer les indicateurs de mode dans les prompts",
|
||||
@@ -918,6 +921,7 @@
|
||||
"Continue with Telegram": "Continuer avec Telegram",
|
||||
"Continue with WeChat": "Continuer avec WeChat",
|
||||
"Contract review, compliance, summarisation": "Revue de contrats, conformité, résumé",
|
||||
"Conversation cleared": "Conversation effacée",
|
||||
"Control which models are exposed and which groups may use them.": "Contrôlez les modèles exposés et les groupes autorisés à les utiliser.",
|
||||
"Controls how much the model thinks before answering": "Contrôle la quantité de raisonnement avant la réponse",
|
||||
"Controls whether user verification (biometrics/PIN) is required during Passkey flows.": "Contrôle si la vérification de l'utilisateur (biométrie/PIN) est requise lors des flux de Passkey.",
|
||||
|
||||
Vendored
+4
@@ -253,6 +253,7 @@
|
||||
"All conditions must match before this tier is used.": "この段階を使用するには、すべての条件に一致する必要があります。",
|
||||
"All edits are overwrite operations. Leave fields empty to keep current values unchanged.": "すべての編集は上書き操作です。現在の値を変更しないままにするには、フィールドを空のままにしてください。",
|
||||
"All files exceed the maximum size.": "すべてのファイルが最大サイズを超えています。",
|
||||
"All playground messages saved in this browser will be removed. This cannot be undone.": "このブラウザに保存されたすべての Playground メッセージが削除されます。この操作は元に戻せません。",
|
||||
"All Groups": "すべてのグループ",
|
||||
"All Models": "すべてのモデル",
|
||||
"All models in use are properly configured.": "使用中のすべてのモデルが適切に構成されています。",
|
||||
@@ -726,6 +727,8 @@
|
||||
"Clear All Cache": "全キャッシュをクリア",
|
||||
"Clear all filters": "すべてのフィルターをクリア",
|
||||
"Clear cache for this rule": "このルールのキャッシュをクリア",
|
||||
"Clear chat history": "チャット履歴を消去",
|
||||
"Clear chat history?": "チャット履歴を消去しますか?",
|
||||
"Clear filters": "フィルターをクリア",
|
||||
"Clear Mapping": "マッピングをクリア",
|
||||
"Clear mode flags in prompts": "プロンプト内のモードフラグをクリア",
|
||||
@@ -918,6 +921,7 @@
|
||||
"Continue with Telegram": "Telegram で続行",
|
||||
"Continue with WeChat": "WeChat で続行",
|
||||
"Contract review, compliance, summarisation": "契約レビュー・コンプライアンス・要約",
|
||||
"Conversation cleared": "会話を消去しました",
|
||||
"Control which models are exposed and which groups may use them.": "公開するモデルと、それらを利用できるグループを制御します。",
|
||||
"Controls how much the model thinks before answering": "モデルが回答前に考える深さを制御します",
|
||||
"Controls whether user verification (biometrics/PIN) is required during Passkey flows.": "Passkeyフロー中にユーザー認証(生体認証/PIN)が必要かどうかを制御します。",
|
||||
|
||||
Vendored
+4
@@ -253,6 +253,7 @@
|
||||
"All conditions must match before this tier is used.": "Все условия должны совпасть, прежде чем будет использован этот уровень.",
|
||||
"All edits are overwrite operations. Leave fields empty to keep current values unchanged.": "Все изменения являются операциями перезаписи. Оставьте поля пустыми, чтобы сохранить текущие значения без изменений.",
|
||||
"All files exceed the maximum size.": "Все файлы превышают максимальный размер.",
|
||||
"All playground messages saved in this browser will be removed. This cannot be undone.": "Все сообщения Playground, сохраненные в этом браузере, будут удалены. Это действие нельзя отменить.",
|
||||
"All Groups": "Все группы",
|
||||
"All Models": "Все модели",
|
||||
"All models in use are properly configured.": "Все используемые модели настроены правильно.",
|
||||
@@ -726,6 +727,8 @@
|
||||
"Clear All Cache": "Очистить весь кэш",
|
||||
"Clear all filters": "Очистить все фильтры",
|
||||
"Clear cache for this rule": "Очистить кэш этого правила",
|
||||
"Clear chat history": "Очистить историю чата",
|
||||
"Clear chat history?": "Очистить историю чата?",
|
||||
"Clear filters": "Очистить фильтры",
|
||||
"Clear Mapping": "Очистить сопоставление",
|
||||
"Clear mode flags in prompts": "Очистить флаги режимов в промптах",
|
||||
@@ -918,6 +921,7 @@
|
||||
"Continue with Telegram": "Продолжить с Telegram",
|
||||
"Continue with WeChat": "Продолжить с WeChat",
|
||||
"Contract review, compliance, summarisation": "Анализ контрактов, комплаенс, резюме",
|
||||
"Conversation cleared": "Диалог очищен",
|
||||
"Control which models are exposed and which groups may use them.": "Управляйте тем, какие модели доступны и какие группы могут их использовать.",
|
||||
"Controls how much the model thinks before answering": "Регулирует глубину размышлений модели перед ответом",
|
||||
"Controls whether user verification (biometrics/PIN) is required during Passkey flows.": "Определяет, требуется ли проверка пользователя (биометрия/PIN) во время процессов Passkey.",
|
||||
|
||||
Vendored
+4
@@ -253,6 +253,7 @@
|
||||
"All conditions must match before this tier is used.": "Tất cả điều kiện phải khớp trước khi tầng này được sử dụng.",
|
||||
"All edits are overwrite operations. Leave fields empty to keep current values unchanged.": "Tất cả các chỉnh sửa đều là thao tác ghi đè. Để trống các trường để giữ nguyên giá trị hiện tại.",
|
||||
"All files exceed the maximum size.": "Tất cả các tệp vượt quá kích thước tối đa.",
|
||||
"All playground messages saved in this browser will be removed. This cannot be undone.": "Tất cả tin nhắn Playground đã lưu trong trình duyệt này sẽ bị xóa. Không thể hoàn tác hành động này.",
|
||||
"All Groups": "Tất cả các nhóm",
|
||||
"All Models": "Tất cả các mẫu",
|
||||
"All models in use are properly configured.": "Tất cả các mô hình đang được sử dụng đều được cấu hình đúng cách.",
|
||||
@@ -726,6 +727,8 @@
|
||||
"Clear All Cache": "Xóa toàn bộ bộ nhớ đệm",
|
||||
"Clear all filters": "Xóa tất cả bộ lọc",
|
||||
"Clear cache for this rule": "Xóa bộ nhớ đệm của quy tắc này",
|
||||
"Clear chat history": "Xóa lịch sử trò chuyện",
|
||||
"Clear chat history?": "Xóa lịch sử trò chuyện?",
|
||||
"Clear filters": "Clear filter",
|
||||
"Clear Mapping": "Xóa Ánh xạ",
|
||||
"Clear mode flags in prompts": "Xóa các cờ chế độ trong lời nhắc",
|
||||
@@ -918,6 +921,7 @@
|
||||
"Continue with Telegram": "Tiếp tục với Telegram",
|
||||
"Continue with WeChat": "Tiếp tục với WeChat",
|
||||
"Contract review, compliance, summarisation": "Rà soát hợp đồng, tuân thủ, tóm tắt",
|
||||
"Conversation cleared": "Đã xóa cuộc trò chuyện",
|
||||
"Control which models are exposed and which groups may use them.": "Kiểm soát mô hình được hiển thị và nhóm nào có thể sử dụng chúng.",
|
||||
"Controls how much the model thinks before answering": "Điều chỉnh mức suy luận trước khi trả lời",
|
||||
"Controls whether user verification (biometrics/PIN) is required during Passkey flows.": "Kiểm soát xem liệu có yêu cầu xác minh người dùng (sinh trắc học/mã PIN) trong các luồng Passkey hay không.",
|
||||
|
||||
Vendored
+4
@@ -253,6 +253,7 @@
|
||||
"All conditions must match before this tier is used.": "所有条件都匹配后才会使用此阶梯。",
|
||||
"All edits are overwrite operations. Leave fields empty to keep current values unchanged.": "所有编辑都是覆盖操作。留空字段将保持当前值不变。",
|
||||
"All files exceed the maximum size.": "所有文件都超过最大尺寸。",
|
||||
"All playground messages saved in this browser will be removed. This cannot be undone.": "保存在此浏览器中的所有游乐场消息都将被移除。此操作无法撤销。",
|
||||
"All Groups": "所有分组",
|
||||
"All Models": "所有模型",
|
||||
"All models in use are properly configured.": "所有正在使用的模型都已正确配置。",
|
||||
@@ -726,6 +727,8 @@
|
||||
"Clear All Cache": "清空全部缓存",
|
||||
"Clear all filters": "清除所有筛选",
|
||||
"Clear cache for this rule": "清空该规则缓存",
|
||||
"Clear chat history": "清空聊天历史",
|
||||
"Clear chat history?": "清空聊天历史?",
|
||||
"Clear filters": "清除筛选器",
|
||||
"Clear Mapping": "清除映射",
|
||||
"Clear mode flags in prompts": "在提示中清除模式标志",
|
||||
@@ -918,6 +921,7 @@
|
||||
"Continue with Telegram": "使用 Telegram 继续",
|
||||
"Continue with WeChat": "使用 微信 继续",
|
||||
"Contract review, compliance, summarisation": "合同审阅、合规与摘要",
|
||||
"Conversation cleared": "对话已清空",
|
||||
"Control which models are exposed and which groups may use them.": "控制对外暴露的模型,以及哪些分组可以使用它们。",
|
||||
"Controls how much the model thinks before answering": "控制模型回答前的推理深度",
|
||||
"Controls whether user verification (biometrics/PIN) is required during Passkey flows.": "控制在通行密钥流程中是否需要用户验证(生物识别/PIN)。",
|
||||
|
||||
Reference in New Issue
Block a user