fix(editor): Usage and plans page on Desktop (#5045)

This commit is contained in:
Csaba Tuncsik 2022-12-28 17:07:34 +01:00 committed by GitHub
parent 16bd7610fc
commit 26e2321a71
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 128 additions and 100 deletions

View file

@ -1148,6 +1148,8 @@
"settings.usageAndPlan.license.activation.error.title": "Activation failed", "settings.usageAndPlan.license.activation.error.title": "Activation failed",
"settings.usageAndPlan.license.activation.success.title": "License activated", "settings.usageAndPlan.license.activation.success.title": "License activated",
"settings.usageAndPlan.license.activation.success.message": "Your {name} {type} has been successfully activated.", "settings.usageAndPlan.license.activation.success.message": "Your {name} {type} has been successfully activated.",
"settings.usageAndPlan.desktop.title": "Upgrade to n8n Cloud for the full experience",
"settings.usageAndPlan.desktop.description": "Cloud plans allow you to collaborate with teammates. Plus you dont need to leave this app open all the time for your workflows to run.",
"showMessage.cancel": "@:_reusableBaseText.cancel", "showMessage.cancel": "@:_reusableBaseText.cancel",
"showMessage.ok": "OK", "showMessage.ok": "OK",
"showMessage.showDetails": "Show Details", "showMessage.showDetails": "Show Details",

View file

@ -8,7 +8,7 @@ import { useUsersStore } from '@/stores/users';
export type UsageTelemetry = { export type UsageTelemetry = {
instance_id: string; instance_id: string;
action: 'view_plans' | 'manage_plan' | 'add_activation_key'; action: 'view_plans' | 'manage_plan' | 'add_activation_key' | 'desktop_view_plans';
plan_name_current: string; plan_name_current: string;
usage: number; usage: number;
quota: number; quota: number;
@ -120,5 +120,6 @@ export const useUsageStore = defineStore('usage', () => {
usage: executionCount.value, usage: executionCount.value,
quota: executionLimit.value, quota: executionLimit.value,
})), })),
isDesktop: computed(() => settingsStore.isDesktopDeployment),
}; };
}); });

View file

