| import Input from '@/app/components/base/input' | import Input from '@/app/components/base/input' | ||||
| const titleClassName = ` | const titleClassName = ` | ||||
| text-sm font-medium text-gray-900 | |||||
| system-sm-semibold text-text-secondary | |||||
| ` | ` | ||||
| const descriptionClassName = ` | const descriptionClassName = ` | ||||
| mt-1 text-xs font-normal text-gray-500 | |||||
| mt-1 body-xs-regular text-text-tertiary | |||||
| ` | ` | ||||
| const validPassword = /^(?=.*[a-zA-Z])(?=.*\d).{8,}$/ | const validPassword = /^(?=.*[a-zA-Z])(?=.*\d).{8,}$/ | ||||
| <div className='mr-3'> | <div className='mr-3'> | ||||
| <AppIcon size='tiny' /> | <AppIcon size='tiny' /> | ||||
| </div> | </div> | ||||
| <div className='mt-[3px] text-xs font-medium text-gray-700 leading-[18px]'>{item.name}</div> | |||||
| <div className='mt-[3px] system-sm-medium text-text-secondary'>{item.name}</div> | |||||
| </div> | </div> | ||||
| ) | ) | ||||
| } | } | ||||
| return ( | return ( | ||||
| <> | <> | ||||
| <div className='pt-2 pb-3'> | <div className='pt-2 pb-3'> | ||||
| <h4 className='title-2xl-semi-bold text-primary'>{t('common.account.myAccount')}</h4> | |||||
| <h4 className='title-2xl-semi-bold text-text-primary'>{t('common.account.myAccount')}</h4> | |||||
| </div> | </div> | ||||
| <div className='mb-8 p-6 rounded-xl flex items-center bg-gradient-to-r from-background-gradient-bg-fill-chat-bg-2 to-background-gradient-bg-fill-chat-bg-1'> | <div className='mb-8 p-6 rounded-xl flex items-center bg-gradient-to-r from-background-gradient-bg-fill-chat-bg-2 to-background-gradient-bg-fill-chat-bg-1'> | ||||
| <Avatar name={userProfile.name} size={64} /> | <Avatar name={userProfile.name} size={64} /> | ||||
| <div className='mb-8'> | <div className='mb-8'> | ||||
| <div className={titleClassName}>{t('common.account.name')}</div> | <div className={titleClassName}>{t('common.account.name')}</div> | ||||
| <div className='flex items-center justify-between gap-2 w-full mt-2'> | <div className='flex items-center justify-between gap-2 w-full mt-2'> | ||||
| <div className='flex-1 bg-gray-100 rounded-md p-2 system-sm-regular text-components-input-text-filled '> | |||||
| <div className='flex-1 bg-components-input-bg-normal rounded-lg p-2 system-sm-regular text-components-input-text-filled '> | |||||
| <span className='pl-1'>{userProfile.name}</span> | <span className='pl-1'>{userProfile.name}</span> | ||||
| </div> | </div> | ||||
| <div className=' bg-gray-100 rounded-md py-2 px-3 cursor-pointer system-sm-medium text-components-input-text-filled' onClick={handleEditName}> | |||||
| <div className='bg-components-button-tertiary-bg rounded-lg py-2 px-3 cursor-pointer system-sm-medium text-components-button-tertiary-text' onClick={handleEditName}> | |||||
| {t('common.operation.edit')} | {t('common.operation.edit')} | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div className='mb-8'> | <div className='mb-8'> | ||||
| <div className={titleClassName}>{t('common.account.email')}</div> | <div className={titleClassName}>{t('common.account.email')}</div> | ||||
| <div className='flex items-center justify-between gap-2 w-full mt-2'> | <div className='flex items-center justify-between gap-2 w-full mt-2'> | ||||
| <div className='flex-1 bg-gray-100 rounded-md p-2 system-sm-regular text-components-input-text-filled '> | |||||
| <div className='flex-1 bg-components-input-bg-normal rounded-lg p-2 system-sm-regular text-components-input-text-filled '> | |||||
| <span className='pl-1'>{userProfile.email}</span> | <span className='pl-1'>{userProfile.email}</span> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| systemFeatures.enable_email_password_login && ( | systemFeatures.enable_email_password_login && ( | ||||
| <div className='mb-8 flex justify-between gap-2'> | <div className='mb-8 flex justify-between gap-2'> | ||||
| <div> | <div> | ||||
| <div className='mb-1 text-sm font-medium text-gray-900'>{t('common.account.password')}</div> | |||||
| <div className='mb-2 text-xs text-gray-500'>{t('common.account.passwordTip')}</div> | |||||
| <div className='mb-1 system-sm-semibold text-text-secondary'>{t('common.account.password')}</div> | |||||
| <div className='mb-2 body-xs-regular text-text-tertiary'>{t('common.account.passwordTip')}</div> | |||||
| </div> | </div> | ||||
| <Button onClick={() => setEditPasswordModalVisible(true)}>{userProfile.is_password_set ? t('common.account.resetPassword') : t('common.account.setPassword')}</Button> | <Button onClick={() => setEditPasswordModalVisible(true)}>{userProfile.is_password_set ? t('common.account.resetPassword') : t('common.account.setPassword')}</Button> | ||||
| </div> | </div> | ||||
| ) | ) | ||||
| } | } | ||||
| <div className='mb-6 border-[0.5px] border-gray-100' /> | |||||
| <div className='mb-6 border-[1px] border-divider-subtle' /> | |||||
| <div className='mb-8'> | <div className='mb-8'> | ||||
| <div className={titleClassName}>{t('common.account.langGeniusAccount')}</div> | <div className={titleClassName}>{t('common.account.langGeniusAccount')}</div> | ||||
| <div className={descriptionClassName}>{t('common.account.langGeniusAccountTip')}</div> | <div className={descriptionClassName}>{t('common.account.langGeniusAccountTip')}</div> | ||||
| wrapperClassName='mt-2' | wrapperClassName='mt-2' | ||||
| /> | /> | ||||
| )} | )} | ||||
| {!IS_CE_EDITION && <Button className='mt-2 text-[#D92D20]' onClick={() => setShowDeleteAccountModal(true)}>{t('common.account.delete')}</Button>} | |||||
| {!IS_CE_EDITION && <Button className='mt-2 text-components-button-destructive-secondary-text' onClick={() => setShowDeleteAccountModal(true)}>{t('common.account.delete')}</Button>} | |||||
| </div> | </div> | ||||
| { | { | ||||
| editNameModalVisible && ( | editNameModalVisible && ( | ||||
| onClose={() => setEditNameModalVisible(false)} | onClose={() => setEditNameModalVisible(false)} | ||||
| className={s.modal} | className={s.modal} | ||||
| > | > | ||||
| <div className='mb-6 text-lg font-medium text-gray-900'>{t('common.account.editName')}</div> | |||||
| <div className='mb-6 title-2xl-semi-bold text-text-primary'>{t('common.account.editName')}</div> | |||||
| <div className={titleClassName}>{t('common.account.name')}</div> | <div className={titleClassName}>{t('common.account.name')}</div> | ||||
| <Input className='mt-2' | <Input className='mt-2' | ||||
| value={editName} | value={editName} | ||||
| }} | }} | ||||
| className={s.modal} | className={s.modal} | ||||
| > | > | ||||
| <div className='mb-6 text-lg font-medium text-gray-900'>{userProfile.is_password_set ? t('common.account.resetPassword') : t('common.account.setPassword')}</div> | |||||
| <div className='mb-6 title-2xl-semi-bold text-text-primary'>{userProfile.is_password_set ? t('common.account.resetPassword') : t('common.account.setPassword')}</div> | |||||
| {userProfile.is_password_set && ( | {userProfile.is_password_set && ( | ||||
| <> | <> | ||||
| <div className={titleClassName}>{t('common.account.currentPassword')}</div> | <div className={titleClassName}>{t('common.account.currentPassword')}</div> | ||||
| </div> | </div> | ||||
| </> | </> | ||||
| )} | )} | ||||
| <div className='mt-8 text-sm font-medium text-gray-900'> | |||||
| <div className='mt-8 system-sm-semibold text-text-secondary'> | |||||
| {userProfile.is_password_set ? t('common.account.newPassword') : t('common.account.password')} | {userProfile.is_password_set ? t('common.account.newPassword') : t('common.account.password')} | ||||
| </div> | </div> | ||||
| <div className='relative mt-2'> | <div className='relative mt-2'> | ||||
| </Button> | </Button> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div className='mt-8 text-sm font-medium text-gray-900'>{t('common.account.confirmPassword')}</div> | |||||
| <div className='mt-8 system-sm-semibold text-text-secondary'>{t('common.account.confirmPassword')}</div> | |||||
| <div className='relative mt-2'> | <div className='relative mt-2'> | ||||
| <Input | <Input | ||||
| type={showConfirmPassword ? 'text' : 'password'} | type={showConfirmPassword ? 'text' : 'password'} | ||||
| title={t('common.account.delete')} | title={t('common.account.delete')} | ||||
| content={ | content={ | ||||
| <> | <> | ||||
| <div className='my-1 text-[#D92D20] text-sm leading-5'> | |||||
| <div className='my-1 text-text-destructive body-md-medium'> | |||||
| {t('common.account.deleteTip')} | {t('common.account.deleteTip')} | ||||
| </div> | </div> | ||||
| <div className='mt-3 text-sm leading-5'> | <div className='mt-3 text-sm leading-5'> | ||||
| <span>{t('common.account.deleteConfirmTip')}</span> | <span>{t('common.account.deleteConfirmTip')}</span> | ||||
| <a | <a | ||||
| className='text-primary-600 cursor' | |||||
| className='text-text-accent cursor' | |||||
| href={`mailto:support@dify.ai?subject=Delete Account Request&body=Delete Account: ${userProfile.email}`} | href={`mailto:support@dify.ai?subject=Delete Account Request&body=Delete Account: ${userProfile.email}`} | ||||
| target='_blank' | target='_blank' | ||||
| rel='noreferrer noopener' | rel='noreferrer noopener' | ||||
| support@dify.ai | support@dify.ai | ||||
| </a> | </a> | ||||
| </div> | </div> | ||||
| <div className='my-2 px-3 py-2 rounded-lg bg-gray-100 text-sm font-medium leading-5 text-gray-800'>{`${t('common.account.delete')}: ${userProfile.email}`}</div> | |||||
| <div className='my-2 px-3 py-2 rounded-lg bg-components-input-bg-active border border-components-input-border-active system-sm-regular text-components-input-text-filled'>{`${t('common.account.delete')}: ${userProfile.email}`}</div> | |||||
| </> | </> | ||||
| } | } | ||||
| confirmText={t('common.operation.ok') as string} | confirmText={t('common.operation.ok') as string} |
| className={` | className={` | ||||
| inline-flex items-center | inline-flex items-center | ||||
| rounded-[20px] p-1x text-sm | rounded-[20px] p-1x text-sm | ||||
| text-gray-700 hover:bg-gray-200 | |||||
| text-text-primary | |||||
| mobile:px-1 | mobile:px-1 | ||||
| ${open && 'bg-gray-200'} | |||||
| ${open && 'bg-components-panel-bg-blur'} | |||||
| `} | `} | ||||
| > | > | ||||
| <Avatar name={userProfile.name} size={32} /> | <Avatar name={userProfile.name} size={32} /> | ||||
| <Menu.Items | <Menu.Items | ||||
| className=" | className=" | ||||
| absolute -right-2 -top-1 w-60 max-w-80 | absolute -right-2 -top-1 w-60 max-w-80 | ||||
| divide-y divide-gray-100 origin-top-right rounded-lg bg-white | |||||
| divide-y divide-divider-subtle origin-top-right rounded-lg bg-components-panel-bg-blur | |||||
| shadow-lg | shadow-lg | ||||
| " | " | ||||
| > | > | ||||
| <Menu.Item> | <Menu.Item> | ||||
| <div className='p-1' onClick={() => handleLogout()}> | <div className='p-1' onClick={() => handleLogout()}> | ||||
| <div | <div | ||||
| className='flex items-center justify-start h-9 px-3 rounded-lg cursor-pointer group hover:bg-gray-50' | |||||
| className='flex items-center justify-start h-9 px-3 rounded-lg cursor-pointer group hover:bg-state-base-hover' | |||||
| > | > | ||||
| <LogOut01 className='w-4 h-4 text-gray-500 flex mr-1' /> | |||||
| <div className='font-normal text-[14px] text-gray-700'>{t('common.userProfile.logout')}</div> | |||||
| <LogOut01 className='w-4 h-4 text-text-tertiary flex mr-1' /> | |||||
| <div className='font-normal text-[14px] text-text-secondary'>{t('common.userProfile.logout')}</div> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </Menu.Item> | </Menu.Item> |
| <HeaderWrapper> | <HeaderWrapper> | ||||
| <Header /> | <Header /> | ||||
| </HeaderWrapper> | </HeaderWrapper> | ||||
| <div className='relative flex flex-col overflow-y-auto bg-white shrink-0 h-0 grow'> | |||||
| <div className='relative flex flex-col overflow-y-auto bg-components-panel-bg shrink-0 h-0 grow'> | |||||
| {children} | {children} | ||||
| </div> | </div> | ||||
| </ModalContextProvider> | </ModalContextProvider> |
| import { Dialog, Transition } from '@headlessui/react' | import { Dialog, Transition } from '@headlessui/react' | ||||
| import { Fragment } from 'react' | import { Fragment } from 'react' | ||||
| import { XMarkIcon } from '@heroicons/react/24/outline' | |||||
| import { RiCloseLine } from '@remixicon/react' | |||||
| import classNames from '@/utils/classnames' | import classNames from '@/utils/classnames' | ||||
| // https://headlessui.com/react/dialog | // https://headlessui.com/react/dialog | ||||
| leaveFrom="opacity-100" | leaveFrom="opacity-100" | ||||
| leaveTo="opacity-0" | leaveTo="opacity-0" | ||||
| > | > | ||||
| <div className="fixed inset-0 bg-black bg-opacity-25" /> | |||||
| <div className="fixed inset-0 bg-background-overlay-fullscreen" /> | |||||
| </Transition.Child> | </Transition.Child> | ||||
| <div | <div | ||||
| )}> | )}> | ||||
| {title && <Dialog.Title | {title && <Dialog.Title | ||||
| as="h3" | as="h3" | ||||
| className="text-lg font-medium leading-6 text-text-primary" | |||||
| className="title-2xl-semi-bold text-text-primary" | |||||
| > | > | ||||
| {title} | {title} | ||||
| </Dialog.Title>} | </Dialog.Title>} | ||||
| {description && <Dialog.Description className='text-text-tertiary text-xs font-normal mt-2'> | |||||
| {description && <Dialog.Description className='text-text-secondary body-md-regular mt-2'> | |||||
| {description} | {description} | ||||
| </Dialog.Description>} | </Dialog.Description>} | ||||
| {closable | {closable | ||||
| && <div className='absolute z-10 top-6 right-6 w-5 h-5 rounded-2xl flex items-center justify-center hover:cursor-pointer hover:bg-components-panel-on-panel-item-bg-hover'> | |||||
| <XMarkIcon className='w-4 h-4 text-text-tertiary' onClick={ | |||||
| && <div className='absolute z-10 top-6 right-6 w-5 h-5 rounded-2xl flex items-center justify-center hover:cursor-pointer hover:bg-state-base-hover'> | |||||
| <RiCloseLine className='w-4 h-4 text-text-tertiary' onClick={ | |||||
| (e) => { | (e) => { | ||||
| e.stopPropagation() | e.stopPropagation() | ||||
| onClose() | onClose() |
| import type { FC } from 'react' | import type { FC } from 'react' | ||||
| import React, { Fragment, useEffect, useState } from 'react' | import React, { Fragment, useEffect, useState } from 'react' | ||||
| import { Combobox, Listbox, Transition } from '@headlessui/react' | import { Combobox, Listbox, Transition } from '@headlessui/react' | ||||
| import { CheckIcon, ChevronDownIcon, ChevronUpIcon, XMarkIcon } from '@heroicons/react/20/solid' | |||||
| import { ChevronDownIcon, ChevronUpIcon, XMarkIcon } from '@heroicons/react/20/solid' | |||||
| import { RiCheckLine } from '@remixicon/react' | |||||
| import { useTranslation } from 'react-i18next' | import { useTranslation } from 'react-i18next' | ||||
| import classNames from '@/utils/classnames' | import classNames from '@/utils/classnames' | ||||
| import { | import { | ||||
| 'absolute inset-y-0 right-0 flex items-center pr-4 text-gray-700', | 'absolute inset-y-0 right-0 flex items-center pr-4 text-gray-700', | ||||
| )} | )} | ||||
| > | > | ||||
| <CheckIcon className="h-5 w-5" aria-hidden="true" /> | |||||
| <RiCheckLine className="h-4 w-4" aria-hidden="true" /> | |||||
| </span> | </span> | ||||
| )} | )} | ||||
| </> | </> | ||||
| <div className={classNames('group/simple-select relative h-9', wrapperClassName)}> | <div className={classNames('group/simple-select relative h-9', wrapperClassName)}> | ||||
| {renderTrigger && <Listbox.Button className='w-full'>{renderTrigger(selectedItem)}</Listbox.Button>} | {renderTrigger && <Listbox.Button className='w-full'>{renderTrigger(selectedItem)}</Listbox.Button>} | ||||
| {!renderTrigger && ( | {!renderTrigger && ( | ||||
| <Listbox.Button className={classNames(`flex items-center w-full h-full rounded-lg border-0 bg-gray-100 pl-3 pr-10 sm:text-sm sm:leading-6 focus-visible:outline-none focus-visible:bg-gray-200 group-hover/simple-select:bg-state-base-hover-alt ${disabled ? 'cursor-not-allowed' : 'cursor-pointer'}`, className)}> | |||||
| <Listbox.Button className={classNames(`flex items-center w-full h-full rounded-lg border-0 bg-components-input-bg-normal pl-3 pr-10 sm:text-sm sm:leading-6 focus-visible:outline-none focus-visible:bg-state-base-hover-alt group-hover/simple-select:bg-state-base-hover-alt ${disabled ? 'cursor-not-allowed' : 'cursor-pointer'}`, className)}> | |||||
| <span className={classNames('block truncate text-left system-sm-regular text-components-input-text-filled', !selectedItem?.name && 'text-components-input-text-placeholder')}>{selectedItem?.name ?? localPlaceholder}</span> | <span className={classNames('block truncate text-left system-sm-regular text-components-input-text-filled', !selectedItem?.name && 'text-components-input-text-placeholder')}>{selectedItem?.name ?? localPlaceholder}</span> | ||||
| <span className="absolute inset-y-0 right-0 flex items-center pr-2"> | <span className="absolute inset-y-0 right-0 flex items-center pr-2"> | ||||
| {(selectedItem && !notClearable) | {(selectedItem && !notClearable) | ||||
| leaveTo="opacity-0" | leaveTo="opacity-0" | ||||
| > | > | ||||
| <Listbox.Options className={classNames('absolute z-10 mt-1 px-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg border-gray-200 border-[0.5px] focus:outline-none sm:text-sm', optionWrapClassName)}> | |||||
| <Listbox.Options className={classNames('absolute z-10 mt-1 px-1 max-h-60 w-full overflow-auto rounded-md bg-components-panel-bg-blur py-1 text-base shadow-lg border-components-panel-border border-[0.5px] focus:outline-none sm:text-sm', optionWrapClassName)}> | |||||
| {items.map((item: Item) => ( | {items.map((item: Item) => ( | ||||
| <Listbox.Option | <Listbox.Option | ||||
| key={item.value} | key={item.value} | ||||
| className={({ active }) => | className={({ active }) => | ||||
| classNames( | classNames( | ||||
| `relative cursor-pointer select-none py-2 pl-3 pr-9 rounded-lg hover:bg-gray-100 text-gray-700 ${active ? 'bg-gray-100' : ''}`, | |||||
| 'relative cursor-pointer select-none py-2 pl-3 pr-9 rounded-lg hover:bg-state-base-hover text-text-secondary', | |||||
| optionClassName, | optionClassName, | ||||
| ) | ) | ||||
| } | } | ||||
| {selected && !hideChecked && ( | {selected && !hideChecked && ( | ||||
| <span | <span | ||||
| className={classNames( | className={classNames( | ||||
| 'absolute inset-y-0 right-0 flex items-center pr-4 text-gray-700', | |||||
| 'absolute inset-y-0 right-0 flex items-center pr-4 text-text-accent', | |||||
| )} | )} | ||||
| > | > | ||||
| <CheckIcon className="h-5 w-5" aria-hidden="true" /> | |||||
| <RiCheckLine className="h-4 w-4" aria-hidden="true" /> | |||||
| </span> | </span> | ||||
| )} | )} | ||||
| </>)} | </>)} | ||||
| {item.name} | {item.name} | ||||
| </span> | </span> | ||||
| {!hideChecked && item.value === value && ( | {!hideChecked && item.value === value && ( | ||||
| <CheckIcon className='shrink-0 h-4 w-4 text-text-accent' /> | |||||
| <RiCheckLine className='shrink-0 h-4 w-4 text-text-accent' /> | |||||
| )} | )} | ||||
| </div> | </div> | ||||
| ))} | ))} |
| import { Fragment, useState } from 'react' | import { Fragment, useState } from 'react' | ||||
| import { useRouter } from 'next/navigation' | import { useRouter } from 'next/navigation' | ||||
| import { useContext } from 'use-context-selector' | import { useContext } from 'use-context-selector' | ||||
| import { RiArrowDownSLine } from '@remixicon/react' | |||||
| import { RiArrowDownSLine, RiLogoutBoxRLine } from '@remixicon/react' | |||||
| import Link from 'next/link' | import Link from 'next/link' | ||||
| import { Menu, Transition } from '@headlessui/react' | import { Menu, Transition } from '@headlessui/react' | ||||
| import Indicator from '../indicator' | import Indicator from '../indicator' | ||||
| import { logout } from '@/service/common' | import { logout } from '@/service/common' | ||||
| import { useAppContext } from '@/context/app-context' | import { useAppContext } from '@/context/app-context' | ||||
| import { ArrowUpRight } from '@/app/components/base/icons/src/vender/line/arrows' | import { ArrowUpRight } from '@/app/components/base/icons/src/vender/line/arrows' | ||||
| import { LogOut01 } from '@/app/components/base/icons/src/vender/line/general' | |||||
| import { useModalContext } from '@/context/modal-context' | import { useModalContext } from '@/context/modal-context' | ||||
| import { LanguagesSupported } from '@/i18n/language' | import { LanguagesSupported } from '@/i18n/language' | ||||
| import { useProviderContext } from '@/context/provider-context' | import { useProviderContext } from '@/context/provider-context' | ||||
| export default function AppSelector({ isMobile }: IAppSelector) { | export default function AppSelector({ isMobile }: IAppSelector) { | ||||
| const itemClassName = ` | const itemClassName = ` | ||||
| flex items-center w-full h-9 px-3 text-gray-700 text-[14px] | |||||
| rounded-lg font-normal hover:bg-gray-50 cursor-pointer | |||||
| flex items-center w-full h-9 px-3 text-text-secondary system-md-regular | |||||
| rounded-lg hover:bg-state-base-hover cursor-pointer | |||||
| ` | ` | ||||
| const router = useRouter() | const router = useRouter() | ||||
| const [aboutVisible, setAboutVisible] = useState(false) | const [aboutVisible, setAboutVisible] = useState(false) | ||||
| <Menu.Items | <Menu.Items | ||||
| className=" | className=" | ||||
| absolute right-0 mt-1.5 w-60 max-w-80 | absolute right-0 mt-1.5 w-60 max-w-80 | ||||
| divide-y divide-gray-100 origin-top-right rounded-lg bg-white | |||||
| divide-y divide-divider-subtle origin-top-right rounded-lg bg-components-panel-bg-blur | |||||
| shadow-lg | shadow-lg | ||||
| " | " | ||||
| > | > | ||||
| <div className='flex flex-nowrap items-center px-4 py-[13px]'> | <div className='flex flex-nowrap items-center px-4 py-[13px]'> | ||||
| <Avatar name={userProfile.name} size={36} className='mr-3' /> | <Avatar name={userProfile.name} size={36} className='mr-3' /> | ||||
| <div className='grow'> | <div className='grow'> | ||||
| <div className='leading-5 font-normal text-[14px] text-gray-800 break-all'>{userProfile.name}</div> | |||||
| <div className='leading-[18px] text-xs font-normal text-gray-500 break-all'>{userProfile.email}</div> | |||||
| <div className='system-md-medium text-text-primary break-all'>{userProfile.name}</div> | |||||
| <div className='system-xs-regular text-text-tertiary break-all'>{userProfile.email}</div> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </Menu.Item> | </Menu.Item> | ||||
| <div className='px-1 py-1'> | <div className='px-1 py-1'> | ||||
| <div className='mt-2 px-3 text-xs font-medium text-gray-500'>{t('common.userProfile.workspace')}</div> | |||||
| <div className='mt-2 px-3 text-xs font-medium text-text-tertiary'>{t('common.userProfile.workspace')}</div> | |||||
| <WorkplaceSelector /> | <WorkplaceSelector /> | ||||
| </div> | </div> | ||||
| <div className="px-1 py-1"> | <div className="px-1 py-1"> | ||||
| href='/account' | href='/account' | ||||
| target='_self' rel='noopener noreferrer'> | target='_self' rel='noopener noreferrer'> | ||||
| <div>{t('common.account.account')}</div> | <div>{t('common.account.account')}</div> | ||||
| <ArrowUpRight className='hidden w-[14px] h-[14px] text-gray-500 group-hover:flex' /> | |||||
| <ArrowUpRight className='hidden w-[14px] h-[14px] text-text-tertiary group-hover:flex' /> | |||||
| </Link> | </Link> | ||||
| </Menu.Item> | </Menu.Item> | ||||
| <Menu.Item> | <Menu.Item> | ||||
| href={mailToSupport(userProfile.email, plan.type, langeniusVersionInfo.current_version)} | href={mailToSupport(userProfile.email, plan.type, langeniusVersionInfo.current_version)} | ||||
| target='_blank' rel='noopener noreferrer'> | target='_blank' rel='noopener noreferrer'> | ||||
| <div>{t('common.userProfile.emailSupport')}</div> | <div>{t('common.userProfile.emailSupport')}</div> | ||||
| <ArrowUpRight className='hidden w-[14px] h-[14px] text-gray-500 group-hover:flex' /> | |||||
| <ArrowUpRight className='hidden w-[14px] h-[14px] text-text-tertiary group-hover:flex' /> | |||||
| </a> | </a> | ||||
| </Menu.Item>} | </Menu.Item>} | ||||
| <Menu.Item> | <Menu.Item> | ||||
| href='https://github.com/langgenius/dify/discussions/categories/feedbacks' | href='https://github.com/langgenius/dify/discussions/categories/feedbacks' | ||||
| target='_blank' rel='noopener noreferrer'> | target='_blank' rel='noopener noreferrer'> | ||||
| <div>{t('common.userProfile.communityFeedback')}</div> | <div>{t('common.userProfile.communityFeedback')}</div> | ||||
| <ArrowUpRight className='hidden w-[14px] h-[14px] text-gray-500 group-hover:flex' /> | |||||
| <ArrowUpRight className='hidden w-[14px] h-[14px] text-text-tertiary group-hover:flex' /> | |||||
| </Link> | </Link> | ||||
| </Menu.Item> | </Menu.Item> | ||||
| <Menu.Item> | <Menu.Item> | ||||
| href='https://discord.gg/5AEfbxcd9k' | href='https://discord.gg/5AEfbxcd9k' | ||||
| target='_blank' rel='noopener noreferrer'> | target='_blank' rel='noopener noreferrer'> | ||||
| <div>{t('common.userProfile.community')}</div> | <div>{t('common.userProfile.community')}</div> | ||||
| <ArrowUpRight className='hidden w-[14px] h-[14px] text-gray-500 group-hover:flex' /> | |||||
| <ArrowUpRight className='hidden w-[14px] h-[14px] text-text-tertiary group-hover:flex' /> | |||||
| </Link> | </Link> | ||||
| </Menu.Item> | </Menu.Item> | ||||
| <Menu.Item> | <Menu.Item> | ||||
| } | } | ||||
| target='_blank' rel='noopener noreferrer'> | target='_blank' rel='noopener noreferrer'> | ||||
| <div>{t('common.userProfile.helpCenter')}</div> | <div>{t('common.userProfile.helpCenter')}</div> | ||||
| <ArrowUpRight className='hidden w-[14px] h-[14px] text-gray-500 group-hover:flex' /> | |||||
| <ArrowUpRight className='hidden w-[14px] h-[14px] text-text-tertiary group-hover:flex' /> | |||||
| </Link> | </Link> | ||||
| </Menu.Item> | </Menu.Item> | ||||
| <Menu.Item> | <Menu.Item> | ||||
| href='https://roadmap.dify.ai' | href='https://roadmap.dify.ai' | ||||
| target='_blank' rel='noopener noreferrer'> | target='_blank' rel='noopener noreferrer'> | ||||
| <div>{t('common.userProfile.roadmap')}</div> | <div>{t('common.userProfile.roadmap')}</div> | ||||
| <ArrowUpRight className='hidden w-[14px] h-[14px] text-gray-500 group-hover:flex' /> | |||||
| <ArrowUpRight className='hidden w-[14px] h-[14px] text-text-tertiary group-hover:flex' /> | |||||
| </Link> | </Link> | ||||
| </Menu.Item> | </Menu.Item> | ||||
| { | { | ||||
| <div className={classNames(itemClassName, 'justify-between')} onClick={() => setAboutVisible(true)}> | <div className={classNames(itemClassName, 'justify-between')} onClick={() => setAboutVisible(true)}> | ||||
| <div>{t('common.userProfile.about')}</div> | <div>{t('common.userProfile.about')}</div> | ||||
| <div className='flex items-center'> | <div className='flex items-center'> | ||||
| <div className='mr-2 text-xs font-normal text-gray-500'>{langeniusVersionInfo.current_version}</div> | |||||
| <div className='mr-2 system-xs-regular text-text-tertiary'>{langeniusVersionInfo.current_version}</div> | |||||
| <Indicator color={langeniusVersionInfo.current_version === langeniusVersionInfo.latest_version ? 'green' : 'orange'} /> | <Indicator color={langeniusVersionInfo.current_version === langeniusVersionInfo.latest_version ? 'green' : 'orange'} /> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <Menu.Item> | <Menu.Item> | ||||
| <div className='p-1' onClick={() => handleLogout()}> | <div className='p-1' onClick={() => handleLogout()}> | ||||
| <div | <div | ||||
| className='flex items-center justify-between h-9 px-3 rounded-lg cursor-pointer group hover:bg-gray-50' | |||||
| className='flex items-center justify-between h-9 px-3 rounded-lg cursor-pointer group hover:bg-state-base-hover' | |||||
| > | > | ||||
| <div className='font-normal text-[14px] text-gray-700'>{t('common.userProfile.logout')}</div> | |||||
| <LogOut01 className='hidden w-[14px] h-[14px] text-gray-500 group-hover:flex' /> | |||||
| <div className='system-md-regular text-text-secondary'>{t('common.userProfile.logout')}</div> | |||||
| <RiLogoutBoxRLine className='hidden w-4 h-4 text-text-tertiary group-hover:flex' /> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </Menu.Item> | </Menu.Item> |
| const toggle = () => setOpen(!open) | const toggle = () => setOpen(!open) | ||||
| return ( | return ( | ||||
| <div className={classNames('border border-gray-200 bg-gray-50 rounded-lg', wrapperClassName)}> | |||||
| <div className='flex items-center justify-between leading-[18px] px-3 py-2 text-xs font-medium text-gray-800 cursor-pointer' onClick={toggle}> | |||||
| <div className={classNames('bg-background-section-burn rounded-xl', wrapperClassName)}> | |||||
| <div className='flex items-center justify-between leading-[18px] px-3 py-2 text-xs font-medium text-text-secondary cursor-pointer' onClick={toggle}> | |||||
| {title} | {title} | ||||
| { | { | ||||
| open | open | ||||
| ? <ChevronDownIcon className='w-3 h-3 text-gray-400' /> | |||||
| : <ChevronRightIcon className='w-3 h-3 text-gray-400' /> | |||||
| ? <ChevronDownIcon className='w-3 h-3 text-components-button-tertiary-text' /> | |||||
| : <ChevronRightIcon className='w-3 h-3 text-components-button-tertiary-text' /> | |||||
| } | } | ||||
| </div> | </div> | ||||
| { | { | ||||
| open && ( | open && ( | ||||
| <div className='py-2 border-t border-t-gray-100'> | |||||
| <div className='py-1 mb-1 mx-1 border-t border-divider-subtle rounded-lg bg-components-panel-on-panel-item-bg'> | |||||
| { | { | ||||
| items.map(item => ( | items.map(item => ( | ||||
| <div key={item.key} onClick={() => onSelect && onSelect(item)}> | <div key={item.key} onClick={() => onSelect && onSelect(item)}> |
| return ( | return ( | ||||
| <div className='mb-8'> | <div className='mb-8'> | ||||
| <div className='mb-2 text-sm font-medium text-gray-900'>{t('common.dataSource.add')}</div> | |||||
| <DataSourceNotion workspaces={notionWorkspaces} /> | <DataSourceNotion workspaces={notionWorkspaces} /> | ||||
| <DataSourceWebsite provider={DataSourceProvider.jinaReader} /> | <DataSourceWebsite provider={DataSourceProvider.jinaReader} /> | ||||
| <DataSourceWebsite provider={DataSourceProvider.fireCrawl} /> | <DataSourceWebsite provider={DataSourceProvider.fireCrawl} /> |
| const onChangeAuthorizedPage = notionActions?.onChangeAuthorizedPage || function () { } | const onChangeAuthorizedPage = notionActions?.onChangeAuthorizedPage || function () { } | ||||
| return ( | return ( | ||||
| <div className={cn(s['workspace-item'], 'flex items-center mb-1 py-1 pr-1 bg-white rounded-lg')} key={payload.id}> | |||||
| <div className={cn(s['workspace-item'], 'flex items-center mb-1 py-1 pr-1 bg-components-panel-on-panel-item-bg rounded-lg')} key={payload.id}> | |||||
| <payload.logo className='ml-3 mr-1.5' /> | <payload.logo className='ml-3 mr-1.5' /> | ||||
| <div className='grow py-[7px] leading-[18px] text-[13px] font-medium text-gray-700 truncate' title={payload.name}>{payload.name}</div> | |||||
| <div className='grow py-[7px] system-sm-medium text-text-secondary truncate' title={payload.name}>{payload.name}</div> | |||||
| { | { | ||||
| payload.isActive | payload.isActive | ||||
| ? <Indicator className='shrink-0 mr-[6px]' /> | |||||
| ? <Indicator className='shrink-0 mr-[6px]' color='green' /> | |||||
| : <Indicator className='shrink-0 mr-[6px]' color='yellow' /> | : <Indicator className='shrink-0 mr-[6px]' color='yellow' /> | ||||
| } | } | ||||
| <div className='shrink-0 mr-3 text-xs font-medium uppercase'> | |||||
| <div className={`shrink-0 mr-3 text-xs font-medium uppercase ${payload.isActive ? 'text-util-colors-green-green-600' : 'text-util-colors-warning-warning-600'}`}> | |||||
| { | { | ||||
| payload.isActive | payload.isActive | ||||
| ? t(isNotion ? 'common.dataSource.notion.connected' : 'common.dataSource.website.active') | ? t(isNotion ? 'common.dataSource.notion.connected' : 'common.dataSource.website.active') | ||||
| : t(isNotion ? 'common.dataSource.notion.disconnected' : 'common.dataSource.website.inactive') | : t(isNotion ? 'common.dataSource.notion.disconnected' : 'common.dataSource.website.inactive') | ||||
| } | } | ||||
| </div> | </div> | ||||
| <div className='mr-2 w-[1px] h-3 bg-gray-100' /> | |||||
| <div className='mr-2 w-[1px] h-3 bg-divider-regular' /> | |||||
| {isNotion && ( | {isNotion && ( | ||||
| <Operate payload={{ | <Operate payload={{ | ||||
| id: payload.id, | id: payload.id, | ||||
| { | { | ||||
| isWebsite && !readOnly && ( | isWebsite && !readOnly && ( | ||||
| <div className='p-2 text-gray-500 cursor-pointer rounded-md hover:bg-black/5' onClick={onRemove} > | |||||
| <RiDeleteBinLine className='w-4 h-4 ' /> | |||||
| <div className='p-2 text-text-tertiary cursor-pointer rounded-md hover:bg-black/5' onClick={onRemove} > | |||||
| <RiDeleteBinLine className='w-4 h-4' /> | |||||
| </div> | </div> | ||||
| ) | ) | ||||
| } | } |
| import type { FC } from 'react' | import type { FC } from 'react' | ||||
| import React from 'react' | import React from 'react' | ||||
| import { useTranslation } from 'react-i18next' | import { useTranslation } from 'react-i18next' | ||||
| import { PlusIcon } from '@heroicons/react/24/solid' | |||||
| import { RiAddLine } from '@remixicon/react' | |||||
| import type { ConfigItemType } from './config-item' | import type { ConfigItemType } from './config-item' | ||||
| import ConfigItem from './config-item' | import ConfigItem from './config-item' | ||||
| const isWebsite = type === DataSourceType.website | const isWebsite = type === DataSourceType.website | ||||
| return ( | return ( | ||||
| <div className='mb-2 border-[0.5px] border-gray-200 bg-gray-50 rounded-xl'> | |||||
| <div className='mb-2 bg-background-section-burn rounded-xl'> | |||||
| <div className='flex items-center px-3 py-[9px]'> | <div className='flex items-center px-3 py-[9px]'> | ||||
| <div className={cn(s[`${type}-icon`], 'w-8 h-8 mr-3 border border-gray-100 rounded-lg')} /> | |||||
| <div className={cn(s[`${type}-icon`], 'w-8 h-8 mr-3 border border-divider-subtle rounded-lg bg-background-default')} /> | |||||
| <div className='grow'> | <div className='grow'> | ||||
| <div className='flex items-center h-5'> | <div className='flex items-center h-5'> | ||||
| <div className='text-sm font-medium text-gray-800'>{t(`common.dataSource.${type}.title`)}</div> | |||||
| <div className='text-sm font-medium text-text-primary'>{t(`common.dataSource.${type}.title`)}</div> | |||||
| {isWebsite && ( | {isWebsite && ( | ||||
| <div className='ml-1 leading-[18px] px-1.5 rounded-md bg-white border border-gray-100 text-xs font-medium text-gray-700'> | <div className='ml-1 leading-[18px] px-1.5 rounded-md bg-white border border-gray-100 text-xs font-medium text-gray-700'> | ||||
| <span className='text-gray-500'>{t('common.dataSource.website.with')}</span> { provider === DataSourceProvider.fireCrawl ? '🔥 Firecrawl' : 'Jina Reader'} | <span className='text-gray-500'>{t('common.dataSource.website.with')}</span> { provider === DataSourceProvider.fireCrawl ? '🔥 Firecrawl' : 'Jina Reader'} | ||||
| </div> | </div> | ||||
| { | { | ||||
| !isConfigured && ( | !isConfigured && ( | ||||
| <div className='leading-5 text-xs text-gray-500'> | |||||
| <div className='system-xs-medium text-text-tertiary'> | |||||
| {t(`common.dataSource.${type}.description`)} | {t(`common.dataSource.${type}.description`)} | ||||
| </div> | </div> | ||||
| ) | ) | ||||
| <> | <> | ||||
| {isSupportList && <div | {isSupportList && <div | ||||
| className={ | className={ | ||||
| `flex items-center px-3 py-1 min-h-7 bg-white border-[0.5px] border-gray-200 text-xs font-medium text-primary-600 rounded-md | |||||
| `flex items-center px-3 py-1 min-h-7 bg-components-button-secondary-bg border-[0.5px] border-components-button-secondary-border system-sm-medium text-components-button-secondary-accent-text rounded-md | |||||
| ${!readOnly ? 'cursor-pointer' : 'grayscale opacity-50 cursor-default'}` | ${!readOnly ? 'cursor-pointer' : 'grayscale opacity-50 cursor-default'}` | ||||
| } | } | ||||
| onClick={onConfigure} | onClick={onConfigure} | ||||
| > | > | ||||
| <PlusIcon className='w-[14px] h-[14px] mr-[5px]' /> | |||||
| {t('common.dataSource.notion.addWorkspace')} | |||||
| <RiAddLine className='w-4 h-4 text-components-button-secondary-accent-text mr-[5px]' /> | |||||
| {t('common.dataSource.connect')} | |||||
| </div>} | </div>} | ||||
| </> | </> | ||||
| ) | ) | ||||
| {isWebsite && !isConfigured && ( | {isWebsite && !isConfigured && ( | ||||
| <div | <div | ||||
| className={ | className={ | ||||
| `flex items-center ml-3 px-3 h-7 bg-white border border-gray-200 | |||||
| rounded-md text-xs font-medium text-gray-700 | |||||
| `flex items-center ml-3 px-3 h-7 bg-components-button-secondary-bg border-[0.5px] border-components-button-secondary-border | |||||
| rounded-md text-xs font-medium text-components-button-secondary-accent-text | |||||
| ${!readOnly ? 'cursor-pointer' : 'grayscale opacity-50 cursor-default'}` | ${!readOnly ? 'cursor-pointer' : 'grayscale opacity-50 cursor-default'}` | ||||
| } | } | ||||
| onClick={!readOnly ? onConfigure : undefined} | onClick={!readOnly ? onConfigure : undefined} | ||||
| isConfigured && ( | isConfigured && ( | ||||
| <> | <> | ||||
| <div className='flex items-center px-3 h-[18px]'> | <div className='flex items-center px-3 h-[18px]'> | ||||
| <div className='text-xs font-medium text-gray-500'> | |||||
| <div className='system-xs-medium text-text-tertiary'> | |||||
| {isNotion ? t('common.dataSource.notion.connectedWorkspace') : t('common.dataSource.website.configuredCrawlers')} | {isNotion ? t('common.dataSource.notion.connectedWorkspace') : t('common.dataSource.website.configuredCrawlers')} | ||||
| </div> | </div> | ||||
| <div className='grow ml-3 border-t border-t-gray-100' /> | |||||
| <div className='grow ml-3 border-t border-t-divider-subtle' /> | |||||
| </div> | </div> | ||||
| <div className='px-3 pt-2 pb-3'> | <div className='px-3 pt-2 pb-3'> | ||||
| { | { |
| wrapperClassName='pt-[60px]' | wrapperClassName='pt-[60px]' | ||||
| > | > | ||||
| <div className='flex'> | <div className='flex'> | ||||
| <div className='w-[44px] sm:w-[200px] px-[1px] py-4 sm:p-4 border border-gray-100 shrink-0 sm:shrink-1 flex flex-col items-center sm:items-start'> | |||||
| <div className='mb-8 ml-0 sm:ml-2 text-sm sm:text-base font-medium leading-6 text-gray-900'>{t('common.userProfile.settings')}</div> | |||||
| <div className='w-[44px] sm:w-[200px] px-[1px] py-4 sm:p-4 border border-divider-burn shrink-0 sm:shrink-1 flex flex-col items-center sm:items-start'> | |||||
| <div className='mb-8 ml-0 sm:ml-2 sm:text-base title-2xl-semi-bold text-text-primary'>{t('common.userProfile.settings')}</div> | |||||
| <div className='w-full'> | <div className='w-full'> | ||||
| { | { | ||||
| menuItems.map(menuItem => ( | menuItems.map(menuItem => ( | ||||
| <div key={menuItem.key} className='mb-4'> | <div key={menuItem.key} className='mb-4'> | ||||
| {!isCurrentWorkspaceDatasetOperator && ( | {!isCurrentWorkspaceDatasetOperator && ( | ||||
| <div className='px-2 mb-[6px] text-[10px] sm:text-xs font-medium text-gray-500'>{menuItem.name}</div> | |||||
| <div className='px-2 mb-[6px] sm:text-xs system-xs-medium-uppercase text-text-tertiary'>{menuItem.name}</div> | |||||
| )} | )} | ||||
| <div> | <div> | ||||
| { | { | ||||
| key={item.key} | key={item.key} | ||||
| className={` | className={` | ||||
| flex items-center h-[37px] mb-[2px] text-sm cursor-pointer rounded-lg | flex items-center h-[37px] mb-[2px] text-sm cursor-pointer rounded-lg | ||||
| ${activeMenu === item.key ? 'font-semibold text-primary-600 bg-primary-50' : 'font-light text-gray-700'} | |||||
| ${activeMenu === item.key ? 'system-sm-semibold text-components-menu-item-text-active bg-state-base-active' : 'system-sm-medium text-components-menu-item-text'} | |||||
| `} | `} | ||||
| title={item.name} | title={item.name} | ||||
| onClick={() => setActiveMenu(item.key)} | onClick={() => setActiveMenu(item.key)} | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div ref={scrollRef} className='relative w-[824px] h-[720px] pb-4 overflow-y-auto'> | <div ref={scrollRef} className='relative w-[824px] h-[720px] pb-4 overflow-y-auto'> | ||||
| <div className={cn('sticky top-0 px-6 py-4 flex items-center h-14 mb-4 bg-white text-base font-medium text-gray-900 z-20', scrolled && scrolledClassName)}> | |||||
| <div className={cn('sticky top-0 px-6 py-4 flex items-center h-14 mb-4 bg-components-panel-bg title-2xl-semi-bold text-text-primary z-20', scrolled && scrolledClassName)}> | |||||
| <div className='shrink-0'>{activeItem?.name}</div> | <div className='shrink-0'>{activeItem?.name}</div> | ||||
| { | { | ||||
| activeItem?.description && ( | activeItem?.description && ( | ||||
| ) | ) | ||||
| } | } | ||||
| <div className='grow flex justify-end'> | <div className='grow flex justify-end'> | ||||
| <div className='flex items-center justify-center -mr-4 w-6 h-6 cursor-pointer' onClick={onCancel}> | |||||
| <RiCloseLine className='w-4 h-4 text-gray-400' /> | |||||
| <div className='z-[10] flex items-center justify-center -mr-4 p-2 cursor-pointer rounded-[10px] hover:bg-components-button-tertiary-bg' onClick={onCancel}> | |||||
| <RiCloseLine className='w-5 h-5 text-components-button-tertiary-text' /> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> |
| import { languages } from '@/i18n/language' | import { languages } from '@/i18n/language' | ||||
| const titleClassName = ` | const titleClassName = ` | ||||
| mb-2 text-sm font-medium text-gray-900 | |||||
| mb-2 system-sm-semibold text-text-secondary | |||||
| ` | ` | ||||
| export default function LanguagePage() { | export default function LanguagePage() { |
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div className='overflow-visible lg:overflow-visible'> | <div className='overflow-visible lg:overflow-visible'> | ||||
| <div className='flex items-center py-[7px] border-b border-gray-200 min-w-[480px]'> | |||||
| <div className='grow px-3 text-xs font-medium text-gray-500'>{t('common.members.name')}</div> | |||||
| <div className='shrink-0 w-[104px] text-xs font-medium text-gray-500'>{t('common.members.lastActive')}</div> | |||||
| <div className='shrink-0 w-[96px] px-3 text-xs font-medium text-gray-500'>{t('common.members.role')}</div> | |||||
| <div className='flex items-center py-[7px] border-b border-divider-regular min-w-[480px]'> | |||||
| <div className='grow px-3 system-xs-medium-uppercase text-text-tertiary'>{t('common.members.name')}</div> | |||||
| <div className='shrink-0 w-[104px] system-xs-medium-uppercase text-text-tertiary'>{t('common.members.lastActive')}</div> | |||||
| <div className='shrink-0 w-[96px] px-3 system-xs-medium-uppercase text-text-tertiary'>{t('common.members.role')}</div> | |||||
| </div> | </div> | ||||
| <div className='min-w-[480px] relative'> | <div className='min-w-[480px] relative'> | ||||
| { | { | ||||
| accounts.map(account => ( | accounts.map(account => ( | ||||
| <div key={account.id} className='flex border-b border-gray-100'> | |||||
| <div key={account.id} className='flex border-b border-divider-subtle'> | |||||
| <div className='grow flex items-center py-2 px-3'> | <div className='grow flex items-center py-2 px-3'> | ||||
| <Avatar size={24} className='mr-2' name={account.name} /> | <Avatar size={24} className='mr-2' name={account.name} /> | ||||
| <div className=''> | <div className=''> | ||||
| <div className='text-[13px] font-medium text-gray-700 leading-[18px]'> | |||||
| <div className='text-text-secondary system-sm-medium'> | |||||
| {account.name} | {account.name} | ||||
| {account.status === 'pending' && <span className='ml-1 text-xs text-[#DC6803]'>{t('common.members.pending')}</span>} | |||||
| {userProfile.email === account.email && <span className='text-xs text-gray-500'>{t('common.members.you')}</span>} | |||||
| {account.status === 'pending' && <span className='ml-1 system-xs-regular text-[#DC6803]'>{t('common.members.pending')}</span>} | |||||
| {userProfile.email === account.email && <span className='system-xs-regular text-text-tertiary'>{t('common.members.you')}</span>} | |||||
| </div> | </div> | ||||
| <div className='text-xs text-gray-500 leading-[18px]'>{account.email}</div> | |||||
| <div className='text-text-tertiary system-xs-regular'>{account.email}</div> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div className='shrink-0 flex items-center w-[104px] py-2 text-[13px] text-gray-700'>{dayjs(Number((account.last_active_at || account.created_at)) * 1000).locale(locale === 'zh-Hans' ? 'zh-cn' : 'en').fromNow()}</div> | |||||
| <div className='shrink-0 flex items-center w-[104px] py-2 system-xs-regular text-text-secondary'>{dayjs(Number((account.last_active_at || account.created_at)) * 1000).locale(locale === 'zh-Hans' ? 'zh-cn' : 'en').fromNow()}</div> | |||||
| <div className='shrink-0 w-[96px] flex items-center'> | <div className='shrink-0 w-[96px] flex items-center'> | ||||
| { | { | ||||
| ((isCurrentWorkspaceOwner && account.role !== 'owner') || (isCurrentWorkspaceManager && !['owner', 'admin'].includes(account.role))) | ((isCurrentWorkspaceOwner && account.role !== 'owner') || (isCurrentWorkspaceManager && !['owner', 'admin'].includes(account.role))) | ||||
| ? <Operation member={account} operatorRole={currentWorkspace.role} onOperate={mutate} /> | ? <Operation member={account} operatorRole={currentWorkspace.role} onOperate={mutate} /> | ||||
| : <div className='px-3 text-[13px] text-gray-700'>{RoleMap[account.role] || RoleMap.normal}</div> | |||||
| : <div className='px-3 system-xs-regular text-text-secondary'>{RoleMap[account.role] || RoleMap.normal}</div> | |||||
| } | } | ||||
| </div> | </div> | ||||
| </div> | </div> |
| children, | children, | ||||
| }: HeaderWrapperProps) => { | }: HeaderWrapperProps) => { | ||||
| const pathname = usePathname() | const pathname = usePathname() | ||||
| const isBordered = ['/apps', '/datasets', '/datasets/create', '/tools', '/account'].includes(pathname) | |||||
| const isBordered = ['/apps', '/datasets', '/datasets/create', '/tools'].includes(pathname) | |||||
| return ( | return ( | ||||
| <div className={classNames( | <div className={classNames( |
| // eslint-disable-next-line react-hooks/exhaustive-deps | // eslint-disable-next-line react-hooks/exhaustive-deps | ||||
| }, [selectedSegment]) | }, [selectedSegment]) | ||||
| return ( | return ( | ||||
| <div className='flex flex-1 items-center justify-between px-4'> | |||||
| <div className='flex flex-1 items-center justify-between px-4 bg-background-body'> | |||||
| <div className='flex items-center'> | <div className='flex items-center'> | ||||
| {isMobile && <div | {isMobile && <div | ||||
| className='flex items-center justify-center h-8 w-8 cursor-pointer' | className='flex items-center justify-center h-8 w-8 cursor-pointer' |
| } | } | ||||
| const BACKGROUND_MAP: ColorMap = { | const BACKGROUND_MAP: ColorMap = { | ||||
| green: 'bg-[#31C48D]', | |||||
| orange: 'bg-[#FF5A1F]', | |||||
| red: 'bg-[#F04438]', | |||||
| blue: 'bg-[#36BFFA]', | |||||
| green: 'bg-components-badge-status-light-success-bg', | |||||
| orange: 'bg-components-badge-status-light-warning-bg', | |||||
| red: 'bg-components-badge-status-light-error-bg', | |||||
| blue: 'bg-components-badge-status-light-normal-bg', | |||||
| yellow: 'bg-[#FDB022]', | yellow: 'bg-[#FDB022]', | ||||
| gray: 'bg-[#D0D5DD]', | |||||
| gray: 'bg-components-badge-status-light-disabled-bg', | |||||
| } | } | ||||
| const BORDER_MAP: ColorMap = { | const BORDER_MAP: ColorMap = { | ||||
| green: 'border-[#0E9F6E]', | |||||
| orange: 'border-[#D03801]', | |||||
| red: 'border-[#D92D20]', | |||||
| blue: 'border-[#0BA5EC]', | |||||
| green: 'border-components-badge-status-light-success-border-inner', | |||||
| orange: 'border-components-badge-status-light-warning-border-inner', | |||||
| red: 'border-components-badge-status-light-error-border-inner', | |||||
| blue: 'border-components-badge-status-light-normal-border-inner', | |||||
| yellow: 'border-[#F79009]', | yellow: 'border-[#F79009]', | ||||
| gray: 'border-[#98A2B3]', | |||||
| gray: 'border-components-badge-status-light-disabled-border-inner', | |||||
| } | } | ||||
| const SHADOW_MAP: ColorMap = { | const SHADOW_MAP: ColorMap = { | ||||
| green: 'shadow-[0_0_5px_-3px_rgba(14,159,110,0.1),0.5px_0.5px_3px_rgba(14,159,110,0.3),inset_1.5px_1.5px_0px_rgba(255,255,255,0.2)]', | green: 'shadow-[0_0_5px_-3px_rgba(14,159,110,0.1),0.5px_0.5px_3px_rgba(14,159,110,0.3),inset_1.5px_1.5px_0px_rgba(255,255,255,0.2)]', |
| html[data-theme="dark"] { | html[data-theme="dark"] { | ||||
| --color-chatbot-bg: linear-gradient(180deg, rgba(34, 34, 37, 0.90) 0%, rgba(29, 29, 32, 0.90) 90.48%); | |||||
| --color-chat-bubble-bg: linear-gradient(180deg, rgba(200, 206, 218, 0.08) 0%, rgba(200, 206, 218, 0.02) 100%); | |||||
| --color-workflow-process-bg: linear-gradient(90deg, rgba(24, 24, 27, 0.25) 0%, rgba(24, 24, 27, 0.04) 100%); | |||||
| --mask-top2bottom-gray-50-to-transparent:linear-gradient(180deg, rgba(24, 24, 27, 0.08) 0%, rgba(0, 0, 0, 0.00) 100%); | |||||
| } | |||||
| --color-chatbot-bg: linear-gradient( | |||||
| 180deg, | |||||
| rgba(34, 34, 37, 0.9) 0%, | |||||
| rgba(29, 29, 32, 0.9) 90.48% | |||||
| ); | |||||
| --color-chat-bubble-bg: linear-gradient( | |||||
| 180deg, | |||||
| rgba(200, 206, 218, 0.08) 0%, | |||||
| rgba(200, 206, 218, 0.02) 100% | |||||
| ); | |||||
| --color-workflow-process-bg: linear-gradient( | |||||
| 90deg, | |||||
| rgba(24, 24, 27, 0.25) 0%, | |||||
| rgba(24, 24, 27, 0.04) 100% | |||||
| ); | |||||
| --color-account-teams-bg: linear-gradient( | |||||
| 271deg, | |||||
| rgba(34, 34, 37, 0.9) -0.1%, | |||||
| rgba(29, 29, 32, 0.9) 98.26% | |||||
| ); | |||||
| --mask-top2bottom-gray-50-to-transparent: linear-gradient( | |||||
| 180deg, | |||||
| rgba(24, 24, 27, 0.08) 0%, | |||||
| rgba(0, 0, 0, 0) 100% | |||||
| ); | |||||
| } |
| html[data-theme="light"] { | html[data-theme="light"] { | ||||
| --color-chatbot-bg: linear-gradient(180deg, rgba(249, 250, 251, 0.90) 0%, rgba(242, 244, 247, 0.90) 90.48%); | |||||
| --color-chat-bubble-bg: linear-gradient(180deg, #FFF 0%, rgba(255, 255, 255, 0.60) 100%); | |||||
| --color-workflow-process-bg: linear-gradient(90deg, rgba(200, 206, 218, 0.20) 0%, rgba(200, 206, 218, 0.04) 100%); | |||||
| --mask-top2bottom-gray-50-to-transparent: linear-gradient(180deg, rgba(200, 206, 218, 0.20) 0%, rgba(255, 255, 255, 0.00) 100%); | |||||
| } | |||||
| --color-chatbot-bg: linear-gradient( | |||||
| 180deg, | |||||
| rgba(249, 250, 251, 0.9) 0%, | |||||
| rgba(242, 244, 247, 0.9) 90.48% | |||||
| ); | |||||
| --color-chat-bubble-bg: linear-gradient( | |||||
| 180deg, | |||||
| #fff 0%, | |||||
| rgba(255, 255, 255, 0.6) 100% | |||||
| ); | |||||
| --color-workflow-process-bg: linear-gradient( | |||||
| 90deg, | |||||
| rgba(200, 206, 218, 0.2) 0%, | |||||
| rgba(200, 206, 218, 0.04) 100% | |||||
| ); | |||||
| --color-account-teams-bg: linear-gradient( | |||||
| 271deg, | |||||
| rgba(249, 250, 251, 0.9) -0.1%, | |||||
| rgba(242, 244, 247, 0.9) 98.26% | |||||
| ); | |||||
| --mask-top2bottom-gray-50-to-transparent: linear-gradient( | |||||
| 180deg, | |||||
| rgba(200, 206, 218, 0.2) 0%, | |||||
| rgba(255, 255, 255, 0) 100% | |||||
| ); | |||||
| } |
| 'background-default-burn': 'var(--color-background-default-burn)', | 'background-default-burn': 'var(--color-background-default-burn)', | ||||
| 'background-overlay-fullscreen': 'var(--color-background-overlay-fullscreen)', | 'background-overlay-fullscreen': 'var(--color-background-overlay-fullscreen)', | ||||
| 'background-default-lighter': 'var(--color-background-default-lighter)', | 'background-default-lighter': 'var(--color-background-default-lighter)', | ||||
| 'background-account-teams-bg': 'var(--color-account-teams-bg)', | |||||
| 'background-section': 'var(--color-background-section)', | 'background-section': 'var(--color-background-section)', | ||||
| 'background-interaction-from-bg-1': 'var(--color-background-interaction-from-bg-1)', | 'background-interaction-from-bg-1': 'var(--color-background-interaction-from-bg-1)', | ||||
| 'background-interaction-from-bg-2': 'var(--color-background-interaction-from-bg-2)', | 'background-interaction-from-bg-2': 'var(--color-background-interaction-from-bg-2)', |