From 1a4dee4313aaf6a61e70454640c4a10779759e9e Mon Sep 17 00:00:00 2001 From: Jimmy Ben Klieve Date: Thu, 12 Mar 2026 21:01:09 +0800 Subject: [PATCH] refactor(ui): unify top level pages structure, use standard language codes and time zones (#13573) ### What problem does this PR solve? - Unify top level pages structure - Standardize locale language codes (BCP 47) and time zones (IANA tz) > **Note:** > Newly created user info brings non-standard default values `timezone: "UTC+8\tAsia/Shanghai"` and `language: "English"`. ### Type of change - [x] Refactoring --- .../chat-overview-modal/api-content.tsx | 5 +- web/src/components/avatar-upload.tsx | 79 +-- web/src/components/card-container.tsx | 6 +- .../card-singleline-container/index.tsx | 22 +- web/src/components/empty/empty.tsx | 8 +- web/src/components/list-filter-bar/index.tsx | 6 +- .../originui/select-with-search.tsx | 10 +- web/src/components/ui/button.tsx | 3 +- web/src/components/ui/ragflow-pagination.tsx | 9 +- web/src/components/ui/segmented.tsx | 2 - web/src/constants/common.ts | 10 +- web/src/constants/setting.ts | 453 ++---------------- web/src/hooks/logic-hooks.ts | 7 +- web/src/hooks/use-user-setting-request.tsx | 23 +- web/src/layouts/components/header.tsx | 31 +- web/src/lib/utils.ts | 17 +- web/src/locales/ar.ts | 2 +- web/src/locales/bg.ts | 2 +- web/src/locales/config.ts | 55 ++- web/src/locales/de.ts | 2 +- web/src/locales/en.ts | 2 +- web/src/locales/it.ts | 2 +- web/src/locales/until.ts | 60 --- web/src/pages/admin/service-status.tsx | 15 +- web/src/pages/admin/users.tsx | 8 +- web/src/pages/agents/index.tsx | 282 +++++------ .../dataset-overview/dataset-filter.tsx | 43 +- .../pages/dataset/dataset-overview/index.tsx | 2 - .../dataset-overview/overview-table.tsx | 48 +- web/src/pages/datasets/index.tsx | 135 +++--- web/src/pages/files/files-table.tsx | 28 +- web/src/pages/files/index.tsx | 32 +- web/src/pages/memories/index.tsx | 106 ++-- web/src/pages/next-chats/index.tsx | 104 ++-- web/src/pages/next-searches/index.tsx | 119 +++-- web/src/pages/user-setting/index.tsx | 4 +- .../user-setting/profile/hooks/use-profile.ts | 6 +- web/src/pages/user-setting/profile/index.tsx | 21 +- .../user-setting/setting-locale/index.tsx | 23 - .../setting-locale/translation-table.tsx | 238 --------- web/src/pages/user-setting/sidebar/index.tsx | 3 +- web/src/routes.tsx | 4 +- 42 files changed, 673 insertions(+), 1364 deletions(-) delete mode 100644 web/src/locales/until.ts delete mode 100644 web/src/pages/user-setting/setting-locale/index.tsx delete mode 100644 web/src/pages/user-setting/setting-locale/translation-table.tsx diff --git a/web/src/components/api-service/chat-overview-modal/api-content.tsx b/web/src/components/api-service/chat-overview-modal/api-content.tsx index be19e016b6..b7127f53e9 100644 --- a/web/src/components/api-service/chat-overview-modal/api-content.tsx +++ b/web/src/components/api-service/chat-overview-modal/api-content.tsx @@ -26,8 +26,9 @@ const ApiContent = ({ id, idKey }: { id?: string; idKey: string }) => { const isDarkTheme = useIsDarkTheme(); return ( -
- +
+ +
) : (
- - - - - -
{ + innerInputRef.current?.click(); + }} > - -
+ + + + + +
+ +
+
)} - -
+
{tips ?? t('knowledgeConfiguration.photoTip')}
@@ -357,7 +372,7 @@ export const AvatarUpload = forwardRef( height: '300px', touchAction: 'none', }} - // onWheel={handleWheel} + onWheel={handleWheel} > {children} - +
); } diff --git a/web/src/components/card-singleline-container/index.tsx b/web/src/components/card-singleline-container/index.tsx index a35a37603b..f5e8e232d1 100644 --- a/web/src/components/card-singleline-container/index.tsx +++ b/web/src/components/card-singleline-container/index.tsx @@ -1,5 +1,5 @@ import { cn } from '@/lib/utils'; -import { isValidElement, PropsWithChildren, ReactNode } from 'react'; +import { PropsWithChildren } from 'react'; import './index.less'; type CardContainerProps = { className?: string } & PropsWithChildren; @@ -8,26 +8,6 @@ export function CardSineLineContainer({ children, className, }: CardContainerProps) { - const flattenChildren = (children: ReactNode): ReactNode[] => { - const result: ReactNode[] = []; - - const traverse = (child: ReactNode) => { - if (Array.isArray(child)) { - child.forEach(traverse); - } else if (isValidElement(child) && child.props.children) { - result.push(child); - } else { - result.push(child); - } - }; - - traverse(children); - return result; - }; - const childArray = flattenChildren(children); - const childCount = childArray.length; - console.log(childArray, childCount); - return (
{ - const { type, showIcon, className, isSearch, children, testId } = props; + const { type, showIcon, className, isSearch, children, testId, tabIndex } = + props; const { t } = useTranslation(); let defaultClass = ''; let style = {}; @@ -110,10 +112,10 @@ export const EmptyAppCard = (props: { diff --git a/web/src/components/list-filter-bar/index.tsx b/web/src/components/list-filter-bar/index.tsx index b84271328c..9cd12d4c42 100644 --- a/web/src/components/list-filter-bar/index.tsx +++ b/web/src/components/list-filter-bar/index.tsx @@ -94,7 +94,7 @@ export default function ListFilterBar({ return (
-
+

{typeof icon === 'string' ? ( // +

{preChildren} - {showFilter && ( + {filters?.length && showFilter && ( {selectLabel || value ? ( - - - {selectLabel || value} - + + {selectLabel || value} ) : ( {placeholder} @@ -209,10 +207,10 @@ export const SelectWithSearch = forwardRef<
- {options.map((group, idx) => { + {options.map((group) => { if (group.options) { return ( - + {group.options.map((option) => ( {t('pagination.page', { page: x })}
, value: x.toString(), })); - }, []); + }, [t]); const pages = useMemo(() => { const num = Math.ceil(total / pageSize); @@ -134,7 +135,7 @@ export function RAGFlowPagination({ }, [pages, currentPage]); return ( -
+
{t('pagination.total', { total: total })} @@ -181,6 +182,6 @@ export function RAGFlowPagination({ triggerClassName="bg-bg-card border-transparent" /> )} -
+
); } diff --git a/web/src/components/ui/segmented.tsx b/web/src/components/ui/segmented.tsx index 5b3eba54d9..7318c017dd 100644 --- a/web/src/components/ui/segmented.tsx +++ b/web/src/components/ui/segmented.tsx @@ -105,8 +105,6 @@ const Segmented = React.forwardRef( const isObject = typeof option === 'object'; const actualValue = isObject ? option.value : option; - console.log(actualValue); - return ( - {langItems.map((x) => ( + {supportedLanguages.map((x) => ( changeLanguage(x.key)} + key={x.code} + onClick={() => changeLanguage(x.code)} > - {x.label} + {x.displayName} ))} diff --git a/web/src/lib/utils.ts b/web/src/lib/utils.ts index 3b3f77e8a6..646e0534f6 100644 --- a/web/src/lib/utils.ts +++ b/web/src/lib/utils.ts @@ -1,4 +1,5 @@ import { clsx, type ClassValue } from 'clsx'; +import React from 'react'; import { twMerge } from 'tailwind-merge'; export function cn(...inputs: ClassValue[]) { @@ -19,6 +20,20 @@ export function formatBytes( if (bytes === 0) return '0 Byte'; const i = Math.floor(Math.log(bytes) / Math.log(1024)); return `${(bytes / Math.pow(1024, i)).toFixed(decimals)} ${ - sizeType === 'accurate' ? accurateSizes[i] ?? 'Bytes' : sizes[i] ?? 'Bytes' + sizeType === 'accurate' + ? (accurateSizes[i] ?? 'Bytes') + : (sizes[i] ?? 'Bytes') }`; } + +export function combineRefs(...refs: React.ForwardedRef[]) { + return (node: T) => { + refs.forEach((ref) => { + if (typeof ref === 'function') { + ref(node); + } else if (ref) { + ref.current = node; + } + }); + }; +} diff --git a/web/src/locales/ar.ts b/web/src/locales/ar.ts index 9e1334f779..f6336c4734 100644 --- a/web/src/locales/ar.ts +++ b/web/src/locales/ar.ts @@ -2300,7 +2300,7 @@ export default { }, pagination: { total: 'الإجمالي {{total}}', - page: '{{page}} /الصفحة', + page: '{{page}} / الصفحة', }, dataflowParser: { result: 'نتيجة', diff --git a/web/src/locales/bg.ts b/web/src/locales/bg.ts index 7a0a91baed..078ece92d7 100644 --- a/web/src/locales/bg.ts +++ b/web/src/locales/bg.ts @@ -2385,7 +2385,7 @@ Important structured information may include: names, dates, locations, events, k }, pagination: { total: 'Общо {{total}}', - page: '{{page}} /Страница', + page: '{{page}} / Страница', }, dataflowParser: { result: 'Резултат', diff --git a/web/src/locales/config.ts b/web/src/locales/config.ts index 73469dcaab..2a625b622c 100644 --- a/web/src/locales/config.ts +++ b/web/src/locales/config.ts @@ -1,13 +1,14 @@ import i18n from 'i18next'; import LanguageDetector from 'i18next-browser-languagedetector'; +import { upperFirst } from 'lodash'; import { initReactI18next } from 'react-i18next'; import { LanguageAbbreviation } from '@/constants/common'; -import { createTranslationTable, flattenObject } from './until'; import translation_en from './en'; const languageImports: Record Promise<{ default: any }>> = { + [LanguageAbbreviation.En]: () => import('./en'), [LanguageAbbreviation.Zh]: () => import('./zh'), [LanguageAbbreviation.ZhTraditional]: () => import('./zh-traditional'), [LanguageAbbreviation.Id]: () => import('./id'), @@ -23,20 +24,22 @@ const languageImports: Record Promise<{ default: any }>> = { [LanguageAbbreviation.Ar]: () => import('./ar'), }; -const languageAliases: Record = { - 'pt-br': LanguageAbbreviation.PtBr, -}; +const supportedLanguageCodes: Intl.UnicodeBCP47LocaleIdentifier[] = + Object.keys(languageImports); -const normalizeLanguageCode = (lng: string): string => { - return languageAliases[lng] ?? lng; -}; +export const supportedLanguages = supportedLanguageCodes.map((code) => { + const locale = new Intl.Locale(code); -const enFlattened = flattenObject(translation_en); + return { + code, + locale, + displayName: upperFirst( + new Intl.DisplayNames(locale, { type: 'language' }).of(code)!, + ), + }; +}); -export const translationTable = createTranslationTable( - [enFlattened], - ['English'], -); +export const DEFAULT_LANGUAGE_CODE = LanguageAbbreviation.En; const resources = { [LanguageAbbreviation.En]: translation_en, @@ -49,16 +52,17 @@ i18n detection: { lookupLocalStorage: 'lng', }, - supportedLngs: Object.values(LanguageAbbreviation), + supportedLngs: supportedLanguageCodes, resources, - fallbackLng: 'en', + fallbackLng: DEFAULT_LANGUAGE_CODE, interpolation: { escapeValue: false, }, }); export const loadLanguageAsync = async (lng: string): Promise => { - const normalizedLng = normalizeLanguageCode(lng); + // const normalizedLng = normalizeLanguageCode(lng); + const normalizedLng = lng; if (i18n.hasResourceBundle(normalizedLng, 'translation')) { return; @@ -74,16 +78,15 @@ export const loadLanguageAsync = async (lng: string): Promise => { const module = await importFn(); const translationData = module.default?.translation || module.default; i18n.addResourceBundle(normalizedLng, 'translation', translationData); - - const flattened = flattenObject({ translation: translationData }); - translationTable.push(flattened); } catch (error) { console.error(`Failed to load language ${lng}:`, error); } }; export const changeLanguageAsync = async (lng: string): Promise => { - const normalizedLng = normalizeLanguageCode(lng); + // const normalizedLng = normalizeLanguageCode(lng); + const normalizedLng = lng; + if ( normalizedLng !== LanguageAbbreviation.En && !i18n.hasResourceBundle(normalizedLng, 'translation') @@ -94,14 +97,14 @@ export const changeLanguageAsync = async (lng: string): Promise => { }; export const initLanguage = async (): Promise => { - const currentLng = normalizeLanguageCode( - i18n.language || localStorage.getItem('lng') || LanguageAbbreviation.En, - ); + // const currentLng = normalizeLanguageCode( + // i18n.language || localStorage.getItem('lng') || LanguageAbbreviation.En, + // ); - if (currentLng !== LanguageAbbreviation.En && languageImports[currentLng]) { - await loadLanguageAsync(currentLng); - await i18n.changeLanguage(currentLng); - } + const currentLng = + i18n.language || localStorage.getItem('lng') || DEFAULT_LANGUAGE_CODE; + + await changeLanguageAsync(currentLng); }; export default i18n; diff --git a/web/src/locales/de.ts b/web/src/locales/de.ts index 5e17b24e5f..5cef98ba33 100644 --- a/web/src/locales/de.ts +++ b/web/src/locales/de.ts @@ -2444,7 +2444,7 @@ Wichtige strukturierte Informationen können sein: Namen, Daten, Orte, Ereigniss }, pagination: { total: 'Gesamt {{total}}', - page: '{{page}} /Seite', + page: '{{page}} / Seite', }, dataflowParser: { result: 'Ergebnis', diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index e58b958923..0671ac33a0 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -2482,7 +2482,7 @@ Important structured information may include: names, dates, locations, events, k }, pagination: { total: 'Total {{total}}', - page: '{{page}} /Page', + page: '{{page}} / Page', }, dataflowParser: { result: 'Result', diff --git a/web/src/locales/it.ts b/web/src/locales/it.ts index 2a16b2ea01..febe4c9f6e 100644 --- a/web/src/locales/it.ts +++ b/web/src/locales/it.ts @@ -1203,7 +1203,7 @@ Quanto sopra è il contenuto che devi riassumere.`, }, pagination: { total: 'Totale {{total}}', - page: '{{page}} /Pagina', + page: '{{page}} / Pagina', }, deleteModal: { delAgent: 'Elimina agente', diff --git a/web/src/locales/until.ts b/web/src/locales/until.ts deleted file mode 100644 index 9934a97570..0000000000 --- a/web/src/locales/until.ts +++ /dev/null @@ -1,60 +0,0 @@ -type NestedObject = { - [key: string]: string | NestedObject; -}; - -type FlattenedObject = { - [key: string]: string; -}; - -export function flattenObject( - obj: NestedObject, - parentKey: string = '', -): FlattenedObject { - const result: FlattenedObject = {}; - - for (const [key, value] of Object.entries(obj)) { - const newKey = parentKey ? `${parentKey}.${key}` : key; - - if (typeof value === 'object' && value !== null) { - Object.assign(result, flattenObject(value as NestedObject, newKey)); - } else { - result[newKey] = value as string; - } - } - - return result; -} -type TranslationTableRow = { - key: string; - [language: string]: string; -}; - -/** - * Creates a translation table from multiple flattened language objects. - * @param langs - A list of flattened language objects. - * @param langKeys - A list of language identifiers (e.g., 'English', 'Vietnamese'). - * @returns An array representing the translation table. - */ -export function createTranslationTable( - langs: FlattenedObject[], - langKeys: string[], -): TranslationTableRow[] { - const keys = new Set(); - - // Collect all unique keys from the language objects - langs.forEach((lang) => { - Object.keys(lang).forEach((key) => keys.add(key)); - }); - - // Build the table - return Array.from(keys).map((key) => { - const row: TranslationTableRow = { key }; - - langs.forEach((lang, index) => { - const langKey = langKeys[index]; - row[langKey] = lang[key] || ''; // Use empty string if key is missing - }); - - return row; - }); -} diff --git a/web/src/pages/admin/service-status.tsx b/web/src/pages/admin/service-status.tsx index 582b38cac6..46da1b50b7 100644 --- a/web/src/pages/admin/service-status.tsx +++ b/web/src/pages/admin/service-status.tsx @@ -229,19 +229,8 @@ function AdminServiceStatus() {
- diff --git a/web/src/pages/admin/users.tsx b/web/src/pages/admin/users.tsx index 4eafa54b0a..9730eec576 100644 --- a/web/src/pages/admin/users.tsx +++ b/web/src/pages/admin/users.tsx @@ -481,12 +481,8 @@ function AdminUserManagement() {
- diff --git a/web/src/pages/agents/index.tsx b/web/src/pages/agents/index.tsx index 7e954aff96..bea639f2f2 100644 --- a/web/src/pages/agents/index.tsx +++ b/web/src/pages/agents/index.tsx @@ -13,6 +13,7 @@ import { import { RAGFlowPagination } from '@/components/ui/ragflow-pagination'; import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks'; import { useFetchAgentListByPage } from '@/hooks/use-agent-request'; +import { Routes } from '@/routes'; import { t } from 'i18next'; import { pick } from 'lodash'; import { Clipboard, ClipboardPlus, FileInput, Plus } from 'lucide-react'; @@ -36,6 +37,7 @@ export default function Agents() { filterValue, handleFilterSubmit, } = useFetchAgentListByPage(); + const { navigateToAgentTemplates } = useNavigatePage(); const { @@ -72,6 +74,7 @@ export default function Agents() { ); const [searchUrl, setSearchUrl] = useSearchParams(); const isCreate = searchUrl.get('isCreate') === 'true'; + useEffect(() => { if (isCreate) { showCreatingModal(); @@ -79,153 +82,162 @@ export default function Agents() { setSearchUrl(searchUrl); } }, [isCreate, showCreatingModal, searchUrl, setSearchUrl]); + return ( <> - {(!data?.length || data?.length <= 0) && !searchString && ( -
- showCreatingModal()} - > -
-
- - {t('flow.createFromBlank')} -
-
- - {t('flow.createFromTemplate')} -
-
- - {t('flow.importJsonFile')} -
-
-
-
- )} -
- {(!!data?.length || searchString) && ( - <> -
- - - - - - - - - {t('flow.createFromBlank')} - - - - {t('flow.createFromTemplate')} - - - - {t('flow.importJsonFile')} - - - - -
- {(!data?.length || data?.length <= 0) && searchString && ( -
- showCreatingModal()} - /> -
- )} -
- + {data?.length || searchString ? ( +
+
+ + + + + + + + + {t('flow.createFromBlank')} + + navigateToAgentTemplates()} + > + + {t('flow.createFromTemplate')} + + + + {t('flow.importJsonFile')} + + + + +
+ + {data.length ? ( + <> + {data.map((x) => { return ( + /> ); })} + +
+ +
+ + ) : ( +
+ showCreatingModal()} + />
-
- -
- - )} - {agentRenameVisible && ( - - )} - {creatingVisible && ( - - )} - {fileUploadVisible && ( - - )} -
+ )} + + ) : ( +
+ showCreatingModal()} + > +
    +
  • + +
  • + +
  • + +
  • + +
  • + +
  • +
+
+
+ )} + + {agentRenameVisible && ( + + )} + {creatingVisible && ( + + )} + {fileUploadVisible && ( + + )} ); } diff --git a/web/src/pages/dataset/dataset-overview/dataset-filter.tsx b/web/src/pages/dataset/dataset-overview/dataset-filter.tsx index 4767ce5d71..ab7bb4f25f 100644 --- a/web/src/pages/dataset/dataset-overview/dataset-filter.tsx +++ b/web/src/pages/dataset/dataset-overview/dataset-filter.tsx @@ -3,9 +3,8 @@ import { CheckboxFormMultipleProps, FilterPopover, } from '@/components/list-filter-bar/filter-popover'; -import { Button } from '@/components/ui/button'; import { SearchInput } from '@/components/ui/input'; -import { cn } from '@/lib/utils'; +import { Segmented } from '@/components/ui/segmented'; import { ChangeEventHandler, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { LogTabs } from './dataset-common'; @@ -40,35 +39,23 @@ const DatasetFilter = ( }, [value]); return (
-
- - + ]} + onChange={(value) => + setActive?.(value as (typeof LogTabs)[keyof typeof LogTabs]) + } + />
-
+ +
{ label: t('knowledgeDetails.status'), list: Object.values(RunningStatus).map((value) => { // const value = key as RunningStatus; - console.log(value); return { id: value, // label: RunningStatusMap[value].label, @@ -245,7 +244,6 @@ const FileLogsPage: FC = () => { page: number; pageSize: number; }) => { - console.log('Pagination changed:', { page, pageSize }); setPagination({ ...pagination, page, diff --git a/web/src/pages/dataset/dataset-overview/overview-table.tsx b/web/src/pages/dataset/dataset-overview/overview-table.tsx index 6c5c93527d..de92a53ef5 100644 --- a/web/src/pages/dataset/dataset-overview/overview-table.tsx +++ b/web/src/pages/dataset/dataset-overview/overview-table.tsx @@ -150,14 +150,19 @@ export const getFileLogsTableColumns = ( accessorKey: 'process_begin_at', header: ({ column }) => { return ( - + + +
); }, cell: ({ row }) => ( @@ -192,8 +197,7 @@ export const getFileLogsTableColumns = (
+ +
); }, cell: ({ row }) => ( @@ -319,11 +326,10 @@ export const getDatasetLogsTableColumns = ( id: 'operations', header: t('operations'), cell: ({ row }) => ( -
+
- {(!kbs?.length || kbs?.length <= 0) && searchString && ( -
- showModal()} - /> -
- )} -
- - {kbs.map((dataset) => { - return ( - - ); - })} + + + {kbs?.length ? ( + <> + + {kbs.map((dataset) => ( + + ))} + +
+ +
+ + ) : ( +
+ showModal()} + />
-
- -
- - )} - {visible && ( - - )} - {datasetRenameVisible && ( - - )} -
+ )} + + ) : ( +
+ showModal()} + /> +
+ )} + {visible && ( + + )} + {datasetRenameVisible && ( + + )} ); } diff --git a/web/src/pages/files/files-table.tsx b/web/src/pages/files/files-table.tsx index cb4a92681d..abc072185e 100644 --- a/web/src/pages/files/files-table.tsx +++ b/web/src/pages/files/files-table.tsx @@ -225,7 +225,7 @@ export function FilesTable({ id: 'actions', header: t('action'), meta: { - headerCellClassName: 'w-0', + headerCellClassName: 'w-0 whitespace-nowrap', }, enableHiding: false, enablePinning: true, @@ -278,8 +278,8 @@ export function FilesTable({ return ( <> -
- +
+
{table.getHeaderGroups().map((headerGroup) => ( @@ -332,17 +332,17 @@ export function FilesTable({
-
-
- { - setPagination({ page, pageSize }); - }} - > -
-
+ +
+ { + setPagination({ page, pageSize }); + }} + /> +
+ {connectToKnowledgeVisible && ( -
+
+
+ {!rowSelectionIsEmpty && ( - + )}
- + +
+ +
+ {fileUploadVisible && ( - {(!list?.data?.memory_list?.length || - list?.data?.memory_list?.length <= 0) && - !searchString && ( -
- openCreateModalFun()} - /> -
- )} - {(!!list?.data?.memory_list?.length || searchString) && ( - <> -
+ <> + {list?.data?.memory_list?.length || searchString ? ( +
+
- -
- {(!list?.data?.memory_list?.length || - list?.data?.memory_list?.length <= 0) && - searchString && ( -
- openCreateModalFun()} - /> -
- )} -
- - {list?.data.memory_list.map((x) => { - return ( +
+ + {list?.data?.memory_list?.length ? ( + <> + + {list?.data.memory_list.map((x) => ( - ); - })} - -
- {list?.data.total_count && list?.data.total_count > 0 && ( -
- + ))} + + +
+ +
+ + ) : ( +
+ openCreateModalFun()} />
)} - + + ) : ( +
+ openCreateModalFun()} + /> +
)} {/* {openCreateModal && ( )} - + ); } diff --git a/web/src/pages/next-chats/index.tsx b/web/src/pages/next-chats/index.tsx index 195fd99121..a6d764c530 100644 --- a/web/src/pages/next-chats/index.tsx +++ b/web/src/pages/next-chats/index.tsx @@ -49,70 +49,72 @@ export default function ChatList() { }, [isCreate, handleShowCreateModal, searchParams, setSearchParams]); return ( -
- {data.dialogs?.length <= 0 && !searchString && ( -
- handleShowCreateModal()} - testId="chats-empty-create" - /> -
- )} - {(data.dialogs?.length > 0 || searchString) && ( - <> -
+ <> + {data.dialogs?.length || searchString ? ( +
+
- -
- {data.dialogs?.length <= 0 && searchString && ( -
- handleShowCreateModal()} - testId="chats-empty-create" - /> -
- )} -
- - {data.dialogs.map((x) => { - return ( + + + {data.dialogs?.length ? ( + <> + + {data.dialogs.map((x) => ( - ); - })} - -
-
- -
- + /> + ))} + + +
+ +
+ + ) : ( +
+ +
+ )} + + ) : ( +
+ handleShowCreateModal()} + testId="chats-empty-create" + /> +
)} + {chatRenameVisible && ( )} -
+ ); } diff --git a/web/src/pages/next-searches/index.tsx b/web/src/pages/next-searches/index.tsx index f49563a2d5..70e9a01f43 100644 --- a/web/src/pages/next-searches/index.tsx +++ b/web/src/pages/next-searches/index.tsx @@ -65,25 +65,10 @@ export default function SearchList() { }, [isCreate, openCreateModalFun, searchUrl, setSearchUrl]); return ( -
- {(!list?.data?.search_apps?.length || - list?.data?.search_apps?.length <= 0) && - !searchString && ( -
- openCreateModalFun()} - testId="search-empty-create" - /> -
- )} - {(!!list?.data?.search_apps?.length || searchString) && ( - <> -
+ <> + {list?.data?.search_apps?.length || searchString ? ( +
+
-
- {(!list?.data?.search_apps?.length || - list?.data?.search_apps?.length <= 0) && - searchString && ( -
- openCreateModalFun()} - testId="search-empty-create" + + + {list?.data?.search_apps?.length ? ( + <> + + {list?.data.search_apps.map((x) => { + return ( + { + showSearchRenameModal(x); + }} + /> + ); + })} + + +
+ -
- )} -
- - {list?.data.search_apps.map((x) => { - return ( - { - showSearchRenameModal(x); - }} - > - ); - })} - -
- {list?.data.total && list?.data.total > 0 && ( -
- + + ) : ( +
+
)} - + + ) : ( +
+ openCreateModalFun()} + testId="search-empty-create" + /> +
)} {openCreateModal && ( )} -
+ ); } diff --git a/web/src/pages/user-setting/index.tsx b/web/src/pages/user-setting/index.tsx index f3b8568579..080ed3b8d1 100644 --- a/web/src/pages/user-setting/index.tsx +++ b/web/src/pages/user-setting/index.tsx @@ -6,10 +6,10 @@ import { cn } from '@/lib/utils'; const UserSetting = () => { return (
- +
- +
); diff --git a/web/src/pages/user-setting/profile/hooks/use-profile.ts b/web/src/pages/user-setting/profile/hooks/use-profile.ts index 5b8bdf7b50..ffcd6ae134 100644 --- a/web/src/pages/user-setting/profile/hooks/use-profile.ts +++ b/web/src/pages/user-setting/profile/hooks/use-profile.ts @@ -1,4 +1,5 @@ // src/hooks/useProfile.ts +import { DEFAULT_TIMEZONE } from '@/constants/setting'; import { useFetchUserInfo, useSaveSetting, @@ -53,7 +54,10 @@ export const useProfile = () => { // form.setValue('currPasswd', ''); // current password const profile = { userName: userInfo.nickname, - timeZone: userInfo.timezone, + timeZone: + userInfo.timezone === ' UTC+8\tAsia/Shanghai' + ? DEFAULT_TIMEZONE.name + : userInfo.timezone, avatar: userInfo.avatar || '', email: userInfo.email, currPasswd: userInfo.password, diff --git a/web/src/pages/user-setting/profile/index.tsx b/web/src/pages/user-setting/profile/index.tsx index 4b0d897ffb..9f330fab33 100644 --- a/web/src/pages/user-setting/profile/index.tsx +++ b/web/src/pages/user-setting/profile/index.tsx @@ -19,12 +19,17 @@ import { TimezoneList } from '@/pages/user-setting/constants'; import { zodResolver } from '@hookform/resolvers/zod'; import { t } from 'i18next'; import { Loader2Icon, PenLine } from 'lucide-react'; -import { FC, useEffect } from 'react'; +import { FC, useEffect, useMemo } from 'react'; import { useForm } from 'react-hook-form'; import { z } from 'zod'; import { ProfileSettingWrapperCard } from '../components/user-setting-header'; import { EditType, modalTitle, useProfile } from './hooks/use-profile'; +const timezoneOptions = TimezoneList.map(({ name }) => ({ + value: name, + label: name, +})); + const baseSchema = z.object({ userName: z .string() @@ -75,6 +80,7 @@ const passwordSchema = baseSchema }); } }); + const ProfilePage: FC = () => { const { t } = useTranslate('setting'); @@ -116,6 +122,11 @@ const ProfilePage: FC = () => { // ); // }; + const timezone = useMemo(() => { + const tz = TimezoneList.find((tz) => tz.name === profile.timeZone); + return tz?.name ?? ''; + }, [profile.timeZone]); + return ( //
{ {t('timezone')}
-
- {profile.timeZone} +
+ {timezone}