mirror of https://github.com/boxyhq/jackson.git
258 lines
8.7 KiB
TypeScript
258 lines
8.7 KiB
TypeScript
import { FormEvent, useState } from 'react';
|
|
import ConfirmationModal from '@components/ConfirmationModal';
|
|
import { useRouter } from 'next/router';
|
|
import { useTranslation } from 'next-i18next';
|
|
import { errorToast, successToast } from '@components/Toaster';
|
|
import { ButtonPrimary } from '../ButtonPrimary';
|
|
import { LinkBack } from '../LinkBack';
|
|
import { InputWithCopyButton } from '../ClipboardButton';
|
|
import type { SetupLinkService, SetupLink } from '@boxyhq/saml-jackson';
|
|
import type { ApiResponse } from 'types';
|
|
|
|
const CreateSetupLink = ({ service }: { service: SetupLinkService }) => {
|
|
const router = useRouter();
|
|
const { t } = useTranslation('common');
|
|
const [loading, setLoading] = useState(false);
|
|
const [loading1, setLoading1] = useState(false);
|
|
const [delModalVisible, setDelModalVisible] = useState(false);
|
|
|
|
const [setupLink, setSetupLink] = useState<SetupLink | null>(null);
|
|
const [formObj, setFormObj] = useState({
|
|
tenant: '',
|
|
product: '',
|
|
service,
|
|
name: '',
|
|
description: '',
|
|
defaultRedirectUrl: '',
|
|
redirectUrl: '',
|
|
});
|
|
|
|
// Create a new setup link
|
|
const createSetupLink = async (event: React.FormEvent) => {
|
|
event.preventDefault();
|
|
|
|
setLoading(true);
|
|
|
|
const rawResponse = await fetch('/api/admin/setup-links', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(formObj),
|
|
});
|
|
|
|
setLoading(false);
|
|
|
|
const response: ApiResponse<SetupLink> = await rawResponse.json();
|
|
|
|
if ('error' in response) {
|
|
errorToast(response.error.message);
|
|
return;
|
|
}
|
|
|
|
if (rawResponse.ok) {
|
|
setSetupLink(response.data);
|
|
successToast(t('link_generated'));
|
|
}
|
|
};
|
|
|
|
// Regenerate setup link
|
|
const regenerateSetupLink = async () => {
|
|
setLoading1(true);
|
|
setDelModalVisible(!delModalVisible);
|
|
|
|
const res = await fetch('/api/admin/setup-links', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
...formObj,
|
|
regenerate: true,
|
|
}),
|
|
});
|
|
if (res.ok) {
|
|
setLoading1(false);
|
|
const json = await res.json();
|
|
setSetupLink(json.data);
|
|
successToast(t('link_regenerated'));
|
|
} else {
|
|
setLoading1(false);
|
|
errorToast(t('server_error'));
|
|
}
|
|
};
|
|
|
|
const handleChange = (event: FormEvent) => {
|
|
const target = event.target as HTMLInputElement | HTMLTextAreaElement;
|
|
setFormObj((cur) => ({ ...cur, [target.name]: target.value }));
|
|
};
|
|
|
|
const toggleDelConfirm = () => setDelModalVisible(!delModalVisible);
|
|
|
|
const buttonDisabled = !formObj.tenant || !formObj.product || !formObj.service;
|
|
|
|
return (
|
|
<>
|
|
<LinkBack onClick={() => router.back()} />
|
|
<div className='mt-5 min-w-[28rem] rounded border border-gray-200 bg-white p-6 dark:border-gray-700 dark:bg-gray-800'>
|
|
<h2 className='mb-5 font-bold text-gray-700 dark:text-white md:text-xl'>
|
|
{t('create_setup_link', {
|
|
service: service === 'sso' ? t('enterprise_sso') : t('directory_sync'),
|
|
})}
|
|
</h2>
|
|
<form onSubmit={createSetupLink} method='POST'>
|
|
<div>
|
|
<div className='mb-6'>
|
|
<label
|
|
htmlFor='tenant'
|
|
className={`mb-2 block text-sm font-medium text-gray-900 dark:text-gray-300`}>
|
|
{t('tenant')}
|
|
</label>
|
|
<input
|
|
id='tenant'
|
|
name='tenant'
|
|
type='text'
|
|
placeholder='acme.com'
|
|
value={formObj['tenant']}
|
|
onChange={handleChange}
|
|
className='input-bordered input w-full'
|
|
required
|
|
/>
|
|
</div>
|
|
<div className='mb-6'>
|
|
<label
|
|
htmlFor='product'
|
|
className={`mb-2 block text-sm font-medium text-gray-900 dark:text-gray-300`}>
|
|
{t('product')}
|
|
</label>
|
|
<input
|
|
id='product'
|
|
name='product'
|
|
type='text'
|
|
placeholder='demo'
|
|
value={formObj['product']}
|
|
onChange={handleChange}
|
|
className='input-bordered input w-full'
|
|
required
|
|
/>
|
|
</div>
|
|
{service === 'sso' && (
|
|
<>
|
|
<div className='mb-6'>
|
|
<label
|
|
htmlFor='name'
|
|
className={`mb-2 block text-sm font-medium text-gray-900 dark:text-gray-300`}>
|
|
{t('name')}
|
|
</label>
|
|
<input
|
|
id='name'
|
|
name='name'
|
|
type='text'
|
|
placeholder='MyApp'
|
|
value={formObj['name']}
|
|
onChange={handleChange}
|
|
className='input-bordered input w-full'
|
|
/>
|
|
</div>
|
|
<div className='mb-6'>
|
|
<label
|
|
htmlFor='description'
|
|
className={`mb-2 block text-sm font-medium text-gray-900 dark:text-gray-300`}>
|
|
{t('description')}
|
|
</label>
|
|
<input
|
|
id='description'
|
|
name='description'
|
|
type='text'
|
|
placeholder='A short description not more than 100 characters'
|
|
value={formObj['description']}
|
|
onChange={handleChange}
|
|
className='input-bordered input w-full'
|
|
/>
|
|
</div>
|
|
<div className='mb-6'>
|
|
<label
|
|
htmlFor='defaultRedirectUrl'
|
|
className={`mb-2 block text-sm font-medium text-gray-900 dark:text-gray-300`}>
|
|
{t('default_redirect_url')}
|
|
</label>
|
|
<input
|
|
id='defaultRedirectUrl'
|
|
name='defaultRedirectUrl'
|
|
type='url'
|
|
placeholder='http://localhost:3366/login/saml'
|
|
value={formObj['defaultRedirectUrl']}
|
|
onChange={handleChange}
|
|
className='input-bordered input w-full'
|
|
required
|
|
/>
|
|
</div>
|
|
<div className='mb-6'>
|
|
<label
|
|
htmlFor='redirectUrl'
|
|
className={`mb-2 block text-sm font-medium text-gray-900 dark:text-gray-300`}>
|
|
{t('allowed_redirect_url')}
|
|
</label>
|
|
<textarea
|
|
id={'redirectUrl'}
|
|
name='redirectUrl'
|
|
placeholder={t('allowed_redirect_url')}
|
|
value={formObj['redirectUrl']}
|
|
required
|
|
onChange={handleChange}
|
|
className={`whitespace-pre} textarea-bordered textarea h-24 w-full`}
|
|
rows={3}
|
|
/>
|
|
</div>
|
|
</>
|
|
)}
|
|
</div>
|
|
<div className='flex'>
|
|
<ButtonPrimary loading={loading} disabled={buttonDisabled}>
|
|
{t('generate')}
|
|
</ButtonPrimary>
|
|
</div>
|
|
</form>
|
|
<ConfirmationModal
|
|
title={t('regenerate_setup_link')}
|
|
description={t('regenerate_setup_link_description')}
|
|
visible={delModalVisible}
|
|
onConfirm={regenerateSetupLink}
|
|
onCancel={toggleDelConfirm}
|
|
actionButtonText={t('regenerate')}
|
|
/>
|
|
</div>
|
|
{setupLink && (
|
|
<div className='mt-5 min-w-[28rem] rounded border border-gray-200 bg-white p-6 dark:border-gray-700 dark:bg-gray-800'>
|
|
<h2 className='mb-5 font-bold text-gray-700 dark:text-white md:text-xl'>
|
|
{setupLink
|
|
? t('setup_link_info')
|
|
: t('create_setup_link', {
|
|
service: service === 'sso' ? t('enterprise_sso') : t('directory_sync'),
|
|
})}
|
|
</h2>
|
|
<div className='form-control'>
|
|
<InputWithCopyButton text={setupLink.url} label={t('setup_link_url')} />
|
|
</div>
|
|
<div className='mt-5 flex'>
|
|
<ButtonPrimary
|
|
loading={loading1}
|
|
disabled={buttonDisabled}
|
|
onClick={
|
|
setupLink
|
|
? () => {
|
|
setDelModalVisible(true);
|
|
}
|
|
: createSetupLink
|
|
}>
|
|
{setupLink ? t('regenerate') : t('generate')}
|
|
</ButtonPrimary>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default CreateSetupLink;
|