From 9e41e2576ff1f8a302a1cd8baa7a9d8d69cbaad9 Mon Sep 17 00:00:00 2001 From: RemiBonnet Date: Fri, 27 Mar 2026 17:54:21 +0100 Subject: [PATCH 1/2] feat(helm): add creation flow --- apps/console-v5/src/routeTree.gen.ts | 113 +++++++++ .../service/create/helm/general.tsx | 29 +++ .../service/create/helm/index.tsx | 23 ++ .../service/create/helm/route.tsx | 19 ++ .../create/helm/values-override-file.tsx | 37 +++ .../_authenticated/organization/route.tsx | 1 + .../domains/service-helm/feature/src/index.ts | 3 + .../helm-create-utils/helm-create-utils.ts | 19 ++ .../helm-creation-flow.spec.tsx | 50 ++++ .../helm-creation-flow/helm-creation-flow.tsx | 95 ++++++++ .../step-general/step-general.spec.tsx | 77 +++++++ .../step-general/step-general.tsx | 215 ++++++++++++++++++ .../step-values-override-files.spec.tsx | 77 +++++++ .../step-values-override-files.tsx | 193 ++++++++++++++++ .../values-override-files-setting.tsx | 20 +- .../values-override-yaml-setting.spec.tsx | 84 ++++++- .../values-override-yaml-setting.tsx | 14 +- libs/domains/services/feature/src/index.ts | 1 + .../service-general-settings-payloads.ts | 55 ++--- .../src/lib/service-new/service-new.spec.tsx | 20 ++ .../src/lib/service-new/service-new.tsx | 7 +- .../step-summary-feature.tsx | 22 +- ...step-values-override-arguments-feature.tsx | 26 +-- .../step-values-override-files-feature.tsx | 23 +- 24 files changed, 1109 insertions(+), 114 deletions(-) create mode 100644 apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/general.tsx create mode 100644 apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/index.tsx create mode 100644 apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/route.tsx create mode 100644 apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/values-override-file.tsx create mode 100644 libs/domains/service-helm/feature/src/lib/helm-creation-flow/helm-create-utils/helm-create-utils.ts create mode 100644 libs/domains/service-helm/feature/src/lib/helm-creation-flow/helm-creation-flow.spec.tsx create mode 100644 libs/domains/service-helm/feature/src/lib/helm-creation-flow/helm-creation-flow.tsx create mode 100644 libs/domains/service-helm/feature/src/lib/helm-creation-flow/step-general/step-general.spec.tsx create mode 100644 libs/domains/service-helm/feature/src/lib/helm-creation-flow/step-general/step-general.tsx create mode 100644 libs/domains/service-helm/feature/src/lib/helm-creation-flow/step-values-override-files/step-values-override-files.spec.tsx create mode 100644 libs/domains/service-helm/feature/src/lib/helm-creation-flow/step-values-override-files/step-values-override-files.tsx diff --git a/apps/console-v5/src/routeTree.gen.ts b/apps/console-v5/src/routeTree.gen.ts index e65e7d13fd6..b9a9656efd1 100644 --- a/apps/console-v5/src/routeTree.gen.ts +++ b/apps/console-v5/src/routeTree.gen.ts @@ -101,15 +101,19 @@ import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnviron import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdOverviewRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/overview' import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdCloudShellRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/cloud-shell' import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdDeploymentDeploymentIdPreCheckLogsRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/deployment/$deploymentId/pre-check-logs' +import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmRouteRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/route' 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' import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringRouteRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/route' +import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmIndexRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/index' import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseIndexRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/index' 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 AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmValuesOverrideFileRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/values-override-file' +import { Route as AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmGeneralRouteImport } from './routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/general' 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' @@ -859,6 +863,14 @@ const AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironm getParentRoute: () => AuthenticatedOrganizationOrganizationIdRouteRoute, } as any, ) +const AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmRouteRoute = + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmRouteRouteImport.update( + { + id: '/project/$projectId/environment/$environmentId/service/create/helm', + path: '/project/$projectId/environment/$environmentId/service/create/helm', + getParentRoute: () => AuthenticatedOrganizationOrganizationIdRouteRoute, + } as any, + ) const AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseRouteRoute = AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseRouteRouteImport.update( { @@ -891,6 +903,15 @@ const AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironm getParentRoute: () => AuthenticatedOrganizationOrganizationIdRouteRoute, } as any, ) +const AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmIndexRoute = + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmIndexRouteImport.update( + { + id: '/', + path: '/', + getParentRoute: () => + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmRouteRoute, + } as any, + ) const AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseIndexRoute = AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseIndexRouteImport.update( { @@ -935,6 +956,24 @@ const AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironm getParentRoute: () => AuthenticatedOrganizationOrganizationIdRouteRoute, } as any, ) +const AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmValuesOverrideFileRoute = + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmValuesOverrideFileRouteImport.update( + { + id: '/values-override-file', + path: '/values-override-file', + getParentRoute: () => + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmRouteRoute, + } as any, + ) +const AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmGeneralRoute = + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmGeneralRouteImport.update( + { + id: '/general', + path: '/general', + getParentRoute: () => + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmRouteRoute, + } as any, + ) const AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseSummaryRoute = AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseSummaryRouteImport.update( { @@ -1302,6 +1341,7 @@ 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/create/helm': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmRouteRouteWithChildren '/organization/$organizationId/project/$projectId/environment/$environmentId/deployment/$deploymentId/pre-check-logs': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdDeploymentDeploymentIdPreCheckLogsRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/cloud-shell': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdCloudShellRoute '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/overview': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdOverviewRoute @@ -1338,11 +1378,14 @@ 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/create/helm/general': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmGeneralRoute + '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/values-override-file': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmValuesOverrideFileRoute '/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/create/helm/': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmIndexRoute '/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 @@ -1458,11 +1501,14 @@ 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/create/helm/general': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmGeneralRoute + '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/values-override-file': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmValuesOverrideFileRoute '/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/create/helm': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmIndexRoute '/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 @@ -1557,6 +1603,7 @@ 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/create/helm': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmRouteRouteWithChildren '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/deployment/$deploymentId/pre-check-logs': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdDeploymentDeploymentIdPreCheckLogsRoute '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/cloud-shell': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdCloudShellRoute '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/overview': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdOverviewRoute @@ -1593,11 +1640,14 @@ 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/create/helm/general': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmGeneralRoute + '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/values-override-file': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmValuesOverrideFileRoute '/_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/create/helm/': typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmIndexRoute '/_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 @@ -1692,6 +1742,7 @@ 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/create/helm' | '/organization/$organizationId/project/$projectId/environment/$environmentId/deployment/$deploymentId/pre-check-logs' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/cloud-shell' | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/overview' @@ -1728,11 +1779,14 @@ 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/create/helm/general' + | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/values-override-file' | '/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/create/helm/' | '/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' @@ -1848,11 +1902,14 @@ 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/create/helm/general' + | '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/values-override-file' | '/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/create/helm' | '/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' @@ -1946,6 +2003,7 @@ 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/create/helm' | '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/deployment/$deploymentId/pre-check-logs' | '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/cloud-shell' | '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/overview' @@ -1982,11 +2040,14 @@ 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/create/helm/general' + | '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/values-override-file' | '/_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/create/helm/' | '/_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' @@ -2645,6 +2706,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdDeploymentDeploymentIdPreCheckLogsRouteImport parentRoute: typeof AuthenticatedOrganizationOrganizationIdRouteRoute } + '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm': { + id: '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm' + path: '/project/$projectId/environment/$environmentId/service/create/helm' + fullPath: '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm' + preLoaderRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmRouteRouteImport + 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' @@ -2673,6 +2741,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdMonitoringRouteRouteImport parentRoute: typeof AuthenticatedOrganizationOrganizationIdRouteRoute } + '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/': { + id: '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/' + path: '/' + fullPath: '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/' + preLoaderRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmIndexRouteImport + parentRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmRouteRoute + } '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/': { id: '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database/' path: '/' @@ -2708,6 +2783,20 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdDeploymentsIndexRouteImport parentRoute: typeof AuthenticatedOrganizationOrganizationIdRouteRoute } + '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/values-override-file': { + id: '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/values-override-file' + path: '/values-override-file' + fullPath: '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/values-override-file' + preLoaderRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmValuesOverrideFileRouteImport + parentRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmRouteRoute + } + '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/general': { + id: '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/general' + path: '/general' + fullPath: '/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/general' + preLoaderRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmGeneralRouteImport + parentRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmRouteRoute + } '/_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' @@ -3312,6 +3401,27 @@ const AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironm AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseRouteRouteChildren, ) +interface AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmRouteRouteChildren { + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmGeneralRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmGeneralRoute + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmValuesOverrideFileRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmValuesOverrideFileRoute + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmIndexRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmIndexRoute +} + +const AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmRouteRouteChildren: AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmRouteRouteChildren = + { + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmGeneralRoute: + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmGeneralRoute, + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmValuesOverrideFileRoute: + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmValuesOverrideFileRoute, + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmIndexRoute: + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmIndexRoute, + } + +const AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmRouteRouteWithChildren = + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmRouteRoute._addFileChildren( + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmRouteRouteChildren, + ) + interface AuthenticatedOrganizationOrganizationIdRouteRouteChildren { AuthenticatedOrganizationOrganizationIdAlertsRouteRoute: typeof AuthenticatedOrganizationOrganizationIdAlertsRouteRouteWithChildren AuthenticatedOrganizationOrganizationIdSettingsRouteRoute: typeof AuthenticatedOrganizationOrganizationIdSettingsRouteRouteWithChildren @@ -3344,6 +3454,7 @@ interface AuthenticatedOrganizationOrganizationIdRouteRouteChildren { AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdSettingsRouteRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdSettingsRouteRouteWithChildren AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateSlugRouteRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateSlugRouteRouteWithChildren AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseRouteRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseRouteRouteWithChildren + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmRouteRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmRouteRouteWithChildren AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdDeploymentDeploymentIdPreCheckLogsRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdDeploymentDeploymentIdPreCheckLogsRoute AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdCloudShellRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdCloudShellRoute AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdOverviewRoute: typeof AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdOverviewRoute @@ -3420,6 +3531,8 @@ const AuthenticatedOrganizationOrganizationIdRouteRouteChildren: AuthenticatedOr AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateSlugRouteRouteWithChildren, AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseRouteRoute: AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateDatabaseRouteRouteWithChildren, + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmRouteRoute: + AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceCreateHelmRouteRouteWithChildren, AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdDeploymentDeploymentIdPreCheckLogsRoute: AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdDeploymentDeploymentIdPreCheckLogsRoute, AuthenticatedOrganizationOrganizationIdProjectProjectIdEnvironmentEnvironmentIdServiceServiceIdCloudShellRoute: diff --git a/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/general.tsx b/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/general.tsx new file mode 100644 index 00000000000..2c5bda85eaf --- /dev/null +++ b/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/general.tsx @@ -0,0 +1,29 @@ +import { createFileRoute, useNavigate } from '@tanstack/react-router' +import { AnnotationSetting, LabelSetting } from '@qovery/domains/organizations/feature' +import { HelmStepGeneral } from '@qovery/domains/service-helm/feature' +import { serviceCreateParamsSchema } from '@qovery/shared/router' +import { useDocumentTitle } from '@qovery/shared/util-hooks' + +export const Route = createFileRoute( + '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/general' +)({ + component: General, + validateSearch: serviceCreateParamsSchema, +}) + +function General() { + const { organizationId = '', projectId = '', environmentId = '' } = Route.useParams() + const search = Route.useSearch() + const navigate = useNavigate() + const creationFlowUrl = `/organization/${organizationId}/project/${projectId}/environment/${environmentId}/service/create/helm` + + useDocumentTitle('General - Create Helm') + + return ( + navigate({ to: `${creationFlowUrl}/values-override-file`, search })} + labelSetting={} + annotationSetting={} + /> + ) +} diff --git a/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/index.tsx b/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/index.tsx new file mode 100644 index 00000000000..fb79a20e01d --- /dev/null +++ b/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/index.tsx @@ -0,0 +1,23 @@ +import { Navigate, createFileRoute, useParams } from '@tanstack/react-router' +import { serviceCreateParamsSchema } from '@qovery/shared/router' + +export const Route = createFileRoute( + '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/' +)({ + component: RouteComponent, + validateSearch: serviceCreateParamsSchema, +}) + +function RouteComponent() { + const { organizationId = '', projectId = '', environmentId = '' } = useParams({ strict: false }) + const search = Route.useSearch() + + return ( + + ) +} diff --git a/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/route.tsx b/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/route.tsx new file mode 100644 index 00000000000..0485a7d153a --- /dev/null +++ b/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/route.tsx @@ -0,0 +1,19 @@ +import { Outlet, createFileRoute, useParams } from '@tanstack/react-router' +import { HelmCreationFlow } from '@qovery/domains/service-helm/feature' + +export const Route = createFileRoute( + '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm' +)({ + component: RouteComponent, +}) + +function RouteComponent() { + const { organizationId = '', projectId = '', environmentId = '' } = useParams({ strict: false }) + const creationFlowUrl = `/organization/${organizationId}/project/${projectId}/environment/${environmentId}/service/create/helm` + + return ( + + + + ) +} diff --git a/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/values-override-file.tsx b/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/values-override-file.tsx new file mode 100644 index 00000000000..b0260a4a5bc --- /dev/null +++ b/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/values-override-file.tsx @@ -0,0 +1,37 @@ +import { Navigate, createFileRoute } from '@tanstack/react-router' +import { HelmStepValuesOverrideFile, useHelmCreateContext } from '@qovery/domains/service-helm/feature' +import { serviceCreateParamsSchema } from '@qovery/shared/router' +import { useDocumentTitle } from '@qovery/shared/util-hooks' + +export const Route = createFileRoute( + '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm/values-override-file' +)({ + component: ValuesOverrideFile, + validateSearch: serviceCreateParamsSchema, +}) + +function ValuesOverrideFile() { + const { organizationId = '', projectId = '', environmentId = '' } = Route.useParams() + const search = Route.useSearch() + const { generalForm } = useHelmCreateContext() + const generalValues = generalForm.getValues() + + useDocumentTitle('Values override as file - Create Helm') + + if (!generalValues.name || !generalValues.source_provider) { + return ( + + ) + } + + return +} diff --git a/apps/console-v5/src/routes/_authenticated/organization/route.tsx b/apps/console-v5/src/routes/_authenticated/organization/route.tsx index 89aa1572e87..5aa5e114588 100644 --- a/apps/console-v5/src/routes/_authenticated/organization/route.tsx +++ b/apps/console-v5/src/routes/_authenticated/organization/route.tsx @@ -420,6 +420,7 @@ const bypassLayoutRouteIds: FileRouteTypes['id'][] = [ '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/monitoring/alerts/$alertId/edit', '/_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/create/helm', ] function useBypassLayout(): boolean { diff --git a/libs/domains/service-helm/feature/src/index.ts b/libs/domains/service-helm/feature/src/index.ts index 58af04aec8d..8291654a08d 100644 --- a/libs/domains/service-helm/feature/src/index.ts +++ b/libs/domains/service-helm/feature/src/index.ts @@ -9,3 +9,6 @@ export * from './lib/hooks/use-helm-repositories/use-helm-repositories' export * from './lib/hooks/use-create-helm-service/use-create-helm-service' export * from './lib/hooks/use-helm-default-values/use-helm-default-values' export * from './lib/hooks/use-kubernetes-services/use-kubernetes-services' +export * from './lib/helm-creation-flow/helm-creation-flow' +export * from './lib/helm-creation-flow/step-general/step-general' +export * from './lib/helm-creation-flow/step-values-override-files/step-values-override-files' diff --git a/libs/domains/service-helm/feature/src/lib/helm-creation-flow/helm-create-utils/helm-create-utils.ts b/libs/domains/service-helm/feature/src/lib/helm-creation-flow/helm-create-utils/helm-create-utils.ts new file mode 100644 index 00000000000..82ab2b3770f --- /dev/null +++ b/libs/domains/service-helm/feature/src/lib/helm-creation-flow/helm-create-utils/helm-create-utils.ts @@ -0,0 +1,19 @@ +import { serviceTemplates } from '@qovery/domains/services/feature' + +export interface HelmTemplateMatch { + templateTitle?: string + iconUri?: string +} + +export function findHelmTemplateMatch(template?: string): HelmTemplateMatch { + if (!template) { + return {} + } + + const helmTemplate = serviceTemplates.find((serviceTemplate) => serviceTemplate.slug === template) + + return { + templateTitle: helmTemplate?.title, + iconUri: helmTemplate?.icon_uri, + } +} diff --git a/libs/domains/service-helm/feature/src/lib/helm-creation-flow/helm-creation-flow.spec.tsx b/libs/domains/service-helm/feature/src/lib/helm-creation-flow/helm-creation-flow.spec.tsx new file mode 100644 index 00000000000..f9445f010cf --- /dev/null +++ b/libs/domains/service-helm/feature/src/lib/helm-creation-flow/helm-creation-flow.spec.tsx @@ -0,0 +1,50 @@ +import { renderWithProviders, screen } from '@qovery/shared/util-tests' +import { HelmCreationFlow, useHelmCreateContext } from './helm-creation-flow' + +const mockNavigate = jest.fn() +const mockSearch = { + template: 'kubecost', +} + +jest.mock('@qovery/shared/assistant/feature', () => ({ + AssistantTrigger: () => null, +})) + +jest.mock('@tanstack/react-router', () => ({ + ...jest.requireActual('@tanstack/react-router'), + useParams: () => ({ + organizationId: 'org-1', + projectId: 'proj-1', + environmentId: 'env-1', + }), + useNavigate: () => mockNavigate, + useSearch: () => mockSearch, +})) + +function ContextConsumer() { + const { currentStep, creationFlowUrl, generalForm, valuesOverrideFileForm } = useHelmCreateContext() + + return ( +
+ step={currentStep} url={creationFlowUrl} name={generalForm.getValues('name')} icon= + {generalForm.getValues('icon_uri')} valuesType={valuesOverrideFileForm.getValues('type')} +
+ ) +} + +describe('HelmCreationFlow', () => { + it('renders and provides helm creation context', () => { + renderWithProviders( + + + + ) + + expect(screen.getByText('General data')).toBeInTheDocument() + expect(screen.getByTestId('context-consumer')).toHaveTextContent('step=1') + expect(screen.getByTestId('context-consumer')).toHaveTextContent('url=/create/helm') + expect(screen.getByTestId('context-consumer')).toHaveTextContent('name=kubecost') + expect(screen.getByTestId('context-consumer')).toHaveTextContent('icon=app://qovery-console/kubecost') + expect(screen.getByTestId('context-consumer')).toHaveTextContent('valuesType=GIT_REPOSITORY') + }) +}) diff --git a/libs/domains/service-helm/feature/src/lib/helm-creation-flow/helm-creation-flow.tsx b/libs/domains/service-helm/feature/src/lib/helm-creation-flow/helm-creation-flow.tsx new file mode 100644 index 00000000000..18d366d1198 --- /dev/null +++ b/libs/domains/service-helm/feature/src/lib/helm-creation-flow/helm-creation-flow.tsx @@ -0,0 +1,95 @@ +import { useNavigate, useParams, useSearch } from '@tanstack/react-router' +import { type Dispatch, type PropsWithChildren, type SetStateAction, createContext, useContext, useState } from 'react' +import { type UseFormReturn, useForm } from 'react-hook-form' +import { type HelmGeneralData } from '@qovery/domains/services/feature' +import { AssistantTrigger } from '@qovery/shared/assistant/feature' +import { FunnelFlow } from '@qovery/shared/ui' +import { type HelmValuesFileData } from '../values-override-files-setting/values-override-files-setting' +import { findHelmTemplateMatch } from './helm-create-utils/helm-create-utils' + +export interface HelmCreateContextInterface { + currentStep: number + setCurrentStep: Dispatch> + creationFlowUrl: string + generalForm: UseFormReturn + valuesOverrideFileForm: UseFormReturn +} + +export const HelmCreateContext = createContext(undefined) + +export const useHelmCreateContext = () => { + const helmCreateContext = useContext(HelmCreateContext) + + if (!helmCreateContext) { + throw new Error('useHelmCreateContext must be used within a HelmCreateContext') + } + + return helmCreateContext +} + +export const helmCreationSteps: { title: string }[] = [{ title: 'General data' }, { title: 'Values override as file' }] + +export interface HelmCreationFlowProps extends PropsWithChildren { + creationFlowUrl: string +} + +export function HelmCreationFlow({ children, creationFlowUrl }: HelmCreationFlowProps) { + const { organizationId = '', projectId = '', environmentId = '' } = useParams({ strict: false }) + const { template } = useSearch({ strict: false }) + const navigate = useNavigate() + const [currentStep, setCurrentStep] = useState(1) + + const templateMatch = findHelmTemplateMatch(template) + + const generalForm = useForm({ + defaultValues: { + name: template ?? '', + icon_uri: templateMatch.iconUri ?? 'app://qovery-console/helm', + arguments: '--wait --atomic --debug', + timeout_sec: 600, + labels_groups: [], + annotations_groups: [], + }, + mode: 'onChange', + }) + + const valuesOverrideFileForm = useForm({ + defaultValues: { + type: 'GIT_REPOSITORY', + }, + mode: 'onChange', + }) + + return ( + + { + if (window.confirm('Do you really want to leave?')) { + navigate({ + to: '/organization/$organizationId/project/$projectId/environment/$environmentId/service/new', + params: { + organizationId, + projectId, + environmentId, + }, + }) + } + }} + totalSteps={helmCreationSteps.length} + currentStep={currentStep} + currentTitle={helmCreationSteps[currentStep - 1]?.title} + > + {children} + + + + ) +} diff --git a/libs/domains/service-helm/feature/src/lib/helm-creation-flow/step-general/step-general.spec.tsx b/libs/domains/service-helm/feature/src/lib/helm-creation-flow/step-general/step-general.spec.tsx new file mode 100644 index 00000000000..e8f86a90513 --- /dev/null +++ b/libs/domains/service-helm/feature/src/lib/helm-creation-flow/step-general/step-general.spec.tsx @@ -0,0 +1,77 @@ +import type { ReactNode } from 'react' +import { renderWithProviders, screen } from '@qovery/shared/util-tests' +import { HelmCreationFlow } from '../helm-creation-flow' +import { HelmStepGeneral } from './step-general' + +const mockOnSubmit = jest.fn() + +jest.mock('@qovery/shared/assistant/feature', () => ({ + AssistantTrigger: () => null, +})) + +jest.mock('@qovery/domains/organizations/feature', () => ({ + GitBranchSettings: () =>
, + GitProviderSetting: () =>
, + GitPublicRepositorySettings: () =>
, + GitRepositorySetting: () =>
, +})) + +jest.mock('../../source-setting/source-setting', () => ({ + SourceSetting: () =>
, +})) + +jest.mock('../../deployment-setting/deployment-setting', () => ({ + DeploymentSetting: () =>
, +})) + +jest.mock('@tanstack/react-router', () => ({ + ...jest.requireActual('@tanstack/react-router'), + useParams: () => ({ + organizationId: 'org-1', + projectId: 'proj-1', + environmentId: 'env-1', + }), + useSearch: () => ({}), + useNavigate: () => jest.fn(), +})) + +jest.mock('@qovery/shared/ui', () => ({ + ...jest.requireActual('@qovery/shared/ui'), + Link: ({ children, ...props }: { children?: ReactNode; [key: string]: unknown }) => {children}, +})) + +const defaultProps = { + labelSetting:
Labels
, + annotationSetting:
Annotations
, + onSubmit: mockOnSubmit, +} + +function renderStepGeneral() { + return renderWithProviders( + + + + ) +} + +describe('HelmStepGeneral', () => { + beforeEach(() => { + mockOnSubmit.mockClear() + }) + + it('renders the general helm form', () => { + renderStepGeneral() + + expect(screen.getByRole('heading', { name: 'General information' })).toBeInTheDocument() + expect(screen.getByRole('heading', { name: 'General' })).toBeInTheDocument() + expect(screen.getByRole('heading', { name: 'Source' })).toBeInTheDocument() + expect(screen.getByTestId('source-setting')).toBeInTheDocument() + expect(screen.getByRole('button', { name: 'Continue' })).toBeInTheDocument() + }) + + it('does not render extra labels section before a source is selected', () => { + renderStepGeneral() + + expect(screen.queryByRole('heading', { name: 'Extra labels/annotations' })).not.toBeInTheDocument() + }) +}) diff --git a/libs/domains/service-helm/feature/src/lib/helm-creation-flow/step-general/step-general.tsx b/libs/domains/service-helm/feature/src/lib/helm-creation-flow/step-general/step-general.tsx new file mode 100644 index 00000000000..4432580ceea --- /dev/null +++ b/libs/domains/service-helm/feature/src/lib/helm-creation-flow/step-general/step-general.tsx @@ -0,0 +1,215 @@ +import * as Collapsible from '@radix-ui/react-collapsible' +import { useNavigate, useParams } from '@tanstack/react-router' +import { type FormEventHandler, type ReactNode, useEffect, useState } from 'react' +import { FormProvider } from 'react-hook-form' +import { + GitBranchSettings, + GitProviderSetting, + GitPublicRepositorySettings, + GitRepositorySetting, +} from '@qovery/domains/organizations/feature' +import { AutoDeploySetting, GeneralSetting, type HelmGeneralData } from '@qovery/domains/services/feature' +import { Button, Callout, FunnelFlowBody, Heading, Icon, Section } from '@qovery/shared/ui' +import { DeploymentSetting } from '../../deployment-setting/deployment-setting' +import { SourceSetting } from '../../source-setting/source-setting' +import { useHelmCreateContext } from '../helm-creation-flow' + +export interface HelmStepGeneralProps { + labelSetting: ReactNode + annotationSetting: ReactNode + onSubmit: (data: HelmGeneralData) => void +} + +export function HelmStepGeneral({ onSubmit, labelSetting, annotationSetting }: HelmStepGeneralProps) { + const { organizationId = '', projectId = '', environmentId = '' } = useParams({ strict: false }) + const navigate = useNavigate() + const { generalForm, setCurrentStep } = useHelmCreateContext() + const [openExtraAttributes, setOpenExtraAttributes] = useState(false) + + useEffect(() => { + setCurrentStep(1) + }, [setCurrentStep]) + + const methods = generalForm + + const watchSourceProvider = methods.watch('source_provider') + const watchGitProvider = methods.watch('provider') + const watchGitTokenId = methods.watch('git_token_id') + const watchGitRepository = methods.watch('git_repository') + const watchIsPublicRepository = methods.watch('is_public_repository') + + const isGitSettingsValid = watchSourceProvider === 'GIT' ? Boolean(methods.watch('branch')) : true + + const handleSubmit: FormEventHandler = methods.handleSubmit((data) => { + const nextData = { + ...data, + auto_deploy: data.is_public_repository ? false : data.auto_deploy, + } + + methods.reset(nextData) + onSubmit(nextData) + }) + + return ( + + +
+ General information +

+ These general settings allow you to set up the service name, its source and deployment parameters. +

+ +
+
+ General + +
+ +
+ Source + + + {watchSourceProvider === 'GIT' && ( +
+ + {watchIsPublicRepository ? ( + <> + + + + + + + Git automations are disabled when using public repos (auto-deploy, automatic preview + environments) + + + + ) : ( + <> + {watchGitProvider && ( + + )} + {watchGitProvider && watchGitRepository && ( + + )} + + )} +
+ )} +
+ + {watchSourceProvider && ( + <> +
+ Deploy + + {watchSourceProvider === 'GIT' && !watchIsPublicRepository && } + {watchSourceProvider === 'HELM_REPOSITORY' && ( + + + + + + + Git automations are disabled when using Helm repositories (auto-deploy, automatic preview + environments) + + + + )} +
+ + +
+
+ Extra labels/annotations + + {openExtraAttributes ? ( + <> + Hide + + ) : ( + <> + Show + + )} + +
+ + {labelSetting} + {annotationSetting} + +
+
+ + )} + +
+ + +
+
+
+
+
+ ) +} diff --git a/libs/domains/service-helm/feature/src/lib/helm-creation-flow/step-values-override-files/step-values-override-files.spec.tsx b/libs/domains/service-helm/feature/src/lib/helm-creation-flow/step-values-override-files/step-values-override-files.spec.tsx new file mode 100644 index 00000000000..6652c6f1a71 --- /dev/null +++ b/libs/domains/service-helm/feature/src/lib/helm-creation-flow/step-values-override-files/step-values-override-files.spec.tsx @@ -0,0 +1,77 @@ +import { useForm } from 'react-hook-form' +import { type HelmGeneralData } from '@qovery/domains/services/feature' +import { renderHook, renderWithProviders, screen } from '@qovery/shared/util-tests' +import { type HelmValuesFileData } from '../../values-override-files-setting/values-override-files-setting' +import { HelmCreateContext } from '../helm-creation-flow' +import { HelmStepValuesOverrideFile } from './step-values-override-files' + +jest.mock('@qovery/domains/organizations/feature', () => ({ + GitBranchSettings: () =>
, + GitProviderSetting: () =>
, + GitPublicRepositorySettings: () =>
, + GitRepositorySetting: () =>
, +})) + +jest.mock('@tanstack/react-router', () => ({ + ...jest.requireActual('@tanstack/react-router'), + useParams: () => ({ + organizationId: 'org-1', + projectId: 'proj-1', + environmentId: 'env-1', + }), + useNavigate: () => jest.fn(), + useSearch: () => ({}), +})) + +describe('HelmStepValuesOverrideFile', () => { + it('renders the terminal step with a disabled continue button', () => { + const { result: generalForm } = renderHook(() => + useForm({ + mode: 'onChange', + defaultValues: { + name: 'my-helm-app', + source_provider: 'GIT', + provider: 'GITHUB', + git_repository: { + id: '1', + name: 'Qovery/github', + url: 'https://github.com/Qovery/github', + default_branch: 'main', + is_private: false, + }, + branch: 'main', + root_path: '/', + arguments: '--wait', + timeout_sec: 600, + }, + }) + ) + + const { result: valuesOverrideFileForm } = renderHook(() => + useForm({ + mode: 'onChange', + defaultValues: { + type: 'NONE', + }, + }) + ) + + renderWithProviders( + + + + ) + + expect(screen.getByText('Next steps are not migrated yet')).toBeInTheDocument() + expect(screen.getByRole('button', { name: 'Back' })).toBeInTheDocument() + expect(screen.getByRole('button', { name: 'Continue' })).toBeDisabled() + }) +}) diff --git a/libs/domains/service-helm/feature/src/lib/helm-creation-flow/step-values-override-files/step-values-override-files.tsx b/libs/domains/service-helm/feature/src/lib/helm-creation-flow/step-values-override-files/step-values-override-files.tsx new file mode 100644 index 00000000000..264f4948cb0 --- /dev/null +++ b/libs/domains/service-helm/feature/src/lib/helm-creation-flow/step-values-override-files/step-values-override-files.tsx @@ -0,0 +1,193 @@ +import { useNavigate, useParams, useSearch } from '@tanstack/react-router' +import { type FormEventHandler, useEffect } from 'react' +import { Controller, FormProvider, type UseFormReturn } from 'react-hook-form' +import { match } from 'ts-pattern' +import { + GitBranchSettings, + GitProviderSetting, + GitPublicRepositorySettings, + GitRepositorySetting, +} from '@qovery/domains/organizations/feature' +import { AutoDeploySetting, buildHelmSourceFromGeneralData } from '@qovery/domains/services/feature' +import { Button, Callout, FunnelFlowBody, Icon, InputText } from '@qovery/shared/ui' +import { + type HelmValuesFileData, + ValuesOverrideFilesSetting, +} from '../../values-override-files-setting/values-override-files-setting' +import { ValuesOverrideYamlSettingBase } from '../../values-override-yaml-setting/values-override-yaml-setting' +import { useHelmCreateContext } from '../helm-creation-flow' + +function GitPathsSettings({ methods }: { methods: UseFormReturn }) { + return ( +
+ ( + + )} + /> +

Specify multiple paths by separating them with a semi-colon

+
+ ) +} + +export function HelmStepValuesOverrideFile() { + const navigate = useNavigate() + const search = useSearch({ strict: false }) + const { organizationId = '', environmentId = '' } = useParams({ strict: false }) + const { generalForm, valuesOverrideFileForm, setCurrentStep, creationFlowUrl } = useHelmCreateContext() + + const generalData = generalForm.getValues() + const source = buildHelmSourceFromGeneralData(generalData) + + useEffect(() => { + setCurrentStep(2) + }, [setCurrentStep]) + + const handleSubmit: FormEventHandler = valuesOverrideFileForm.handleSubmit((data) => { + valuesOverrideFileForm.reset({ + ...data, + auto_deploy: data.is_public_repository ? false : data.auto_deploy, + }) + }) + + const watchFieldType = valuesOverrideFileForm.watch('type') + const watchFieldGitProvider = valuesOverrideFileForm.watch('provider') + const watchFieldGitTokenId = valuesOverrideFileForm.watch('git_token_id') + const watchFieldGitRepository = valuesOverrideFileForm.watch('git_repository') + const watchFieldGitBranch = valuesOverrideFileForm.watch('branch') + const watchFieldIsPublicRepository = valuesOverrideFileForm.watch('is_public_repository') + + const gitRepositorySettings = ( + <> + + {watchFieldIsPublicRepository ? ( + <> + + + + + + + + Git automations are disabled when using public repos (auto-deploy, automatic preview environments) + + + + ) : ( + <> + {watchFieldGitProvider && ( + + )} + {watchFieldGitProvider && watchFieldGitRepository && ( + <> + + {watchFieldGitBranch && } + + )} + {generalData.source_provider === 'HELM_REPOSITORY' && watchFieldGitProvider && watchFieldGitRepository && ( + + )} + {generalData.source_provider === 'GIT' && + (generalData.auto_deploy ? ( + + + + + + Auto-deploy is activated + The service will be automatically updated on every new commit on the branch. + + + ) : ( + + + + + + Auto-deploy is not activated + + + ))} + + )} + + ) + + const isContinueDisabled = match(watchFieldType) + .with('GIT_REPOSITORY', () => true) + .with('YAML', () => true) + .with('NONE', () => true) + .exhaustive() + + const yamlSetting = ( + { + valuesOverrideFileForm.setValue('content', value) + }} + source={source} + /> + ) + + return ( + + + + + + + + + Next steps are not migrated yet + You can already configure the Helm chart source and the values override file in console-v5. The remaining + creation steps will be added in a later iteration. + + + +
+ + +
+
+
+
+ ) +} diff --git a/libs/domains/service-helm/feature/src/lib/values-override-files-setting/values-override-files-setting.tsx b/libs/domains/service-helm/feature/src/lib/values-override-files-setting/values-override-files-setting.tsx index f36a6ebe158..5f3eacbb589 100644 --- a/libs/domains/service-helm/feature/src/lib/values-override-files-setting/values-override-files-setting.tsx +++ b/libs/domains/service-helm/feature/src/lib/values-override-files-setting/values-override-files-setting.tsx @@ -33,6 +33,7 @@ export interface ValuesOverrideFilesSettingProps { gitRepositorySettings: ReactNode onSubmit: () => void isSetting?: boolean + yamlSetting?: ReactNode } export function ValuesOverrideFilesSetting({ @@ -43,6 +44,7 @@ export function ValuesOverrideFilesSetting({ gitRepositorySettings, onSubmit, isSetting, + yamlSetting, }: PropsWithChildren) { return (
@@ -141,14 +143,16 @@ export function ValuesOverrideFilesSetting({ and can be updated later within the settings but no history will be retained.

- { - methods.setValue('content', value) - isSetting && onSubmit() - }} - source={source} - /> + {yamlSetting ?? ( + { + methods.setValue('content', value) + isSetting && onSubmit() + }} + source={source} + /> + )}
)} diff --git a/libs/domains/service-helm/feature/src/lib/values-override-yaml-setting/values-override-yaml-setting.spec.tsx b/libs/domains/service-helm/feature/src/lib/values-override-yaml-setting/values-override-yaml-setting.spec.tsx index 00e6b9d8de4..96b466c62a6 100644 --- a/libs/domains/service-helm/feature/src/lib/values-override-yaml-setting/values-override-yaml-setting.spec.tsx +++ b/libs/domains/service-helm/feature/src/lib/values-override-yaml-setting/values-override-yaml-setting.spec.tsx @@ -1,10 +1,78 @@ -import { wrapWithReactHookForm } from '__tests__/utils/wrap-with-react-hook-form' -import { renderWithProviders } from '@qovery/shared/util-tests' -import { ValuesOverrideYamlSetting } from './values-override-yaml-setting' - -describe('ValuesOverrideAsYamlSetting', () => { - it('should match snapshot', () => { - const { baseElement } = renderWithProviders(wrapWithReactHookForm()) - expect(baseElement).toMatchSnapshot() +import { renderWithProviders, screen } from '@qovery/shared/util-tests' +import { ValuesOverrideYamlSetting, ValuesOverrideYamlSettingBase } from './values-override-yaml-setting' + +const openModal = jest.fn() + +jest.mock('react-router', () => ({ + useParams: () => ({ + environmentId: 'env-from-router', + }), +})) + +jest.mock('@qovery/shared/ui', () => ({ + ...jest.requireActual('@qovery/shared/ui'), + useModal: () => ({ + openModal, + closeModal: jest.fn(), + }), + CodeEditorInlineSetting: ({ onOpenModal }: { onOpenModal: () => void }) => ( + + ), +})) + +jest.mock('../values-override-yaml-modal/values-override-yaml-modal', () => ({ + __esModule: true, + default: ({ environmentId }: { environmentId: string }) =>
{environmentId}
, +})) + +describe('ValuesOverrideYamlSetting', () => { + beforeEach(() => { + openModal.mockClear() + }) + + it('should use the provided environmentId when opening the modal', async () => { + const { userEvent } = renderWithProviders( + + ) + + await userEvent.click(screen.getByRole('button', { name: 'Open YAML modal' })) + + expect(openModal).toHaveBeenCalledTimes(1) + expect(openModal.mock.calls[0][0].content.props.environmentId).toBe('env-from-prop') + }) + + it('should fallback to router params when environmentId is not provided', async () => { + const { userEvent } = renderWithProviders( + + ) + + await userEvent.click(screen.getByRole('button', { name: 'Open YAML modal' })) + + expect(openModal).toHaveBeenCalledTimes(1) + expect(openModal.mock.calls[0][0].content.props.environmentId).toBe('env-from-router') }) }) diff --git a/libs/domains/service-helm/feature/src/lib/values-override-yaml-setting/values-override-yaml-setting.tsx b/libs/domains/service-helm/feature/src/lib/values-override-yaml-setting/values-override-yaml-setting.tsx index b27d97a1992..ef6cfd5ce6d 100644 --- a/libs/domains/service-helm/feature/src/lib/values-override-yaml-setting/values-override-yaml-setting.tsx +++ b/libs/domains/service-helm/feature/src/lib/values-override-yaml-setting/values-override-yaml-setting.tsx @@ -3,13 +3,13 @@ import { useParams } from 'react-router' import { CodeEditorInlineSetting, useModal } from '@qovery/shared/ui' import ValuesOverrideYamlModal from '../values-override-yaml-modal/values-override-yaml-modal' -export interface ValuesOverrideYamlSettingProps { +export interface ValuesOverrideYamlSettingBaseProps { source: HelmRequestAllOfSource onSubmit: (value?: string) => void content?: string } -export function ValuesOverrideYamlSetting({ onSubmit, content, source }: ValuesOverrideYamlSettingProps) { +export function ValuesOverrideYamlSettingBase({ onSubmit, content, source }: ValuesOverrideYamlSettingBaseProps) { const { openModal, closeModal } = useModal() const { environmentId = '' } = useParams() @@ -44,4 +44,14 @@ export function ValuesOverrideYamlSetting({ onSubmit, content, source }: ValuesO ) } +export interface ValuesOverrideYamlSettingProps { + source: HelmRequestAllOfSource + onSubmit: (value?: string) => void + content?: string +} + +export function ValuesOverrideYamlSetting({ onSubmit, content, source }: ValuesOverrideYamlSettingProps) { + return +} + export default ValuesOverrideYamlSetting diff --git a/libs/domains/services/feature/src/index.ts b/libs/domains/services/feature/src/index.ts index e1e5393018e..cea366e1da6 100644 --- a/libs/domains/services/feature/src/index.ts +++ b/libs/domains/services/feature/src/index.ts @@ -94,6 +94,7 @@ export * from './lib/pod-details/pod-details' export * from './lib/force-unlock-modal/force-unlock-modal' export * from './lib/application-settings-resources/application-settings-resources' export * from './lib/service-new/service-new' +export * from './lib/service-new/service-templates' export * from './lib/service-general-settings/service-general-default-values' export * from './lib/service-general-settings/service-general-payload' export * from './lib/service-general-settings/service-general-settings-payloads' diff --git a/libs/domains/services/feature/src/lib/service-general-settings/service-general-settings-payloads.ts b/libs/domains/services/feature/src/lib/service-general-settings/service-general-settings-payloads.ts index eddbaa6409b..f8303c99950 100644 --- a/libs/domains/services/feature/src/lib/service-general-settings/service-general-settings-payloads.ts +++ b/libs/domains/services/feature/src/lib/service-general-settings/service-general-settings-payloads.ts @@ -47,6 +47,34 @@ export interface HelmGeneralData timeout_sec: string | number } +export function buildHelmSourceFromGeneralData(data: HelmGeneralData): HelmRequestAllOfSource { + return match(data.source_provider) + .with('GIT', (): HelmRequestAllOfSourceOneOf => { + return { + git_repository: { + url: match(data.is_public_repository) + .with(true, () => data.repository ?? '') + .with(false, undefined, () => data.git_repository?.url ?? '') + .exhaustive(), + branch: data.branch, + root_path: data.root_path, + git_token_id: data.git_token_id, + }, + } + }) + .with( + 'HELM_REPOSITORY', + (): HelmRequestAllOfSourceOneOf1 => ({ + helm_repository: { + repository: data.repository, + chart_name: data.chart_name, + chart_version: data.chart_version, + }, + }) + ) + .exhaustive() +} + export interface TerraformGeneralData extends Omit { auto_deploy?: boolean terraform_action?: TerraformAutoDeployConfigTerraformActionEnum @@ -226,32 +254,7 @@ export const handleJobSubmit = ( } export const handleHelmSubmit = (data: HelmGeneralData, helm: Helm): HelmRequest => { - const sourceProvider: 'HELM_REPOSITORY' | 'GIT' = data.source_provider - const source: HelmRequestAllOfSource = match(sourceProvider) - .with('GIT', (): HelmRequestAllOfSourceOneOf => { - return { - git_repository: { - url: match(data.is_public_repository) - .with(true, () => data.repository ?? '') - .with(false, undefined, () => data.git_repository?.url ?? '') - .exhaustive(), - branch: data.branch, - root_path: data.root_path, - git_token_id: data.git_token_id, - }, - } - }) - .with( - 'HELM_REPOSITORY', - (): HelmRequestAllOfSourceOneOf1 => ({ - helm_repository: { - repository: data.repository, - chart_name: data.chart_name, - chart_version: data.chart_version, - }, - }) - ) - .exhaustive() + const source = buildHelmSourceFromGeneralData(data) const timeoutSec = Number.parseInt(String(data.timeout_sec), 10) diff --git a/libs/domains/services/feature/src/lib/service-new/service-new.spec.tsx b/libs/domains/services/feature/src/lib/service-new/service-new.spec.tsx index c18af4666aa..a3ff7d8baf9 100644 --- a/libs/domains/services/feature/src/lib/service-new/service-new.spec.tsx +++ b/libs/domains/services/feature/src/lib/service-new/service-new.spec.tsx @@ -108,4 +108,24 @@ describe('ServiceNew', () => { ).toBeInTheDocument() }) }) + + it('should link helm entries to the v5 helm create flow', async () => { + const { container, userEvent } = renderWithProviders( + + ) + + expect( + container.querySelector('a[href="/organization/org-1/project/project-1/environment/env-1/service/create/helm"]') + ).toBeInTheDocument() + + await userEvent.click(screen.getByText('Apache Kafka')) + + await waitFor(() => { + expect( + container.querySelector( + 'a[href="/organization/org-1/project/project-1/environment/env-1/service/create/helm?template=apachekafka"]' + ) + ).toBeInTheDocument() + }) + }) }) diff --git a/libs/domains/services/feature/src/lib/service-new/service-new.tsx b/libs/domains/services/feature/src/lib/service-new/service-new.tsx index 224cf05a898..2d6ebd401f4 100644 --- a/libs/domains/services/feature/src/lib/service-new/service-new.tsx +++ b/libs/domains/services/feature/src/lib/service-new/service-new.tsx @@ -7,8 +7,6 @@ import { match } from 'ts-pattern' import { type ServiceType } from '@qovery/domains/services/data-access' import { SERVICES_CRONJOB_CREATION_URL, - SERVICES_HELM_CREATION_URL, - SERVICES_HELM_TEMPLATE_CREATION_URL, SERVICES_LIFECYCLE_CREATION_URL, SERVICES_LIFECYCLE_TEMPLATE_CREATION_URL, SERVICES_TERRAFORM_CREATION_URL, @@ -170,9 +168,8 @@ function Card({ /** Types listed in CREATE_FLOW_SLUG_BY_TYPE use /service/create/:flowSlug?template=; others use legacy URLs until migrated. */ const servicePathSuffix = (type: ServiceType, parentSlug: string, slug: string) => match(type) - .with('APPLICATION', 'CONTAINER', 'DATABASE', () => buildCreateFlowPathForType(type, parentSlug, slug)) + .with('APPLICATION', 'CONTAINER', 'DATABASE', 'HELM', () => buildCreateFlowPathForType(type, parentSlug, slug)) .with('LIFECYCLE_JOB', () => SERVICES_LIFECYCLE_TEMPLATE_CREATION_URL(parentSlug, slug)) - .with('HELM', () => SERVICES_HELM_TEMPLATE_CREATION_URL(parentSlug, slug)) .with('JOB', 'CRON_JOB', () => undefined) .with('TERRAFORM', () => undefined) .otherwise(() => buildCreateFlowPathForType(type, parentSlug, slug)) @@ -576,7 +573,7 @@ export function ServiceNew({ title: 'Helm', description: 'Deploy a Helm Chart on your Kubernetes cluster.', icon: , - link: getServicesPath(organizationId, projectId, environmentId, SERVICES_HELM_CREATION_URL), + link: getServicesPath(organizationId, projectId, environmentId, getCreateFlowPath('helm')), cloud_provider: cloudProvider, }, ...(isTerraformFeatureFlag diff --git a/libs/pages/services/src/lib/feature/page-helm-create-feature/step-summary-feature/step-summary-feature.tsx b/libs/pages/services/src/lib/feature/page-helm-create-feature/step-summary-feature/step-summary-feature.tsx index 0acd57849d8..862278f228b 100644 --- a/libs/pages/services/src/lib/feature/page-helm-create-feature/step-summary-feature/step-summary-feature.tsx +++ b/libs/pages/services/src/lib/feature/page-helm-create-feature/step-summary-feature/step-summary-feature.tsx @@ -4,7 +4,7 @@ import { useNavigate, useParams } from 'react-router-dom' import { match } from 'ts-pattern' import { useHelmRepositories } from '@qovery/domains/organizations/feature' import { type ArgumentTypes, useCreateHelmService } from '@qovery/domains/service-helm/feature' -import { useDeployService } from '@qovery/domains/services/feature' +import { buildHelmSourceFromGeneralData, useDeployService } from '@qovery/domains/services/feature' import { SERVICES_CREATION_GENERAL_URL, SERVICES_GENERAL_URL, @@ -46,25 +46,7 @@ export function StepSummaryFeature() { setIsLoadingCreate(true) } - const source = match(generalData.source_provider) - .with('GIT', () => { - return { - git_repository: { - url: generalData.git_repository?.url ?? generalData.repository ?? '', - branch: generalData.branch, - root_path: generalData.root_path, - git_token_id: generalData.git_token_id, - }, - } - }) - .with('HELM_REPOSITORY', () => ({ - helm_repository: { - repository: generalData.repository, - chart_name: generalData.chart_name, - chart_version: generalData.chart_version, - }, - })) - .exhaustive() + const source = buildHelmSourceFromGeneralData(generalData) const valuesOverrideFile = match(valuesOverrideFileData.type) .with('GIT_REPOSITORY', () => { diff --git a/libs/pages/services/src/lib/feature/page-helm-create-feature/step-values-override-arguments-feature/step-values-override-arguments-feature.tsx b/libs/pages/services/src/lib/feature/page-helm-create-feature/step-values-override-arguments-feature/step-values-override-arguments-feature.tsx index 291699dde1c..9598224759e 100644 --- a/libs/pages/services/src/lib/feature/page-helm-create-feature/step-values-override-arguments-feature/step-values-override-arguments-feature.tsx +++ b/libs/pages/services/src/lib/feature/page-helm-create-feature/step-values-override-arguments-feature/step-values-override-arguments-feature.tsx @@ -1,9 +1,8 @@ -import { type HelmRequestAllOfSourceOneOf, type HelmRequestAllOfSourceOneOf1 } from 'qovery-typescript-axios' import { useEffect } from 'react' import { FormProvider } from 'react-hook-form' import { useNavigate } from 'react-router-dom' -import { match } from 'ts-pattern' import { ValuesOverrideArgumentsSetting } from '@qovery/domains/service-helm/feature' +import { buildHelmSourceFromGeneralData } from '@qovery/domains/services/feature' import { SERVICES_HELM_CREATION_SUMMARY_URL, SERVICES_HELM_CREATION_VALUES_STEP_1_URL } from '@qovery/shared/routes' import { Button, FunnelFlowBody } from '@qovery/shared/ui' import { useDocumentTitle } from '@qovery/shared/util-hooks' @@ -16,28 +15,7 @@ export function StepValuesOverrideArgumentsFeature() { const generalData = generalForm.getValues() - const source = match(generalData.source_provider) - .with('GIT', (): HelmRequestAllOfSourceOneOf => { - return { - git_repository: { - url: generalData.git_repository?.url ?? generalData.repository ?? '', - branch: generalData.branch, - root_path: generalData.root_path, - git_token_id: generalData.git_token_id, - }, - } - }) - .with( - 'HELM_REPOSITORY', - (): HelmRequestAllOfSourceOneOf1 => ({ - helm_repository: { - repository: generalData.repository, - chart_name: generalData.chart_name, - chart_version: generalData.chart_version, - }, - }) - ) - .exhaustive() + const source = buildHelmSourceFromGeneralData(generalData) const navigate = useNavigate() diff --git a/libs/pages/services/src/lib/feature/page-helm-create-feature/step-values-override-files-feature/step-values-override-files-feature.tsx b/libs/pages/services/src/lib/feature/page-helm-create-feature/step-values-override-files-feature/step-values-override-files-feature.tsx index bf0b66d89a0..fc2b9f7bde3 100644 --- a/libs/pages/services/src/lib/feature/page-helm-create-feature/step-values-override-files-feature/step-values-override-files-feature.tsx +++ b/libs/pages/services/src/lib/feature/page-helm-create-feature/step-values-override-files-feature/step-values-override-files-feature.tsx @@ -9,11 +9,10 @@ import { GitRepositorySetting, } from '@qovery/domains/organizations/feature' import { type HelmValuesFileData, ValuesOverrideFilesSetting } from '@qovery/domains/service-helm/feature' -import { AutoDeploySetting } from '@qovery/domains/services/feature' +import { AutoDeploySetting, buildHelmSourceFromGeneralData } from '@qovery/domains/services/feature' import { SERVICES_HELM_CREATION_GENERAL_URL, SERVICES_HELM_CREATION_VALUES_STEP_2_URL } from '@qovery/shared/routes' import { Button, Callout, FunnelFlowBody, Icon, InputText } from '@qovery/shared/ui' import { useDocumentTitle } from '@qovery/shared/util-hooks' -import { buildGitRepoUrl } from '@qovery/shared/util-js' import { useHelmCreateContext } from '../page-helm-create-feature' function GitPathsSettings({ methods }: { methods: UseFormReturn }) { @@ -48,25 +47,7 @@ export function StepValuesOverrideFilesFeature() { const generalData = generalForm.getValues() - const source = match(generalData.source_provider) - .with('GIT', () => { - return { - git_repository: { - url: generalData.git_repository?.url ?? generalData.repository ?? '', - branch: generalData.branch, - root_path: generalData.root_path, - git_token_id: generalData.git_token_id, - }, - } - }) - .with('HELM_REPOSITORY', () => ({ - helm_repository: { - repository: generalData.repository, - chart_name: generalData.chart_name, - chart_version: generalData.chart_version, - }, - })) - .exhaustive() + const source = buildHelmSourceFromGeneralData(generalData) const navigate = useNavigate() From b9be47367962b6b12040f920dcb5620876a72aad Mon Sep 17 00:00:00 2001 From: RemiBonnet Date: Fri, 27 Mar 2026 18:08:26 +0100 Subject: [PATCH 2/2] style(helm-creation-flow): update text color for better readability in override files settings --- .../step-values-override-files.tsx | 11 ++++++----- .../values-override-files-setting.tsx | 14 +++++++------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/libs/domains/service-helm/feature/src/lib/helm-creation-flow/step-values-override-files/step-values-override-files.tsx b/libs/domains/service-helm/feature/src/lib/helm-creation-flow/step-values-override-files/step-values-override-files.tsx index 264f4948cb0..4c5523a2c05 100644 --- a/libs/domains/service-helm/feature/src/lib/helm-creation-flow/step-values-override-files/step-values-override-files.tsx +++ b/libs/domains/service-helm/feature/src/lib/helm-creation-flow/step-values-override-files/step-values-override-files.tsx @@ -1,5 +1,5 @@ import { useNavigate, useParams, useSearch } from '@tanstack/react-router' -import { type FormEventHandler, useEffect } from 'react' +import { useEffect } from 'react' import { Controller, FormProvider, type UseFormReturn } from 'react-hook-form' import { match } from 'ts-pattern' import { @@ -36,7 +36,9 @@ function GitPathsSettings({ methods }: { methods: UseFormReturn )} /> -

Specify multiple paths by separating them with a semi-colon

+

+ Specify multiple paths by separating them with a semi-colon +

) } @@ -44,7 +46,7 @@ function GitPathsSettings({ methods }: { methods: UseFormReturn = valuesOverrideFileForm.handleSubmit((data) => { + const handleSubmit = valuesOverrideFileForm.handleSubmit((data) => { valuesOverrideFileForm.reset({ ...data, auto_deploy: data.is_public_repository ? false : data.auto_deploy, @@ -142,7 +144,6 @@ export function HelmStepValuesOverrideFile() { const yamlSetting = ( { valuesOverrideFileForm.setValue('content', value) }} diff --git a/libs/domains/service-helm/feature/src/lib/values-override-files-setting/values-override-files-setting.tsx b/libs/domains/service-helm/feature/src/lib/values-override-files-setting/values-override-files-setting.tsx index 5f3eacbb589..b3250bb2297 100644 --- a/libs/domains/service-helm/feature/src/lib/values-override-files-setting/values-override-files-setting.tsx +++ b/libs/domains/service-helm/feature/src/lib/values-override-files-setting/values-override-files-setting.tsx @@ -60,18 +60,18 @@ export function ValuesOverrideFilesSetting({
{!isSetting && (
-

+

Define the YAML file(s) to be applied as override to the default values.yaml delivered with the chart. It is highly recommended to store the override file(s) in a git repository.

- + How it works - -
How it works
+ +
How it works
  • Your helm chart might have already a variables.yaml file with some basic configuration. In this @@ -100,7 +100,7 @@ export function ValuesOverrideFilesSetting({ @@ -138,7 +138,7 @@ export function ValuesOverrideFilesSetting({ {watchFieldType === 'YAML' && (
    Override with raw Yaml -

    +

    You can define here the YAML containing the overrides you want to apply. The YAML will be stored by Qovery and can be updated later within the settings but no history will be retained.

    @@ -160,7 +160,7 @@ export function ValuesOverrideFilesSetting({ {watchFieldType === 'GIT_REPOSITORY' && (
    Override from repository -

    +

    Specify the repository and the path containing the override yaml file to be passed via the “-f” helm argument. More than one file can be used as override by adding them in the path field separated by a semi-colon. If you don’t have a repository, you can set the override manually or via a raw YAML file.