Skip to content

Commit 229fcaf

Browse files
fix project import validation
1 parent 09a99d8 commit 229fcaf

File tree

13 files changed

+295
-174
lines changed

13 files changed

+295
-174
lines changed

apps/gitness/src/pages-v2/project/project-import-container.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { ImporterProviderType, ImportSpaceRequestBody, useImportSpaceMutation }
44
import { ImportProjectFormFields, ImportProjectPage, ProviderOptionsEnum } from '@harnessio/ui/views'
55

66
import { useRoutes } from '../../framework/context/NavigationContext'
7+
import { useTranslationStore } from '../../i18n/stores/i18n-store'
78

89
export const ImportProjectContainer = () => {
910
const routes = useRoutes()
@@ -53,6 +54,7 @@ export const ImportProjectContainer = () => {
5354
onFormCancel={onCancel}
5455
isLoading={isLoading}
5556
apiErrorsValue={error?.message?.toString()}
57+
useTranslationStore={useTranslationStore}
5658
/>
5759
)
5860
}

packages/ui/locales/en/views.json

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,38 @@
458458
"generalTab": "General",
459459
"keysTab": "Keys and Tokens"
460460
},
461+
"importProject": {
462+
"validation": {
463+
"nameMax": "Name must be no longer than 100 characters",
464+
"nameRegex": "Organization name must contain only letters, numbers, and the characters: - _ .",
465+
"nameNoSpaces": "Name cannot contain spaces",
466+
"descriptionMax": "Description must be no longer than 1024 characters",
467+
"organizationNameMax": "Organization name must be no longer than 100 characters",
468+
"noSpaces": "Organization name cannot contain spaces",
469+
"hostUrlRequired": "Repository URL is required",
470+
"hostUrlInvalid": "Invalid URL"
471+
},
472+
"title": "Import a project",
473+
"gitProviderPlaceholder": "Select provider",
474+
"gitProviderLabel": "Git provider",
475+
"hostUrlLabel": "Host URL",
476+
"hostUrlPlaceholder": "Enter the host URL",
477+
"tokenLabel": "Token",
478+
"tokenPlaceholder": "Enter your access token",
479+
"organizationLabel": "Organization",
480+
"organizationPLaceholder": "Enter the organization name",
481+
"repositoriesLabel": "Repositories",
482+
"pipelinesLabel": "Import Pipelines",
483+
"projectNameLabel": "Name",
484+
"projectNamePlaceholder": "Enter repository name",
485+
"descriptionLabel": "Description",
486+
"descriptionPlaceholder": "Enter a description",
487+
"importButton": {
488+
"default": "Import project",
489+
"importing": "Importing project..."
490+
},
491+
"cancelButton": "Cancel"
492+
},
461493
"forms": {
462494
"selectMember": "Select member",
463495
"selectRole": "Select role",
@@ -520,4 +552,4 @@
520552
"secrets": {
521553
"secretsTitle": "Secrets"
522554
}
523-
}
555+
}

