Skip to content

Commit db7b22b

Browse files
committed
refactor
1 parent 910ff53 commit db7b22b

File tree

4 files changed

+90
-135
lines changed

4 files changed

+90
-135
lines changed

public/locales/en.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,8 @@
270270
"properFormattingLowercase": "Use lowercase a-z, 0-9, hyphen (-), and period (.), but note that whitespace (spaces, tabs, etc.) is not allowed for proper compatibility.",
271271
"max25chars": "Max length is 25 characters.",
272272
"userExists": "User with this email already exists!",
273-
"atLeastOneUser": "You need to have at least one member assigned."
273+
"atLeastOneUser": "You need to have at least one member assigned.",
274+
"notValidChargingTargetFormat": "Use lowercase letters a-f, numbers 0-9, and hyphens (-) in the format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
274275
},
275276
"common": {
276277
"documentation": "Documentation",

src/components/Dialogs/MetadataForm.tsx

Lines changed: 16 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,7 @@
1-
import { FieldErrors, UseFormRegister, UseFormSetValue } from 'react-hook-form';
1+
import { FieldErrors, UseFormGetValues, UseFormRegister, UseFormSetValue } from 'react-hook-form';
22
import { CreateDialogProps } from './CreateWorkspaceDialogContainer.tsx';
33
import { useTranslation } from 'react-i18next';
4-
import {
5-
Form,
6-
FormGroup,
7-
Input,
8-
Label,
9-
Option,
10-
Select,
11-
SelectDomRef,
12-
Ui5CustomEvent,
13-
} from '@ui5/webcomponents-react';
4+
import { Form, FormGroup, Input, Label, Option, Select, SelectDomRef, Ui5CustomEvent } from '@ui5/webcomponents-react';
145
import styles from './CreateProjectWorkspaceDialog.module.css';
156
import React from 'react';
167

@@ -20,6 +11,7 @@ export interface MetadataFormProps {
2011
setValue: UseFormSetValue<CreateDialogProps>;
2112
sideFormContent?: React.ReactNode;
2213
requireChargingTarget?: boolean;
14+
getValues: UseFormGetValues<CreateDialogProps>;
2315
}
2416

2517
interface SelectOption {
@@ -28,31 +20,26 @@ interface SelectOption {
2820
}
2921

3022
export function MetadataForm({
23+
getValues,
3124
register,
3225
errors,
3326
setValue,
3427
sideFormContent,
3528
requireChargingTarget = false,
3629
}: MetadataFormProps) {
3730
const { t } = useTranslation();
38-
const handleChargingTargetTypeChange = (
39-
event: Ui5CustomEvent<SelectDomRef, { selectedOption: HTMLElement }>,
40-
) => {
31+
const handleChargingTargetTypeChange = (event: Ui5CustomEvent<SelectDomRef, { selectedOption: HTMLElement }>) => {
4132
const selectedOption = event.detail.selectedOption as HTMLElement;
4233
setValue('chargingTargetType', selectedOption.dataset.value);
34+
// alert('now');
4335
};
4436
const chargingTypes: SelectOption[] = [
45-
...(!requireChargingTarget
46-
? [{ label: t('common.notSelected'), value: '' }]
47-
: []),
37+
...(!requireChargingTarget ? [{ label: t('common.notSelected'), value: '' }] : []),
4838
{ label: t('common.btp'), value: 'btp' },
4939
];
5040
return (
5141
<Form>
52-
<FormGroup
53-
headerText={t('CreateProjectWorkspaceDialog.metadataHeader')}
54-
columnSpan={12}
55-
>
42+
<FormGroup headerText={t('CreateProjectWorkspaceDialog.metadataHeader')} columnSpan={12}>
5643
<Label for="name" required>
5744
{t('CreateProjectWorkspaceDialog.nameLabel')}
5845
</Label>
@@ -64,35 +51,26 @@ export function MetadataForm({
6451
valueStateMessage={<span>{errors.name?.message}</span>}
6552
required
6653
/>
67-
<Label for={'displayName'}>
68-
{t('CreateProjectWorkspaceDialog.displayNameLabel')}
69-
</Label>
70-
<Input
71-
id="displayName"
72-
{...register('displayName')}
73-
className={styles.input}
74-
/>
75-
<Label for={'chargingTargetType'} required={requireChargingTarget}>
76-
{t('CreateProjectWorkspaceDialog.chargingTargetTypeLabel')}
77-
</Label>
78-
<Select
79-
id={'chargingTargetType'}
80-
className={styles.input}
81-
onChange={handleChargingTargetTypeChange}
82-
>
54+
<Label for={'displayName'}>{t('CreateProjectWorkspaceDialog.displayNameLabel')}</Label>
55+
<Input id="displayName" {...register('displayName')} className={styles.input} />
56+
<Label for={'chargingTargetType'}>{t('CreateProjectWorkspaceDialog.chargingTargetTypeLabel')}</Label>
57+
<Select id={'chargingTargetType'} className={styles.input} onChange={handleChargingTargetTypeChange}>
8358
{chargingTypes.map((option) => (
8459
<Option key={option.value} data-value={option.value}>
8560
{option.label}
8661
</Option>
8762
))}
8863
</Select>
89-
<Label for={'chargingTarget'} required={requireChargingTarget}>
64+
65+
<Label for={'chargingTarget'} required={!!getValues?.('chargingTargetType')}>
9066
{t('CreateProjectWorkspaceDialog.chargingTargetLabel')}
9167
</Label>
9268
<Input
9369
id="chargingTarget"
9470
{...register('chargingTarget')}
9571
className={styles.input}
72+
valueState={errors.chargingTarget ? 'Negative' : 'None'}
73+
valueStateMessage={<span>{errors.chargingTarget?.message}</span>}
9674
/>
9775
</FormGroup>
9876

src/components/Wizards/CreateManagedControlPlane/CreateManagedControlPlaneWizardContainer.tsx

Lines changed: 22 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,7 @@ import {
2121
import { SummarizeStep } from './SummarizeStep.tsx';
2222
import { useTranslation } from 'react-i18next';
2323
import { useAuthOnboarding } from '../../../spaces/onboarding/auth/AuthContextOnboarding.tsx';
24-
import {
25-
ErrorDialog,
26-
ErrorDialogHandle,
27-
} from '../../Shared/ErrorMessageBox.tsx';
24+
import { ErrorDialog, ErrorDialogHandle } from '../../Shared/ErrorMessageBox.tsx';
2825
import { CreateDialogProps } from '../../Dialogs/CreateWorkspaceDialogContainer.tsx';
2926
import { validationSchemaCreateManagedControlPlane } from '../../../lib/api/validations/schemas.ts';
3027
import { Member, MemberRoles } from '../../../lib/api/types/shared/members.ts';
@@ -50,24 +47,16 @@ type CreateManagedControlPlaneWizardContainerProps = {
5047
workspaceName?: string;
5148
};
5249

53-
type WizardStepType =
54-
| 'metadata'
55-
| 'members'
56-
| 'componentSelection'
57-
| 'summarize'
58-
| 'success';
50+
type WizardStepType = 'metadata' | 'members' | 'componentSelection' | 'summarize' | 'success';
5951

60-
const wizardStepOrder: WizardStepType[] = [
61-
'metadata',
62-
'members',
63-
'componentSelection',
64-
'summarize',
65-
'success',
66-
];
52+
const wizardStepOrder: WizardStepType[] = ['metadata', 'members', 'componentSelection', 'summarize', 'success'];
6753

68-
export const CreateManagedControlPlaneWizardContainer: FC<
69-
CreateManagedControlPlaneWizardContainerProps
70-
> = ({ isOpen, setIsOpen, projectName = '', workspaceName = '' }) => {
54+
export const CreateManagedControlPlaneWizardContainer: FC<CreateManagedControlPlaneWizardContainerProps> = ({
55+
isOpen,
56+
setIsOpen,
57+
projectName = '',
58+
workspaceName = '',
59+
}) => {
7160
const { t } = useTranslation();
7261
const { user } = useAuthOnboarding();
7362
const errorDialogRef = useRef<ErrorDialogHandle>(null);
@@ -122,9 +111,7 @@ export const CreateManagedControlPlaneWizardContainer: FC<
122111

123112
useEffect(() => {
124113
if (user?.email && isOpen) {
125-
setValue('members', [
126-
{ name: user.email, roles: [MemberRoles.admin], kind: 'User' },
127-
]);
114+
setValue('members', [{ name: user.email, roles: [MemberRoles.admin], kind: 'User' }]);
128115
}
129116
if (!isOpen) {
130117
clearFormFields();
@@ -137,12 +124,7 @@ export const CreateManagedControlPlaneWizardContainer: FC<
137124
const componentsList = watch('componentsList');
138125

139126
const handleCreateManagedControlPlane = useCallback(
140-
async ({
141-
name,
142-
displayName,
143-
chargingTarget,
144-
members,
145-
}: OnCreatePayload): Promise<boolean> => {
127+
async ({ name, displayName, chargingTarget, members }: OnCreatePayload): Promise<boolean> => {
146128
try {
147129
await trigger(
148130
CreateManagedControlPlane(
@@ -161,9 +143,7 @@ export const CreateManagedControlPlaneWizardContainer: FC<
161143
return true;
162144
} catch (e) {
163145
if (e instanceof APIError && errorDialogRef.current) {
164-
errorDialogRef.current.showErrorDialog(
165-
`${e.message}: ${JSON.stringify(e.info)}`,
166-
);
146+
errorDialogRef.current.showErrorDialog(`${e.message}: ${JSON.stringify(e.info)}`);
167147
} else {
168148
console.error(e);
169149
}
@@ -173,13 +153,10 @@ export const CreateManagedControlPlaneWizardContainer: FC<
173153
[trigger, projectName, workspaceName, componentsList],
174154
);
175155

176-
const handleStepChange = useCallback(
177-
(e: Ui5CustomEvent<WizardDomRef, WizardStepChangeEventDetail>) => {
178-
const step = (e.detail.step.dataset.step ?? '') as WizardStepType;
179-
setSelectedStep(step);
180-
},
181-
[],
182-
);
156+
const handleStepChange = useCallback((e: Ui5CustomEvent<WizardDomRef, WizardStepChangeEventDetail>) => {
157+
const step = (e.detail.step.dataset.step ?? '') as WizardStepType;
158+
setSelectedStep(step);
159+
}, []);
183160

184161
const onNextClick = useCallback(() => {
185162
switch (selectedStep) {
@@ -201,14 +178,7 @@ export const CreateManagedControlPlaneWizardContainer: FC<
201178
default:
202179
break;
203180
}
204-
}, [
205-
selectedStep,
206-
handleSubmit,
207-
setSelectedStep,
208-
handleCreateManagedControlPlane,
209-
getValues,
210-
resetFormAndClose,
211-
]);
181+
}, [selectedStep, handleSubmit, setSelectedStep, handleCreateManagedControlPlane, getValues, resetFormAndClose]);
212182

213183
const setMembers = useCallback(
214184
(members: Member[]) => {
@@ -232,11 +202,7 @@ export const CreateManagedControlPlaneWizardContainer: FC<
232202
case 'members':
233203
return selectedStep === 'metadata' || !isValid;
234204
case 'componentSelection':
235-
return (
236-
selectedStep === 'metadata' ||
237-
selectedStep === 'members' ||
238-
!isValid
239-
);
205+
return selectedStep === 'metadata' || selectedStep === 'members' || !isValid;
240206
case 'summarize':
241207
return (
242208
selectedStep === 'metadata' ||
@@ -276,9 +242,7 @@ export const CreateManagedControlPlaneWizardContainer: FC<
276242
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
277243
{selectedStep !== 'success' &&
278244
(selectedStep === 'metadata' ? (
279-
<Button onClick={resetFormAndClose}>
280-
{t('buttons.close')}
281-
</Button>
245+
<Button onClick={resetFormAndClose}>{t('buttons.close')}</Button>
282246
) : (
283247
<Button onClick={onBackClick}>{t('buttons.back')}</Button>
284248
))}
@@ -301,11 +265,7 @@ export const CreateManagedControlPlaneWizardContainer: FC<
301265
selected={selectedStep === 'metadata'}
302266
data-step="metadata"
303267
>
304-
<MetadataForm
305-
setValue={setValue}
306-
register={register}
307-
errors={errors}
308-
/>
268+
<MetadataForm getValues={getValues} setValue={setValue} register={register} errors={errors} />
309269
</WizardStep>
310270
<WizardStep
311271
icon="user-edit"
@@ -315,9 +275,7 @@ export const CreateManagedControlPlaneWizardContainer: FC<
315275
disabled={isStepDisabled('members')}
316276
>
317277
<Form>
318-
<FormGroup
319-
headerText={t('CreateProjectWorkspaceDialog.membersHeader')}
320-
>
278+
<FormGroup headerText={t('CreateProjectWorkspaceDialog.membersHeader')}>
321279
<EditMembers
322280
members={watch('members')}
323281
isValidationError={!!errors.members}
@@ -334,10 +292,7 @@ export const CreateManagedControlPlaneWizardContainer: FC<
334292
data-step="componentSelection"
335293
disabled={isStepDisabled('componentSelection')}
336294
>
337-
<ComponentsSelectionContainer
338-
componentsList={componentsList ?? []}
339-
setComponentsList={setComponentsList}
340-
/>
295+
<ComponentsSelectionContainer componentsList={componentsList ?? []} setComponentsList={setComponentsList} />
341296
</WizardStep>
342297
<WizardStep
343298
icon="activities"

src/lib/api/validations/schemas.ts

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,58 @@
11
import { z } from 'zod';
22
import { Member } from '../types/shared/members.ts';
33
import i18n from '../../../../i18n.ts';
4-
import {
5-
managedControlPlaneNameRegex,
6-
projectWorkspaceNameRegex,
7-
} from './regex.ts';
4+
import { btpChargingTargetRegex, managedControlPlaneNameRegex, projectWorkspaceNameRegex } from './regex.ts';
85

96
const { t } = i18n;
107

118
const member = z.custom<Member>();
129

13-
export const validationSchemaProjectWorkspace = z.object({
14-
name: z
15-
.string()
16-
.min(1, t('validationErrors.required'))
17-
.regex(projectWorkspaceNameRegex, t('validationErrors.properFormatting'))
18-
.max(25, t('validationErrors.max25chars')),
19-
displayName: z.string().optional(),
20-
chargingTarget: z.string().optional(),
21-
chargingTargetType: z.string().optional(),
22-
members: z.array(member).refine((members) => members?.length > 0),
23-
});
24-
export const validationSchemaCreateManagedControlPlane = z.object({
25-
name: z
26-
.string()
27-
.min(1, t('validationErrors.required'))
28-
.regex(
29-
managedControlPlaneNameRegex,
30-
t('validationErrors.properFormattingLowercase'),
31-
)
32-
.max(25, t('validationErrors.max25chars')),
33-
displayName: z.string().optional(),
34-
chargingTarget: z.string().optional(),
35-
chargingTargetType: z.string().optional(),
36-
members: z.array(member),
37-
});
10+
export const validationSchemaProjectWorkspace = z
11+
.object({
12+
name: z
13+
.string()
14+
.min(1, t('validationErrors.required'))
15+
.regex(projectWorkspaceNameRegex, t('validationErrors.properFormatting'))
16+
.max(25, t('validationErrors.max25chars')),
17+
displayName: z.string().optional(),
18+
chargingTarget: z.string(),
19+
chargingTargetType: z.string().optional(),
20+
members: z.array(member).refine((members) => members?.length > 0),
21+
})
22+
.superRefine((data, ctx) => {
23+
if (data.chargingTargetType && !data.chargingTarget) {
24+
ctx.addIssue({
25+
path: ['chargingTarget'],
26+
code: z.ZodIssueCode.custom,
27+
message: t('validationErrors.required'),
28+
});
29+
}
30+
});
31+
32+
export const validationSchemaCreateManagedControlPlane = z
33+
.object({
34+
name: z
35+
.string()
36+
.min(1, t('validationErrors.required'))
37+
.regex(managedControlPlaneNameRegex, t('validationErrors.properFormattingLowercase'))
38+
.max(25, t('validationErrors.max25chars')),
39+
displayName: z.string().optional(),
40+
chargingTarget: z.string().optional(),
41+
chargingTargetType: z.string().optional(),
42+
members: z.array(member),
43+
})
44+
.superRefine((data, ctx) => {
45+
if (data.chargingTargetType && data.chargingTarget && !btpChargingTargetRegex.test(data.chargingTarget ?? '')) {
46+
ctx.addIssue({
47+
path: ['chargingTarget'],
48+
code: z.ZodIssueCode.custom,
49+
message: t('validationErrors.notValidChargingTargetFormat'),
50+
});
51+
} else if (data.chargingTargetType && !data.chargingTarget) {
52+
ctx.addIssue({
53+
path: ['chargingTarget'],
54+
code: z.ZodIssueCode.custom,
55+
message: t('validationErrors.required'),
56+
});
57+
}
58+
});

0 commit comments

Comments
 (0)