feat(editor): SAML paywall state (#5906)

* feat(editor): SAML paywall state

* fix(editor): fix translation

* fix(editor): SSO update links
This commit is contained in:
Csaba Tuncsik 2023-04-07 13:29:22 +02:00 committed by GitHub
parent 07c360c30d
commit d40e86aabc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 76 additions and 41 deletions

View file

@ -1736,6 +1736,9 @@
"settings.sso.settings.ips.help": "Add the raw Metadata XML provided by your Identity Provider", "settings.sso.settings.ips.help": "Add the raw Metadata XML provided by your Identity Provider",
"settings.sso.settings.test": "Test settings", "settings.sso.settings.test": "Test settings",
"settings.sso.settings.save": "Save settings", "settings.sso.settings.save": "Save settings",
"settings.sso.actionBox.title": "Available on Enterprise plan",
"settings.sso.actionBox.description": "Use Single Sign On to consolidate authentication into a single platform to improve security and agility.",
"settings.sso.actionBox.buttonText": "See plans",
"sso.login.divider": "or", "sso.login.divider": "or",
"sso.login.button": "Continue with SSO" "sso.login.button": "Continue with SSO"
} }

View file

@ -578,12 +578,7 @@ export const routes = [
deny: { deny: {
shouldDeny: () => { shouldDeny: () => {
const settingsStore = useSettingsStore(); const settingsStore = useSettingsStore();
const ssoStore = useSSOStore(); return settingsStore.isCloudDeployment || settingsStore.isDesktopDeployment;
return (
!ssoStore.isEnterpriseSamlEnabled ||
settingsStore.isCloudDeployment ||
settingsStore.isDesktopDeployment
);
}, },
}, },
}, },

View file

