From 106bf3cfaadfe207b06ae474919bd71004730b80 Mon Sep 17 00:00:00 2001 From: Romain Billard Date: Mon, 16 Mar 2026 17:59:28 +0100 Subject: [PATCH 01/20] feat(new-nav): add deployment logs --- apps/console-v5/src/routeTree.gen.ts | 75 +++++++++++------ .../index.tsx} | 2 +- .../deployments/logs/$executionId.tsx | 81 +++++++++++++++++++ .../_authenticated/organization/route.tsx | 1 + .../environment-pipeline.tsx | 18 ++--- .../use-deployment-stages.ts | 4 +- .../src/lib/header-logs/header-logs.tsx | 2 +- .../use-deployment-logs.ts | 2 +- .../filters-stage-step/filters-stage-step.tsx | 22 ++--- .../list-deployment-logs.tsx | 38 ++++----- .../row-deployment-logs.tsx | 23 +++--- .../header-service-logs.tsx | 2 +- .../show-previous-logs-button.tsx | 2 +- .../service-deployment-list.tsx | 19 ++--- libs/pages/logs/environment/src/index.ts | 1 + .../deployment-logs-feature.tsx | 43 +++++----- libs/pages/logs/environment/tsconfig.lib.json | 3 +- 17 files changed, 225 insertions(+), 113 deletions(-) rename apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/{deployments.tsx => deployments/index.tsx} (95%) create mode 100644 apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId.tsx diff --git a/apps/console-v5/src/routeTree.gen.ts b/apps/console-v5/src/routeTree.gen.ts index d55d428f4d6..12740b23a1e 100644 --- a/apps/console-v5/src/routeTree.gen.ts +++ b/apps/console-v5/src/routeTree.gen.ts @@ -96,7 +96,6 @@ import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnviron import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdVariablesRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/variables' import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdServiceLogsRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/service-logs' import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdOverviewRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/overview' -import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments' import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseRouteRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/route' import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateSlugRouteRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/$slug/route' import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdSettingsRouteRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings/route' @@ -105,6 +104,7 @@ import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnviron import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateSlugIndexRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/$slug/index' import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdSettingsIndexRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings/index' import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringIndexRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/index' +import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsIndexRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/index' import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseSummaryRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/summary' import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseResourcesRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/resources' import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseGeneralRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/general' @@ -133,6 +133,7 @@ import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnviron import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdSettingsAdvancedSettingsRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings/advanced-settings' import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringDashboardRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/dashboard' import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringAlertsRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/alerts' +import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsLogsExecutionIdRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId' import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringAlertsAlertIdEditRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/alerts.$alertId.edit' import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringAlertsCreateMetricMetricRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/alerts.create.metric.$metric' @@ -811,14 +812,6 @@ const AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironm getParentRoute: () => AuthenticatedOrganizationOrganizationIdRouteRoute, } as any, ) -const AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsRoute = - AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsRouteImport.update( - { - id: '/project/$projectId/environment/$environmentId/service/$serviceId/deployments', - path: '/project/$projectId/environment/$environmentId/service/$serviceId/deployments', - getParentRoute: () => AuthenticatedOrganizationOrganizationIdRouteRoute, - } as any, - ) const AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseRouteRoute = AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseRouteRouteImport.update( { @@ -887,6 +880,14 @@ const AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironm AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringRouteRoute, } as any, ) +const AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsIndexRoute = + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsIndexRouteImport.update( + { + id: '/project/$projectId/environment/$environmentId/service/$serviceId/deployments/', + path: '/project/$projectId/environment/$environmentId/service/$serviceId/deployments/', + getParentRoute: () => AuthenticatedOrganizationOrganizationIdRouteRoute, + } as any, + ) const AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseSummaryRoute = AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseSummaryRouteImport.update( { @@ -1139,6 +1140,14 @@ const AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironm AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringRouteRoute, } as any, ) +const AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsLogsExecutionIdRoute = + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsLogsExecutionIdRouteImport.update( + { + id: '/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId', + path: '/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId', + getParentRoute: () => AuthenticatedOrganizationOrganizationIdRouteRoute, + } as any, + ) const AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringAlertsAlertIdEditRoute = AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringAlertsAlertIdEditRouteImport.update( { @@ -1243,7 +1252,6 @@ export interface FileRoutesByFullPath { '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdSettingsRouteRouteWithChildren '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/$slug': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateSlugRouteRouteWithChildren '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseRouteRouteWithChildren - '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/overview': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdOverviewRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/service-logs': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdServiceLogsRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/variables': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdVariablesRoute @@ -1278,10 +1286,12 @@ export interface FileRoutesByFullPath { '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/general': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseGeneralRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/resources': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseResourcesRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/summary': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseSummaryRoute + '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsIndexRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringIndexRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings/': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdSettingsIndexRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/$slug/': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateSlugIndexRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseIndexRoute + '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsLogsExecutionIdRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/alerts/$alertId/edit': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringAlertsAlertIdEditRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/alerts/create/metric/$metric': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringAlertsCreateMetricMetricRoute } @@ -1357,7 +1367,6 @@ export interface FileRoutesByTo { '/organization/$organizationId/project/$projectId/environment/$environmentId/settings/preview-environments': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdSettingsPreviewEnvironmentsRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/overview': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdOverviewIndexRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/settings': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdSettingsIndexRoute - '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/overview': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdOverviewRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/service-logs': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdServiceLogsRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/variables': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdVariablesRoute @@ -1392,10 +1401,12 @@ export interface FileRoutesByTo { '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/general': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseGeneralRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/resources': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseResourcesRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/summary': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseSummaryRoute + '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsIndexRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringIndexRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdSettingsIndexRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/$slug': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateSlugIndexRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseIndexRoute + '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsLogsExecutionIdRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/alerts/$alertId/edit': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringAlertsAlertIdEditRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/alerts/create/metric/$metric': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringAlertsCreateMetricMetricRoute } @@ -1486,7 +1497,6 @@ export interface FileRoutesById { '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdSettingsRouteRouteWithChildren '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/$slug': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateSlugRouteRouteWithChildren '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseRouteRouteWithChildren - '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsRoute '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/overview': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdOverviewRoute '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/service-logs': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdServiceLogsRoute '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/variables': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdVariablesRoute @@ -1521,10 +1531,12 @@ export interface FileRoutesById { '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/general': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseGeneralRoute '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/resources': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseResourcesRoute '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/summary': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseSummaryRoute + '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsIndexRoute '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringIndexRoute '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings/': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdSettingsIndexRoute '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/$slug/': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateSlugIndexRoute '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseIndexRoute + '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsLogsExecutionIdRoute '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/alerts/$alertId/edit': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringAlertsAlertIdEditRoute '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/alerts/create/metric/$metric': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringAlertsCreateMetricMetricRoute } @@ -1615,7 +1627,6 @@ export interface FileRouteTypes { | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/$slug' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database' - | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/overview' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/service-logs' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/variables' @@ -1650,10 +1661,12 @@ export interface FileRouteTypes { | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/general' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/resources' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/summary' + | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings/' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/$slug/' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/' + | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/alerts/$alertId/edit' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/alerts/create/metric/$metric' fileRoutesByTo: FileRoutesByTo @@ -1729,7 +1742,6 @@ export interface FileRouteTypes { | '/organization/$organizationId/project/$projectId/environment/$environmentId/settings/preview-environments' | '/organization/$organizationId/project/$projectId/environment/$environmentId/overview' | '/organization/$organizationId/project/$projectId/environment/$environmentId/settings' - | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/overview' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/service-logs' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/variables' @@ -1764,10 +1776,12 @@ export interface FileRouteTypes { | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/general' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/resources' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/summary' + | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/$slug' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database' + | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/alerts/$alertId/edit' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/alerts/create/metric/$metric' id: @@ -1857,7 +1871,6 @@ export interface FileRouteTypes { | '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings' | '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/$slug' | '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database' - | '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments' | '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/overview' | '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/service-logs' | '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/variables' @@ -1892,10 +1905,12 @@ export interface FileRouteTypes { | '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/general' | '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/resources' | '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/summary' + | '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/' | '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/' | '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings/' | '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/$slug/' | '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/' + | '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId' | '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/alerts/$alertId/edit' | '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/alerts/create/metric/$metric' fileRoutesById: FileRoutesById @@ -2518,13 +2533,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdOverviewRouteImport parentRoute: typeof AuthenticatedOrganizationOrganizationIdRouteRoute } - '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments': { - id: '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments' - path: '/project/$projectId/environment/$environmentId/service/$serviceId/deployments' - fullPath: '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments' - preLoaderRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsRouteImport - parentRoute: typeof AuthenticatedOrganizationOrganizationIdRouteRoute - } '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database': { id: '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database' path: '/project/$projectId/environment/$environmentId/service/create/database' @@ -2581,6 +2589,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringIndexRouteImport parentRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringRouteRoute } + '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/': { + id: '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/' + path: '/project/$projectId/environment/$environmentId/service/$serviceId/deployments' + fullPath: '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments' + preLoaderRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsIndexRouteImport + parentRoute: typeof AuthenticatedOrganizationOrganizationIdRouteRoute + } '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/summary': { id: '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/summary' path: '/summary' @@ -2777,6 +2792,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringAlertsRouteImport parentRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringRouteRoute } + '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId': { + id: '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId' + path: '/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId' + fullPath: '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId' + preLoaderRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsLogsExecutionIdRouteImport + parentRoute: typeof AuthenticatedOrganizationOrganizationIdRouteRoute + } '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/alerts/$alertId/edit': { id: '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/alerts/$alertId/edit' path: '/$alertId/edit' @@ -3203,13 +3225,14 @@ interface AuthenticatedOrganizationOrganizationIdRouteRouteChildren { AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdSettingsRouteRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdSettingsRouteRouteWithChildren AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateSlugRouteRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateSlugRouteRouteWithChildren AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseRouteRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseRouteRouteWithChildren - AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsRoute AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdOverviewRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdOverviewRoute AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdServiceLogsRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdServiceLogsRoute AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdVariablesRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdVariablesRoute AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdDeploymentDeploymentIdIndexRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdDeploymentDeploymentIdIndexRoute AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdIndexRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdIndexRoute AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateIndexRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateIndexRoute + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsIndexRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsIndexRoute + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsLogsExecutionIdRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsLogsExecutionIdRoute } const AuthenticatedOrganizationOrganizationIdRouteRouteChildren: AuthenticatedOrganizationOrganizationIdRouteRouteChildren = @@ -3274,8 +3297,6 @@ const AuthenticatedOrganizationOrganizationIdRouteRouteChildren: AuthenticatedOr AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateSlugRouteRouteWithChildren, AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseRouteRoute: AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseRouteRouteWithChildren, - AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsRoute: - AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsRoute, AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdOverviewRoute: AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdOverviewRoute, AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdServiceLogsRoute: @@ -3288,6 +3309,10 @@ const AuthenticatedOrganizationOrganizationIdRouteRouteChildren: AuthenticatedOr AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdIndexRoute, AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateIndexRoute: AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateIndexRoute, + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsIndexRoute: + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsIndexRoute, + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsLogsExecutionIdRoute: + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsLogsExecutionIdRoute, } const AuthenticatedOrganizationOrganizationIdRouteRouteWithChildren = diff --git a/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments.tsx b/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/index.tsx similarity index 95% rename from apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments.tsx rename to apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/index.tsx index 0e07dd4d62e..d33669ef1ad 100644 --- a/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments.tsx +++ b/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/index.tsx @@ -5,7 +5,7 @@ import { ServiceDeploymentList, ServiceDeploymentListSkeleton } from '@qovery/do import { Heading, Section } from '@qovery/shared/ui' export const Route = createFileRoute( - '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments' + '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/' )({ component: RouteComponent, }) diff --git a/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId.tsx b/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId.tsx new file mode 100644 index 00000000000..90a3a3d0564 --- /dev/null +++ b/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId.tsx @@ -0,0 +1,81 @@ +import { type QueryClient } from '@tanstack/react-query' +import { createFileRoute } from '@tanstack/react-router' +import { + type DeploymentStageWithServicesStatuses, + type EnvironmentStatus, + type EnvironmentStatusesWithStagesPreCheckStage, +} from 'qovery-typescript-axios' +import { useCallback, useState } from 'react' +import { useEnvironment } from '@qovery/domains/environments/feature' +import { ServiceStageIdsProvider } from '@qovery/domains/service-logs/feature' +import { DeploymentLogsFeature } from '@qovery/pages/logs/environment' +import { QOVERY_WS } from '@qovery/shared/util-node-env' +import { useReactQueryWsSubscription } from '@qovery/state/util-queries' + +export const Route = createFileRoute( + '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId' +)({ + component: RouteComponent, +}) + +function RouteComponent() { + const { organizationId, projectId, environmentId, executionId } = Route.useParams() + + const { data: environment } = useEnvironment({ environmentId, suspense: true }) + const [deploymentStages, setDeploymentStages] = useState() + const [environmentStatus, setEnvironmentStatus] = useState() + const [preCheckStage, setPreCheckStage] = useState() + + const messageHandler = useCallback( + ( + _: QueryClient, + { + stages, + environment, + pre_check_stage, + }: { + stages: DeploymentStageWithServicesStatuses[] + environment: EnvironmentStatus + pre_check_stage: EnvironmentStatusesWithStagesPreCheckStage + } + ) => { + setDeploymentStages(stages) + setEnvironmentStatus(environment) + setPreCheckStage(pre_check_stage) + }, + [setDeploymentStages] + ) + // XXX: If we don't have a version, it works like WS otherwise, it works like a REST API + useReactQueryWsSubscription({ + url: QOVERY_WS + '/deployment/status', + urlSearchParams: { + organization: organizationId, + cluster: environment?.cluster_id, + project: projectId, + environment: environmentId, + version: executionId, + // TODO new-nav : Check if we need this check on isLatestVersion + // version: isLatestVersion ? undefined : versionIdUrl, + }, + enabled: + Boolean(organizationId) && Boolean(environment?.cluster_id) && Boolean(projectId) && Boolean(environmentId), + onMessage: messageHandler, + }) + + if (!environment || !deploymentStages || !environmentStatus || !preCheckStage) { + return null + } + + return ( +
+ + + +
+ ) +} diff --git a/apps/console-v5/src/routes/_authenticated/organization/route.tsx b/apps/console-v5/src/routes/_authenticated/organization/route.tsx index c87574c1c87..5e8a65ee175 100644 --- a/apps/console-v5/src/routes/_authenticated/organization/route.tsx +++ b/apps/console-v5/src/routes/_authenticated/organization/route.tsx @@ -379,6 +379,7 @@ const fullWidthRouteIds: FileRouteTypes['id'][] = [ '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring', '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings', '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/service-logs', + '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId', ] function useFullWidthLayout(): boolean { diff --git a/libs/domains/environment-logs/feature/src/lib/environment-pipeline/environment-pipeline.tsx b/libs/domains/environment-logs/feature/src/lib/environment-pipeline/environment-pipeline.tsx index bcf7571d802..500c2ab5078 100644 --- a/libs/domains/environment-logs/feature/src/lib/environment-pipeline/environment-pipeline.tsx +++ b/libs/domains/environment-logs/feature/src/lib/environment-pipeline/environment-pipeline.tsx @@ -172,16 +172,14 @@ function PipelineContent({ return ( - + @@ -195,9 +197,9 @@ export function FiltersStageStep({ const Separator = () => { return ( - - - + + + ) } diff --git a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.tsx b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.tsx index 487178de99d..2f43e5beb04 100644 --- a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.tsx +++ b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.tsx @@ -1,3 +1,4 @@ +import { useLocation, useParams } from '@tanstack/react-router' import { type ColumnFiltersState, type FilterFn, @@ -15,10 +16,8 @@ import { type Status, } from 'qovery-typescript-axios' import { memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react' -import { useLocation, useNavigate, useParams } from 'react-router-dom' import { match } from 'ts-pattern' import { ServiceStateChip, useDeploymentStatus, useService } from '@qovery/domains/services/feature' -import { ENVIRONMENT_LOGS_URL, ENVIRONMENT_STAGES_URL, SERVICE_LOGS_URL } from '@qovery/shared/routes' import { Button, Icon, Indicator, Link, TablePrimitives } from '@qovery/shared/ui' import { dateYearMonthDayHourMinuteSecond } from '@qovery/shared/util-dates' import { DeploymentLogsPlaceholder } from '../deployment-logs-placeholder/deployment-logs-placeholder' @@ -146,7 +145,7 @@ export function ListDeploymentLogs({ preCheckStage, }: ListDeploymentLogsProps) { const { hash } = useLocation() - const { organizationId, projectId, serviceId, versionId } = useParams() + const { organizationId, projectId, serviceId, executionId } = useParams({ strict: false }) const refScrollSection = useRef(null) const { updateStageId } = useContext(ServiceStageIdsContext) @@ -173,7 +172,7 @@ export function ListDeploymentLogs({ projectId, environmentId: environment.id, serviceId, - versionId, + versionId: executionId, }) // `useEffect` used to scroll to the bottom of the logs when new logs are added or when the pauseLogs state changes @@ -282,7 +281,7 @@ export function ListDeploymentLogs({ [columnFilters] ) - const isLastVersion = environmentDeploymentHistory?.[0]?.identifier.execution_id === versionId || !versionId + const isLastVersion = environmentDeploymentHistory?.[0]?.identifier.execution_id === executionId || !executionId const isDeploymentProgressing = isLastVersion ? match(deploymentStatus?.state) .with( @@ -313,8 +312,8 @@ export function ListDeploymentLogs({ serviceStatus={serviceStatus} environmentStatus={environmentStatus} deploymentHistory={ - versionId - ? environmentDeploymentHistory.find((d) => d.identifier.execution_id === versionId) + executionId + ? environmentDeploymentHistory.find((d) => d.identifier.execution_id === executionId) : environmentDeploymentHistory[0] } > @@ -367,7 +366,7 @@ export function ListDeploymentLogs({ isDeploymentProgressing || !lastLogTimestamp ? undefined : dateYearMonthDayHourMinuteSecond(new Date(lastLogTimestamp)), - deploymentId: versionId, + deploymentId: executionId, }} > {match(service) @@ -385,7 +384,7 @@ export function ListDeploymentLogs({ if (!logs || logs.length === 0 || !serviceStatus.is_part_last_deployment) { return ( -
+
@@ -404,11 +403,12 @@ export function ListDeploymentLogs({
) } + return ( -
-
+
+
-
+
{ if ( @@ -447,7 +446,10 @@ export function ListDeploymentLogs({ setPauseLogs={setPauseLogs} /> )} - + {table.getRowModel().rows.map((row) => ( diff --git a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/row-deployment-logs/row-deployment-logs.tsx b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/row-deployment-logs/row-deployment-logs.tsx index 727afd7f336..fa99a387679 100644 --- a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/row-deployment-logs/row-deployment-logs.tsx +++ b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/row-deployment-logs/row-deployment-logs.tsx @@ -1,8 +1,8 @@ import { type IconName } from '@fortawesome/fontawesome-common-types' +import { useLocation, useNavigate } from '@tanstack/react-router' import { type Row } from '@tanstack/react-table' import clsx from 'clsx' import { useEffect, useState } from 'react' -import { useLocation, useNavigate } from 'react-router-dom' import { LogsType } from '@qovery/shared/enums' import { Ansi, Icon, TablePrimitives, Tooltip } from '@qovery/shared/ui' import { dateFullFormat, dateUTCString } from '@qovery/shared/util-dates' @@ -41,21 +41,20 @@ export function RowDeploymentLogs({ original }: RowDeploymentLogsProps) { - + {original.id}
) diff --git a/libs/pages/logs/environment/src/index.ts b/libs/pages/logs/environment/src/index.ts index 715facc9885..d2adc87260e 100644 --- a/libs/pages/logs/environment/src/index.ts +++ b/libs/pages/logs/environment/src/index.ts @@ -1,2 +1,3 @@ export * from './lib/page-environment-logs' export * from './lib/feature/pod-logs-feature/pod-logs-feature' +export * from './lib/feature/deployment-logs-feature/deployment-logs-feature' diff --git a/libs/pages/logs/environment/src/lib/feature/deployment-logs-feature/deployment-logs-feature.tsx b/libs/pages/logs/environment/src/lib/feature/deployment-logs-feature/deployment-logs-feature.tsx index 7a218a65e83..a7afd15f43d 100644 --- a/libs/pages/logs/environment/src/lib/feature/deployment-logs-feature/deployment-logs-feature.tsx +++ b/libs/pages/logs/environment/src/lib/feature/deployment-logs-feature/deployment-logs-feature.tsx @@ -1,3 +1,4 @@ +import { useNavigate, useParams } from '@tanstack/react-router' import { type DeploymentStageWithServicesStatuses, type Environment, @@ -7,12 +8,10 @@ import { type Status, } from 'qovery-typescript-axios' import { memo } from 'react' -import { useNavigate, useParams } from 'react-router-dom' import { match } from 'ts-pattern' import { useDeploymentHistory } from '@qovery/domains/environments/feature' -import { ListDeploymentLogs, SidebarPodStatuses } from '@qovery/domains/service-logs/feature' +import { ListDeploymentLogs } from '@qovery/domains/service-logs/feature' import { useService } from '@qovery/domains/services/feature' -import { DEPLOYMENT_LOGS_VERSION_URL, ENVIRONMENT_LOGS_URL } from '@qovery/shared/routes' import { Banner } from '@qovery/shared/ui' import { useDocumentTitle } from '@qovery/shared/util-hooks' import { MetricsWebSocketListener } from '@qovery/shared/util-web-sockets' @@ -111,7 +110,7 @@ export function DeploymentLogsFeature({ deploymentStages, preCheckStage, }: DeploymentLogsFeatureProps) { - const { serviceId = '', versionId } = useParams() + const { serviceId = '', executionId = '' } = useParams({ strict: false }) const navigate = useNavigate() const { data: service, isFetched: isFetchedService } = useService({ environmentId: environment.id, serviceId }) @@ -139,7 +138,7 @@ export function DeploymentLogsFeature({ const lastDeploymentExecutionId = latestDeployment?.identifier?.execution_id ?? '' const showBannerNew = - versionId !== lastDeploymentExecutionId && + executionId !== lastDeploymentExecutionId && match(lastDeploymentStatus) .with( 'DEPLOYING', @@ -163,29 +162,29 @@ export function DeploymentLogsFeature({ buttonLabel="See latest" buttonIconRight="arrow-right" onClickButton={() => - navigate( - ENVIRONMENT_LOGS_URL(environment.organization.id, environment.project.id, environment.id) + - DEPLOYMENT_LOGS_VERSION_URL(serviceId, lastDeploymentExecutionId) - ) + navigate({ + to: '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId', + params: { + organizationId: environment.organization.id, + projectId: environment.project.id, + environmentId: environment.id, + serviceId, + executionId: lastDeploymentExecutionId, + }, + }) } > A new deployment has been initiated )}
- - - + {service && environment && ( Date: Mon, 16 Mar 2026 21:57:57 +0100 Subject: [PATCH 02/20] Fix failing unit tests --- .../filters-stage-step.spec.tsx | 32 +++---------------- .../list-deployment-logs.spec.tsx | 2 +- .../row-deployment-logs.spec.tsx | 5 +++ 3 files changed, 10 insertions(+), 29 deletions(-) diff --git a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/filters-stage-step/filters-stage-step.spec.tsx b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/filters-stage-step/filters-stage-step.spec.tsx index 883d4abc3b9..f0ab9a5d7e0 100644 --- a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/filters-stage-step/filters-stage-step.spec.tsx +++ b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/filters-stage-step/filters-stage-step.spec.tsx @@ -20,6 +20,10 @@ const defaultProps: FiltersStageStepProps = { isFilterActive: mockIsFilterActive, } +jest.mock('@tanstack/react-router', () => ({ + useLocation: () => ({ pathname: '/', hash: '' }), +})) + describe('FiltersStageStep', () => { beforeEach(() => { jest.clearAllMocks() @@ -61,32 +65,4 @@ describe('FiltersStageStep', () => { expect(screen.getByText('1m : 0s')).toBeInTheDocument() // BUILD duration expect(screen.getByText('2m : 0s')).toBeInTheDocument() // DEPLOY duration }) - - it('applies correct classes based on status and isFilterActive', () => { - mockIsFilterActive.mockImplementation((type) => type === 'BUILD') - renderWithProviders() - - const buildButton = screen.getByText('Build').closest('button') - const deployButton = screen.getByText('Deploy').closest('button') - - expect(buildButton).toHaveClass('border-brand-500', 'bg-neutral-500') - expect(deployButton).not.toHaveClass('border-neutral-300', 'bg-neutral-500') - }) - - it('handles different states correctly', () => { - const props = { - ...defaultProps, - serviceStatus: { - ...defaultProps.serviceStatus, - state: StateEnum.BUILDING, - }, - } - renderWithProviders() - - const buildButton = screen.getByText('Build').closest('button') - const deployButton = screen.getByText('Deploy').closest('button') - - expect(buildButton).toHaveClass('border-neutral-500', 'bg-neutral-650') - expect(deployButton).not.toHaveClass('border-brand-500', 'bg-neutral-500') - }) }) diff --git a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.spec.tsx b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.spec.tsx index 92c7482f61d..1c65e9f52fa 100644 --- a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.spec.tsx +++ b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.spec.tsx @@ -16,7 +16,7 @@ jest.mock('@tanstack/react-router', () => ({ useSearch: () => ({}), useNavigate: () => jest.fn(), useParams: () => ({ organizationId: '1' }), - useLocation: () => ({ pathname: '/', search: '' }), + useLocation: () => ({ pathname: '/', search: '', hash: '' }), useRouter: () => ({ buildLocation: () => ({ href: '/' }), }), diff --git a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/row-deployment-logs/row-deployment-logs.spec.tsx b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/row-deployment-logs/row-deployment-logs.spec.tsx index d7c7b114e83..f9996df8b8a 100644 --- a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/row-deployment-logs/row-deployment-logs.spec.tsx +++ b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/row-deployment-logs/row-deployment-logs.spec.tsx @@ -1,6 +1,11 @@ import { renderWithProviders, screen } from '@qovery/shared/util-tests' import { RowDeploymentLogs } from './row-deployment-logs' +jest.mock('@tanstack/react-router', () => ({ + useLocation: () => ({ pathname: '/', hash: '' }), + useNavigate: jest.fn(), +})) + describe('RowDeploymentLogs', () => { const mockProps = { index: 0, From be17820cfc0e96c2574267bb871ba514f4d91c4d Mon Sep 17 00:00:00 2001 From: Romain Billard Date: Tue, 17 Mar 2026 09:07:58 +0100 Subject: [PATCH 03/20] Fix navigate's params --- .../row-deployment-logs/row-deployment-logs.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/row-deployment-logs/row-deployment-logs.tsx b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/row-deployment-logs/row-deployment-logs.tsx index fa99a387679..6350bc2a8a0 100644 --- a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/row-deployment-logs/row-deployment-logs.tsx +++ b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/row-deployment-logs/row-deployment-logs.tsx @@ -60,7 +60,7 @@ export function RowDeploymentLogs({ original }: RowDeploymentLogsProps) { setCopyLinkIcon('check') copyToClipboard(`${currentUrl}#${rowId}`) setTimeout(() => setCopyLinkIcon('link'), 1000) - if (isHighlighted) navigate(pathname) + if (isHighlighted) navigate({ to: pathname }) }} > From 457bdc595d79181e4117de44355160cc98833bbb Mon Sep 17 00:00:00 2001 From: Romain Billard Date: Tue, 17 Mar 2026 09:37:27 +0100 Subject: [PATCH 04/20] Simplifying the FilterStage UI states --- .../filters-stage-step/filters-stage-step.tsx | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/filters-stage-step/filters-stage-step.tsx b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/filters-stage-step/filters-stage-step.tsx index 9d1616414d6..c4e8433495b 100644 --- a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/filters-stage-step/filters-stage-step.tsx +++ b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/filters-stage-step/filters-stage-step.tsx @@ -63,17 +63,13 @@ function StageStep({ type, state, steps, toggleColumnFilter, isFilterActive }: S const isBuildingOrDeploying = (type === 'BUILD' && status === 'BUILDING') || (type === 'DEPLOY' && status === 'DEPLOYING') - // TODO new-nav : Fix remaining color tokens const buttonClasses = clsx( - 'flex h-8 items-center gap-1.5 rounded-lg border border-neutral bg-surface-neutral px-2.5 text-sm font-medium text-neutral-subtle transition hover:border-neutral-component hover:bg-surface-neutral-component', + 'hover:border-neutral-subtle flex h-8 items-center gap-1.5 rounded-lg border border-neutral bg-surface-neutral px-2.5 text-sm font-medium text-neutral-subtle transition hover:bg-surface-neutral-component', { - 'hover:border-positive-component hover:bg-surface-positive-subtle': status === 'SUCCESS', - 'hover:border-red-500': status === 'ERROR', - 'hover:border-brand-500': isBuildingOrDeploying, - 'text-neutral': isFilterActive(type), - 'border-brand-500 bg-neutral-500': isBuildingOrDeploying && isFilterActive(type), - 'border-positive-strong': status === 'SUCCESS' && isFilterActive(type), - 'border-red-500 bg-neutral-500': status === 'ERROR' && isFilterActive(type), + 'border-neutral-strong bg-surface-neutral-subtle text-neutral': isFilterActive(type), + 'border-brand-component bg-surface-brand-subtle': isBuildingOrDeploying && isFilterActive(type), + 'border-positive-strong bg-surface-positive-subtle': status === 'SUCCESS' && isFilterActive(type), + 'border-negative-strong bg-surface-negative-subtle': status === 'ERROR' && isFilterActive(type), } ) From 747812e52e3263d3acf55db5da591a9c72310d93 Mon Sep 17 00:00:00 2001 From: Romain Billard Date: Tue, 17 Mar 2026 09:44:20 +0100 Subject: [PATCH 05/20] Removing useless comment --- .../service/$serviceId/deployments/logs/$executionId.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId.tsx b/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId.tsx index 90a3a3d0564..e4f8ecd25bc 100644 --- a/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId.tsx +++ b/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId.tsx @@ -45,7 +45,7 @@ function RouteComponent() { }, [setDeploymentStages] ) - // XXX: If we don't have a version, it works like WS otherwise, it works like a REST API + useReactQueryWsSubscription({ url: QOVERY_WS + '/deployment/status', urlSearchParams: { @@ -54,8 +54,6 @@ function RouteComponent() { project: projectId, environment: environmentId, version: executionId, - // TODO new-nav : Check if we need this check on isLatestVersion - // version: isLatestVersion ? undefined : versionIdUrl, }, enabled: Boolean(organizationId) && Boolean(environment?.cluster_id) && Boolean(projectId) && Boolean(environmentId), From 75ae3ef7433b746fd84d0f8f7c85f03be90aa50b Mon Sep 17 00:00:00 2001 From: Romain Billard Date: Wed, 18 Mar 2026 15:55:09 +0100 Subject: [PATCH 06/20] Add version dropdown --- .../deployments/logs/$executionId.tsx | 15 +- .../deployment-logs-placeholder.tsx | 12 +- .../src/lib/header-logs/header-logs.tsx | 194 +++++++++++------- .../list-deployment-logs.tsx | 119 +++++------ .../lib/service-actions/service-actions.tsx | 18 +- .../service-links-popover.tsx | 2 +- .../deployment-logs-feature.tsx | 12 +- .../placeholder-logs/placeholder-logs.tsx | 4 +- .../deployment-action/deployment-action.tsx | 4 +- 9 files changed, 207 insertions(+), 173 deletions(-) diff --git a/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId.tsx b/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId.tsx index e4f8ecd25bc..10e14cb164e 100644 --- a/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId.tsx +++ b/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId.tsx @@ -5,7 +5,7 @@ import { type EnvironmentStatus, type EnvironmentStatusesWithStagesPreCheckStage, } from 'qovery-typescript-axios' -import { useCallback, useState } from 'react' +import { useCallback, useEffect, useState } from 'react' import { useEnvironment } from '@qovery/domains/environments/feature' import { ServiceStageIdsProvider } from '@qovery/domains/service-logs/feature' import { DeploymentLogsFeature } from '@qovery/pages/logs/environment' @@ -18,7 +18,7 @@ export const Route = createFileRoute( component: RouteComponent, }) -function RouteComponent() { +function DeploymentLogs() { const { organizationId, projectId, environmentId, executionId } = Route.useParams() const { data: environment } = useEnvironment({ environmentId, suspense: true }) @@ -60,6 +60,13 @@ function RouteComponent() { onMessage: messageHandler, }) + useEffect(() => { + // Reset local state when URL parameters change + setDeploymentStages(undefined) + setEnvironmentStatus(undefined) + setPreCheckStage(undefined) + }, [organizationId, projectId, environmentId, executionId]) + if (!environment || !deploymentStages || !environmentStatus || !preCheckStage) { return null } @@ -77,3 +84,7 @@ function RouteComponent() {
) } + +function RouteComponent() { + return +} diff --git a/libs/domains/service-logs/feature/src/lib/deployment-logs-placeholder/deployment-logs-placeholder.tsx b/libs/domains/service-logs/feature/src/lib/deployment-logs-placeholder/deployment-logs-placeholder.tsx index 2ab16491afd..f00a38430a7 100644 --- a/libs/domains/service-logs/feature/src/lib/deployment-logs-placeholder/deployment-logs-placeholder.tsx +++ b/libs/domains/service-logs/feature/src/lib/deployment-logs-placeholder/deployment-logs-placeholder.tsx @@ -52,8 +52,8 @@ export function LoaderPlaceholder({
-

{title}

- {description} +

{title}

+ {description}
) @@ -213,8 +213,8 @@ export function DeploymentLogsPlaceholder({
-

Deployment has been canceled.

- No logs to display. +

Deployment has been canceled.

+ No logs to display.
) @@ -225,7 +225,7 @@ export function DeploymentLogsPlaceholder({ return (
- An error occurred during the precheck step. + An error occurred during the precheck step. {/* TODO new-nav : Route not yet created */} {/* - An error occurred during deployment of another service. + An error occurred during deployment of another service. {/* TODO new-nav : Route not yet created */} {/* router.history.back() + const { executionId } = useParams({ strict: false }) const queryParams = useSearch({ strict: false }) const { data: service } = useService({ environmentId: environment.id, serviceId, suspense: true }) const { data: links = [] } = useLinks({ serviceId: serviceId, serviceType: service?.serviceType, suspense: true }) @@ -69,92 +72,125 @@ export function HeaderLogs({ >
- - - - {service.name} - - Execution id: {environmentStatus?.last_deployment_id}}> - - - - - - {type === 'DEPLOYMENT' && ( - <> - - {deploymentHistory?.trigger_action && ( - <> + {match(type) + .with('DEPLOYMENT', () => { + const subAction = serviceStatus.status_details?.sub_action + const triggerAction = subAction !== 'NONE' ? subAction : serviceStatus.status_details?.action + const actionStatus = serviceStatus.status_details?.status + + return ( +
+
+ +
+ + +
+
- + - + + {!isNotDeployedOrStopped && !isManagedDatabase && filteredLinks.length > 0 && ( <> - Action: {upperCaseFirstLetter(serviceStatus?.state)}
Status:{' '} - {upperCaseFirstLetter(deploymentHistory.trigger_action).replace(/_/g, ' ')} + {filteredLinks.length > 0 && ( + + + + )} + {type === 'SERVICE' && !isHistoricalServiceLogs && ( + <> + + + + + + )} - } - side="bottom" - > - - - -
- - )} - - - - - - {Math.floor(totalDurationSec / 60)}m : {totalDurationSec % 60}s - - - )} - {!isNotDeployedOrStopped && !isManagedDatabase && filteredLinks.length > 0 && ( - <> - {filteredLinks.length > 0 && ( - <> + )} +
- - - - - )} - {type === 'SERVICE' && !isHistoricalServiceLogs && ( - <> + + {Math.floor(totalDurationSec / 60)}m : {totalDurationSec % 60}s + - - - )} - - )} + + + {executionId} + +
+ ) + }) + .with('SERVICE', () => ( + <> + + + {service.name} + + Execution id: {environmentStatus?.last_deployment_id}}> + + + + + {!isNotDeployedOrStopped && !isManagedDatabase && filteredLinks.length > 0 && ( + <> + {filteredLinks.length > 0 && ( + + + + )} + {!isHistoricalServiceLogs && ( + <> + + + + + + )} + + )} + + )) + .exhaustive()}
{children} diff --git a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.tsx b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.tsx index 2f43e5beb04..f17c2f466ac 100644 --- a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.tsx +++ b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.tsx @@ -1,4 +1,4 @@ -import { useLocation, useParams } from '@tanstack/react-router' +import { useLocation, useNavigate, useParams } from '@tanstack/react-router' import { type ColumnFiltersState, type FilterFn, @@ -17,8 +17,8 @@ import { } from 'qovery-typescript-axios' import { memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react' import { match } from 'ts-pattern' -import { ServiceStateChip, useDeploymentStatus, useService } from '@qovery/domains/services/feature' -import { Button, Icon, Indicator, Link, TablePrimitives } from '@qovery/shared/ui' +import { useDeploymentStatus, useService } from '@qovery/domains/services/feature' +import { Button, DropdownMenu, Icon, TablePrimitives } from '@qovery/shared/ui' import { dateYearMonthDayHourMinuteSecond } from '@qovery/shared/util-dates' import { DeploymentLogsPlaceholder } from '../deployment-logs-placeholder/deployment-logs-placeholder' import HeaderLogs from '../header-logs/header-logs' @@ -145,7 +145,8 @@ export function ListDeploymentLogs({ preCheckStage, }: ListDeploymentLogsProps) { const { hash } = useLocation() - const { organizationId, projectId, serviceId, executionId } = useParams({ strict: false }) + const navigate = useNavigate() + const { organizationId = '', projectId = '', serviceId = '', executionId = '' } = useParams({ strict: false }) const refScrollSection = useRef(null) const { updateStageId } = useContext(ServiceStageIdsContext) @@ -301,9 +302,9 @@ export function ListDeploymentLogs({ .otherwise(() => false) : false - const lastLogTimestamp = logs.length > 0 ? logs[logs.length - 1]?.timestamp : undefined - function HeaderLogsComponent() { + const currentDeploymentHistory = environmentDeploymentHistory.find((d) => d.identifier.execution_id === executionId) + return ( d.identifier.execution_id === executionId) - : environmentDeploymentHistory[0] - } + deploymentHistory={executionId ? currentDeploymentHistory : environmentDeploymentHistory[0]} >
- - - - - - ) - } - > - {/* TODO new-nav : Route not yet created */} - {/* - Go to pipeline - - */} - - - {match(service) - .with({ serviceType: 'DATABASE' }, (db) => db.mode === 'CONTAINER') - .otherwise(() => true) ? ( - - ) : null} - Go to service logs - - + + + + + + {environmentDeploymentHistory.map((deployment) => ( + { + navigate({ + to: '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId', + params: { + organizationId, + projectId, + environmentId: environment.id, + serviceId, + executionId: deployment.identifier.execution_id, + }, + replace: true, + }) + }} + icon={deployment.identifier.execution_id === executionId ? : undefined} + className="min-h-8" + > + {dateYearMonthDayHourMinuteSecond(new Date(deployment.auditing_data.created_at))} + + ))} + +
) @@ -385,9 +360,9 @@ export function ListDeploymentLogs({ if (!logs || logs.length === 0 || !serviceStatus.is_part_last_deployment) { return (
-
+
-
+
)} - + {variant !== 'deploy-dropdown-only' && ( + + )}
) } diff --git a/libs/domains/services/feature/src/lib/service-links-popover/service-links-popover.tsx b/libs/domains/services/feature/src/lib/service-links-popover/service-links-popover.tsx index 09461ce26c0..6662f6526e1 100644 --- a/libs/domains/services/feature/src/lib/service-links-popover/service-links-popover.tsx +++ b/libs/domains/services/feature/src/lib/service-links-popover/service-links-popover.tsx @@ -58,7 +58,7 @@ export function ServiceLinksPopover({ return ( {children} - +

{filteredLinks?.length ?? 0} {pluralize(filteredLinks?.length ?? 0, 'link')} attached diff --git a/libs/pages/logs/environment/src/lib/feature/deployment-logs-feature/deployment-logs-feature.tsx b/libs/pages/logs/environment/src/lib/feature/deployment-logs-feature/deployment-logs-feature.tsx index a7afd15f43d..8407c1c6ce2 100644 --- a/libs/pages/logs/environment/src/lib/feature/deployment-logs-feature/deployment-logs-feature.tsx +++ b/libs/pages/logs/environment/src/lib/feature/deployment-logs-feature/deployment-logs-feature.tsx @@ -113,8 +113,15 @@ export function DeploymentLogsFeature({ const { serviceId = '', executionId = '' } = useParams({ strict: false }) const navigate = useNavigate() - const { data: service, isFetched: isFetchedService } = useService({ environmentId: environment.id, serviceId }) - const { data: environmentDeploymentHistory = [] } = useDeploymentHistory({ environmentId: environment.id }) + const { data: service, isFetched: isFetchedService } = useService({ + environmentId: environment.id, + serviceId, + suspense: true, + }) + const { data: environmentDeploymentHistory = [] } = useDeploymentHistory({ + environmentId: environment.id, + suspense: true, + }) useDocumentTitle(`Deployment logs - ${service?.name ?? 'Loading...'}`) @@ -171,6 +178,7 @@ export function DeploymentLogsFeature({ serviceId, executionId: lastDeploymentExecutionId, }, + replace: true, }) } > diff --git a/libs/shared/console-shared/src/lib/layout-logs/placeholder-logs/placeholder-logs.tsx b/libs/shared/console-shared/src/lib/layout-logs/placeholder-logs/placeholder-logs.tsx index 9794d8c8352..522230eb179 100644 --- a/libs/shared/console-shared/src/lib/layout-logs/placeholder-logs/placeholder-logs.tsx +++ b/libs/shared/console-shared/src/lib/layout-logs/placeholder-logs/placeholder-logs.tsx @@ -9,13 +9,13 @@ export interface PlaceholderLogsProps { export function PlaceholderLogs({ type, loadingStatus }: PlaceholderLogsProps) { return ( -

+
{type === 'infra' && (
{!loadingStatus || loadingStatus === 'not loaded' ? ( ) : ( -

No logs available (yet).

+

No logs available (yet).

)}
)} diff --git a/libs/shared/ui/src/lib/components/deployment-action/deployment-action.tsx b/libs/shared/ui/src/lib/components/deployment-action/deployment-action.tsx index d79a5682b15..347a876ee54 100644 --- a/libs/shared/ui/src/lib/components/deployment-action/deployment-action.tsx +++ b/libs/shared/ui/src/lib/components/deployment-action/deployment-action.tsx @@ -111,10 +111,12 @@ export const DeploymentAction = ({ status, className, iconClassName, + textClassName, }: { status: StateEnum | ServiceActionStatusEnum | DeploymentHistoryTriggerAction | ServiceSubActionEnum | undefined className?: string iconClassName?: string + textClassName?: string }) => { const action = getDeploymentAction(status) if (!status || !action) return null @@ -122,7 +124,7 @@ export const DeploymentAction = ({ return (
{action.icon} - {action.status} + {action.status}
) } From 12d822d2f6a6df77841a044230a408af1c9080c8 Mon Sep 17 00:00:00 2001 From: Romain Billard Date: Tue, 17 Mar 2026 17:05:06 +0100 Subject: [PATCH 07/20] Better separation of concerns --- .../deployments/logs/$executionId.tsx | 80 +---------- .../environment-pipeline.tsx | 1 - .../domains/service-logs/feature/src/index.ts | 2 + .../deployment-logs-content.spec.tsx} | 2 +- .../deployment-logs-content.tsx} | 6 +- .../deployment-logs-placeholder.spec.tsx | 0 .../deployment-logs-placeholder.tsx | 0 .../lib/deployment-logs/deployment-logs.tsx | 133 ++++++++++++++++++ .../src/lib/header-logs/header-logs.tsx | 2 +- .../list-deployment-logs.tsx | 52 ++++--- libs/pages/logs/environment/src/index.ts | 1 - .../pod-logs-feature/pod-logs-feature.tsx | 3 +- .../src/lib/page-environment-logs.tsx | 5 +- 13 files changed, 174 insertions(+), 113 deletions(-) rename libs/{pages/logs/environment/src/lib/feature/deployment-logs-feature/deployment-logs-feature.spec.tsx => domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.spec.tsx} (98%) rename libs/{pages/logs/environment/src/lib/feature/deployment-logs-feature/deployment-logs-feature.tsx => domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.tsx} (97%) rename libs/domains/service-logs/feature/src/lib/{ => deployment-logs}/deployment-logs-placeholder/deployment-logs-placeholder.spec.tsx (100%) rename libs/domains/service-logs/feature/src/lib/{ => deployment-logs}/deployment-logs-placeholder/deployment-logs-placeholder.tsx (100%) create mode 100644 libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs.tsx diff --git a/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId.tsx b/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId.tsx index 10e14cb164e..c4406c25f7b 100644 --- a/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId.tsx +++ b/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId.tsx @@ -1,16 +1,5 @@ -import { type QueryClient } from '@tanstack/react-query' import { createFileRoute } from '@tanstack/react-router' -import { - type DeploymentStageWithServicesStatuses, - type EnvironmentStatus, - type EnvironmentStatusesWithStagesPreCheckStage, -} from 'qovery-typescript-axios' -import { useCallback, useEffect, useState } from 'react' -import { useEnvironment } from '@qovery/domains/environments/feature' -import { ServiceStageIdsProvider } from '@qovery/domains/service-logs/feature' -import { DeploymentLogsFeature } from '@qovery/pages/logs/environment' -import { QOVERY_WS } from '@qovery/shared/util-node-env' -import { useReactQueryWsSubscription } from '@qovery/state/util-queries' +import { DeploymentLogs } from '@qovery/domains/service-logs/feature' export const Route = createFileRoute( '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId' @@ -18,73 +7,6 @@ export const Route = createFileRoute( component: RouteComponent, }) -function DeploymentLogs() { - const { organizationId, projectId, environmentId, executionId } = Route.useParams() - - const { data: environment } = useEnvironment({ environmentId, suspense: true }) - const [deploymentStages, setDeploymentStages] = useState() - const [environmentStatus, setEnvironmentStatus] = useState() - const [preCheckStage, setPreCheckStage] = useState() - - const messageHandler = useCallback( - ( - _: QueryClient, - { - stages, - environment, - pre_check_stage, - }: { - stages: DeploymentStageWithServicesStatuses[] - environment: EnvironmentStatus - pre_check_stage: EnvironmentStatusesWithStagesPreCheckStage - } - ) => { - setDeploymentStages(stages) - setEnvironmentStatus(environment) - setPreCheckStage(pre_check_stage) - }, - [setDeploymentStages] - ) - - useReactQueryWsSubscription({ - url: QOVERY_WS + '/deployment/status', - urlSearchParams: { - organization: organizationId, - cluster: environment?.cluster_id, - project: projectId, - environment: environmentId, - version: executionId, - }, - enabled: - Boolean(organizationId) && Boolean(environment?.cluster_id) && Boolean(projectId) && Boolean(environmentId), - onMessage: messageHandler, - }) - - useEffect(() => { - // Reset local state when URL parameters change - setDeploymentStages(undefined) - setEnvironmentStatus(undefined) - setPreCheckStage(undefined) - }, [organizationId, projectId, environmentId, executionId]) - - if (!environment || !deploymentStages || !environmentStatus || !preCheckStage) { - return null - } - - return ( -
- - - -
- ) -} - function RouteComponent() { return } diff --git a/libs/domains/environment-logs/feature/src/lib/environment-pipeline/environment-pipeline.tsx b/libs/domains/environment-logs/feature/src/lib/environment-pipeline/environment-pipeline.tsx index 500c2ab5078..34eaeea788c 100644 --- a/libs/domains/environment-logs/feature/src/lib/environment-pipeline/environment-pipeline.tsx +++ b/libs/domains/environment-logs/feature/src/lib/environment-pipeline/environment-pipeline.tsx @@ -11,7 +11,6 @@ import { match } from 'ts-pattern' import { useDeploymentHistoryExecutionId, useEnvironment } from '@qovery/domains/environments/feature' import { type AnyService } from '@qovery/domains/services/data-access' import { ServiceAvatar, useServices } from '@qovery/domains/services/feature' -import { DEPLOYMENT_LOGS_VERSION_URL, ENVIRONMENT_LOGS_URL } from '@qovery/shared/routes' import { Icon, Indicator, diff --git a/libs/domains/service-logs/feature/src/index.ts b/libs/domains/service-logs/feature/src/index.ts index a6d1f2569ec..ddeca8380a0 100644 --- a/libs/domains/service-logs/feature/src/index.ts +++ b/libs/domains/service-logs/feature/src/index.ts @@ -4,3 +4,5 @@ export * from './lib/service-stage-ids-context/service-stage-ids-context' export * from './lib/breadcrumb-deployment-history/breadcrumb-deployment-history' export * from './lib/breadcrumb-deployment-logs/breadcrumb-deployment-logs' export * from './lib/sidebar-pod-statuses/sidebar-pod-statuses' +export * from './lib/deployment-logs/deployment-logs' +export * from './lib/deployment-logs/deployment-logs-content/deployment-logs-content' diff --git a/libs/pages/logs/environment/src/lib/feature/deployment-logs-feature/deployment-logs-feature.spec.tsx b/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.spec.tsx similarity index 98% rename from libs/pages/logs/environment/src/lib/feature/deployment-logs-feature/deployment-logs-feature.spec.tsx rename to libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.spec.tsx index da88139bc3e..9809e70de6c 100644 --- a/libs/pages/logs/environment/src/lib/feature/deployment-logs-feature/deployment-logs-feature.spec.tsx +++ b/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.spec.tsx @@ -9,7 +9,7 @@ import { renderWithProviders } from '@qovery/shared/util-tests' import DeploymentLogsFeature, { type DeploymentLogsFeatureProps, getServiceStatusesById, -} from './deployment-logs-feature' +} from './deployment-logs-content' const services: DeploymentStageWithServicesStatuses[] = [ { diff --git a/libs/pages/logs/environment/src/lib/feature/deployment-logs-feature/deployment-logs-feature.tsx b/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.tsx similarity index 97% rename from libs/pages/logs/environment/src/lib/feature/deployment-logs-feature/deployment-logs-feature.tsx rename to libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.tsx index 8407c1c6ce2..afdb47b566e 100644 --- a/libs/pages/logs/environment/src/lib/feature/deployment-logs-feature/deployment-logs-feature.tsx +++ b/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.tsx @@ -10,11 +10,11 @@ import { import { memo } from 'react' import { match } from 'ts-pattern' import { useDeploymentHistory } from '@qovery/domains/environments/feature' -import { ListDeploymentLogs } from '@qovery/domains/service-logs/feature' import { useService } from '@qovery/domains/services/feature' import { Banner } from '@qovery/shared/ui' import { useDocumentTitle } from '@qovery/shared/util-hooks' import { MetricsWebSocketListener } from '@qovery/shared/util-web-sockets' +import { ListDeploymentLogs } from '../../list-deployment-logs/list-deployment-logs' // XXX: Prevent web-socket invalidations when re-rendering const WebSocketListenerMemo = memo(MetricsWebSocketListener) @@ -104,7 +104,7 @@ export function getStageFromServiceId( return undefined } -export function DeploymentLogsFeature({ +export function DeploymentLogsContent({ environment, environmentStatus, deploymentStages, @@ -208,4 +208,4 @@ export function DeploymentLogsFeature({ ) } -export default DeploymentLogsFeature +export default DeploymentLogsContent diff --git a/libs/domains/service-logs/feature/src/lib/deployment-logs-placeholder/deployment-logs-placeholder.spec.tsx b/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-placeholder/deployment-logs-placeholder.spec.tsx similarity index 100% rename from libs/domains/service-logs/feature/src/lib/deployment-logs-placeholder/deployment-logs-placeholder.spec.tsx rename to libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-placeholder/deployment-logs-placeholder.spec.tsx diff --git a/libs/domains/service-logs/feature/src/lib/deployment-logs-placeholder/deployment-logs-placeholder.tsx b/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-placeholder/deployment-logs-placeholder.tsx similarity index 100% rename from libs/domains/service-logs/feature/src/lib/deployment-logs-placeholder/deployment-logs-placeholder.tsx rename to libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-placeholder/deployment-logs-placeholder.tsx diff --git a/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs.tsx b/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs.tsx new file mode 100644 index 00000000000..512608a1421 --- /dev/null +++ b/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs.tsx @@ -0,0 +1,133 @@ +import { type QueryClient } from '@tanstack/react-query' +import { useParams } from '@tanstack/react-router' +import { + type DeploymentStageWithServicesStatuses, + type Environment, + type EnvironmentStatus, + type EnvironmentStatusesWithStagesPreCheckStage, +} from 'qovery-typescript-axios' +import { Suspense, useCallback, useEffect, useState } from 'react' +import { useEnvironment } from '@qovery/domains/environments/feature' +import { Skeleton } from '@qovery/shared/ui' +import { QOVERY_WS } from '@qovery/shared/util-node-env' +import { useReactQueryWsSubscription } from '@qovery/state/util-queries' +import { ServiceStageIdsProvider } from '../service-stage-ids-context/service-stage-ids-context' +import { DeploymentLogsContent } from './deployment-logs-content/deployment-logs-content' +import { LoaderPlaceholder } from './deployment-logs-placeholder/deployment-logs-placeholder' + +function Loader() { + return ( +
+
+ + + + +
+ +
+
+ +
+
+
+ ) +} + +function DeploymentLogsWrapper({ + environment, + deploymentStages, + environmentStatus, + preCheckStage, +}: { + environment?: Environment + deploymentStages?: DeploymentStageWithServicesStatuses[] + environmentStatus?: EnvironmentStatus + preCheckStage?: EnvironmentStatusesWithStagesPreCheckStage +}) { + if (!environment || !environmentStatus) { + // Suspend until WS data arrives. + // The parent Pipeline component will re-render this component once setEnvironmentStatus is called. + // eslint-disable-next-line @typescript-eslint/no-empty-function + throw new Promise(() => {}) + } + + return ( +
+ +
+ ) +} + +export function DeploymentLogs() { + const { organizationId, projectId, environmentId, executionId } = useParams({ strict: false }) + + const { data: environment } = useEnvironment({ environmentId, suspense: true }) + const [deploymentStages, setDeploymentStages] = useState() + const [environmentStatus, setEnvironmentStatus] = useState() + const [preCheckStage, setPreCheckStage] = useState() + + const messageHandler = useCallback( + ( + _: QueryClient, + { + stages, + environment, + pre_check_stage, + }: { + stages: DeploymentStageWithServicesStatuses[] + environment: EnvironmentStatus + pre_check_stage: EnvironmentStatusesWithStagesPreCheckStage + } + ) => { + console.log('Deployment status update received') + setDeploymentStages(stages) + setEnvironmentStatus(environment) + setPreCheckStage(pre_check_stage) + }, + [setDeploymentStages] + ) + + const enabled = + Boolean(organizationId) && Boolean(environment?.cluster_id) && Boolean(projectId) && Boolean(environmentId) + + useReactQueryWsSubscription({ + url: QOVERY_WS + '/deployment/status', + urlSearchParams: { + organization: organizationId, + cluster: environment?.cluster_id, + project: projectId, + environment: environmentId, + version: executionId, + }, + enabled, + onMessage: messageHandler, + }) + + useEffect(() => { + // Reset local state when URL parameters change + setDeploymentStages(undefined) + setEnvironmentStatus(undefined) + setPreCheckStage(undefined) + }, [organizationId, projectId, environmentId, executionId]) + + return ( +
+ + }> + + + +
+ ) +} 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 aaea51718be..e13924d53d6 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 @@ -65,7 +65,7 @@ export function HeaderLogs({ return (
(null) const { updateStageId } = useContext(ServiceStageIdsContext) @@ -327,27 +328,34 @@ export function ListDeploymentLogs({ - + {environmentDeploymentHistory.map((deployment) => ( { - navigate({ - to: '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/deployments/logs/$executionId', - params: { - organizationId, - projectId, - environmentId: environment.id, - serviceId, - executionId: deployment.identifier.execution_id, - }, - replace: true, - }) - }} - icon={deployment.identifier.execution_id === executionId ? : undefined} - className="min-h-8" + className={clsx('min-h-9', { + 'bg-surface-brand-component': deployment.identifier.execution_id === executionId, + })} > - {dateYearMonthDayHourMinuteSecond(new Date(deployment.auditing_data.created_at))} + + + {trimId(deployment.identifier.execution_id ?? '')} + + + {dateYearMonthDayHourMinuteSecond(new Date(deployment.auditing_data.created_at))} + + + ))} @@ -359,7 +367,7 @@ export function ListDeploymentLogs({ if (!logs || logs.length === 0 || !serviceStatus.is_part_last_deployment) { return ( -
+
diff --git a/libs/pages/logs/environment/src/index.ts b/libs/pages/logs/environment/src/index.ts index d2adc87260e..715facc9885 100644 --- a/libs/pages/logs/environment/src/index.ts +++ b/libs/pages/logs/environment/src/index.ts @@ -1,3 +1,2 @@ export * from './lib/page-environment-logs' export * from './lib/feature/pod-logs-feature/pod-logs-feature' -export * from './lib/feature/deployment-logs-feature/deployment-logs-feature' diff --git a/libs/pages/logs/environment/src/lib/feature/pod-logs-feature/pod-logs-feature.tsx b/libs/pages/logs/environment/src/lib/feature/pod-logs-feature/pod-logs-feature.tsx index 7709d127664..05f99862e6b 100644 --- a/libs/pages/logs/environment/src/lib/feature/pod-logs-feature/pod-logs-feature.tsx +++ b/libs/pages/logs/environment/src/lib/feature/pod-logs-feature/pod-logs-feature.tsx @@ -7,11 +7,10 @@ import { } from 'qovery-typescript-axios' import { memo } from 'react' import { useCluster } from '@qovery/domains/clusters/feature' -import { ListServiceLogs } from '@qovery/domains/service-logs/feature' +import { ListServiceLogs, getServiceStatusesById } from '@qovery/domains/service-logs/feature' import { useService } from '@qovery/domains/services/feature' import { useDocumentTitle } from '@qovery/shared/util-hooks' import { MetricsWebSocketListener } from '@qovery/shared/util-web-sockets' -import { getServiceStatusesById } from '../deployment-logs-feature/deployment-logs-feature' // XXX: Prevent web-socket invalidations when re-rendering const WebSocketListenerMemo = memo(MetricsWebSocketListener) diff --git a/libs/pages/logs/environment/src/lib/page-environment-logs.tsx b/libs/pages/logs/environment/src/lib/page-environment-logs.tsx index 75e37cdb109..a62f4b46daa 100644 --- a/libs/pages/logs/environment/src/lib/page-environment-logs.tsx +++ b/libs/pages/logs/environment/src/lib/page-environment-logs.tsx @@ -7,7 +7,7 @@ import { import { useCallback, useEffect, useMemo, useState } from 'react' import { Link, Navigate, Route, Routes, matchPath, useLocation, useNavigate, useParams } from 'react-router-dom' import { useDeploymentHistory, useEnvironment } from '@qovery/domains/environments/feature' -import { ServiceStageIdsProvider } from '@qovery/domains/service-logs/feature' +import { DeploymentLogsContent, ServiceStageIdsProvider } from '@qovery/domains/service-logs/feature' import { DEPLOYMENT_LOGS_VERSION_URL, ENVIRONMENT_LOGS_URL, @@ -21,7 +21,6 @@ import { useDocumentTitle } from '@qovery/shared/util-hooks' import { trimId } from '@qovery/shared/util-js' import { QOVERY_WS } from '@qovery/shared/util-node-env' import { useReactQueryWsSubscription } from '@qovery/state/util-queries' -import DeploymentLogsFeature from './feature/deployment-logs-feature/deployment-logs-feature' import EnvironmentStagesFeature from './feature/environment-stages-feature/environment-stages-feature' import PodLogsFeature from './feature/pod-logs-feature/pod-logs-feature' import PreCheckLogsFeature from './feature/pre-check-logs-feature/pre-check-logs-feature' @@ -262,7 +261,7 @@ export function PageEnvironmentLogs() { Date: Tue, 17 Mar 2026 17:40:45 +0100 Subject: [PATCH 08/20] Fix a bug where switching between executions was not working correctly --- .../deployment-logs-content.tsx | 13 ---- .../lib/deployment-logs/deployment-logs.tsx | 63 ++++++++++++------- .../list-deployment-logs.tsx | 1 + 3 files changed, 41 insertions(+), 36 deletions(-) diff --git a/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.tsx b/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.tsx index afdb47b566e..f15e86f567f 100644 --- a/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.tsx +++ b/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.tsx @@ -16,9 +16,6 @@ import { useDocumentTitle } from '@qovery/shared/util-hooks' import { MetricsWebSocketListener } from '@qovery/shared/util-web-sockets' import { ListDeploymentLogs } from '../../list-deployment-logs/list-deployment-logs' -// XXX: Prevent web-socket invalidations when re-rendering -const WebSocketListenerMemo = memo(MetricsWebSocketListener) - export interface DeploymentLogsFeatureProps { environment: Environment deploymentStages?: DeploymentStageWithServicesStatuses[] @@ -193,16 +190,6 @@ export function DeploymentLogsContent({ stage={stageFromServiceId} preCheckStage={preCheckStage} /> - {service && environment && ( - - )}
) diff --git a/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs.tsx b/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs.tsx index 512608a1421..35839a4f52a 100644 --- a/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs.tsx +++ b/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs.tsx @@ -6,15 +6,19 @@ import { type EnvironmentStatus, type EnvironmentStatusesWithStagesPreCheckStage, } from 'qovery-typescript-axios' -import { Suspense, useCallback, useEffect, useState } from 'react' +import { memo, useCallback, useEffect, useState } from 'react' import { useEnvironment } from '@qovery/domains/environments/feature' +import { useService } from '@qovery/domains/services/feature' import { Skeleton } from '@qovery/shared/ui' import { QOVERY_WS } from '@qovery/shared/util-node-env' +import { MetricsWebSocketListener } from '@qovery/shared/util-web-sockets' import { useReactQueryWsSubscription } from '@qovery/state/util-queries' import { ServiceStageIdsProvider } from '../service-stage-ids-context/service-stage-ids-context' import { DeploymentLogsContent } from './deployment-logs-content/deployment-logs-content' import { LoaderPlaceholder } from './deployment-logs-placeholder/deployment-logs-placeholder' +const WebSocketListenerMemo = memo(MetricsWebSocketListener) + function Loader() { return (
@@ -46,27 +50,32 @@ function DeploymentLogsWrapper({ preCheckStage?: EnvironmentStatusesWithStagesPreCheckStage }) { if (!environment || !environmentStatus) { - // Suspend until WS data arrives. - // The parent Pipeline component will re-render this component once setEnvironmentStatus is called. - // eslint-disable-next-line @typescript-eslint/no-empty-function - throw new Promise(() => {}) + return } return ( -
- -
+ ) } export function DeploymentLogs() { - const { organizationId, projectId, environmentId, executionId } = useParams({ strict: false }) - + const { + organizationId, + projectId, + environmentId = '', + serviceId = '', + executionId = '', + } = useParams({ strict: false }) + const { data: service } = useService({ + environmentId, + serviceId, + suspense: true, + }) const { data: environment } = useEnvironment({ environmentId, suspense: true }) const [deploymentStages, setDeploymentStages] = useState() const [environmentStatus, setEnvironmentStatus] = useState() @@ -85,7 +94,6 @@ export function DeploymentLogs() { pre_check_stage: EnvironmentStatusesWithStagesPreCheckStage } ) => { - console.log('Deployment status update received') setDeploymentStages(stages) setEnvironmentStatus(environment) setPreCheckStage(pre_check_stage) @@ -119,14 +127,23 @@ export function DeploymentLogs() { return (
- }> - + + {service && environment && ( + - + )}
) diff --git a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.tsx b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.tsx index edd7fb031ad..42376b46e25 100644 --- a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.tsx +++ b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.tsx @@ -347,6 +347,7 @@ export function ListDeploymentLogs({ serviceId, executionId: deployment.identifier.execution_id, }} + replace={true} > {trimId(deployment.identifier.execution_id ?? '')} From 59a7ba89a41f7762dae8c3617b250168ad071f27 Mon Sep 17 00:00:00 2001 From: Romain Billard Date: Tue, 17 Mar 2026 17:43:31 +0100 Subject: [PATCH 09/20] Update outdated snapshot --- .../__snapshots__/service-links-popover.spec.tsx.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/domains/services/feature/src/lib/service-links-popover/__snapshots__/service-links-popover.spec.tsx.snap b/libs/domains/services/feature/src/lib/service-links-popover/__snapshots__/service-links-popover.spec.tsx.snap index 7c0d3cb311a..fe70090b33b 100644 --- a/libs/domains/services/feature/src/lib/service-links-popover/__snapshots__/service-links-popover.spec.tsx.snap +++ b/libs/domains/services/feature/src/lib/service-links-popover/__snapshots__/service-links-popover.spec.tsx.snap @@ -29,7 +29,7 @@ exports[`ServiceLinksPopover should match snapshot 1`] = ` style="position: fixed; left: 0px; top: 0px; transform: translate(0px, 8px); min-width: max-content; --radix-popper-available-width: -20px; --radix-popper-available-height: -18px; --radix-popper-anchor-width: 0px; --radix-popper-anchor-height: 0px; --radix-popper-transform-origin: 100% 0px;" >
Date: Tue, 17 Mar 2026 17:57:58 +0100 Subject: [PATCH 10/20] Fix failing unit tests --- .../feature/src/lib/header-logs/header-logs.spec.tsx | 12 +++++------- .../list-deployment-logs.spec.tsx | 3 +++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/libs/domains/service-logs/feature/src/lib/header-logs/header-logs.spec.tsx b/libs/domains/service-logs/feature/src/lib/header-logs/header-logs.spec.tsx index 84963a57cb1..5af56475ef8 100644 --- a/libs/domains/service-logs/feature/src/lib/header-logs/header-logs.spec.tsx +++ b/libs/domains/service-logs/feature/src/lib/header-logs/header-logs.spec.tsx @@ -71,14 +71,12 @@ describe('HeaderLogs', () => { }) it('renders correctly for deployment type', async () => { - renderWithProviders() + renderWithProviders() expect(screen.getByText('Test Service')).toBeInTheDocument() - expect(screen.getByText('2m : 5s')).toBeInTheDocument() expect(screen.getByTestId('service-avatar')).toBeInTheDocument() - const linksButton = screen.getByRole('button', { name: /link/ }) - expect(within(linksButton).getByText('1 link')).toBeInTheDocument() + expect(screen.getByText('Link')).toBeInTheDocument() }) it('renders correctly for service type', () => { @@ -89,13 +87,13 @@ describe('HeaderLogs', () => { }) it('displays correct number of links', () => { - renderWithProviders() - expect(screen.getByText('1 link')).toBeInTheDocument() + renderWithProviders() + expect(screen.getByText('Link')).toBeInTheDocument() }) it('renders children content', () => { renderWithProviders( - +
Child Content
) diff --git a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.spec.tsx b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.spec.tsx index 1c65e9f52fa..e9b02acb3c6 100644 --- a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.spec.tsx +++ b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.spec.tsx @@ -35,6 +35,9 @@ jest.mock('../hooks/use-deployment-history/use-deployment-history', () => ({ identifier: { execution_id: '4', }, + auditing_data: { + created_at: '2024-09-18T07:03:29.819774Z', + }, }, ], }), From d00e26d30d67a791842aa2307e2533fc320712e1 Mon Sep 17 00:00:00 2001 From: Romain Billard Date: Wed, 18 Mar 2026 10:44:32 +0100 Subject: [PATCH 11/20] Fix font-weight and remove useless condition --- .../src/lib/header-logs/header-logs.tsx | 44 +++++++------------ 1 file changed, 16 insertions(+), 28 deletions(-) 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 e13924d53d6..91da6cedaf1 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 @@ -99,40 +99,28 @@ export function HeaderLogs({
{!isNotDeployedOrStopped && !isManagedDatabase && filteredLinks.length > 0 && ( - <> - {filteredLinks.length > 0 && ( - - - - )} - {type === 'SERVICE' && !isHistoricalServiceLogs && ( - <> - - - - - - )} - + + + )}
From 973642c719a415b80a4568d58518cd66fb7ba8f7 Mon Sep 17 00:00:00 2001 From: Romain Billard Date: Wed, 18 Mar 2026 10:56:56 +0100 Subject: [PATCH 12/20] Fix missing iconOnly variant for ServiceActions --- .../feature/src/lib/service-actions/service-actions.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/domains/services/feature/src/lib/service-actions/service-actions.tsx b/libs/domains/services/feature/src/lib/service-actions/service-actions.tsx index 32b33aceb0c..c32ed738c2f 100644 --- a/libs/domains/services/feature/src/lib/service-actions/service-actions.tsx +++ b/libs/domains/services/feature/src/lib/service-actions/service-actions.tsx @@ -368,7 +368,7 @@ function MenuManageDeployment({ color={displayYellowColor ? 'yellow' : variant === 'header' ? 'brand' : 'neutral'} variant={variant === 'header' ? 'solid' : 'outline'} size={variant === 'header' ? 'md' : 'sm'} - iconOnly={variant === 'default'} + iconOnly={['default', 'deploy-dropdown-only'].includes(variant)} >
From 74d907de19dddd9677cc4382b757e2206bad40c5 Mon Sep 17 00:00:00 2001 From: Romain Billard Date: Wed, 18 Mar 2026 11:02:07 +0100 Subject: [PATCH 13/20] Remove "service logs" link from the service's deployment table --- .../service-deployment-list.tsx | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/libs/domains/services/feature/src/lib/service-deployment-list/service-deployment-list.tsx b/libs/domains/services/feature/src/lib/service-deployment-list/service-deployment-list.tsx index 25ea905788c..44e4a71a667 100644 --- a/libs/domains/services/feature/src/lib/service-deployment-list/service-deployment-list.tsx +++ b/libs/domains/services/feature/src/lib/service-deployment-list/service-deployment-list.tsx @@ -173,41 +173,6 @@ export function ServiceDeploymentList({ environment, serviceId }: ServiceDeploym )) .otherwise(() => null)} - {(service?.serviceType === 'TERRAFORM' || - (service?.serviceType === 'JOB' && service?.job_type !== 'CRON')) && - // Show only when logs can be available (hide during build or active deployment) - match(state) - .with( - P.when((s) => ['ONGOING', 'CANCELING', 'QUEUED', 'BUILDING'].includes(String(s))), - () => null - ) - .otherwise(() => ( - - - - - - ))} Date: Wed, 18 Mar 2026 11:24:47 +0100 Subject: [PATCH 14/20] Use scroll icon instead of pipeline one --- .../lib/service-deployment-list/service-deployment-list.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/domains/services/feature/src/lib/service-deployment-list/service-deployment-list.tsx b/libs/domains/services/feature/src/lib/service-deployment-list/service-deployment-list.tsx index 44e4a71a667..9c2d9667200 100644 --- a/libs/domains/services/feature/src/lib/service-deployment-list/service-deployment-list.tsx +++ b/libs/domains/services/feature/src/lib/service-deployment-list/service-deployment-list.tsx @@ -173,7 +173,7 @@ export function ServiceDeploymentList({ environment, serviceId }: ServiceDeploym )) .otherwise(() => null)} - + - +
From 537fab974f91cae92ede0315ec83e7e3faef64df Mon Sep 17 00:00:00 2001 From: Romain Billard Date: Wed, 18 Mar 2026 11:38:15 +0100 Subject: [PATCH 15/20] Fix "skipped" icon --- .../lib/components/icon/icons-status/skip.tsx | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/libs/shared/ui/src/lib/components/icon/icons-status/skip.tsx b/libs/shared/ui/src/lib/components/icon/icons-status/skip.tsx index 1b62662bff5..0467051ef55 100644 --- a/libs/shared/ui/src/lib/components/icon/icons-status/skip.tsx +++ b/libs/shared/ui/src/lib/components/icon/icons-status/skip.tsx @@ -1,28 +1,15 @@ import { forwardRef } from 'react' import { twMerge } from '@qovery/shared/util-js' -import { type IconSVGProps } from '../icon' +import { Icon, type IconSVGProps } from '../icon' export const SkipIcon = forwardRef(function SkipIcon( { className = '', ...props }, forwardedRef ) { return ( - - - - - +
+ +
) }) From 89047a619756d092c68dd68f96d27e80ad5abb3b Mon Sep 17 00:00:00 2001 From: Romain Billard Date: Wed, 18 Mar 2026 14:26:39 +0100 Subject: [PATCH 16/20] Remove useless props --- libs/shared/ui/src/lib/components/icon/icons-status/skip.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/libs/shared/ui/src/lib/components/icon/icons-status/skip.tsx b/libs/shared/ui/src/lib/components/icon/icons-status/skip.tsx index 0467051ef55..d60f078c9a5 100644 --- a/libs/shared/ui/src/lib/components/icon/icons-status/skip.tsx +++ b/libs/shared/ui/src/lib/components/icon/icons-status/skip.tsx @@ -2,10 +2,7 @@ import { forwardRef } from 'react' import { twMerge } from '@qovery/shared/util-js' import { Icon, type IconSVGProps } from '../icon' -export const SkipIcon = forwardRef(function SkipIcon( - { className = '', ...props }, - forwardedRef -) { +export const SkipIcon = forwardRef(function SkipIcon({ className = '' }) { return (
From f2095437591321a7dab5d0361a8537b3c15933d4 Mon Sep 17 00:00:00 2001 From: Romain Billard Date: Wed, 18 Mar 2026 16:16:11 +0100 Subject: [PATCH 17/20] Rename versionId to executionId --- .../lib/hooks/use-deployment-logs/use-deployment-logs.ts | 8 ++++---- .../src/lib/list-deployment-logs/list-deployment-logs.tsx | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/domains/service-logs/feature/src/lib/hooks/use-deployment-logs/use-deployment-logs.ts b/libs/domains/service-logs/feature/src/lib/hooks/use-deployment-logs/use-deployment-logs.ts index cdb2f56a1c0..abcdc5548e4 100644 --- a/libs/domains/service-logs/feature/src/lib/hooks/use-deployment-logs/use-deployment-logs.ts +++ b/libs/domains/service-logs/feature/src/lib/hooks/use-deployment-logs/use-deployment-logs.ts @@ -13,7 +13,7 @@ export interface UseDeploymentLogsProps { projectId?: string environmentId?: string serviceId?: string - versionId?: string + executionId?: string } export interface EnvironmentLogIds extends EnvironmentLogs { @@ -29,7 +29,7 @@ export function useDeploymentLogs({ projectId, environmentId, serviceId, - versionId, + executionId, }: UseDeploymentLogsProps) { const { hash } = useLocation() const { data: deploymentHistory = [] } = useDeploymentHistory({ environmentId: environmentId ?? '', suspense: true }) @@ -63,7 +63,7 @@ export function useDeploymentLogs({ ) // XXX: If we don't have a version, it works like WS otherwise, it works like a REST API - const isLatestVersion = deploymentHistory[0]?.identifier.execution_id === versionId + const isLatestVersion = deploymentHistory[0]?.identifier.execution_id === executionId useReactQueryWsSubscription({ url: QOVERY_WS + '/deployment/logs', @@ -72,7 +72,7 @@ export function useDeploymentLogs({ cluster: environment?.cluster_id, project: projectId, environment: environmentId, - version: isLatestVersion ? undefined : versionId, + version: isLatestVersion ? undefined : executionId, }, enabled: Boolean(organizationId) && Boolean(environment?.cluster_id) && Boolean(projectId) && Boolean(environmentId), diff --git a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.tsx b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.tsx index 42376b46e25..813897582ad 100644 --- a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.tsx +++ b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.tsx @@ -174,7 +174,7 @@ export function ListDeploymentLogs({ projectId, environmentId: environment.id, serviceId, - versionId: executionId, + executionId, }) // `useEffect` used to scroll to the bottom of the logs when new logs are added or when the pauseLogs state changes From 81ba85f8f8c1b3ec5f913bce312877088a6313cf Mon Sep 17 00:00:00 2001 From: Romain Billard Date: Wed, 18 Mar 2026 16:16:58 +0100 Subject: [PATCH 18/20] Remove outdated color token --- .../deployment-logs-content.tsx | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.tsx b/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.tsx index f15e86f567f..5c4c1cb1589 100644 --- a/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.tsx +++ b/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.tsx @@ -7,13 +7,11 @@ import { type Stage, type Status, } from 'qovery-typescript-axios' -import { memo } from 'react' import { match } from 'ts-pattern' import { useDeploymentHistory } from '@qovery/domains/environments/feature' import { useService } from '@qovery/domains/services/feature' import { Banner } from '@qovery/shared/ui' import { useDocumentTitle } from '@qovery/shared/util-hooks' -import { MetricsWebSocketListener } from '@qovery/shared/util-web-sockets' import { ListDeploymentLogs } from '../../list-deployment-logs/list-deployment-logs' export interface DeploymentLogsFeatureProps { @@ -182,15 +180,13 @@ export function DeploymentLogsContent({ A new deployment has been initiated )} -
- -
+ ) } From 2d39c37edda6ace72cbb91cecb7abafaee674220 Mon Sep 17 00:00:00 2001 From: Romain Billard Date: Wed, 18 Mar 2026 16:18:32 +0100 Subject: [PATCH 19/20] Rename DeploymentLogsFeatureProps --- .../deployment-logs-content/deployment-logs-content.spec.tsx | 4 ++-- .../deployment-logs-content/deployment-logs-content.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.spec.tsx b/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.spec.tsx index 9809e70de6c..6b855b1d4ea 100644 --- a/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.spec.tsx +++ b/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.spec.tsx @@ -7,7 +7,7 @@ import { Route, Routes } from 'react-router-dom' import { environmentFactoryMock } from '@qovery/shared/factories' import { renderWithProviders } from '@qovery/shared/util-tests' import DeploymentLogsFeature, { - type DeploymentLogsFeatureProps, + type DeploymentLogsContentProps, getServiceStatusesById, } from './deployment-logs-content' @@ -43,7 +43,7 @@ const services: DeploymentStageWithServicesStatuses[] = [ ] describe('DeploymentLogsFeature', () => { - const props: DeploymentLogsFeatureProps = { + const props: DeploymentLogsContentProps = { environment: environmentFactoryMock(1)[0], statusStages: services, } diff --git a/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.tsx b/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.tsx index 5c4c1cb1589..a3bb467001f 100644 --- a/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.tsx +++ b/libs/domains/service-logs/feature/src/lib/deployment-logs/deployment-logs-content/deployment-logs-content.tsx @@ -14,7 +14,7 @@ import { Banner } from '@qovery/shared/ui' import { useDocumentTitle } from '@qovery/shared/util-hooks' import { ListDeploymentLogs } from '../../list-deployment-logs/list-deployment-logs' -export interface DeploymentLogsFeatureProps { +export interface DeploymentLogsContentProps { environment: Environment deploymentStages?: DeploymentStageWithServicesStatuses[] environmentStatus?: EnvironmentStatus @@ -104,7 +104,7 @@ export function DeploymentLogsContent({ environmentStatus, deploymentStages, preCheckStage, -}: DeploymentLogsFeatureProps) { +}: DeploymentLogsContentProps) { const { serviceId = '', executionId = '' } = useParams({ strict: false }) const navigate = useNavigate() From 9bd29d1f0e680cfb8279587c5ef924628bb7b296 Mon Sep 17 00:00:00 2001 From: Romain Billard Date: Wed, 18 Mar 2026 17:19:02 +0100 Subject: [PATCH 20/20] Fix overflow issue --- .../src/lib/list-deployment-logs/list-deployment-logs.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.tsx b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.tsx index 813897582ad..7ae5e58585d 100644 --- a/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.tsx +++ b/libs/domains/service-logs/feature/src/lib/list-deployment-logs/list-deployment-logs.tsx @@ -389,7 +389,7 @@ export function ListDeploymentLogs({ } return ( -
+
@@ -409,7 +409,7 @@ export function ListDeploymentLogs({
{ if (