Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ interface EditGitRepositorySettingsProps {
gitRepository?: ApplicationGitRepository
rootPathLabel?: string
rootPathHint?: string
showEditAction?: boolean
}

export function EditGitRepositorySettings({
organizationId,
gitRepository,
rootPathHint,
rootPathLabel,
showEditAction = true,
}: EditGitRepositorySettingsProps) {
const { setValue } = useFormContext<{
provider: GitProviderEnum | undefined
Expand Down Expand Up @@ -52,7 +54,7 @@ export function EditGitRepositorySettings({
return (
<GitRepositorySettings
gitDisabled={gitDisabled}
editGitSettings={editGitSettings}
editGitSettings={showEditAction ? editGitSettings : undefined}
currentProvider={gitRepository?.provider}
currentRepository={gitRepository?.name}
urlRepository={gitRepository?.url}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,42 @@ import { organizationFactoryMock, terraformFactoryMock } from '@qovery/shared/fa
import { renderWithProviders, screen } from '@qovery/shared/util-tests'
import { TerraformGeneralSettings } from './terraform-general-settings'

const mockNavigate = jest.fn()
const mockUseBlueprintUpdate = jest.fn()
const mockEditGitRepositorySettings = jest.fn()

jest.mock('@tanstack/react-router', () => ({
...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(<TerraformGeneralSettings service={service} organization={organization} />, {
Expand All @@ -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(
<TerraformGeneralSettings service={{ ...service, blueprint_id: 'blueprint-id' }} organization={organization} />,
{
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(<TerraformGeneralSettings service={service} organization={organization} />, {
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(
<TerraformGeneralSettings service={{ ...service, blueprint_id: 'blueprint-id' }} organization={organization} />,
{
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(
<TerraformGeneralSettings service={{ ...service, blueprint_id: 'blueprint-id' }} organization={organization} />,
{
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()
})
})
Original file line number Diff line number Diff line change
@@ -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 },
Expand Down Expand Up @@ -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 && <BlueprintUpdateSettings blueprintId={service.blueprint_id} />}
</Section>

<Section className="gap-4">
Expand All @@ -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 })
Comment thread
rmnbrd marked this conversation as resolved.
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 && (
<div>
<Button type="button" variant="plain" color="brand" size="md" onClick={openBlueprintUpdate}>
New major version available
</Button>
</div>
)}
{!blueprintUpdate.is_up_to_date && (
<Callout.Root color="sky" className="items-center">
<Callout.Icon>
<Icon iconName="circle-info" iconStyle="regular" />
</Callout.Icon>
<Callout.Text>New blueprint version available</Callout.Text>
<Button type="button" size="sm" className="ml-auto" onClick={openBlueprintUpdate}>
Update
</Button>
</Callout.Root>
)}
</>
)
}

export default TerraformGeneralSettings
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ function ServiceInformationSectionContent({ onContinue }: ServiceInformationSect
/>
{blueprintVersionOptions.length > 1 ? (
<InputSelect
label="Blueprint version"
label="Version"
value={versionTag}
options={blueprintVersionOptions}
onChange={(value) =>
Expand All @@ -153,7 +153,7 @@ function ServiceInformationSectionContent({ onContinue }: ServiceInformationSect
isSearchable={blueprintVersionOptions.length > 6}
/>
) : (
<InputText name="blueprint-version" label="Blueprint version" value={serviceVersion} disabled />
<InputText name="blueprint-version" label="Version" value={serviceVersion} disabled />
)}
<Button
type="button"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ export function BlueprintStepSummary() {
<ul className="list-none space-y-2 text-sm text-neutral-subtle">
<SummaryValue label="Name" value={serviceName} />
<SummaryValue label="Blueprint" value={blueprint.name} />
<SummaryValue label="Blueprint version" value={serviceVersion} />
<SummaryValue label="Version" value={serviceVersion} />
</ul>
</Section>

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
10 changes: 5 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down