From 1b940e7daa748e549ac2f928623170fa16ef1810 Mon Sep 17 00:00:00 2001 From: kurokobo Date: Thu, 9 Jan 2025 01:04:58 +0900 Subject: [PATCH 01/14] feat: add ci job to test template for docker compose (#12514) --- .github/workflows/style.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index b5e63a8870..12213380bd 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -82,6 +82,33 @@ jobs: if: steps.changed-files.outputs.any_changed == 'true' run: yarn run lint + docker-compose-template: + name: Docker Compose Template + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Check changed files + id: changed-files + uses: tj-actions/changed-files@v45 + with: + files: | + docker/generate_docker_compose + docker/.env.example + docker/docker-compose-template.yaml + docker/docker-compose.yaml + + - name: Generate Docker Compose + if: steps.changed-files.outputs.any_changed == 'true' + run: | + cd docker + ./generate_docker_compose + + - name: Check for changes + if: steps.changed-files.outputs.any_changed == 'true' + run: git diff --exit-code superlinter: name: SuperLinter From b4c1c2f73100c942090bff951d8c5125e55fa4ec Mon Sep 17 00:00:00 2001 From: Hiroshi Fujita Date: Thu, 9 Jan 2025 11:21:22 +0900 Subject: [PATCH 02/14] fix: Reverse sync docker-compose-template.yaml (#12509) --- docker/.env.example | 2 +- docker/docker-compose-template.yaml | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/docker/.env.example b/docker/.env.example index 333050a892..b21bdc7085 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -513,7 +513,7 @@ TENCENT_VECTOR_DB_SHARD=1 TENCENT_VECTOR_DB_REPLICAS=2 # ElasticSearch configuration, only available when VECTOR_STORE is `elasticsearch` -ELASTICSEARCH_HOST=elasticsearch +ELASTICSEARCH_HOST=0.0.0.0 ELASTICSEARCH_PORT=9200 ELASTICSEARCH_USERNAME=elastic ELASTICSEARCH_PASSWORD=elastic diff --git a/docker/docker-compose-template.yaml b/docker/docker-compose-template.yaml index c96b0538ca..6d70f14424 100644 --- a/docker/docker-compose-template.yaml +++ b/docker/docker-compose-template.yaml @@ -409,7 +409,7 @@ services: milvus-standalone: container_name: milvus-standalone - image: milvusdb/milvus:v2.3.1 + image: milvusdb/milvus:v2.5.0-beta profiles: - milvus command: [ 'milvus', 'run', 'standalone' ] @@ -493,20 +493,28 @@ services: container_name: elasticsearch profiles: - elasticsearch + - elasticsearch-ja restart: always volumes: + - ./elasticsearch/docker-entrypoint.sh:/docker-entrypoint-mount.sh - dify_es01_data:/usr/share/elasticsearch/data environment: ELASTIC_PASSWORD: ${ELASTICSEARCH_PASSWORD:-elastic} + VECTOR_STORE: ${VECTOR_STORE:-} cluster.name: dify-es-cluster node.name: dify-es0 discovery.type: single-node - xpack.license.self_generated.type: trial + xpack.license.self_generated.type: basic xpack.security.enabled: 'true' xpack.security.enrollment.enabled: 'false' xpack.security.http.ssl.enabled: 'false' ports: - ${ELASTICSEARCH_PORT:-9200}:9200 + deploy: + resources: + limits: + memory: 2g + entrypoint: [ 'sh', '-c', "sh /docker-entrypoint-mount.sh" ] healthcheck: test: [ 'CMD', 'curl', '-s', 'http://localhost:9200/_cluster/health?pretty' ] interval: 30s From 018e32e35510c4dace16f20e9b243e177fea4c6d Mon Sep 17 00:00:00 2001 From: Joel Date: Thu, 9 Jan 2025 10:49:15 +0800 Subject: [PATCH 03/14] fix: installed not clear countdown --- .../install-from-marketplace/index.tsx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/web/app/components/plugins/install-plugin/install-from-marketplace/index.tsx b/web/app/components/plugins/install-plugin/install-from-marketplace/index.tsx index 72262894db..045cdde047 100644 --- a/web/app/components/plugins/install-plugin/install-from-marketplace/index.tsx +++ b/web/app/components/plugins/install-plugin/install-from-marketplace/index.tsx @@ -44,7 +44,12 @@ const InstallFromMarketplace: React.FC = ({ countDownFoldIntoAnim, } = useFoldAnimInto(onClose) - const [isInstalling, setIsInstalling] = useState(false) + const [isInstalling, doSetIsInstalling] = useState(false) + const setIsInstalling = useCallback((isInstalling: boolean) => { + if (!isInstalling) + clearCountDown() + doSetIsInstalling(isInstalling) + }, [clearCountDown]) const foldAnimInto = useCallback(() => { if (isInstalling) { @@ -57,7 +62,7 @@ const InstallFromMarketplace: React.FC = ({ const handleStartToInstall = useCallback(() => { setIsInstalling(true) countDownFoldIntoAnim() - }, [countDownFoldIntoAnim]) + }, [countDownFoldIntoAnim, setIsInstalling]) const getTitle = useCallback(() => { if (isBundle && step === InstallStep.installed) @@ -73,14 +78,14 @@ const InstallFromMarketplace: React.FC = ({ setStep(InstallStep.installed) refreshPluginList(manifest) setIsInstalling(false) - }, [manifest, refreshPluginList]) + }, [manifest, refreshPluginList, setIsInstalling]) const handleFailed = useCallback((errorMsg?: string) => { setStep(InstallStep.installFailed) setIsInstalling(false) if (errorMsg) setErrorMsg(errorMsg) - }, []) + }, [setIsInstalling]) return ( Date: Thu, 9 Jan 2025 11:04:23 +0800 Subject: [PATCH 04/14] chore: all hide logic to hooks --- .../install-plugin/hooks/use-hide-logic.ts | 40 +++++++++++++++++++ .../install-from-marketplace/index.tsx | 30 +++----------- 2 files changed, 45 insertions(+), 25 deletions(-) create mode 100644 web/app/components/plugins/install-plugin/hooks/use-hide-logic.ts diff --git a/web/app/components/plugins/install-plugin/hooks/use-hide-logic.ts b/web/app/components/plugins/install-plugin/hooks/use-hide-logic.ts new file mode 100644 index 0000000000..e5d2d1883a --- /dev/null +++ b/web/app/components/plugins/install-plugin/hooks/use-hide-logic.ts @@ -0,0 +1,40 @@ +import { useCallback, useState } from 'react' +import useFoldAnimInto from './use-fold-anim-into' + +const useHideLogic = (onClose: () => void) => { + const { + modalClassName, + foldIntoAnim: doFoldAnimInto, + clearCountDown, + countDownFoldIntoAnim, + } = useFoldAnimInto(onClose) + + const [isInstalling, doSetIsInstalling] = useState(false) + const setIsInstalling = useCallback((isInstalling: boolean) => { + if (!isInstalling) + clearCountDown() + doSetIsInstalling(isInstalling) + }, [clearCountDown]) + + const foldAnimInto = useCallback(() => { + if (isInstalling) { + doFoldAnimInto() + return + } + onClose() + }, [doFoldAnimInto, isInstalling, onClose]) + + const handleStartToInstall = useCallback(() => { + setIsInstalling(true) + countDownFoldIntoAnim() + }, [countDownFoldIntoAnim, setIsInstalling]) + + return { + modalClassName, + foldAnimInto, + setIsInstalling, + handleStartToInstall, + } +} + +export default useHideLogic diff --git a/web/app/components/plugins/install-plugin/install-from-marketplace/index.tsx b/web/app/components/plugins/install-plugin/install-from-marketplace/index.tsx index 045cdde047..6ce0bb14ed 100644 --- a/web/app/components/plugins/install-plugin/install-from-marketplace/index.tsx +++ b/web/app/components/plugins/install-plugin/install-from-marketplace/index.tsx @@ -9,8 +9,8 @@ import Installed from '../base/installed' import { useTranslation } from 'react-i18next' import useRefreshPluginList from '../hooks/use-refresh-plugin-list' import ReadyToInstallBundle from '../install-bundle/ready-to-install' -import useFoldAnimInto from '../hooks/use-fold-anim-into' import cn from '@/utils/classnames' +import useHideLogic from '../hooks/use-hide-logic' const i18nPrefix = 'plugin.installModal' @@ -39,30 +39,10 @@ const InstallFromMarketplace: React.FC = ({ const { modalClassName, - foldIntoAnim: doFoldAnimInto, - clearCountDown, - countDownFoldIntoAnim, - } = useFoldAnimInto(onClose) - - const [isInstalling, doSetIsInstalling] = useState(false) - const setIsInstalling = useCallback((isInstalling: boolean) => { - if (!isInstalling) - clearCountDown() - doSetIsInstalling(isInstalling) - }, [clearCountDown]) - - const foldAnimInto = useCallback(() => { - if (isInstalling) { - doFoldAnimInto() - return - } - onClose() - }, [doFoldAnimInto, isInstalling, onClose]) - - const handleStartToInstall = useCallback(() => { - setIsInstalling(true) - countDownFoldIntoAnim() - }, [countDownFoldIntoAnim, setIsInstalling]) + foldAnimInto, + setIsInstalling, + handleStartToInstall, + } = useHideLogic(onClose) const getTitle = useCallback(() => { if (isBundle && step === InstallStep.installed) From 192af8df9f8519dbb2b307a26d3747acb8bfa222 Mon Sep 17 00:00:00 2001 From: Joel Date: Thu, 9 Jan 2025 11:16:33 +0800 Subject: [PATCH 05/14] feat: local and bundle support hide anim --- .../install-plugin/install-bundle/index.tsx | 15 +++++++++++++-- .../install-bundle/ready-to-install.tsx | 8 +++++++- .../install-bundle/steps/install.tsx | 3 +++ .../install-from-local-package/index.tsx | 17 +++++++++++++++-- .../ready-to-install.tsx | 11 +++++++++-- .../install-from-marketplace/index.tsx | 2 ++ 6 files changed, 49 insertions(+), 7 deletions(-) diff --git a/web/app/components/plugins/install-plugin/install-bundle/index.tsx b/web/app/components/plugins/install-plugin/install-bundle/index.tsx index 035de8b781..84750d65ad 100644 --- a/web/app/components/plugins/install-plugin/install-bundle/index.tsx +++ b/web/app/components/plugins/install-plugin/install-bundle/index.tsx @@ -6,6 +6,8 @@ import { InstallStep } from '../../types' import type { Dependency } from '../../types' import ReadyToInstall from './ready-to-install' import { useTranslation } from 'react-i18next' +import useHideLogic from '../hooks/use-hide-logic' +import cn from '@/utils/classnames' const i18nPrefix = 'plugin.installModal' @@ -30,6 +32,13 @@ const InstallBundle: FC = ({ const { t } = useTranslation() const [step, setStep] = useState(installType === InstallType.fromMarketplace ? InstallStep.readyToInstall : InstallStep.uploading) + const { + modalClassName, + foldAnimInto, + setIsInstalling, + handleStartToInstall, + } = useHideLogic(onClose) + const getTitle = useCallback(() => { if (step === InstallStep.uploadFailed) return t(`${i18nPrefix}.uploadFailed`) @@ -42,8 +51,8 @@ const InstallBundle: FC = ({ return (
@@ -54,6 +63,8 @@ const InstallBundle: FC = ({ diff --git a/web/app/components/plugins/install-plugin/install-bundle/ready-to-install.tsx b/web/app/components/plugins/install-plugin/install-bundle/ready-to-install.tsx index b534f0c6b9..63c0b5b07e 100644 --- a/web/app/components/plugins/install-plugin/install-bundle/ready-to-install.tsx +++ b/web/app/components/plugins/install-plugin/install-bundle/ready-to-install.tsx @@ -9,6 +9,8 @@ import type { Dependency, InstallStatusResponse, Plugin } from '../../types' type Props = { step: InstallStep onStepChange: (step: InstallStep) => void, + onStartToInstall: () => void + setIsInstalling: (isInstalling: boolean) => void allPlugins: Dependency[] onClose: () => void isFromMarketPlace?: boolean @@ -17,6 +19,8 @@ type Props = { const ReadyToInstall: FC = ({ step, onStepChange, + onStartToInstall, + setIsInstalling, allPlugins, onClose, isFromMarketPlace, @@ -27,13 +31,15 @@ const ReadyToInstall: FC = ({ setInstallStatus(installStatus) setInstalledPlugins(plugins) onStepChange(InstallStep.installed) - }, [onStepChange]) + setIsInstalling(false) + }, [onStepChange, setIsInstalling]) return ( <> {step === InstallStep.readyToInstall && ( diff --git a/web/app/components/plugins/install-plugin/install-bundle/steps/install.tsx b/web/app/components/plugins/install-plugin/install-bundle/steps/install.tsx index a1a17f2df1..c70e2759d0 100644 --- a/web/app/components/plugins/install-plugin/install-bundle/steps/install.tsx +++ b/web/app/components/plugins/install-plugin/install-bundle/steps/install.tsx @@ -12,6 +12,7 @@ const i18nPrefix = 'plugin.installModal' type Props = { allPlugins: Dependency[] + onStartToInstall?: () => void onInstalled: (plugins: Plugin[], installStatus: InstallStatusResponse[]) => void onCancel: () => void isFromMarketPlace?: boolean @@ -20,6 +21,7 @@ type Props = { const Install: FC = ({ allPlugins, + onStartToInstall, onInstalled, onCancel, isFromMarketPlace, @@ -65,6 +67,7 @@ const Install: FC = ({ }, }) const handleInstall = () => { + onStartToInstall?.() installOrUpdate({ payload: allPlugins.filter((_d, index) => selectedIndexes.includes(index)), plugin: selectedPlugins, diff --git a/web/app/components/plugins/install-plugin/install-from-local-package/index.tsx b/web/app/components/plugins/install-plugin/install-from-local-package/index.tsx index c126a38a1d..b37ab60079 100644 --- a/web/app/components/plugins/install-plugin/install-from-local-package/index.tsx +++ b/web/app/components/plugins/install-plugin/install-from-local-package/index.tsx @@ -9,6 +9,8 @@ import { useTranslation } from 'react-i18next' import useGetIcon from '@/app/components/plugins/install-plugin/base/use-get-icon' import ReadyToInstallPackage from './ready-to-install' import ReadyToInstallBundle from '../install-bundle/ready-to-install' +import useHideLogic from '../hooks/use-hide-logic' +import cn from '@/utils/classnames' const i18nPrefix = 'plugin.installModal' @@ -31,6 +33,13 @@ const InstallFromLocalPackage: React.FC = ({ const isBundle = file.name.endsWith('.difybndl') const [dependencies, setDependencies] = useState([]) + const { + modalClassName, + foldAnimInto, + setIsInstalling, + handleStartToInstall, + } = useHideLogic(onClose) + const getTitle = useCallback(() => { if (step === InstallStep.uploadFailed) return t(`${i18nPrefix}.uploadFailed`) @@ -76,8 +85,8 @@ const InstallFromLocalPackage: React.FC = ({ return (
@@ -99,6 +108,8 @@ const InstallFromLocalPackage: React.FC = ({ @@ -106,6 +117,8 @@ const InstallFromLocalPackage: React.FC = ({ void, + onStartToInstall: () => void + setIsInstalling: (isInstalling: boolean) => void onClose: () => void uniqueIdentifier: string | null, manifest: PluginDeclaration | null, @@ -20,6 +22,8 @@ type Props = { const ReadyToInstall: FC = ({ step, onStepChange, + onStartToInstall, + setIsInstalling, onClose, uniqueIdentifier, manifest, @@ -31,13 +35,15 @@ const ReadyToInstall: FC = ({ const handleInstalled = useCallback(() => { onStepChange(InstallStep.installed) refreshPluginList(manifest) - }, [manifest, onStepChange, refreshPluginList]) + setIsInstalling(false) + }, [manifest, onStepChange, refreshPluginList, setIsInstalling]) const handleFailed = useCallback((errorMsg?: string) => { onStepChange(InstallStep.installFailed) + setIsInstalling(false) if (errorMsg) onError(errorMsg) - }, [onError, onStepChange]) + }, [onError, onStepChange, setIsInstalling]) return ( <> @@ -49,6 +55,7 @@ const ReadyToInstall: FC = ({ onCancel={onClose} onInstalled={handleInstalled} onFailed={handleFailed} + onStartToInstall={onStartToInstall} /> ) } diff --git a/web/app/components/plugins/install-plugin/install-from-marketplace/index.tsx b/web/app/components/plugins/install-plugin/install-from-marketplace/index.tsx index 6ce0bb14ed..a5ce01d041 100644 --- a/web/app/components/plugins/install-plugin/install-from-marketplace/index.tsx +++ b/web/app/components/plugins/install-plugin/install-from-marketplace/index.tsx @@ -85,6 +85,8 @@ const InstallFromMarketplace: React.FC = ({ Date: Thu, 9 Jan 2025 11:29:48 +0800 Subject: [PATCH 06/14] feat: github install add anim --- .../install-from-github/index.tsx | 22 ++++++++++++++----- .../install-from-github/steps/loaded.tsx | 4 ++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/web/app/components/plugins/install-plugin/install-from-github/index.tsx b/web/app/components/plugins/install-plugin/install-from-github/index.tsx index 71f81f0ffa..933934e9ba 100644 --- a/web/app/components/plugins/install-plugin/install-from-github/index.tsx +++ b/web/app/components/plugins/install-plugin/install-from-github/index.tsx @@ -16,6 +16,8 @@ import Loaded from './steps/loaded' import useGetIcon from '@/app/components/plugins/install-plugin/base/use-get-icon' import { useTranslation } from 'react-i18next' import useRefreshPluginList from '../hooks/use-refresh-plugin-list' +import cn from '@/utils/classnames' +import useHideLogic from '../hooks/use-hide-logic' const i18nPrefix = 'plugin.installFromGitHub' @@ -31,6 +33,13 @@ const InstallFromGitHub: React.FC = ({ updatePayload, on const { fetchReleases } = useGitHubReleases() const { refreshPluginList } = useRefreshPluginList() + const { + modalClassName, + foldAnimInto, + setIsInstalling, + handleStartToInstall, + } = useHideLogic(onClose) + const [state, setState] = useState({ step: updatePayload ? InstallStepFromGitHub.selectPackage : InstallStepFromGitHub.setUrl, repoUrl: updatePayload?.originalPackageInfo?.repo @@ -115,14 +124,16 @@ const InstallFromGitHub: React.FC = ({ updatePayload, on const handleInstalled = useCallback(() => { setState(prevState => ({ ...prevState, step: InstallStepFromGitHub.installed })) refreshPluginList(manifest) + setIsInstalling(false) onSuccess() - }, [manifest, onSuccess, refreshPluginList]) + }, [manifest, onSuccess, refreshPluginList, setIsInstalling]) const handleFailed = useCallback((errorMsg?: string) => { setState(prevState => ({ ...prevState, step: InstallStepFromGitHub.installFailed })) + setIsInstalling(false) if (errorMsg) setErrorMsg(errorMsg) - }, []) + }, [setIsInstalling]) const handleBack = () => { setState((prevState) => { @@ -140,9 +151,9 @@ const InstallFromGitHub: React.FC = ({ updatePayload, on return (
@@ -195,6 +206,7 @@ const InstallFromGitHub: React.FC = ({ updatePayload, on selectedVersion={state.selectedVersion} selectedPackage={state.selectedPackage} onBack={handleBack} + onStartToInstall={handleStartToInstall} onInstalled={handleInstalled} onFailed={handleFailed} /> diff --git a/web/app/components/plugins/install-plugin/install-from-github/steps/loaded.tsx b/web/app/components/plugins/install-plugin/install-from-github/steps/loaded.tsx index e2de988a74..b1bcf01251 100644 --- a/web/app/components/plugins/install-plugin/install-from-github/steps/loaded.tsx +++ b/web/app/components/plugins/install-plugin/install-from-github/steps/loaded.tsx @@ -23,6 +23,7 @@ type LoadedProps = { selectedVersion: string selectedPackage: string onBack: () => void + onStartToInstall?: () => void onInstalled: () => void onFailed: (message?: string) => void } @@ -37,6 +38,7 @@ const Loaded: React.FC = ({ selectedVersion, selectedPackage, onBack, + onStartToInstall, onInstalled, onFailed, }) => { @@ -59,11 +61,13 @@ const Loaded: React.FC = ({ useEffect(() => { if (hasInstalled && uniqueIdentifier === installedInfoPayload.uniqueIdentifier) onInstalled() + // eslint-disable-next-line react-hooks/exhaustive-deps }, [hasInstalled]) const handleInstall = async () => { if (isInstalling) return setIsInstalling(true) + onStartToInstall?.() try { const { owner, repo } = parseGitHubUrl(repoUrl) From 297b5280f0dfaae22390e5a60f43a93916501801 Mon Sep 17 00:00:00 2001 From: JzoNg Date: Thu, 9 Jan 2025 09:56:11 +0800 Subject: [PATCH 07/14] tracing modal & config --- .../[appId]/overview/tracing/config-popup.tsx | 22 +++++++++---------- .../[appId]/overview/tracing/field.tsx | 4 ++-- .../tracing/provider-config-modal.tsx | 19 ++++++++-------- .../overview/tracing/provider-panel.tsx | 21 +++++++++++------- web/app/components/base/switch/index.tsx | 2 +- web/context/app-context.tsx | 2 +- 6 files changed, 38 insertions(+), 32 deletions(-) diff --git a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/config-popup.tsx b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/config-popup.tsx index 8e3d8f9ec6..571b4fd3a6 100644 --- a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/config-popup.tsx +++ b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/config-popup.tsx @@ -11,6 +11,8 @@ import ProviderConfigModal from './provider-config-modal' import Indicator from '@/app/components/header/indicator' import Switch from '@/app/components/base/switch' import Tooltip from '@/app/components/base/tooltip' +import Divider from '@/app/components/base/divider' +import cn from '@/utils/classnames' const I18N_PREFIX = 'app.tracing' @@ -77,7 +79,6 @@ const ConfigPopup: FC = ({ className='ml-3' defaultValue={enabled} onChange={onStatusChange} - size='l' disabled={providerAllNotConfigured} /> ) @@ -106,15 +107,15 @@ const ConfigPopup: FC = ({ ) return ( -
+
-
{t(`${I18N_PREFIX}.tracing`)}
+
{t(`${I18N_PREFIX}.tracing`)}
-
+
{t(`${I18N_PREFIX}.${enabled ? 'enabled' : 'disabled'}`)}
{!readOnly && ( @@ -130,19 +131,18 @@ const ConfigPopup: FC = ({ : switchContent} )} -
-
+
{t(`${I18N_PREFIX}.tracingDescription`)}
-
-
+ +
{(providerAllConfigured || providerAllNotConfigured) ? ( <> -
{t(`${I18N_PREFIX}.configProviderTitle.${providerAllConfigured ? 'configured' : 'notConfigured'}`)}
+
{t(`${I18N_PREFIX}.configProviderTitle.${providerAllConfigured ? 'configured' : 'notConfigured'}`)}
{langSmithPanel} {langfusePanel} @@ -151,11 +151,11 @@ const ConfigPopup: FC = ({ ) : ( <> -
{t(`${I18N_PREFIX}.configProviderTitle.configured`)}
+
{t(`${I18N_PREFIX}.configProviderTitle.configured`)}
{langSmithConfig ? langSmithPanel : langfusePanel}
-
{t(`${I18N_PREFIX}.configProviderTitle.moreProvider`)}
+
{t(`${I18N_PREFIX}.configProviderTitle.moreProvider`)}
{!langSmithConfig ? langSmithPanel : langfusePanel}
diff --git a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/field.tsx b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/field.tsx index 917df92451..84c48a6dde 100644 --- a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/field.tsx +++ b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/field.tsx @@ -4,7 +4,7 @@ import React from 'react' import cn from '@/utils/classnames' import Input from '@/app/components/base/input' -interface Props { +type Props = { className?: string label: string labelClassName?: string @@ -26,7 +26,7 @@ const Field: FC = ({ return (
-
{label}
+
{label}
{isRequired && *}
= ({ ? ( -
-
+
+
-
{t(`${I18N_PREFIX}.title`)}{t(`app.tracing.${type}.title`)}
+
{t(`${I18N_PREFIX}.title`)}{t(`app.tracing.${type}.title`)}
@@ -230,16 +231,16 @@ const ProviderConfigModal: FC = ({ {isEdit && ( <> -
+ )}
-
-
- +
+
+ {t('common.modelProvider.encrypted.front')} = ({ }, [hasConfigured, isChosen, onChoose, readOnly]) return (
- {isChosen &&
{t(`${I18N_PREFIX}.inUse`)}
} + {isChosen &&
{t(`${I18N_PREFIX}.inUse`)}
}
{!readOnly && (
{hasConfigured && ( -
+
{t(`${I18N_PREFIX}.view`)}
)}
- +
{t(`${I18N_PREFIX}.config`)}
)} -
-
+
{t(`${I18N_PREFIX}.${type}.description`)}
diff --git a/web/app/components/base/switch/index.tsx b/web/app/components/base/switch/index.tsx index fd3e5ef4e7..48e5c0cd8c 100644 --- a/web/app/components/base/switch/index.tsx +++ b/web/app/components/base/switch/index.tsx @@ -3,7 +3,7 @@ import React, { useEffect, useState } from 'react' import { Switch as OriginalSwitch } from '@headlessui/react' import classNames from '@/utils/classnames' -interface SwitchProps { +type SwitchProps = { onChange?: (value: boolean) => void size?: 'sm' | 'md' | 'lg' | 'l' defaultValue?: boolean diff --git a/web/context/app-context.tsx b/web/context/app-context.tsx index 7addfb83d4..25a313a76b 100644 --- a/web/context/app-context.tsx +++ b/web/context/app-context.tsx @@ -127,7 +127,7 @@ export const AppContextProvider: FC = ({ children }) => setCurrentWorkspace(currentWorkspaceResponse) }, [currentWorkspaceResponse]) - const [theme, setTheme] = useState(Theme.light) + const [theme, setTheme] = useState(Theme.dark) const handleSetTheme = useCallback((theme: Theme) => { setTheme(theme) globalThis.document.documentElement.setAttribute('data-theme', theme) From eaf1177cd4a2c57acd9ff7f62247ff1c6c406f2f Mon Sep 17 00:00:00 2001 From: JzoNg Date: Thu, 9 Jan 2025 11:35:19 +0800 Subject: [PATCH 08/14] dark mode of overview card view --- .../app/overview/apikey-info-panel/index.tsx | 10 +-- .../apikey-info-panel/progress/index.tsx | 29 --------- .../progress/style.module.css | 16 ----- web/app/components/app/overview/appCard.tsx | 49 ++++++--------- .../components/base/copy-feedback/index.tsx | 23 +++---- web/app/components/base/qrcode/index.tsx | 32 +++++----- .../components/base/qrcode/style.module.css | 62 ------------------- .../develop/secret-key/secret-key-button.tsx | 2 +- web/context/app-context.tsx | 2 +- 9 files changed, 53 insertions(+), 172 deletions(-) delete mode 100644 web/app/components/app/overview/apikey-info-panel/progress/index.tsx delete mode 100644 web/app/components/app/overview/apikey-info-panel/progress/style.module.css delete mode 100644 web/app/components/base/qrcode/style.module.css diff --git a/web/app/components/app/overview/apikey-info-panel/index.tsx b/web/app/components/app/overview/apikey-info-panel/index.tsx index 661a88e823..2ca098a313 100644 --- a/web/app/components/app/overview/apikey-info-panel/index.tsx +++ b/web/app/components/app/overview/apikey-info-panel/index.tsx @@ -27,8 +27,8 @@ const APIKeyInfoPanel: FC = () => { return null return ( -
-
+
+
{isCloud && } {isCloud ? ( @@ -42,11 +42,11 @@ const APIKeyInfoPanel: FC = () => { )}
{isCloud && ( -
{t(`appOverview.apiKeyInfo.cloud.${'trial'}.description`)}
+
{t(`appOverview.apiKeyInfo.cloud.${'trial'}.description`)}
)}
) diff --git a/web/app/components/app/overview/apikey-info-panel/progress/index.tsx b/web/app/components/app/overview/apikey-info-panel/progress/index.tsx deleted file mode 100644 index cc8356e754..0000000000 --- a/web/app/components/app/overview/apikey-info-panel/progress/index.tsx +++ /dev/null @@ -1,29 +0,0 @@ -'use client' -import type { FC } from 'react' -import React from 'react' -import s from './style.module.css' -import cn from '@/utils/classnames' - -export type IProgressProps = { - className?: string - value: number // percent -} - -const Progress: FC = ({ - className, - value, -}) => { - const exhausted = value === 100 - return ( -
-
- {Array.from({ length: 10 }).fill(0).map((i, k) => ( -
- ))} -
- ) -} -export default React.memo(Progress) diff --git a/web/app/components/app/overview/apikey-info-panel/progress/style.module.css b/web/app/components/app/overview/apikey-info-panel/progress/style.module.css deleted file mode 100644 index 94c3ef45cf..0000000000 --- a/web/app/components/app/overview/apikey-info-panel/progress/style.module.css +++ /dev/null @@ -1,16 +0,0 @@ -.bar { - background: linear-gradient(90deg, rgba(41, 112, 255, 0.9) 0%, rgba(21, 94, 239, 0.9) 100%); -} - -.bar-error { - background: linear-gradient(90deg, rgba(240, 68, 56, 0.72) 0%, rgba(217, 45, 32, 0.9) 100%); -} - -.bar-item { - width: 10%; - border-right: 1px solid rgba(255, 255, 255, 0.5); -} - -.bar-item:last-of-type { - border-right: 0; -} \ No newline at end of file diff --git a/web/app/components/app/overview/appCard.tsx b/web/app/components/app/overview/appCard.tsx index f9f5c1fbff..99e847f8b6 100644 --- a/web/app/components/app/overview/appCard.tsx +++ b/web/app/components/app/overview/appCard.tsx @@ -1,6 +1,9 @@ 'use client' import type { HTMLProps } from 'react' import React, { useMemo, useState } from 'react' +import { + RiLoopLeftLine, +} from '@remixicon/react' import { Cog8ToothIcon, DocumentTextIcon, @@ -16,24 +19,25 @@ import style from './style.module.css' import type { ConfigParams } from './settings' import Tooltip from '@/app/components/base/tooltip' import AppBasic from '@/app/components/app-sidebar/basic' -import { asyncRunSafe, randomString } from '@/utils' +import { asyncRunSafe } from '@/utils' import Button from '@/app/components/base/button' import Tag from '@/app/components/base/tag' import Switch from '@/app/components/base/switch' import Divider from '@/app/components/base/divider' import CopyFeedback from '@/app/components/base/copy-feedback' +import ActionButton from '@/app/components/base/action-button' import Confirm from '@/app/components/base/confirm' import ShareQRCode from '@/app/components/base/qrcode' import SecretKeyButton from '@/app/components/develop/secret-key/secret-key-button' import type { AppDetailResponse } from '@/models/app' import { useAppContext } from '@/context/app-context' import type { AppSSO } from '@/types/app' +import cn from '@/utils/classnames' export type IAppCardProps = { className?: string appInfo: AppDetailResponse & Partial cardType?: 'api' | 'webapp' - customBgColor?: string onChangeStatus: (val: boolean) => Promise onSaveSiteConfig?: (params: ConfigParams) => Promise onGenerateCode?: () => Promise @@ -46,7 +50,6 @@ const EmbedIcon = ({ className = '' }: HTMLProps) => { function AppCard({ appInfo, cardType = 'webapp', - customBgColor, onChangeStatus, onSaveSiteConfig, onGenerateCode, @@ -92,10 +95,6 @@ function AppCard({ const appUrl = `${app_base_url}/${appMode}/${access_token}` const apiUrl = appInfo?.api_base_url - let bgColor = 'bg-primary-50 bg-opacity-40' - if (cardType === 'api') - bgColor = 'bg-purple-50' - const genClickFuncByName = (opName: string) => { switch (opName) { case t('appOverview.overview.appInfo.preview'): @@ -133,11 +132,8 @@ function AppCard({ } return ( -
-
+
+
-
+
{isApp ? t('appOverview.overview.appInfo.accessibleAddress') : t('appOverview.overview.apiInfo.accessibleAddress')}
-
+
-
+
{isApp ? appUrl : apiUrl}
- - {isApp && } - + + {isApp && } + {/* button copy link/ button regenerate */} {showConfirmDelete && ( -
setShowConfirmDelete(true)} - > -
-
+ setShowConfirmDelete(true)}> + + )}
- {!isApp && } + {!isApp && } {OPERATIONS_MAP[cardType].map((op) => { const disabled = op.opName === t('appOverview.overview.appInfo.settings.entry') diff --git a/web/app/components/base/copy-feedback/index.tsx b/web/app/components/base/copy-feedback/index.tsx index ead1eb1d18..bc1cca5205 100644 --- a/web/app/components/base/copy-feedback/index.tsx +++ b/web/app/components/base/copy-feedback/index.tsx @@ -1,10 +1,15 @@ 'use client' import React, { useState } from 'react' import { useTranslation } from 'react-i18next' +import { + RiClipboardFill, + RiClipboardLine, +} from '@remixicon/react' import { debounce } from 'lodash-es' import copy from 'copy-to-clipboard' import copyStyle from './style.module.css' import Tooltip from '@/app/components/base/tooltip' +import ActionButton from '@/app/components/base/action-button' type Props = { content: string @@ -13,7 +18,7 @@ type Props = { const prefixEmbedded = 'appOverview.overview.appInfo.embedded' -const CopyFeedback = ({ content, className }: Props) => { +const CopyFeedback = ({ content }: Props) => { const { t } = useTranslation() const [isCopied, setIsCopied] = useState(false) @@ -34,19 +39,15 @@ const CopyFeedback = ({ content, className }: Props) => { : t(`${prefixEmbedded}.copy`)) || '' } > -
+
-
+ > + {isCopied && } + {!isCopied && } +
+ ) } diff --git a/web/app/components/base/qrcode/index.tsx b/web/app/components/base/qrcode/index.tsx index c5549192cf..08569a8c89 100644 --- a/web/app/components/base/qrcode/index.tsx +++ b/web/app/components/base/qrcode/index.tsx @@ -1,19 +1,20 @@ 'use client' import React, { useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' +import { + RiQrCodeLine, +} from '@remixicon/react' import { QRCodeCanvas as QRCode } from 'qrcode.react' -import QrcodeStyle from './style.module.css' +import ActionButton from '@/app/components/base/action-button' import Tooltip from '@/app/components/base/tooltip' -interface Props { +type Props = { content: string - selectorId: string - className?: string } const prefixEmbedded = 'appOverview.overview.appInfo.qrcode.title' -const ShareQRCode = ({ content, selectorId, className }: Props) => { +const ShareQRCode = ({ content }: Props) => { const { t } = useTranslation() const [isShow, setIsShow] = useState(false) const qrCodeRef = useRef(null) @@ -53,22 +54,21 @@ const ShareQRCode = ({ content, selectorId, className }: Props) => { -
-
+
+ + + {isShow && (
- -
-
{t('appOverview.overview.appInfo.qrcode.scan')}
-
·
-
{t('appOverview.overview.appInfo.qrcode.download')}
+ +
+
{t('appOverview.overview.appInfo.qrcode.scan')}
+
·
+
{t('appOverview.overview.appInfo.qrcode.download')}
)} diff --git a/web/app/components/base/qrcode/style.module.css b/web/app/components/base/qrcode/style.module.css deleted file mode 100644 index d84e5fa45c..0000000000 --- a/web/app/components/base/qrcode/style.module.css +++ /dev/null @@ -1,62 +0,0 @@ -.QrcodeIcon { - background-image: url(~@/app/components/develop/secret-key/assets/qrcode.svg); - background-position: center; - background-repeat: no-repeat; -} - -.QrcodeIcon:hover { - background-image: url(~@/app/components/develop/secret-key/assets/qrcode-hover.svg); - background-position: center; - background-repeat: no-repeat; -} - -.QrcodeIcon.show { - background-image: url(~@/app/components/develop/secret-key/assets/qrcode-hover.svg); - background-position: center; - background-repeat: no-repeat; -} - -.qrcodeimage { - position: relative; - object-fit: cover; -} -.scan { - margin: 0; - line-height: 1rem; - font-size: 0.75rem; -} -.download { - position: relative; - color: #155eef; - font-size: 0.75rem; - line-height: 1rem; -} -.text { - align-self: stretch; - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - white-space: nowrap; - gap: 4px; -} -.qrcodeform { - z-index: 50; - border: 0.5px solid #eaecf0; - display: flex; - flex-direction: column; - margin: 0 !important; - margin-top: 4px !important; - margin-left: -75px !important; - width: fit-content; - position: relative; - border-radius: 8px; - background-color: #fff; - box-shadow: 0 12px 16px -4px rgba(16, 24, 40, 0.08), - 0 4px 6px -2px rgba(16, 24, 40, 0.03); - overflow: hidden; - align-items: center; - justify-content: center; - padding: 15px; - gap: 8px; -} diff --git a/web/app/components/develop/secret-key/secret-key-button.tsx b/web/app/components/develop/secret-key/secret-key-button.tsx index dab319bab4..a9f2656392 100644 --- a/web/app/components/develop/secret-key/secret-key-button.tsx +++ b/web/app/components/develop/secret-key/secret-key-button.tsx @@ -23,7 +23,7 @@ const SecretKeyButton = ({ className, appId, iconCls, textCls }: ISecretKeyButto
-
{t('appApi.apiKey')}
+
{t('appApi.apiKey')}
setVisible(false)} appId={appId} /> diff --git a/web/context/app-context.tsx b/web/context/app-context.tsx index 25a313a76b..7addfb83d4 100644 --- a/web/context/app-context.tsx +++ b/web/context/app-context.tsx @@ -127,7 +127,7 @@ export const AppContextProvider: FC = ({ children }) => setCurrentWorkspace(currentWorkspaceResponse) }, [currentWorkspaceResponse]) - const [theme, setTheme] = useState(Theme.dark) + const [theme, setTheme] = useState(Theme.light) const handleSetTheme = useCallback((theme: Theme) => { setTheme(theme) globalThis.document.documentElement.setAttribute('data-theme', theme) From a7f0933e55b1ddbc1db164bf25f74c6cd0ed2971 Mon Sep 17 00:00:00 2001 From: Yi Date: Thu, 9 Jan 2025 11:52:44 +0800 Subject: [PATCH 09/14] chore: add checks in the url fetch step of the installFromGitHub --- .../install-from-github/index.tsx | 29 ++++++++++++++----- web/i18n/en-US/plugin.ts | 2 ++ web/i18n/zh-Hans/plugin.ts | 2 ++ 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/web/app/components/plugins/install-plugin/install-from-github/index.tsx b/web/app/components/plugins/install-plugin/install-from-github/index.tsx index 933934e9ba..7e43907564 100644 --- a/web/app/components/plugins/install-plugin/install-from-github/index.tsx +++ b/web/app/components/plugins/install-plugin/install-from-github/index.tsx @@ -86,13 +86,28 @@ const InstallFromGitHub: React.FC = ({ updatePayload, on }) return } - await fetchReleases(owner, repo).then((fetchedReleases) => { - setState(prevState => ({ - ...prevState, - releases: fetchedReleases, - step: InstallStepFromGitHub.selectPackage, - })) - }) + try { + const fetchedReleases = await fetchReleases(owner, repo) + if (fetchedReleases.length > 0) { + setState(prevState => ({ + ...prevState, + releases: fetchedReleases, + step: InstallStepFromGitHub.selectPackage, + })) + } + else { + Toast.notify({ + type: 'error', + message: t('plugin.error.noReleasesFound'), + }) + } + } + catch (error) { + Toast.notify({ + type: 'error', + message: t('plugin.error.fetchReleasesError'), + }) + } } const handleError = (e: any, isInstall: boolean) => { diff --git a/web/i18n/en-US/plugin.ts b/web/i18n/en-US/plugin.ts index 725450d61d..d5bc3ecbf8 100644 --- a/web/i18n/en-US/plugin.ts +++ b/web/i18n/en-US/plugin.ts @@ -172,6 +172,8 @@ const translation = { }, error: { inValidGitHubUrl: 'Invalid GitHub URL. Please enter a valid URL in the format: https://github.com/owner/repo', + fetchReleasesError: 'Unable to retrieve releases. Please try again later.', + noReleasesFound: 'No releases found. Please check the GitHub repository or the input URL.', }, marketplace: { empower: 'Empower your AI development', diff --git a/web/i18n/zh-Hans/plugin.ts b/web/i18n/zh-Hans/plugin.ts index fc1a052e39..50219dc322 100644 --- a/web/i18n/zh-Hans/plugin.ts +++ b/web/i18n/zh-Hans/plugin.ts @@ -172,6 +172,8 @@ const translation = { }, error: { inValidGitHubUrl: '无效的 GitHub URL。请输入格式为 https://github.com/owner/repo 的有效 URL', + fetchReleasesError: '无法获取发布版本。请稍后再试。', + noReleasesFound: '未找到发布版本。请检查 GitHub 仓库或输入的 URL。', }, marketplace: { empower: '助力您的 AI 开发', From eff6a5596051f17e840074addf142bfce88b8ec8 Mon Sep 17 00:00:00 2001 From: AkaraChen Date: Thu, 9 Jan 2025 11:53:24 +0800 Subject: [PATCH 10/14] fix: install button --- .../_base/components/install-plugin-button.tsx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/web/app/components/workflow/nodes/_base/components/install-plugin-button.tsx b/web/app/components/workflow/nodes/_base/components/install-plugin-button.tsx index bf4073358f..dc5930e15b 100644 --- a/web/app/components/workflow/nodes/_base/components/install-plugin-button.tsx +++ b/web/app/components/workflow/nodes/_base/components/install-plugin-button.tsx @@ -17,17 +17,19 @@ export const InstallPluginButton = (props: InstallPluginButtonProps) => { pluginIds: [uniqueIdentifier], enabled: !!uniqueIdentifier, }) - const install = useInstallPackageFromMarketPlace({ - onSuccess() { - manifest.refetch() - onSuccess?.() - }, - }) + const install = useInstallPackageFromMarketPlace() + const isLoading = manifest.isLoading || install.isPending + // await for refetch to get the new installed plugin, when manifest refetch, this component will unmount + || install.isSuccess const handleInstall: MouseEventHandler = (e) => { e.stopPropagation() - install.mutate(uniqueIdentifier) + install.mutate(uniqueIdentifier, { + onSuccess: async () => { + await manifest.refetch() + onSuccess?.() + }, + }) } - const isLoading = manifest.isLoading || install.isPending if (!manifest.data) return null if (manifest.data.plugins.some(plugin => plugin.id === uniqueIdentifier)) return null return