diff --git a/libs/domains/environments/feature/src/lib/environment-last-deployment-section/environment-last-deployment-section.spec.tsx b/libs/domains/environments/feature/src/lib/environment-last-deployment-section/environment-last-deployment-section.spec.tsx index f5e2c82b7fe..b6aee6cf62c 100644 --- a/libs/domains/environments/feature/src/lib/environment-last-deployment-section/environment-last-deployment-section.spec.tsx +++ b/libs/domains/environments/feature/src/lib/environment-last-deployment-section/environment-last-deployment-section.spec.tsx @@ -89,7 +89,7 @@ describe('EnvironmentLastDeploymentSection', () => { expect(screen.queryByText(/Running since/i)).not.toBeInTheDocument() }) - it('renders a running since label for an ongoing deployment', () => { + it('renders a live relative time for an ongoing deployment', () => { mockUseDeploymentHistory.mockReturnValue({ data: [ { @@ -103,9 +103,7 @@ describe('EnvironmentLastDeploymentSection', () => { renderWithProviders() - expect( - screen.getByText((_, element) => element?.textContent === 'Running since mocked-time ago') - ).toBeInTheDocument() + expect(screen.getByText('mocked-time ago')).toBeInTheDocument() }) it('renders the empty state when no deployment exists', () => { diff --git a/libs/domains/environments/feature/src/lib/environment-last-deployment-section/environment-last-deployment-section.tsx b/libs/domains/environments/feature/src/lib/environment-last-deployment-section/environment-last-deployment-section.tsx index 7bd7db22645..10a7ec79c5b 100644 --- a/libs/domains/environments/feature/src/lib/environment-last-deployment-section/environment-last-deployment-section.tsx +++ b/libs/domains/environments/feature/src/lib/environment-last-deployment-section/environment-last-deployment-section.tsx @@ -1,6 +1,6 @@ import { useLinkProps, useParams } from '@tanstack/react-router' import posthog from 'posthog-js' -import { Suspense, useContext, useMemo } from 'react' +import { Suspense, useContext, useEffect, useMemo, useState } from 'react' import { P, match } from 'ts-pattern' import { DevopsCopilotContext } from '@qovery/shared/devops-copilot/context' import { @@ -71,17 +71,25 @@ const EnvironmentLastDeploymentContent = () => { [deploymentHistory] ) const trigger_action = useMemo(() => lastDeployment?.trigger_action || 'UNKNOWN', [lastDeployment]) - const deploymentStartedLabel = useMemo( + const isOngoing = useMemo( () => match(lastDeployment?.status) - .with('DEPLOYING', 'RESTARTING', 'BUILDING', 'DELETING', 'CANCELING', 'STOPPING', () => 'Running since') - .otherwise(() => undefined), + .with('DEPLOYING', 'RESTARTING', 'BUILDING', 'DELETING', 'CANCELING', 'STOPPING', () => true) + .otherwise(() => false), [lastDeployment?.status] ) - const deploymentRelativeTime = useMemo( - () => (lastDeployment ? `${timeAgo(new Date(lastDeployment.auditing_data.created_at))} ago` : ''), - [lastDeployment] - ) + + const [, forceUpdate] = useState(0) + + useEffect(() => { + if (!isOngoing) return + const interval = setInterval(() => forceUpdate((n) => n + 1), 1000) + return () => clearInterval(interval) + }, [isOngoing]) + + const deploymentRelativeTime = !lastDeployment + ? '' + : `${timeAgo(new Date(lastDeployment.auditing_data.created_at))} ago` const logsLink = useLinkProps({ to: '/organization/$organizationId/project/$projectId/environment/$environmentId/deployments', @@ -161,7 +169,6 @@ const EnvironmentLastDeploymentContent = () => { )}
- {deploymentStartedLabel ? `${deploymentStartedLabel} ` : ''} {deploymentRelativeTime} diff --git a/libs/domains/service-logs/feature/src/lib/header-logs/header-logs.tsx b/libs/domains/service-logs/feature/src/lib/header-logs/header-logs.tsx index 63633412fc8..df231a24df0 100644 --- a/libs/domains/service-logs/feature/src/lib/header-logs/header-logs.tsx +++ b/libs/domains/service-logs/feature/src/lib/header-logs/header-logs.tsx @@ -1,6 +1,6 @@ import { useParams, useRouter, useSearch } from '@tanstack/react-router' import { DatabaseModeEnum, type Environment, type EnvironmentStatus, type Status } from 'qovery-typescript-axios' -import { type PropsWithChildren, useMemo } from 'react' +import { type PropsWithChildren, useEffect, useMemo, useState } from 'react' import { match } from 'ts-pattern' import { ServiceActions, @@ -47,9 +47,24 @@ export function HeaderLogs({ return service?.serviceType === 'DATABASE' && service?.mode === DatabaseModeEnum.MANAGED }, [service]) - if (!service) return null + const isOngoing = match(serviceStatus?.status_details?.status) + .with('ONGOING', 'CANCELING', () => true) + .otherwise(() => false) + + const [, forceUpdate] = useState(0) + + useEffect(() => { + if (!isOngoing) return + const interval = setInterval(() => forceUpdate((n) => n + 1), 1000) + return () => clearInterval(interval) + }, [isOngoing]) - const totalDurationSec = serviceStatus?.steps?.total_computing_duration_sec ?? 0 + const totalDurationSec = + isOngoing && serviceStatus?.last_deployment_date + ? Math.floor((Date.now() - new Date(serviceStatus.last_deployment_date).getTime()) / 1000) + : serviceStatus?.steps?.total_computing_duration_sec ?? 0 + + if (!service) return null const isNotDeployedOrStopped = serviceStatus?.status_details?.status === 'ERROR' || diff --git a/libs/domains/services/feature/src/lib/service-overview/service-last-deployment/service-last-deployment.spec.tsx b/libs/domains/services/feature/src/lib/service-overview/service-last-deployment/service-last-deployment.spec.tsx index 5bc5871ca1e..8d5a49fc3ae 100644 --- a/libs/domains/services/feature/src/lib/service-overview/service-last-deployment/service-last-deployment.spec.tsx +++ b/libs/domains/services/feature/src/lib/service-overview/service-last-deployment/service-last-deployment.spec.tsx @@ -169,7 +169,7 @@ describe('ServiceLastDeployment', () => { expect(clickEvent.defaultPrevented).toBe(true) }) - it('renders a running since label when the deployment is ongoing', () => { + it('renders a live relative time when the deployment is ongoing', () => { mockUseDeploymentHistory.mockReturnValue({ data: [ { @@ -191,9 +191,7 @@ describe('ServiceLastDeployment', () => { /> ) - expect( - screen.getByText((_, element) => element?.textContent === 'Running since mocked-time ago') - ).toBeInTheDocument() + expect(screen.getByText('mocked-time ago')).toBeInTheDocument() }) it('renders the AI diagnostic panel only when the last deployment failed', () => { diff --git a/libs/domains/services/feature/src/lib/service-overview/service-last-deployment/service-last-deployment.tsx b/libs/domains/services/feature/src/lib/service-overview/service-last-deployment/service-last-deployment.tsx index f17da436a8c..478d2fdffac 100644 --- a/libs/domains/services/feature/src/lib/service-overview/service-last-deployment/service-last-deployment.tsx +++ b/libs/domains/services/feature/src/lib/service-overview/service-last-deployment/service-last-deployment.tsx @@ -1,7 +1,7 @@ import { useParams } from '@tanstack/react-router' import posthog from 'posthog-js' import { type ApplicationGitRepository } from 'qovery-typescript-axios' -import { type MouseEvent, Suspense, useContext } from 'react' +import { type MouseEvent, Suspense, useContext, useEffect, useState } from 'react' import { P, match } from 'ts-pattern' import { type AnyService, type ServiceType } from '@qovery/domains/services/data-access' import { DevopsCopilotContext } from '@qovery/shared/devops-copilot/context' @@ -83,6 +83,18 @@ function ServiceLastDeploymentContent({ serviceId, serviceType, service }: Servi Boolean(gitRepository) && Boolean(service?.id && service?.name && service?.serviceType && 'environment' in service && service.environment) + const isOngoing = match(lastDeployment?.status_details?.status) + .with('ONGOING', 'CANCELING', () => true) + .otherwise(() => false) + + const [, forceUpdate] = useState(0) + + useEffect(() => { + if (!isOngoing) return + const interval = setInterval(() => forceUpdate((n) => n + 1), 1000) + return () => clearInterval(interval) + }, [isOngoing]) + if (!lastDeployment) { return ( 'Running since') - .otherwise(() => undefined) const deploymentRelativeTime = `${timeAgo(new Date(lastDeployment.auditing_data.created_at))} ago` const preventParentLinkNavigation = (event: MouseEvent) => { @@ -169,7 +178,6 @@ function ServiceLastDeploymentContent({ serviceId, serviceType, service }: Servi <> - {deploymentStartedLabel ? `${deploymentStartedLabel} ` : ''} {deploymentRelativeTime}