diff --git a/libs/domains/organizations/feature/src/lib/git-repository-service-settings/edit-git-repository-settings/edit-git-repository-settings.tsx b/libs/domains/organizations/feature/src/lib/git-repository-service-settings/edit-git-repository-settings/edit-git-repository-settings.tsx index 5caf135b8c2..2224c38c51f 100644 --- a/libs/domains/organizations/feature/src/lib/git-repository-service-settings/edit-git-repository-settings/edit-git-repository-settings.tsx +++ b/libs/domains/organizations/feature/src/lib/git-repository-service-settings/edit-git-repository-settings/edit-git-repository-settings.tsx @@ -8,6 +8,7 @@ interface EditGitRepositorySettingsProps { gitRepository?: ApplicationGitRepository rootPathLabel?: string rootPathHint?: string + showEditAction?: boolean } export function EditGitRepositorySettings({ @@ -15,6 +16,7 @@ export function EditGitRepositorySettings({ gitRepository, rootPathHint, rootPathLabel, + showEditAction = true, }: EditGitRepositorySettingsProps) { const { setValue } = useFormContext<{ provider: GitProviderEnum | undefined @@ -52,7 +54,7 @@ export function EditGitRepositorySettings({ return ( ({ + ...jest.requireActual('@tanstack/react-router'), + useNavigate: () => mockNavigate, + useParams: () => ({ + organizationId: 'organization-id', + projectId: 'project-id', + environmentId: 'environment-id', + serviceId: 'service-id', + }), +})) + jest.mock('@qovery/domains/organizations/feature', () => ({ - EditGitRepositorySettings: () => null, + EditGitRepositorySettings: (props: unknown) => { + mockEditGitRepositorySettings(props) + return null + }, })) jest.mock('@qovery/domains/services/feature', () => ({ AutoDeploySection: () => null, GeneralSetting: () => null, + useBlueprintUpdate: (props: unknown) => mockUseBlueprintUpdate(props), })) describe('TerraformGeneralSettings', () => { const service = terraformFactoryMock(1)[0] const organization = organizationFactoryMock(1)[0] + beforeEach(() => { + jest.clearAllMocks() + }) + it('should render main sections', () => { renderWithProviders( wrapWithReactHookForm(, { @@ -31,4 +54,103 @@ describe('TerraformGeneralSettings', () => { expect(screen.getByText('Source')).toBeInTheDocument() expect(screen.getByText('Build and deploy')).toBeInTheDocument() }) + + it('shows the major version signal and blueprint update callout for blueprint services', async () => { + mockUseBlueprintUpdate.mockReturnValue({ + data: { + is_up_to_date: false, + new_major_versions: [{ service_version: '17', latest_tag: 'aws/postgres/17/1.0.0' }], + }, + }) + + const { userEvent } = renderWithProviders( + wrapWithReactHookForm( + , + { + defaultValues: { + name: service.name, + terraform_action: TerraformAutoDeployConfigTerraformActionEnum.DEFAULT, + }, + } + ) + ) + + expect(screen.getByRole('button', { name: 'New major version available' })).toBeInTheDocument() + expect(screen.getByText('New blueprint version available')).toBeInTheDocument() + expect(mockEditGitRepositorySettings).toHaveBeenCalledWith( + expect.objectContaining({ showEditAction: false }) + ) + + await userEvent.click(screen.getByRole('button', { name: 'Update' })) + + expect(mockNavigate).toHaveBeenCalledWith({ + to: '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/update/blueprint', + params: { + organizationId: 'organization-id', + projectId: 'project-id', + environmentId: 'environment-id', + serviceId: 'service-id', + }, + }) + }) + + it('allows editing the Git repository for non-blueprint services', () => { + renderWithProviders( + wrapWithReactHookForm(, { + defaultValues: { + name: service.name, + terraform_action: TerraformAutoDeployConfigTerraformActionEnum.DEFAULT, + }, + }) + ) + + expect(mockEditGitRepositorySettings).toHaveBeenCalledWith(expect.objectContaining({ showEditAction: true })) + }) + + it('hides blueprint update signals when the blueprint is up to date', () => { + mockUseBlueprintUpdate.mockReturnValue({ + data: { + is_up_to_date: true, + new_major_versions: [], + }, + }) + + renderWithProviders( + wrapWithReactHookForm( + , + { + defaultValues: { + name: service.name, + terraform_action: TerraformAutoDeployConfigTerraformActionEnum.DEFAULT, + }, + } + ) + ) + + expect(screen.queryByText('New major version available')).not.toBeInTheDocument() + expect(screen.queryByText('New blueprint version available')).not.toBeInTheDocument() + }) + + it('still renders the blueprint update callout when an older API response omits major versions', () => { + mockUseBlueprintUpdate.mockReturnValue({ + data: { + is_up_to_date: false, + }, + }) + + renderWithProviders( + wrapWithReactHookForm( + , + { + defaultValues: { + name: service.name, + terraform_action: TerraformAutoDeployConfigTerraformActionEnum.DEFAULT, + }, + } + ) + ) + + expect(screen.queryByText('New major version available')).not.toBeInTheDocument() + expect(screen.getByText('New blueprint version available')).toBeInTheDocument() + }) }) diff --git a/libs/domains/service-settings/feature/src/lib/service-general-settings/terraform-general-settings/terraform-general-settings.tsx b/libs/domains/service-settings/feature/src/lib/service-general-settings/terraform-general-settings/terraform-general-settings.tsx index 4a48089813b..a61dee900a8 100644 --- a/libs/domains/service-settings/feature/src/lib/service-general-settings/terraform-general-settings/terraform-general-settings.tsx +++ b/libs/domains/service-settings/feature/src/lib/service-general-settings/terraform-general-settings/terraform-general-settings.tsx @@ -1,9 +1,10 @@ +import { useNavigate, useParams } from '@tanstack/react-router' import { type Organization, TerraformAutoDeployConfigTerraformActionEnum } from 'qovery-typescript-axios' import { Controller, useFormContext } from 'react-hook-form' import { EditGitRepositorySettings } from '@qovery/domains/organizations/feature' import { type Terraform } from '@qovery/domains/services/data-access' -import { AutoDeploySection, GeneralSetting } from '@qovery/domains/services/feature' -import { Heading, InputSelect, Section } from '@qovery/shared/ui' +import { AutoDeploySection, GeneralSetting, useBlueprintUpdate } from '@qovery/domains/services/feature' +import { Button, Callout, Heading, Icon, InputSelect, Section } from '@qovery/shared/ui' const triggeredActionItems = [ { label: 'Plan & apply', value: TerraformAutoDeployConfigTerraformActionEnum.DEFAULT }, @@ -33,7 +34,9 @@ export function TerraformGeneralSettings({ service, organization }: TerraformGen gitRepository={service.terraform_files_source?.git?.git_repository} rootPathLabel="Terraform root folder path" rootPathHint="Provide the folder path where the Terraform code is located in the repository." + showEditAction={!service.blueprint_id} /> + {service.blueprint_id && }
@@ -59,4 +62,42 @@ export function TerraformGeneralSettings({ service, organization }: TerraformGen ) } +function BlueprintUpdateSettings({ blueprintId }: { blueprintId: string }) { + const { data: blueprintUpdate } = useBlueprintUpdate({ blueprintId, suspense: true }) + const { organizationId = '', projectId = '', environmentId = '', serviceId = '' } = useParams({ strict: false }) + const navigate = useNavigate() + + if (!blueprintUpdate) return null + + const openBlueprintUpdate = () => { + navigate({ + to: '/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/update/blueprint', + params: { organizationId, projectId, environmentId, serviceId }, + }) + } + + return ( + <> + {blueprintUpdate.new_major_versions?.length > 0 && ( +
+ +
+ )} + {!blueprintUpdate.is_up_to_date && ( + + + + + New blueprint version available + + + )} + + ) +} + export default TerraformGeneralSettings diff --git a/libs/domains/services/feature/src/lib/service-creation-flow/blueprint/blueprint-configuration-view/blueprint-configuration-view.tsx b/libs/domains/services/feature/src/lib/service-creation-flow/blueprint/blueprint-configuration-view/blueprint-configuration-view.tsx index 191bc8c69c4..8dc3628a5bd 100644 --- a/libs/domains/services/feature/src/lib/service-creation-flow/blueprint/blueprint-configuration-view/blueprint-configuration-view.tsx +++ b/libs/domains/services/feature/src/lib/service-creation-flow/blueprint/blueprint-configuration-view/blueprint-configuration-view.tsx @@ -144,7 +144,7 @@ function ServiceInformationSectionContent({ onContinue }: ServiceInformationSect /> {blueprintVersionOptions.length > 1 ? ( @@ -153,7 +153,7 @@ function ServiceInformationSectionContent({ onContinue }: ServiceInformationSect isSearchable={blueprintVersionOptions.length > 6} /> ) : ( - + )}
diff --git a/package.json b/package.json index de3d8048b56..82e843a9525 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "mermaid": "11.6.0", "monaco-editor": "0.53.0", "posthog-js": "1.345.1", - "qovery-typescript-axios": "1.1.920", + "qovery-typescript-axios": "1.1.925", "react": "18.3.1", "react-country-flag": "3.0.2", "react-datepicker": "4.12.0", diff --git a/yarn.lock b/yarn.lock index 1a6101f9168..1629f25e935 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6343,7 +6343,7 @@ __metadata: prettier: 3.2.5 prettier-plugin-tailwindcss: 0.5.14 pretty-quick: 4.0.0 - qovery-typescript-axios: 1.1.920 + qovery-typescript-axios: 1.1.925 qovery-ws-typescript-axios: 0.1.621 react: 18.3.1 react-country-flag: 3.0.2 @@ -25862,12 +25862,12 @@ __metadata: languageName: node linkType: hard -"qovery-typescript-axios@npm:1.1.920": - version: 1.1.920 - resolution: "qovery-typescript-axios@npm:1.1.920" +"qovery-typescript-axios@npm:1.1.925": + version: 1.1.925 + resolution: "qovery-typescript-axios@npm:1.1.925" dependencies: axios: 1.15.2 - checksum: ea8634a4c39cffb4127fd69ff1e9f59948db6ab35ddce30afd8a32312ae5a2394e88196b6ab25f47bf5a8d1801c839d5b63e8d7ca708da1da77eb9bdf6fe0e68 + checksum: 8661bdc95d6333250ca73cc697f5c4f33dcd357504af2f7242f55054ce6b2530778519494078b0df6a3c9df1f20b388c178ec4e63b89efca6a5dc1b44c09199e languageName: node linkType: hard