sozsoft-platform/ui/src/views/admin/tenant-management/TenantsConnectionString.tsx
2026-03-21 23:34:14 +03:00

423 lines
13 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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