packages/ui/locales/es/views.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,38 @@
449449
"generalTab": "General",
450450
"keysTab": "Claves y Tokens"
451451
},
452+
"importProject": {
453+
"validation": {
454+
"nameMax": "El nombre no debe superar los 100 caracteres",
455+
"nameRegex": "El nombre de la organización debe contener solo letras, números y los caracteres: - _ .",
456+
"nameNoSpaces": "El nombre no puede contener espacios",
457+
"descriptionMax": "La descripción no debe superar los 1024 caracteres",
458+
"organizationNameMax": "El nombre de la organización no debe superar los 100 caracteres",
459+
"noSpaces": "El nombre de la organización no puede contener espacios",
460+
"hostUrlRequired": "La URL del repositorio es obligatoria",
461+
"hostUrlInvalid": "URL inválida"
462+
},
463+
"title": "Importar un proyecto",
464+
"gitProviderPlaceholder": "Seleccionar proveedor",
465+
"gitProviderLabel": "Proveedor Git",
466+
"hostUrlLabel": "URL de host",
467+
"hostUrlPlaceholder": "Ingrese la URL de host",
468+
"tokenLabel": "Token",
469+
"tokenPlaceholder": "Ingrese su token de acceso",
470+
"organizationLabel": "Organización",
471+
"organizationPlaceholder": "Ingrese el nombre de la organización",
472+
"repositoriesLabel": "Repositorios",
473+
"pipelinesLabel": "Importar pipelines",
474+
"projectNameLabel": "Nombre",
475+
"projectNamePlaceholder": "Ingrese el nombre del repositorio",
476+
"descriptionLabel": "Descripción",
477+
"descriptionPlaceholder": "Ingrese una descripción",
478+
"importButton": {
479+
"default": "Importar proyecto",
480+
"importing": "Importando proyecto..."
481+
},
482+
"cancelButton": "Cancelar"
483+
},
452484
"forms": {
453485
"selectMember": "",
454486
"selectRole": "",

packages/ui/locales/fr/views.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,38 @@
454454
"generalTab": "Général",
455455
"keysTab": "Clés et Jetons"
456456
},
457+
"importProject": {
458+
"validation": {
459+
"nameMax": "Le nom ne doit pas dépasser 100 caractères",
460+
"nameRegex": "Le nom de l'organisation doit contenir uniquement des lettres, des chiffres et les caractères : - _ .",
461+
"nameNoSpaces": "Le nom ne peut pas contenir d'espaces",
462+
"descriptionMax": "La description ne doit pas dépasser 1024 caractères",
463+
"organizationNameMax": "Le nom de l'organisation ne doit pas dépasser 100 caractères",
464+
"noSpaces": "Le nom de l'organisation ne peut pas contenir d'espaces",
465+
"hostUrlRequired": "L'URL du référentiel est requis",
466+
"hostUrlInvalid": "URL invalide"
467+
},
468+
"title": "Importer un projet",
469+
"gitProviderPlaceholder": "Sélectionner un fournisseur",
470+
"gitProviderLabel": "Fournisseur Git",
471+
"hostUrlLabel": "URL d'hôte",
472+
"hostUrlPlaceholder": "Entrer l'URL d'hôte",
473+
"tokenLabel": "Jeton",
474+
"tokenPlaceholder": "Entrer votre jeton d'accès",
475+
"organizationLabel": "Organisation",
476+
"organizationPlaceholder": "Entrer le nom de l'organisation",
477+
"repositoriesLabel": "Référentiels",
478+
"pipelinesLabel": "Importer des pipelines",
479+
"projectNameLabel": "Nom",
480+
"projectNamePlaceholder": "Entrer le nom du référentiel",
481+
"descriptionLabel": "Description",
482+
"descriptionPlaceholder": "Entrer une description",
483+
"importButton": {
484+
"default": "Importer le projet",
485+
"importing": "Importation du projet..."
486+
},
487+
"cancelButton": "Annuler"
488+
},
457489
"forms": {
458490
"selectMember": "",
459491
"selectRole": "",

packages/ui/src/components/button-with-options.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ export const ButtonWithOptions = <T extends string>({
127127
control={<RadioButton className="mt-px" value={String(option.value)} id={String(option.value)} />}
128128
id={String(option.value)}
129129
label={option.label}
130-
ariaSelected={selectedValue === option.value}
130+
aria-selected={selectedValue === option.value}
131131
description={option?.description}
132132
/>
133133
</DropdownMenu.Item>

packages/ui/src/components/form-primitives/fieldset.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,31 @@ import { cn } from '@utils/cn'
55
interface FieldsetProps extends HTMLAttributes<HTMLFieldSetElement> {
66
box?: boolean
77
shaded?: boolean
8+
/**
9+
* For better accessibility, the fieldset should start from the legend element
10+
*/
11+
legend?: string
812
}
913

1014
/**
1115
* A form fieldset component that groups related form elements.
1216
* @example
13-
* <Fieldset box shaded>
17+
* <Fieldset box shaded legend="Some Information">
1418
* <div>Form elements</div>
1519
* </Fieldset>
1620
*/
17-
export function Fieldset({ children, box, shaded, className, ...props }: FieldsetProps) {
21+
export function Fieldset({ children, box, shaded, className, legend, ...props }: FieldsetProps) {
1822
return (
1923
<fieldset
2024
className={cn(
2125
'flex flex-col gap-y-7',
2226
{ 'rounded-md border px-5 py-3.5 pb-5': box, 'bg-primary/[0.02]': shaded },
2327
className
2428
)}
25-
role="group"
26-
aria-describedby="fieldset-description"
2729
{...props}
2830
>
31+
<legend className="sr-only">{legend}</legend>
32+
2933
{children}
3034
</fieldset>
3135
)

packages/ui/src/components/form-primitives/separator.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ interface FormSeparatorProps {
99
/**
1010
* A horizontal separator component for forms
1111
* @example
12-
* // Basic usage
12+
* Basic usage
1313
* <FormSeparator />
1414
*
15-
* // With dashed style
15+
* With dashed style
1616
* <FormSeparator dashed />
1717
*
18-
* // With custom className
18+
* With custom className
1919
* <FormSeparator className="my-4" />
2020
*/
2121
export function FormSeparator({ dashed, dotted, className }: FormSeparatorProps) {

packages/ui/src/components/git-commit-dialog/git-commit-dialog.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ export const GitCommitDialog: FC<GitCommitDialogProps> = ({
185185
branch
186186
</span>
187187
}
188-
ariaSelected={commitToGitRefValue === CommitToGitRefOption.DIRECTLY}
188+
aria-selected={commitToGitRefValue === CommitToGitRefOption.DIRECTLY}
189189
/>
190190
<Option
191191
control={
@@ -197,7 +197,7 @@ export const GitCommitDialog: FC<GitCommitDialogProps> = ({
197197
}
198198
id={CommitToGitRefOption.NEW_BRANCH}
199199
label="Create a new branch for this commit and start a pull request"
200-
ariaSelected={commitToGitRefValue === CommitToGitRefOption.NEW_BRANCH}
200+
aria-selected={commitToGitRefValue === CommitToGitRefOption.NEW_BRANCH}
201201
description={
202202
// TODO: Add correct path
203203
<StyledLink to="/">Learn more about pull requests</StyledLink>

packages/ui/src/components/input.tsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { forwardRef, Fragment, InputHTMLAttributes, ReactNode } from 'react'
1+
import { forwardRef, InputHTMLAttributes, ReactNode } from 'react'
22

33
import { Caption, ControlGroup, Icon, IconProps, Label, Message, MessageTheme } from '@/components'
44
import { cn } from '@utils/cn'
@@ -114,10 +114,6 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
114114
},
115115
ref
116116
) => {
117-
const isControlGroup = !!error || !!caption || !!label || !!wrapperClassName
118-
const InputWrapper = isControlGroup ? ControlGroup : Fragment
119-
const inputWrapperProps = isControlGroup ? { className: wrapperClassName } : {}
120-
121117
const InputComponent = customContent ? BaseInputWithWrapper : BaseInput
122118

123119
const baseInputComp = (
@@ -163,7 +159,7 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
163159
}
164160

165161
return (
166-
<InputWrapper {...inputWrapperProps}>
162+
<ControlGroup className={wrapperClassName}>
167163
{!!label && (
168164
<Label className="mb-2.5" color={disabled ? 'disabled-dark' : 'secondary'} optional={optional} htmlFor={id}>
169165
{label}
@@ -179,7 +175,7 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
179175
)}
180176

181177
{caption && <Caption className={cn({ 'text-foreground-9': disabled })}>{caption}</Caption>}
182-
</InputWrapper>
178+
</ControlGroup>
183179
)
184180
}
185181
)

packages/ui/src/components/option.tsx

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
1-
import { FC, ReactElement, ReactNode } from 'react'
1+
import { FC, HTMLAttributes, ReactElement, ReactNode } from 'react'
22

3-
import { Checkbox, Label, RadioButton, Text } from '@/components'
3+
import { Checkbox, Label, RadioButton } from '@/components'
44
import { cn } from '@utils/cn'
55

66
type ControlType = ReactElement<typeof RadioButton> | ReactElement<typeof Checkbox>
77

8-
interface OptionProps {
8+
interface OptionProps extends HTMLAttributes<HTMLDivElement> {
99
control: ControlType
1010
id: string
1111
label?: string | ReactNode
1212
description?: string | ReactNode
13-
className?: string
14-
ariaSelected?: boolean
13+
disabled?: boolean
1514
}
1615

1716
/**
@@ -24,30 +23,32 @@ interface OptionProps {
2423
* description="Description for Option 1"
2524
* />
2625
*/
27-
export const Option: FC<OptionProps> = ({ control, id, label, description, ariaSelected, className }) => {
26+
export const Option: FC<OptionProps> = ({ control, id, label, description, className, disabled, ...props }) => {
2827
return (
2928
<div
3029
className={cn('flex items-start', className)}
3130
role="option"
3231
aria-labelledby={`${id}-label`}
33-
aria-selected={ariaSelected}
32+
aria-selected={false}
33+
{...props}
3434
>
3535
{control}
3636
<div className="flex flex-col gap-0">
37-
<Label htmlFor={id} className="cursor-pointer pl-2.5 leading-tight">
37+
<Label
38+
htmlFor={id}
39+
className={cn('cursor-pointer pl-2.5 leading-tight', { 'cursor-default': disabled })}
40+
color={disabled ? 'disabled' : 'primary'}
41+
>
3842
{label}
3943
</Label>
4044
{description && (
41-
<Text
42-
className="ml-2.5 mt-1.5 leading-snug tracking-tight"
43-
as="p"
44-
size={2}
45-
color="foreground-4"
45+
<p
46+
className="ml-2.5 mt-1.5 text-sm leading-snug tracking-tight text-foreground-4"
4647
id={`${id}-description`}
4748
role="note"
4849
>
4950
{description}
50-
</Text>
51+
</p>
5152
)}
5253
</div>
5354
</div>

0 commit comments

Comments
 (0)