mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-12 05:17:28 -08:00
feat(editor): Show banner for non-production licenses (#6943)
https://linear.app/n8n/issue/PAY-692
This commit is contained in:
parent
d3f01270c7
commit
413570c49d
|
@ -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 }>, {}>;
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
|
@ -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.",
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -2203,4 +2203,4 @@ export interface IN8nUISettings {
|
|||
};
|
||||
}
|
||||
|
||||
export type Banners = 'V1' | 'TRIAL_OVER' | 'TRIAL';
|
||||
export type BannerName = 'V1' | 'TRIAL_OVER' | 'TRIAL' | 'NON_PRODUCTION_LICENSE';
|
||||
|
|
Loading…
Reference in a new issue