From 7bbe12b2bd23c05c7f5df13d177c82198d227f34 Mon Sep 17 00:00:00 2001 From: Joel Date: Tue, 23 Jan 2024 19:31:56 +0800 Subject: [PATCH] feat: support assistant frontend (#2139) Co-authored-by: StyleZhang --- web/.gitignore | 4 +- .../app/(appDetailLayout)/[appId]/layout.tsx | 13 +- web/app/(commonLayout)/apps/AppCard.tsx | 9 +- web/app/(commonLayout)/apps/AppModeLabel.tsx | 40 +- web/app/(commonLayout)/apps/Apps.tsx | 110 +- web/app/(commonLayout)/apps/NewAppDialog.tsx | 111 +- web/app/(commonLayout)/apps/page.tsx | 2 +- web/app/(commonLayout)/list.module.css | 47 +- web/app/(commonLayout)/tools/custom/page.tsx | 10 + web/app/(commonLayout)/tools/page.tsx | 23 + .../(commonLayout)/tools/third-part/page.tsx | 10 + web/app/components/app/chat/answer/index.tsx | 101 +- web/app/components/app/chat/index.tsx | 48 +- web/app/components/app/chat/thought/index.tsx | 114 +-- web/app/components/app/chat/thought/panel.tsx | 28 + web/app/components/app/chat/thought/tool.tsx | 103 ++ web/app/components/app/chat/type.ts | 18 +- .../base/operation-btn/index.tsx | 9 +- .../config-prompt/advanced-prompt-input.tsx | 31 +- .../config-prompt/simple-prompt-input.tsx | 55 +- .../config-var/config-select/style.module.css | 2 - .../app/configuration/config-var/index.tsx | 137 ++- .../config-var/input-type-icon.tsx | 4 + .../config-var/select-var-type.tsx | 76 ++ .../config/agent/agent-setting/index.tsx | 156 +++ .../config/agent/agent-setting/item-panel.tsx | 44 + .../agent/agent-tools/choose-tool/index.tsx | 77 ++ .../config/agent/agent-tools/index.tsx | 216 ++++ .../agent-tools/setting-built-in-tool.tsx | 192 ++++ .../config/agent/prompt-editor.tsx | 141 +++ .../config/assistant-type-picker/index.tsx | 165 +++ .../config/automatic/automatic-btn.tsx | 10 +- .../preview-imgs/opening-statement.png | Bin 0 -> 19955 bytes .../preview-imgs/opening-statement.svg | 144 --- .../feature-item/style.module.css | 3 +- .../app/configuration/config/index.tsx | 22 +- .../configuration/dataset-config/index.tsx | 3 +- .../dataset-config/settings-modal/index.tsx | 10 +- .../app/configuration/debug/index.tsx | 161 ++- .../chat-group/opening-statement/index.tsx | 140 ++- .../components/app/configuration/index.tsx | 342 ++++--- .../prompt-mode/advanced-mode-waring.tsx | 27 +- .../app/configuration/style.module.css | 9 +- .../tools/external-data-tool-modal.tsx | 6 +- .../app/configuration/tools/index.tsx | 1 + web/app/components/app/log/filter.tsx | 2 +- web/app/components/app/log/list.tsx | 5 +- web/app/components/base/app-icon/index.tsx | 2 +- .../components/base/app-icon/style.module.css | 10 +- web/app/components/base/drawer-plus/index.tsx | 44 +- .../components/base/emoji-picker/index.tsx | 4 +- .../public/common/diagonal-dividing-line.svg | 3 + .../header-nav/explore/explore-active.svg | 13 + .../public/header-nav/explore/explore.svg | 13 + .../header-nav/knowledge/knowledge-active.svg | 3 + .../public/header-nav/knowledge/knowledge.svg | 3 + .../public/header-nav/studio/Robot-Active.svg | 4 + .../assets/public/header-nav/studio/Robot.svg | 3 + .../public/header-nav/tools/tools-active.svg | 5 + .../assets/public/header-nav/tools/tools.svg | 14 + .../assets/public/other/default-tool-icon.svg | 9 + .../vender/line/arrows/arrow-narrow-right.svg | 3 + .../vender/solid/arrows/chevron-down.svg | 5 + .../vender/solid/communication/ai-text.svg | 6 + .../solid/communication/cute-robote.svg | 5 + .../solid/development/api-connection.svg | 8 + .../vender/solid/education/bubble-text.svg | 5 + .../vender/solid/education/heart-02.svg | 3 + .../assets/vender/solid/education/unblur.svg | 19 + .../assets/vender/solid/general/search-md.svg | 5 + .../public/common/DiagonalDividingLine.json | 28 + .../public/common/DiagonalDividingLine.tsx | 16 + .../base/icons/src/public/common/index.ts | 1 + .../public/header-nav/explore/Explore.json | 96 ++ .../src/public/header-nav/explore/Explore.tsx | 16 + .../header-nav/explore/ExploreActive.json | 88 ++ .../header-nav/explore/ExploreActive.tsx | 16 + .../src/public/header-nav/explore/index.ts | 2 + .../header-nav/knowledge/Knowledge.json | 29 + .../public/header-nav/knowledge/Knowledge.tsx | 16 + .../header-nav/knowledge/KnowledgeActive.json | 28 + .../header-nav/knowledge/KnowledgeActive.tsx | 16 + .../src/public/header-nav/knowledge/index.ts | 2 + .../src/public/header-nav/studio/Robot.json | 29 + .../src/public/header-nav/studio/Robot.tsx | 16 + .../public/header-nav/studio/RobotActive.json | 39 + .../public/header-nav/studio/RobotActive.tsx | 16 + .../src/public/header-nav/studio/index.ts | 2 + .../src/public/header-nav/tools/Tools.json | 112 ++ .../src/public/header-nav/tools/Tools.tsx | 16 + .../public/header-nav/tools/ToolsActive.json | 46 + .../public/header-nav/tools/ToolsActive.tsx | 16 + .../src/public/header-nav/tools/index.ts | 2 + .../src/public/other/DefaultToolIcon.json | 81 ++ .../src/public/other/DefaultToolIcon.tsx | 16 + .../base/icons/src/public/other/index.ts | 1 + .../vender/line/arrows/ArrowNarrowRight.json | 29 + .../vender/line/arrows/ArrowNarrowRight.tsx | 16 + .../icons/src/vender/line/arrows/index.ts | 1 + .../src/vender/solid/arrows/ChevronDown.json | 39 + .../src/vender/solid/arrows/ChevronDown.tsx | 16 + .../icons/src/vender/solid/arrows/index.ts | 1 + .../vender/solid/communication/AiText.json | 53 + .../src/vender/solid/communication/AiText.tsx | 16 + .../solid/communication/CuteRobote.json | 38 + .../vender/solid/communication/CuteRobote.tsx | 16 + .../src/vender/solid/communication/index.ts | 2 + .../solid/development/ApiConnection.json | 53 + .../solid/development/ApiConnection.tsx | 16 + .../src/vender/solid/development/index.ts | 1 + .../vender/solid/education/BubbleText.json | 38 + .../src/vender/solid/education/BubbleText.tsx | 16 + .../src/vender/solid/education/Heart02.json | 26 + .../src/vender/solid/education/Heart02.tsx | 16 + .../src/vender/solid/education/Unblur.json | 152 +++ .../src/vender/solid/education/Unblur.tsx | 16 + .../icons/src/vender/solid/education/index.ts | 3 + .../src/vender/solid/general/SearchMd.json | 38 + .../src/vender/solid/general/SearchMd.tsx | 16 + .../icons/src/vender/solid/general/index.ts | 1 + .../plugins/component-picker.tsx | 3 +- .../prompt-editor/plugins/variable-picker.tsx | 8 + web/app/components/base/radio/ui.tsx | 18 + web/app/components/base/select/index.tsx | 75 +- web/app/components/base/tab-slider/index.tsx | 19 +- web/app/components/base/voice-input/utils.ts | 7 + .../develop/template/template.en.mdx | 476 ++++++--- .../develop/template/template.zh.mdx | 383 ++++--- .../develop/template/template_chat.en.mdx | 911 ++++++++++++----- .../develop/template/template_chat.zh.mdx | 965 +++++++++++++----- web/app/components/explore/app-card/index.tsx | 6 +- web/app/components/explore/app-list/index.tsx | 4 +- .../explore/create-app-modal/index.tsx | 8 +- web/app/components/explore/sidebar/index.tsx | 12 +- .../api-based-extension-page/modal.tsx | 2 +- .../api-based-extension-page/selector.tsx | 2 +- .../header/account-setting/index.tsx | 15 +- .../model-provider-page/declarations.ts | 3 + .../model-provider-page/model-modal/Form.tsx | 42 +- .../model-provider-page/model-modal/Input.tsx | 19 + web/app/components/header/app-nav/index.tsx | 12 +- .../components/header/app-selector/index.tsx | 2 +- .../components/header/dataset-nav/index.tsx | 7 +- .../components/header/explore-nav/index.tsx | 8 +- web/app/components/header/index.tsx | 5 +- web/app/components/header/tools-nav/index.tsx | 35 + web/app/components/share/chat/index.tsx | 152 ++- web/app/components/share/utils.ts | 1 - web/app/components/tools/contribute.tsx | 31 + .../config-credentials.tsx | 108 ++ .../edit-custom-collection-modal/examples.ts | 181 ++++ .../get-schema.tsx | 117 +++ .../edit-custom-collection-modal/index.tsx | 290 ++++++ .../edit-custom-collection-modal/test-api.tsx | 120 +++ web/app/components/tools/index.tsx | 232 +++++ .../components/tools/info/no-custom-tool.tsx | 38 + .../components/tools/info/no-search-res.tsx | 38 + web/app/components/tools/search.tsx | 41 + .../setting/build-in/config-credentials.tsx | 88 ++ web/app/components/tools/tool-list/header.tsx | 74 ++ web/app/components/tools/tool-list/index.tsx | 190 ++++ web/app/components/tools/tool-list/item.tsx | 78 ++ .../components/tools/tool-nav-list/index.tsx | 28 + .../components/tools/tool-nav-list/item.tsx | 49 + web/app/components/tools/types.ts | 111 ++ web/app/components/tools/utils/index.ts | 26 + .../components/tools/utils/to-form-schema.ts | 64 ++ web/config/index.ts | 98 +- web/context/debug-configuration.ts | 19 +- web/context/modal-context.tsx | 11 +- web/global.d.ts | 4 +- web/i18n/i18next-config.ts | 6 + web/i18n/lang/app-debug.en.ts | 47 +- web/i18n/lang/app-debug.zh.ts | 43 +- web/i18n/lang/app.en.ts | 13 +- web/i18n/lang/app.zh.ts | 11 +- web/i18n/lang/common.en.ts | 6 +- web/i18n/lang/common.zh.ts | 6 +- web/i18n/lang/dataset.en.ts | 1 + web/i18n/lang/dataset.zh.ts | 1 + web/i18n/lang/tools.en.ts | 103 ++ web/i18n/lang/tools.zh.ts | 95 ++ web/models/debug.ts | 22 +- web/models/explore.ts | 2 + web/models/share.ts | 4 + web/package.json | 2 +- web/service/base.ts | 15 +- web/service/debug.ts | 9 +- web/service/share.ts | 12 +- web/service/tools.ts | 83 ++ web/tailwind.config.js | 1 + web/types/app.ts | 26 +- web/utils/model-config.ts | 30 + web/utils/var.ts | 3 +- 194 files changed, 8726 insertions(+), 1586 deletions(-) create mode 100644 web/app/(commonLayout)/tools/custom/page.tsx create mode 100644 web/app/(commonLayout)/tools/page.tsx create mode 100644 web/app/(commonLayout)/tools/third-part/page.tsx create mode 100644 web/app/components/app/chat/thought/panel.tsx create mode 100644 web/app/components/app/chat/thought/tool.tsx create mode 100644 web/app/components/app/configuration/config-var/select-var-type.tsx create mode 100644 web/app/components/app/configuration/config/agent/agent-setting/index.tsx create mode 100644 web/app/components/app/configuration/config/agent/agent-setting/item-panel.tsx create mode 100644 web/app/components/app/configuration/config/agent/agent-tools/choose-tool/index.tsx create mode 100644 web/app/components/app/configuration/config/agent/agent-tools/index.tsx create mode 100644 web/app/components/app/configuration/config/agent/agent-tools/setting-built-in-tool.tsx create mode 100644 web/app/components/app/configuration/config/agent/prompt-editor.tsx create mode 100644 web/app/components/app/configuration/config/assistant-type-picker/index.tsx create mode 100644 web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/opening-statement.png delete mode 100644 web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/opening-statement.svg create mode 100644 web/app/components/base/icons/assets/public/common/diagonal-dividing-line.svg create mode 100644 web/app/components/base/icons/assets/public/header-nav/explore/explore-active.svg create mode 100644 web/app/components/base/icons/assets/public/header-nav/explore/explore.svg create mode 100644 web/app/components/base/icons/assets/public/header-nav/knowledge/knowledge-active.svg create mode 100644 web/app/components/base/icons/assets/public/header-nav/knowledge/knowledge.svg create mode 100644 web/app/components/base/icons/assets/public/header-nav/studio/Robot-Active.svg create mode 100644 web/app/components/base/icons/assets/public/header-nav/studio/Robot.svg create mode 100644 web/app/components/base/icons/assets/public/header-nav/tools/tools-active.svg create mode 100644 web/app/components/base/icons/assets/public/header-nav/tools/tools.svg create mode 100644 web/app/components/base/icons/assets/public/other/default-tool-icon.svg create mode 100644 web/app/components/base/icons/assets/vender/line/arrows/arrow-narrow-right.svg create mode 100644 web/app/components/base/icons/assets/vender/solid/arrows/chevron-down.svg create mode 100644 web/app/components/base/icons/assets/vender/solid/communication/ai-text.svg create mode 100644 web/app/components/base/icons/assets/vender/solid/communication/cute-robote.svg create mode 100644 web/app/components/base/icons/assets/vender/solid/development/api-connection.svg create mode 100644 web/app/components/base/icons/assets/vender/solid/education/bubble-text.svg create mode 100644 web/app/components/base/icons/assets/vender/solid/education/heart-02.svg create mode 100644 web/app/components/base/icons/assets/vender/solid/education/unblur.svg create mode 100644 web/app/components/base/icons/assets/vender/solid/general/search-md.svg create mode 100644 web/app/components/base/icons/src/public/common/DiagonalDividingLine.json create mode 100644 web/app/components/base/icons/src/public/common/DiagonalDividingLine.tsx create mode 100644 web/app/components/base/icons/src/public/header-nav/explore/Explore.json create mode 100644 web/app/components/base/icons/src/public/header-nav/explore/Explore.tsx create mode 100644 web/app/components/base/icons/src/public/header-nav/explore/ExploreActive.json create mode 100644 web/app/components/base/icons/src/public/header-nav/explore/ExploreActive.tsx create mode 100644 web/app/components/base/icons/src/public/header-nav/explore/index.ts create mode 100644 web/app/components/base/icons/src/public/header-nav/knowledge/Knowledge.json create mode 100644 web/app/components/base/icons/src/public/header-nav/knowledge/Knowledge.tsx create mode 100644 web/app/components/base/icons/src/public/header-nav/knowledge/KnowledgeActive.json create mode 100644 web/app/components/base/icons/src/public/header-nav/knowledge/KnowledgeActive.tsx create mode 100644 web/app/components/base/icons/src/public/header-nav/knowledge/index.ts create mode 100644 web/app/components/base/icons/src/public/header-nav/studio/Robot.json create mode 100644 web/app/components/base/icons/src/public/header-nav/studio/Robot.tsx create mode 100644 web/app/components/base/icons/src/public/header-nav/studio/RobotActive.json create mode 100644 web/app/components/base/icons/src/public/header-nav/studio/RobotActive.tsx create mode 100644 web/app/components/base/icons/src/public/header-nav/studio/index.ts create mode 100644 web/app/components/base/icons/src/public/header-nav/tools/Tools.json create mode 100644 web/app/components/base/icons/src/public/header-nav/tools/Tools.tsx create mode 100644 web/app/components/base/icons/src/public/header-nav/tools/ToolsActive.json create mode 100644 web/app/components/base/icons/src/public/header-nav/tools/ToolsActive.tsx create mode 100644 web/app/components/base/icons/src/public/header-nav/tools/index.ts create mode 100644 web/app/components/base/icons/src/public/other/DefaultToolIcon.json create mode 100644 web/app/components/base/icons/src/public/other/DefaultToolIcon.tsx create mode 100644 web/app/components/base/icons/src/public/other/index.ts create mode 100644 web/app/components/base/icons/src/vender/line/arrows/ArrowNarrowRight.json create mode 100644 web/app/components/base/icons/src/vender/line/arrows/ArrowNarrowRight.tsx create mode 100644 web/app/components/base/icons/src/vender/solid/arrows/ChevronDown.json create mode 100644 web/app/components/base/icons/src/vender/solid/arrows/ChevronDown.tsx create mode 100644 web/app/components/base/icons/src/vender/solid/communication/AiText.json create mode 100644 web/app/components/base/icons/src/vender/solid/communication/AiText.tsx create mode 100644 web/app/components/base/icons/src/vender/solid/communication/CuteRobote.json create mode 100644 web/app/components/base/icons/src/vender/solid/communication/CuteRobote.tsx create mode 100644 web/app/components/base/icons/src/vender/solid/development/ApiConnection.json create mode 100644 web/app/components/base/icons/src/vender/solid/development/ApiConnection.tsx create mode 100644 web/app/components/base/icons/src/vender/solid/education/BubbleText.json create mode 100644 web/app/components/base/icons/src/vender/solid/education/BubbleText.tsx create mode 100644 web/app/components/base/icons/src/vender/solid/education/Heart02.json create mode 100644 web/app/components/base/icons/src/vender/solid/education/Heart02.tsx create mode 100644 web/app/components/base/icons/src/vender/solid/education/Unblur.json create mode 100644 web/app/components/base/icons/src/vender/solid/education/Unblur.tsx create mode 100644 web/app/components/base/icons/src/vender/solid/general/SearchMd.json create mode 100644 web/app/components/base/icons/src/vender/solid/general/SearchMd.tsx create mode 100644 web/app/components/base/radio/ui.tsx create mode 100644 web/app/components/header/tools-nav/index.tsx create mode 100644 web/app/components/tools/contribute.tsx create mode 100644 web/app/components/tools/edit-custom-collection-modal/config-credentials.tsx create mode 100644 web/app/components/tools/edit-custom-collection-modal/examples.ts create mode 100644 web/app/components/tools/edit-custom-collection-modal/get-schema.tsx create mode 100644 web/app/components/tools/edit-custom-collection-modal/index.tsx create mode 100644 web/app/components/tools/edit-custom-collection-modal/test-api.tsx create mode 100644 web/app/components/tools/index.tsx create mode 100644 web/app/components/tools/info/no-custom-tool.tsx create mode 100644 web/app/components/tools/info/no-search-res.tsx create mode 100644 web/app/components/tools/search.tsx create mode 100644 web/app/components/tools/setting/build-in/config-credentials.tsx create mode 100644 web/app/components/tools/tool-list/header.tsx create mode 100644 web/app/components/tools/tool-list/index.tsx create mode 100644 web/app/components/tools/tool-list/item.tsx create mode 100644 web/app/components/tools/tool-nav-list/index.tsx create mode 100644 web/app/components/tools/tool-nav-list/item.tsx create mode 100644 web/app/components/tools/types.ts create mode 100644 web/app/components/tools/utils/index.ts create mode 100644 web/app/components/tools/utils/to-form-schema.ts create mode 100644 web/i18n/lang/tools.en.ts create mode 100644 web/i18n/lang/tools.zh.ts create mode 100644 web/service/tools.ts diff --git a/web/.gitignore b/web/.gitignore index 6942941877..9dd00b1b08 100644 --- a/web/.gitignore +++ b/web/.gitignore @@ -47,4 +47,6 @@ package-lock.json .yarnrc.yml # pmpm -pnpm-lock.yaml \ No newline at end of file +pnpm-lock.yaml + +.favorites.json \ No newline at end of file diff --git a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/layout.tsx b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/layout.tsx index 8568c7d7b6..14b27f8a64 100644 --- a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/layout.tsx +++ b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/layout.tsx @@ -38,15 +38,24 @@ const AppDetailLayout: FC = (props) => { const navigation = useMemo(() => { const navs = [ - { name: t('common.appMenus.overview'), href: `/app/${appId}/overview`, icon: ChartBarSquareIcon, selectedIcon: ChartBarSquareSolidIcon }, ...(isCurrentWorkspaceManager ? [{ name: t('common.appMenus.promptEng'), href: `/app/${appId}/configuration`, icon: Cog8ToothIcon, selectedIcon: Cog8ToothSolidIcon }] : []), + { name: t('common.appMenus.overview'), href: `/app/${appId}/overview`, icon: ChartBarSquareIcon, selectedIcon: ChartBarSquareSolidIcon }, { name: t('common.appMenus.apiAccess'), href: `/app/${appId}/develop`, icon: CommandLineIcon, selectedIcon: CommandLineSolidIcon }, { name: t('common.appMenus.logAndAnn'), href: `/app/${appId}/logs`, icon: DocumentTextIcon, selectedIcon: DocumentTextSolidIcon }, ] return navs }, [appId, isCurrentWorkspaceManager, t]) - const appModeName = response?.mode?.toUpperCase() === 'COMPLETION' ? t('common.appModes.completionApp') : t('common.appModes.chatApp') + const appModeName = (() => { + if (response?.mode?.toUpperCase() === 'COMPLETION') + return t('app.newApp.completeApp') + + const isAgent = !!response?.is_agent + if (isAgent) + return t('appDebug.assistantType.agentAssistant.name') + + return t('appDebug.assistantType.chatAssistant.name') + })() useEffect(() => { if (response?.name) document.title = `${(response.name || 'App')} - Dify` diff --git a/web/app/(commonLayout)/apps/AppCard.tsx b/web/app/(commonLayout)/apps/AppCard.tsx index 97b8f7b64c..17f85d9b61 100644 --- a/web/app/(commonLayout)/apps/AppCard.tsx +++ b/web/app/(commonLayout)/apps/AppCard.tsx @@ -55,9 +55,7 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => { catch (e: any) { notify({ type: 'error', - message: `${t('app.appDeleteFailed')}${ - 'message' in e ? `: ${e.message}` : '' - }`, + message: `${t('app.appDeleteFailed')}${'message' in e ? `: ${e.message}` : ''}`, }) } setShowConfirmDelete(false) @@ -141,7 +139,8 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => { if (showSettingsModal) return e.preventDefault() - push(`/app/${app.id}/overview`) + + push(`/app/${app.id}/${isCurrentWorkspaceManager ? 'configuration' : 'overview'}`) }} className={style.listItem} > @@ -173,7 +172,7 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => { {app.model_config?.pre_prompt}
- +
{showConfirmDelete && ( diff --git a/web/app/(commonLayout)/apps/AppModeLabel.tsx b/web/app/(commonLayout)/apps/AppModeLabel.tsx index d40d29a11e..bbe6154bec 100644 --- a/web/app/(commonLayout)/apps/AppModeLabel.tsx +++ b/web/app/(commonLayout)/apps/AppModeLabel.tsx @@ -1,25 +1,53 @@ 'use client' -import classNames from 'classnames' import { useTranslation } from 'react-i18next' -import style from '../list.module.css' import { type AppMode } from '@/types/app' +import { + AiText, + CuteRobote, +} from '@/app/components/base/icons/src/vender/solid/communication' +import { BubbleText } from '@/app/components/base/icons/src/vender/solid/education' export type AppModeLabelProps = { mode: AppMode + isAgent?: boolean className?: string } const AppModeLabel = ({ mode, + isAgent, className, }: AppModeLabelProps) => { const { t } = useTranslation() + return ( - - - {t(`app.modes.${mode}`)} - +
+ { + mode === 'completion' && ( + <> + + {t('app.newApp.completeApp')} + + ) + } + { + mode === 'chat' && !isAgent && ( + <> + + {t('appDebug.assistantType.chatAssistant.name')} + + ) + } + { + mode === 'chat' && isAgent && ( + <> + + {t('appDebug.assistantType.agentAssistant.name')} + + ) + } +
) } diff --git a/web/app/(commonLayout)/apps/Apps.tsx b/web/app/(commonLayout)/apps/Apps.tsx index d4ea2fef72..c5331d744a 100644 --- a/web/app/(commonLayout)/apps/Apps.tsx +++ b/web/app/(commonLayout)/apps/Apps.tsx @@ -1,8 +1,9 @@ 'use client' -import { useEffect, useRef } from 'react' +import { useEffect, useRef, useState } from 'react' import useSWRInfinite from 'swr/infinite' import { useTranslation } from 'react-i18next' +import { useDebounceFn } from 'ahooks' import AppCard from './AppCard' import NewAppCard from './NewAppCard' import type { AppListResponse } from '@/models/app' @@ -10,17 +11,46 @@ import { fetchAppList } from '@/service/apps' import { useAppContext } from '@/context/app-context' import { NEED_REFRESH_APP_LIST_KEY } from '@/config' import { CheckModal } from '@/hooks/use-pay' -const getKey = (pageIndex: number, previousPageData: AppListResponse) => { - if (!pageIndex || previousPageData.has_more) - return { url: 'apps', params: { page: pageIndex + 1, limit: 30 } } +import TabSlider from '@/app/components/base/tab-slider' +import { SearchLg } from '@/app/components/base/icons/src/vender/line/general' +import { XCircle } from '@/app/components/base/icons/src/vender/solid/general' + +const getKey = ( + pageIndex: number, + previousPageData: AppListResponse, + activeTab: string, + keywords: string, +) => { + if (!pageIndex || previousPageData.has_more) { + const params: any = { url: 'apps', params: { page: pageIndex + 1, limit: 30, name: keywords } } + + if (activeTab !== 'all') + params.params.mode = activeTab + + return params + } return null } const Apps = () => { const { t } = useTranslation() const { isCurrentWorkspaceManager } = useAppContext() - const { data, isLoading, setSize, mutate } = useSWRInfinite(getKey, fetchAppList, { revalidateFirstPage: false }) + const [activeTab, setActiveTab] = useState('all') + const [keywords, setKeywords] = useState('') + const [searchKeywords, setSearchKeywords] = useState('') + + const { data, isLoading, setSize, mutate } = useSWRInfinite( + (pageIndex: number, previousPageData: AppListResponse) => getKey(pageIndex, previousPageData, activeTab, searchKeywords), + fetchAppList, + { revalidateFirstPage: false }, + ) + const anchorRef = useRef(null) + const options = [ + { value: 'all', text: t('app.types.all') }, + { value: 'chat', text: t('app.types.assistant') }, + { value: 'completion', text: t('app.types.completion') }, + ] useEffect(() => { document.title = `${t('app.title')} - Dify` @@ -34,24 +64,72 @@ const Apps = () => { let observer: IntersectionObserver | undefined if (anchorRef.current) { observer = new IntersectionObserver((entries) => { - if (entries[0].isIntersecting) - setSize(size => size + 1) + if (entries[0].isIntersecting && !isLoading) + setSize((size: number) => size + 1) }, { rootMargin: '100px' }) observer.observe(anchorRef.current) } return () => observer?.disconnect() }, [isLoading, setSize, anchorRef, mutate]) + const { run: handleSearch } = useDebounceFn(() => { + setSearchKeywords(keywords) + }, { wait: 500 }) + + const handleKeywordsChange = (value: string) => { + setKeywords(value) + handleSearch() + } + + const handleClear = () => { + handleKeywordsChange('') + } + return ( - <> -
+ <> +
+
+
+
+ { + handleKeywordsChange(e.target.value) + }} + autoComplete="off" + /> + { + keywords && ( +
+ +
+ ) + } +
+ + +
+ +
) } diff --git a/web/app/(commonLayout)/apps/NewAppDialog.tsx b/web/app/(commonLayout)/apps/NewAppDialog.tsx index 912bcd98dd..f157631de4 100644 --- a/web/app/(commonLayout)/apps/NewAppDialog.tsx +++ b/web/app/(commonLayout)/apps/NewAppDialog.tsx @@ -15,10 +15,11 @@ import type { AppMode } from '@/types/app' import { ToastContext } from '@/app/components/base/toast' import { createApp, fetchAppTemplates } from '@/service/apps' import AppIcon from '@/app/components/base/app-icon' -import AppsContext from '@/context/app-context' +import AppsContext, { useAppContext } from '@/context/app-context' import EmojiPicker from '@/app/components/base/emoji-picker' import { useProviderContext } from '@/context/provider-context' import AppsFull from '@/app/components/billing/apps-full-in-dialog' +import { AiText } from '@/app/components/base/icons/src/vender/solid/communication' type NewAppDialogProps = { show: boolean @@ -29,6 +30,8 @@ type NewAppDialogProps = { const NewAppDialog = ({ show, onSuccess, onClose }: NewAppDialogProps) => { const router = useRouter() const { notify } = useContext(ToastContext) + const { isCurrentWorkspaceManager } = useAppContext() + const { t } = useTranslation() const nameInputRef = useRef(null) @@ -90,7 +93,7 @@ const NewAppDialog = ({ show, onSuccess, onClose }: NewAppDialogProps) => { onClose() notify({ type: 'success', message: t('app.newApp.appCreated') }) mutateApps() - router.push(`/app/${app.id}/overview`) + router.push(`/app/${app.id}/${isCurrentWorkspaceManager ? 'configuration' : 'overview'}`) } catch (e) { notify({ type: 'error', message: t('app.newApp.appCreateFailed') }) @@ -119,13 +122,6 @@ const NewAppDialog = ({ show, onSuccess, onClose }: NewAppDialogProps) => { } > -

{t('app.newApp.captionName')}

- -
- { setShowEmojiPicker(true) }} className='cursor-pointer' icon={emoji.icon} background={emoji.icon_background} /> - -
-

{t('app.newApp.captionAppType')}

@@ -141,29 +137,9 @@ const NewAppDialog = ({ show, onSuccess, onClose }: NewAppDialogProps) => { )}
- {isWithTemplate - ? ( -
    - {templates?.data?.map((template, index) => ( -
  • setSelectedTemplateIndex(index)} - > -
    - -
    -
    {template.name}
    -
    -
    -
    {template.model_config?.pre_prompt}
    - - {/* */} -
  • - ))} -
- ) - : ( + + {!isWithTemplate && ( + ( <>
  • {
    {t('app.newApp.chatApp')}
-
{t('app.newApp.chatAppIntro')}
-
+
{t('app.newApp.chatAppIntro')}
+ {/* +
*/}
  • { >
    - + {/* */} +
    {t('app.newApp.completeApp')}
    -
    {t('app.newApp.completeAppIntro')}
    - +
    {t('app.newApp.completeAppIntro')}
  • -
    - setIsWithTemplate(true)} - > - {t('app.newApp.showTemplates')} - -
    + - )} + ) + )} + + {isWithTemplate && ( +
      + {templates?.data?.map((template, index) => ( +
    • setSelectedTemplateIndex(index)} + > +
      + +
      +
      {template.name}
      +
      +
      +
      {template.model_config?.pre_prompt}
      +
      + +
      +
    • + ))} +
    + )} + +
    +

    {t('app.newApp.captionName')}

    +
    + { setShowEmojiPicker(true) }} className='cursor-pointer' icon={emoji.icon} background={emoji.icon_background} /> + +
    +
    + + { + !isWithTemplate && ( +
    + setIsWithTemplate(true)} + > + {t('app.newApp.showTemplates')} + +
    + ) + } + {isAppsFull && } diff --git a/web/app/(commonLayout)/apps/page.tsx b/web/app/(commonLayout)/apps/page.tsx index e2e774bec7..30c2ef9e57 100644 --- a/web/app/(commonLayout)/apps/page.tsx +++ b/web/app/(commonLayout)/apps/page.tsx @@ -9,7 +9,7 @@ const AppList = async () => { const { t } = await translate(locale, 'app') return ( -
    +