From 12c060b7952945debe9cb4a1e9b04a1844fa28fc Mon Sep 17 00:00:00 2001 From: twwu Date: Tue, 6 May 2025 16:58:37 +0800 Subject: [PATCH] feat: enhance dataset icon handling by making icon background and URL optional --- .../list/template-card/edit-pipeline-info.tsx | 3 +- .../datasets/rename-modal/index.tsx | 89 +++++++++++++++---- web/models/datasets.ts | 4 +- 3 files changed, 73 insertions(+), 23 deletions(-) diff --git a/web/app/components/datasets/create-from-pipeline/list/template-card/edit-pipeline-info.tsx b/web/app/components/datasets/create-from-pipeline/list/template-card/edit-pipeline-info.tsx index 269f62a25b..0bc1fbf975 100644 --- a/web/app/components/datasets/create-from-pipeline/list/template-card/edit-pipeline-info.tsx +++ b/web/app/components/datasets/create-from-pipeline/list/template-card/edit-pipeline-info.tsx @@ -3,7 +3,6 @@ import type { AppIconSelection } from '@/app/components/base/app-icon-picker' import AppIconPicker from '@/app/components/base/app-icon-picker' import Input from '@/app/components/base/input' import Textarea from '@/app/components/base/textarea' -import type { AppIconType } from '@/types/app' import { RiCloseLine } from '@remixicon/react' import React, { useCallback, useRef, useState } from 'react' import Button from '@/app/components/base/button' @@ -103,7 +102,7 @@ const EditPipelineInfo = ({ size='xxl' onClick={handleOpenAppIconPicker} className='cursor-pointer' - iconType={appIcon.type as AppIconType} + iconType={appIcon.type} icon={appIcon.type === 'image' ? appIcon.fileId : appIcon.icon} background={appIcon.type === 'image' ? undefined : appIcon.background} imageUrl={appIcon.type === 'image' ? appIcon.url : undefined} diff --git a/web/app/components/datasets/rename-modal/index.tsx b/web/app/components/datasets/rename-modal/index.tsx index dd53bafdd9..b071822387 100644 --- a/web/app/components/datasets/rename-modal/index.tsx +++ b/web/app/components/datasets/rename-modal/index.tsx @@ -1,19 +1,21 @@ 'use client' import type { MouseEventHandler } from 'react' -import { useState } from 'react' +import { useCallback, useRef, useState } from 'react' import { RiCloseLine } from '@remixicon/react' -import { useContext } from 'use-context-selector' import { useTranslation } from 'react-i18next' import cn from '@/utils/classnames' import Button from '@/app/components/base/button' import Input from '@/app/components/base/input' import Textarea from '@/app/components/base/textarea' import Modal from '@/app/components/base/modal' -import { ToastContext } from '@/app/components/base/toast' import type { DataSet } from '@/models/datasets' import { updateDatasetSetting } from '@/service/datasets' import { noop } from 'lodash-es' +import AppIcon from '../../base/app-icon' +import type { AppIconSelection } from '../../base/app-icon-picker' +import AppIconPicker from '../../base/app-icon-picker' +import Toast from '../../base/toast' type RenameDatasetModalProps = { show: boolean @@ -24,16 +26,41 @@ type RenameDatasetModalProps = { const RenameDatasetModal = ({ show, dataset, onSuccess, onClose }: RenameDatasetModalProps) => { const { t } = useTranslation() - const { notify } = useContext(ToastContext) const [loading, setLoading] = useState(false) const [name, setName] = useState(dataset.name) const [description, setDescription] = useState(dataset.description) - const [externalKnowledgeId, setExternalKnowledgeId] = useState(dataset.external_knowledge_info.external_knowledge_id) - const [externalKnowledgeApiId, setExternalKnowledgeApiId] = useState(dataset.external_knowledge_info.external_knowledge_api_id) + const [externalKnowledgeId] = useState(dataset.external_knowledge_info.external_knowledge_id) + const [externalKnowledgeApiId] = useState(dataset.external_knowledge_info.external_knowledge_api_id) + const [appIcon, setAppIcon] = useState( + dataset.icon_info?.icon_type === 'image' + ? { type: 'image' as const, url: dataset.icon_info?.icon_url || '', fileId: dataset.icon_info?.icon || '' } + : { type: 'emoji' as const, icon: dataset.icon_info?.icon || '', background: dataset.icon_info?.icon_background || '' }, + ) + const [showAppIconPicker, setShowAppIconPicker] = useState(false) + const previousAppIcon = useRef( + dataset.icon_info?.icon_type === 'image' + ? { type: 'image' as const, url: dataset.icon_info?.icon_url || '', fileId: dataset.icon_info?.icon || '' } + : { type: 'emoji' as const, icon: dataset.icon_info?.icon || '', background: dataset.icon_info?.icon_background || '' }, + ) - const onConfirm: MouseEventHandler = async () => { + const handleOpenAppIconPicker = useCallback(() => { + setShowAppIconPicker(true) + previousAppIcon.current = appIcon + }, [appIcon]) + + const handleSelectAppIcon = useCallback((icon: AppIconSelection) => { + setAppIcon(icon) + setShowAppIconPicker(false) + }, []) + + const handleCloseAppIconPicker = useCallback(() => { + setAppIcon(previousAppIcon.current) + setShowAppIconPicker(false) + }, []) + + const onConfirm: MouseEventHandler = useCallback(async () => { if (!name.trim()) { - notify({ type: 'error', message: t('datasetSettings.form.nameError') }) + Toast.notify({ type: 'error', message: t('datasetSettings.form.nameError') }) return } try { @@ -41,6 +68,12 @@ const RenameDatasetModal = ({ show, dataset, onSuccess, onClose }: RenameDataset const body: Partial & { external_knowledge_id?: string; external_knowledge_api_id?: string } = { name, description, + icon_info: { + icon: appIcon.type === 'image' ? appIcon.fileId : appIcon.icon, + icon_type: appIcon.type, + icon_background: appIcon.type === 'image' ? undefined : appIcon.background, + icon_url: appIcon.type === 'image' ? appIcon.url : undefined, + }, } if (externalKnowledgeId && externalKnowledgeApiId) { body.external_knowledge_id = externalKnowledgeId @@ -50,18 +83,18 @@ const RenameDatasetModal = ({ show, dataset, onSuccess, onClose }: RenameDataset datasetId: dataset.id, body, }) - notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') }) + Toast.notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') }) if (onSuccess) onSuccess() onClose() } catch { - notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') }) + Toast.notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') }) } finally { setLoading(false) } - } + }, [appIcon, description, dataset.id, externalKnowledgeApiId, externalKnowledgeId, name, onClose, onSuccess, t]) return (
-
+
{t('datasetSettings.form.name')}
- setName(e.target.value)} - className='h-9' - placeholder={t('datasetSettings.form.namePlaceholder') || ''} - /> +
+ + setName(e.target.value)} + className='h-9 grow' + placeholder={t('datasetSettings.form.namePlaceholder') || ''} + /> +
-
+
{t('datasetSettings.form.desc')}
@@ -103,6 +148,12 @@ const RenameDatasetModal = ({ show, dataset, onSuccess, onClose }: RenameDataset
+ {showAppIconPicker && ( + + )} ) } diff --git a/web/models/datasets.ts b/web/models/datasets.ts index f6a5d8aab8..cc06d6e564 100644 --- a/web/models/datasets.ts +++ b/web/models/datasets.ts @@ -37,9 +37,9 @@ export type DataSet = { indexing_status: DocumentIndexingStatus icon_info: { icon: string - icon_background: string + icon_background?: string icon_type: AppIconType - icon_url: string + icon_url?: string } description: string permission: DatasetPermission