423 lines
13 KiB
TypeScript
423 lines
13 KiB
TypeScript
import {
|
||
Button,
|
||
Dialog,
|
||
FormContainer,
|
||
FormItem,
|
||
Input,
|
||
Notification,
|
||
Select,
|
||
Tabs,
|
||
toast,
|
||
} from '@/components/ui'
|
||
import TabList from '@/components/ui/Tabs/TabList'
|
||
import TabNav from '@/components/ui/Tabs/TabNav'
|
||
import { SeedTenantDataInput } from '@/proxy/admin/tenant/models'
|
||
import {
|
||
deleteTenantDefaultConnectionString,
|
||
getTenantDefaultConnectionString,
|
||
postSeedTenantData,
|
||
putTenantDefaultConnectionString,
|
||
} from '@/services/tenant.service'
|
||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||
import { Field, FieldProps, Form, Formik, FormikHelpers } from 'formik'
|
||
import { Suspense, useEffect, useRef, useState } from 'react'
|
||
import * as Yup from 'yup'
|
||
import { dataSourceTypeOptions } from '../listForm/edit/options'
|
||
import { DataSourceTypeEnum } from '@/proxy/form/models'
|
||
import { FaEye, FaEyeSlash } from 'react-icons/fa'
|
||
|
||
export interface ConnectionStringDto {
|
||
id: string
|
||
name: string
|
||
value: string
|
||
isNew?: boolean
|
||
dataSourceType?: number
|
||
}
|
||
|
||
const schemaCs = Yup.object().shape({
|
||
id: Yup.string().required(),
|
||
name: Yup.string().required(),
|
||
dataSourceType: Yup.number().required(),
|
||
value: Yup.string().required(),
|
||
})
|
||
|
||
const schemaSeed = Yup.object().shape({
|
||
id: Yup.string().required(),
|
||
adminEmail: Yup.string().required(),
|
||
adminPassword: Yup.string().required(),
|
||
})
|
||
|
||
function TenantConnectionString({
|
||
open,
|
||
onDialogClose,
|
||
name,
|
||
id,
|
||
}: {
|
||
open: boolean
|
||
onDialogClose: () => void
|
||
name: string
|
||
id: string
|
||
}) {
|
||
const { translate } = useLocalization()
|
||
const [currentTab, setCurrentTab] = useState('cs')
|
||
const [loading, setLoading] = useState(true)
|
||
const [connectionString, setConnectionString] = useState<ConnectionStringDto>()
|
||
|
||
const fetchDataTenants = async () => {
|
||
if (!id) {
|
||
return
|
||
}
|
||
setLoading(true)
|
||
const response = await getTenantDefaultConnectionString(id)
|
||
let value = ''
|
||
let isNew = false
|
||
|
||
if (response.data.length == 0) {
|
||
isNew = true
|
||
value = ''
|
||
} else {
|
||
isNew = false
|
||
value = response.data
|
||
}
|
||
|
||
setConnectionString({
|
||
id,
|
||
name: 'Default',
|
||
value,
|
||
isNew,
|
||
...(value && { dataSourceType: value.startsWith('Server') ? 1 : 2 }),
|
||
})
|
||
setLoading(false)
|
||
}
|
||
|
||
useEffect(() => {
|
||
fetchDataTenants()
|
||
}, [id])
|
||
|
||
const deleteConnectionString = async () => {
|
||
if (!id) {
|
||
return
|
||
}
|
||
setLoading(true)
|
||
|
||
try {
|
||
await deleteTenantDefaultConnectionString(id)
|
||
toast.push(
|
||
<Notification type="success" duration={2000}>
|
||
{translate('::AbpTenantManagement.Tenants.ConnectionStringDeleted')}
|
||
</Notification>,
|
||
{
|
||
placement: 'top-end',
|
||
},
|
||
)
|
||
onDialogClose()
|
||
} catch (error) {
|
||
toast.push(
|
||
<Notification type="danger" duration={2000}>
|
||
{'Hata'}
|
||
</Notification>,
|
||
{
|
||
placement: 'top-end',
|
||
},
|
||
)
|
||
} finally {
|
||
setLoading(false)
|
||
}
|
||
}
|
||
|
||
const handleSubmit = async (
|
||
values: ConnectionStringDto,
|
||
{ setSubmitting }: FormikHelpers<ConnectionStringDto>,
|
||
) => {
|
||
if (!id) {
|
||
return
|
||
}
|
||
|
||
setLoading(true)
|
||
setSubmitting(true)
|
||
|
||
try {
|
||
await putTenantDefaultConnectionString(id, values.value)
|
||
toast.push(
|
||
<Notification type="success" duration={2000}>
|
||
{translate('::AbpTenantManagement.Tenants.ConnectionStringSaved')}
|
||
</Notification>,
|
||
{
|
||
placement: 'top-end',
|
||
},
|
||
)
|
||
|
||
await fetchDataTenants()
|
||
//onDialogClose()
|
||
} catch (error) {
|
||
toast.push(
|
||
<Notification type="danger" duration={2000}>
|
||
{'Hata'}
|
||
</Notification>,
|
||
{
|
||
placement: 'top-end',
|
||
},
|
||
)
|
||
} finally {
|
||
setLoading(false)
|
||
setSubmitting(false)
|
||
}
|
||
}
|
||
|
||
const [pwInputType, setPwInputType] = useState('password')
|
||
|
||
const onPasswordVisibleClick = (e: React.MouseEvent<HTMLSpanElement>) => {
|
||
e.preventDefault()
|
||
setPwInputType(pwInputType === 'password' ? 'text' : 'password')
|
||
}
|
||
|
||
const passwordVisible = (
|
||
<span className="cursor-pointer" onClick={(e) => onPasswordVisibleClick(e as any)}>
|
||
{pwInputType === 'password' ? <FaEyeSlash /> : <FaEye />}
|
||
</span>
|
||
)
|
||
|
||
const handleSubmitSeed = async (
|
||
values: SeedTenantDataInput,
|
||
{ setSubmitting }: FormikHelpers<SeedTenantDataInput>,
|
||
) => {
|
||
if (!id) {
|
||
return
|
||
}
|
||
|
||
setLoading(true)
|
||
setSubmitting(true)
|
||
|
||
try {
|
||
await postSeedTenantData(values)
|
||
toast.push(
|
||
<Notification type="success" duration={2000}>
|
||
{translate('::AbpTenantManagement.Tenants.DatabaseSeeded')}
|
||
</Notification>,
|
||
{
|
||
placement: 'top-end',
|
||
},
|
||
)
|
||
|
||
onDialogClose()
|
||
} catch (error) {
|
||
const errorMessage =
|
||
(error as any)?.response?.data?.error?.message ??
|
||
(error as any)?.response?.data?.message ??
|
||
(error as any)?.message ??
|
||
'İşlem başarısız'
|
||
|
||
toast.push(
|
||
<Notification type="warning" duration={10000}>
|
||
{errorMessage}
|
||
</Notification>,
|
||
{
|
||
placement: 'top-end',
|
||
},
|
||
)
|
||
} finally {
|
||
setLoading(false)
|
||
setSubmitting(false)
|
||
}
|
||
}
|
||
|
||
if (!connectionString) {
|
||
return <></>
|
||
}
|
||
|
||
return (
|
||
<Dialog isOpen={open} onClose={onDialogClose} onRequestClose={onDialogClose}>
|
||
<h5 className="mb-4">{name}</h5>
|
||
<hr className="my-2"></hr>
|
||
|
||
<Tabs value={currentTab} onChange={setCurrentTab}>
|
||
<TabList>
|
||
<TabNav key="cs" value="cs">
|
||
Connection String
|
||
</TabNav>
|
||
<TabNav key="seed" value="seed">
|
||
{connectionString.isNew
|
||
? translate('::Abp.Account.SignUp')
|
||
: translate('::AbpTenantManagement.Tenants.DatabaseSeed')}
|
||
</TabNav>
|
||
</TabList>
|
||
</Tabs>
|
||
<div className="px-4 py-6">
|
||
<Suspense fallback={<></>}>
|
||
{currentTab === 'cs' && (
|
||
<Formik
|
||
initialValues={connectionString}
|
||
validationSchema={schemaCs}
|
||
onSubmit={handleSubmit}
|
||
>
|
||
{({ touched, errors, values, isSubmitting }) => {
|
||
return (
|
||
<Form>
|
||
<FormContainer size="sm">
|
||
<FormItem
|
||
label={translate('AbpAccount::DisplayName:Name')}
|
||
invalid={errors.name && touched.name}
|
||
errorMessage={errors.name}
|
||
>
|
||
<Field
|
||
type="text"
|
||
autoComplete="off"
|
||
name="name"
|
||
placeholder="Name"
|
||
disabled
|
||
component={Input}
|
||
/>
|
||
</FormItem>
|
||
|
||
<FormItem
|
||
label={translate('::ListForms.ListFormFieldEdit.LookupDataSourceType')}
|
||
invalid={errors.dataSourceType && touched.dataSourceType}
|
||
errorMessage={errors.dataSourceType}
|
||
>
|
||
<Field
|
||
type="text"
|
||
autoComplete="off"
|
||
name="dataSourceType"
|
||
placeholder={translate(
|
||
'::ListForms.ListFormFieldEdit.LookupDataSourceType',
|
||
)}
|
||
>
|
||
{({ field, form }: FieldProps<DataSourceTypeEnum>) => (
|
||
<Select
|
||
field={field}
|
||
form={form}
|
||
autoFocus
|
||
isClearable={true}
|
||
options={dataSourceTypeOptions}
|
||
value={dataSourceTypeOptions?.filter(
|
||
(option: any) => option.value === values.dataSourceType,
|
||
)}
|
||
onChange={(option) => {
|
||
form.setFieldValue(field.name, option?.value)
|
||
|
||
if (option?.value == 1)
|
||
//PostgreSQL
|
||
form.setFieldValue(
|
||
'value',
|
||
'Server=sql;Database=' +
|
||
name +
|
||
';User Id=sa;password=@Password;Trusted_Connection=False;TrustServerCertificate=True;Connection Timeout=60;',
|
||
)
|
||
else if (option?.value == 2)
|
||
//MsSql
|
||
form.setFieldValue(
|
||
'value',
|
||
'User ID=sa;Password=@Password;Host=postgres;Port=5432;Database=' +
|
||
name +
|
||
';',
|
||
)
|
||
}}
|
||
/>
|
||
)}
|
||
</Field>
|
||
</FormItem>
|
||
|
||
<FormItem
|
||
label="Connection String"
|
||
invalid={errors.value && touched.value}
|
||
errorMessage={errors.value}
|
||
>
|
||
<Field
|
||
textArea="true"
|
||
type="text"
|
||
autoComplete="off"
|
||
name="value"
|
||
placeholder="Value"
|
||
component={Input}
|
||
/>
|
||
</FormItem>
|
||
|
||
<div className="mt-6 flex flex-row justify-end gap-3">
|
||
<Button
|
||
disabled={connectionString.isNew}
|
||
className="mr-auto"
|
||
type="button"
|
||
color="red-500"
|
||
variant="twoTone"
|
||
onClick={deleteConnectionString}
|
||
>
|
||
{translate('::Delete')}
|
||
</Button>
|
||
<Button variant="solid" loading={isSubmitting} type="submit">
|
||
{isSubmitting ? translate('::SavingWithThreeDot') : translate('::Save')}
|
||
</Button>
|
||
<Button type="button" variant="plain" onClick={onDialogClose}>
|
||
{translate('::Cancel')}
|
||
</Button>
|
||
</div>
|
||
</FormContainer>
|
||
</Form>
|
||
)
|
||
}}
|
||
</Formik>
|
||
)}
|
||
{currentTab === 'seed' && (
|
||
<Formik
|
||
initialValues={{ id, adminEmail: '', adminPassword: '' } as SeedTenantDataInput}
|
||
validationSchema={schemaSeed}
|
||
onSubmit={handleSubmitSeed}
|
||
>
|
||
{({ touched, errors, values, isSubmitting }) => {
|
||
return (
|
||
<Form>
|
||
<FormContainer size="sm">
|
||
<FormItem
|
||
label={translate('::Abp.Account.EmailAddress')}
|
||
invalid={errors.adminEmail && touched.adminEmail}
|
||
errorMessage={errors.adminEmail}
|
||
>
|
||
<Field
|
||
type="text"
|
||
autoFocus
|
||
autoComplete="off"
|
||
name="adminEmail"
|
||
component={Input}
|
||
/>
|
||
</FormItem>
|
||
|
||
<FormItem
|
||
label={translate('::Abp.Identity.Password')}
|
||
invalid={errors.adminPassword && touched.adminPassword}
|
||
errorMessage={errors.adminPassword}
|
||
>
|
||
<Field
|
||
type={pwInputType}
|
||
suffix={passwordVisible}
|
||
autoComplete="off"
|
||
name="adminPassword"
|
||
component={Input}
|
||
/>
|
||
</FormItem>
|
||
|
||
<div className="mt-6 flex flex-row justify-end gap-3">
|
||
<Button variant="solid" loading={isSubmitting} type="submit">
|
||
{isSubmitting
|
||
? connectionString.isNew
|
||
? translate('::Abp.Identity.UserCreating')
|
||
: translate('::AbpTenantManagement.Tenants.DatabaseSeeding')
|
||
: connectionString.isNew
|
||
? translate('::Abp.Identity.CreateUser')
|
||
: translate('::AbpTenantManagement.Tenants.DatabaseSeed')}
|
||
</Button>
|
||
<Button type="button" variant="plain" onClick={onDialogClose}>
|
||
{translate('::Cancel')}
|
||
</Button>
|
||
</div>
|
||
</FormContainer>
|
||
</Form>
|
||
)
|
||
}}
|
||
</Formik>
|
||
)}
|
||
</Suspense>
|
||
</div>
|
||
</Dialog>
|
||
)
|
||
}
|
||
|
||
export default TenantConnectionString
|