Wizard güncellemesi

This commit is contained in:
Sedat ÖZTÜRK 2026-02-27 09:54:25 +03:00
parent 4099ef9079
commit 877d0e7397
2 changed files with 422 additions and 371 deletions

View file

@ -879,21 +879,11 @@
"RequiredPermissionName": "App.Contact",
"IsDisabled": false
},
{
"ParentCode": "App.Administration",
"Code": "App.Listforms.Wizard",
"DisplayName": "App.Listforms.Wizard",
"Order": 5,
"Url": "/admin/listform/wizard",
"Icon": "FcFlashAuto",
"RequiredPermissionName": "App.Listforms.Wizard",
"IsDisabled": false
},
{
"ParentCode": "App.Administration",
"Code": "App.Routes",
"DisplayName": "App.Routes",
"Order": 6,
"Order": 5,
"Url": "/admin/list/App.Routes",
"Icon": "FaSynagogue",
"RequiredPermissionName": "App.Routes",
@ -903,7 +893,7 @@
"ParentCode": "App.Administration",
"Code": "App.Menus",
"DisplayName": "App.Menus",
"Order": 7,
"Order": 6,
"Url": null,
"Icon": "FaSchlix",
"RequiredPermissionName": null,
@ -933,7 +923,7 @@
"ParentCode": "App.Administration",
"Code": "App.Files",
"DisplayName": "App.Files",
"Order": 8,
"Order": 7,
"Url": "/admin/files",
"Icon": "FcFolder",
"RequiredPermissionName": "App.Files",
@ -943,7 +933,7 @@
"ParentCode": "App.Administration",
"Code": "App.Reports.Management",
"DisplayName": "App.Reports.Management",
"Order": 9,
"Order": 8,
"Url": null,
"Icon": "FcDocument",
"RequiredPermissionName": null,
@ -973,7 +963,7 @@
"ParentCode": "App.Administration",
"Code": "App.DeveloperKit",
"DisplayName": "App.DeveloperKit",
"Order": 10,
"Order": 9,
"Url": null,
"Icon": "FcAndroidOs",
"RequiredPermissionName": null,
@ -1059,6 +1049,16 @@
"RequiredPermissionName": "App.SqlQueryManager",
"IsDisabled": false
},
{
"ParentCode": "App.Administration",
"Code": "App.Listforms.Wizard",
"DisplayName": "App.Listforms.Wizard",
"Order": 10,
"Url": "/admin/listform/wizard",
"Icon": "FcFlashAuto",
"RequiredPermissionName": "App.Listforms.Wizard",
"IsDisabled": false
},
{
"ParentCode": "App.Administration",
"Code": "App.Forum",

View file

@ -6,14 +6,15 @@ import {
Input,
Notification,
Select,
Steps,
toast,
} from '@/components/ui'
import { ROUTES_ENUM } from '@/routes/route.constant'
import { ListFormWizardDto } from '@/proxy/admin/list-form/models'
import { SelectBoxOption } from '@/types/shared'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { Field, FieldProps, Form, Formik } from 'formik'
import { useEffect, useState } from 'react'
import { Field, FieldProps, Form, Formik, FormikProps } from 'formik'
import { useEffect, useRef, useState } from 'react'
import { Helmet } from 'react-helmet'
import { useNavigate } from 'react-router-dom'
import CreatableSelect from 'react-select/creatable'
@ -47,19 +48,22 @@ const initialValues: ListFormWizardDto = {
keyFieldDbSourceType: DbTypeEnum.Int32, // Select: Enum dbSourceTypeOptions
}
const listFormValidationSchema = Yup.object().shape({
const step1ValidationSchema = Yup.object().shape({
listFormCode: Yup.string().required(),
permissionGroupName: Yup.string().required(),
menuParentCode: Yup.string().required(),
menuIcon: Yup.string(),
languageTextMenuEn: Yup.string(),
languageTextMenuTr: Yup.string(),
languageTextMenuParentEn: Yup.string(),
languageTextMenuParentTr: Yup.string(),
})
const step2ValidationSchema = Yup.object().shape({
languageTextTitleEn: Yup.string(),
languageTextTitleTr: Yup.string(),
languageTextDescEn: Yup.string(),
languageTextDescTr: Yup.string(),
languageTextMenuParentEn: Yup.string(),
languageTextMenuParentTr: Yup.string(),
permissionGroupName: Yup.string().required(),
menuParentCode: Yup.string().required(),
menuIcon: Yup.string(),
dataSourceCode: Yup.string(),
dataSourceConnectionString: Yup.string(),
selectCommandType: Yup.string().required(),
@ -68,8 +72,12 @@ const listFormValidationSchema = Yup.object().shape({
keyFieldDbSourceType: Yup.string().required(),
})
const listFormValidationSchema = step1ValidationSchema.concat(step2ValidationSchema)
const Wizard = () => {
const { translate } = useLocalization()
const [currentStep, setCurrentStep] = useState(0)
const [isLoadingDataSource, setIsLoadingDataSource] = useState(false)
const [dataSourceList, setDataSourceList] = useState<SelectBoxOption[]>([])
const [isDataSourceNew, setIsDataSourceNew] = useState(false)
@ -106,7 +114,6 @@ const Wizard = () => {
const [isLoadingPermissionGroup, setIsLoadingPermissionGroup] = useState(false)
const [permissionGroupList, setPermissionGroupList] = useState<SelectBoxOption[]>([])
const [isPermissionGroupNew, setIsPermissionGroupNew] = useState(false)
const getPermissionGroupList = async () => {
setIsLoadingPermissionGroup(true)
const response = await getPermissions('R', '')
@ -128,6 +135,27 @@ const Wizard = () => {
}, [])
const navigate = useNavigate()
const formikRef = useRef<FormikProps<ListFormWizardDto>>(null)
const handleNext = async () => {
if (!formikRef.current) return
const errors = await formikRef.current.validateForm()
const step1Fields = Object.keys(step1ValidationSchema.fields)
const hasStep1Errors = step1Fields.some((f) => errors[f as keyof ListFormWizardDto])
// Touch all step 1 fields so errors appear
const touchedStep1 = step1Fields.reduce(
(acc, key) => ({ ...acc, [key]: true }),
{} as Record<string, boolean>,
)
formikRef.current.setTouched({ ...formikRef.current.touched, ...touchedStep1 })
if (!hasStep1Errors) {
setCurrentStep(1)
}
}
const handleBack = () => {
setCurrentStep(0)
}
return (
<Container>
@ -137,8 +165,16 @@ const Wizard = () => {
defaultTitle={APP_NAME}
></Helmet>
<div className="mb-8">
<Steps current={currentStep}>
<Steps.Item title={translate('::ListForms.Wizard.BasicInfo') || 'Basic Info'} />
<Steps.Item title={translate('::ListForms.Wizard.DataSettings') || 'Data Settings'} />
</Steps>
</div>
<div className="grid lg:grid-cols-2 xl:grid-cols-3">
<Formik
innerRef={formikRef}
initialValues={{ ...initialValues }}
validationSchema={listFormValidationSchema}
onSubmit={async (values, { setSubmitting }) => {
@ -172,369 +208,384 @@ const Wizard = () => {
{({ touched, errors, isSubmitting, values }) => (
<Form>
<FormContainer size="sm">
<FormItem
label="ListForm Code"
invalid={errors.listFormCode && touched.listFormCode}
errorMessage={errors.listFormCode}
asterisk={true}
>
<Field
type="text"
autoComplete="off"
name="listFormCode"
placeholder="ListForm Code"
component={Input}
/>
</FormItem>
<FormItem
label="Permission Group Name"
invalid={errors.permissionGroupName && touched.permissionGroupName}
errorMessage={errors.permissionGroupName}
asterisk={true}
>
<Field type="text" autoComplete="off" name="permissionGroupName">
{({ field, form }: FieldProps<string>) => (
<Select
componentAs={CreatableSelect}
field={field}
form={form}
placeholder="Permission Group Name"
isClearable={true}
isLoading={isLoadingPermissionGroup}
options={permissionGroupList}
value={
values.permissionGroupName
? (menuList?.find((o) => o.value === values.permissionGroupName) ?? {
label: values.permissionGroupName,
value: values.permissionGroupName,
})
: null
}
onChange={(option) => {
form.setFieldValue(field.name, option?.value)
setIsPermissionGroupNew(
!!option?.value && !menuList.some((a) => a.value === option?.value),
)
}}
/>
)}
</Field>
</FormItem>
<div className="grid grid-cols-2 gap-1">
<FormItem
label="Menu Parent Code"
invalid={errors.menuParentCode && touched.menuParentCode}
errorMessage={errors.menuParentCode}
asterisk={true}
>
<Field type="text" autoComplete="off" name="menuParentCode">
{({ field, form }: FieldProps<string>) => (
<Select
componentAs={CreatableSelect}
field={field}
form={form}
placeholder="Menu Parent Code"
isClearable={true}
isLoading={isLoadingMenu}
options={menuList}
value={
values.menuParentCode
? (menuList?.find((o) => o.value === values.menuParentCode) ?? {
label: values.menuParentCode,
value: values.menuParentCode,
})
: null
}
onChange={(option) => {
form.setFieldValue(field.name, option?.value)
setIsMenuNew(
!!option?.value && !menuList.some((a) => a.value === option?.value),
)
}}
/>
)}
</Field>
</FormItem>
<FormItem
label="Menu Icon"
invalid={errors.menuIcon && touched.menuIcon}
errorMessage={errors.menuIcon}
asterisk={true}
>
<Field
type="text"
autoComplete="off"
name="menuIcon"
placeholder="Menu Icon"
component={Input}
/>
</FormItem>
</div>
{isMenuNew && (
<div className="grid grid-cols-2 gap-1">
{/* ─── Step 1: Basic Info ─────────────────────────────── */}
{currentStep === 0 && (
<>
<FormItem
label="Parent Menu Code (En)"
invalid={errors.languageTextMenuParentEn && touched.languageTextMenuParentEn}
errorMessage={errors.languageTextMenuParentEn}
label="ListForm Code"
invalid={errors.listFormCode && touched.listFormCode}
errorMessage={errors.listFormCode}
asterisk={true}
>
<Field
type="text"
autoComplete="off"
name="languageTextMenuParentEn"
placeholder="Parent Menu Code (En)"
name="listFormCode"
placeholder="ListForm Code"
component={Input}
/>
</FormItem>
<FormItem
label="Parent Menu Code (Tr)"
invalid={errors.languageTextMenuParentTr && touched.languageTextMenuParentTr}
errorMessage={errors.languageTextMenuParentTr}
label="Permission Group Name"
invalid={errors.permissionGroupName && touched.permissionGroupName}
errorMessage={errors.permissionGroupName}
asterisk={true}
>
<Field
type="text"
autoComplete="off"
name="languageTextMenuParentTr"
placeholder="Parent Menu Code (Tr)"
component={Input}
/>
<Field type="text" autoComplete="off" name="permissionGroupName">
{({ field, form }: FieldProps<string>) => (
<Select
componentAs={CreatableSelect}
field={field}
form={form}
placeholder="Permission Group Name"
isClearable={true}
isLoading={isLoadingPermissionGroup}
options={permissionGroupList}
value={
values.permissionGroupName
? (permissionGroupList?.find(
(o) => o.value === values.permissionGroupName,
) ?? {
label: values.permissionGroupName,
value: values.permissionGroupName,
})
: null
}
onChange={(option) => {
form.setFieldValue(field.name, option?.value)
}}
/>
)}
</Field>
</FormItem>
</div>
)}
<div className="grid grid-cols-2 gap-1">
<FormItem
label="Data Source Code"
invalid={errors.dataSourceCode && touched.dataSourceCode}
errorMessage={errors.dataSourceCode}
>
<Field
type="text"
autoComplete="off"
name="dataSourceCode"
placeholder="Data Source Code"
>
{({ field, form }: FieldProps<string>) => (
<Select
componentAs={CreatableSelect}
field={field}
form={form}
placeholder="Data Source Code"
isClearable={true}
isLoading={isLoadingDataSource}
options={dataSourceList}
value={
values.dataSourceCode
? (dataSourceList?.find((o) => o.value === values.dataSourceCode) ?? {
label: values.dataSourceCode,
value: values.dataSourceCode,
})
: null
}
onChange={(option) => {
form.setFieldValue(field.name, option?.value)
setIsDataSourceNew(
!!option?.value &&
!dataSourceList.some((a) => a.value === option?.value),
)
}}
/>
)}
</Field>
</FormItem>
{isDataSourceNew && (
<FormItem
label="Connection String"
invalid={
errors.dataSourceConnectionString && touched.dataSourceConnectionString
}
errorMessage={errors.dataSourceConnectionString}
>
<Field
type="text"
autoComplete="off"
name="dataSourceConnectionString"
placeholder="Connection String"
component={Input}
/>
</FormItem>
)}
</div>
<div className="grid grid-cols-2 gap-1">
<FormItem
label="Select Command Type"
invalid={errors.selectCommandType && touched.selectCommandType}
errorMessage={errors.selectCommandType}
asterisk={true}
>
<Field
type="text"
autoComplete="off"
name="selectCommandType"
placeholder="Select Command Type"
component={Input}
>
{({ field, form }: FieldProps<SelectCommandTypeEnum>) => (
<Select
field={field}
form={form}
options={selectCommandTypeOptions}
value={selectCommandTypeOptions.find((o: any) => o.value === field.value)}
onChange={(o) => form.setFieldValue(field.name, o?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label="Select Command"
invalid={errors.selectCommand && touched.selectCommand}
errorMessage={errors.selectCommand}
asterisk={true}
>
<Field
type="text"
autoComplete="off"
name="selectCommand"
placeholder="Select Command"
component={Input}
/>
</FormItem>
</div>
<div className="grid grid-cols-2 gap-1">
<FormItem
label="Key Field Name"
invalid={errors.keyFieldName && touched.keyFieldName}
errorMessage={errors.keyFieldName}
asterisk={true}
>
<Field
type="text"
autoComplete="off"
name="keyFieldName"
placeholder="Key Field Name"
component={Input}
/>
</FormItem>
<FormItem
label="Key Field Db Source Type"
invalid={errors.keyFieldDbSourceType && touched.keyFieldDbSourceType}
errorMessage={errors.keyFieldDbSourceType}
asterisk={true}
>
<Field
type="text"
autoComplete="off"
name="keyFieldDbSourceType"
placeholder="Key Field Db Source Type"
component={Input}
>
{({ field, form }: FieldProps<DbTypeEnum>) => (
<Select
field={field}
form={form}
options={dbSourceTypeOptions}
value={dbSourceTypeOptions?.filter(
(o: any) => o.value === values.keyFieldDbSourceType,
<div className="grid grid-cols-2 gap-1">
<FormItem
label="Menu Parent Code"
invalid={errors.menuParentCode && touched.menuParentCode}
errorMessage={errors.menuParentCode}
asterisk={true}
>
<Field type="text" autoComplete="off" name="menuParentCode">
{({ field, form }: FieldProps<string>) => (
<Select
componentAs={CreatableSelect}
field={field}
form={form}
placeholder="Menu Parent Code"
isClearable={true}
isLoading={isLoadingMenu}
options={menuList}
value={
values.menuParentCode
? (menuList?.find((o) => o.value === values.menuParentCode) ?? {
label: values.menuParentCode,
value: values.menuParentCode,
})
: null
}
onChange={(option) => {
form.setFieldValue(field.name, option?.value)
setIsMenuNew(
!!option?.value &&
!menuList.some((a) => a.value === option?.value),
)
}}
/>
)}
onChange={(o) => form.setFieldValue(field.name, o?.value)}
</Field>
</FormItem>
<FormItem
label="Menu Icon"
invalid={errors.menuIcon && touched.menuIcon}
errorMessage={errors.menuIcon}
>
<Field
type="text"
autoComplete="off"
name="menuIcon"
placeholder="Menu Icon"
component={Input}
/>
</FormItem>
</div>
{isMenuNew && (
<div className="grid grid-cols-2 gap-1">
<FormItem
label="Parent Menu Text (En)"
invalid={
errors.languageTextMenuParentEn && touched.languageTextMenuParentEn
}
errorMessage={errors.languageTextMenuParentEn}
>
<Field
type="text"
autoComplete="off"
name="languageTextMenuParentEn"
placeholder="Parent Menu Text (En)"
component={Input}
/>
</FormItem>
<FormItem
label="Parent Menu Text (Tr)"
invalid={
errors.languageTextMenuParentTr && touched.languageTextMenuParentTr
}
errorMessage={errors.languageTextMenuParentTr}
>
<Field
type="text"
autoComplete="off"
name="languageTextMenuParentTr"
placeholder="Parent Menu Text (Tr)"
component={Input}
/>
</FormItem>
</div>
)}
<div className="grid grid-cols-2 gap-1">
<FormItem
label="Menu Text (En)"
invalid={errors.languageTextMenuEn && touched.languageTextMenuEn}
errorMessage={errors.languageTextMenuEn}
>
<Field
type="text"
autoComplete="off"
name="languageTextMenuEn"
placeholder="Menu Text (En)"
component={Input}
/>
</FormItem>
<FormItem
label="Menu Text (Tr)"
invalid={errors.languageTextMenuTr && touched.languageTextMenuTr}
errorMessage={errors.languageTextMenuTr}
>
<Field
type="text"
autoComplete="off"
name="languageTextMenuTr"
placeholder="Menu Text (Tr)"
component={Input}
/>
</FormItem>
</div>
<Button block className="mt-4" variant="solid" type="button" onClick={handleNext}>
{translate('::Next') || 'Next'}
</Button>
</>
)}
{/* ─── Step 2: Data Settings ───────────────────────────── */}
{currentStep === 1 && (
<>
<div className="grid grid-cols-2 gap-1">
<FormItem
label="Title (En)"
invalid={errors.languageTextTitleEn && touched.languageTextTitleEn}
errorMessage={errors.languageTextTitleEn}
>
<Field
type="text"
autoComplete="off"
name="languageTextTitleEn"
placeholder="Title (En)"
component={Input}
/>
</FormItem>
<FormItem
label="Title (Tr)"
invalid={errors.languageTextTitleTr && touched.languageTextTitleTr}
errorMessage={errors.languageTextTitleTr}
>
<Field
type="text"
autoComplete="off"
name="languageTextTitleTr"
placeholder="Title (Tr)"
component={Input}
/>
</FormItem>
</div>
<div className="grid grid-cols-2 gap-1">
<FormItem
label="Description (En)"
invalid={errors.languageTextDescEn && touched.languageTextDescEn}
errorMessage={errors.languageTextDescEn}
>
<Field
type="text"
autoComplete="off"
name="languageTextDescEn"
placeholder="Description (En)"
component={Input}
/>
</FormItem>
<FormItem
label="Description (Tr)"
invalid={errors.languageTextDescTr && touched.languageTextDescTr}
errorMessage={errors.languageTextDescTr}
>
<Field
type="text"
autoComplete="off"
name="languageTextDescTr"
placeholder="Description (Tr)"
component={Input}
/>
</FormItem>
</div>
<div className="grid grid-cols-2 gap-1">
<FormItem
label="Data Source Code"
invalid={errors.dataSourceCode && touched.dataSourceCode}
errorMessage={errors.dataSourceCode}
>
<Field type="text" autoComplete="off" name="dataSourceCode">
{({ field, form }: FieldProps<string>) => (
<Select
componentAs={CreatableSelect}
field={field}
form={form}
placeholder="Data Source Code"
isClearable={true}
isLoading={isLoadingDataSource}
options={dataSourceList}
value={
values.dataSourceCode
? (dataSourceList?.find(
(o) => o.value === values.dataSourceCode,
) ?? {
label: values.dataSourceCode,
value: values.dataSourceCode,
})
: null
}
onChange={(option) => {
form.setFieldValue(field.name, option?.value)
setIsDataSourceNew(
!!option?.value &&
!dataSourceList.some((a) => a.value === option?.value),
)
}}
/>
)}
</Field>
</FormItem>
{isDataSourceNew && (
<FormItem
label="Connection String"
invalid={
errors.dataSourceConnectionString && touched.dataSourceConnectionString
}
errorMessage={errors.dataSourceConnectionString}
>
<Field
type="text"
autoComplete="off"
name="dataSourceConnectionString"
placeholder="Connection String"
component={Input}
/>
</FormItem>
)}
</Field>
</FormItem>
</div>
<div className="grid grid-cols-2 gap-1">
<FormItem
label="Menu Text (En)"
invalid={errors.languageTextMenuEn && touched.languageTextMenuEn}
errorMessage={errors.languageTextMenuEn}
asterisk={true}
>
<Field
type="text"
autoComplete="off"
name="languageTextMenuEn"
placeholder="Menu Text (En)"
component={Input}
/>
</FormItem>
<FormItem
label="Menu Text (Tr)"
invalid={errors.languageTextMenuTr && touched.languageTextMenuTr}
errorMessage={errors.languageTextMenuTr}
asterisk={true}
>
<Field
type="text"
autoComplete="off"
name="languageTextMenuTr"
placeholder="Menu Text (Tr)"
component={Input}
/>
</FormItem>
</div>
<div className="grid grid-cols-2 gap-1">
<FormItem
label="Title (En)"
invalid={errors.languageTextTitleEn && touched.languageTextTitleEn}
errorMessage={errors.languageTextTitleEn}
asterisk={true}
>
<Field
type="text"
autoComplete="off"
name="languageTextTitleEn"
placeholder="Title (En)"
component={Input}
/>
</FormItem>
<FormItem
label="Title (Tr)"
invalid={errors.languageTextTitleTr && touched.languageTextTitleTr}
errorMessage={errors.languageTextTitleTr}
asterisk={true}
>
<Field
type="text"
autoComplete="off"
name="languageTextTitleTr"
placeholder="Title (Tr)"
component={Input}
/>
</FormItem>
</div>
<div className="grid grid-cols-2 gap-1">
<FormItem
label="Description (En)"
invalid={errors.languageTextDescEn && touched.languageTextDescEn}
errorMessage={errors.languageTextDescEn}
asterisk={true}
>
<Field
type="text"
autoComplete="off"
name="languageTextDescEn"
placeholder="Description (En)"
component={Input}
/>
</FormItem>
<FormItem
label="Description (Tr)"
invalid={errors.languageTextDescTr && touched.languageTextDescTr}
errorMessage={errors.languageTextDescTr}
asterisk={true}
>
<Field
type="text"
autoComplete="off"
name="languageTextDescTr"
placeholder="Description (Tr)"
component={Input}
/>
</FormItem>
</div>
<Button block className="mt-4" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::SavingWithThreeDot') : translate('::Save')}
</Button>
</div>
<div className="grid grid-cols-2 gap-1">
<FormItem
label="Select Command Type"
invalid={errors.selectCommandType && touched.selectCommandType}
errorMessage={errors.selectCommandType}
asterisk={true}
>
<Field type="text" autoComplete="off" name="selectCommandType">
{({ field, form }: FieldProps<SelectCommandTypeEnum>) => (
<Select
field={field}
form={form}
options={selectCommandTypeOptions}
value={selectCommandTypeOptions.find(
(o: any) => o.value === field.value,
)}
onChange={(o) => form.setFieldValue(field.name, o?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label="Select Command"
invalid={errors.selectCommand && touched.selectCommand}
errorMessage={errors.selectCommand}
asterisk={true}
>
<Field
type="text"
autoComplete="off"
name="selectCommand"
placeholder="Select Command"
component={Input}
/>
</FormItem>
</div>
<div className="grid grid-cols-2 gap-1">
<FormItem
label="Key Field Name"
invalid={errors.keyFieldName && touched.keyFieldName}
errorMessage={errors.keyFieldName}
asterisk={true}
>
<Field
type="text"
autoComplete="off"
name="keyFieldName"
placeholder="Key Field Name"
component={Input}
/>
</FormItem>
<FormItem
label="Key Field Db Source Type"
invalid={errors.keyFieldDbSourceType && touched.keyFieldDbSourceType}
errorMessage={errors.keyFieldDbSourceType}
asterisk={true}
>
<Field type="text" autoComplete="off" name="keyFieldDbSourceType">
{({ field, form }: FieldProps<DbTypeEnum>) => (
<Select
field={field}
form={form}
options={dbSourceTypeOptions}
value={dbSourceTypeOptions?.filter(
(o: any) => o.value === values.keyFieldDbSourceType,
)}
onChange={(o) => form.setFieldValue(field.name, o?.value)}
/>
)}
</Field>
</FormItem>
</div>
<div className="flex gap-2 mt-4">
<Button block variant="default" type="button" onClick={handleBack}>
{translate('::Back') || 'Back'}
</Button>
<Button block variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::SavingWithThreeDot') : translate('::Save')}
</Button>
</div>
</>
)}
</FormContainer>
</Form>
)}