feat(editor): Show banner for non-production licenses (#6943)

https://linear.app/n8n/issue/PAY-692
This commit is contained in:
Iván Ovejero 2023-08-17 14:00:17 +02:00 committed by GitHub
parent d3f01270c7
commit 413570c49d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 33 additions and 20 deletions

View file

@ -1,6 +1,6 @@
import type express from 'express';
import type {
Banners,
BannerName,
IConnections,
ICredentialDataDecryptedObject,
ICredentialNodeAccess,
@ -216,7 +216,7 @@ export interface UserSetupPayload {
export declare namespace OwnerRequest {
type Post = AuthenticatedRequest<{}, {}, UserSetupPayload, {}>;
type DismissBanner = AuthenticatedRequest<{}, {}, Partial<{ bannerName: Banners }>, {}>;
type DismissBanner = AuthenticatedRequest<{}, {}, Partial<{ bannerName: BannerName }>, {}>;
}
// ----------------------------------

View file

@ -34,7 +34,7 @@ import type {
IUserManagementSettings,
WorkflowSettings,
IUserSettings,
Banners,
BannerName,
} from 'n8n-workflow';
import type { SignInType } from './constants';
import type {
@ -1074,7 +1074,7 @@ export interface UIState {
addFirstStepOnLoad: boolean;
executionSidebarAutoRefresh: boolean;
bannersHeight: number;
banners: { [key in Banners]: { dismissed: boolean; type?: 'temporary' | 'permanent' } };
banners: { [key in BannerName]: { dismissed: boolean; type?: 'temporary' | 'permanent' } };
}
export type IFakeDoor = {

View file

@ -1,10 +1,10 @@
import type { IRestApiContext } from '@/Interface';
import { makeRestApiRequest } from '@/utils/apiUtils';
import type { Banners } from 'n8n-workflow';
import type { BannerName } from 'n8n-workflow';
export async function dismissBannerPermanently(
context: IRestApiContext,
data: { bannerName: Banners; dismissedBanners: string[] },
data: { bannerName: BannerName; dismissedBanners: string[] },
): Promise<void> {
return makeRestApiRequest(context, 'POST', '/owner/dismiss-banner', { banner: data.bannerName });
}

View file

@ -1,15 +1,16 @@
<script setup lang="ts">
import NonProductionLicenseBanner from '@/components/banners/NonProductionLicenseBanner.vue';
import TrialOverBanner from '@/components/banners/TrialOverBanner.vue';
import TrialBanner from '@/components/banners/TrialBanner.vue';
import V1Banner from '@/components/banners/V1Banner.vue';
import { useUIStore } from '@/stores/ui.store';
import { onMounted, watch } from 'vue';
import { getBannerRowHeight } from '@/utils';
import type { Banners } from 'n8n-workflow';
import type { BannerName } from 'n8n-workflow';
const uiStore = useUIStore();
function shouldShowBanner(bannerName: Banners) {
function shouldShowBanner(bannerName: BannerName) {
return uiStore.banners[bannerName].dismissed === false;
}
@ -32,5 +33,6 @@ watch(uiStore.banners, async () => {
<trial-over-banner v-if="shouldShowBanner('TRIAL_OVER')" />
<trial-banner v-if="shouldShowBanner('TRIAL')" />
<v1-banner v-if="shouldShowBanner('V1')" />
<non-production-license-banner v-if="shouldShowBanner('NON_PRODUCTION_LICENSE')" />
</div>
</template>

View file

@ -1,9 +1,9 @@
<script lang="ts" setup>
import { useUIStore } from '@/stores/ui.store';
import type { Banners } from 'n8n-workflow';
import type { BannerName } from 'n8n-workflow';
interface Props {
name: Banners;
name: BannerName;
theme?: string;
customIcon?: string;
dismissible?: boolean;

View file

@ -0,0 +1,12 @@
<script lang="ts" setup>
import BaseBanner from '@/components/banners/BaseBanner.vue';
import { i18n as locale } from '@/plugins/i18n';
</script>
<template>
<base-banner name="NON_PRODUCTION_LICENSE" :dismissible="false">
<template #mainContent>
<span>{{ locale.baseText('banners.nonProductionLicense.message') }}</span>
</template>
</base-banner>
</template>

View file

@ -115,6 +115,7 @@
"auth.signup.setupYourAccount": "Set up your account",
"auth.signup.setupYourAccountError": "Problem setting up your account",
"auth.signup.tokenValidationError": "Issue validating invite token",
"banners.nonProductionLicense.message": "This n8n instance is not licensed for production purposes!",
"banners.trial.message": "1 day left in your n8n trial | {count} days left in your n8n trial",
"banners.trialOver.message": "Your trial is over. Upgrade now to keep automating.",
"banners.v1.message": "n8n has been updated to version 1, introducing some breaking changes. Please consult the <a target=\"_blank\" href=\"https://docs.n8n.io/1-0-migration-checklist\">migration guide</a> for more information.",

View file

@ -198,6 +198,9 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, {
this.saml.loginEnabled = settings.sso.saml.loginEnabled;
this.saml.loginLabel = settings.sso.saml.loginLabel;
}
if (settings.enterprise?.showNonProdBanner) {
useUIStore().banners.NON_PRODUCTION_LICENSE.dismissed = false;
}
},
async getSettings(): Promise<void> {
const rootStore = useRootStore();

View file

@ -56,7 +56,7 @@ import { i18n as locale } from '@/plugins/i18n';
import { useTelemetryStore } from '@/stores/telemetry.store';
import { getStyleTokenValue } from '@/utils/htmlUtils';
import { dismissBannerPermanently } from '@/api/ui';
import type { Banners } from 'n8n-workflow';
import type { BannerName } from 'n8n-workflow';
export const useUIStore = defineStore(STORES.UI, {
state: (): UIState => ({
@ -176,6 +176,7 @@ export const useUIStore = defineStore(STORES.UI, {
V1: { dismissed: true },
TRIAL: { dismissed: true },
TRIAL_OVER: { dismissed: true },
NON_PRODUCTION_LICENSE: { dismissed: true },
},
bannersHeight: 0,
}),
@ -333,12 +334,6 @@ export const useUIStore = defineStore(STORES.UI, {
},
},
actions: {
setBanners(banners: UIState['banners']): void {
this.banners = {
...this.banners,
...banners,
};
},
setMode(name: keyof Modals, mode: string): void {
this.modals[name] = {
...this.modals[name],
@ -541,7 +536,7 @@ export const useUIStore = defineStore(STORES.UI, {
}
},
async dismissBanner(
name: Banners,
name: BannerName,
type: 'temporary' | 'permanent' = 'temporary',
): Promise<void> {
if (type === 'permanent') {
@ -556,7 +551,7 @@ export const useUIStore = defineStore(STORES.UI, {
this.banners[name].dismissed = true;
this.banners[name].type = 'temporary';
},
showBanner(name: Banners): void {
showBanner(name: BannerName): void {
this.banners[name].dismissed = false;
},
updateBannersHeight(newHeight: number): void {

View file

@ -2203,4 +2203,4 @@ export interface IN8nUISettings {
};
}
export type Banners = 'V1' | 'TRIAL_OVER' | 'TRIAL';
export type BannerName = 'V1' | 'TRIAL_OVER' | 'TRIAL' | 'NON_PRODUCTION_LICENSE';