diff --git a/web/src/components/avatar-upload.tsx b/web/src/components/avatar-upload.tsx index 95e9d9c3a..70d50026f 100644 --- a/web/src/components/avatar-upload.tsx +++ b/web/src/components/avatar-upload.tsx @@ -318,7 +318,7 @@ export const AvatarUpload = forwardRef( data-testid={uploadInputTestId} /> -
+
{tips ?? t('knowledgeConfiguration.photoTip')}
diff --git a/web/src/components/file-upload-dialog/index.tsx b/web/src/components/file-upload-dialog/index.tsx index d7239e2e8..251c52f4c 100644 --- a/web/src/components/file-upload-dialog/index.tsx +++ b/web/src/components/file-upload-dialog/index.tsx @@ -76,7 +76,7 @@ function UploadForm({ submit, showParseOnCreation }: UploadFormProps) { data-testid="parse-on-creation-toggle" onCheckedChange={field.onChange} checked={field.value} - > + /> )} )} @@ -85,7 +85,7 @@ function UploadForm({ submit, showParseOnCreation }: UploadFormProps) { )} @@ -124,10 +124,7 @@ export function FileUploadDialog({ {t('common.comingSoon')} */} - + {t('common.save')} diff --git a/web/src/components/file-uploader.tsx b/web/src/components/file-uploader.tsx index 56163df10..813787a7c 100644 --- a/web/src/components/file-uploader.tsx +++ b/web/src/components/file-uploader.tsx @@ -2,7 +2,7 @@ 'use client'; -import { FileText, FolderUp, Upload, X } from 'lucide-react'; +import { FileText, FolderUp, LucideTrash2, Upload } from 'lucide-react'; import * as React from 'react'; import Dropzone, { type DropzoneProps, @@ -80,12 +80,12 @@ function FileCard({ file, progress, onRemove }: FileCardProps) {
@@ -300,71 +300,67 @@ export function FileUploader(props: FileUploaderProps) { const isDisabled = disabled || (files?.length ?? 0) >= maxFileCount; - const renderDropzone = (isFolderMode: boolean = false) => ( - 1 || multiple} - disabled={isDisabled} - noClick={isFolderMode} - noDrag={isFolderMode} - > - {({ getRootProps, getInputProps, isDragActive }) => ( -
- {!isFolderMode && } - {isDragActive && !isFolderMode ? ( -
-
-
-

- {t('fileManager.dropFilesHere', 'Drop the files here')} -

-
- ) : ( -
{ - if (isFolderMode && !isDisabled) { - folderInputRef.current?.click(); - } - }} - > -
- {isFolderMode ? ( -
+ )} + + ); + }; return (
@@ -417,7 +413,7 @@ export function FileUploader(props: FileUploaderProps) { )} {files?.length ? ( -
+
{files?.map((file, index) => ( - - - - + + + ); } diff --git a/web/src/components/ui/button.tsx b/web/src/components/ui/button.tsx index 93f366e01..76ee1682d 100644 --- a/web/src/components/ui/button.tsx +++ b/web/src/components/ui/button.tsx @@ -68,6 +68,13 @@ const buttonVariants = cva( hover:bg-state-error/10 focus-visible:bg-state-error/10 `, + 'danger-hover': ` + bg-bg-input border-border-button + hover:bg-state-error/10 focus-visible:bg-state-error/10 + hover:text-state-error focus-visible:text-state-error + hover:border-state-error focus-visible:border-state-error + `, + // Ghost variant series // Button has transparent background, without borders ghost: ` @@ -91,11 +98,11 @@ const buttonVariants = cva( size: { auto: '', - xl: 'h-12 rounded-xl px-5', + xl: 'h-12 rounded-xl px-5 gap-3', lg: 'h-10 rounded-lg px-4', default: 'h-8 rounded px-3', - sm: 'h-7 rounded-sm px-2', - xs: 'h-6 rounded-xs px-1', + sm: 'h-7 rounded-sm px-2 gap-1', + xs: 'h-6 rounded-xs px-1 gap-0.5', 'icon-xl': 'size-12 rounded-xl', 'icon-lg': 'size-10 rounded-lg', diff --git a/web/src/components/ui/checkbox.tsx b/web/src/components/ui/checkbox.tsx index 50f937cfb..362b7d5ca 100644 --- a/web/src/components/ui/checkbox.tsx +++ b/web/src/components/ui/checkbox.tsx @@ -1,7 +1,7 @@ 'use client'; import * as CheckboxPrimitive from '@radix-ui/react-checkbox'; -import { LucideCheck } from 'lucide-react'; +import { LucideCheck, LucideMinus } from 'lucide-react'; import * as React from 'react'; import { cn } from '@/lib/utils'; @@ -23,7 +23,12 @@ const Checkbox = React.forwardRef< {...props} > - + {props.checked === 'indeterminate' && ( + + )} + {props.checked === true && ( + + )} )); diff --git a/web/src/constants/common.ts b/web/src/constants/common.ts index f988d535f..e34692a56 100644 --- a/web/src/constants/common.ts +++ b/web/src/constants/common.ts @@ -41,6 +41,7 @@ export const fileIconMap = { xml: 'xml.svg', }; +// TODO: Need to migrate to standard BCP 47 language tag export const LanguageList = [ 'English', 'Chinese', @@ -68,7 +69,7 @@ export const LanguageMap = { Vietnamese: 'Tiếng việt', Japanese: '日本語', 'Portuguese BR': 'Português BR', - German: 'German', + German: 'Deutsch', French: 'Français', Italian: 'Italiano', Bulgarian: 'Български', diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index 1f12cc927..e58b95892 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -360,11 +360,11 @@ Example: A 1 KB message with 1024-dim embedding uses ~9 KB. The 5 MB default lim filesSelected: 'Files selected', upload: 'Upload', run: 'Parse', - runningStatus0: 'PENDING', - runningStatus1: 'PARSING', - runningStatus2: 'CANCELED', - runningStatus3: 'SUCCESS', - runningStatus4: 'FAIL', + runningStatus0: 'Pending', + runningStatus1: 'Parsing', + runningStatus2: 'Cancelled', + runningStatus3: 'Success', + runningStatus4: 'Fail', pageRanges: 'Page ranges', pageRangesTip: 'Range of pages to be parsed; pages outside this range will not be processed.', diff --git a/web/src/pages/dataset/dataset-overview/index.tsx b/web/src/pages/dataset/dataset-overview/index.tsx index 5d6035939..a535960bc 100644 --- a/web/src/pages/dataset/dataset-overview/index.tsx +++ b/web/src/pages/dataset/dataset-overview/index.tsx @@ -1,4 +1,3 @@ -import FileStatusBadge from '@/components/file-status-badge'; import { FilterCollection } from '@/components/list-filter-bar/interface'; import SvgIcon from '@/components/svg-icon'; import { useIsDarkTheme } from '@/components/theme-provider'; @@ -192,12 +191,7 @@ const FileLogsPage: FC = () => { return { id: value, // label: RunningStatusMap[value].label, - label: ( - - ), + label: RunningStatusMap[value], }; }), }, diff --git a/web/src/pages/dataset/sidebar/index.tsx b/web/src/pages/dataset/sidebar/index.tsx index 77bb55a3b..3fb9a6311 100644 --- a/web/src/pages/dataset/sidebar/index.tsx +++ b/web/src/pages/dataset/sidebar/index.tsx @@ -72,9 +72,9 @@ export function SideBar({ refreshCount }: PropType) { }, [t, routerData]); return ( -
); }, meta: { cellClassName: 'max-w-[20vw]' }, @@ -147,21 +151,18 @@ export function FilesTable({ return ( -
- - - - - {name} - -
+
- -

{name}

-
+ + {name}
); }, @@ -170,13 +171,18 @@ export function FilesTable({ accessorKey: 'create_time', header: ({ column }) => { return ( - + +
); }, cell: ({ row }) => ( @@ -189,13 +195,18 @@ export function FilesTable({ accessorKey: 'size', header: ({ column }) => { return ( - + +
); }, cell: ({ row }) => ( @@ -213,6 +224,9 @@ export function FilesTable({ { id: 'actions', header: t('action'), + meta: { + headerCellClassName: 'w-0', + }, enableHiding: false, enablePinning: true, cell: ({ row }) => { @@ -222,7 +236,7 @@ export function FilesTable({ showConnectToKnowledgeModal={showConnectToKnowledgeModal} showFileRenameModal={showFileRenameModal} showMoveFileModal={showMoveFileModal} - > + /> ); }, }, @@ -271,7 +285,12 @@ export function FilesTable({ {headerGroup.headers.map((header) => { return ( - + {header.isPlaceholder ? null : flexRender( diff --git a/web/src/pages/files/index.tsx b/web/src/pages/files/index.tsx index 3f8581ff9..db2c57a38 100644 --- a/web/src/pages/files/index.tsx +++ b/web/src/pages/files/index.tsx @@ -11,7 +11,7 @@ import { } from '@/components/ui/dropdown-menu'; import { useRowSelection } from '@/hooks/logic-hooks/use-row-selection'; import { useFetchFileList } from '@/hooks/use-file-request'; -import { Upload } from 'lucide-react'; +import { LucidePlus } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { CreateFolderDialog } from './create-folder-dialog'; import { FileBreadcrumb } from './file-breadcrumb'; @@ -87,35 +87,38 @@ export default function Files() { ); return ( -
- - - - - - - - {t('fileManager.uploadFile')} - - - - {t('fileManager.newFolder')} - - - - - {!rowSelectionIsEmpty && ( - - )} +
+
+ + + + + + + + {t('fileManager.uploadFile')} + + + + {t('fileManager.newFolder')} + + + + + {!rowSelectionIsEmpty && ( + + )} +
)} -
+ ); } diff --git a/web/src/pages/user-setting/components/user-setting-header/index.tsx b/web/src/pages/user-setting/components/user-setting-header/index.tsx index d54e57769..4f6026f43 100644 --- a/web/src/pages/user-setting/components/user-setting-header/index.tsx +++ b/web/src/pages/user-setting/components/user-setting-header/index.tsx @@ -1,26 +1,7 @@ +import Spotlight from '@/components/spotlight'; import { Card, CardContent, CardHeader } from '@/components/ui/card'; import { PropsWithChildren } from 'react'; -export const UserSettingHeader = ({ - name, - description, -}: { - name: string; - description?: string; -}) => { - return ( - <> -
-
{name}
- {description && ( -
{description}
- )} -
- {/* */} - - ); -}; - export function Title({ children }: PropsWithChildren) { return {children}; } @@ -34,11 +15,17 @@ export function ProfileSettingWrapperCard({ children, }: ProfileSettingWrapperCardProps) { return ( - - + + {header} - {children} + + {children} + + ); } diff --git a/web/src/pages/user-setting/data-source/index.tsx b/web/src/pages/user-setting/data-source/index.tsx index 801b919db..d4da96d7b 100644 --- a/web/src/pages/user-setting/data-source/index.tsx +++ b/web/src/pages/user-setting/data-source/index.tsx @@ -1,19 +1,62 @@ -import { CardTitle } from '@/components/ui/card'; import { useTranslation } from 'react-i18next'; -import Spotlight from '@/components/spotlight'; import { Button } from '@/components/ui/button'; import { Plus } from 'lucide-react'; -import { - ProfileSettingWrapperCard, - UserSettingHeader, -} from '../components/user-setting-header'; +import { ProfileSettingWrapperCard } from '../components/user-setting-header'; import AddDataSourceModal from './add-datasource-modal'; import { AddedSourceCard } from './component/added-source-card'; import { DataSourceKey, useDataSourceInfo } from './constant'; import { useAddDataSource, useListDataSource } from './hooks'; import { IDataSorceInfo } from './interface'; +const AvailableSourceCard = ({ + name, + description, + icon, + onAdd, +}: IDataSorceInfo & { onAdd: () => void }) => { + const { t } = useTranslation(); + + return ( +
onAdd()} + > + + {icon} + + +
+

{name}

+ + +
+ +

+ {description} +

+
+ ); +}; + const DataSource = () => { const { t } = useTranslation(); const { dataSourceInfo } = useDataSourceInfo(); @@ -38,97 +81,68 @@ const DataSource = () => { showAddingModal, } = useAddDataSource(); - const AbailableSourceCard = ({ - id, - name, - description, - icon, - }: IDataSorceInfo) => { - return ( -
- showAddingModal({ - id, - name, - description, - icon, - }) - } - > -
-
{icon}
-
-
{name}
-
{description}
-
-
-
- -
-
- ); - }; - return ( +
+

+ {t('setting.dataSources')} +

+

+ {t('setting.datasourceDescription')} +

+
} > - -
-
-
- {categorizedList?.length <= 0 && ( -
- {t('setting.sourceEmptyTip')} -
- )} - {categorizedList.map((item, index) => ( - - ))} -
-
-
- {/* */} - - {t('setting.availableSources')} -
- {t('setting.availableSourcesDescription')} -
-
-
-
- {/* */} -
- {dataSourceTemplates.map((item, index) => ( - - ))} -
-
-
-
+
+
+ {categorizedList?.length <= 0 && ( +
+ {t('setting.sourceEmptyTip')} +
+ )} + {categorizedList.map((item, index) => ( + + ))} +
- {addingModalVisible && ( - { - console.log(data); - handleAddOk(data); - }} - sourceData={addSource} - > - )} +
+
+ {/* */} +

+ {t('setting.availableSources')} +
+ {t('setting.availableSourcesDescription')} +
+

+
+ + {/* */} +
    + {dataSourceTemplates.map((item) => ( +
  • + showAddingModal(item)} + /> +
  • + ))} +
+
+ + {addingModalVisible && ( + { + console.log(data); + handleAddOk(data); + }} + sourceData={addSource} + /> + )} ); }; diff --git a/web/src/pages/user-setting/mcp/edit-mcp-dialog.tsx b/web/src/pages/user-setting/mcp/edit-mcp-dialog.tsx index ca9391884..b472d2196 100644 --- a/web/src/pages/user-setting/mcp/edit-mcp-dialog.tsx +++ b/web/src/pages/user-setting/mcp/edit-mcp-dialog.tsx @@ -196,7 +196,7 @@ export function EditMcpDialog({ form={form} setFieldChanged={setFieldChanged} > - + -
- {t('mcp.mcpServers')} -
-
-
+
+
+

+ {t('mcp.mcpServers')} +

+ +

{t('mcp.customizeTheListOfMcpServers')} -

-
- - - - -
-
- +

+
+ +
+ + + + +
+ } > - {!data.mcp_servers?.length && ( -
-
{t('empty.noMCP')}
- -
- )} - {!!data.mcp_servers?.length && ( - <> - {isSelectionMode && ( -
- - - - {t('mcp.selected')} {selectedList.length} - -
- - - ), - }} +
+ {data.mcp_servers?.length ? ( + <> + {isSelectionMode && ( +
+ +
-
- )} - - {data.mcp_servers.map((item) => ( - - ))} - -
- + + ), + }} + > + + +
+ + )} + + {data.mcp_servers.map((item) => ( + + ))} + +
+ +
+ + ) : ( +
+
+ {t('empty.noMCP')} +
+
- - )} + )} +
+ {editVisible && ( )} - ); } diff --git a/web/src/pages/user-setting/profile/index.tsx b/web/src/pages/user-setting/profile/index.tsx index 8b496a9d5..4b0d897ff 100644 --- a/web/src/pages/user-setting/profile/index.tsx +++ b/web/src/pages/user-setting/profile/index.tsx @@ -22,10 +22,7 @@ import { Loader2Icon, PenLine } from 'lucide-react'; import { FC, useEffect } from 'react'; import { useForm } from 'react-hook-form'; import { z } from 'zod'; -import { - ProfileSettingWrapperCard, - UserSettingHeader, -} from '../components/user-setting-header'; +import { ProfileSettingWrapperCard } from '../components/user-setting-header'; import { EditType, modalTitle, useProfile } from './hooks/use-profile'; const baseSchema = z.object({ @@ -123,10 +120,14 @@ const ProfilePage: FC = () => { //
+
+

+ {t('profile')} +

+

+ {t('profileDescription')} +

+
} > @@ -142,11 +143,11 @@ const ProfilePage: FC = () => {
{profile.userName}
+ @@ -175,10 +176,9 @@ const ProfilePage: FC = () => { {profile.timeZone}
@@ -208,10 +208,9 @@ const ProfilePage: FC = () => { {profile.currPasswd ? '********' : ''}
diff --git a/web/src/pages/user-setting/setting-model/components/modal-card.tsx b/web/src/pages/user-setting/setting-model/components/modal-card.tsx index b27c2ba17..f688cc9f6 100644 --- a/web/src/pages/user-setting/setting-model/components/modal-card.tsx +++ b/web/src/pages/user-setting/setting-model/components/modal-card.tsx @@ -93,26 +93,22 @@ export const ModelProviderCard: FC = ({
@@ -161,9 +157,9 @@ export const ModelProviderCard: FC = ({ ))}
-
+
    {item.llm.map((model) => ( -
    @@ -176,36 +172,38 @@ export const ModelProviderCard: FC = ({
    -
    +
    {isLocalLlmFactory(item.name) && ( )} + { handleEnableLlm(model.name, value); }} /> +
    -
    + ))} -
+
)} diff --git a/web/src/pages/user-setting/setting-model/components/system-setting.tsx b/web/src/pages/user-setting/setting-model/components/system-setting.tsx index 607f2a99f..f1fbdaaf5 100644 --- a/web/src/pages/user-setting/setting-model/components/system-setting.tsx +++ b/web/src/pages/user-setting/setting-model/components/system-setting.tsx @@ -173,13 +173,16 @@ const SystemSetting = ({ onOk, loading }: IProps) => { }; return ( -
-
-
{t('systemModelSettings')}
-
+
+
+

+ {t('systemModelSettings')} +

+

{t('systemModelDescription')} -

-
+

+ +
{llmList.map((item) => ( @@ -194,7 +197,7 @@ const SystemSetting = ({ onOk, loading }: IProps) => { {t('common:cancel')}
*/} -
+ ); }; diff --git a/web/src/pages/user-setting/setting-model/components/un-add-model.tsx b/web/src/pages/user-setting/setting-model/components/un-add-model.tsx index ba87e3830..a78aa6862 100644 --- a/web/src/pages/user-setting/setting-model/components/un-add-model.tsx +++ b/web/src/pages/user-setting/setting-model/components/un-add-model.tsx @@ -79,97 +79,97 @@ export const AvailableModels: FC<{ }; return ( -
-
- {t('availableModels')} -
- {/* Search Bar */} -
- {/*
*/} - setSearchTerm(e.target.value)} - className="w-full px-4 py-2 pl-10 bg-bg-input border border-border-default rounded-lg focus:outline-none focus:ring-1 focus:ring-border-button transition-colors" - /> - {/* */} - {/*
*/} -
+
+

{t('availableModels')}

+ {/* Search Bar */} +
+ {/*
*/} + setSearchTerm(e.target.value)} + className="w-full px-4 py-2 pl-10 bg-bg-input border border-border-default rounded-lg focus:outline-none focus:ring-1 focus:ring-border-button transition-colors" + /> + {/* */} + {/*
*/} +
- {/* Tags Filter */} -
- - {allTags.map((tag) => ( + {/* Tags Filter */} +
- ))} -
+ + {allTags.map((tag) => ( + + ))} +
+
{/* Models List */} -
+
{filteredModels.map((model) => (
handleAddModel(model.name)} >
-
+
{model.name}
{!!APIMapUrl[model.name as keyof typeof APIMapUrl] && ( )}
-
-
+
{sortTags(model.tags).map((tag, index) => ( ))}
-
+ ); }; diff --git a/web/src/pages/user-setting/setting-team/index.tsx b/web/src/pages/user-setting/setting-team/index.tsx index 374400c74..cd70b4d50 100644 --- a/web/src/pages/user-setting/setting-team/index.tsx +++ b/web/src/pages/user-setting/setting-team/index.tsx @@ -10,10 +10,7 @@ import Spotlight from '@/components/spotlight'; import { SearchInput } from '@/components/ui/input'; import { UserPlus } from 'lucide-react'; import { useState } from 'react'; -import { - ProfileSettingWrapperCard, - UserSettingHeader, -} from '../components/user-setting-header'; +import { ProfileSettingWrapperCard } from '../components/user-setting-header'; import AddingUserModal from './add-user-modal'; import { useAddUser } from './hooks'; import TenantTable from './tenant-table'; @@ -40,53 +37,60 @@ const UserSettingTeam = () => { // /> +
+

+ {userInfo?.nickname + ' ' + t('setting.workspace')} +

+
} > - - - {/* */} - - {t('setting.teamMembers')} - -
+ +
+ + + {/* */} + + {t('setting.teamMembers')} + + +
+ setSearchUser(e.target.value)} + /> + +
+
+ + + + +
+ + + + {/* */} + + {t('setting.joinedTeams')} + setSearchTerm(e.target.value)} placeholder={t('common.search')} - value={searchUser} - onChange={(e) => setSearchUser(e.target.value)} /> - -
-
- - - -
- - - - {/* */} - - {t('setting.joinedTeams')} - - setSearchTerm(e.target.value)} - placeholder={t('common.search')} - /> - - - - - + + + + + +
{addingTenantModalVisible && ( { const renderSortIcon = () => { if (sortOrder === 'asc') { - return ; + return ; } else if (sortOrder === 'desc') { - return ; + return ; } else { - return ; + return ; } }; @@ -77,13 +77,16 @@ const TenantTable = ({ searchTerm }: { searchTerm: string }) => { {t('common.name')} - -
+ +
{t('setting.updateDate')} - {renderSortIcon()} +
{t('setting.email')} diff --git a/web/src/pages/user-setting/setting-team/user-table.tsx b/web/src/pages/user-setting/setting-team/user-table.tsx index 840e08a89..a4f6fb569 100644 --- a/web/src/pages/user-setting/setting-team/user-table.tsx +++ b/web/src/pages/user-setting/setting-team/user-table.tsx @@ -71,11 +71,11 @@ const UserTable = ({ searchUser }: { searchUser: string }) => { const renderSortIcon = () => { if (sortOrder === 'asc') { - return ; + return ; } else if (sortOrder === 'desc') { - return ; + return ; } else { - return ; + return ; } }; return ( @@ -84,13 +84,16 @@ const UserTable = ({ searchUser }: { searchUser: string }) => { {t('common.name')} - -
+ +
{t('setting.updateDate')} - {renderSortIcon()} +
{t('setting.email')} @@ -110,7 +113,7 @@ const UserTable = ({ searchUser }: { searchUser: string }) => { ) : sortedData && sortedData.length > 0 ? ( sortedData.map((record) => ( - +
[ - { icon: Server, label: t('setting.dataSources'), key: Routes.DataSource }, - { icon: Box, label: t('setting.model'), key: Routes.Model }, - { icon: Banknote, label: 'MCP', key: Routes.Mcp }, - { icon: Users, label: t('setting.team'), key: Routes.Team }, - { icon: User, label: t('setting.profile'), key: Routes.Profile }, - { icon: Unplug, label: t('setting.api'), key: Routes.Api }, + { + icon: , + label: t('setting.dataSources'), + key: Routes.DataSource, + }, + { + icon: , + label: t('setting.model'), + key: Routes.Model, + 'data-testid': 'settings-nav-model-providers', + }, + { + icon: , + label: 'MCP', + key: Routes.Mcp, + }, + { + icon: , + label: t('setting.team'), + key: Routes.Team, + }, + { + icon: , + label: t('setting.profile'), + key: Routes.Profile, + }, + { + icon: , + label: t('setting.api'), + key: Routes.Api, + }, // { // icon: MessageSquareQuote, // label: 'Prompt Templates', @@ -33,10 +63,10 @@ const menuItems = (t: TFunction) => [ // { icon: Cog, label: t('setting.system'), key: Routes.System }, // { icon: Banknote, label: 'Plan', key: Routes.Plan }, ]; + export function SideBar() { - const pathName = useSecondPathName(); const { data: userInfo } = useFetchUserInfo(); - const { handleMenuClick, active } = useHandleMenuClick(); + const { handleMenuClick, active: activeItemKey } = useHandleMenuClick(); const { version, fetchSystemVersion } = useFetchSystemVersion(); const { t } = useTranslation(); useEffect(() => { @@ -48,40 +78,38 @@ export function SideBar() { return ( ); }