@ -2,10 +2,14 @@
import { computed, ref, onBeforeMount } from 'vue'; import { computed, ref, onBeforeMount } from 'vue';
import { Notification } from 'element-ui'; import { Notification } from 'element-ui';
import { useSSOStore } from '@/stores/sso'; import { useSSOStore } from '@/stores/sso';
import { i18n as locale } from '@/plugins/i18n'; import { useUsageStore } from '@/stores/usage';
import { useUIStore } from '@/stores/ui';
import { BaseTextKey, i18n as locale } from '@/plugins/i18n';
import CopyInput from '@/components/CopyInput.vue'; import CopyInput from '@/components/CopyInput.vue';
const ssoStore = useSSOStore(); const ssoStore = useSSOStore();
const usageStore = useUsageStore();
const uiStore = useUIStore();
const ssoActivatedLabel = computed(() => const ssoActivatedLabel = computed(() =>
ssoStore.isSamlLoginEnabled ssoStore.isSamlLoginEnabled
@ -51,7 +55,23 @@ const onTest = async () => {
} }
}; };
const goToUpgrade = () => {
const linkUrlTranslationKey = uiStore.contextBasedTranslationKeys.upgradeLinkUrl as BaseTextKey;
let linkUrl = locale.baseText(linkUrlTranslationKey);
if (linkUrlTranslationKey.endsWith('.upgradeLinkUrl')) {
linkUrl = `${usageStore.viewPlansUrl}&source=sso`;
} else if (linkUrlTranslationKey.endsWith('.desktop')) {
linkUrl = `${linkUrl}&utm_campaign=upgrade-sso`;
}
window.open(linkUrl, '_blank');
};
onBeforeMount(async () => { onBeforeMount(async () => {
if (!ssoStore.isEnterpriseSamlEnabled) {
return;
}
try { try {
await getSamlConfig(); await getSamlConfig();
} catch (error) { } catch (error) {
@ -69,7 +89,7 @@ onBeforeMount(async () => {
<n8n-heading size="2xlarge">{{ locale.baseText('settings.sso.title') }}</n8n-heading> <n8n-heading size="2xlarge">{{ locale.baseText('settings.sso.title') }}</n8n-heading>
<div :class="$style.top"> <div :class="$style.top">
<n8n-heading size="medium">{{ locale.baseText('settings.sso.subtitle') }}</n8n-heading> <n8n-heading size="medium">{{ locale.baseText('settings.sso.subtitle') }}</n8n-heading>
<n8n-tooltip :disabled="ssoStore.isSamlLoginEnabled"> <n8n-tooltip v-if="ssoStore.isEnterpriseSamlEnabled" :disabled="ssoStore.isSamlLoginEnabled">
<template #content> <template #content>
<span> <span>
{{ locale.baseText('settings.sso.activation.tooltip') }} {{ locale.baseText('settings.sso.activation.tooltip') }}
@ -86,45 +106,58 @@ onBeforeMount(async () => {
<n8n-info-tip> <n8n-info-tip>
<i18n :class="$style.count" path="settings.sso.info"> <i18n :class="$style.count" path="settings.sso.info">
<template #link> <template #link>
<a href="https://docs.n8n.io/user-management/sso/" target="_blank"> <a href="https://docs.n8n.io/user-management/saml/" target="_blank">
{{ locale.baseText('settings.sso.info.link') }} {{ locale.baseText('settings.sso.info.link') }}
</a> </a>
</template> </template>
</i18n> </i18n>
</n8n-info-tip> </n8n-info-tip>
<div :class="$style.group"> <div v-if="ssoStore.isEnterpriseSamlEnabled">
<label>{{ locale.baseText('settings.sso.settings.redirectUrl.label') }}</label> <div :class="$style.group">
<CopyInput <label>{{ locale.baseText('settings.sso.settings.redirectUrl.label') }}</label>
:class="$style.copyInput" <CopyInput
:value="redirectUrl" :class="$style.copyInput"
:copy-button-text="locale.baseText('generic.clickToCopy')" :value="redirectUrl"
:toast-title="locale.baseText('settings.sso.settings.redirectUrl.copied')" :copy-button-text="locale.baseText('generic.clickToCopy')"
/> :toast-title="locale.baseText('settings.sso.settings.redirectUrl.copied')"
<small>{{ locale.baseText('settings.sso.settings.redirectUrl.help') }}</small> />
</div> <small>{{ locale.baseText('settings.sso.settings.redirectUrl.help') }}</small>
<div :class="$style.group"> </div>
<label>{{ locale.baseText('settings.sso.settings.entityId.label') }}</label> <div :class="$style.group">
<CopyInput <label>{{ locale.baseText('settings.sso.settings.entityId.label') }}</label>
:class="$style.copyInput" <CopyInput
:value="entityId" :class="$style.copyInput"
:copy-button-text="locale.baseText('generic.clickToCopy')" :value="entityId"
:toast-title="locale.baseText('settings.sso.settings.entityId.copied')" :copy-button-text="locale.baseText('generic.clickToCopy')"
/> :toast-title="locale.baseText('settings.sso.settings.entityId.copied')"
<small>{{ locale.baseText('settings.sso.settings.entityId.help') }}</small> />
</div> <small>{{ locale.baseText('settings.sso.settings.entityId.help') }}</small>
<div :class="$style.group"> </div>
<label>{{ locale.baseText('settings.sso.settings.ips.label') }}</label> <div :class="$style.group">
<n8n-input v-model="metadata" type="textarea" /> <label>{{ locale.baseText('settings.sso.settings.ips.label') }}</label>
<small>{{ locale.baseText('settings.sso.settings.ips.help') }}</small> <n8n-input v-model="metadata" type="textarea" />
</div> <small>{{ locale.baseText('settings.sso.settings.ips.help') }}</small>
<div :class="$style.buttons"> </div>
<n8n-button :disabled="!ssoSettingsSaved" type="tertiary" @click="onTest"> <div :class="$style.buttons">
{{ locale.baseText('settings.sso.settings.test') }} <n8n-button :disabled="!ssoSettingsSaved" type="tertiary" @click="onTest">
</n8n-button> {{ locale.baseText('settings.sso.settings.test') }}
<n8n-button :disabled="!metadata" @click="onSave"> </n8n-button>
{{ locale.baseText('settings.sso.settings.save') }} <n8n-button :disabled="!metadata" @click="onSave">
</n8n-button> {{ locale.baseText('settings.sso.settings.save') }}
</n8n-button>
</div>
</div> </div>
<n8n-action-box
v-else
:class="$style.actionBox"
:description="locale.baseText('settings.sso.actionBox.description')"
:buttonText="locale.baseText('settings.sso.actionBox.buttonText')"
@click="goToUpgrade"
>
<template #heading>
<span>{{ locale.baseText('settings.sso.actionBox.title') }}</span>
</template>
</n8n-action-box>
</div> </div>
</template> </template>
@ -171,4 +204,8 @@ onBeforeMount(async () => {
color: var(--color-text-base); color: var(--color-text-base);
} }
} }
.actionBox {
margin: var(--spacing-2xl) 0 0;
}
</style> </style>