Skip to content
Merged
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
70 changes: 41 additions & 29 deletions apps/client/src/components/DeploymentModal.vue
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
<script lang="ts" setup>
import type { Cluster, Deployment, Environment, Stage, UpdateDeployment, Zone } from '@cpn-console/shared'
import type {
Cluster,
Deployment,
Environment,
Stage,
UpdateDeployment,
UpdateDeploymentSource,
Zone,
} from '@cpn-console/shared'
import type { DsfrRadioButtonProps } from '@gouvminint/vue-dsfr'
import type { Project } from '@/utils/project-utils.js'
import { CreateDeploymentSchema, DeploymentSchema, longestDeploymentName } from '@cpn-console/shared'
import { useSnackbarStore } from '@/stores/snackbar.js'
import { scrollToFirstError } from '@/utils/func.js'
import { CreateDeploymentSchema, DeploymentSchema, longestDeploymentName, UpdateDeploymentSchema } from '@cpn-console/shared'
import { useSnackbarStore } from '@/stores/snackbar'
import { toDeploymentDraft } from '@/utils/deployment-draft'
import { scrollToFirstError } from '@/utils/func'

const props = withDefaults(defineProps<{
const props = defineProps<{
opened: boolean
environments: (Environment & { cluster?: Cluster, zone?: Zone, stage?: Stage })[]
repoOptions: { text: string, value: string }[]
deployment?: Deployment
project: Project
disabled?: boolean
}>(), { opened: false, disabled: false })
disabled: boolean
}>()

const emit = defineEmits<{ close: [] }>()

Expand All @@ -31,16 +40,16 @@ const options: ComputedRef<Omit<DsfrRadioButtonProps, 'modelValue'>[]> = compute
)

const deployment = ref<Partial<UpdateDeployment & { id: string }>>(
props.deployment ? { ...props.deployment } : { projectId: props.project.id, autosync: true },
props.deployment ? toDeploymentDraft(props.deployment) : { projectId: props.project.id, autosync: true },
)

watch(() => props.deployment, (newValue) => {
deployment.value = newValue ? { ...newValue } : { projectId: props.project.id, autosync: true }
deployment.value = newValue ? toDeploymentDraft(newValue) : { projectId: props.project.id, autosync: true }
}, { deep: true })

const deploymentSourcesModel = computed({
get: () => deployment.value?.deploymentSources ?? [],
set: (value: UpdateDeployment['deploymentSources']) =>
set: (value: UpdateDeploymentSource[]) =>
deployment.value = { ...deployment.value, deploymentSources: value },
})

