Skip to content

Commit e9e7848

Browse files
douxciamjoel
authored andcommitted
Feat: new entry point for app creation (#10847)
1 parent bc82de8 commit e9e7848

File tree

89 files changed

+1311
-567
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+1311
-567
lines changed

web/app/(commonLayout)/apps/AppCard.tsx

+9-26
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ import Divider from '@/app/components/base/divider'
2121
import { getRedirection } from '@/utils/app-redirection'
2222
import { useProviderContext } from '@/context/provider-context'
2323
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
24-
import { AiText, ChatBot, CuteRobot } from '@/app/components/base/icons/src/vender/solid/communication'
25-
import { Route } from '@/app/components/base/icons/src/vender/solid/mapsAndTravel'
2624
import type { CreateAppModalProps } from '@/app/components/explore/create-app-modal'
2725
import EditAppModal from '@/app/components/explore/create-app-modal'
2826
import SwitchAppModal from '@/app/components/app/switch-app-modal'
@@ -32,6 +30,7 @@ import type { EnvironmentVariable } from '@/app/components/workflow/types'
3230
import DSLExportConfirmModal from '@/app/components/workflow/dsl-export-confirm-modal'
3331
import { fetchWorkflowDraft } from '@/service/workflow'
3432
import { fetchInstalledAppList } from '@/service/explore'
33+
import { AppTypeIcon } from '@/app/components/app/type-selector'
3534

3635
export type AppCardProps = {
3736
app: App
@@ -277,7 +276,7 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
277276
e.preventDefault()
278277
getRedirection(isCurrentWorkspaceEditor, app, push)
279278
}}
280-
className='relative group col-span-1 bg-white border-2 border-solid border-transparent rounded-xl shadow-sm flex flex-col transition-all duration-200 ease-in-out cursor-pointer hover:shadow-lg'
279+
className='relative h-[160px] group col-span-1 bg-components-card-bg border-[1px] border-solid border-components-card-border rounded-xl shadow-sm inline-flex flex-col transition-all duration-200 ease-in-out cursor-pointer hover:shadow-lg'
281280
>
282281
<div className='flex pt-[14px] px-[14px] pb-3 h-[66px] items-center gap-3 grow-0 shrink-0'>
283282
<div className='relative shrink-0'>
@@ -288,38 +287,22 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
288287
background={app.icon_background}
289288
imageUrl={app.icon_url}
290289
/>
291-
<span className='absolute bottom-[-3px] right-[-3px] w-4 h-4 p-0.5 bg-white rounded border-[0.5px] border-[rgba(0,0,0,0.02)] shadow-sm'>
292-
{app.mode === 'advanced-chat' && (
293-
<ChatBot className='w-3 h-3 text-[#1570EF]' />
294-
)}
295-
{app.mode === 'agent-chat' && (
296-
<CuteRobot className='w-3 h-3 text-indigo-600' />
297-
)}
298-
{app.mode === 'chat' && (
299-
<ChatBot className='w-3 h-3 text-[#1570EF]' />
300-
)}
301-
{app.mode === 'completion' && (
302-
<AiText className='w-3 h-3 text-[#0E9384]' />
303-
)}
304-
{app.mode === 'workflow' && (
305-
<Route className='w-3 h-3 text-[#f79009]' />
306-
)}
307-
</span>
290+
<AppTypeIcon type={app.mode} wrapperClassName='absolute -bottom-0.5 -right-0.5 w-4 h-4 shadow-sm' className='w-3 h-3' />
308291
</div>
309292
<div className='grow w-0 py-[1px]'>
310-
<div className='flex items-center text-sm leading-5 font-semibold text-gray-800'>
293+
<div className='flex items-center text-sm leading-5 font-semibold text-text-secondary'>
311294
<div className='truncate' title={app.name}>{app.name}</div>
312295
</div>
313-
<div className='flex items-center text-[10px] leading-[18px] text-gray-500 font-medium'>
314-
{app.mode === 'advanced-chat' && <div className='truncate'>{t('app.types.chatbot').toUpperCase()}</div>}
296+
<div className='flex items-center text-[10px] leading-[18px] text-text-tertiary font-medium'>
297+
{app.mode === 'advanced-chat' && <div className='truncate'>{t('app.types.advanced').toUpperCase()}</div>}
315298
{app.mode === 'chat' && <div className='truncate'>{t('app.types.chatbot').toUpperCase()}</div>}
316299
{app.mode === 'agent-chat' && <div className='truncate'>{t('app.types.agent').toUpperCase()}</div>}
317300
{app.mode === 'workflow' && <div className='truncate'>{t('app.types.workflow').toUpperCase()}</div>}
318301
{app.mode === 'completion' && <div className='truncate'>{t('app.types.completion').toUpperCase()}</div>}
319302
</div>
320303
</div>
321304
</div>
322-
<div className='title-wrapper h-[90px] px-[14px] text-xs leading-normal text-gray-500'>
305+
<div className='title-wrapper h-[90px] px-[14px] text-xs leading-normal text-text-tertiary'>
323306
<div
324307
className={cn(tags.length ? 'line-clamp-2' : 'line-clamp-4', 'group-hover:line-clamp-2')}
325308
title={app.description}
@@ -352,7 +335,7 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
352335
/>
353336
</div>
354337
</div>
355-
<div className='!hidden group-hover:!flex shrink-0 mx-1 w-[1px] h-[14px] bg-gray-200' />
338+
<div className='!hidden group-hover:!flex shrink-0 mx-1 w-[1px] h-[14px]' />
356339
<div className='!hidden group-hover:!flex shrink-0'>
357340
<CustomPopover
358341
htmlContent={<Operations />}
@@ -362,7 +345,7 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
362345
<div
363346
className='flex items-center justify-center w-8 h-8 cursor-pointer rounded-md'
364347
>
365-
<RiMoreFill className='w-4 h-4 text-gray-700' />
348+
<RiMoreFill className='w-4 h-4 text-text-tertiary' />
366349
</div>
367350
}
368351
btnClassName={open =>

web/app/(commonLayout)/apps/Apps.tsx

+33-9
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ const Apps = () => {
125125

126126
return (
127127
<>
128-
<div className='sticky top-0 flex justify-between items-center pt-4 px-12 pb-2 leading-[56px] bg-gray-100 z-10 flex-wrap gap-y-2'>
128+
<div className='sticky top-0 flex justify-between items-center pt-4 px-12 pb-2 leading-[56px] bg-background-body z-10 flex-wrap gap-y-2'>
129129
<TabSliderNew
130130
value={activeTab}
131131
onChange={setActiveTab}
@@ -143,14 +143,20 @@ const Apps = () => {
143143
/>
144144
</div>
145145
</div>
146-
<nav className='grid content-start grid-cols-1 gap-4 px-12 pt-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 grow shrink-0'>
147-
{isCurrentWorkspaceEditor
148-
&& <NewAppCard onSuccess={mutate} />}
149-
{data?.map(({ data: apps }) => apps.map(app => (
150-
<AppCard key={app.id} app={app} onRefresh={mutate} />
151-
)))}
152-
<CheckModal />
153-
</nav>
146+
{(data && data[0].total > 0)
147+
? <div className='grid content-start grid-cols-1 sm:grid-cols-1 md:grid-cols-2 xl:grid-cols-4 2xl:grid-cols-5 2k:grid-cols-6 gap-4 px-12 pt-2 grow relative'>
148+
{isCurrentWorkspaceEditor
149+
&& <NewAppCard onSuccess={mutate} />}
150+
{data.map(({ data: apps }) => apps.map(app => (
151+
<AppCard key={app.id} app={app} onRefresh={mutate} />
152+
)))}
153+
</div>
154+
: <div className='grid content-start grid-cols-1 sm:grid-cols-1 md:grid-cols-2 xl:grid-cols-4 2xl:grid-cols-5 2k:grid-cols-6 gap-4 px-12 pt-2 grow relative overflow-hidden'>
155+
{isCurrentWorkspaceEditor
156+
&& <NewAppCard className='z-10' onSuccess={mutate} />}
157+
<NoAppsFound />
158+
</div>}
159+
<CheckModal />
154160
<div ref={anchorRef} className='h-0'> </div>
155161
{showTagManagementModal && (
156162
<TagManagementModal type='app' show={showTagManagementModal} />
@@ -160,3 +166,21 @@ const Apps = () => {
160166
}
161167

162168
export default Apps
169+
170+
function NoAppsFound() {
171+
const { t } = useTranslation()
172+
function renderDefaultCard() {
173+
const defaultCards = Array.from({ length: 36 }, (_, index) => (
174+
<div key={index} className='h-[160px] inline-flex rounded-xl bg-background-default-lighter'></div>
175+
))
176+
return defaultCards
177+
}
178+
return (
179+
<>
180+
{renderDefaultCard()}
181+
<div className='absolute top-0 left-0 right-0 bottom-0 flex items-center justify-center bg-gradient-to-t from-background-body to-transparent'>
182+
<span className='system-md-medium text-text-tertiary'>{t('app.newApp.noAppsFound')}</span>
183+
</div>
184+
</>
185+
)
186+
}

web/app/(commonLayout)/apps/NewAppCard.tsx

+19-9
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ import CreateAppModal from '@/app/components/app/create-app-modal'
1111
import CreateFromDSLModal, { CreateFromDSLModalTab } from '@/app/components/app/create-from-dsl-modal'
1212
import { useProviderContext } from '@/context/provider-context'
1313
import { FileArrow01, FilePlus01, FilePlus02 } from '@/app/components/base/icons/src/vender/line/files'
14+
import cn from '@/utils/classnames'
1415

1516
export type CreateAppCardProps = {
17+
className?: string
1618
onSuccess?: () => void
1719
}
1820

1921
// eslint-disable-next-line react/display-name
20-
const CreateAppCard = forwardRef<HTMLAnchorElement, CreateAppCardProps>(({ onSuccess }, ref) => {
22+
const CreateAppCard = forwardRef<HTMLDivElement, CreateAppCardProps>(({ className, onSuccess }, ref) => {
2123
const { t } = useTranslation()
2224
const { onPlanInfoChanged } = useProviderContext()
2325
const searchParams = useSearchParams()
@@ -36,26 +38,26 @@ const CreateAppCard = forwardRef<HTMLAnchorElement, CreateAppCardProps>(({ onSuc
3638
}, [dslUrl])
3739

3840
return (
39-
<a
41+
<div
4042
ref={ref}
41-
className='relative col-span-1 flex flex-col justify-between min-h-[160px] bg-gray-200 rounded-xl border-[0.5px] border-black/5'
43+
className={cn('relative col-span-1 inline-flex flex-col justify-between h-[160px] bg-components-card-bg rounded-xl border-[0.5px] border-components-card-border', className)}
4244
>
4345
<div className='grow p-2 rounded-t-xl'>
44-
<div className='px-6 pt-2 pb-1 text-xs font-medium leading-[18px] text-gray-500'>{t('app.createApp')}</div>
45-
<div className='flex items-center mb-1 px-6 py-[7px] rounded-lg text-[13px] font-medium leading-[18px] text-gray-600 cursor-pointer hover:text-primary-600 hover:bg-white' onClick={() => setShowNewAppModal(true)}>
46+
<div className='px-6 pt-2 pb-1 text-xs font-medium leading-[18px] text-text-tertiary'>{t('app.createApp')}</div>
47+
<div className='flex items-center mb-1 px-6 py-[7px] rounded-lg text-[13px] font-medium leading-[18px] text-text-tertiary cursor-pointer hover:text-text-secondary hover:bg-state-base-hover' onClick={() => setShowNewAppModal(true)}>
4648
<FilePlus01 className='shrink-0 mr-2 w-4 h-4' />
4749
{t('app.newApp.startFromBlank')}
4850
</div>
49-
<div className='flex items-center px-6 py-[7px] rounded-lg text-[13px] font-medium leading-[18px] text-gray-600 cursor-pointer hover:text-primary-600 hover:bg-white' onClick={() => setShowNewAppTemplateDialog(true)}>
51+
<div className='flex items-center px-6 py-[7px] rounded-lg text-[13px] font-medium leading-[18px] text-text-tertiary cursor-pointer hover:text-text-secondary hover:bg-state-base-hover' onClick={() => setShowNewAppTemplateDialog(true)}>
5052
<FilePlus02 className='shrink-0 mr-2 w-4 h-4' />
5153
{t('app.newApp.startFromTemplate')}
5254
</div>
5355
</div>
5456
<div
55-
className='p-2 border-t-[0.5px] border-black/5 rounded-b-xl'
57+
className='p-2 border-t-[0.5px] border-components-card-border rounded-b-xl'
5658
onClick={() => setShowCreateFromDSLModal(true)}
5759
>
58-
<div className='flex items-center px-6 py-[7px] rounded-lg text-[13px] font-medium leading-[18px] text-gray-600 cursor-pointer hover:text-primary-600 hover:bg-white'>
60+
<div className='flex items-center px-6 py-[7px] rounded-lg text-[13px] font-medium leading-[18px] text-text-tertiary cursor-pointer hover:text-text-secondary hover:bg-state-base-hover'>
5961
<FileArrow01 className='shrink-0 mr-2 w-4 h-4' />
6062
{t('app.importDSL')}
6163
</div>
@@ -68,6 +70,10 @@ const CreateAppCard = forwardRef<HTMLAnchorElement, CreateAppCardProps>(({ onSuc
6870
if (onSuccess)
6971
onSuccess()
7072
}}
73+
onCreateFromTemplate={() => {
74+
setShowNewAppTemplateDialog(true)
75+
setShowNewAppModal(false)
76+
}}
7177
/>
7278
<CreateAppTemplateDialog
7379
show={showNewAppTemplateDialog}
@@ -77,6 +83,10 @@ const CreateAppCard = forwardRef<HTMLAnchorElement, CreateAppCardProps>(({ onSuc
7783
if (onSuccess)
7884
onSuccess()
7985
}}
86+
onCreateFromBlank={() => {
87+
setShowNewAppModal(true)
88+
setShowNewAppTemplateDialog(false)
89+
}}
8090
/>
8191
<CreateFromDSLModal
8292
show={showCreateFromDSLModal}
@@ -94,7 +104,7 @@ const CreateAppCard = forwardRef<HTMLAnchorElement, CreateAppCardProps>(({ onSuc
94104
onSuccess()
95105
}}
96106
/>
97-
</a>
107+
</div>
98108
)
99109
})
100110

web/app/(commonLayout)/apps/page.tsx

+10-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
'use client'
22
import { useContextSelector } from 'use-context-selector'
33
import { useTranslation } from 'react-i18next'
4+
import { RiDiscordFill, RiGithubFill } from '@remixicon/react'
5+
import Link from 'next/link'
46
import style from '../list.module.css'
57
import Apps from './Apps'
6-
import classNames from '@/utils/classnames'
78
import AppContext from '@/context/app-context'
89
import { LicenseStatus } from '@/types/feature'
910

@@ -12,14 +13,18 @@ const AppList = () => {
1213
const systemFeatures = useContextSelector(AppContext, v => v.systemFeatures)
1314

1415
return (
15-
<div className='relative flex flex-col overflow-y-auto bg-gray-100 shrink-0 h-0 grow'>
16+
<div className='relative flex flex-col overflow-y-auto bg-background-body shrink-0 h-0 grow'>
1617
<Apps />
1718
{systemFeatures.license.status === LicenseStatus.NONE && <footer className='px-12 py-6 grow-0 shrink-0'>
1819
<h3 className='text-xl font-semibold leading-tight text-gradient'>{t('app.join')}</h3>
19-
<p className='mt-1 text-sm font-normal leading-tight text-gray-700'>{t('app.communityIntro')}</p>
20+
<p className='mt-1 system-sm-regular text-text-tertiary'>{t('app.communityIntro')}</p>
2021
<div className='flex items-center gap-2 mt-3'>
21-
<a className={style.socialMediaLink} target='_blank' rel='noopener noreferrer' href='https://github.com/langgenius/dify'><span className={classNames(style.socialMediaIcon, style.githubIcon)} /></a>
22-
<a className={style.socialMediaLink} target='_blank' rel='noopener noreferrer' href='https://discord.gg/FngNHpbcY7'><span className={classNames(style.socialMediaIcon, style.discordIcon)} /></a>
22+
<Link className={style.socialMediaLink} target='_blank' rel='noopener noreferrer' href='https://github.com/langgenius/dify'>
23+
<RiGithubFill className='w-5 h-5 text-text-tertiary' />
24+
</Link>
25+
<Link className={style.socialMediaLink} target='_blank' rel='noopener noreferrer' href='https://discord.gg/FngNHpbcY7'>
26+
<RiDiscordFill className='w-5 h-5 text-text-tertiary' />
27+
</Link>
2328
</div>
2429
</footer>}
2530
</div >

web/app/(commonLayout)/list.module.css

-8
Original file line numberDiff line numberDiff line change
@@ -201,14 +201,6 @@
201201
@apply block w-6 h-6 bg-center bg-contain;
202202
}
203203

204-
.githubIcon {
205-
background-image: url("./apps/assets/github.svg");
206-
}
207-
208-
.discordIcon {
209-
background-image: url("./apps/assets/discord.svg");
210-
}
211-
212204
/* #region new app dialog */
213205
.newItemCaption {
214206
@apply inline-flex items-center mb-2 text-sm font-medium;

0 commit comments

Comments
 (0)