@ -53,35 +53,37 @@ const onLicenseActivation = async () => {
}; };
onMounted(async () => { onMounted(async () => {
usageStore.setLoading(true); if (!usageStore.isDesktop) {
if (route.query.key) { usageStore.setLoading(true);
if (route.query.key) {
try {
await usageStore.activateLicense(route.query.key as string);
await router.replace({ query: {} });
showActivationSuccess();
usageStore.setLoading(false);
return;
} catch (error) {
showActivationError(error);
}
}
try { try {
await usageStore.activateLicense(route.query.key as string); if (!route.query.key && usageStore.canUserActivateLicense) {
await router.replace({ query: {} }); await usageStore.refreshLicenseManagementToken();
showActivationSuccess(); } else {
await usageStore.getLicenseInfo();
}
usageStore.setLoading(false); usageStore.setLoading(false);
return;
} catch (error) { } catch (error) {
showActivationError(error); if (!error.name) {
error.name = locale.baseText('settings.usageAndPlan.error');
}
Notification.error({
title: error.name,
message: error.message,
position: 'bottom-right',
});
} }
} }
try {
if (!route.query.key && usageStore.canUserActivateLicense) {
await usageStore.refreshLicenseManagementToken();
} else {
await usageStore.getLicenseInfo();
}
usageStore.setLoading(false);
} catch (error) {
if (!error.name) {
error.name = locale.baseText('settings.usageAndPlan.error');
}
Notification.error({
title: error.name,
message: error.message,
position: 'bottom-right',
});
}
}); });
const sendUsageTelemetry = (action: UsageTelemetry['action']) => { const sendUsageTelemetry = (action: UsageTelemetry['action']) => {
@ -110,99 +112,122 @@ const onDialogClosed = () => {
const onDialogOpened = () => { const onDialogOpened = () => {
activationKeyInput.value?.focus(); activationKeyInput.value?.focus();
}; };
const openPricingPage = () => {
sendUsageTelemetry('desktop_view_plans');
window.open('https://n8n.io/pricing', '_blank');
};
</script> </script>
<template> <template>
<div v-if="!usageStore.isLoading"> <div>
<n8n-heading size="2xlarge">{{ locale.baseText('settings.usageAndPlan.title') }}</n8n-heading> <n8n-heading size="2xlarge">{{ locale.baseText('settings.usageAndPlan.title') }}</n8n-heading>
<n8n-heading :class="$style.title" size="large"> <n8n-action-box
<i18n path="settings.usageAndPlan.description"> v-if="usageStore.isDesktop"
<template #name>{{ usageStore.planName }}</template> :class="$style.actionBox"
<template #type> :heading="locale.baseText('settings.usageAndPlan.desktop.title')"
<span v-if="usageStore.planId">{{ locale.baseText('settings.usageAndPlan.plan') }}</span> :description="locale.baseText('settings.usageAndPlan.desktop.description')"
<span v-else>{{ locale.baseText('settings.usageAndPlan.edition') }}</span> :buttonText="locale.baseText('settings.usageAndPlan.button.plans')"
</template> @click="openPricingPage"
</i18n> />
</n8n-heading> <div v-if="!usageStore.isDesktop && !usageStore.isLoading">
<n8n-heading :class="$style.title" size="large">
<div :class="$style.quota"> <i18n path="settings.usageAndPlan.description">
<n8n-text size="medium" color="text-light"> <template #name>{{ usageStore.planName }}</template>
{{ locale.baseText('settings.usageAndPlan.activeWorkflows') }} <template #type>
</n8n-text> <span v-if="usageStore.planId">{{
<div :class="$style.chart"> locale.baseText('settings.usageAndPlan.plan')
<span v-if="usageStore.executionLimit > 0" :class="$style.chartLine">
<span
:class="$style.chartBar"
:style="{ width: `${usageStore.executionPercentage}%` }"
></span>
</span>
<i18n :class="$style.count" path="settings.usageAndPlan.activeWorkflows.count">
<template #count>{{ usageStore.executionCount }}</template>
<template #limit>
<span v-if="usageStore.executionLimit < 0">{{
locale.baseText('settings.usageAndPlan.activeWorkflows.unlimited')
}}</span> }}</span>
<span v-else>{{ usageStore.executionLimit }}</span> <span v-else>{{ locale.baseText('settings.usageAndPlan.edition') }}</span>
</template> </template>
</i18n> </i18n>
</n8n-heading>
<div :class="$style.quota">
<n8n-text size="medium" color="text-light">
{{ locale.baseText('settings.usageAndPlan.activeWorkflows') }}
</n8n-text>
<div :class="$style.chart">
<span v-if="usageStore.executionLimit > 0" :class="$style.chartLine">
<span
:class="$style.chartBar"
:style="{ width: `${usageStore.executionPercentage}%` }"
></span>
</span>
<i18n :class="$style.count" path="settings.usageAndPlan.activeWorkflows.count">
<template #count>{{ usageStore.executionCount }}</template>
<template #limit>
<span v-if="usageStore.executionLimit < 0">{{
locale.baseText('settings.usageAndPlan.activeWorkflows.unlimited')
}}</span>
<span v-else>{{ usageStore.executionLimit }}</span>
</template>
</i18n>
</div>
</div> </div>
</div>
<n8n-info-tip>{{ locale.baseText('settings.usageAndPlan.activeWorkflows.hint') }}</n8n-info-tip> <n8n-info-tip>{{
locale.baseText('settings.usageAndPlan.activeWorkflows.hint')
}}</n8n-info-tip>
<div :class="$style.buttons"> <div :class="$style.buttons">
<n8n-button <n8n-button
:class="$style.buttonTertiary" :class="$style.buttonTertiary"
@click="onAddActivationKey" @click="onAddActivationKey"
v-if="usageStore.canUserActivateLicense" v-if="usageStore.canUserActivateLicense"
type="tertiary" type="tertiary"
size="large" size="large"
>
<strong>{{ locale.baseText('settings.usageAndPlan.button.activation') }}</strong>
</n8n-button>
<n8n-button v-if="usageStore.managementToken" @click="onManagePlan" size="large">
<a :href="managePlanUrl" target="_blank">{{
locale.baseText('settings.usageAndPlan.button.manage')
}}</a>
</n8n-button>
<n8n-button v-else @click="onViewPlans" size="large">
<a :href="viewPlansUrl" target="_blank">{{
locale.baseText('settings.usageAndPlan.button.plans')
}}</a>
</n8n-button>
</div>
<el-dialog
width="480px"
top="0"
@closed="onDialogClosed"
@opened="onDialogOpened"
:visible.sync="activationKeyModal"
:title="locale.baseText('settings.usageAndPlan.dialog.activation.title')"
> >
<strong>{{ locale.baseText('settings.usageAndPlan.button.activation') }}</strong> <template #default>
</n8n-button> <n8n-input
<n8n-button v-if="usageStore.managementToken" @click="onManagePlan" size="large"> ref="activationKeyInput"
<a :href="managePlanUrl" target="_blank">{{ v-model="activationKey"
locale.baseText('settings.usageAndPlan.button.manage') size="medium"
}}</a> :placeholder="locale.baseText('settings.usageAndPlan.dialog.activation.label')"
</n8n-button> />
<n8n-button v-else @click="onViewPlans" size="large"> </template>
<a :href="viewPlansUrl" target="_blank">{{ <template #footer>
locale.baseText('settings.usageAndPlan.button.plans') <n8n-button @click="activationKeyModal = false" size="medium" type="secondary">
}}</a> {{ locale.baseText('settings.usageAndPlan.dialog.activation.cancel') }}
</n8n-button> </n8n-button>
<n8n-button @click="onLicenseActivation" size="medium">
{{ locale.baseText('settings.usageAndPlan.dialog.activation.activate') }}
</n8n-button>
</template>
</el-dialog>
</div> </div>
<el-dialog
width="480px"
top="0"
@closed="onDialogClosed"
@opened="onDialogOpened"
:visible.sync="activationKeyModal"
:title="locale.baseText('settings.usageAndPlan.dialog.activation.title')"
>
<template #default>
<n8n-input
ref="activationKeyInput"
v-model="activationKey"
size="medium"
:placeholder="locale.baseText('settings.usageAndPlan.dialog.activation.label')"
/>
</template>
<template #footer>
<n8n-button @click="activationKeyModal = false" size="medium" type="secondary">
{{ locale.baseText('settings.usageAndPlan.dialog.activation.cancel') }}
</n8n-button>
<n8n-button @click="onLicenseActivation" size="medium">
{{ locale.baseText('settings.usageAndPlan.dialog.activation.activate') }}
</n8n-button>
</template>
</el-dialog>
</div> </div>
</template> </template>
<style lang="scss" module> <style lang="scss" module>
@import '@/styles/css-animation-helpers.scss'; @import '@/styles/css-animation-helpers.scss';
.actionBox {
margin: var(--spacing-2xl) 0 0;
}
.spacedFlex { .spacedFlex {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;