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}