mirror of https://github.com/boxyhq/jackson.git
Add missing translations (#2089)
* Add missing translations * Add eslint-plugin-i18next plugin * Add missing translation * Update translations * Update ESLint rules and improve UI text * Update WellKnownURLs locales * Add server-side translations in SetupLinkIndexPage
This commit is contained in:
parent
1525035092
commit
fde4e59fa6
|
@ -9,18 +9,20 @@ module.exports = {
|
||||||
},
|
},
|
||||||
root: true,
|
root: true,
|
||||||
parser: '@typescript-eslint/parser',
|
parser: '@typescript-eslint/parser',
|
||||||
plugins: ['@typescript-eslint'],
|
plugins: ['@typescript-eslint', 'i18next'],
|
||||||
extends: [
|
extends: [
|
||||||
'eslint:recommended',
|
'eslint:recommended',
|
||||||
'plugin:@typescript-eslint/recommended',
|
'plugin:@typescript-eslint/recommended',
|
||||||
'prettier',
|
'prettier',
|
||||||
'next/core-web-vitals',
|
'next/core-web-vitals',
|
||||||
|
'plugin:i18next/recommended',
|
||||||
],
|
],
|
||||||
overrides: [
|
overrides: [
|
||||||
{
|
{
|
||||||
files: ['*.ts', '*.tsx'],
|
files: ['*.ts', '*.tsx'],
|
||||||
rules: {
|
rules: {
|
||||||
'@typescript-eslint/no-explicit-any': 'warn',
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
|
'import/no-anonymous-default-export': 'off',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
|
||||||
export const PoweredBy = () => {
|
export const PoweredBy = () => {
|
||||||
|
const { t } = useTranslation('common');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<p className='text-center text-xs text-gray-500 py-5'>
|
<p className='text-center text-xs text-gray-500 py-5'>
|
||||||
<a href='https://boxyhq.com/' target='_blank' rel='noopener noreferrer'>
|
<a href='https://boxyhq.com/' target='_blank' rel='noopener noreferrer'>
|
||||||
Powered by BoxyHQ
|
{t('boxyhq_powered_by')}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
);
|
);
|
||||||
|
|
|
@ -165,7 +165,7 @@ export const Sidebar = ({ isOpen, setIsOpen }: SidebarProps) => {
|
||||||
<div className='flex flex-shrink-0 items-center px-4'>
|
<div className='flex flex-shrink-0 items-center px-4'>
|
||||||
<Link href='/' className='flex items-center'>
|
<Link href='/' className='flex items-center'>
|
||||||
<Image src={Logo} alt='BoxyHQ' width={36} height={36} className='h-8 w-auto' />
|
<Image src={Logo} alt='BoxyHQ' width={36} height={36} className='h-8 w-auto' />
|
||||||
<span className='ml-4 text-xl font-bold text-gray-900'>BoxyHQ Admin Portal</span>
|
<span className='ml-4 text-xl font-bold text-gray-900'>{t('boxyhq_admin_portal')}</span>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className='mt-5 h-0 flex-1 overflow-y-auto'>
|
<div className='mt-5 h-0 flex-1 overflow-y-auto'>
|
||||||
|
@ -182,7 +182,7 @@ export const Sidebar = ({ isOpen, setIsOpen }: SidebarProps) => {
|
||||||
<div className='flex flex-shrink-0 items-center px-4'>
|
<div className='flex flex-shrink-0 items-center px-4'>
|
||||||
<Link href='/' className='flex items-center'>
|
<Link href='/' className='flex items-center'>
|
||||||
<Image src={Logo} alt='BoxyHQ' width={36} height={36} className='h-8 w-auto' />
|
<Image src={Logo} alt='BoxyHQ' width={36} height={36} className='h-8 w-auto' />
|
||||||
<span className='ml-4 text-lg font-bold text-gray-900'>BoxyHQ Admin Portal</span>
|
<span className='ml-4 text-lg font-bold text-gray-900'>{t('boxyhq_admin_portal')}</span>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className='mt-5 flex flex-1 flex-col'>
|
<div className='mt-5 flex flex-1 flex-col'>
|
||||||
|
|
|
@ -13,49 +13,49 @@ const WellKnownURLs = () => {
|
||||||
|
|
||||||
const links = [
|
const links = [
|
||||||
{
|
{
|
||||||
title: 'SP Metadata',
|
title: t('sp_metadata'),
|
||||||
description: t('sp_metadata_description'),
|
description: t('sp_metadata_description'),
|
||||||
href: '/.well-known/sp-metadata',
|
href: '/.well-known/sp-metadata',
|
||||||
buttonText: viewText,
|
buttonText: viewText,
|
||||||
type: 'idp-config',
|
type: 'idp-config',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'SAML Configuration',
|
title: t('saml_configuration'),
|
||||||
description: t('sp_config_description'),
|
description: t('sp_config_description'),
|
||||||
href: '/.well-known/saml-configuration',
|
href: '/.well-known/saml-configuration',
|
||||||
buttonText: viewText,
|
buttonText: viewText,
|
||||||
type: 'idp-config',
|
type: 'idp-config',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'SAML Public Certificate',
|
title: t('saml_public_cert'),
|
||||||
description: t('saml_public_cert_description'),
|
description: t('saml_public_cert_description'),
|
||||||
href: '/.well-known/saml.cer',
|
href: '/.well-known/saml.cer',
|
||||||
buttonText: downloadText,
|
buttonText: downloadText,
|
||||||
type: 'idp-config',
|
type: 'idp-config',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'OpenID Configuration',
|
title: t('oidc_configuration'),
|
||||||
description: t('oidc_config_description'),
|
description: t('oidc_config_description'),
|
||||||
href: '/.well-known/oidc-configuration',
|
href: '/.well-known/oidc-configuration',
|
||||||
buttonText: viewText,
|
buttonText: viewText,
|
||||||
type: 'idp-config',
|
type: 'idp-config',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'OpenID Connect Discovery',
|
title: t('oidc_discovery'),
|
||||||
description: t('oidc_discovery_description'),
|
description: t('oidc_discovery_description'),
|
||||||
href: '/.well-known/openid-configuration',
|
href: '/.well-known/openid-configuration',
|
||||||
buttonText: viewText,
|
buttonText: viewText,
|
||||||
type: 'auth',
|
type: 'auth',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'IdP Metadata',
|
title: t('idp_metadata'),
|
||||||
description: t('idp_metadata_description'),
|
description: t('idp_metadata_description'),
|
||||||
href: '/.well-known/idp-metadata',
|
href: '/.well-known/idp-metadata',
|
||||||
buttonText: viewText,
|
buttonText: viewText,
|
||||||
type: 'saml-fed',
|
type: 'saml-fed',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'IdP Configuration',
|
title: t('idp_configuration'),
|
||||||
description: t('idp_config_description'),
|
description: t('idp_config_description'),
|
||||||
href: '/.well-known/idp-configuration',
|
href: '/.well-known/idp-configuration',
|
||||||
buttonText: viewText,
|
buttonText: viewText,
|
||||||
|
@ -74,23 +74,23 @@ const WellKnownURLs = () => {
|
||||||
<Tab
|
<Tab
|
||||||
isActive={view === 'idp-config'}
|
isActive={view === 'idp-config'}
|
||||||
setIsActive={() => setView('idp-config')}
|
setIsActive={() => setView('idp-config')}
|
||||||
title='Identity Provider Configuration'
|
title={t('idp_configuration_title')}
|
||||||
description='Links for SAML/OIDC IdP setup'
|
description={t('idp_configuration_description')}
|
||||||
label='Identity Provider Configuration links'
|
label={t('idp_configuration_label')}
|
||||||
/>
|
/>
|
||||||
<Tab
|
<Tab
|
||||||
isActive={view === 'auth'}
|
isActive={view === 'auth'}
|
||||||
setIsActive={() => setView('auth')}
|
setIsActive={() => setView('auth')}
|
||||||
title='Auth integration'
|
title={t('auth_integration_title')}
|
||||||
description='Links for OAuth 2.0/OpenID Connect auth'
|
description={t('auth_integration_description')}
|
||||||
label='Auth integration links'
|
label={t('auth_integration_label')}
|
||||||
/>
|
/>
|
||||||
<Tab
|
<Tab
|
||||||
isActive={view === 'saml-fed'}
|
isActive={view === 'saml-fed'}
|
||||||
setIsActive={() => setView('saml-fed')}
|
setIsActive={() => setView('saml-fed')}
|
||||||
title='SAML Federation'
|
title={t('saml_fed_configuration_title')}
|
||||||
description='Links for SAML Federation app setup'
|
description={t('saml_fed_configuration_description')}
|
||||||
label='SAML Federation links'
|
label={t('saml_fed_configuration_label')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='space-y-3 mt-8'>
|
<div className='space-y-3 mt-8'>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import type { Directory } from '@boxyhq/saml-jackson';
|
import type { Directory } from '@boxyhq/saml-jackson';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
|
||||||
const DirectoryTab = ({
|
const DirectoryTab = ({
|
||||||
directory,
|
directory,
|
||||||
|
@ -11,32 +12,34 @@ const DirectoryTab = ({
|
||||||
activeTab: string;
|
activeTab: string;
|
||||||
setupLinkToken?: string;
|
setupLinkToken?: string;
|
||||||
}) => {
|
}) => {
|
||||||
|
const { t } = useTranslation('common');
|
||||||
|
|
||||||
const menus = setupLinkToken
|
const menus = setupLinkToken
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
name: 'Directory',
|
name: t('directory'),
|
||||||
href: `/setup/${setupLinkToken}/directory-sync/${directory.id}`,
|
href: `/setup/${setupLinkToken}/directory-sync/${directory.id}`,
|
||||||
active: activeTab === 'directory',
|
active: activeTab === 'directory',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: [
|
: [
|
||||||
{
|
{
|
||||||
name: 'Directory',
|
name: t('directory'),
|
||||||
href: `/admin/directory-sync/${directory.id}`,
|
href: `/admin/directory-sync/${directory.id}`,
|
||||||
active: activeTab === 'directory',
|
active: activeTab === 'directory',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Users',
|
name: t('users'),
|
||||||
href: `/admin/directory-sync/${directory.id}/users`,
|
href: `/admin/directory-sync/${directory.id}/users`,
|
||||||
active: activeTab === 'users',
|
active: activeTab === 'users',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Groups',
|
name: t('groups'),
|
||||||
href: `/admin/directory-sync/${directory.id}/groups`,
|
href: `/admin/directory-sync/${directory.id}/groups`,
|
||||||
active: activeTab === 'groups',
|
active: activeTab === 'groups',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Webhook Events',
|
name: t('webhook_events'),
|
||||||
href: `/admin/directory-sync/${directory.id}/events`,
|
href: `/admin/directory-sync/${directory.id}/events`,
|
||||||
active: activeTab === 'events',
|
active: activeTab === 'events',
|
||||||
},
|
},
|
||||||
|
|
|
@ -20,7 +20,7 @@ export const AccountLayout = ({ children }: { children: React.ReactNode }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
<title>Admin Portal | BoxyHQ</title>
|
<title>{t('boxyhq_admin_portal')}</title>
|
||||||
<link rel='icon' href='/favicon.ico' />
|
<link rel='icon' href='/favicon.ico' />
|
||||||
</Head>
|
</Head>
|
||||||
<Sidebar isOpen={isOpen} setIsOpen={setIsOpen} />
|
<Sidebar isOpen={isOpen} setIsOpen={setIsOpen} />
|
||||||
|
|
|
@ -3,9 +3,11 @@ import classNames from 'classnames';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { successToast, errorToast } from '@components/Toaster';
|
import { successToast, errorToast } from '@components/Toaster';
|
||||||
import { LinkBack } from '@components/LinkBack';
|
import { LinkBack } from '@components/LinkBack';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
|
||||||
const AddProject = () => {
|
const AddProject = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const { t } = useTranslation('common');
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [project, setProject] = useState({
|
const [project, setProject] = useState({
|
||||||
|
@ -49,7 +51,7 @@ const AddProject = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data && data.project) {
|
if (data && data.project) {
|
||||||
successToast('Project created successfully.');
|
successToast(t('retraced_project_created'));
|
||||||
router.replace(`/admin/retraced/projects/${data.project.id}`);
|
router.replace(`/admin/retraced/projects/${data.project.id}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -58,13 +60,15 @@ const AddProject = () => {
|
||||||
<>
|
<>
|
||||||
<LinkBack href='/admin/retraced/projects' />
|
<LinkBack href='/admin/retraced/projects' />
|
||||||
<div className='mt-5'>
|
<div className='mt-5'>
|
||||||
<h2 className='mb-5 mt-5 font-bold text-gray-700 dark:text-white md:text-xl'>Create Project</h2>
|
<h2 className='mb-5 mt-5 font-bold text-gray-700 dark:text-white md:text-xl'>
|
||||||
|
{t('create_project')}
|
||||||
|
</h2>
|
||||||
<div className='min-w-[28rem] rounded border border-gray-200 bg-white p-3 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-3 dark:border-gray-700 dark:bg-gray-800 md:w-3/4 md:max-w-lg'>
|
||||||
<form onSubmit={createProject}>
|
<form onSubmit={createProject}>
|
||||||
<div className='flex flex-col space-y-3'>
|
<div className='flex flex-col space-y-3'>
|
||||||
<div className='form-control w-full'>
|
<div className='form-control w-full'>
|
||||||
<label className='label'>
|
<label className='label'>
|
||||||
<span className='label-text'>Project name</span>
|
<span className='label-text'>{t('project_name')}</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type='text'
|
type='text'
|
||||||
|
@ -76,7 +80,7 @@ const AddProject = () => {
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button className={classNames('btn-primary btn', loading ? 'loading' : '')}>
|
<button className={classNames('btn-primary btn', loading ? 'loading' : '')}>
|
||||||
Create Project
|
{t('create_project')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import RetracedEventsBrowser from '@retracedhq/logs-viewer';
|
import RetracedEventsBrowser from '@retracedhq/logs-viewer';
|
||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
|
||||||
import type { ApiError, ApiSuccess } from 'types';
|
import type { ApiError, ApiSuccess } from 'types';
|
||||||
import type { Project } from 'types/retraced';
|
import type { Project } from 'types/retraced';
|
||||||
|
@ -8,6 +9,8 @@ import Loading from '@components/Loading';
|
||||||
import { fetcher } from '@lib/ui/utils';
|
import { fetcher } from '@lib/ui/utils';
|
||||||
|
|
||||||
const LogsViewer = (props: { project: Project; environmentId: string; groupId: string; host: string }) => {
|
const LogsViewer = (props: { project: Project; environmentId: string; groupId: string; host: string }) => {
|
||||||
|
const { t } = useTranslation('common');
|
||||||
|
|
||||||
const { project, environmentId, groupId, host } = props;
|
const { project, environmentId, groupId, host } = props;
|
||||||
|
|
||||||
const token = project.tokens.filter((token) => token.environment_id === environmentId)[0];
|
const token = project.tokens.filter((token) => token.environment_id === environmentId)[0];
|
||||||
|
@ -36,7 +39,7 @@ const LogsViewer = (props: { project: Project; environmentId: string; groupId: s
|
||||||
<RetracedEventsBrowser
|
<RetracedEventsBrowser
|
||||||
host={`${host}/viewer/v1`}
|
host={`${host}/viewer/v1`}
|
||||||
auditLogToken={viewerToken}
|
auditLogToken={viewerToken}
|
||||||
header='Audit Logs'
|
header={t('audit_logs')}
|
||||||
customClass={'text-primary dark:text-white'}
|
customClass={'text-primary dark:text-white'}
|
||||||
skipViewLogEvent={true}
|
skipViewLogEvent={true}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -19,7 +19,7 @@ const ProjectDetails = (props: { project: Project; host?: string }) => {
|
||||||
<>
|
<>
|
||||||
<div className='form-control mb-5 max-w-xs'>
|
<div className='form-control mb-5 max-w-xs'>
|
||||||
<label className='label pl-0'>
|
<label className='label pl-0'>
|
||||||
<span className='label-text'>Environment</span>
|
<span className='label-text'>{t('environment')}</span>
|
||||||
</label>
|
</label>
|
||||||
<Select
|
<Select
|
||||||
value={selectedIndex}
|
value={selectedIndex}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
import { ButtonPrimary } from '@components/ButtonPrimary';
|
import { ButtonPrimary } from '@components/ButtonPrimary';
|
||||||
|
|
||||||
const NextButton = () => {
|
const NextButton = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const { t } = useTranslation('common');
|
||||||
|
|
||||||
const onClick = () => {
|
const onClick = () => {
|
||||||
const { idp, step, token } = router.query as { idp: string; step: string; token: string };
|
const { idp, step, token } = router.query as { idp: string; step: string; token: string };
|
||||||
|
@ -20,7 +21,7 @@ const NextButton = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ButtonPrimary onClick={onClick}>Next Step</ButtonPrimary>
|
<ButtonPrimary onClick={onClick}>{t('next_step')}</ButtonPrimary>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
import { ButtonOutline } from '@components/ButtonOutline';
|
import { ButtonOutline } from '@components/ButtonOutline';
|
||||||
|
|
||||||
const PreviousButton = () => {
|
const PreviousButton = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const { t } = useTranslation('common');
|
||||||
|
|
||||||
const onClick = () => {
|
const onClick = () => {
|
||||||
const { idp, step, token } = router.query as { idp: string; step: string; token: string };
|
const { idp, step, token } = router.query as { idp: string; step: string; token: string };
|
||||||
|
@ -20,7 +21,7 @@ const PreviousButton = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ButtonOutline onClick={onClick}>Previous Step</ButtonOutline>
|
<ButtonOutline onClick={onClick}>{t('previous_step')}</ButtonOutline>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -196,7 +196,7 @@ const CreateSetupLink = ({ service }: { service: SetupLinkService }) => {
|
||||||
<textarea
|
<textarea
|
||||||
id={'redirectUrl'}
|
id={'redirectUrl'}
|
||||||
name='redirectUrl'
|
name='redirectUrl'
|
||||||
placeholder={'Allowed redirect URLs (newline separated)'}
|
placeholder={t('allowed_redirect_url')}
|
||||||
value={formObj['redirectUrl']}
|
value={formObj['redirectUrl']}
|
||||||
required
|
required
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
|
||||||
const InvalidSetupLinkAlert = ({ message }: { message: string }) => {
|
const InvalidSetupLinkAlert = ({ message }: { message: string }) => {
|
||||||
|
const { t } = useTranslation('common');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col gap-3 rounded border border-error p-4'>
|
<div className='flex flex-col gap-3 rounded border border-error p-4'>
|
||||||
<h3 className='text-base font-medium'>{message}</h3>
|
<h3 className='text-base font-medium'>{message}</h3>
|
||||||
<p className='leading-6'>
|
<p className='leading-6'>{t('invalid_setup_link_alert')}</p>
|
||||||
Please contact your administrator to get a new setup link. If you are the administrator, visit the
|
|
||||||
Admin Portal to create a new setup link for the service.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,13 +23,10 @@ export const SetupLinkInfo = ({ setupLink, visible, onClose }: SetupLinkInfoProp
|
||||||
title={`Setup link info: tenant '${setupLink.tenant}', product '${setupLink.product}'`}>
|
title={`Setup link info: tenant '${setupLink.tenant}', product '${setupLink.product}'`}>
|
||||||
<div className='mt-2 flex flex-col gap-3'>
|
<div className='mt-2 flex flex-col gap-3'>
|
||||||
<div>
|
<div>
|
||||||
<InputWithCopyButton
|
<InputWithCopyButton text={setupLink.url} label={t('share_setup_link')} />
|
||||||
text={setupLink.url}
|
|
||||||
label='Share this link with your customer to setup their service'
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<p className='text-sm'>
|
<p className='text-sm'>
|
||||||
This link is valid till{' '}
|
{t('setup_link_valid_till')}{' '}
|
||||||
<span className={new Date(setupLink.validTill) < new Date() ? 'text-red-400' : ''}>
|
<span className={new Date(setupLink.validTill) < new Date() ? 'text-red-400' : ''}>
|
||||||
{new Date(setupLink.validTill).toString()}
|
{new Date(setupLink.validTill).toString()}
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -113,11 +113,11 @@ function BlocklyComponent(props) {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='mb-6 w-full px-3 md:mb-0 md:w-1/3'>
|
<div className='mb-6 w-full px-3 md:mb-0 md:w-1/3'>
|
||||||
<ButtonPrimary onClick={uploadModel}>Publish Model</ButtonPrimary>
|
<ButtonPrimary onClick={uploadModel}>{t('publish_model')}</ButtonPrimary>
|
||||||
</div>
|
</div>
|
||||||
<div className='mb-6 w-full px-3 md:mb-0 md:w-1/3'>
|
<div className='mb-6 w-full px-3 md:mb-0 md:w-1/3'>
|
||||||
<ButtonBase color='secondary' onClick={toggleRetrieveConfirm}>
|
<ButtonBase color='secondary' onClick={toggleRetrieveConfirm}>
|
||||||
Retrieve Model
|
{t('retrieve_model')}
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -162,10 +162,7 @@ const UpdateApp = ({ hasValidLicense }: { hasValidLicense: boolean }) => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='pt-4'>
|
<div className='pt-4'>
|
||||||
<p className='text-base leading-6 text-gray-500'>
|
<p className='text-base leading-6 text-gray-500'>{t('customize_branding')}:</p>
|
||||||
You can customize the look and feel Identity Provider selection page by setting following
|
|
||||||
options:
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div className='form-control w-full md:w-1/2'>
|
<div className='form-control w-full md:w-1/2'>
|
||||||
<label className='label'>
|
<label className='label'>
|
||||||
|
|
|
@ -171,6 +171,8 @@
|
||||||
"assertion_encryption": "Assertion Encryption",
|
"assertion_encryption": "Assertion Encryption",
|
||||||
"sp_saml_config_title": "Service Provider (SP) SAML Configuration",
|
"sp_saml_config_title": "Service Provider (SP) SAML Configuration",
|
||||||
"sp_saml_config_description": "Your Identity Provider (IdP) will ask for the following information while configuring the SAML application. Share this information with your IT administrator.",
|
"sp_saml_config_description": "Your Identity Provider (IdP) will ask for the following information while configuring the SAML application. Share this information with your IT administrator.",
|
||||||
|
"refer_to_provider_instructions": "Refer to our <guideLink>guides</guideLink> for provider specific instructions.",
|
||||||
|
"sp_download_our_public_cert": "If you want to encrypt the assertion, you can <downloadLink>download our public certificate.</downloadLink> Otherwise select the Unencrypted option.",
|
||||||
"sp_oidc_config_title": "Service Provider (SP) OIDC Configuration",
|
"sp_oidc_config_title": "Service Provider (SP) OIDC Configuration",
|
||||||
"sp_oidc_config_description": "Your Identity Provider (IdP) will ask for the following information while configuring the OIDC application. Share this information with your IT administrator.",
|
"sp_oidc_config_description": "Your Identity Provider (IdP) will ask for the following information while configuring the OIDC application. Share this information with your IT administrator.",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
|
@ -214,5 +216,52 @@
|
||||||
"directory_domain": "Directory Domain",
|
"directory_domain": "Directory Domain",
|
||||||
"dsync_google_auth_url": "The URL that you will need to authorize the application to access your Google Directory.",
|
"dsync_google_auth_url": "The URL that you will need to authorize the application to access your Google Directory.",
|
||||||
"show_secret": "Show secret",
|
"show_secret": "Show secret",
|
||||||
"hide_secret": "Hide secret"
|
"hide_secret": "Hide secret",
|
||||||
|
"directory": "Directory",
|
||||||
|
"users": "Users",
|
||||||
|
"groups": "Groups",
|
||||||
|
"webhook_events": "Webhook Events",
|
||||||
|
"sp_metadata": "SP Metadata",
|
||||||
|
"saml_configuration": "SAML Configuration",
|
||||||
|
"saml_public_cert": "SAML Public Certificate",
|
||||||
|
"oidc_configuration": "OpenID Configuration",
|
||||||
|
"oidc_discovery": "OpenID Connect Discovery",
|
||||||
|
"idp_metadata": "IdP Metadata",
|
||||||
|
"idp_configuration": "IdP Configuration",
|
||||||
|
"idp_configuration_title": "Identity Provider Configuration",
|
||||||
|
"idp_configuration_description": "Links for SAML/OIDC IdP setup",
|
||||||
|
"idp_configuration_label": "Identity Provider Configuration links",
|
||||||
|
"auth_integration_title": "Auth integration",
|
||||||
|
"auth_integration_description": "Links for OAuth 2.0/OpenID Connect auth",
|
||||||
|
"auth_integration_label": "Auth integration links",
|
||||||
|
"saml_fed_configuration_title": "SAML Federation",
|
||||||
|
"saml_fed_configuration_description": "Links for SAML Federation app setup",
|
||||||
|
"saml_fed_configuration_label": "SAML Federation links",
|
||||||
|
"retraced_project_created": "Project created successfully",
|
||||||
|
"project_name": "Project name",
|
||||||
|
"create_project": "Create Project",
|
||||||
|
"share_setup_link": "Share this link with your customer to setup their service",
|
||||||
|
"setup_link_valid_till": "This link is valid till",
|
||||||
|
"invalid_setup_link_alert": "Please contact your administrator to get a new setup link. If you are the administrator, visit the Admin Portal to create a new setup link for the service.",
|
||||||
|
"boxyhq_admin_portal": "BoxyHQ Admin Portal",
|
||||||
|
"environment:": "Environment",
|
||||||
|
"group_or_tenant": "Group (Tenant)",
|
||||||
|
"id": "Id",
|
||||||
|
"created_at": "Created At",
|
||||||
|
"previous_step": "Previous Step",
|
||||||
|
"next_step": "Next Step",
|
||||||
|
"boxyhq_powered_by": "Powered by BoxyHQ",
|
||||||
|
"publish_model": "Publish Model",
|
||||||
|
"retrieve_model": "Retrieve Model",
|
||||||
|
"guides": "guides",
|
||||||
|
"learn_to_enable_auth_methods": "Please visit <docLink>BoxyHQ documentation</docLink> to learn how to enable the Magic Link or Email/Password authentication methods.",
|
||||||
|
"advanced_sp_saml_configuration": "Advanced Service Provider (SP) SAML Configuration",
|
||||||
|
"select_identity_provider": "Select Identity Provider",
|
||||||
|
"configure_identity_provider": "Configure {{provider}}",
|
||||||
|
"change_identity_provider": "Change Identity Provider",
|
||||||
|
"invalid_request_try_again": "Invalid request. Please try again.",
|
||||||
|
"choose_an_identity_provider_to_continue": "Choose an Identity Provider to continue. If you don't see your Identity Provider, please contact your administrator.",
|
||||||
|
"choose_an_app_to_continue": "Choose an app to continue. If you don't see your app, please contact your administrator.",
|
||||||
|
"no_saml_response_try_again": "No SAMLResponse found. Please try again.",
|
||||||
|
"customize_branding": "You can customize the look and feel Identity Provider selection page by setting following options"
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
"eslint": "8.56.0",
|
"eslint": "8.56.0",
|
||||||
"eslint-config-next": "14.0.4",
|
"eslint-config-next": "14.0.4",
|
||||||
"eslint-config-prettier": "9.1.0",
|
"eslint-config-prettier": "9.1.0",
|
||||||
|
"eslint-plugin-i18next": "6.0.3",
|
||||||
"postcss": "8.4.32",
|
"postcss": "8.4.32",
|
||||||
"prettier": "3.1.1",
|
"prettier": "3.1.1",
|
||||||
"prettier-plugin-tailwindcss": "0.5.9",
|
"prettier-plugin-tailwindcss": "0.5.9",
|
||||||
|
@ -7748,6 +7749,19 @@
|
||||||
"ms": "^2.1.1"
|
"ms": "^2.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/eslint-plugin-i18next": {
|
||||||
|
"version": "6.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/eslint-plugin-i18next/-/eslint-plugin-i18next-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-RtQXYfg6PZCjejIQ/YG+dUj/x15jPhufJ9hUDGH0kCpJ6CkVMAWOQ9exU1CrbPmzeykxLjrXkjAaOZF/V7+DOA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"requireindex": "~1.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/eslint-plugin-import": {
|
"node_modules/eslint-plugin-import": {
|
||||||
"version": "2.29.0",
|
"version": "2.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz",
|
||||||
|
@ -16871,6 +16885,15 @@
|
||||||
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
|
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/requireindex": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-LBnkqsDE7BZKvqylbmn7lTIVdpx4K/QCduRATpO5R+wtPmky/a8pN1bO2D6wXppn1497AJF9mNjqAXr6bdl9jg==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/requires-port": {
|
"node_modules/requires-port": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
||||||
|
|
|
@ -100,6 +100,7 @@
|
||||||
"eslint": "8.56.0",
|
"eslint": "8.56.0",
|
||||||
"eslint-config-next": "14.0.4",
|
"eslint-config-next": "14.0.4",
|
||||||
"eslint-config-prettier": "9.1.0",
|
"eslint-config-prettier": "9.1.0",
|
||||||
|
"eslint-plugin-i18next": "6.0.3",
|
||||||
"postcss": "8.4.32",
|
"postcss": "8.4.32",
|
||||||
"prettier": "3.1.1",
|
"prettier": "3.1.1",
|
||||||
"prettier-plugin-tailwindcss": "0.5.9",
|
"prettier-plugin-tailwindcss": "0.5.9",
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { useRouter } from 'next/router';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { useSession, getCsrfToken, signIn, SessionProvider } from 'next-auth/react';
|
import { useSession, getCsrfToken, signIn, SessionProvider } from 'next-auth/react';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation, Trans } from 'next-i18next';
|
||||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
|
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
|
||||||
import { errorToast, successToast } from '@components/Toaster';
|
import { errorToast, successToast } from '@components/Toaster';
|
||||||
import { ButtonOutline } from '@components/ButtonOutline';
|
import { ButtonOutline } from '@components/ButtonOutline';
|
||||||
|
@ -114,7 +114,9 @@ const Login = ({
|
||||||
<div className='flex justify-center'>
|
<div className='flex justify-center'>
|
||||||
<Image src='/logo.png' alt='BoxyHQ logo' width={50} height={50} />
|
<Image src='/logo.png' alt='BoxyHQ logo' width={50} height={50} />
|
||||||
</div>
|
</div>
|
||||||
<h2 className='text-center text-3xl font-extrabold text-gray-900'>BoxyHQ Admin Portal</h2>
|
<h2 className='text-center text-3xl font-extrabold text-gray-900'>
|
||||||
|
{t('boxyhq_admin_portal')}
|
||||||
|
</h2>
|
||||||
<p className='text-center text-sm text-gray-600'>{t('boxyhq_tagline')}</p>
|
<p className='text-center text-sm text-gray-600'>{t('boxyhq_tagline')}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -170,17 +172,21 @@ const Login = ({
|
||||||
{/* No login methods enabled */}
|
{/* No login methods enabled */}
|
||||||
{!isEmailPasswordEnabled && !isMagicLinkEnabled && (
|
{!isEmailPasswordEnabled && !isMagicLinkEnabled && (
|
||||||
<div className='mt-10 text-center font-medium text-gray-600'>
|
<div className='mt-10 text-center font-medium text-gray-600'>
|
||||||
<p>
|
<Trans
|
||||||
Please visit
|
i18nKey='learn_to_enable_auth_methods'
|
||||||
<a
|
t={t}
|
||||||
href='https://boxyhq.com/docs/admin-portal/overview'
|
components={{
|
||||||
target='_blank'
|
docLink: (
|
||||||
rel='noopener noreferrer'
|
<a
|
||||||
className='underline underline-offset-2'>
|
href='https://boxyhq.com/docs/admin-portal/overview'
|
||||||
BoxyHQ documentation
|
target='_blank'
|
||||||
</a>
|
rel='noopener noreferrer'
|
||||||
to learn how to enable the Magic Link or Email/Password authentication methods.
|
className='underline underline-offset-2'>
|
||||||
</p>
|
{t('documentation')}
|
||||||
|
</a>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import ErrorMessage from '@components/Error';
|
||||||
import { LinkBack } from '@components/LinkBack';
|
import { LinkBack } from '@components/LinkBack';
|
||||||
import { Select } from 'react-daisyui';
|
import { Select } from 'react-daisyui';
|
||||||
import { retracedOptions } from '@lib/env';
|
import { retracedOptions } from '@lib/env';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
|
||||||
const LogsViewer = dynamic(() => import('@components/retraced/LogsViewer'), {
|
const LogsViewer = dynamic(() => import('@components/retraced/LogsViewer'), {
|
||||||
ssr: false,
|
ssr: false,
|
||||||
|
@ -20,6 +21,7 @@ export interface Props {
|
||||||
|
|
||||||
const Events: NextPage<Props> = ({ host }: Props) => {
|
const Events: NextPage<Props> = ({ host }: Props) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const { t } = useTranslation('common');
|
||||||
|
|
||||||
const [environment, setEnvironment] = useState('');
|
const [environment, setEnvironment] = useState('');
|
||||||
const [group, setGroup] = useState('');
|
const [group, setGroup] = useState('');
|
||||||
|
@ -62,7 +64,7 @@ const Events: NextPage<Props> = ({ host }: Props) => {
|
||||||
<div className='flex space-x-2'>
|
<div className='flex space-x-2'>
|
||||||
<div className='form-control max-w-xs'>
|
<div className='form-control max-w-xs'>
|
||||||
<label className='label pl-0'>
|
<label className='label pl-0'>
|
||||||
<span className='label-text'>Environment</span>
|
<span className='label-text'>{t('environment')}</span>
|
||||||
</label>
|
</label>
|
||||||
{project ? (
|
{project ? (
|
||||||
<Select
|
<Select
|
||||||
|
@ -81,7 +83,7 @@ const Events: NextPage<Props> = ({ host }: Props) => {
|
||||||
</div>
|
</div>
|
||||||
<div className='form-control max-w-xs'>
|
<div className='form-control max-w-xs'>
|
||||||
<label className='label pl-0'>
|
<label className='label pl-0'>
|
||||||
<span className='label-text'>Group (Tenant)</span>
|
<span className='label-text'>{t('group_or_tenant')}</span>
|
||||||
</label>
|
</label>
|
||||||
{groups ? (
|
{groups ? (
|
||||||
<Select
|
<Select
|
||||||
|
|
|
@ -32,7 +32,7 @@ const ProjectList: NextPage = () => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className='mb-5 flex items-center justify-between'>
|
<div className='mb-5 flex items-center justify-between'>
|
||||||
<h2 className='font-bold text-gray-700 dark:text-white md:text-xl'>Projects</h2>
|
<h2 className='font-bold text-gray-700 dark:text-white md:text-xl'>{t('projects')}</h2>
|
||||||
<LinkPrimary Icon={PlusIcon} href={'/admin/retraced/projects/new'}>
|
<LinkPrimary Icon={PlusIcon} href={'/admin/retraced/projects/new'}>
|
||||||
{t('new_project')}
|
{t('new_project')}
|
||||||
</LinkPrimary>
|
</LinkPrimary>
|
||||||
|
@ -46,16 +46,16 @@ const ProjectList: NextPage = () => {
|
||||||
<thead className='bg-gray-50 text-xs uppercase text-gray-700 dark:bg-gray-700 dark:text-gray-400'>
|
<thead className='bg-gray-50 text-xs uppercase text-gray-700 dark:bg-gray-700 dark:text-gray-400'>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope='col' className='px-6 py-3'>
|
<th scope='col' className='px-6 py-3'>
|
||||||
Name
|
{t('name')}
|
||||||
</th>
|
</th>
|
||||||
<th scope='col' className='px-6 py-3'>
|
<th scope='col' className='px-6 py-3'>
|
||||||
Id
|
{t('id')}
|
||||||
</th>
|
</th>
|
||||||
<th scope='col' className='px-6 py-3'>
|
<th scope='col' className='px-6 py-3'>
|
||||||
Created At
|
{t('created_at')}
|
||||||
</th>
|
</th>
|
||||||
<th scope='col' className='px-6 py-3'>
|
<th scope='col' className='px-6 py-3'>
|
||||||
Actions
|
{t('actions')}
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
|
@ -58,7 +58,7 @@ const SAMLTraceInspector: NextPage = () => {
|
||||||
<h3 className='text-base font-semibold leading-6 text-gray-900'>{t('trace_details')}</h3>
|
<h3 className='text-base font-semibold leading-6 text-gray-900'>{t('trace_details')}</h3>
|
||||||
<p className='mt-1 flex max-w-2xl gap-6 text-sm text-gray-500'>
|
<p className='mt-1 flex max-w-2xl gap-6 text-sm text-gray-500'>
|
||||||
<span className='whitespace-nowrap'>
|
<span className='whitespace-nowrap'>
|
||||||
<span className='font-medium text-gray-500'>TraceID:</span>
|
<span className='font-medium text-gray-500'>{t('trace_id')}</span>
|
||||||
<span className='ml-2 font-bold text-gray-700'> {traceId}</span>
|
<span className='ml-2 font-bold text-gray-700'> {traceId}</span>
|
||||||
</span>
|
</span>
|
||||||
<span className='whitespace-nowrap'>
|
<span className='whitespace-nowrap'>
|
||||||
|
|
|
@ -53,7 +53,7 @@ export default function ChooseIdPConnection({
|
||||||
{authFlow in selectors ? (
|
{authFlow in selectors ? (
|
||||||
selectors[authFlow]
|
selectors[authFlow]
|
||||||
) : (
|
) : (
|
||||||
<p className='text-center text-sm text-slate-600'>Invalid request. Please try again.</p>
|
<p className='text-center text-sm text-slate-600'>{t('invalid_request_try_again')}</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className='my-4'>
|
<div className='my-4'>
|
||||||
|
@ -98,10 +98,7 @@ const IdpSelector = ({ connections }: { connections: Connection[] }) => {
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
<p className='text-center text-sm text-slate-600'>
|
<p className='text-center text-sm text-slate-600'>{t('choose_an_identity_provider_to_continue')}</p>
|
||||||
Choose an Identity Provider to continue. If you don't see your Identity Provider, please contact
|
|
||||||
your administrator.
|
|
||||||
</p>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -143,7 +140,7 @@ const AppSelector = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!SAMLResponse) {
|
if (!SAMLResponse) {
|
||||||
return <p className='text-center text-sm text-slate-600'>No SAMLResponse found. Please try again.</p>;
|
return <p className='text-center text-sm text-slate-600'>{t('no_saml_response_try_again')}</p>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -171,9 +168,7 @@ const AppSelector = ({
|
||||||
})}
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
</form>
|
</form>
|
||||||
<p className='text-center text-sm text-slate-600'>
|
<p className='text-center text-sm text-slate-600'>{t('choose_an_app_to_continue')}</p>
|
||||||
Choose an app to continue. If you don't see your app, please contact your administrator.
|
|
||||||
</p>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,6 +3,7 @@ import type { NextPage } from 'next';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import Loading from '@components/Loading';
|
import Loading from '@components/Loading';
|
||||||
import useSetupLink from '@lib/ui/hooks/useSetupLink';
|
import useSetupLink from '@lib/ui/hooks/useSetupLink';
|
||||||
|
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
|
||||||
|
|
||||||
const SetupLinkIndexPage: NextPage = () => {
|
const SetupLinkIndexPage: NextPage = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -29,4 +30,14 @@ const SetupLinkIndexPage: NextPage = () => {
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getServerSideProps = async (context) => {
|
||||||
|
const { locale } = context;
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
...(await serverSideTranslations(locale, ['common'])),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export default SetupLinkIndexPage;
|
export default SetupLinkIndexPage;
|
||||||
|
|
|
@ -10,6 +10,7 @@ import type { GetServerSidePropsContext, InferGetServerSidePropsType } from 'nex
|
||||||
import type { MDXRemoteSerializeResult } from 'next-mdx-remote';
|
import type { MDXRemoteSerializeResult } from 'next-mdx-remote';
|
||||||
import { ArrowsRightLeftIcon } from '@heroicons/react/24/outline';
|
import { ArrowsRightLeftIcon } from '@heroicons/react/24/outline';
|
||||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
|
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
|
||||||
import jackson from '@lib/jackson';
|
import jackson from '@lib/jackson';
|
||||||
import { jacksonOptions } from '@lib/env';
|
import { jacksonOptions } from '@lib/env';
|
||||||
|
@ -24,10 +25,12 @@ import SelectIdentityProviders from '@components/setup-link-instructions/SelectI
|
||||||
type NewConnectionProps = InferGetServerSidePropsType<typeof getServerSideProps>;
|
type NewConnectionProps = InferGetServerSidePropsType<typeof getServerSideProps>;
|
||||||
|
|
||||||
const AdvancedSPConfigLink = () => {
|
const AdvancedSPConfigLink = () => {
|
||||||
|
const { t } = useTranslation('common');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='py-2'>
|
<div className='py-2'>
|
||||||
<Link href='/.well-known/saml-configuration' target='_blank' className='underline-offset-4'>
|
<Link href='/.well-known/saml-configuration' target='_blank' className='underline-offset-4'>
|
||||||
<span className='text-xs'>Advanced Service Provider (SP) SAML Configuration</span>
|
<span className='text-xs'>{t('advanced_sp_saml_configuration')}</span>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -72,6 +75,8 @@ const NewConnection = ({
|
||||||
publicCertUrl,
|
publicCertUrl,
|
||||||
oidcCallbackUrl,
|
oidcCallbackUrl,
|
||||||
}: NewConnectionProps) => {
|
}: NewConnectionProps) => {
|
||||||
|
const { t } = useTranslation('common');
|
||||||
|
|
||||||
const linkSelectIdp = { pathname: '/setup/[token]/sso-connection/new', query: { token: setupLinkToken } };
|
const linkSelectIdp = { pathname: '/setup/[token]/sso-connection/new', query: { token: setupLinkToken } };
|
||||||
|
|
||||||
const scope = {
|
const scope = {
|
||||||
|
@ -108,9 +113,9 @@ const NewConnection = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
progress = (100 / selectedIdP.stepCount) * parseInt(step);
|
progress = (100 / selectedIdP.stepCount) * parseInt(step);
|
||||||
heading = `Configure ${selectedIdP?.name}`;
|
heading = t('configure_identity_provider', { provider: selectedIdP.name });
|
||||||
} else {
|
} else {
|
||||||
heading = 'Select Identity Provider';
|
heading = t('select_identity_provider');
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -121,7 +126,7 @@ const NewConnection = ({
|
||||||
{source && (
|
{source && (
|
||||||
<Link className='btn btn-xs h-0' href={linkSelectIdp}>
|
<Link className='btn btn-xs h-0' href={linkSelectIdp}>
|
||||||
<ArrowsRightLeftIcon className='w-5 h-5' />
|
<ArrowsRightLeftIcon className='w-5 h-5' />
|
||||||
Change Identity Provider
|
{t('change_identity_provider')}
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import type { NextPage, InferGetStaticPropsType } from 'next';
|
import type { NextPage, InferGetStaticPropsType } from 'next';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation, Trans } from 'next-i18next';
|
||||||
import jackson from '@lib/jackson';
|
import jackson from '@lib/jackson';
|
||||||
import { InputWithCopyButton } from '@components/ClipboardButton';
|
import { InputWithCopyButton } from '@components/ClipboardButton';
|
||||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
|
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
|
||||||
|
@ -18,15 +18,21 @@ const SPConfig: NextPage<InferGetStaticPropsType<typeof getServerSideProps>> = (
|
||||||
<h2 className='font-bold text-gray-700 md:text-xl'>{t('sp_oidc_config_title')}</h2>
|
<h2 className='font-bold text-gray-700 md:text-xl'>{t('sp_oidc_config_title')}</h2>
|
||||||
<p className='text-sm leading-6 text-gray-800'>{t('sp_oidc_config_description')}</p>
|
<p className='text-sm leading-6 text-gray-800'>{t('sp_oidc_config_description')}</p>
|
||||||
<p className='text-sm leading-6 text-gray-600'>
|
<p className='text-sm leading-6 text-gray-600'>
|
||||||
Refer to our
|
<Trans
|
||||||
<a
|
i18nKey='refer_to_provider_instructions'
|
||||||
href='https://boxyhq.com/docs/jackson/sso-providers'
|
t={t}
|
||||||
target='_blank'
|
components={{
|
||||||
rel='noreferrer'
|
guideLink: (
|
||||||
className='underline underline-offset-4'>
|
<a
|
||||||
guides
|
href='https://boxyhq.com/docs/jackson/sso-providers'
|
||||||
</a>
|
target='_blank'
|
||||||
for provider specific instructions.
|
rel='noreferrer'
|
||||||
|
className='underline underline-offset-4'>
|
||||||
|
{t('guides')}
|
||||||
|
</a>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className='mt-6 flex flex-col gap-6'>
|
<div className='mt-6 flex flex-col gap-6'>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { NextPage, InferGetStaticPropsType } from 'next';
|
import type { NextPage, InferGetStaticPropsType } from 'next';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation, Trans } from 'next-i18next';
|
||||||
import jackson from '@lib/jackson';
|
import jackson from '@lib/jackson';
|
||||||
import { InputWithCopyButton } from '@components/ClipboardButton';
|
import { InputWithCopyButton } from '@components/ClipboardButton';
|
||||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
|
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
|
||||||
|
@ -19,15 +19,21 @@ const SPConfig: NextPage<InferGetStaticPropsType<typeof getServerSideProps>> = (
|
||||||
<h2 className='font-bold text-gray-700 md:text-xl'>{t('sp_saml_config_title')}</h2>
|
<h2 className='font-bold text-gray-700 md:text-xl'>{t('sp_saml_config_title')}</h2>
|
||||||
<p className='text-sm leading-6 text-gray-800'>{t('sp_saml_config_description')}</p>
|
<p className='text-sm leading-6 text-gray-800'>{t('sp_saml_config_description')}</p>
|
||||||
<p className='text-sm leading-6 text-gray-600'>
|
<p className='text-sm leading-6 text-gray-600'>
|
||||||
Refer to our
|
<Trans
|
||||||
<a
|
i18nKey='refer_to_provider_instructions'
|
||||||
href='https://boxyhq.com/docs/jackson/sso-providers'
|
t={t}
|
||||||
target='_blank'
|
components={{
|
||||||
rel='noreferrer'
|
guideLink: (
|
||||||
className='underline underline-offset-4'>
|
<a
|
||||||
guides
|
href='https://boxyhq.com/docs/jackson/sso-providers'
|
||||||
</a>
|
target='_blank'
|
||||||
for provider specific instructions.
|
rel='noreferrer'
|
||||||
|
className='underline underline-offset-4'>
|
||||||
|
{t('guides')}
|
||||||
|
</a>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className='mt-6 flex flex-col gap-6'>
|
<div className='mt-6 flex flex-col gap-6'>
|
||||||
|
@ -67,11 +73,20 @@ const SPConfig: NextPage<InferGetStaticPropsType<typeof getServerSideProps>> = (
|
||||||
{t('assertion_encryption')}
|
{t('assertion_encryption')}
|
||||||
</label>
|
</label>
|
||||||
<p className='text-sm'>
|
<p className='text-sm'>
|
||||||
If you want to encrypt the assertion, you can
|
<Trans
|
||||||
<Link href='/.well-known/saml.cer' className='underline underline-offset-4' target='_blank'>
|
i18nKey='sp_download_our_public_cert'
|
||||||
download our public certificate.
|
t={t}
|
||||||
</Link>
|
components={{
|
||||||
Otherwise select the Unencrypted option.
|
downloadLink: (
|
||||||
|
<Link
|
||||||
|
href='/.well-known/saml.cer'
|
||||||
|
className='underline underline-offset-4'
|
||||||
|
target='_blank'>
|
||||||
|
{t('download')}
|
||||||
|
</Link>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue