feat(editor): Support autologin for upgrade path (#7316)

Github issue / Community forum post (link here to close automatically):
This commit is contained in:
Ricardo Espinoza
2023-10-06 13:16:27 +02:00
committed by GitHub
parent ab647b231d
commit 1dfa052301
26 changed files with 101 additions and 54 deletions

View File

@@ -47,26 +47,53 @@ function setupOwnerAndCloudDeployment() {
}
describe('UI store', () => {
let mockedCloudStore;
beforeEach(() => {
setActivePinia(createPinia());
uiStore = useUIStore();
settingsStore = useSettingsStore();
rootStore = useRootStore();
cloudPlanStore = useCloudPlanStore();
mockedCloudStore = vi.spyOn(cloudPlanStore, 'getAutoLoginCode');
mockedCloudStore.mockImplementationOnce(async () => ({
code: '123',
}));
global.window = Object.create(window);
const url = 'https://test.app.n8n.cloud';
Object.defineProperty(window, 'location', {
value: {
href: url,
},
writable: true,
});
});
test.each([
['default', 'production', 'https://n8n.io/pricing/?ref=test_source'],
['default', 'development', 'https://n8n.io/pricing/?ref=test_source'],
[
'desktop_win',
'default',
'production',
'https://n8n.io/pricing/?utm_source=n8n-internal&utm_medium=desktop&utm_campaign=utm-test-campaign',
'https://n8n.io/pricing?utm_campaign=utm-test-campaign&source=test_source',
],
[
'default',
'development',
'https://n8n.io/pricing?utm_campaign=utm-test-campaign&source=test_source',
],
[
'cloud',
'production',
`https://app.n8n.cloud/login?code=123&returnPath=${encodeURIComponent(
'/account/change-plan',
)}&utm_campaign=utm-test-campaign&source=test_source`,
],
['cloud', 'production', 'https://app.n8n.cloud/account/change-plan'],
])(
'"upgradeLinkUrl" should generate the correct URL for "%s" deployment and "%s" license environment',
(type, environment, expectation) => {
async (type, environment, expectation) => {
settingsStore.setSettings(
merge({}, SETTINGS_STORE_DEFAULT_STATE.settings, {
deployment: {
@@ -80,7 +107,9 @@ describe('UI store', () => {
}),
);
expect(uiStore.upgradeLinkUrl('test_source', 'utm-test-campaign')).toBe(expectation);
const updateLinkUrl = await uiStore.upgradeLinkUrl('test_source', 'utm-test-campaign', type);
expect(updateLinkUrl).toBe(expectation);
},
);

View File

@@ -5,7 +5,7 @@ import { useRootStore } from '@/stores/n8nRoot.store';
import { useSettingsStore } from '@/stores/settings.store';
import { useUIStore } from '@/stores/ui.store';
import { useUsersStore } from '@/stores/users.store';
import { getCurrentPlan, getCurrentUsage } from '@/api/cloudPlans';
import { getAdminPanelLoginCode, getCurrentPlan, getCurrentUsage } from '@/api/cloudPlans';
import { DateTime } from 'luxon';
import { CLOUD_TRIAL_CHECK_INTERVAL, STORES } from '@/constants';
@@ -71,6 +71,10 @@ export const useCloudPlanStore = defineStore(STORES.CLOUD_PLAN, () => {
}
};
const getAutoLoginCode = async (): Promise<{ code: string }> => {
return getAdminPanelLoginCode(rootStore.getRestApiContext);
};
const getOwnerCurrentPlan = async () => {
if (!hasCloudPlan.value) throw new Error('User does not have a cloud plan');
state.loadingPlan = true;
@@ -161,5 +165,6 @@ export const useCloudPlanStore = defineStore(STORES.CLOUD_PLAN, () => {
reset,
checkForCloudPlanData,
fetchUserCloudAccount,
getAutoLoginCode,
};
});

View File

@@ -35,6 +35,7 @@ import {
SOURCE_CONTROL_PUSH_MODAL_KEY,
SOURCE_CONTROL_PULL_MODAL_KEY,
DEBUG_PAYWALL_MODAL_KEY,
N8N_PRICING_PAGE_URL,
} from '@/constants';
import type {
CloudUpdateLinkSourceType,
@@ -56,8 +57,6 @@ import { getCurlToJson } from '@/api/curlHelper';
import { useWorkflowsStore } from '@/stores/workflows.store';
import { useSettingsStore } from '@/stores/settings.store';
import { useCloudPlanStore } from '@/stores/cloudPlan.store';
import type { BaseTextKey } from '@/plugins/i18n';
import { i18n as locale } from '@/plugins/i18n';
import { useTelemetryStore } from '@/stores/telemetry.store';
import { getStyleTokenValue } from '@/utils/htmlUtils';
import { dismissBannerPermanently } from '@/api/ui';
@@ -214,7 +213,6 @@ export const useUIStore = defineStore(STORES.UI, {
}
return {
upgradeLinkUrl: `contextual.upgradeLinkUrl${contextKey}`,
feature: {
unavailable: {
title: `contextual.feature.unavailable.title${contextKey}`,
@@ -343,18 +341,29 @@ export const useUIStore = defineStore(STORES.UI, {
};
},
upgradeLinkUrl() {
return (source: string, utm_campaign: string): string => {
const linkUrlTranslationKey = this.contextBasedTranslationKeys
.upgradeLinkUrl as BaseTextKey;
let linkUrl = locale.baseText(linkUrlTranslationKey);
return async (source: string, utm_campaign: string, deploymentType: string) => {
let linkUrl = '';
if (linkUrlTranslationKey.endsWith('.upgradeLinkUrl')) {
linkUrl = `${linkUrl}?ref=${source}`;
} else if (linkUrlTranslationKey.endsWith('.desktop')) {
linkUrl = `${linkUrl}&utm_campaign=${utm_campaign || source}`;
const searchParams = new URLSearchParams();
if (deploymentType === 'cloud') {
const { code } = await useCloudPlanStore().getAutoLoginCode();
const adminPanelHost = new URL(window.location.href).host.split('.').slice(1).join('.');
linkUrl = `https://${adminPanelHost}/login`;
searchParams.set('code', code);
searchParams.set('returnPath', '/account/change-plan');
} else {
linkUrl = N8N_PRICING_PAGE_URL;
}
return linkUrl;
if (utm_campaign) {
searchParams.set('utm_campaign', utm_campaign);
}
if (source) {
searchParams.set('source', source);
}
return `${linkUrl}?${searchParams.toString()}`;
};
},
headerHeight() {
@@ -542,25 +551,30 @@ export const useUIStore = defineStore(STORES.UI, {
const rootStore = useRootStore();
return getCurlToJson(rootStore.getRestApiContext, curlCommand);
},
goToUpgrade(
async goToUpgrade(
source: CloudUpdateLinkSourceType,
utm_campaign: UTMCampaign,
mode: 'open' | 'redirect' = 'open',
): void {
): Promise<void> {
const { usageLeft, trialDaysLeft, userIsTrialing } = useCloudPlanStore();
const { executionsLeft, workflowsLeft } = usageLeft;
const deploymentType = useSettingsStore().deploymentType;
useTelemetryStore().track('User clicked upgrade CTA', {
source,
isTrial: userIsTrialing,
deploymentType: useSettingsStore().deploymentType,
deploymentType,
trialDaysLeft,
executionsLeft,
workflowsLeft,
});
const upgradeLink = await this.upgradeLinkUrl(source, utm_campaign, deploymentType);
if (mode === 'open') {
window.open(this.upgradeLinkUrl(source, utm_campaign), '_blank');
window.open(upgradeLink, '_blank');
} else {
location.href = this.upgradeLinkUrl(source, utm_campaign);
location.href = upgradeLink;
}
},
async dismissBanner(