diff --git a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/layout.tsx b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/layout.tsx index 95665fbe00..014b109477 100644 --- a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/layout.tsx +++ b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/layout.tsx @@ -5,6 +5,7 @@ import React, { useCallback, useEffect, useState } from 'react' import { usePathname, useRouter } from 'next/navigation' import cn from 'classnames' import { useTranslation } from 'react-i18next' +import { useShallow } from 'zustand/react/shallow' import s from './style.module.css' import { useStore } from '@/app/components/app/store' import AppSideBar from '@/app/components/app-sidebar' @@ -32,7 +33,11 @@ const AppDetailLayout: FC = (props) => { const media = useBreakpoints() const isMobile = media === MediaType.mobile const { isCurrentWorkspaceManager } = useAppContext() - const { appDetail, setAppDetail, setAppSiderbarExpand } = useStore() + const { appDetail, setAppDetail, setAppSiderbarExpand } = useStore(useShallow(state => ({ + appDetail: state.appDetail, + setAppDetail: state.setAppDetail, + setAppSiderbarExpand: state.setAppSiderbarExpand, + }))) const [navigation, setNavigation] = useState = ({ appId }) => { const { t } = useTranslation() const { notify } = useContext(ToastContext) - const { appDetail, setAppDetail } = useAppStore() + const appDetail = useAppStore(state => state.appDetail) + const setAppDetail = useAppStore(state => state.setAppDetail) const updateAppDetail = async () => { fetchAppDetail({ url: '/apps', id: appId }).then((res) => { diff --git a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/chartView.tsx b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/chartView.tsx index 3073075cfa..74e9140fe5 100644 --- a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/chartView.tsx +++ b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/chartView.tsx @@ -22,7 +22,7 @@ export type IChartViewProps = { export default function ChartView({ appId }: IChartViewProps) { const { t } = useTranslation() - const { appDetail } = useAppStore() + const appDetail = useAppStore(state => state.appDetail) const isChatApp = appDetail?.mode !== 'completion' && appDetail?.mode !== 'workflow' const isWorkflow = appDetail?.mode === 'workflow' const [period, setPeriod] = useState({ name: t('appLog.filter.period.last7days'), query: { start: today.subtract(7, 'day').format(queryDateFormat), end: today.format(queryDateFormat) } }) diff --git a/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/layout.tsx b/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/layout.tsx index 3f2681ed35..f113693fbf 100644 --- a/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/layout.tsx +++ b/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/layout.tsx @@ -1,248 +1,248 @@ -'use client' -import type { FC, SVGProps } from 'react' -import React, { useEffect } from 'react' -import { usePathname } from 'next/navigation' -import useSWR from 'swr' -import { useTranslation } from 'react-i18next' -import classNames from 'classnames' -import { useBoolean } from 'ahooks' -import { - Cog8ToothIcon, - // CommandLineIcon, - Squares2X2Icon, - // eslint-disable-next-line sort-imports - PuzzlePieceIcon, - DocumentTextIcon, - PaperClipIcon, - QuestionMarkCircleIcon, -} from '@heroicons/react/24/outline' -import { - Cog8ToothIcon as Cog8ToothSolidIcon, - // CommandLineIcon as CommandLineSolidIcon, - DocumentTextIcon as DocumentTextSolidIcon, -} from '@heroicons/react/24/solid' -import Link from 'next/link' -import s from './style.module.css' -import { fetchDatasetDetail, fetchDatasetRelatedApps } from '@/service/datasets' -import type { RelatedApp, RelatedAppResponse } from '@/models/datasets' -import { getLocaleOnClient } from '@/i18n' -import AppSideBar from '@/app/components/app-sidebar' -import Divider from '@/app/components/base/divider' -import AppIcon from '@/app/components/base/app-icon' -import Loading from '@/app/components/base/loading' -import FloatPopoverContainer from '@/app/components/base/float-popover-container' -import DatasetDetailContext from '@/context/dataset-detail' -import { DataSourceType } from '@/models/datasets' -import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' -import { LanguagesSupported } from '@/i18n/language' -import { useStore } from '@/app/components/app/store' -import { AiText, ChatBot, CuteRobote } from '@/app/components/base/icons/src/vender/solid/communication' -import { Route } from '@/app/components/base/icons/src/vender/solid/mapsAndTravel' - -export type IAppDetailLayoutProps = { - children: React.ReactNode - params: { datasetId: string } -} - -type ILikedItemProps = { - type?: 'plugin' | 'app' - appStatus?: boolean - detail: RelatedApp - isMobile: boolean -} - -const LikedItem = ({ - type = 'app', - detail, - isMobile, -}: ILikedItemProps) => { - return ( - -
- - {type === 'app' && ( - - {detail.mode === 'advanced-chat' && ( - - )} - {detail.mode === 'agent-chat' && ( - - )} - {detail.mode === 'chat' && ( - - )} - {detail.mode === 'completion' && ( - - )} - {detail.mode === 'workflow' && ( - - )} - - )} -
- {!isMobile &&
{detail?.name || '--'}
} - - ) -} - -const TargetIcon = ({ className }: SVGProps) => { - return - - - - - - - - - -} - -const TargetSolidIcon = ({ className }: SVGProps) => { - return - - - - -} - -const BookOpenIcon = ({ className }: SVGProps) => { - return - - - -} - -type IExtraInfoProps = { - isMobile: boolean - relatedApps?: RelatedAppResponse -} - -const ExtraInfo = ({ isMobile, relatedApps }: IExtraInfoProps) => { - const locale = getLocaleOnClient() - const [isShowTips, { toggle: toggleTips, set: setShowTips }] = useBoolean(!isMobile) - const { t } = useTranslation() - - useEffect(() => { - setShowTips(!isMobile) - }, [isMobile, setShowTips]) - - return
- - {(relatedApps?.data && relatedApps?.data?.length > 0) && ( - <> - {!isMobile &&
{relatedApps?.total || '--'} {t('common.datasetMenus.relatedApp')}
} - {isMobile &&
- {relatedApps?.total || '--'} - -
} - {relatedApps?.data?.map((item, index) => ())} - - )} - {!relatedApps?.data?.length && ( - - -
- } - > -
-
-
- -
-
- -
-
-
{t('common.datasetMenus.emptyTip')}
- - - {t('common.datasetMenus.viewDoc')} - -
- - )} - -} - -const DatasetDetailLayout: FC = (props) => { - const { - children, - params: { datasetId }, - } = props - const pathname = usePathname() - const hideSideBar = /documents\/create$/.test(pathname) - const { t } = useTranslation() - - const media = useBreakpoints() - const isMobile = media === MediaType.mobile - - const { data: datasetRes, error, mutate: mutateDatasetRes } = useSWR({ - url: 'fetchDatasetDetail', - datasetId, - }, apiParams => fetchDatasetDetail(apiParams.datasetId)) - - const { data: relatedApps } = useSWR({ - action: 'fetchDatasetRelatedApps', - datasetId, - }, apiParams => fetchDatasetRelatedApps(apiParams.datasetId)) - - const navigation = [ - { name: t('common.datasetMenus.documents'), href: `/datasets/${datasetId}/documents`, icon: DocumentTextIcon, selectedIcon: DocumentTextSolidIcon }, - { name: t('common.datasetMenus.hitTesting'), href: `/datasets/${datasetId}/hitTesting`, icon: TargetIcon, selectedIcon: TargetSolidIcon }, - // { name: 'api & webhook', href: `/datasets/${datasetId}/api`, icon: CommandLineIcon, selectedIcon: CommandLineSolidIcon }, - { name: t('common.datasetMenus.settings'), href: `/datasets/${datasetId}/settings`, icon: Cog8ToothIcon, selectedIcon: Cog8ToothSolidIcon }, - ] - - useEffect(() => { - if (datasetRes) - document.title = `${datasetRes.name || 'Dataset'} - Dify` - }, [datasetRes]) - - const { setAppSiderbarExpand } = useStore() - - useEffect(() => { - const localeMode = localStorage.getItem('app-detail-collapse-or-expand') || 'expand' - const mode = isMobile ? 'collapse' : 'expand' - setAppSiderbarExpand(isMobile ? mode : localeMode) - }, [isMobile, setAppSiderbarExpand]) - - if (!datasetRes && !error) - return - - return ( -
- {!hideSideBar && } - iconType={datasetRes?.data_source_type === DataSourceType.NOTION ? 'notion' : 'dataset'} - />} - mutateDatasetRes(), - }}> -
{children}
-
-
- ) -} -export default React.memo(DatasetDetailLayout) +'use client' +import type { FC, SVGProps } from 'react' +import React, { useEffect } from 'react' +import { usePathname } from 'next/navigation' +import useSWR from 'swr' +import { useTranslation } from 'react-i18next' +import classNames from 'classnames' +import { useBoolean } from 'ahooks' +import { + Cog8ToothIcon, + // CommandLineIcon, + Squares2X2Icon, + // eslint-disable-next-line sort-imports + PuzzlePieceIcon, + DocumentTextIcon, + PaperClipIcon, + QuestionMarkCircleIcon, +} from '@heroicons/react/24/outline' +import { + Cog8ToothIcon as Cog8ToothSolidIcon, + // CommandLineIcon as CommandLineSolidIcon, + DocumentTextIcon as DocumentTextSolidIcon, +} from '@heroicons/react/24/solid' +import Link from 'next/link' +import s from './style.module.css' +import { fetchDatasetDetail, fetchDatasetRelatedApps } from '@/service/datasets' +import type { RelatedApp, RelatedAppResponse } from '@/models/datasets' +import { getLocaleOnClient } from '@/i18n' +import AppSideBar from '@/app/components/app-sidebar' +import Divider from '@/app/components/base/divider' +import AppIcon from '@/app/components/base/app-icon' +import Loading from '@/app/components/base/loading' +import FloatPopoverContainer from '@/app/components/base/float-popover-container' +import DatasetDetailContext from '@/context/dataset-detail' +import { DataSourceType } from '@/models/datasets' +import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' +import { LanguagesSupported } from '@/i18n/language' +import { useStore } from '@/app/components/app/store' +import { AiText, ChatBot, CuteRobote } from '@/app/components/base/icons/src/vender/solid/communication' +import { Route } from '@/app/components/base/icons/src/vender/solid/mapsAndTravel' + +export type IAppDetailLayoutProps = { + children: React.ReactNode + params: { datasetId: string } +} + +type ILikedItemProps = { + type?: 'plugin' | 'app' + appStatus?: boolean + detail: RelatedApp + isMobile: boolean +} + +const LikedItem = ({ + type = 'app', + detail, + isMobile, +}: ILikedItemProps) => { + return ( + +
+ + {type === 'app' && ( + + {detail.mode === 'advanced-chat' && ( + + )} + {detail.mode === 'agent-chat' && ( + + )} + {detail.mode === 'chat' && ( + + )} + {detail.mode === 'completion' && ( + + )} + {detail.mode === 'workflow' && ( + + )} + + )} +
+ {!isMobile &&
{detail?.name || '--'}
} + + ) +} + +const TargetIcon = ({ className }: SVGProps) => { + return + + + + + + + + + +} + +const TargetSolidIcon = ({ className }: SVGProps) => { + return + + + + +} + +const BookOpenIcon = ({ className }: SVGProps) => { + return + + + +} + +type IExtraInfoProps = { + isMobile: boolean + relatedApps?: RelatedAppResponse +} + +const ExtraInfo = ({ isMobile, relatedApps }: IExtraInfoProps) => { + const locale = getLocaleOnClient() + const [isShowTips, { toggle: toggleTips, set: setShowTips }] = useBoolean(!isMobile) + const { t } = useTranslation() + + useEffect(() => { + setShowTips(!isMobile) + }, [isMobile, setShowTips]) + + return
+ + {(relatedApps?.data && relatedApps?.data?.length > 0) && ( + <> + {!isMobile &&
{relatedApps?.total || '--'} {t('common.datasetMenus.relatedApp')}
} + {isMobile &&
+ {relatedApps?.total || '--'} + +
} + {relatedApps?.data?.map((item, index) => ())} + + )} + {!relatedApps?.data?.length && ( + + +
+ } + > +
+
+
+ +
+
+ +
+
+
{t('common.datasetMenus.emptyTip')}
+ + + {t('common.datasetMenus.viewDoc')} + +
+ + )} + +} + +const DatasetDetailLayout: FC = (props) => { + const { + children, + params: { datasetId }, + } = props + const pathname = usePathname() + const hideSideBar = /documents\/create$/.test(pathname) + const { t } = useTranslation() + + const media = useBreakpoints() + const isMobile = media === MediaType.mobile + + const { data: datasetRes, error, mutate: mutateDatasetRes } = useSWR({ + url: 'fetchDatasetDetail', + datasetId, + }, apiParams => fetchDatasetDetail(apiParams.datasetId)) + + const { data: relatedApps } = useSWR({ + action: 'fetchDatasetRelatedApps', + datasetId, + }, apiParams => fetchDatasetRelatedApps(apiParams.datasetId)) + + const navigation = [ + { name: t('common.datasetMenus.documents'), href: `/datasets/${datasetId}/documents`, icon: DocumentTextIcon, selectedIcon: DocumentTextSolidIcon }, + { name: t('common.datasetMenus.hitTesting'), href: `/datasets/${datasetId}/hitTesting`, icon: TargetIcon, selectedIcon: TargetSolidIcon }, + // { name: 'api & webhook', href: `/datasets/${datasetId}/api`, icon: CommandLineIcon, selectedIcon: CommandLineSolidIcon }, + { name: t('common.datasetMenus.settings'), href: `/datasets/${datasetId}/settings`, icon: Cog8ToothIcon, selectedIcon: Cog8ToothSolidIcon }, + ] + + useEffect(() => { + if (datasetRes) + document.title = `${datasetRes.name || 'Dataset'} - Dify` + }, [datasetRes]) + + const setAppSiderbarExpand = useStore(state => state.setAppSiderbarExpand) + + useEffect(() => { + const localeMode = localStorage.getItem('app-detail-collapse-or-expand') || 'expand' + const mode = isMobile ? 'collapse' : 'expand' + setAppSiderbarExpand(isMobile ? mode : localeMode) + }, [isMobile, setAppSiderbarExpand]) + + if (!datasetRes && !error) + return + + return ( +
+ {!hideSideBar && } + iconType={datasetRes?.data_source_type === DataSourceType.NOTION ? 'notion' : 'dataset'} + />} + mutateDatasetRes(), + }}> +
{children}
+
+
+ ) +} +export default React.memo(DatasetDetailLayout) diff --git a/web/app/components/app-sidebar/index.tsx b/web/app/components/app-sidebar/index.tsx index ba0de0ae17..9a78cd7e6e 100644 --- a/web/app/components/app-sidebar/index.tsx +++ b/web/app/components/app-sidebar/index.tsx @@ -1,4 +1,5 @@ -import React, { useEffect, useState } from 'react' +import React, { useEffect } from 'react' +import { useShallow } from 'zustand/react/shallow' import NavLink from './navLink' import type { NavIcon } from './navLink' import AppBasic from './basic' @@ -26,11 +27,13 @@ export type IAppDetailNavProps = { } const AppDetailNav = ({ title, desc, icon, icon_background, navigation, extraInfo, iconType = 'app' }: IAppDetailNavProps) => { - const { appSidebarExpand, setAppSiderbarExpand } = useAppStore() + const { appSidebarExpand, setAppSiderbarExpand } = useAppStore(useShallow(state => ({ + appSidebarExpand: state.appSidebarExpand, + setAppSiderbarExpand: state.setAppSiderbarExpand, + }))) const media = useBreakpoints() const isMobile = media === MediaType.mobile - const [modeState, setModeState] = useState(appSidebarExpand) - const expand = modeState === 'expand' + const expand = appSidebarExpand === 'expand' const handleToggle = (state: string) => { setAppSiderbarExpand(state === 'expand' ? 'collapse' : 'expand') @@ -39,9 +42,9 @@ const AppDetailNav = ({ title, desc, icon, icon_background, navigation, extraInf useEffect(() => { if (appSidebarExpand) { localStorage.setItem('app-detail-collapse-or-expand', appSidebarExpand) - setModeState(appSidebarExpand) + setAppSiderbarExpand(appSidebarExpand) } - }, [appSidebarExpand]) + }, [appSidebarExpand, setAppSiderbarExpand]) return (
{navigation.map((item, index) => { return ( - + ) })} - {extraInfo && extraInfo(modeState)} + {extraInfo && extraInfo(appSidebarExpand)} { !isMobile && ( @@ -96,7 +99,7 @@ const AppDetailNav = ({ title, desc, icon, icon_background, navigation, extraInf >
handleToggle(modeState)} + onClick={() => handleToggle(appSidebarExpand)} > { expand diff --git a/web/app/components/app/configuration/debug/index.tsx b/web/app/components/app/configuration/debug/index.tsx index 0058f13361..dba0b6d05f 100644 --- a/web/app/components/app/configuration/debug/index.tsx +++ b/web/app/components/app/configuration/debug/index.tsx @@ -6,6 +6,7 @@ import React, { useCallback, useEffect, useRef, useState } from 'react' import { setAutoFreeze } from 'immer' import { useBoolean } from 'ahooks' import { useContext } from 'use-context-selector' +import { useShallow } from 'zustand/react/shallow' import HasNotSetAPIKEY from '../base/warning-mask/has-not-set-api' import FormattingChanged from '../base/warning-mask/formatting-changed' import GroupName from '../base/group-name' @@ -367,7 +368,12 @@ const Debug: FC = ({ handleVisionConfigInMultipleModel() }, [multipleModelConfigs, mode]) - const { currentLogItem, setCurrentLogItem, showPromptLogModal, setShowPromptLogModal } = useAppStore() + const { currentLogItem, setCurrentLogItem, showPromptLogModal, setShowPromptLogModal } = useAppStore(useShallow(state => ({ + currentLogItem: state.currentLogItem, + setCurrentLogItem: state.setCurrentLogItem, + showPromptLogModal: state.showPromptLogModal, + setShowPromptLogModal: state.setShowPromptLogModal, + }))) const [width, setWidth] = useState(0) const ref = useRef(null) diff --git a/web/app/components/app/configuration/index.tsx b/web/app/components/app/configuration/index.tsx index 4f44f0eab7..259f6b2deb 100644 --- a/web/app/components/app/configuration/index.tsx +++ b/web/app/components/app/configuration/index.tsx @@ -8,6 +8,7 @@ import produce from 'immer' import { useBoolean, useGetState } from 'ahooks' import { clone, isEqual } from 'lodash-es' import { CodeBracketIcon } from '@heroicons/react/20/solid' +import { useShallow } from 'zustand/react/shallow' import Button from '../../base/button' import Loading from '../../base/loading' import AppPublisher from '../app-publisher' @@ -65,7 +66,10 @@ type PublishConfig = { const Configuration: FC = () => { const { t } = useTranslation() const { notify } = useContext(ToastContext) - const { appDetail, setAppSiderbarExpand } = useAppStore() + const { appDetail, setAppSiderbarExpand } = useAppStore(useShallow(state => ({ + appDetail: state.appDetail, + setAppSiderbarExpand: state.setAppSiderbarExpand, + }))) const [formattingChanged, setFormattingChanged] = useState(false) const { setShowAccountSettingModal } = useModalContext() const [hasFetchedDetail, setHasFetchedDetail] = useState(false) diff --git a/web/app/components/app/log-annotation/index.tsx b/web/app/components/app/log-annotation/index.tsx index d767a1473c..626671fa18 100644 --- a/web/app/components/app/log-annotation/index.tsx +++ b/web/app/components/app/log-annotation/index.tsx @@ -21,7 +21,7 @@ const LogAnnotation: FC = ({ }) => { const { t } = useTranslation() const router = useRouter() - const { appDetail } = useAppStore() + const appDetail = useAppStore(state => state.appDetail) const options = [ { value: PageType.log, text: t('appLog.title') }, diff --git a/web/app/components/base/chat/chat/index.tsx b/web/app/components/base/chat/chat/index.tsx index 6d374b0089..4c9718de7f 100644 --- a/web/app/components/base/chat/chat/index.tsx +++ b/web/app/components/base/chat/chat/index.tsx @@ -12,6 +12,7 @@ import { import { useTranslation } from 'react-i18next' import { debounce } from 'lodash-es' import classNames from 'classnames' +import { useShallow } from 'zustand/react/shallow' import type { ChatConfig, ChatItem, @@ -79,7 +80,14 @@ const Chat: FC = ({ chatAnswerContainerInner, }) => { const { t } = useTranslation() - const { currentLogItem, setCurrentLogItem, showPromptLogModal, setShowPromptLogModal, showAgentLogModal, setShowAgentLogModal } = useAppStore() + const { currentLogItem, setCurrentLogItem, showPromptLogModal, setShowPromptLogModal, showAgentLogModal, setShowAgentLogModal } = useAppStore(useShallow(state => ({ + currentLogItem: state.currentLogItem, + setCurrentLogItem: state.setCurrentLogItem, + showPromptLogModal: state.showPromptLogModal, + setShowPromptLogModal: state.setShowPromptLogModal, + showAgentLogModal: state.showAgentLogModal, + setShowAgentLogModal: state.setShowAgentLogModal, + }))) const [width, setWidth] = useState(0) const chatContainerRef = useRef(null) const chatContainerInnerRef = useRef(null) diff --git a/web/app/components/develop/index.tsx b/web/app/components/develop/index.tsx index 9b9fec8fd5..2f6a2a2fdf 100644 --- a/web/app/components/develop/index.tsx +++ b/web/app/components/develop/index.tsx @@ -12,7 +12,7 @@ type IDevelopMainProps = { } const DevelopMain = ({ appId }: IDevelopMainProps) => { - const { appDetail } = useAppStore() + const appDetail = useAppStore(state => state.appDetail) const { t } = useTranslation() if (!appDetail) { diff --git a/web/app/components/header/app-nav/index.tsx b/web/app/components/header/app-nav/index.tsx index cdca258257..bbf96ec2ea 100644 --- a/web/app/components/header/app-nav/index.tsx +++ b/web/app/components/header/app-nav/index.tsx @@ -40,7 +40,7 @@ const AppNav = () => { const { t } = useTranslation() const { appId } = useParams() const { isCurrentWorkspaceManager } = useAppContext() - const { appDetail } = useAppStore() + const appDetail = useAppStore(state => state.appDetail) const [showNewAppDialog, setShowNewAppDialog] = useState(false) const [showNewAppTemplateDialog, setShowNewAppTemplateDialog] = useState(false) const [showCreateFromDSLModal, setShowCreateFromDSLModal] = useState(false) diff --git a/web/app/components/header/nav/index.tsx b/web/app/components/header/nav/index.tsx index f236cd2ee9..9d18777812 100644 --- a/web/app/components/header/nav/index.tsx +++ b/web/app/components/header/nav/index.tsx @@ -31,7 +31,7 @@ const Nav = ({ onLoadmore, isApp, }: INavProps) => { - const { setAppDetail } = useAppStore() + const setAppDetail = useAppStore(state => state.setAppDetail) const [hovered, setHovered] = useState(false) const segment = useSelectedLayoutSegment() const isActived = Array.isArray(activeSegment) ? activeSegment.includes(segment!) : segment === activeSegment diff --git a/web/app/components/header/nav/nav-selector/index.tsx b/web/app/components/header/nav/nav-selector/index.tsx index c69be802b5..edb6c3a388 100644 --- a/web/app/components/header/nav/nav-selector/index.tsx +++ b/web/app/components/header/nav/nav-selector/index.tsx @@ -35,7 +35,7 @@ const NavSelector = ({ curNav, navs, createText, isApp, onCreate, onLoadmore }: const { t } = useTranslation() const router = useRouter() const { isCurrentWorkspaceManager } = useAppContext() - const { setAppDetail } = useAppStore() + const setAppDetail = useAppStore(state => state.setAppDetail) const handleScroll = useCallback(debounce((e) => { if (typeof onLoadmore === 'function') { diff --git a/web/app/components/workflow/header/index.tsx b/web/app/components/workflow/header/index.tsx index 9f6de7d613..c72bca3317 100644 --- a/web/app/components/workflow/header/index.tsx +++ b/web/app/components/workflow/header/index.tsx @@ -33,7 +33,7 @@ const Header: FC = () => { const workflowStore = useWorkflowStore() const appDetail = useAppStore(s => s.appDetail) const appSidebarExpand = useAppStore(s => s.appSidebarExpand) - const appID = useAppStore(state => state.appDetail?.id) + const appID = appDetail?.id const { nodesReadOnly, getNodesReadOnly, diff --git a/web/app/components/workflow/header/view-history.tsx b/web/app/components/workflow/header/view-history.tsx index 32b004fbc1..ec9e2ead1c 100644 --- a/web/app/components/workflow/header/view-history.tsx +++ b/web/app/components/workflow/header/view-history.tsx @@ -5,6 +5,7 @@ import { import cn from 'classnames' import useSWR from 'swr' import { useTranslation } from 'react-i18next' +import { useShallow } from 'zustand/react/shallow' import { useIsChatMode, useWorkflow, @@ -40,7 +41,11 @@ const ViewHistory = () => { const [open, setOpen] = useState(false) const { formatTimeFromNow } = useWorkflow() const workflowStore = useWorkflowStore() - const { appDetail, setCurrentLogItem, setShowMessageLogModal } = useAppStore() + const { appDetail, setCurrentLogItem, setShowMessageLogModal } = useAppStore(useShallow(state => ({ + appDetail: state.appDetail, + setCurrentLogItem: state.setCurrentLogItem, + setShowMessageLogModal: state.setShowMessageLogModal, + }))) const historyWorkflowData = useStore(s => s.historyWorkflowData) const { handleBackupDraft } = useWorkflowRun() const { data: runList, isLoading: runListLoading } = useSWR((appDetail && !isChatMode && open) ? `/apps/${appDetail.id}/workflow-runs` : null, fetchWorkflowRunHistory) diff --git a/web/app/components/workflow/panel/index.tsx b/web/app/components/workflow/panel/index.tsx index a564c504d4..fd22285328 100644 --- a/web/app/components/workflow/panel/index.tsx +++ b/web/app/components/workflow/panel/index.tsx @@ -4,6 +4,7 @@ import { useMemo, } from 'react' import { useNodes } from 'reactflow' +import { useShallow } from 'zustand/react/shallow' import type { CommonNodeType } from '../types' import { Panel as NodePanel } from '../nodes' import { useStore } from '../store' @@ -22,7 +23,12 @@ const Panel: FC = () => { const showInputsPanel = useStore(s => s.showInputsPanel) const workflowRunningData = useStore(s => s.workflowRunningData) const historyWorkflowData = useStore(s => s.historyWorkflowData) - const { currentLogItem, setCurrentLogItem, showMessageLogModal, setShowMessageLogModal } = useAppStore() + const { currentLogItem, setCurrentLogItem, showMessageLogModal, setShowMessageLogModal } = useAppStore(useShallow(state => ({ + currentLogItem: state.currentLogItem, + setCurrentLogItem: state.setCurrentLogItem, + showMessageLogModal: state.showMessageLogModal, + setShowMessageLogModal: state.setShowMessageLogModal, + }))) const { showNodePanel, showDebugAndPreviewPanel, diff --git a/web/app/components/workflow/run/index.tsx b/web/app/components/workflow/run/index.tsx index ec30c801d7..ffcfa46330 100644 --- a/web/app/components/workflow/run/index.tsx +++ b/web/app/components/workflow/run/index.tsx @@ -25,7 +25,7 @@ const RunPanel: FC = ({ hideResult, activeTab = 'RESULT', runID, getRe const { t } = useTranslation() const { notify } = useContext(ToastContext) const [currentTab, setCurrentTab] = useState(activeTab) - const { appDetail } = useAppStore() + const appDetail = useAppStore(state => state.appDetail) const [loading, setLoading] = useState(true) const [runDetail, setRunDetail] = useState() const [list, setList] = useState([]) diff --git a/web/app/components/workflow/store.ts b/web/app/components/workflow/store.ts index f0c648fce3..3701ed1535 100644 --- a/web/app/components/workflow/store.ts +++ b/web/app/components/workflow/store.ts @@ -1,8 +1,8 @@ import { useContext } from 'react' import { - create, useStore as useZustandStore, } from 'zustand' +import { createStore } from 'zustand/vanilla' import { debounce } from 'lodash-es' import type { Viewport } from 'reactflow' import type { @@ -70,9 +70,9 @@ type Shape = { } export const createWorkflowStore = () => { - return create(set => ({ + return createStore(set => ({ appId: '', - workflowData: undefined, + workflowRunningData: undefined, setWorkflowRunningData: workflowRunningData => set(() => ({ workflowRunningData })), historyWorkflowData: undefined, setHistoryWorkflowData: historyWorkflowData => set(() => ({ historyWorkflowData })),