Skip to content

Commit

Permalink
fix create pipeline form validation
Browse files Browse the repository at this point in the history
  • Loading branch information
ankormoreankor committed Feb 28, 2025
1 parent 5934bae commit 3d8aad9
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const PipelineListWrapper: FC<Partial<RepoSummaryViewProps>> = () => {
/>
<CreatePipelineDialog
isOpen={createPipelineOpen}
useTranslationStore={useTranslationStore}
onClose={() => setCreatePipelineOpen(false)}
onSubmit={() => {
setCreatePipelineOpen(false)
Expand Down
2 changes: 2 additions & 0 deletions apps/gitness/src/pages-v2/pipeline/create-pipeline-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { CreatePipelineDialog as CreatePipelineDialogView, CreatePipelineFormTyp

import { useRoutes } from '../../framework/context/NavigationContext'
import { useGetRepoRef } from '../../framework/hooks/useGetRepoPath'
import { useTranslationStore } from '../../i18n/stores/i18n-store'
import { PathParams } from '../../RouteDefinitions'
import { apiBranches2BranchNames, apiBranches2DefaultBranchName } from '../repo/transform-utils/branch-transform'
import { useCreatePipelineStore } from './stores/create-pipeline-dialog.store'
Expand Down Expand Up @@ -69,6 +70,7 @@ export default function CreatePipelineDialog({ open, onClose }: CreatePipelineDi
onSubmit={onSubmit}
onCancel={onCloseInternal}
useCreatePipelineStore={useCreatePipelineStore}
useTranslationStore={useTranslationStore}
/>
)
}
8 changes: 8 additions & 0 deletions packages/ui/locales/en/views.json
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,14 @@
"description": "The requested page is not found.",
"button": "Reload page"
},
"pipelines": {
"createPipelineValidation": {
"nameMin": "Pipeline name is required",
"nameMax": "Pipeline name must be no longer than 100 characters",
"nameRegex": "Pipeline name must contain only letters, numbers, and the characters: - _ .",
"noSpaces": "Pipeline name cannot contain spaces"
}
},
"profileSettings": {
"newSshKey": "New SSH key",
"enterNamePlaceholder": "Enter the name",
Expand Down
10 changes: 9 additions & 1 deletion packages/ui/locales/es/views.json
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,14 @@
"description": "La página solicitada no se encontró.",
"button": "Recargar página"
},
"pipelines": {
"createPipelineValidation": {
"nameMin": "El nombre del pipeline es obligatorio",
"nameMax": "El nombre del pipeline no debe superar los 100 caracteres",
"nameRegex": "El nombre del pipeline debe contener solo letras, números y los caracteres: - _ .",
"noSpaces": "El nombre del pipeline no puede contener espacios"
}
},
"profileSettings": {
"newSshKey": "Nueva clave SSH",
"enterNamePlaceholder": "Ingresa el nombre",
Expand Down Expand Up @@ -480,4 +488,4 @@
"secrets": {
"secretsTitle": "Secrets"
}
}
}
10 changes: 9 additions & 1 deletion packages/ui/locales/fr/views.json
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,14 @@
"description": "La page demandée est introuvable.",
"button": "Recharger la page"
},
"pipelines": {
"createPipelineValidation": {
"nameMin": "Le nom du pipeline est requis",
"nameMax": "Le nom du pipeline ne doit pas dépasser 100 caractères",
"nameRegex": "Le nom du pipeline doit contenir uniquement des lettres, des chiffres et les caractères : - _ .",
"noSpaces": "Le nom du pipeline ne peut pas contenir d'espaces"
}
},
"profileSettings": {
"newSshKey": "Nouvelle clé SSH",
"enterNamePlaceholder": "Entrez le nom",
Expand Down Expand Up @@ -485,4 +493,4 @@
"secrets": {
"secretsTitle": "Secrets"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,51 @@ import { useEffect, useState } from 'react'
import { useForm } from 'react-hook-form'

import { Alert, Button, ControlGroup, Dialog, Fieldset, FormWrapper, Input, Select } from '@/components'
import { TranslationStore } from '@/views'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'

import { CreatePipelineDialogProps, CreatePipelineFormType } from './types'
import { ICreatePipelineStore } from './types'

export const makeCreatePipelineSchema = (t: TranslationStore['t']) =>
z.object({
name: z
.string()
.trim()
.min(1, { message: t('views:pipelines.createPipelineValidation.nameMin', 'Pipeline name is required') })
.max(100, {
message: t(
'views:pipelines.createPipelineValidation.nameMax',
'Pipeline name must be no longer than 100 characters'
)
})
.regex(/^[a-zA-Z0-9._-\s]+$/, {
message: t(
'views:pipelines.createPipelineValidation.nameRegex',
'Pipeline name must contain only letters, numbers, and the characters: - _ .'
)
})
.refine(data => !data.includes(' '), {
message: t('views:pipelines.createPipelineValidation.noSpaces', 'Pipeline name cannot contain spaces')
}),
branch: z.string().min(1, { message: 'Branch name is required' }),
yamlPath: z.string().min(1, { message: 'YAML path is required' })
})

export type CreatePipelineFormType = z.infer<ReturnType<typeof makeCreatePipelineSchema>>

const createPipelineSchema = z.object({
name: z.string().min(1, { message: 'Pipeline name is required' }),
branch: z.string().min(1, { message: 'Branch name is required' }),
yamlPath: z.string().min(1, { message: 'YAML path is required' })
})
interface CreatePipelineDialogProps {
useCreatePipelineStore: () => ICreatePipelineStore
isOpen: boolean
onClose: () => void
onCancel: () => void
onSubmit: (formValues: CreatePipelineFormType) => Promise<void>
useTranslationStore: () => TranslationStore
}

export function CreatePipelineDialog(props: CreatePipelineDialogProps) {
const { onCancel, onSubmit, isOpen, onClose, useCreatePipelineStore } = props
const { onCancel, onSubmit, isOpen, onClose, useCreatePipelineStore, useTranslationStore } = props
const { t } = useTranslationStore()

const { isLoadingBranchNames, branchNames, defaultBranch, error } = useCreatePipelineStore()

Expand All @@ -35,7 +67,7 @@ export function CreatePipelineDialog(props: CreatePipelineDialogProps) {
trigger,
formState: { errors, isValid }
} = useForm<CreatePipelineFormType>({
resolver: zodResolver(createPipelineSchema),
resolver: zodResolver(makeCreatePipelineSchema(t)),
mode: 'onChange',
defaultValues: {
name: '',
Expand Down Expand Up @@ -70,14 +102,14 @@ export function CreatePipelineDialog(props: CreatePipelineDialogProps) {
setValue(fieldName, value, { shouldValidate: true })
}

const handleClose = () => {
onCancel()
onClose()
reset()
}

return (
<Dialog.Root
open={isOpen}
onOpenChange={() => {
onClose()
reset()
}}
>
<Dialog.Root open={isOpen} onOpenChange={handleClose}>
<Dialog.Content className="max-w-xl" aria-describedby={undefined}>
<Dialog.Header>
<Dialog.Title>Create Pipeline</Dialog.Title>
Expand Down Expand Up @@ -131,15 +163,7 @@ export function CreatePipelineDialog(props: CreatePipelineDialogProps) {
)}

<Dialog.Footer className="-mx-5 -mb-5">
<Button
type="button"
onClick={() => {
onCancel()
reset()
}}
className="text-primary"
variant="outline"
>
<Button type="button" onClick={handleClose} className="text-primary" variant="outline">
Cancel
</Button>
<Button type="submit" disabled={!isValid || isLoadingBranchNames}>
Expand Down
14 changes: 0 additions & 14 deletions packages/ui/src/views/pipelines/create-pipeline-dialog/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,3 @@ export interface ICreatePipelineStore {
error?: { message: string }
setError: (error?: { message: string }) => void
}

export interface CreatePipelineFormType {
name: string
branch: string
yamlPath: string
}

export interface CreatePipelineDialogProps {
useCreatePipelineStore: () => ICreatePipelineStore
isOpen: boolean
onClose: () => void
onCancel: () => void
onSubmit: (formValues: CreatePipelineFormType) => Promise<void>
}

0 comments on commit 3d8aad9

Please sign in to comment.