Expand All @@ -67,31 +76,29 @@ const environmentErrorMessage = computed(() => {
function upsertDeployment() {
if (isLoading.value) return

const body = CreateDeploymentSchema.safeParse(deployment.value)
const id = deployment.value.id
const body = id
? UpdateDeploymentSchema.safeParse(deployment.value)
: CreateDeploymentSchema.safeParse(deployment.value)

if (!body.success) {
isDirty.value = true
scrollToFirstError(formContainer)
return
}

const request = id
? props.project.Deployments.update(id, body.data)
: props.project.Deployments.create(body.data)

isLoading.value = true
if (deployment.value.id) {
props.project.Deployments.update(deployment.value.id, body.data)
.then(() => {
closeModal()
snackbarStore.setMessage('Déploiement enregistré, opérations en cours en arrière-plan...')
})
.catch(error => snackbarStore.setMessage(error, 'error'))
.finally(() => isLoading.value = false)
} else {
props.project.Deployments.create(body.data)
.then(() => {
closeModal()
snackbarStore.setMessage('Déploiement enregistré, opérations en cours en arrière-plan...')
})
.catch(error => snackbarStore.setMessage(error, 'error'))
.finally(() => isLoading.value = false)
}
request
.then(() => {
closeModal()
snackbarStore.setMessage('Déploiement enregistré, opérations en cours en arrière-plan...')
})
.catch((error: string) => snackbarStore.setMessage(error, 'error'))
.finally(() => isLoading.value = false)
}

function deleteDeployment() {
Expand Down Expand Up @@ -158,7 +165,12 @@ function closeModal() {
<h6 class="fr-mb-0">
Dépôts à inclure
</h6>
<DeploymentRepoSelect v-model="deploymentSourcesModel" :is-dirty :repo-options="repoOptions" :disabled="props.disabled" />
<DeploymentRepoSelect
v-model="deploymentSourcesModel"
:is-dirty
:repo-options="repoOptions"
:disabled="props.disabled"
/>
</div>
<div class="w-full flex justify-end gap-4">
<DsfrButton
Expand Down
36 changes: 14 additions & 22 deletions apps/client/src/components/DeploymentRepoOption.vue
Original file line number Diff line number Diff line change
@@ -1,32 +1,29 @@
<script setup lang="ts">
import type { UpdateDeployment } from '@cpn-console/shared'
import type { UpdateDeploymentSource } from '@cpn-console/shared'
import { DeploymentSourceSchema } from '@cpn-console/shared'

withDefaults(defineProps<{
type DeploymentSourceDraft = Partial<UpdateDeploymentSource>

const props = withDefaults(defineProps<{
cantDelete: boolean
options: { text: string, value: string }[]
disabled?: boolean
isDirty?: boolean
disabled: boolean
isDirty: boolean
}>(), {
options: () => [],
cantDelete: false,
disabled: false,
isDirty: false,
})
defineEmits<{ delete: [] }>()

const model = defineModel<Partial<UpdateDeployment['deploymentSources'][0]>>(
const model = defineModel<DeploymentSourceDraft>(
{
default: {
id: undefined,
type: 'git',
repositoryId: undefined,
targetRevision: undefined,
path: undefined,
helmValuesFiles: undefined,
valueSources: [],
},
},
)

const valueSourceRepoOptions = computed(() => props.options.filter(option => option.value !== model.value.repositoryId))
</script>

<template>
Expand All @@ -51,16 +48,11 @@ const model = defineModel<Partial<UpdateDeployment['deploymentSources'][0]>>(
label-visible
:disabled="$props.disabled"
/>
<DsfrInputGroup
v-model="model.helmValuesFiles"
class="mb-2"
is-textarea
label="Fichiers values (Helm)"
label-visible
hint="Un fichier par ligne, chemin relatif par rapport au répertoire à déployer. L'ordre des fichiers est déterminant pour la surcharge des valeurs communes. Champ optionnel."
placeholder="values/extra.yaml
values-<env>/custom.yaml"
<DeploymentValueSources
v-model="model.valueSources"
:repo-options="valueSourceRepoOptions"
:disabled="$props.disabled"
:is-dirty="$props.isDirty"
/>
</div>
</template>
Expand Down
24 changes: 11 additions & 13 deletions apps/client/src/components/DeploymentRepoSelect.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
<script lang="ts" setup>
import type { UpdateDeployment } from '@cpn-console/shared'
import type { UpdateDeploymentSource } from '@cpn-console/shared'

withDefaults(defineProps<{
type DeploymentSourceDraft = Partial<UpdateDeploymentSource>

defineProps<{
repoOptions: { text: string, value: string }[]
disabled?: boolean
isDirty?: boolean
}>(), { disabled: false, isDirty: false })
disabled: boolean
isDirty: boolean
}>()

const depots = defineModel<Partial<UpdateDeployment['deploymentSources'][0]>[]>({ default: [] })
const depots = defineModel<DeploymentSourceDraft[]>({ default: [] })

if (depots.value.length === 0) {
addDepot()
Expand All @@ -17,12 +19,8 @@ function addDepot() {
depots.value = [
...depots.value,
{
id: undefined,
type: 'git',
repositoryId: undefined,
targetRevision: undefined,
path: undefined,
helmValuesFiles: undefined,
valueSources: [],
},
]
}
Expand All @@ -31,7 +29,7 @@ function removeDepot(index: number) {
depots.value = depots.value.filter((_, i) => i !== index)
}

function updateDepot(index: number, value: Partial<UpdateDeployment['deploymentSources'][0]>) {
function updateDepot(index: number, value: DeploymentSourceDraft) {
depots.value[index] = value
}
</script>
Expand All @@ -48,7 +46,7 @@ function updateDepot(index: number, value: Partial<UpdateDeployment['deploymentS
:cant-delete="index === 0"
:disabled="$props.disabled"
:is-dirty="$props.isDirty"
@update:model-value="(value :Partial<UpdateDeployment['deploymentSources'][0]>) => updateDepot(index, value)"
@update:model-value="(value: DeploymentSourceDraft) => updateDepot(index, value)"
@delete="removeDepot(index)"
/>
</div>
Expand Down
Loading