mirror of
https://github.com/langgenius/dify.git
synced 2026-05-05 01:48:04 +08:00
Merge branch 'main' into feat/rag-pipeline
This commit is contained in:
@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'
|
||||
|
||||
import { useRouter, useSearchParams } from 'next/navigation'
|
||||
import { useContext, useContextSelector } from 'use-context-selector'
|
||||
import { RiArrowRightLine, RiCommandLine, RiCornerDownLeftLine, RiExchange2Fill } from '@remixicon/react'
|
||||
import { RiArrowRightLine, RiArrowRightSLine, RiCommandLine, RiCornerDownLeftLine, RiExchange2Fill } from '@remixicon/react'
|
||||
import Link from 'next/link'
|
||||
import { useDebounceFn, useKeyPress } from 'ahooks'
|
||||
import Image from 'next/image'
|
||||
@ -43,11 +43,12 @@ function CreateApp({ onClose, onSuccess, onCreateFromTemplate }: CreateAppProps)
|
||||
const { notify } = useContext(ToastContext)
|
||||
const mutateApps = useContextSelector(AppsContext, state => state.mutateApps)
|
||||
|
||||
const [appMode, setAppMode] = useState<AppMode>('chat')
|
||||
const [appMode, setAppMode] = useState<AppMode>('advanced-chat')
|
||||
const [appIcon, setAppIcon] = useState<AppIconSelection>({ type: 'emoji', icon: '🤖', background: '#FFEAD5' })
|
||||
const [showAppIconPicker, setShowAppIconPicker] = useState(false)
|
||||
const [name, setName] = useState('')
|
||||
const [description, setDescription] = useState('')
|
||||
const [isAppTypeExpanded, setIsAppTypeExpanded] = useState(false)
|
||||
|
||||
const { plan, enableBilling } = useProviderContext()
|
||||
const isAppsFull = (enableBilling && plan.usage.buildApps >= plan.total.buildApps)
|
||||
@ -116,57 +117,7 @@ function CreateApp({ onClose, onSuccess, onCreateFromTemplate }: CreateAppProps)
|
||||
</div>
|
||||
<div className='flex w-[660px] flex-col gap-4'>
|
||||
<div>
|
||||
<div className='mb-2'>
|
||||
<span className='system-2xs-medium-uppercase text-text-tertiary'>{t('app.newApp.forBeginners')}</span>
|
||||
</div>
|
||||
<div className='flex flex-row gap-2'>
|
||||
<AppTypeCard
|
||||
active={appMode === 'chat'}
|
||||
title={t('app.types.chatbot')}
|
||||
description={t('app.newApp.chatbotShortDescription')}
|
||||
icon={<div className='flex h-6 w-6 items-center justify-center rounded-md bg-components-icon-bg-blue-solid'>
|
||||
<ChatBot className='h-4 w-4 text-components-avatar-shape-fill-stop-100' />
|
||||
</div>}
|
||||
onClick={() => {
|
||||
setAppMode('chat')
|
||||
}} />
|
||||
<AppTypeCard
|
||||
active={appMode === 'agent-chat'}
|
||||
title={t('app.types.agent')}
|
||||
description={t('app.newApp.agentShortDescription')}
|
||||
icon={<div className='flex h-6 w-6 items-center justify-center rounded-md bg-components-icon-bg-violet-solid'>
|
||||
<Logic className='h-4 w-4 text-components-avatar-shape-fill-stop-100' />
|
||||
</div>}
|
||||
onClick={() => {
|
||||
setAppMode('agent-chat')
|
||||
}} />
|
||||
<AppTypeCard
|
||||
active={appMode === 'completion'}
|
||||
title={t('app.newApp.completeApp')}
|
||||
description={t('app.newApp.completionShortDescription')}
|
||||
icon={<div className='flex h-6 w-6 items-center justify-center rounded-md bg-components-icon-bg-teal-solid'>
|
||||
<ListSparkle className='h-4 w-4 text-components-avatar-shape-fill-stop-100' />
|
||||
</div>}
|
||||
onClick={() => {
|
||||
setAppMode('completion')
|
||||
}} />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className='mb-2'>
|
||||
<span className='system-2xs-medium-uppercase text-text-tertiary'>{t('app.newApp.forAdvanced')}</span>
|
||||
</div>
|
||||
<div className='flex flex-row gap-2'>
|
||||
<AppTypeCard
|
||||
active={appMode === 'advanced-chat'}
|
||||
title={t('app.types.advanced')}
|
||||
description={t('app.newApp.advancedShortDescription')}
|
||||
icon={<div className='flex h-6 w-6 items-center justify-center rounded-md bg-components-icon-bg-blue-light-solid'>
|
||||
<BubbleTextMod className='h-4 w-4 text-components-avatar-shape-fill-stop-100' />
|
||||
</div>}
|
||||
onClick={() => {
|
||||
setAppMode('advanced-chat')
|
||||
}} />
|
||||
<AppTypeCard
|
||||
active={appMode === 'workflow'}
|
||||
title={t('app.types.workflow')}
|
||||
@ -177,8 +128,63 @@ function CreateApp({ onClose, onSuccess, onCreateFromTemplate }: CreateAppProps)
|
||||
onClick={() => {
|
||||
setAppMode('workflow')
|
||||
}} />
|
||||
<AppTypeCard
|
||||
active={appMode === 'advanced-chat'}
|
||||
title={t('app.types.advanced')}
|
||||
description={t('app.newApp.advancedShortDescription')}
|
||||
icon={<div className='flex h-6 w-6 items-center justify-center rounded-md bg-components-icon-bg-blue-light-solid'>
|
||||
<BubbleTextMod className='h-4 w-4 text-components-avatar-shape-fill-stop-100' />
|
||||
</div>}
|
||||
onClick={() => {
|
||||
setAppMode('advanced-chat')
|
||||
}} />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className='mb-2 flex items-center'>
|
||||
<button
|
||||
className='flex cursor-pointer items-center border-0 bg-transparent p-0'
|
||||
onClick={() => setIsAppTypeExpanded(!isAppTypeExpanded)}
|
||||
>
|
||||
<span className='system-2xs-medium-uppercase text-text-tertiary'>{t('app.newApp.forBeginners')}</span>
|
||||
<RiArrowRightSLine className={`ml-1 h-4 w-4 text-text-tertiary transition-transform ${isAppTypeExpanded ? 'rotate-90' : ''}`} />
|
||||
</button>
|
||||
</div>
|
||||
{isAppTypeExpanded && (
|
||||
<div className='flex flex-row gap-2'>
|
||||
<AppTypeCard
|
||||
active={appMode === 'chat'}
|
||||
title={t('app.types.chatbot')}
|
||||
description={t('app.newApp.chatbotShortDescription')}
|
||||
icon={<div className='flex h-6 w-6 items-center justify-center rounded-md bg-components-icon-bg-blue-solid'>
|
||||
<ChatBot className='h-4 w-4 text-components-avatar-shape-fill-stop-100' />
|
||||
</div>}
|
||||
onClick={() => {
|
||||
setAppMode('chat')
|
||||
}} />
|
||||
<AppTypeCard
|
||||
active={appMode === 'agent-chat'}
|
||||
title={t('app.types.agent')}
|
||||
description={t('app.newApp.agentShortDescription')}
|
||||
icon={<div className='flex h-6 w-6 items-center justify-center rounded-md bg-components-icon-bg-violet-solid'>
|
||||
<Logic className='h-4 w-4 text-components-avatar-shape-fill-stop-100' />
|
||||
</div>}
|
||||
onClick={() => {
|
||||
setAppMode('agent-chat')
|
||||
}} />
|
||||
<AppTypeCard
|
||||
active={appMode === 'completion'}
|
||||
title={t('app.newApp.completeApp')}
|
||||
description={t('app.newApp.completionShortDescription')}
|
||||
icon={<div className='flex h-6 w-6 items-center justify-center rounded-md bg-components-icon-bg-teal-solid'>
|
||||
<ListSparkle className='h-4 w-4 text-components-avatar-shape-fill-stop-100' />
|
||||
</div>}
|
||||
onClick={() => {
|
||||
setAppMode('completion')
|
||||
}} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<Divider style={{ margin: 0 }} />
|
||||
<div className='flex items-center space-x-3'>
|
||||
<div className='flex-1'>
|
||||
|
||||
@ -93,7 +93,7 @@ const TagInput: FC<TagInputProps> = ({
|
||||
<div className={cn('group/tag-add mt-1 flex items-center gap-x-0.5', !isSpecialMode ? 'rounded-md border border-dashed border-divider-deep px-1.5' : '')}>
|
||||
{!isSpecialMode && !focused && <RiAddLine className='h-3.5 w-3.5 text-text-placeholder group-hover/tag-add:text-text-secondary' />}
|
||||
<AutosizeInput
|
||||
inputClassName={cn('appearance-none caret-[#295EFF] outline-none placeholder:text-text-placeholder group-hover/tag-add:placeholder:text-text-secondary', isSpecialMode ? 'bg-transparent' : '')}
|
||||
inputClassName={cn('appearance-none text-text-primary caret-[#295EFF] outline-none placeholder:text-text-placeholder group-hover/tag-add:placeholder:text-text-secondary', isSpecialMode ? 'bg-transparent' : '')}
|
||||
className={cn(
|
||||
!isInWorkflow && 'max-w-[300px]',
|
||||
isInWorkflow && 'max-w-[146px]',
|
||||
|
||||
@ -70,7 +70,7 @@ const EmptyElement: FC<{ canAdd: boolean; onClick: () => void; type?: 'upload' |
|
||||
<div className={s.emptyTip}>
|
||||
{t(`datasetDocuments.list.empty.${type}.tip`)}
|
||||
</div>
|
||||
{type === 'upload' && canAdd && <Button onClick={onClick} className={s.addFileBtn}>
|
||||
{type === 'upload' && canAdd && <Button onClick={onClick} className={s.addFileBtn} variant='secondary-accent'>
|
||||
<PlusIcon className={s.plusIcon} />{t('datasetDocuments.list.addFile')}
|
||||
</Button>}
|
||||
</div>
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
@apply text-text-secondary text-sm;
|
||||
}
|
||||
.addFileBtn {
|
||||
@apply mt-4 w-fit !text-[13px] text-primary-600 font-medium bg-white border-[0.5px];
|
||||
@apply mt-4 w-fit !text-[13px] font-medium border-[0.5px];
|
||||
}
|
||||
.plusIcon {
|
||||
@apply w-4 h-4 mr-2 stroke-current stroke-[1.5px];
|
||||
@ -35,16 +35,16 @@
|
||||
@apply flex items-center justify-center h-full;
|
||||
}
|
||||
.emptyElement {
|
||||
@apply bg-gray-50 w-[560px] h-fit box-border px-5 py-4 rounded-2xl;
|
||||
@apply bg-components-panel-on-panel-item-bg border-divider-subtle w-[560px] h-fit box-border px-5 py-4 rounded-2xl;
|
||||
}
|
||||
.emptyTitle {
|
||||
@apply text-gray-700 font-semibold;
|
||||
@apply text-text-secondary font-semibold;
|
||||
}
|
||||
.emptyTip {
|
||||
@apply mt-2 text-gray-500 text-sm font-normal;
|
||||
@apply mt-2 text-text-primary text-sm font-normal;
|
||||
}
|
||||
.emptySymbolIconWrapper {
|
||||
@apply w-[44px] h-[44px] border border-solid border-gray-100 rounded-lg flex items-center justify-center mb-2;
|
||||
@apply w-[44px] h-[44px] border border-solid border-components-button-secondary-border rounded-lg flex items-center justify-center mb-2;
|
||||
}
|
||||
.commonIcon {
|
||||
@apply w-4 h-4 inline-block align-middle;
|
||||
|
||||
@ -214,8 +214,8 @@ const PermissionSelector = ({
|
||||
/>
|
||||
</div>
|
||||
{isPartialMembers && (
|
||||
<div className='max-h-[360px] overflow-y-auto border-t-[1px] border-divider-regular'>
|
||||
<div className='sticky left-0 top-0 z-10 p-2 pb-1'>
|
||||
<div className='max-h-[360px] overflow-y-auto border-t-[1px] border-divider-regular pb-1 pl-1 pr-1'>
|
||||
<div className='sticky left-0 top-0 z-10 bg-components-panel-on-panel-item-bg p-2 pb-1'>
|
||||
<Input
|
||||
showLeftIcon
|
||||
showClearIcon
|
||||
|
||||
@ -42,7 +42,7 @@ const InvitationLink = ({
|
||||
<Tooltip
|
||||
popupContent={isCopied ? `${t('appApi.copied')}` : `${t('appApi.copy')}`}
|
||||
>
|
||||
<div className='r-0 absolute left-0 top-0 w-full cursor-pointer truncate pl-2 pr-2' onClick={copyHandle}>{value.url}</div>
|
||||
<div className='r-0 absolute left-0 top-0 w-full cursor-pointer truncate pl-2 pr-2 text-text-primary' onClick={copyHandle}>{value.url}</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className="h-4 shrink-0 border bg-divider-regular" />
|
||||
|
||||
@ -2,6 +2,11 @@
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import type { FC } from 'react'
|
||||
import type { GithubRepo } from '@/models/common'
|
||||
import { RiLoader2Line } from '@remixicon/react'
|
||||
|
||||
const defaultData = {
|
||||
stargazers_count: 98570,
|
||||
}
|
||||
|
||||
const getStar = async () => {
|
||||
const res = await fetch('https://api.github.com/repos/langgenius/dify')
|
||||
@ -13,15 +18,21 @@ const getStar = async () => {
|
||||
}
|
||||
|
||||
const GithubStar: FC<{ className: string }> = (props) => {
|
||||
const { isFetching, data } = useQuery<GithubRepo>({
|
||||
const { isFetching, isError, data } = useQuery<GithubRepo>({
|
||||
queryKey: ['github-star'],
|
||||
queryFn: getStar,
|
||||
enabled: process.env.NODE_ENV !== 'development',
|
||||
initialData: { stargazers_count: 81204 },
|
||||
retry: false,
|
||||
placeholderData: defaultData,
|
||||
})
|
||||
|
||||
if (isFetching)
|
||||
return null
|
||||
return <span {...props}>{data.stargazers_count.toLocaleString()}</span>
|
||||
return <RiLoader2Line className='size-3 shrink-0 animate-spin text-text-tertiary' />
|
||||
|
||||
if (isError)
|
||||
return <span {...props}>{defaultData.stargazers_count.toLocaleString()}</span>
|
||||
|
||||
return <span {...props}>{data?.stargazers_count.toLocaleString()}</span>
|
||||
}
|
||||
|
||||
export default GithubStar
|
||||
|
||||
Reference in New Issue
Block a user