diff --git a/web/features/deployments/components/create-instance-modal.tsx b/web/features/deployments/components/create-instance-modal.tsx index 8e0853bd52..326f61fdf5 100644 --- a/web/features/deployments/components/create-instance-modal.tsx +++ b/web/features/deployments/components/create-instance-modal.tsx @@ -6,6 +6,7 @@ import { Dialog, DialogCloseButton, DialogContent, DialogDescription, DialogTitl import { Popover, PopoverContent, PopoverTrigger } from '@langgenius/dify-ui/popover' import { toast } from '@langgenius/dify-ui/toast' import { useMutation, useQuery } from '@tanstack/react-query' +import { useAtomValue, useSetAtom } from 'jotai' import { useState } from 'react' import { useTranslation } from 'react-i18next' import { AppTypeIcon } from '@/app/components/app/type-selector' @@ -14,7 +15,7 @@ import Input from '@/app/components/base/input' import { useRouter } from '@/next/navigation' import { consoleQuery } from '@/service/client' import { AppModeEnum } from '@/types/app' -import { useDeploymentsStore } from '../store' +import { closeCreateInstanceModalAtom, createInstanceModalOpenAtom } from '../store' const MAX_STUDIO_SOURCE_APPS = 100 @@ -324,17 +325,17 @@ function CreateInstanceForm({ onClose }: { } export function CreateInstanceModal() { - const modal = useDeploymentsStore(state => state.createInstanceModal) - const closeModal = useDeploymentsStore(state => state.closeCreateInstanceModal) + const open = useAtomValue(createInstanceModalOpenAtom) + const closeModal = useSetAtom(closeCreateInstanceModalAtom) return ( !next && closeModal()} > - {modal.open && } + {open && } ) diff --git a/web/features/deployments/components/deploy-drawer.tsx b/web/features/deployments/components/deploy-drawer.tsx index 8da6e730d8..4766356463 100644 --- a/web/features/deployments/components/deploy-drawer.tsx +++ b/web/features/deployments/components/deploy-drawer.tsx @@ -3,20 +3,28 @@ import { Dialog, DialogCloseButton, DialogContent } from '@langgenius/dify-ui/dialog' import { toast } from '@langgenius/dify-ui/toast' import { skipToken, useMutation, useQuery } from '@tanstack/react-query' +import { useAtomValue, useSetAtom } from 'jotai' import { useTranslation } from 'react-i18next' import { consoleQuery } from '@/service/client' import { DEPLOYMENT_PAGE_SIZE } from '../data' -import { useDeploymentsStore } from '../store' +import { + closeDeployDrawerAtom, + deployDrawerAppInstanceIdAtom, + deployDrawerEnvironmentIdAtom, + deployDrawerOpenAtom, + deployDrawerReleaseIdAtom, +} from '../store' import { environmentOptionsFromOptionsReply } from '../utils' import { DeployForm } from './deploy-drawer/form' export function DeployDrawer() { const { t } = useTranslation('deployments') - const drawer = useDeploymentsStore(state => state.deployDrawer) - const drawerAppInstanceId = drawer.appInstanceId - const closeDeployDrawer = useDeploymentsStore(state => state.closeDeployDrawer) + const open = useAtomValue(deployDrawerOpenAtom) + const drawerAppInstanceId = useAtomValue(deployDrawerAppInstanceIdAtom) + const drawerEnvironmentId = useAtomValue(deployDrawerEnvironmentIdAtom) + const drawerReleaseId = useAtomValue(deployDrawerReleaseIdAtom) + const closeDeployDrawer = useSetAtom(closeDeployDrawerAtom) const startDeploy = useMutation(consoleQuery.enterprise.appDeploy.createDeployment.mutationOptions()) - const open = drawer.open const { data: releaseHistory } = useQuery(consoleQuery.enterprise.appDeploy.listReleases.queryOptions({ input: drawerAppInstanceId ? { @@ -36,7 +44,7 @@ export function DeployDrawer() { const environments = environmentOptionsFromOptionsReply(environmentOptionsReply) const releases = releaseHistory?.data?.filter(release => release.id) ?? [] const defaultReleaseId = releases[0]?.id - const formKey = `${drawer.appInstanceId ?? 'none'}-${drawer.environmentId ?? 'any'}-${drawer.releaseId ?? 'new'}-${open ? '1' : '0'}` + const formKey = `${drawerAppInstanceId ?? 'none'}-${drawerEnvironmentId ?? 'any'}-${drawerReleaseId ?? 'new'}-${open ? '1' : '0'}` return ( { diff --git a/web/features/deployments/components/rollback-modal.tsx b/web/features/deployments/components/rollback-modal.tsx index 9e6b9d83c2..c0b06ca178 100644 --- a/web/features/deployments/components/rollback-modal.tsx +++ b/web/features/deployments/components/rollback-modal.tsx @@ -9,10 +9,17 @@ import { AlertDialogTitle, } from '@langgenius/dify-ui/alert-dialog' import { skipToken, useMutation, useQuery } from '@tanstack/react-query' +import { useAtomValue, useSetAtom } from 'jotai' import { useTranslation } from 'react-i18next' import { consoleQuery } from '@/service/client' import { DEPLOYMENT_PAGE_SIZE } from '../data' -import { useDeploymentsStore } from '../store' +import { + closeRollbackModalAtom, + rollbackModalAppInstanceIdAtom, + rollbackModalEnvironmentIdAtom, + rollbackModalOpenAtom, + rollbackModalTargetReleaseIdAtom, +} from '../store' import { activeRelease, deployedRows, @@ -37,60 +44,63 @@ function InfoRow({ label, value }: { export function RollbackModal() { const { t } = useTranslation('deployments') - const modal = useDeploymentsStore(state => state.rollbackModal) - const closeRollbackModal = useDeploymentsStore(state => state.closeRollbackModal) + const open = useAtomValue(rollbackModalOpenAtom) + const appInstanceId = useAtomValue(rollbackModalAppInstanceIdAtom) + const modalEnvironmentId = useAtomValue(rollbackModalEnvironmentIdAtom) + const targetReleaseId = useAtomValue(rollbackModalTargetReleaseIdAtom) + const closeRollbackModal = useSetAtom(closeRollbackModalAtom) const rollbackDeployment = useMutation(consoleQuery.enterprise.appDeploy.createDeployment.mutationOptions()) - const appInput = modal.appInstanceId - ? { params: { appInstanceId: modal.appInstanceId } } + const appInput = appInstanceId + ? { params: { appInstanceId } } : skipToken const { data: overview } = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceOverview.queryOptions({ input: appInput, - enabled: modal.open && Boolean(modal.appInstanceId), + enabled: open && Boolean(appInstanceId), })) const { data: environmentDeployments } = useQuery(consoleQuery.enterprise.appDeploy.listRuntimeInstances.queryOptions({ input: appInput, - enabled: modal.open && Boolean(modal.appInstanceId), + enabled: open && Boolean(appInstanceId), })) const { data: environmentOptionsReply } = useQuery(consoleQuery.enterprise.appDeploy.listDeploymentEnvironmentOptions.queryOptions({ - enabled: modal.open, + enabled: open, })) const { data: releaseHistory } = useQuery(consoleQuery.enterprise.appDeploy.listReleases.queryOptions({ - input: modal.appInstanceId + input: appInstanceId ? { - params: { appInstanceId: modal.appInstanceId }, + params: { appInstanceId }, query: { pageNumber: 1, resultsPerPage: DEPLOYMENT_PAGE_SIZE, }, } : skipToken, - enabled: modal.open && Boolean(modal.appInstanceId), + enabled: open && Boolean(appInstanceId), })) const environmentOptions = environmentOptionsFromOptionsReply(environmentOptionsReply) const currentRow = deployedRows(environmentDeployments?.data) - .find(row => environmentId(row.environment) === modal.environmentId) + .find(row => environmentId(row.environment) === modalEnvironmentId) const targetRelease = [ ...(releaseHistory?.data?.filter(release => !!release.id) ?? []), - ].find(release => release.id === modal.targetReleaseId) + ].find(release => release.id === targetReleaseId) const currentRelease = activeRelease(currentRow) const environment = currentRow?.environment - ?? environmentOptions.find(env => env.id === modal.environmentId) + ?? environmentOptions.find(env => env.id === modalEnvironmentId) const app = overview?.instance const appName = app?.name ?? '-' const sourceAppName = app?.sourceAppName ?? appName const confirm = () => { - if (!modal.appInstanceId || !modal.environmentId || !modal.targetReleaseId) + if (!appInstanceId || !modalEnvironmentId || !targetReleaseId) return closeRollbackModal() rollbackDeployment.mutate({ params: { - appInstanceId: modal.appInstanceId, + appInstanceId, }, body: { - environmentId: modal.environmentId, - releaseId: modal.targetReleaseId, + environmentId: modalEnvironmentId, + releaseId: targetReleaseId, bindings: [], }, }) @@ -98,7 +108,7 @@ export function RollbackModal() { return ( !next && closeRollbackModal()} > diff --git a/web/features/deployments/detail/deploy-tab.tsx b/web/features/deployments/detail/deploy-tab.tsx index 0e599cdcb6..6747440c4b 100644 --- a/web/features/deployments/detail/deploy-tab.tsx +++ b/web/features/deployments/detail/deploy-tab.tsx @@ -10,10 +10,11 @@ import { DropdownMenuTrigger, } from '@langgenius/dify-ui/dropdown-menu' import { useMutation, useQuery } from '@tanstack/react-query' +import { useSetAtom } from 'jotai' import { useState } from 'react' import { useTranslation } from 'react-i18next' import { consoleQuery } from '@/service/client' -import { useDeploymentsStore } from '../store' +import { openDeployDrawerAtom } from '../store' import { activeRelease, deployedRows, @@ -38,7 +39,7 @@ function NewDeploymentMenu({ appInstanceId, availableEnvs }: { availableEnvs: EnvironmentOption[] }) { const { t } = useTranslation('deployments') - const openDeployDrawer = useDeploymentsStore(state => state.openDeployDrawer) + const openDeployDrawer = useSetAtom(openDeployDrawerAtom) const [open, setOpen] = useState(false) return ( @@ -100,7 +101,7 @@ function DeploymentRowActions({ appInstanceId, envId, row }: { }) { const { t } = useTranslation('deployments') const [menuOpen, setMenuOpen] = useState(false) - const openDeployDrawer = useDeploymentsStore(state => state.openDeployDrawer) + const openDeployDrawer = useSetAtom(openDeployDrawerAtom) const cancelDeployment = useMutation(consoleQuery.enterprise.appDeploy.cancelRuntimeDeployment.mutationOptions()) const undeployDeployment = useMutation(consoleQuery.enterprise.appDeploy.undeployRuntimeInstance.mutationOptions()) const isUndeployed = isUndeployedDeploymentRow(row) diff --git a/web/features/deployments/detail/overview-tab.tsx b/web/features/deployments/detail/overview-tab.tsx index e93147e270..4b41dd5b2f 100644 --- a/web/features/deployments/detail/overview-tab.tsx +++ b/web/features/deployments/detail/overview-tab.tsx @@ -3,13 +3,14 @@ import type { ReactNode } from 'react' import { Button } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' import { useQuery } from '@tanstack/react-query' +import { useSetAtom } from 'jotai' import { useTranslation } from 'react-i18next' import { getAppModeLabel } from '@/app/components/app-sidebar/app-info/app-mode-labels' import Link from '@/next/link' import { consoleQuery } from '@/service/client' import { StatusBadge } from '../components/status-badge' import { DEPLOYMENT_PAGE_SIZE } from '../data' -import { useDeploymentsStore } from '../store' +import { openDeployDrawerAtom } from '../store' import { releaseLabel, webappUrl, @@ -107,7 +108,7 @@ export function OverviewTab({ instanceId }: { const { data: accessConfig } = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceAccess.queryOptions({ input, })) - const openDeployDrawer = useDeploymentsStore(state => state.openDeployDrawer) + const openDeployDrawer = useSetAtom(openDeployDrawerAtom) const overviewApp = overview?.instance const deployments = overview?.deployments?.filter(row => row.environment?.id && row.status?.toLowerCase() !== 'undeployed') ?? [] const releaseRows = releaseHistory?.data?.filter(row => row.id) ?? [] diff --git a/web/features/deployments/detail/versions-tab/deploy-release-menu.tsx b/web/features/deployments/detail/versions-tab/deploy-release-menu.tsx index a60f949261..0f62f4dc0b 100644 --- a/web/features/deployments/detail/versions-tab/deploy-release-menu.tsx +++ b/web/features/deployments/detail/versions-tab/deploy-release-menu.tsx @@ -8,10 +8,11 @@ import { DropdownMenuTrigger, } from '@langgenius/dify-ui/dropdown-menu' import { useQuery } from '@tanstack/react-query' +import { useSetAtom } from 'jotai' import { useState } from 'react' import { useTranslation } from 'react-i18next' import { consoleQuery } from '@/service/client' -import { useDeploymentsStore } from '../../store' +import { openDeployDrawerAtom } from '../../store' import { activeRelease, deployedRows, @@ -26,7 +27,7 @@ export function DeployReleaseMenu({ appInstanceId, releaseId }: { releaseId: string }) { const { t } = useTranslation('deployments') - const openDeployDrawer = useDeploymentsStore(state => state.openDeployDrawer) + const openDeployDrawer = useSetAtom(openDeployDrawerAtom) const [open, setOpen] = useState(false) const { data: environmentDeployments } = useQuery(consoleQuery.enterprise.appDeploy.listRuntimeInstances.queryOptions({ input: { diff --git a/web/features/deployments/list/instance-card.tsx b/web/features/deployments/list/instance-card.tsx index 044a230c65..97ee9deef4 100644 --- a/web/features/deployments/list/instance-card.tsx +++ b/web/features/deployments/list/instance-card.tsx @@ -12,13 +12,14 @@ import { DropdownMenuTrigger, } from '@langgenius/dify-ui/dropdown-menu' import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip' +import { useSetAtom } from 'jotai' import { useState } from 'react' import { useTranslation } from 'react-i18next' import { AppTypeIcon } from '@/app/components/app/type-selector' import AppIcon from '@/app/components/base/app-icon' import { useFormatTimeFromNow } from '@/hooks/use-format-time-from-now' import Link from '@/next/link' -import { useDeploymentsStore } from '../store' +import { openDeployDrawerAtom } from '../store' export function InstanceCard({ app }: { app: AppInstanceCard @@ -194,7 +195,7 @@ function InstanceCardActions({ appId, detailHref }: { }) { const { t } = useTranslation('deployments') const [menuOpen, setMenuOpen] = useState(false) - const openDeployDrawer = useDeploymentsStore(state => state.openDeployDrawer) + const openDeployDrawer = useSetAtom(openDeployDrawerAtom) return (
diff --git a/web/features/deployments/list/new-instance-card.tsx b/web/features/deployments/list/new-instance-card.tsx index 262a82487a..3e08e155cd 100644 --- a/web/features/deployments/list/new-instance-card.tsx +++ b/web/features/deployments/list/new-instance-card.tsx @@ -1,8 +1,9 @@ 'use client' import { cn } from '@langgenius/dify-ui/cn' +import { useSetAtom } from 'jotai' import { useTranslation } from 'react-i18next' -import { useDeploymentsStore } from '../store' +import { openCreateInstanceModalAtom } from '../store' type NewInstanceActionProps = { icon: string @@ -40,7 +41,7 @@ function NewInstanceAction({ icon, label, disabled, onClick }: NewInstanceAction export function NewInstanceCard() { const { t } = useTranslation('deployments') - const openCreateInstanceModal = useDeploymentsStore(state => state.openCreateInstanceModal) + const openCreateInstanceModal = useSetAtom(openCreateInstanceModalAtom) return (
diff --git a/web/features/deployments/nav/index.tsx b/web/features/deployments/nav/index.tsx index 60c18fe78e..07977cddd3 100644 --- a/web/features/deployments/nav/index.tsx +++ b/web/features/deployments/nav/index.tsx @@ -4,12 +4,13 @@ import type { AppInstanceBasicInfo, AppInstanceCard } from '@dify/contracts/ente import type { NavItem } from '@/app/components/header/nav/nav-selector' import type { AppModeEnum } from '@/types/app' import { skipToken, useQuery } from '@tanstack/react-query' +import { useSetAtom } from 'jotai' import { useTranslation } from 'react-i18next' import Nav from '@/app/components/header/nav' import { useParams, useRouter, useSelectedLayoutSegment } from '@/next/navigation' import { consoleQuery } from '@/service/client' import { SOURCE_APPS_PAGE_SIZE } from '../data' -import { useDeploymentsStore } from '../store' +import { openCreateInstanceModalAtom } from '../store' function navItemFromListApp(app: AppInstanceCard): NavItem[] { if (!app.id || !app.name) @@ -53,7 +54,7 @@ export function DeploymentsNav() { const params = useParams<{ instanceId?: string }>() const instanceId = params?.instanceId - const openCreateInstanceModal = useDeploymentsStore(state => state.openCreateInstanceModal) + const openCreateInstanceModal = useSetAtom(openCreateInstanceModalAtom) const { data: currentInstance } = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceOverview.queryOptions({ input: instanceId ? { params: { appInstanceId: instanceId } } diff --git a/web/features/deployments/store.ts b/web/features/deployments/store.ts index 741f791ab5..faf8e63a1e 100644 --- a/web/features/deployments/store.ts +++ b/web/features/deployments/store.ts @@ -1,4 +1,4 @@ -import { create } from 'zustand' +import { atom } from 'jotai' type OpenDeployDrawerParams = { appInstanceId: string @@ -13,48 +13,55 @@ type OpenRollbackParams = { deploymentId?: string } -type DeploymentsStore = { - deployDrawer: { - open: boolean - appInstanceId?: string - environmentId?: string - releaseId?: string - } - rollbackModal: { - open: boolean - appInstanceId?: string - environmentId?: string - deploymentId?: string - targetReleaseId?: string - } - createInstanceModal: { open: boolean } +export const deployDrawerOpenAtom = atom(false) +export const deployDrawerAppInstanceIdAtom = atom(undefined) +export const deployDrawerEnvironmentIdAtom = atom(undefined) +export const deployDrawerReleaseIdAtom = atom(undefined) - openDeployDrawer: (params: OpenDeployDrawerParams) => void - closeDeployDrawer: () => void - openRollbackModal: (params: OpenRollbackParams) => void - closeRollbackModal: () => void - openCreateInstanceModal: () => void - closeCreateInstanceModal: () => void -} +export const rollbackModalOpenAtom = atom(false) +export const rollbackModalAppInstanceIdAtom = atom(undefined) +export const rollbackModalEnvironmentIdAtom = atom(undefined) +export const rollbackModalDeploymentIdAtom = atom(undefined) +export const rollbackModalTargetReleaseIdAtom = atom(undefined) -export const useDeploymentsStore = create()(set => ({ - deployDrawer: { open: false }, - rollbackModal: { open: false }, - createInstanceModal: { open: false }, +export const createInstanceModalOpenAtom = atom(false) - openDeployDrawer: params => set({ - deployDrawer: { - open: true, - appInstanceId: params.appInstanceId, - environmentId: params.environmentId, - releaseId: params.releaseId, - }, - }), - closeDeployDrawer: () => set({ deployDrawer: { open: false } }), - openRollbackModal: ({ appInstanceId, environmentId, deploymentId, targetReleaseId }) => set({ - rollbackModal: { open: true, appInstanceId, environmentId, deploymentId, targetReleaseId }, - }), - closeRollbackModal: () => set({ rollbackModal: { open: false } }), - openCreateInstanceModal: () => set({ createInstanceModal: { open: true } }), - closeCreateInstanceModal: () => set({ createInstanceModal: { open: false } }), -})) +export const openDeployDrawerAtom = atom(null, (_get, set, params: OpenDeployDrawerParams) => { + set(deployDrawerAppInstanceIdAtom, params.appInstanceId) + set(deployDrawerEnvironmentIdAtom, params.environmentId) + set(deployDrawerReleaseIdAtom, params.releaseId) + set(deployDrawerOpenAtom, true) +}) +export const closeDeployDrawerAtom = atom(null, (_get, set) => { + set(deployDrawerOpenAtom, false) + set(deployDrawerAppInstanceIdAtom, undefined) + set(deployDrawerEnvironmentIdAtom, undefined) + set(deployDrawerReleaseIdAtom, undefined) +}) + +export const openRollbackModalAtom = atom(null, (_get, set, { + appInstanceId, + environmentId, + deploymentId, + targetReleaseId, +}: OpenRollbackParams) => { + set(rollbackModalAppInstanceIdAtom, appInstanceId) + set(rollbackModalEnvironmentIdAtom, environmentId) + set(rollbackModalDeploymentIdAtom, deploymentId) + set(rollbackModalTargetReleaseIdAtom, targetReleaseId) + set(rollbackModalOpenAtom, true) +}) +export const closeRollbackModalAtom = atom(null, (_get, set) => { + set(rollbackModalOpenAtom, false) + set(rollbackModalAppInstanceIdAtom, undefined) + set(rollbackModalEnvironmentIdAtom, undefined) + set(rollbackModalDeploymentIdAtom, undefined) + set(rollbackModalTargetReleaseIdAtom, undefined) +}) + +export const openCreateInstanceModalAtom = atom(null, (_get, set) => { + set(createInstanceModalOpenAtom, true) +}) +export const closeCreateInstanceModalAtom = atom(null, (_get, set) => { + set(createInstanceModalOpenAtom, false) +})