0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-04-07 23:01:25 -05:00

refactor(console): provide default rel value for external links (#5000)

This commit is contained in:
Xiao Yijun 2023-11-29 17:31:18 +08:00 committed by GitHub
parent e49e92fb6f
commit 152d2815c7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 175 additions and 104 deletions

View file

@ -42,9 +42,9 @@ function BillInfo({ cost, isManagePaymentVisible }: Props) {
components={{
a: (
<TextLink
href="https://blog.logto.io/logto-pricing-model"
target="_blank"
className={styles.articleLink}
href="https://blog.logto.io/logto-pricing-model"
targetBlank="noopener"
/>
),
}}

View file

@ -114,7 +114,7 @@ function BasicForm({
a: (
<TextLink
href={getDocumentationUrl('/docs/references/connectors/#target')}
target="_blank"
targetBlank="noopener"
onClick={closeTipHandler}
/>
),

View file

@ -103,9 +103,8 @@ function PlanCardItem({ plan, onSelect }: Props) {
<TextLink
isTrailingIcon
href={pricingLink}
targetBlank="noopener"
icon={<ArrowRight className={styles.linkIcon} />}
target="_blank"
rel="noopener"
className={styles.link}
>
<DynamicT forKey="upsell.create_tenant.view_all_features" />

View file

@ -67,9 +67,7 @@ function SelectTenantPlanModal({ tenantData, onClose }: Props) {
title="upsell.create_tenant.title"
subtitle={
<DangerousRaw>
<Trans
components={{ a: <TextLink href={pricingLink} target="_blank" rel="noopener" /> }}
>
<Trans components={{ a: <TextLink href={pricingLink} targetBlank="noopener" /> }}>
{t('upsell.create_tenant.description')}
</Trans>
</DangerousRaw>

View file

@ -3,6 +3,7 @@ import type { ReactNode } from 'react';
import DynamicT from '@/ds-components/DynamicT';
import TextLink from '@/ds-components/TextLink';
import type { Props as TextLinkProps } from '@/ds-components/TextLink';
import FormCardLayout from './FormCardLayout';
import * as styles from './index.module.scss';
@ -12,8 +13,7 @@ type Props = {
tag?: ReactNode;
description?: AdminConsoleKey;
descriptionInterpolation?: Record<string, unknown>;
learnMoreLink?: string;
learnMoreLinkText?: AdminConsoleKey;
learnMoreLink?: Pick<TextLinkProps, 'href' | 'targetBlank'> & { linkText?: AdminConsoleKey };
children: ReactNode;
};
@ -23,7 +23,6 @@ function FormCard({
description,
descriptionInterpolation,
learnMoreLink,
learnMoreLinkText,
children,
}: Props) {
return (
@ -37,11 +36,11 @@ function FormCard({
{description && (
<div className={styles.description}>
<DynamicT forKey={description} interpolation={descriptionInterpolation} />
{learnMoreLink && (
{learnMoreLink?.href && (
<>
{' '}
<TextLink href={learnMoreLink} target="_blank" rel="noopener">
<DynamicT forKey={learnMoreLinkText ?? 'general.learn_more'} />
<TextLink href={learnMoreLink.href} targetBlank={learnMoreLink.targetBlank}>
<DynamicT forKey={learnMoreLink.linkText ?? 'general.learn_more'} />
</TextLink>
</>
)}

View file

@ -83,7 +83,7 @@ function Guide({ className, guideId, isEmpty, isLoading, onClose }: Props) {
);
},
a: ({ children, ...props }) => (
<TextLink {...props} target="_blank" rel="noopener noreferrer">
<TextLink {...props} targetBlank>
{children}
</TextLink>
),

View file

@ -165,7 +165,10 @@ function PermissionsTable({
imageDark={<PermissionsEmptyDark />}
title="permissions.placeholder_title"
description="permissions.placeholder_description"
learnMoreLink={getDocumentationUrl('/docs/recipes/rbac/manage-permissions-and-roles')}
learnMoreLink={{
href: getDocumentationUrl('/docs/recipes/rbac/manage-permissions-and-roles'),
targetBlank: 'noopener',
}}
action={
<Button
title={createButtonTitle}

View file

@ -12,7 +12,7 @@ function DocumentNavButton() {
return (
<TextLink
href={documentationSiteUrl}
target="_blank"
targetBlank="noopener"
className={classNames(styles.textLink, styles.documentNavButton)}
icon={<DocumentIcon className={styles.icon} />}
>

View file

@ -66,10 +66,10 @@ function TenantEnvMigrationModal() {
footer={
<>
<LinkButton
targetBlank
title="tenants.dev_tenant_migration.about_tenant_type"
size="large"
href={getDocumentationUrl(envTagsFeatureLink)}
targetBlank="noopener"
/>
<Button title="general.got_it" size="large" type="primary" onClick={onClose} />
</>

View file

@ -113,6 +113,8 @@ type LinkProps = Omit<HTMLProps<HTMLAnchorElement>, 'type' | 'size' | 'title' |
*
* - When it's `true`, the `rel` attribute will be set to `noopener noreferrer`.
* - When it's `noopener`, the `rel` attribute will be set to `noopener`.
*
* Typically, when navigating to Logto's website (official site, blog, documentation, etc.), use 'noopener'.
*/
targetBlank?: boolean | 'noopener';
type?: ButtonType;

View file

@ -5,6 +5,7 @@ import type { ReactElement } from 'react';
import { useTranslation } from 'react-i18next';
import FeatureTag from '@/components/FeatureTag';
import type { Props as TextLinkProps } from '@/ds-components/TextLink';
import type DangerousRaw from '../DangerousRaw';
import DynamicT from '../DynamicT';
@ -16,7 +17,7 @@ export type Props = {
title: AdminConsoleKey | ReactElement<typeof DangerousRaw>;
subtitle?: AdminConsoleKey | ReactElement<typeof DangerousRaw>;
size?: 'small' | 'medium' | 'large';
learnMoreLink?: string;
learnMoreLink?: Pick<TextLinkProps, 'href' | 'targetBlank'>;
isWordWrapEnabled?: boolean;
className?: string;
/** If a beta tag should be shown next to the title. */
@ -56,8 +57,12 @@ function CardTitle({
{subtitle && (
<span>{typeof subtitle === 'string' ? <DynamicT forKey={subtitle} /> : subtitle}</span>
)}
{learnMoreLink && (
<TextLink href={learnMoreLink} target="_blank" className={styles.learnMore}>
{learnMoreLink?.href && (
<TextLink
href={learnMoreLink.href}
targetBlank={learnMoreLink.targetBlank}
className={styles.learnMore}
>
{t('general.learn_more')}
</TextLink>
)}

View file

@ -6,6 +6,7 @@ import type { ReactNode, Ref } from 'react';
import Info from '@/assets/icons/info.svg';
import Error from '@/assets/icons/toast-error.svg';
import Success from '@/assets/icons/toast-success.svg';
import type { Props as TextLinkProps } from '@/ds-components/TextLink';
import Button from '../Button';
import DynamicT from '../DynamicT';
@ -18,6 +19,7 @@ type Props = {
children?: ReactNode;
action?: AdminConsoleKey;
href?: string;
hrefTargetBlank?: TextLinkProps['targetBlank'];
onClick?: () => void;
variant?: 'plain' | 'shadow';
hasIcon?: boolean;
@ -48,6 +50,7 @@ function InlineNotification(
children,
action,
href,
hrefTargetBlank,
onClick,
severity = 'info',
variant = 'plain',
@ -74,7 +77,7 @@ function InlineNotification(
)}
<div className={styles.content}>{children}</div>
{action && href && (
<TextLink to={href}>
<TextLink to={href} targetBlank={hrefTargetBlank}>
<DynamicT forKey={action} />
</TextLink>
)}

View file

@ -3,6 +3,7 @@ import { Theme } from '@logto/schemas';
import type { ReactNode } from 'react';
import { useTranslation } from 'react-i18next';
import type { Props as TextLinkProps } from '@/ds-components/TextLink';
import useTheme from '@/hooks/use-theme';
import DynamicT from '../DynamicT';
@ -15,7 +16,7 @@ type Props = {
imageDark: ReactNode;
title: AdminConsoleKey;
description: AdminConsoleKey;
learnMoreLink?: string;
learnMoreLink?: Pick<TextLinkProps, 'href' | 'targetBlank'>;
action: ReactNode;
};
@ -31,10 +32,10 @@ function TablePlaceholder({ image, imageDark, title, description, learnMoreLink,
</div>
<div className={styles.description}>
<DynamicT forKey={description} />
{learnMoreLink && (
{learnMoreLink?.href && (
<>
{' '}
<TextLink href={learnMoreLink} target="_blank" rel="noopener">
<TextLink href={learnMoreLink.href} targetBlank={learnMoreLink.targetBlank}>
{t('general.learn_more')}
</TextLink>
</>

View file

@ -1,26 +1,59 @@
import classNames from 'classnames';
import type { AnchorHTMLAttributes, ReactNode } from 'react';
import { useMemo, type AnchorHTMLAttributes, type ReactNode } from 'react';
import type { LinkProps } from 'react-router-dom';
import { Link } from 'react-router-dom';
// Used in the docs
// eslint-disable-next-line unused-imports/no-unused-imports
import { LinkButton } from '@/ds-components/Button';
import useTenantPathname from '@/hooks/use-tenant-pathname';
import * as styles from './index.module.scss';
type Props = AnchorHTMLAttributes<HTMLAnchorElement> &
export type Props = AnchorHTMLAttributes<HTMLAnchorElement> &
Partial<LinkProps> & {
icon?: ReactNode;
isTrailingIcon?: boolean;
/**
* If the link will be opened in a new tab. This prop will override the `target`
* and `rel` attributes.
*
* - When it's `true`, the `rel` attribute will be set to `noopener noreferrer`.
* - When it's `noopener`, the `rel` attribute will be set to `noopener`.
*
* Typically, when navigating to Logto's website (official site, blog, documentation, etc.), use 'noopener'.
*
* Note: This prop is align with the `targetBlank` prop of {@link LinkButton}, they share the same logic.
*/
targetBlank?: boolean | 'noopener';
};
function TextLink({ to, children, icon, isTrailingIcon = false, className, ...rest }: Props) {
function TextLink({
to,
children,
icon,
isTrailingIcon = false,
className,
targetBlank,
...rest
}: Props) {
const { getTo } = useTenantPathname();
const styleClassNames = classNames(styles.link, isTrailingIcon && styles.trailingIcon, className);
const props = useMemo(
() => ({
...rest,
className: classNames(styles.link, isTrailingIcon && styles.trailingIcon, className),
...(Boolean(targetBlank) && {
rel: typeof targetBlank === 'string' ? targetBlank : 'noopener noreferrer',
target: '_blank',
}),
}),
[className, isTrailingIcon, rest, targetBlank]
);
if (to) {
return (
<Link to={getTo(to)} className={styleClassNames} {...rest}>
<Link to={getTo(to)} {...props}>
{icon}
{children}
</Link>
@ -28,7 +61,7 @@ function TextLink({ to, children, icon, isTrailingIcon = false, className, ...re
}
return (
<a className={styleClassNames} {...rest}>
<a {...props}>
{icon}
{children}
</a>

View file

@ -23,8 +23,8 @@ function ApplicationCredentials() {
components={{
a: (
<TextLink
targetBlank
href="https://openid.net/specs/openid-connect-core-1_0.html"
target="_blank"
onClick={closeTipHandler}
/>
),

View file

@ -29,10 +29,10 @@ export default function Sample() {
</hgroup>
<Spacer />
<LinkButton
targetBlank
type="outline"
href={appendPath(new URL(githubOrgLink), sample.repo, 'tree/HEAD', sample.path).href}
title={<DangerousRaw>Check out sample</DangerousRaw>}
targetBlank="noopener"
/>
</aside>
);

View file

@ -11,19 +11,14 @@ function FurtherReadings(props: Props, ref?: Ref<HTMLDivElement>) {
<Step ref={ref} {...props}>
<ul>
<li>
<TextLink
target="blank"
rel="noopener"
href="https://docs.logto.io/docs/recipes/customize-sie/"
>
<TextLink href="https://docs.logto.io/docs/recipes/customize-sie/" targetBlank="noopener">
Customize sign-in experience
</TextLink>
</li>
<li>
<TextLink
target="blank"
rel="noopener"
href="https://docs.logto.io/docs/recipes/protect-your-api/"
targetBlank="noopener"
>
Protect your API
</TextLink>

View file

@ -72,7 +72,10 @@ function CreatePermissionModal({ resourceId, totalResourceCount, onClose }: Prop
<ModalLayout
title="api_resource_details.permission.create_title"
subtitle="api_resource_details.permission.create_subtitle"
learnMoreLink="https://docs.logto.io/docs/recipes/rbac/manage-permissions-and-roles#manage-role-permissions"
learnMoreLink={{
href: 'https://docs.logto.io/docs/recipes/rbac/manage-permissions-and-roles#manage-role-permissions',
targetBlank: 'noopener',
}}
footer={
isScopesPerResourceReachLimit && currentPlan ? (
<QuotaGuardFooter>

View file

@ -71,11 +71,14 @@ function ApiResourceSettings() {
? 'api_resource_details.management_api_settings_description'
: 'api_resource_details.settings_description'
}
learnMoreLink={getDocumentationUrl(
isLogtoManagementApiResource
? '/docs/recipes/interact-with-management-api/'
: '/docs/recipes/protect-your-api/'
)}
learnMoreLink={{
href: getDocumentationUrl(
isLogtoManagementApiResource
? '/docs/recipes/interact-with-management-api/'
: '/docs/recipes/protect-your-api/'
),
targetBlank: 'noopener',
}}
>
<FormField isRequired title="api_resources.api_name">
<TextInput
@ -106,7 +109,7 @@ function ApiResourceSettings() {
a: (
<TextLink
href="https://docs.logto.io/docs/references/resources/#default-api"
target="_blank"
targetBlank="noopener"
/>
),
}}

View file

@ -26,7 +26,7 @@ function ManagementApiNotice() {
>
<Trans
components={{
a: <TextLink href={learnMoreLink} target="_blank" rel="noopener" />,
a: <TextLink href={learnMoreLink} targetBlank="noopener" />,
}}
>
{t('api_resource_details.management_api_notice')}

View file

@ -123,8 +123,8 @@ function CreateForm({ onClose }: Props) {
components={{
a: (
<TextLink
targetBlank
href="https://datatracker.ietf.org/doc/html/rfc8707#section-2"
target="_blank"
onClick={closeTipHandler}
/>
),

View file

@ -49,7 +49,10 @@ function AdvancedSettings({ app: { type }, oidcConfig }: Props) {
<FormCard
title="application_details.advanced_settings"
description="application_details.advanced_settings_description"
learnMoreLink="https://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint"
learnMoreLink={{
href: 'https://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint',
targetBlank: true,
}}
>
{tenantEndpoint && (
<FormField title="application_details.config_endpoint">
@ -67,8 +70,8 @@ function AdvancedSettings({ app: { type }, oidcConfig }: Props) {
components={{
a: (
<TextLink
targetBlank
href="https://openid.net/specs/openid-connect-core-1_0.html#Authentication"
target="_blank"
onClick={closeTipHandler}
/>
),
@ -127,7 +130,7 @@ function AdvancedSettings({ app: { type }, oidcConfig }: Props) {
a: (
<TextLink
href="https://docs.logto.io/docs/references/applications/#rotate-refresh-token"
target="_blank"
targetBlank="noopener"
/>
),
}}

View file

@ -52,7 +52,10 @@ function Settings({ data }: Props) {
<FormCard
title="application_details.settings"
description="application_details.settings_description"
learnMoreLink={getDocumentationUrl('/docs/references/applications')}
learnMoreLink={{
href: getDocumentationUrl('/docs/references/applications'),
targetBlank: 'noopener',
}}
>
<FormField isRequired title="application_details.application_name">
<TextInput
@ -108,8 +111,8 @@ function Settings({ data }: Props) {
components={{
a: (
<TextLink
targetBlank
href="https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest"
target="_blank"
onClick={closeTipHandler}
/>
),
@ -163,8 +166,8 @@ function Settings({ data }: Props) {
components={{
a: (
<TextLink
targetBlank
href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"
target="_blank"
onClick={closeTipHandler}
/>
),

View file

@ -53,10 +53,13 @@ function EmailServiceConnectorForm({ extraInfo }: Props) {
<FormCard
title="connector_details.logto_email.email_template_title"
description="connector_details.logto_email.template_description"
learnMoreLink={getDocumentationUrl(
'/docs/recipes/configure-connectors/email-connector/configure-logto-email-service/#unified-email-templates'
)}
learnMoreLinkText="connector_details.logto_email.template_description_link_text"
learnMoreLink={{
href: getDocumentationUrl(
'/docs/recipes/configure-connectors/email-connector/configure-logto-email-service/#unified-email-templates'
),
targetBlank: 'noopener',
linkText: 'connector_details.logto_email.template_description_link_text',
}}
>
<FormField title="connector_details.logto_email.from_email_field">
<TextInput

View file

@ -134,7 +134,10 @@ function ConnectorContent({ isDeleted, connectorData, onConnectorUpdated }: Prop
<FormCard
title="connector_details.settings"
description="connector_details.settings_description"
learnMoreLink={getDocumentationUrl('/docs/references/connectors')}
learnMoreLink={{
href: getDocumentationUrl('/docs/references/connectors'),
targetBlank: 'noopener',
}}
>
<BasicForm isStandard={isStandardConnector} isDarkDefaultVisible={Boolean(logoDark)} />
</FormCard>
@ -148,7 +151,10 @@ function ConnectorContent({ isDeleted, connectorData, onConnectorUpdated }: Prop
!isSocialConnector && 'connector_details.settings_description'
)}
learnMoreLink={conditional(
!isSocialConnector && getDocumentationUrl('/docs/references/connectors')
!isSocialConnector && {
href: getDocumentationUrl('/docs/references/connectors'),
targetBlank: 'noopener',
}
)}
>
<ConfigForm formItems={formItems} connectorId={id} connectorType={connectorType} />

View file

@ -42,7 +42,7 @@ function EmailUsage({ usage, isCompact }: Props) {
href={getDocumentationUrl(
'docs/recipes/configure-connectors/email-connector/configure-logto-email-service'
)}
target="_blank"
targetBlank="noopener"
onClick={closeTipHandler}
/>
),

View file

@ -183,9 +183,12 @@ function Connectors() {
imageDark={<SocialConnectorEmptyDark />}
title="connectors.placeholder_title"
description="connectors.placeholder_description"
learnMoreLink={getDocumentationUrl(
'/docs/recipes/configure-connectors/configure-social-connector'
)}
learnMoreLink={{
href: getDocumentationUrl(
'/docs/recipes/configure-connectors/configure-social-connector'
),
targetBlank: 'noopener',
}}
action={
<Button
title="connectors.create"

View file

@ -35,7 +35,7 @@ function SsoGuide({ ssoConnector, className }: Props) {
<MDXProvider
components={{
a: ({ children, ...props }) => (
<TextLink {...props} target="_blank" rel="noopener noreferrer">
<TextLink {...props} targetBlank>
{children}
</TextLink>
),

View file

@ -25,14 +25,7 @@ function DevelopmentTenantNotification() {
<div className={styles.title}>
<Trans
components={{
a: (
<TextLink
href={pricingLink}
target="_blank"
rel="noopener"
className={styles.link}
/>
),
a: <TextLink href={pricingLink} targetBlank="noopener" className={styles.link} />,
}}
>
{t('tenants.dev_tenant_notification.title')}
@ -43,11 +36,11 @@ function DevelopmentTenantNotification() {
</div>
</div>
<LinkButton
targetBlank
title="general.learn_more"
type="outline"
size="large"
href={getDocumentationUrl(envTagsFeatureLink)}
targetBlank="noopener"
/>
</div>
);

View file

@ -150,7 +150,7 @@ function GetStarted() {
<LinkButton
title="get_started.customize.try_now"
href={new URL('/demo-app', tenantEndpoint).href}
target="_blank"
targetBlank="noopener"
/>
</div>
</div>

View file

@ -93,7 +93,10 @@ function MfaForm({ data, onMfaUpdated }: Props) {
<FormCard
title="mfa.factors"
description="mfa.multi_factors_description"
learnMoreLink={getDocumentationUrl('/docs/recipes/multi-factor-auth/config-mfa')}
learnMoreLink={{
href: getDocumentationUrl('/docs/recipes/multi-factor-auth/configure-mfa'),
targetBlank: 'noopener',
}}
>
<FormField title="mfa.multi_factors" headlineSpacing="large">
<div className={styles.factorField}>

View file

@ -83,11 +83,7 @@ function OrganizationInfo() {
{/* TODO: @charles Documentation links will be updated later */}
<ul>
<li>
<TextLink
target="blank"
rel="noopener"
href="https://docs.logto.io/docs/tutorials/"
>
<TextLink href="https://docs.logto.io/docs/tutorials/" targetBlank="noopener">
{t('guide.add_members_action')}
</TextLink>
</li>

View file

@ -76,7 +76,10 @@ function AssignPermissionsModal({ roleId, roleType, totalRoleScopeCount, onClose
<ModalLayout
title="role_details.permission.assign_title"
subtitle="role_details.permission.assign_subtitle"
learnMoreLink="https://docs.logto.io/docs/recipes/rbac/manage-permissions-and-roles#manage-role-permissions"
learnMoreLink={{
href: 'https://docs.logto.io/docs/recipes/rbac/manage-permissions-and-roles#manage-role-permissions',
targetBlank: 'noopener',
}}
size="large"
footer={
shouldBlockScopeAssignment && currentPlan ? (

View file

@ -52,7 +52,10 @@ function RoleSettings() {
<FormCard
title="role_details.settings"
description="role_details.settings_description"
learnMoreLink="https://docs.logto.io/docs/recipes/rbac/manage-permissions-and-roles#manage-roles"
learnMoreLink={{
href: 'https://docs.logto.io/docs/recipes/rbac/manage-permissions-and-roles#manage-roles',
targetBlank: 'noopener',
}}
>
<FormField isRequired title="role_details.field_name">
<TextInput {...register('name', { required: true })} error={Boolean(errors.name)} />

View file

@ -104,7 +104,10 @@ function CreateRoleForm({ totalRoleCount, onClose }: Props) {
<ModalLayout
title="roles.create_role_title"
subtitle="roles.create_role_description"
learnMoreLink="https://docs.logto.io/docs/recipes/rbac/manage-permissions-and-roles#manage-roles"
learnMoreLink={{
href: 'https://docs.logto.io/docs/recipes/rbac/manage-permissions-and-roles#manage-roles',
targetBlank: 'noopener',
}}
size="large"
footer={(() => {
if (

View file

@ -74,8 +74,10 @@ function Roles() {
title={{
title: 'roles.title',
subtitle: 'roles.subtitle',
learnMoreLink:
'https://docs.logto.io/docs/recipes/rbac/manage-permissions-and-roles#manage-roles',
learnMoreLink: {
href: 'https://docs.logto.io/docs/recipes/rbac/manage-permissions-and-roles#manage-roles',
targetBlank: 'noopener',
},
}}
pageMeta={{ titleKey: 'roles.page_title' }}
createButton={{
@ -172,9 +174,12 @@ function Roles() {
imageDark={<RolesEmptyDark />}
title="roles.placeholder_title"
description="roles.placeholder_description"
learnMoreLink={getDocumentationUrl(
'/docs/recipes/rbac/manage-permissions-and-roles#manage-roles'
)}
learnMoreLink={{
href: getDocumentationUrl(
'/docs/recipes/rbac/manage-permissions-and-roles#manage-roles'
),
targetBlank: 'noopener',
}}
action={
<Button
title="roles.create"

View file

@ -30,8 +30,8 @@ function CustomCssForm() {
components={{
a: (
<TextLink
targetBlank="noopener"
href={getDocumentationUrl('/docs/recipes/customize-sie/custom-css')}
target="_blank"
onClick={closeTipHandler}
/>
),

View file

@ -81,9 +81,8 @@ function PasswordPolicy({ isActive }: Props) {
components={{
a: (
<TextLink
targetBlank
href="https://pages.nist.gov/800-63-3/sp800-63b.html#sec5"
target="_blank"
rel="noopener"
/>
),
}}

View file

@ -22,13 +22,7 @@ function TenantEnvironment({ tag }: Props) {
<div className={styles.description}>
<Trans
components={{
a: (
<TextLink
href={getDocumentationUrl(envTagsFeatureLink)}
target="_blank"
rel="noopener"
/>
),
a: <TextLink targetBlank="noopener" href={getDocumentationUrl(envTagsFeatureLink)} />,
}}
>
{t(

View file

@ -16,7 +16,7 @@ function TenantRegion() {
<div className={styles.regionTip}>
<Trans
components={{
a: <TextLink href={trustAndSecurityLink} target="_blank" rel="noopener" />,
a: <TextLink targetBlank="noopener" href={trustAndSecurityLink} />,
}}
>
{t('tenants.settings.tenant_region_tip', { region: 'EU' })}

View file

@ -34,6 +34,7 @@ function CustomDomain({ customDomain, onDeleteCustomDomain }: Props) {
components={{
a: (
<TextLink
targetBlank="noopener"
to={getDocumentationUrl('docs/recipes/custom-domain/use-custom-domain')}
/>
),

View file

@ -27,7 +27,10 @@ function TenantDomainSettings() {
<FormCard
title="domain.custom.custom_domain"
description="domain.custom.custom_domain_description"
learnMoreLink={getDocumentationUrl('docs/recipes/custom-domain')}
learnMoreLink={{
href: getDocumentationUrl('docs/recipes/custom-domain'),
targetBlank: 'noopener',
}}
>
<FormField title="domain.custom.custom_domain_field">
{customDomain ? (

View file

@ -102,7 +102,10 @@ function UserSettings() {
<FormCard
title="user_details.authentication"
description="user_details.authentication_description"
learnMoreLink={getDocumentationUrl('/docs/references/users')}
learnMoreLink={{
href: getDocumentationUrl('/docs/references/users'),
targetBlank: 'noopener',
}}
>
<FormField title="user_details.field_email">
<TextInput

View file

@ -58,7 +58,10 @@ function WebhookSettings() {
<FormCard
title="webhook_details.settings.settings"
description="webhook_details.settings.settings_description"
learnMoreLink={getDocumentationUrl('/docs/recipes/webhooks')}
learnMoreLink={{
href: getDocumentationUrl('/docs/recipes/webhooks'),
targetBlank: 'noopener',
}}
>
<BasicWebhookForm />
<SigningKeyField