mirror of https://github.com/boxyhq/jackson.git
Display the Google dsync auth button on Setup Link (#2361)
* Display the Google auth button * Delete DirectoryInfo and DirectoryTab components
This commit is contained in:
parent
503940c122
commit
952bfe360f
|
@ -95,7 +95,7 @@ const CreateDirectory = ({ setupLinkToken, defaultWebhookEndpoint }: CreateDirec
|
|||
<div>
|
||||
<LinkBack href={backUrl} />
|
||||
<h2 className='mb-5 mt-5 font-bold text-gray-700 md:text-xl'>{t('new_directory')}</h2>
|
||||
<div className='min-w-[28rem] rounded border border-gray-200 bg-white p-6 dark:border-gray-700 dark:bg-gray-800 md:w-3/4 md:max-w-lg'>
|
||||
<div className='min-w-[28rem] rounded border border-gray-200 bg-white p-6 dark:border-gray-700 dark:bg-gray-800'>
|
||||
<form onSubmit={onSubmit}>
|
||||
<div className='flex flex-col space-y-3'>
|
||||
<div className='form-control w-full'>
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
import DirectoryTab from './DirectoryTab';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { InputWithCopyButton } from '@components/ClipboardButton';
|
||||
import { LinkBack } from '@components/LinkBack';
|
||||
import React from 'react';
|
||||
import useDirectory from '@lib/ui/hooks/useDirectory';
|
||||
import Loading from '@components/Loading';
|
||||
import { errorToast } from '@components/Toaster';
|
||||
import { dsyncGoogleAuthURL } from '@lib/env';
|
||||
|
||||
const DirectoryInfo = ({ directoryId, setupLinkToken }: { directoryId: string; setupLinkToken?: string }) => {
|
||||
const { t } = useTranslation('common');
|
||||
|
||||
const { directory, isLoading, error } = useDirectory(directoryId, setupLinkToken);
|
||||
|
||||
if (isLoading) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
errorToast(error.message);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!directory) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const displayWebhook = directory.webhook.endpoint && directory.webhook.secret;
|
||||
const displayTenantProduct = setupLinkToken ? false : true;
|
||||
const backUrl = setupLinkToken ? `/setup/${setupLinkToken}/directory-sync` : '/admin/directory-sync';
|
||||
|
||||
return (
|
||||
<>
|
||||
<LinkBack href={backUrl} />
|
||||
<h2 className='mt-5 font-bold text-gray-700 md:text-xl'>{directory.name}</h2>
|
||||
<div className='w-full md:w-3/4'>
|
||||
<DirectoryTab directory={directory} activeTab='directory' setupLinkToken={setupLinkToken} />
|
||||
<div className='my-3 rounded border'>
|
||||
<dl className='divide-y'>
|
||||
<div className='px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6'>
|
||||
<dt className='text-sm font-medium text-gray-500'>{t('directory_id')}</dt>
|
||||
<dd className='mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0'>{directory.id}</dd>
|
||||
</div>
|
||||
{displayTenantProduct && (
|
||||
<>
|
||||
<div className='px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6'>
|
||||
<dt className='text-sm font-medium text-gray-500'>{t('tenant')}</dt>
|
||||
<dd className='mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0'>{directory.tenant}</dd>
|
||||
</div>
|
||||
<div className='px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6'>
|
||||
<dt className='text-sm font-medium text-gray-500'>{t('product')}</dt>
|
||||
<dd className='mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0'>{directory.product}</dd>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{displayWebhook && (
|
||||
<>
|
||||
<div className='px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6'>
|
||||
<dt className='text-sm font-medium text-gray-500'>{t('webhook_endpoint')}</dt>
|
||||
<dd className='mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0'>
|
||||
{directory.webhook.endpoint}
|
||||
</dd>
|
||||
</div>
|
||||
<div className='px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6'>
|
||||
<dt className='text-sm font-medium text-gray-500'>{t('webhook_secret')}</dt>
|
||||
<dd className='mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0'>
|
||||
{directory.webhook.secret}
|
||||
</dd>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</dl>
|
||||
</div>
|
||||
{directory.scim.endpoint && directory.scim.secret && (
|
||||
<div className='mt-4 space-y-4 rounded border p-6'>
|
||||
<div className='form-control'>
|
||||
<InputWithCopyButton text={directory.scim.endpoint as string} label={t('scim_endpoint')} />
|
||||
</div>
|
||||
<div className='form-control'>
|
||||
<InputWithCopyButton text={directory.scim.secret} label={t('scim_token')} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{directory.type === 'google' && (
|
||||
<div className='form-control mt-10'>
|
||||
<InputWithCopyButton
|
||||
text={`${dsyncGoogleAuthURL}?directoryId=${directory.id}`}
|
||||
label={t('dsync_google_auth_url')}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DirectoryInfo;
|
|
@ -1,69 +0,0 @@
|
|||
import Link from 'next/link';
|
||||
import type { Directory } from '@boxyhq/saml-jackson';
|
||||
import classNames from 'classnames';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
const DirectoryTab = ({
|
||||
directory,
|
||||
activeTab,
|
||||
setupLinkToken,
|
||||
}: {
|
||||
directory: Directory;
|
||||
activeTab: string;
|
||||
setupLinkToken?: string;
|
||||
}) => {
|
||||
const { t } = useTranslation('common');
|
||||
|
||||
const menus = setupLinkToken
|
||||
? [
|
||||
{
|
||||
name: t('directory'),
|
||||
href: `/setup/${setupLinkToken}/directory-sync/${directory.id}`,
|
||||
active: activeTab === 'directory',
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
name: t('directory'),
|
||||
href: `/admin/directory-sync/${directory.id}`,
|
||||
active: activeTab === 'directory',
|
||||
},
|
||||
{
|
||||
name: t('users'),
|
||||
href: `/admin/directory-sync/${directory.id}/users`,
|
||||
active: activeTab === 'users',
|
||||
},
|
||||
{
|
||||
name: t('groups'),
|
||||
href: `/admin/directory-sync/${directory.id}/groups`,
|
||||
active: activeTab === 'groups',
|
||||
},
|
||||
{
|
||||
name: t('webhook_events'),
|
||||
href: `/admin/directory-sync/${directory.id}/events`,
|
||||
active: activeTab === 'events',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<nav className='-mb-px flex space-x-5 border-b' aria-label='Tabs'>
|
||||
{menus.map((menu) => {
|
||||
return (
|
||||
<Link
|
||||
href={menu.href}
|
||||
key={menu.href}
|
||||
className={classNames(
|
||||
'inline-flex items-center border-b-2 py-4 text-sm font-medium',
|
||||
menu.active
|
||||
? 'border-gray-700 text-gray-700'
|
||||
: 'border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700'
|
||||
)}>
|
||||
{menu.name}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
export default DirectoryTab;
|
File diff suppressed because it is too large
Load Diff
|
@ -1,9 +1,10 @@
|
|||
import { useTranslation } from 'next-i18next';
|
||||
import ArrowTopRightOnSquareIcon from '@heroicons/react/24/outline/ArrowTopRightOnSquareIcon';
|
||||
|
||||
import { useDirectory } from '../hooks';
|
||||
import { DirectoryTab } from '../dsync';
|
||||
import { Loading, Error, PageHeader, Badge } from '../shared';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { InputWithCopyButton } from '../shared/InputWithCopyButton';
|
||||
import type { Directory } from '../types';
|
||||
import { Loading, Error, PageHeader, Badge, Alert, InputWithCopyButton, LinkPrimary } from '../shared';
|
||||
|
||||
type ExcludeFields = keyof Pick<Directory, 'tenant' | 'product' | 'webhook'>;
|
||||
|
||||
|
@ -13,9 +14,13 @@ type ExcludeFields = keyof Pick<Directory, 'tenant' | 'product' | 'webhook'>;
|
|||
export const DirectoryInfo = ({
|
||||
urls,
|
||||
excludeFields = [],
|
||||
hideTabs = false,
|
||||
displayGoogleAuthButton = false,
|
||||
}: {
|
||||
urls: { getDirectory: string; tabBase: string; googleAuth: string };
|
||||
excludeFields?: ExcludeFields[];
|
||||
hideTabs?: boolean;
|
||||
displayGoogleAuthButton?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslation('common');
|
||||
const { directory, isLoadingDirectory, directoryError } = useDirectory(urls.getDirectory);
|
||||
|
@ -32,11 +37,30 @@ export const DirectoryInfo = ({
|
|||
return null;
|
||||
}
|
||||
|
||||
const authorizedGoogle = directory.google_access_token && directory.google_refresh_token;
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageHeader title={directory.name} />
|
||||
<DirectoryTab activeTab='directory' baseUrl={urls.tabBase} />
|
||||
<div className='rounded border'>
|
||||
{!hideTabs && <DirectoryTab activeTab='directory' baseUrl={urls.tabBase} />}
|
||||
{!authorizedGoogle && displayGoogleAuthButton && (
|
||||
<div className='mt-5'>
|
||||
<Alert variant='success' className='bg-white border-error'>
|
||||
<div className='space-y-3'>
|
||||
<p className='text-sm text-gray-600'>{t('bui-dsync-authorization-google-desc')}</p>
|
||||
<LinkPrimary
|
||||
href={`${urls.googleAuth}?directoryId=${directory.id}`}
|
||||
target='_blank'
|
||||
className='btn-md'
|
||||
Icon={ArrowTopRightOnSquareIcon}
|
||||
rel='noopener noreferrer'>
|
||||
{t('bui-dsync-authorization-google')}
|
||||
</LinkPrimary>
|
||||
</div>
|
||||
</Alert>
|
||||
</div>
|
||||
)}
|
||||
<div className={`rounded border ${hideTabs ? 'mt-5' : ''}`}>
|
||||
<dl className='divide-y'>
|
||||
<div className='px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6'>
|
||||
<dt className='text-sm font-medium text-gray-500'>{t('bui-dsync-directory-id')}</dt>
|
||||
|
@ -74,7 +98,7 @@ export const DirectoryInfo = ({
|
|||
<div className='px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6'>
|
||||
<dt className='text-sm font-medium text-gray-500'>{t('bui-dsync-authorized-status')}</dt>
|
||||
<dd className='mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0'>
|
||||
{directory.google_access_token && directory.google_refresh_token ? (
|
||||
{authorizedGoogle ? (
|
||||
<Badge color='success'>{t('bui-dsync-authorized')}</Badge>
|
||||
) : (
|
||||
<Badge color='warning'>{t('bui-dsync-not-authorized')}</Badge>
|
||||
|
|
|
@ -3,7 +3,8 @@ import { useTranslation } from 'next-i18next';
|
|||
import { useContext } from 'react';
|
||||
import { BUIContext } from '../provider';
|
||||
|
||||
type Tabs = 'directory' | 'users' | 'groups' | 'events';
|
||||
export const allTabs = ['directory', 'users', 'groups', 'events'] as const;
|
||||
export type Tabs = (typeof allTabs)[number];
|
||||
|
||||
export const DirectoryTab = ({ activeTab, baseUrl }: { activeTab: Tabs; baseUrl: string }) => {
|
||||
const { t } = useTranslation('common');
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
type AlertType = 'error' | 'success' | 'warning';
|
||||
|
||||
const variants = {
|
||||
error: 'alert-error',
|
||||
success: 'alert-success',
|
||||
warning: 'alert-warning',
|
||||
} as const;
|
||||
|
||||
export const Alert = ({
|
||||
variant,
|
||||
children,
|
||||
className,
|
||||
}: {
|
||||
variant: AlertType;
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}) => {
|
||||
return (
|
||||
<div role='alert' className={`rounded alert ${className} ${variants[variant]}`}>
|
||||
<span>{children}</span>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -15,3 +15,5 @@ export { LinkPrimary } from './LinkPrimary';
|
|||
export { LinkBack } from './LinkBack';
|
||||
export { pageLimit } from './Pagination';
|
||||
export { ButtonPrimary } from './ButtonPrimary';
|
||||
export { Alert } from './Alert';
|
||||
export { InputWithCopyButton } from './InputWithCopyButton';
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
"deleted": "Deleted",
|
||||
"delete_the_connection": "Delete the Connection?",
|
||||
"delete_this_connection": "Delete this Connection",
|
||||
"directory_id": "Directory ID",
|
||||
"directory_name": "Directory name",
|
||||
"directory_provider": "Directory provider",
|
||||
"directory_sync": "Directory Sync",
|
||||
|
@ -56,15 +55,12 @@
|
|||
"sign_out": "Sign out",
|
||||
"saml": "SAML",
|
||||
"sso_error": "SSO error",
|
||||
"scim_endpoint": "SCIM endpoint",
|
||||
"scim_token": "SCIM token",
|
||||
"select_sso_type": "Select SSO type",
|
||||
"select_an_app": "Select an App to continue",
|
||||
"send_magic_link": "Send Magic Link",
|
||||
"setup_links": "Setup Links",
|
||||
"tenant": "Tenant",
|
||||
"update_directory": "Update Directory",
|
||||
"webhook_endpoint": "Webhook Endpoint",
|
||||
"webhook_secret": "Webhook secret",
|
||||
"webhook_url": "Webhook URL",
|
||||
"download": "Download",
|
||||
|
@ -178,13 +174,8 @@
|
|||
"delete_this_directory_desc": "This action cannot be undone. This will permanently delete the directory connection, users, and groups.",
|
||||
"directory_connection_deleted_successfully": "Directory connection deleted successfully",
|
||||
"directory_domain": "Directory Domain",
|
||||
"dsync_google_auth_url": "The URL that you will need to authorize the application to access your Google Directory.",
|
||||
"show_secret": "Show secret",
|
||||
"hide_secret": "Hide secret",
|
||||
"directory": "Directory",
|
||||
"users": "Users",
|
||||
"groups": "Groups",
|
||||
"webhook_events": "Webhook Events",
|
||||
"retraced_project_created": "Project created successfully",
|
||||
"project_name": "Project name",
|
||||
"create_project": "Create Project",
|
||||
|
@ -319,5 +310,7 @@
|
|||
"bui-dsync-delete-events-desc": "This action will permanently delete all webhook events log. Are you sure you want to proceed?",
|
||||
"bui-dsync-authorized-status": "Status",
|
||||
"bui-dsync-authorized": "Authorized",
|
||||
"bui-dsync-not-authorized": "Not Authorized"
|
||||
"bui-dsync-not-authorized": "Not Authorized",
|
||||
"bui-dsync-authorization-google": "Authorize Google Workspace",
|
||||
"bui-dsync-authorization-google-desc": "You should authorize Google Workspace to sync your directory. Click the button below start the authorization process. Make sure you have the necessary permissions to authorize Google Workspace."
|
||||
}
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
}
|
||||
},
|
||||
"internal-ui": {
|
||||
"name": "@boxyhq/internal-ui",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"vite-tsconfig-paths": "4.3.1"
|
||||
|
@ -85,6 +86,8 @@
|
|||
"@types/react": "18.2.56",
|
||||
"@vitejs/plugin-react": "4.2.1",
|
||||
"autoprefixer": "10.4.17",
|
||||
"rollup": "4.12.0",
|
||||
"tslib": "2.6.2",
|
||||
"typescript": "5.3.3",
|
||||
"vite": "5.1.0"
|
||||
},
|
||||
|
@ -23579,6 +23582,7 @@
|
|||
}
|
||||
},
|
||||
"npm": {
|
||||
"name": "@boxyhq/saml-jackson",
|
||||
"version": "0.0.0",
|
||||
"license": "Apache 2.0",
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,15 +1,33 @@
|
|||
import type { NextPage } from 'next';
|
||||
import React from 'react';
|
||||
import type { NextPage } from 'next';
|
||||
import { useRouter } from 'next/router';
|
||||
import DirectoryInfo from '@components/dsync/DirectoryInfo';
|
||||
import { DirectoryInfo, LinkBack } from '@boxyhq/internal-ui';
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
|
||||
|
||||
import { dsyncGoogleAuthURL } from '@lib/env';
|
||||
|
||||
const DirectoryDetailsPage: NextPage = () => {
|
||||
const router = useRouter();
|
||||
|
||||
const { token, directoryId } = router.query as { token: string; directoryId: string };
|
||||
|
||||
return <DirectoryInfo directoryId={directoryId} setupLinkToken={token} />;
|
||||
return (
|
||||
<div className='flex flex-col gap-4'>
|
||||
<div>
|
||||
<LinkBack href={`/setup/${token}/directory-sync`} />
|
||||
</div>
|
||||
<div>
|
||||
<DirectoryInfo
|
||||
urls={{
|
||||
getDirectory: `/api/setup/${token}/directory-sync/${directoryId}`,
|
||||
tabBase: '',
|
||||
googleAuth: dsyncGoogleAuthURL,
|
||||
}}
|
||||
hideTabs={true}
|
||||
displayGoogleAuthButton={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const getServerSideProps = async (context) => {
|
||||
|
|
Loading…
Reference in New Issue