mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-25 04:34:06 -08:00
fix(editor): Move versions check to init function and refactor store (no-changelog) (#8067)
This commit is contained in:
parent
faadfd6d4a
commit
fcff34c401
32
cypress/composables/versions.ts
Normal file
32
cypress/composables/versions.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
* Getters
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function getVersionUpdatesPanelOpenButton() {
|
||||||
|
return cy.getByTestId('version-updates-panel-button');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getVersionUpdatesPanel() {
|
||||||
|
return cy.getByTestId('version-updates-panel');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getVersionUpdatesPanelCloseButton() {
|
||||||
|
return getVersionUpdatesPanel().get('.el-drawer__close-btn').first();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getVersionCard() {
|
||||||
|
return cy.getByTestId('version-card');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actions
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function openVersionUpdatesPanel() {
|
||||||
|
getVersionUpdatesPanelOpenButton().click();
|
||||||
|
getVersionUpdatesPanel().should('be.visible');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function closeVersionUpdatesPanel() {
|
||||||
|
getVersionUpdatesPanelCloseButton().click();
|
||||||
|
}
|
66
cypress/e2e/36-versions.cy.ts
Normal file
66
cypress/e2e/36-versions.cy.ts
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
import { INSTANCE_OWNER } from '../constants';
|
||||||
|
import { WorkflowsPage } from '../pages/workflows';
|
||||||
|
import {
|
||||||
|
closeVersionUpdatesPanel,
|
||||||
|
getVersionCard,
|
||||||
|
getVersionUpdatesPanelOpenButton,
|
||||||
|
openVersionUpdatesPanel,
|
||||||
|
} from '../composables/versions';
|
||||||
|
|
||||||
|
const workflowsPage = new WorkflowsPage();
|
||||||
|
|
||||||
|
describe('Versions', () => {
|
||||||
|
it('should open updates panel', () => {
|
||||||
|
cy.intercept('GET', '/rest/settings', (req) => {
|
||||||
|
req.continue((res) => {
|
||||||
|
if (res.body.hasOwnProperty('data')) {
|
||||||
|
res.body.data = {
|
||||||
|
...res.body.data,
|
||||||
|
releaseChannel: 'stable',
|
||||||
|
versionCli: '1.0.0',
|
||||||
|
versionNotifications: {
|
||||||
|
enabled: true,
|
||||||
|
endpoint: 'https://api.n8n.io/api/versions/',
|
||||||
|
infoUrl: 'https://docs.n8n.io/getting-started/installation/updating.html',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).as('settings');
|
||||||
|
|
||||||
|
cy.intercept('GET', 'https://api.n8n.io/api/versions/1.0.0', [
|
||||||
|
{
|
||||||
|
name: '1.3.1',
|
||||||
|
createdAt: '2023-08-18T11:53:12.857Z',
|
||||||
|
hasSecurityIssue: null,
|
||||||
|
hasSecurityFix: null,
|
||||||
|
securityIssueFixVersion: null,
|
||||||
|
hasBreakingChange: null,
|
||||||
|
documentationUrl: 'https://docs.n8n.io/release-notes/#n8n131',
|
||||||
|
nodes: [],
|
||||||
|
description: 'Includes <strong>bug fixes</strong>',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '1.0.5',
|
||||||
|
createdAt: '2023-07-24T10:54:56.097Z',
|
||||||
|
hasSecurityIssue: false,
|
||||||
|
hasSecurityFix: null,
|
||||||
|
securityIssueFixVersion: null,
|
||||||
|
hasBreakingChange: true,
|
||||||
|
documentationUrl: 'https://docs.n8n.io/release-notes/#n8n104',
|
||||||
|
nodes: [],
|
||||||
|
description: 'Includes <strong>core functionality</strong> and <strong>bug fixes</strong>',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
cy.signin(INSTANCE_OWNER);
|
||||||
|
|
||||||
|
cy.visit(workflowsPage.url);
|
||||||
|
cy.wait('@settings');
|
||||||
|
|
||||||
|
getVersionUpdatesPanelOpenButton().should('contain', '2 updates');
|
||||||
|
openVersionUpdatesPanel();
|
||||||
|
getVersionCard().should('have.length', 2);
|
||||||
|
closeVersionUpdatesPanel();
|
||||||
|
});
|
||||||
|
});
|
|
@ -35,7 +35,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
import { newVersions } from '@/mixins/newVersions';
|
|
||||||
|
|
||||||
import BannerStack from '@/components/banners/BannerStack.vue';
|
import BannerStack from '@/components/banners/BannerStack.vue';
|
||||||
import Modals from '@/components/Modals.vue';
|
import Modals from '@/components/Modals.vue';
|
||||||
|
@ -69,15 +68,13 @@ export default defineComponent({
|
||||||
Telemetry,
|
Telemetry,
|
||||||
Modals,
|
Modals,
|
||||||
},
|
},
|
||||||
mixins: [newVersions, userHelpers],
|
mixins: [userHelpers],
|
||||||
setup(props) {
|
setup() {
|
||||||
return {
|
return {
|
||||||
...useGlobalLinkActions(),
|
...useGlobalLinkActions(),
|
||||||
...useHistoryHelper(useRoute()),
|
...useHistoryHelper(useRoute()),
|
||||||
...useToast(),
|
...useToast(),
|
||||||
externalHooks: useExternalHooks(),
|
externalHooks: useExternalHooks(),
|
||||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
||||||
...newVersions.setup?.(props),
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -115,7 +112,6 @@ export default defineComponent({
|
||||||
async mounted() {
|
async mounted() {
|
||||||
this.logHiringBanner();
|
this.logHiringBanner();
|
||||||
|
|
||||||
void this.checkForNewVersions();
|
|
||||||
void initializeAuthenticatedFeatures();
|
void initializeAuthenticatedFeatures();
|
||||||
|
|
||||||
void useExternalHooks().run('app.mount');
|
void useExternalHooks().run('app.mount');
|
||||||
|
|
|
@ -3,14 +3,14 @@ import { useCloudPlanStore } from '@/stores/cloudPlan.store';
|
||||||
import { useSourceControlStore } from '@/stores/sourceControl.store';
|
import { useSourceControlStore } from '@/stores/sourceControl.store';
|
||||||
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||||
import { useRootStore } from '@/stores/n8nRoot.store';
|
import { useRootStore } from '@/stores/n8nRoot.store';
|
||||||
import { initializeAuthenticatedFeatures } from '@/init';
|
import { initializeAuthenticatedFeatures, initializeCore } from '@/init';
|
||||||
import type { SpyInstance } from 'vitest';
|
|
||||||
import { createTestingPinia } from '@pinia/testing';
|
import { createTestingPinia } from '@pinia/testing';
|
||||||
import { setActivePinia } from 'pinia';
|
import { setActivePinia } from 'pinia';
|
||||||
import { useSettingsStore } from '@/stores/settings.store';
|
import { useSettingsStore } from '@/stores/settings.store';
|
||||||
|
import { useVersionsStore } from '@/stores/versions.store';
|
||||||
|
|
||||||
vi.mock('@/stores/users.store', () => ({
|
vi.mock('@/stores/users.store', () => ({
|
||||||
useUsersStore: vi.fn(),
|
useUsersStore: vi.fn().mockReturnValue({ initialize: vi.fn() }),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock('@/stores/n8nRoot.store', () => ({
|
vi.mock('@/stores/n8nRoot.store', () => ({
|
||||||
|
@ -18,22 +18,48 @@ vi.mock('@/stores/n8nRoot.store', () => ({
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('Init', () => {
|
describe('Init', () => {
|
||||||
describe('Authenticated Features', () => {
|
let settingsStore: ReturnType<typeof useSettingsStore>;
|
||||||
let settingsStore: ReturnType<typeof useSettingsStore>;
|
let cloudPlanStore: ReturnType<typeof useCloudPlanStore>;
|
||||||
let cloudPlanStore: ReturnType<typeof useCloudPlanStore>;
|
let sourceControlStore: ReturnType<typeof useSourceControlStore>;
|
||||||
let sourceControlStore: ReturnType<typeof useSourceControlStore>;
|
let usersStore: ReturnType<typeof useUsersStore>;
|
||||||
let nodeTypesStore: ReturnType<typeof useNodeTypesStore>;
|
let nodeTypesStore: ReturnType<typeof useNodeTypesStore>;
|
||||||
let cloudStoreSpy: SpyInstance<[], Promise<void>>;
|
let versionsStore: ReturnType<typeof useVersionsStore>;
|
||||||
let templatesTestSpy: SpyInstance<[], Promise<void>>;
|
|
||||||
let sourceControlSpy: SpyInstance<[], Promise<void>>;
|
|
||||||
let nodeTranslationSpy: SpyInstance<[], Promise<void>>;
|
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeEach(() => {
|
||||||
setActivePinia(createTestingPinia());
|
setActivePinia(createTestingPinia());
|
||||||
settingsStore = useSettingsStore();
|
settingsStore = useSettingsStore();
|
||||||
cloudPlanStore = useCloudPlanStore();
|
cloudPlanStore = useCloudPlanStore();
|
||||||
sourceControlStore = useSourceControlStore();
|
sourceControlStore = useSourceControlStore();
|
||||||
nodeTypesStore = useNodeTypesStore();
|
nodeTypesStore = useNodeTypesStore();
|
||||||
|
usersStore = useUsersStore();
|
||||||
|
versionsStore = useVersionsStore();
|
||||||
|
versionsStore = useVersionsStore();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('initializeCore()', () => {
|
||||||
|
afterEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should initialize core features only once', async () => {
|
||||||
|
const usersStoreSpy = vi.spyOn(usersStore, 'initialize');
|
||||||
|
const settingsStoreSpy = vi.spyOn(settingsStore, 'initialize');
|
||||||
|
const versionsSpy = vi.spyOn(versionsStore, 'checkForNewVersions');
|
||||||
|
|
||||||
|
await initializeCore();
|
||||||
|
|
||||||
|
expect(settingsStoreSpy).toHaveBeenCalled();
|
||||||
|
expect(usersStoreSpy).toHaveBeenCalled();
|
||||||
|
expect(versionsSpy).toHaveBeenCalled();
|
||||||
|
|
||||||
|
await initializeCore();
|
||||||
|
|
||||||
|
expect(settingsStoreSpy).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('initializeAuthenticatedFeatures()', () => {
|
||||||
|
beforeEach(() => {
|
||||||
vi.spyOn(settingsStore, 'isCloudDeployment', 'get').mockReturnValue(true);
|
vi.spyOn(settingsStore, 'isCloudDeployment', 'get').mockReturnValue(true);
|
||||||
vi.spyOn(settingsStore, 'isTemplatesEnabled', 'get').mockReturnValue(true);
|
vi.spyOn(settingsStore, 'isTemplatesEnabled', 'get').mockReturnValue(true);
|
||||||
vi.spyOn(sourceControlStore, 'isEnterpriseSourceControlEnabled', 'get').mockReturnValue(true);
|
vi.spyOn(sourceControlStore, 'isEnterpriseSourceControlEnabled', 'get').mockReturnValue(true);
|
||||||
|
@ -43,10 +69,6 @@ describe('Init', () => {
|
||||||
vi.mock('@/hooks/register', () => ({
|
vi.mock('@/hooks/register', () => ({
|
||||||
initializeCloudHooks: vi.fn(),
|
initializeCloudHooks: vi.fn(),
|
||||||
}));
|
}));
|
||||||
cloudStoreSpy = vi.spyOn(cloudPlanStore, 'initialize');
|
|
||||||
templatesTestSpy = vi.spyOn(settingsStore, 'testTemplatesEndpoint');
|
|
||||||
sourceControlSpy = vi.spyOn(sourceControlStore, 'getPreferences');
|
|
||||||
nodeTranslationSpy = vi.spyOn(nodeTypesStore, 'getNodeTranslationHeaders');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
@ -54,24 +76,40 @@ describe('Init', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not init authenticated features if user is not logged in', async () => {
|
it('should not init authenticated features if user is not logged in', async () => {
|
||||||
|
const cloudStoreSpy = vi.spyOn(cloudPlanStore, 'initialize');
|
||||||
|
const templatesTestSpy = vi.spyOn(settingsStore, 'testTemplatesEndpoint');
|
||||||
|
const sourceControlSpy = vi.spyOn(sourceControlStore, 'getPreferences');
|
||||||
|
const nodeTranslationSpy = vi.spyOn(nodeTypesStore, 'getNodeTranslationHeaders');
|
||||||
vi.mocked(useUsersStore).mockReturnValue({ currentUser: null } as ReturnType<
|
vi.mocked(useUsersStore).mockReturnValue({ currentUser: null } as ReturnType<
|
||||||
typeof useUsersStore
|
typeof useUsersStore
|
||||||
>);
|
>);
|
||||||
|
|
||||||
await initializeAuthenticatedFeatures();
|
await initializeAuthenticatedFeatures();
|
||||||
expect(cloudStoreSpy).not.toHaveBeenCalled();
|
expect(cloudStoreSpy).not.toHaveBeenCalled();
|
||||||
expect(templatesTestSpy).not.toHaveBeenCalled();
|
expect(templatesTestSpy).not.toHaveBeenCalled();
|
||||||
expect(sourceControlSpy).not.toHaveBeenCalled();
|
expect(sourceControlSpy).not.toHaveBeenCalled();
|
||||||
expect(nodeTranslationSpy).not.toHaveBeenCalled();
|
expect(nodeTranslationSpy).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
it('should init authenticated features if user is not logged in', async () => {
|
|
||||||
|
it('should init authenticated features only once if user is logged in', async () => {
|
||||||
|
const cloudStoreSpy = vi.spyOn(cloudPlanStore, 'initialize');
|
||||||
|
const templatesTestSpy = vi.spyOn(settingsStore, 'testTemplatesEndpoint');
|
||||||
|
const sourceControlSpy = vi.spyOn(sourceControlStore, 'getPreferences');
|
||||||
|
const nodeTranslationSpy = vi.spyOn(nodeTypesStore, 'getNodeTranslationHeaders');
|
||||||
vi.mocked(useUsersStore).mockReturnValue({ currentUser: { id: '123' } } as ReturnType<
|
vi.mocked(useUsersStore).mockReturnValue({ currentUser: { id: '123' } } as ReturnType<
|
||||||
typeof useUsersStore
|
typeof useUsersStore
|
||||||
>);
|
>);
|
||||||
|
|
||||||
await initializeAuthenticatedFeatures();
|
await initializeAuthenticatedFeatures();
|
||||||
|
|
||||||
expect(cloudStoreSpy).toHaveBeenCalled();
|
expect(cloudStoreSpy).toHaveBeenCalled();
|
||||||
expect(templatesTestSpy).toHaveBeenCalled();
|
expect(templatesTestSpy).toHaveBeenCalled();
|
||||||
expect(sourceControlSpy).toHaveBeenCalled();
|
expect(sourceControlSpy).toHaveBeenCalled();
|
||||||
expect(nodeTranslationSpy).toHaveBeenCalled();
|
expect(nodeTranslationSpy).toHaveBeenCalled();
|
||||||
|
|
||||||
|
await initializeAuthenticatedFeatures();
|
||||||
|
|
||||||
|
expect(cloudStoreSpy).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -29,7 +29,12 @@
|
||||||
/></template>
|
/></template>
|
||||||
<template #menuSuffix>
|
<template #menuSuffix>
|
||||||
<div>
|
<div>
|
||||||
<div v-if="hasVersionUpdates" :class="$style.updates" @click="openUpdatesPanel">
|
<div
|
||||||
|
v-if="hasVersionUpdates"
|
||||||
|
data-test-id="version-updates-panel-button"
|
||||||
|
:class="$style.updates"
|
||||||
|
@click="openUpdatesPanel"
|
||||||
|
>
|
||||||
<div :class="$style.giftContainer">
|
<div :class="$style.giftContainer">
|
||||||
<GiftNotificationIcon />
|
<GiftNotificationIcon />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<ModalDrawer :name="VERSIONS_MODAL_KEY" direction="ltr" width="520px">
|
<ModalDrawer
|
||||||
|
:name="VERSIONS_MODAL_KEY"
|
||||||
|
direction="ltr"
|
||||||
|
width="520px"
|
||||||
|
data-test-id="version-updates-panel"
|
||||||
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<span :class="$style.title">
|
<span :class="$style.title">
|
||||||
{{ $locale.baseText('updatesPanel.weVeBeenBusy') }}
|
{{ $locale.baseText('updatesPanel.weVeBeenBusy') }}
|
||||||
|
@ -31,7 +36,7 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<n8n-link v-if="infoUrl" :to="infoUrl" :bold="true">
|
<n8n-link v-if="infoUrl" :to="infoUrl" :bold="true">
|
||||||
<font-awesome-icon icon="info-circle"></font-awesome-icon>
|
<font-awesome-icon icon="info-circle" class="mr-2xs" />
|
||||||
<span>
|
<span>
|
||||||
{{ $locale.baseText('updatesPanel.howToUpdateYourN8nVersion') }}
|
{{ $locale.baseText('updatesPanel.howToUpdateYourN8nVersion') }}
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<a v-if="version" :href="version.documentationUrl" target="_blank" :class="$style.card">
|
<a
|
||||||
|
v-if="version"
|
||||||
|
:href="version.documentationUrl"
|
||||||
|
target="_blank"
|
||||||
|
:class="$style.card"
|
||||||
|
data-test-id="version-card"
|
||||||
|
>
|
||||||
<div :class="$style.header">
|
<div :class="$style.header">
|
||||||
<div>
|
<div>
|
||||||
<div :class="$style.name">
|
<div :class="$style.name">
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { useSettingsStore } from '@/stores/settings.store';
|
||||||
import { useSourceControlStore } from '@/stores/sourceControl.store';
|
import { useSourceControlStore } from '@/stores/sourceControl.store';
|
||||||
import { useUsersStore } from '@/stores/users.store';
|
import { useUsersStore } from '@/stores/users.store';
|
||||||
import { initializeCloudHooks } from '@/hooks/register';
|
import { initializeCloudHooks } from '@/hooks/register';
|
||||||
|
import { useVersionsStore } from '@/stores/versions.store';
|
||||||
|
|
||||||
let coreInitialized = false;
|
let coreInitialized = false;
|
||||||
let authenticatedFeaturesInitialized = false;
|
let authenticatedFeaturesInitialized = false;
|
||||||
|
@ -20,10 +21,13 @@ export async function initializeCore() {
|
||||||
|
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
const usersStore = useUsersStore();
|
const usersStore = useUsersStore();
|
||||||
|
const versionsStore = useVersionsStore();
|
||||||
|
|
||||||
await settingsStore.initialize();
|
await settingsStore.initialize();
|
||||||
await usersStore.initialize();
|
await usersStore.initialize();
|
||||||
|
|
||||||
|
void versionsStore.checkForNewVersions();
|
||||||
|
|
||||||
if (settingsStore.isCloudDeployment) {
|
if (settingsStore.isCloudDeployment) {
|
||||||
try {
|
try {
|
||||||
await initializeCloudHooks();
|
await initializeCloudHooks();
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import { useToast } from '@/composables/useToast';
|
|
||||||
import { VERSIONS_MODAL_KEY } from '@/constants';
|
|
||||||
import { mapStores } from 'pinia';
|
|
||||||
import { useUIStore } from '@/stores/ui.store';
|
|
||||||
import { useVersionsStore } from '@/stores/versions.store';
|
|
||||||
|
|
||||||
export const newVersions = defineComponent({
|
|
||||||
setup() {
|
|
||||||
return {
|
|
||||||
...useToast(),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapStores(useUIStore, useVersionsStore),
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
async checkForNewVersions() {
|
|
||||||
const enabled = this.versionsStore.areNotificationsEnabled;
|
|
||||||
if (!enabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.versionsStore.fetchVersions();
|
|
||||||
|
|
||||||
const currentVersion = this.versionsStore.currentVersion;
|
|
||||||
const nextVersions = this.versionsStore.nextVersions;
|
|
||||||
if (currentVersion && currentVersion.hasSecurityIssue && nextVersions.length) {
|
|
||||||
const fixVersion = currentVersion.securityIssueFixVersion;
|
|
||||||
let message = 'Please update to latest version.';
|
|
||||||
if (fixVersion) {
|
|
||||||
message = `Please update to version ${fixVersion} or higher.`;
|
|
||||||
}
|
|
||||||
|
|
||||||
message = `${message} <a class="primary-color">More info</a>`;
|
|
||||||
this.showToast({
|
|
||||||
title: 'Critical update available',
|
|
||||||
message,
|
|
||||||
onClick: () => {
|
|
||||||
this.uiStore.openModal(VERSIONS_MODAL_KEY);
|
|
||||||
},
|
|
||||||
closeOnClick: true,
|
|
||||||
customClass: 'clickable',
|
|
||||||
type: 'warning',
|
|
||||||
duration: 0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1,8 +1,10 @@
|
||||||
import { getNextVersions } from '@/api/versions';
|
import { getNextVersions } from '@/api/versions';
|
||||||
import { STORES } from '@/constants';
|
import { STORES, VERSIONS_MODAL_KEY } from '@/constants';
|
||||||
import type { IVersion, IVersionNotificationSettings, IVersionsState } from '@/Interface';
|
import type { IVersion, IVersionNotificationSettings, IVersionsState } from '@/Interface';
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { useRootStore } from './n8nRoot.store';
|
import { useRootStore } from './n8nRoot.store';
|
||||||
|
import { useToast } from '@/composables/useToast';
|
||||||
|
import { useUIStore } from '@/stores/ui.store';
|
||||||
|
|
||||||
export const useVersionsStore = defineStore(STORES.VERSIONS, {
|
export const useVersionsStore = defineStore(STORES.VERSIONS, {
|
||||||
state: (): IVersionsState => ({
|
state: (): IVersionsState => ({
|
||||||
|
@ -45,5 +47,40 @@ export const useVersionsStore = defineStore(STORES.VERSIONS, {
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
},
|
},
|
||||||
|
async checkForNewVersions() {
|
||||||
|
const enabled = this.areNotificationsEnabled;
|
||||||
|
if (!enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { showToast } = useToast();
|
||||||
|
const uiStore = useUIStore();
|
||||||
|
|
||||||
|
await this.fetchVersions();
|
||||||
|
|
||||||
|
const currentVersion = this.currentVersion;
|
||||||
|
const nextVersions = this.nextVersions;
|
||||||
|
|
||||||
|
if (currentVersion && currentVersion.hasSecurityIssue && nextVersions.length) {
|
||||||
|
const fixVersion = currentVersion.securityIssueFixVersion;
|
||||||
|
let message = 'Please update to latest version.';
|
||||||
|
if (fixVersion) {
|
||||||
|
message = `Please update to version ${fixVersion} or higher.`;
|
||||||
|
}
|
||||||
|
|
||||||
|
message = `${message} <a class="primary-color">More info</a>`;
|
||||||
|
showToast({
|
||||||
|
title: 'Critical update available',
|
||||||
|
message,
|
||||||
|
onClick: () => {
|
||||||
|
uiStore.openModal(VERSIONS_MODAL_KEY);
|
||||||
|
},
|
||||||
|
closeOnClick: true,
|
||||||
|
customClass: 'clickable',
|
||||||
|
type: 'warning',
|
||||||
|
duration: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue