Tweaks to well-known links listing page (#765)

* wip

* Move the links to /well-known and update the UI

* Infer the props type

* localised strings

* switched to LinkOutline

Co-authored-by: Deepak Prabhakara <deepak@boxyhq.com>
This commit is contained in:
Kiran K 2022-12-24 04:13:04 +05:30 committed by GitHub
parent 94ec2a6bc1
commit fb1c504222
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 166 additions and 73 deletions

View File

@ -1,27 +1,34 @@
import Link from 'next/link';
import classNames from 'classnames';
export interface LinkProps {
export type LinkProps = {
href: string;
children: any;
Icon?: any;
onClick?: any;
}
interface LinkBaseProps extends LinkProps {
target?: string;
rel?: string;
className?: string;
}
};
export const LinkBase = ({
href,
onClick,
className = '',
children,
target,
rel,
Icon = null,
...others
}: LinkBaseProps) => {
}: LinkProps) => {
return (
<Link href={href} onClick={onClick} className={classNames('btn m-2', className)} {...others}>
<Link
href={href}
onClick={onClick}
className={classNames('btn m-2', className)}
target={target}
rel={rel}
{...others}>
{Icon && <Icon className='mr-1 h-4 w-4' aria-hidden />}
{children}
</Link>

View File

@ -1,9 +1,22 @@
import classNames from 'classnames';
import type { LinkProps } from './LinkBase';
import { LinkBase } from './LinkBase';
export const LinkOutline = ({ href, onClick, children, Icon = null, ...others }: LinkProps) => {
export const LinkOutline = ({
href,
onClick,
children,
className = '',
Icon = null,
...others
}: LinkProps) => {
return (
<LinkBase href={href} onClick={onClick} className='btn-outline' Icon={Icon} {...others}>
<LinkBase
href={href}
onClick={onClick}
className={classNames('btn-outline', className)}
Icon={Icon}
{...others}>
{children}
</LinkBase>
);

View File

@ -1,68 +1,104 @@
import { ArrowRightOnRectangleIcon } from '@heroicons/react/20/solid';
import { ArrowTopRightOnSquareIcon } from '@heroicons/react/20/solid';
import Link from 'next/link';
import { useTranslation } from 'next-i18next';
import { LinkOutline } from '@components/LinkOutline';
const links = [
{
title: 'SP Metadata',
description:
'The metadata file that your customers who use federated management systems like OpenAthens and Shibboleth will need to configure your service.',
href: '/.well-known/sp-metadata',
},
{
title: 'SAML Configuration',
description:
'The configuration setup guide that your customers will need to refer to when setting up SAML application with their Identity Provider.',
href: '/.well-known/saml-configuration',
},
{
title: 'SAML Public Certificate',
description: 'The SAML Public Certificate if you want to enable encryption with your Identity Provider.',
href: '/.well-known/saml.cer',
},
{
title: 'OpenID Configuration',
description:
'Our OpenID configuration URI which your customers will need if they are connecting via OAuth 2.0 or Open ID Connect.',
href: '/.well-known/openid-configuration',
},
{
title: 'IdP Metadata',
description:
'The metadata file that your customers who use our SAML federation feature will need to set up SAML SP configuration on their application.',
href: '/.well-known/idp-metadata',
},
{
title: 'IdP Configuration',
description:
'The configuration setup guide that your customers who use our SAML federation feature will need to set up SAML SP configuration on their application.',
href: '/.well-known/idp-configuration',
},
];
const WellKnownURLs = ({ className }: { className?: string }) => {
const WellKnownURLs = () => {
const { t } = useTranslation('common');
const viewText = t('view');
const downloadText = t('download');
const links = [
{
title: 'SP Metadata',
description: t('sp_metadata_description'),
href: '/.well-known/sp-metadata',
buttonText: viewText,
},
{
title: 'SAML Configuration',
description: t('sp_config_description'),
href: '/.well-known/saml-configuration',
buttonText: viewText,
},
{
title: 'SAML Public Certificate',
description: t('saml_public_cert_description'),
href: '/.well-known/saml.cer',
buttonText: downloadText,
},
{
title: 'OpenID Configuration',
description: t('oidc_config_description'),
href: '/.well-known/openid-configuration',
buttonText: viewText,
},
{
title: 'IdP Metadata',
description: t('idp_metadata_description'),
href: '/.well-known/idp-metadata',
buttonText: viewText,
},
{
title: 'IdP Configuration',
description: t('idp_config_description'),
href: '/.well-known/idp-configuration',
buttonText: viewText,
},
];
return (
<div className={className}>
<p>{t('here_are_the_set_of_uris_you_would_need_access_to')}:</p>
<br />
<ul className='flex flex-col space-y-1'>
{links.map((link) => {
return (
<li key={link.href} className='text-sm'>
<p>{link.description}</p>
<Link
href={link.href}
target='_blank'
rel='noreferrer'
className='link flex hover:link-primary'>
<ArrowRightOnRectangleIcon className='mr-1 h-5 w-5' aria-hidden /> {link.title}
</Link>
<br />
</li>
);
})}
</ul>
<>
<div className='mb-5 flex items-center justify-between'>
<h2 className='font-bold text-gray-700 dark:text-white md:text-xl'>
{t('here_are_the_set_of_uris_you_would_need_access_to')}:
</h2>
</div>
<div className='space-y-3'>
{links.map((link) => (
<LinkCard
key={link.href}
title={link.title}
description={link.description}
href={link.href}
buttonText={link.buttonText}
/>
))}
</div>
</>
);
};
const LinkCard = ({
title,
description,
href,
buttonText,
}: {
title: string;
description: string;
href: string;
buttonText: string;
}) => {
return (
<div className='space-y-2 rounded-md border p-4 hover:border-gray-400'>
<div className='flex items-center justify-between'>
<div className='space-y-2'>
<h3 className='font-bold'>{title}</h3>
<p className='text-[15px]'>{description}</p>
</div>
<div className='mx-4'>
<LinkOutline
className='w-32'
href={href}
target='_blank'
rel='noreferrer'
Icon={ArrowTopRightOnSquareIcon}>
{buttonText}
</LinkOutline>
</div>
</div>
</div>
);
};

View File

@ -9,7 +9,7 @@ const Metadata: NextPage<any> = ({ metadata }) => {
return (
<LicenseRequired>
<div className='my-10 mx-5 flex h-screen justify-center'>
<div className='my-10 mx-5 flex justify-center'>
<div className='rounded border border-gray-200 bg-white p-6 dark:border-gray-700 dark:bg-gray-800'>
<h2 className='mb-5 mt-5 font-bold text-gray-700 md:text-xl'>{t('saml_federation_app_info')}</h2>
<div className='flex flex-col'>

View File

@ -109,5 +109,11 @@
"new_saml_federation_app": "New App",
"view": "View",
"view_idp_configuration": "View IdP Configuration",
"edit": "Edit"
"edit": "Edit",
"sp_metadata_description": "The metadata file that your customers who use federated management systems like OpenAthens and Shibboleth will need to configure your service.",
"sp_config_description": "The configuration setup guide that your customers will need to refer to when setting up SAML application with their Identity Provider.",
"saml_public_cert_description": "The SAML Public Certificate if you want to enable encryption with your Identity Provider.",
"oidc_config_description": "Our OpenID configuration URI which your customers will need if they are connecting via OAuth 2.0 or Open ID Connect.",
"idp_metadata_description": "The metadata file that your customers who use our SAML federation feature will need to set up SAML SP configuration on their application.",
"idp_config_description": "The configuration setup guide that your customers who use our SAML federation feature will need to set up SAML SP configuration on their application."
}

View File

@ -70,6 +70,10 @@ module.exports = {
source: '/admin/directory-sync/setup-link/new',
destination: '/admin/setup-link/new',
},
{
source: '/.well-known',
destination: '/well-known',
},
];
},
};

View File

@ -21,6 +21,7 @@ const unauthenticatedRoutes = [
'/oauth/jwks',
'/idp/select',
'/error',
'/well-known',
];
const isUnauthenticatedRoute = (pathname: string) => {

View File

@ -6,11 +6,11 @@ import Image from 'next/image';
import { SessionProvider } from 'next-auth/react';
import { useState } from 'react';
import WellKnownURLs from '@components/connection/WellKnownURLs';
import { useTranslation } from 'next-i18next';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import { errorToast, successToast } from '@components/Toaster';
import { ButtonPrimary } from '@components/ButtonPrimary';
import Link from 'next/link';
const Login = ({ csrfToken }: InferGetServerSidePropsType<typeof getServerSideProps>) => {
const { t } = useTranslation('common');
@ -97,7 +97,9 @@ const Login = ({ csrfToken }: InferGetServerSidePropsType<typeof getServerSidePr
</form>
</div>
</div>
<WellKnownURLs className='mt-5 border p-5' />
<Link href='/.well-known' className='my-3 text-sm underline' target='_blank'>
{t('here_are_the_set_of_uris_you_would_need_access_to')}
</Link>
</div>
</>
);

View File

@ -0,0 +1,24 @@
import type { NextPage, GetServerSidePropsContext } from 'next';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import WellKnownURLs from '@components/connection/WellKnownURLs';
const WellKnownURLsIndex: NextPage = () => {
return (
<div className='my-10 mx-5 flex justify-center'>
<div className='flex flex-col'>
<WellKnownURLs />
</div>
</div>
);
};
export async function getStaticProps({ locale }: GetServerSidePropsContext) {
return {
props: {
...(locale ? await serverSideTranslations(locale, ['common']) : {}),
},
};
}
export default WellKnownURLsIndex;