mirror of
https://github.com/n8n-io/n8n.git
synced 2025-02-21 02:56:40 -08:00
feat(editor): Add v1 banner (#6443)
This commit is contained in:
parent
85372aabdf
commit
0fe415add2
|
@ -316,6 +316,11 @@ export class Server extends AbstractServer {
|
||||||
variables: {
|
variables: {
|
||||||
limit: 0,
|
limit: 0,
|
||||||
},
|
},
|
||||||
|
banners: {
|
||||||
|
v1: {
|
||||||
|
dismissed: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,6 +416,16 @@ export class Server extends AbstractServer {
|
||||||
config.getEnv('deployment.type').startsWith('desktop_') === false,
|
config.getEnv('deployment.type').startsWith('desktop_') === false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let v1Dismissed = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
v1Dismissed = config.getEnv('ui.banners.v1.dismissed');
|
||||||
|
} catch {
|
||||||
|
// not yet in DB
|
||||||
|
}
|
||||||
|
|
||||||
|
this.frontendSettings.banners.v1.dismissed = v1Dismissed;
|
||||||
|
|
||||||
// refresh enterprise status
|
// refresh enterprise status
|
||||||
Object.assign(this.frontendSettings.enterprise, {
|
Object.assign(this.frontendSettings.enterprise, {
|
||||||
sharing: isSharingEnabled(),
|
sharing: isSharingEnabled(),
|
||||||
|
|
1
packages/cli/src/config/types.d.ts
vendored
1
packages/cli/src/config/types.d.ts
vendored
|
@ -80,6 +80,7 @@ type ExceptionPaths = {
|
||||||
'nodes.exclude': string[] | undefined;
|
'nodes.exclude': string[] | undefined;
|
||||||
'nodes.include': string[] | undefined;
|
'nodes.include': string[] | undefined;
|
||||||
'userManagement.isInstanceOwnerSetUp': boolean;
|
'userManagement.isInstanceOwnerSetUp': boolean;
|
||||||
|
'ui.banners.v1.dismissed': boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
|
|
|
@ -148,4 +148,11 @@ export class OwnerController {
|
||||||
|
|
||||||
return sanitizeUser(owner);
|
return sanitizeUser(owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Post('/dismiss-v1')
|
||||||
|
async dismissBanner() {
|
||||||
|
await this.settingsRepository.saveSetting('ui.banners.v1.dismissed', JSON.stringify(true));
|
||||||
|
|
||||||
|
return { success: true };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,23 @@
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
import { DataSource, Repository } from 'typeorm';
|
import { DataSource, Repository } from 'typeorm';
|
||||||
import { Settings } from '../entities/Settings';
|
import { Settings } from '../entities/Settings';
|
||||||
|
import config from '@/config';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class SettingsRepository extends Repository<Settings> {
|
export class SettingsRepository extends Repository<Settings> {
|
||||||
constructor(dataSource: DataSource) {
|
constructor(dataSource: DataSource) {
|
||||||
super(Settings, dataSource.manager);
|
super(Settings, dataSource.manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async saveSetting(key: string, value: string, loadOnStartup = true) {
|
||||||
|
const setting = await this.findOneBy({ key });
|
||||||
|
|
||||||
|
if (setting) {
|
||||||
|
await this.update({ key }, { value, loadOnStartup });
|
||||||
|
} else {
|
||||||
|
await this.save({ key, value, loadOnStartup });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loadOnStartup) config.set('ui.banners.v1.dismissed', true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,10 @@ export default defineComponent({
|
||||||
slim: {
|
slim: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
},
|
},
|
||||||
|
overrideIcon: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
classes(): string[] {
|
classes(): string[] {
|
||||||
|
@ -61,6 +65,8 @@ export default defineComponent({
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
getIcon(): string {
|
getIcon(): string {
|
||||||
|
if (this.overrideIcon) return this.icon;
|
||||||
|
|
||||||
if (Object.keys(CALLOUT_DEFAULT_ICONS).includes(this.theme)) {
|
if (Object.keys(CALLOUT_DEFAULT_ICONS).includes(this.theme)) {
|
||||||
return CALLOUT_DEFAULT_ICONS[this.theme];
|
return CALLOUT_DEFAULT_ICONS[this.theme];
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
[$style.sidebarCollapsed]: uiStore.sidebarMenuCollapsed,
|
[$style.sidebarCollapsed]: uiStore.sidebarMenuCollapsed,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
|
<V1Banner />
|
||||||
<div id="header" :class="$style.header">
|
<div id="header" :class="$style.header">
|
||||||
<router-view name="header"></router-view>
|
<router-view name="header"></router-view>
|
||||||
</div>
|
</div>
|
||||||
|
@ -30,6 +31,7 @@
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
|
|
||||||
|
import V1Banner from '@/components/V1Banner.vue';
|
||||||
import Modals from '@/components/Modals.vue';
|
import Modals from '@/components/Modals.vue';
|
||||||
import LoadingView from '@/views/LoadingView.vue';
|
import LoadingView from '@/views/LoadingView.vue';
|
||||||
import Telemetry from '@/components/Telemetry.vue';
|
import Telemetry from '@/components/Telemetry.vue';
|
||||||
|
@ -60,6 +62,7 @@ export default defineComponent({
|
||||||
LoadingView,
|
LoadingView,
|
||||||
Telemetry,
|
Telemetry,
|
||||||
Modals,
|
Modals,
|
||||||
|
V1Banner,
|
||||||
},
|
},
|
||||||
mixins: [newVersions, userHelpers],
|
mixins: [newVersions, userHelpers],
|
||||||
setup(props) {
|
setup(props) {
|
||||||
|
@ -278,12 +281,12 @@ export default defineComponent({
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
grid-area: header;
|
grid-area: header;
|
||||||
z-index: 999;
|
z-index: 99;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar {
|
.sidebar {
|
||||||
grid-area: sidebar;
|
grid-area: sidebar;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
z-index: 999;
|
z-index: 99;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1044,6 +1044,12 @@ export interface UIState {
|
||||||
activeActions: string[];
|
activeActions: string[];
|
||||||
activeCredentialType: string | null;
|
activeCredentialType: string | null;
|
||||||
sidebarMenuCollapsed: boolean;
|
sidebarMenuCollapsed: boolean;
|
||||||
|
banners: {
|
||||||
|
v1: {
|
||||||
|
dismissed: boolean;
|
||||||
|
mode: 'temporary' | 'permanent';
|
||||||
|
};
|
||||||
|
};
|
||||||
modalStack: string[];
|
modalStack: string[];
|
||||||
modals: Modals;
|
modals: Modals;
|
||||||
isPageLoading: boolean;
|
isPageLoading: boolean;
|
||||||
|
|
|
@ -56,7 +56,6 @@ const defaultSettings: IN8nUISettings = {
|
||||||
urlBaseEditor: '',
|
urlBaseEditor: '',
|
||||||
urlBaseWebhook: '',
|
urlBaseWebhook: '',
|
||||||
userManagement: {
|
userManagement: {
|
||||||
enabled: true,
|
|
||||||
showSetupOnFirstLoad: true,
|
showSetupOnFirstLoad: true,
|
||||||
smtpSetup: true,
|
smtpSetup: true,
|
||||||
authenticationMethod: 'email',
|
authenticationMethod: 'email',
|
||||||
|
@ -75,6 +74,11 @@ const defaultSettings: IN8nUISettings = {
|
||||||
deployment: {
|
deployment: {
|
||||||
type: 'default',
|
type: 'default',
|
||||||
},
|
},
|
||||||
|
banners: {
|
||||||
|
v1: {
|
||||||
|
dismissed: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export function routesForSettings(server: Server) {
|
export function routesForSettings(server: Server) {
|
||||||
|
|
6
packages/editor-ui/src/api/ui.ts
Normal file
6
packages/editor-ui/src/api/ui.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import type { IRestApiContext } from '@/Interface';
|
||||||
|
import { makeRestApiRequest } from '@/utils/apiUtils';
|
||||||
|
|
||||||
|
export async function dismissV1BannerPermanently(context: IRestApiContext): Promise<void> {
|
||||||
|
return makeRestApiRequest(context, 'POST', '/owner/dismiss-v1');
|
||||||
|
}
|
76
packages/editor-ui/src/components/V1Banner.vue
Normal file
76
packages/editor-ui/src/components/V1Banner.vue
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
<template>
|
||||||
|
<n8n-callout
|
||||||
|
v-if="shouldDisplay"
|
||||||
|
theme="warning"
|
||||||
|
icon="info-circle"
|
||||||
|
override-icon
|
||||||
|
:class="$style['v1-banner']"
|
||||||
|
>
|
||||||
|
<span v-html="locale.baseText('banners.v1.message')"></span>
|
||||||
|
{{ '' }}
|
||||||
|
<a v-if="isInstanceOwner" @click="dismissBanner('v1', 'permanent')">
|
||||||
|
<span v-html="locale.baseText('banners.v1.action')"></span>
|
||||||
|
</a>
|
||||||
|
<template #trailingContent>
|
||||||
|
<n8n-icon
|
||||||
|
size="small"
|
||||||
|
icon="xmark"
|
||||||
|
:title="locale.baseText('banners.v1.iconTitle')"
|
||||||
|
:class="$style.xmark"
|
||||||
|
@click="dismissBanner('v1', 'temporary')"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</n8n-callout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { VIEWS } from '@/constants';
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import { useUIStore, useUsersStore, useRootStore } from '@/stores';
|
||||||
|
import { useRoute } from 'vue-router/composables';
|
||||||
|
import { i18n as locale } from '@/plugins/i18n';
|
||||||
|
|
||||||
|
const { isInstanceOwner } = useUsersStore();
|
||||||
|
const { dismissBanner } = useUIStore();
|
||||||
|
|
||||||
|
const shouldDisplay = computed(() => {
|
||||||
|
if (!useRootStore().versionCli.startsWith('1.')) return false;
|
||||||
|
|
||||||
|
if (useUIStore().banners.v1.dismissed) return false;
|
||||||
|
|
||||||
|
const VIEWABLE_AT: string[] = [
|
||||||
|
VIEWS.HOMEPAGE,
|
||||||
|
VIEWS.COLLECTION,
|
||||||
|
VIEWS.TEMPLATE,
|
||||||
|
VIEWS.TEMPLATES,
|
||||||
|
VIEWS.CREDENTIALS,
|
||||||
|
VIEWS.VARIABLES,
|
||||||
|
VIEWS.WORKFLOWS,
|
||||||
|
VIEWS.EXECUTIONS,
|
||||||
|
];
|
||||||
|
|
||||||
|
const { name } = useRoute();
|
||||||
|
|
||||||
|
if (name && VIEWABLE_AT.includes(name)) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style module lang="scss">
|
||||||
|
.v1-banner {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 999;
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xmark {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -24,7 +24,7 @@ import { FontAwesomePlugin } from './plugins/icons';
|
||||||
|
|
||||||
import { runExternalHook } from '@/utils';
|
import { runExternalHook } from '@/utils';
|
||||||
import { createPinia, PiniaVuePlugin } from 'pinia';
|
import { createPinia, PiniaVuePlugin } from 'pinia';
|
||||||
import { useWebhooksStore } from '@/stores';
|
import { useWebhooksStore, useUIStore } from '@/stores';
|
||||||
|
|
||||||
Vue.config.productionTip = false;
|
Vue.config.productionTip = false;
|
||||||
|
|
||||||
|
@ -46,6 +46,8 @@ new Vue({
|
||||||
}).$mount('#app');
|
}).$mount('#app');
|
||||||
|
|
||||||
router.afterEach((to, from) => {
|
router.afterEach((to, from) => {
|
||||||
|
useUIStore().restoreBanner('v1');
|
||||||
|
|
||||||
void runExternalHook('main.routeChange', useWebhooksStore(), { from, to });
|
void runExternalHook('main.routeChange', useWebhooksStore(), { from, to });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -109,6 +109,9 @@
|
||||||
"auth.signup.setupYourAccount": "Set up your account",
|
"auth.signup.setupYourAccount": "Set up your account",
|
||||||
"auth.signup.setupYourAccountError": "Problem setting up your account",
|
"auth.signup.setupYourAccountError": "Problem setting up your account",
|
||||||
"auth.signup.tokenValidationError": "Issue validating invite token",
|
"auth.signup.tokenValidationError": "Issue validating invite token",
|
||||||
|
"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.",
|
||||||
|
"banners.v1.action": "Confirm",
|
||||||
|
"banners.v1.iconTitle": "Dismiss v1 banner",
|
||||||
"binaryDataDisplay.backToList": "Back to list",
|
"binaryDataDisplay.backToList": "Back to list",
|
||||||
"binaryDataDisplay.backToOverviewPage": "Back to overview page",
|
"binaryDataDisplay.backToOverviewPage": "Back to overview page",
|
||||||
"binaryDataDisplay.noDataFoundToDisplay": "No data found to display",
|
"binaryDataDisplay.noDataFoundToDisplay": "No data found to display",
|
||||||
|
|
|
@ -11,3 +11,15 @@ export const faVariable: IconDefinition = {
|
||||||
'M42.6,17.8c2.4,0,7.2-2,7.2-8.4c0-6.4-4.6-6.8-6.1-6.8c-2.8,0-5.6,2-8.1,6.3c-2.5,4.4-5.3,9.1-5.3,9.1 l-0.1,0c-0.6-3.1-1.1-5.6-1.3-6.7c-0.5-2.7-3.6-8.4-9.9-8.4c-6.4,0-12.2,3.7-12.2,3.7l0,0C5.8,7.3,5.1,8.5,5.1,9.9 c0,2.1,1.7,3.9,3.9,3.9c0.6,0,1.2-0.2,1.7-0.4l0,0c0,0,4.8-2.7,5.9,0c0.3,0.8,0.6,1.7,0.9,2.7c1.2,4.2,2.4,9.1,3.3,13.5l-4.2,6 c0,0-4.7-1.7-7.1-1.7s-7.2,2-7.2,8.4s4.6,6.8,6.1,6.8c2.8,0,5.6-2,8.1-6.3c2.5-4.4,5.3-9.1,5.3-9.1c0.8,4,1.5,7.1,1.9,8.5 c1.6,4.5,5.3,7.2,10.1,7.2c0,0,5,0,10.9-3.3c1.4-0.6,2.4-2,2.4-3.6c0-2.1-1.7-3.9-3.9-3.9c-0.6,0-1.2,0.2-1.7,0.4l0,0 c0,0-4.2,2.4-5.6,0.5c-1-2-1.9-4.6-2.6-7.8c-0.6-2.8-1.3-6.2-2-9.5l4.3-6.2C35.5,16.1,40.2,17.8,42.6,17.8z',
|
'M42.6,17.8c2.4,0,7.2-2,7.2-8.4c0-6.4-4.6-6.8-6.1-6.8c-2.8,0-5.6,2-8.1,6.3c-2.5,4.4-5.3,9.1-5.3,9.1 l-0.1,0c-0.6-3.1-1.1-5.6-1.3-6.7c-0.5-2.7-3.6-8.4-9.9-8.4c-6.4,0-12.2,3.7-12.2,3.7l0,0C5.8,7.3,5.1,8.5,5.1,9.9 c0,2.1,1.7,3.9,3.9,3.9c0.6,0,1.2-0.2,1.7-0.4l0,0c0,0,4.8-2.7,5.9,0c0.3,0.8,0.6,1.7,0.9,2.7c1.2,4.2,2.4,9.1,3.3,13.5l-4.2,6 c0,0-4.7-1.7-7.1-1.7s-7.2,2-7.2,8.4s4.6,6.8,6.1,6.8c2.8,0,5.6-2,8.1-6.3c2.5-4.4,5.3-9.1,5.3-9.1c0.8,4,1.5,7.1,1.9,8.5 c1.6,4.5,5.3,7.2,10.1,7.2c0,0,5,0,10.9-3.3c1.4-0.6,2.4-2,2.4-3.6c0-2.1-1.7-3.9-3.9-3.9c-0.6,0-1.2,0.2-1.7,0.4l0,0 c0,0-4.2,2.4-5.6,0.5c-1-2-1.9-4.6-2.6-7.8c-0.6-2.8-1.3-6.2-2-9.5l4.3-6.2C35.5,16.1,40.2,17.8,42.6,17.8z',
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const faXmark: IconDefinition = {
|
||||||
|
prefix: 'fas' as IconPrefix,
|
||||||
|
iconName: 'xmark' as IconName,
|
||||||
|
icon: [
|
||||||
|
400,
|
||||||
|
400,
|
||||||
|
[],
|
||||||
|
'',
|
||||||
|
'M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z',
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
|
@ -134,7 +134,7 @@ import {
|
||||||
faUserLock,
|
faUserLock,
|
||||||
faGem,
|
faGem,
|
||||||
} from '@fortawesome/free-solid-svg-icons';
|
} from '@fortawesome/free-solid-svg-icons';
|
||||||
import { faVariable } from './custom';
|
import { faVariable, faXmark } from './custom';
|
||||||
import { faStickyNote } from '@fortawesome/free-regular-svg-icons';
|
import { faStickyNote } from '@fortawesome/free-regular-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
|
||||||
|
|
||||||
|
@ -277,6 +277,7 @@ export const FontAwesomePlugin: PluginObject<{}> = {
|
||||||
addIcon(faTree);
|
addIcon(faTree);
|
||||||
addIcon(faUserLock);
|
addIcon(faUserLock);
|
||||||
addIcon(faGem);
|
addIcon(faGem);
|
||||||
|
addIcon(faXmark);
|
||||||
|
|
||||||
app.component('font-awesome-icon', FontAwesomeIcon);
|
app.component('font-awesome-icon', FontAwesomeIcon);
|
||||||
},
|
},
|
||||||
|
|
|
@ -212,6 +212,10 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, {
|
||||||
rootStore.setN8nMetadata(settings.n8nMetadata || {});
|
rootStore.setN8nMetadata(settings.n8nMetadata || {});
|
||||||
rootStore.setDefaultLocale(settings.defaultLocale);
|
rootStore.setDefaultLocale(settings.defaultLocale);
|
||||||
rootStore.setIsNpmAvailable(settings.isNpmAvailable);
|
rootStore.setIsNpmAvailable(settings.isNpmAvailable);
|
||||||
|
if (settings.banners.v1.dismissed) {
|
||||||
|
useUIStore().setBanners({ v1: { dismissed: true, mode: 'permanent' } });
|
||||||
|
}
|
||||||
|
|
||||||
useVersionsStore().setVersionNotificationSettings(settings.versionNotifications);
|
useVersionsStore().setVersionNotificationSettings(settings.versionNotifications);
|
||||||
},
|
},
|
||||||
stopShowingSetupPage(): void {
|
stopShowingSetupPage(): void {
|
||||||
|
|
|
@ -52,6 +52,7 @@ import type { BaseTextKey } from '@/plugins/i18n';
|
||||||
import { i18n as locale } from '@/plugins/i18n';
|
import { i18n as locale } from '@/plugins/i18n';
|
||||||
import type { Modals, NewCredentialsModal } from '@/Interface';
|
import type { Modals, NewCredentialsModal } from '@/Interface';
|
||||||
import { useTelemetryStore } from '@/stores/telemetry.store';
|
import { useTelemetryStore } from '@/stores/telemetry.store';
|
||||||
|
import { dismissV1BannerPermanently } from '@/api/ui';
|
||||||
|
|
||||||
export const useUIStore = defineStore(STORES.UI, {
|
export const useUIStore = defineStore(STORES.UI, {
|
||||||
state: (): UIState => ({
|
state: (): UIState => ({
|
||||||
|
@ -139,6 +140,12 @@ export const useUIStore = defineStore(STORES.UI, {
|
||||||
},
|
},
|
||||||
modalStack: [],
|
modalStack: [],
|
||||||
sidebarMenuCollapsed: true,
|
sidebarMenuCollapsed: true,
|
||||||
|
banners: {
|
||||||
|
v1: {
|
||||||
|
dismissed: false,
|
||||||
|
mode: 'temporary',
|
||||||
|
},
|
||||||
|
},
|
||||||
isPageLoading: true,
|
isPageLoading: true,
|
||||||
currentView: '',
|
currentView: '',
|
||||||
mainPanelPosition: 0.5,
|
mainPanelPosition: 0.5,
|
||||||
|
@ -332,6 +339,12 @@ export const useUIStore = defineStore(STORES.UI, {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
setBanners(banners: UIState['banners']): void {
|
||||||
|
this.banners = {
|
||||||
|
...this.banners,
|
||||||
|
...banners,
|
||||||
|
};
|
||||||
|
},
|
||||||
setMode(name: keyof Modals, mode: string): void {
|
setMode(name: keyof Modals, mode: string): void {
|
||||||
this.modals[name] = {
|
this.modals[name] = {
|
||||||
...this.modals[name],
|
...this.modals[name],
|
||||||
|
@ -508,6 +521,22 @@ export const useUIStore = defineStore(STORES.UI, {
|
||||||
toggleSidebarMenuCollapse(): void {
|
toggleSidebarMenuCollapse(): void {
|
||||||
this.sidebarMenuCollapsed = !this.sidebarMenuCollapsed;
|
this.sidebarMenuCollapsed = !this.sidebarMenuCollapsed;
|
||||||
},
|
},
|
||||||
|
async dismissBanner(bannerType: 'v1', mode: 'temporary' | 'permanent'): Promise<void> {
|
||||||
|
if (mode === 'permanent') {
|
||||||
|
await dismissV1BannerPermanently(useRootStore().getRestApiContext);
|
||||||
|
this.banners[bannerType].dismissed = true;
|
||||||
|
this.banners[bannerType].mode = 'permanent';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.banners[bannerType].dismissed = true;
|
||||||
|
this.banners[bannerType].mode = 'temporary';
|
||||||
|
},
|
||||||
|
restoreBanner(bannerType: 'v1'): void {
|
||||||
|
if (this.banners[bannerType].dismissed && this.banners[bannerType].mode === 'temporary') {
|
||||||
|
this.banners[bannerType].dismissed = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
async getCurlToJson(curlCommand: string): Promise<CurlToJSONResponse> {
|
async getCurlToJson(curlCommand: string): Promise<CurlToJSONResponse> {
|
||||||
const rootStore = useRootStore();
|
const rootStore = useRootStore();
|
||||||
return getCurlToJson(rootStore.getRestApiContext, curlCommand);
|
return getCurlToJson(rootStore.getRestApiContext, curlCommand);
|
||||||
|
|
|
@ -2146,4 +2146,9 @@ export interface IN8nUISettings {
|
||||||
variables: {
|
variables: {
|
||||||
limit: number;
|
limit: number;
|
||||||
};
|
};
|
||||||
|
banners: {
|
||||||
|
v1: {
|
||||||
|
dismissed: boolean;
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue