refactor(editor): Decouple REST calls from views (no-changelog) (#5202)

* decouple rest calls

* remove console.log
This commit is contained in:
Michael Auerswald
2023-01-20 12:08:40 +01:00
committed by GitHub
parent 7aa65315cc
commit b69f480d4c
6 changed files with 139 additions and 76 deletions

View File

@@ -0,0 +1,54 @@
import { IRestApiContext } from '@/Interface';
import { makeRestApiRequest } from '@/utils';
import { IDataObject, MessageEventBusDestinationOptions } from 'n8n-workflow';
export async function saveDestinationToDb(
context: IRestApiContext,
destination: MessageEventBusDestinationOptions,
subscribedEvents: string[] = [],
) {
if (destination.id) {
const data: IDataObject = {
...destination,
subscribedEvents,
};
return makeRestApiRequest(context, 'POST', '/eventbus/destination', data);
}
}
export async function deleteDestinationFromDb(context: IRestApiContext, destinationId: string) {
return makeRestApiRequest(context, 'DELETE', `/eventbus/destination?id=${destinationId}`);
}
export async function sendTestMessageToDestination(
context: IRestApiContext,
destination: MessageEventBusDestinationOptions,
) {
if (destination.id) {
const data: IDataObject = {
...destination,
};
return makeRestApiRequest(context, 'GET', '/eventbus/testmessage', data);
}
}
export async function getEventNamesFromBackend(context: IRestApiContext): Promise<string[]> {
return makeRestApiRequest(context, 'GET', '/eventbus/eventnames');
}
export async function getDestinationsFromBackend(
context: IRestApiContext,
): Promise<MessageEventBusDestinationOptions[]> {
return makeRestApiRequest(context, 'GET', '/eventbus/destination');
}
export async function getExecutionEvents(context: IRestApiContext, executionId: string) {
return makeRestApiRequest(context, 'GET', `/eventbus/execution/${executionId}`);
}
export async function recoverExecutionDataFromEvents(
context: IRestApiContext,
executionId: string,
) {
return makeRestApiRequest(context, 'GET', `/eventbus/execution-recover/${executionId}`);
}

View File

@@ -51,7 +51,6 @@ import mixins from 'vue-typed-mixins';
import { EnterpriseEditionFeature } from '@/constants'; import { EnterpriseEditionFeature } from '@/constants';
import { showMessage } from '@/mixins/showMessage'; import { showMessage } from '@/mixins/showMessage';
import { useLogStreamingStore } from '../../stores/logStreamingStore'; import { useLogStreamingStore } from '../../stores/logStreamingStore';
import { restApi } from '@/mixins/restApi';
import Vue from 'vue'; import Vue from 'vue';
import { mapStores } from 'pinia'; import { mapStores } from 'pinia';
import { import {
@@ -59,7 +58,6 @@ import {
defaultMessageEventBusDestinationOptions, defaultMessageEventBusDestinationOptions,
MessageEventBusDestinationOptions, MessageEventBusDestinationOptions,
} from 'n8n-workflow'; } from 'n8n-workflow';
import { saveDestinationToDb } from './Helpers.ee';
import { BaseTextKey } from '../../plugins/i18n'; import { BaseTextKey } from '../../plugins/i18n';
export const DESTINATION_LIST_ITEM_ACTIONS = { export const DESTINATION_LIST_ITEM_ACTIONS = {
@@ -67,7 +65,7 @@ export const DESTINATION_LIST_ITEM_ACTIONS = {
DELETE: 'delete', DELETE: 'delete',
}; };
export default mixins(showMessage, restApi).extend({ export default mixins(showMessage).extend({
data() { data() {
return { return {
EnterpriseEditionFeature, EnterpriseEditionFeature,
@@ -142,7 +140,7 @@ export default mixins(showMessage, restApi).extend({
this.saveDestination(); this.saveDestination();
}, },
async saveDestination() { async saveDestination() {
await saveDestinationToDb(this.restApi(), this.nodeParameters); await this.logStreamingStore.saveDestination(this.nodeParameters);
}, },
async onAction(action: string) { async onAction(action: string) {
if (action === DESTINATION_LIST_ITEM_ACTIONS.OPEN) { if (action === DESTINATION_LIST_ITEM_ACTIONS.OPEN) {

View File

@@ -178,7 +178,6 @@ import mixins from 'vue-typed-mixins';
import { useLogStreamingStore } from '../../stores/logStreamingStore'; import { useLogStreamingStore } from '../../stores/logStreamingStore';
import { useNDVStore } from '../../stores/ndv'; import { useNDVStore } from '../../stores/ndv';
import { useWorkflowsStore } from '../../stores/workflows'; import { useWorkflowsStore } from '../../stores/workflows';
import { restApi } from '../../mixins/restApi';
import ParameterInputList from '@/components/ParameterInputList.vue'; import ParameterInputList from '@/components/ParameterInputList.vue';
import NodeCredentials from '@/components/NodeCredentials.vue'; import NodeCredentials from '@/components/NodeCredentials.vue';
import { IMenuItem, INodeUi, ITab, IUpdateInformation } from '../../Interface'; import { IMenuItem, INodeUi, ITab, IUpdateInformation } from '../../Interface';
@@ -200,7 +199,7 @@ import Modal from '@/components/Modal.vue';
import { showMessage } from '@/mixins/showMessage'; import { showMessage } from '@/mixins/showMessage';
import { useUIStore } from '../../stores/ui'; import { useUIStore } from '../../stores/ui';
import { useUsersStore } from '../../stores/users'; import { useUsersStore } from '../../stores/users';
import { destinationToFakeINodeUi, saveDestinationToDb, sendTestMessage } from './Helpers.ee'; import { destinationToFakeINodeUi } from './Helpers.ee';
import { import {
webhookModalDescription, webhookModalDescription,
sentryModalDescription, sentryModalDescription,
@@ -212,7 +211,7 @@ import SaveButton from '../SaveButton.vue';
import EventSelection from '@/components/SettingsLogStreaming/EventSelection.ee.vue'; import EventSelection from '@/components/SettingsLogStreaming/EventSelection.ee.vue';
import { Checkbox } from 'element-ui'; import { Checkbox } from 'element-ui';
export default mixins(showMessage, restApi).extend({ export default mixins(showMessage).extend({
name: 'event-destination-settings-modal', name: 'event-destination-settings-modal',
props: { props: {
modalName: String, modalName: String,
@@ -427,12 +426,14 @@ export default mixins(showMessage, restApi).extend({
this.nodeParameters = deepCopy(nodeParameters); this.nodeParameters = deepCopy(nodeParameters);
this.workflowsStore.updateNodeProperties({ this.workflowsStore.updateNodeProperties({
name: this.node.name, name: this.node.name,
properties: { parameters: this.nodeParameters as unknown as IDataObject }, properties: { parameters: this.nodeParameters as unknown as IDataObject, position: [0, 0] },
}); });
this.logStreamingStore.updateDestination(this.nodeParameters); if (this.hasOnceBeenSaved) {
this.logStreamingStore.updateDestination(this.nodeParameters);
}
}, },
async sendTestEvent() { async sendTestEvent() {
this.testMessageResult = await sendTestMessage(this.restApi(), this.nodeParameters); this.testMessageResult = await this.logStreamingStore.sendTestMessage(this.nodeParameters);
this.testMessageSent = true; this.testMessageSent = true;
}, },
async removeThis() { async removeThis() {
@@ -467,12 +468,14 @@ export default mixins(showMessage, restApi).extend({
if (this.unchanged || !this.destination.id) { if (this.unchanged || !this.destination.id) {
return; return;
} }
await saveDestinationToDb(this.restApi(), this.nodeParameters); const saveResult = await this.logStreamingStore.saveDestination(this.nodeParameters);
this.hasOnceBeenSaved = true; if (saveResult === true) {
this.testMessageSent = false; this.hasOnceBeenSaved = true;
this.unchanged = true; this.testMessageSent = false;
this.$props.eventBus.$emit('destinationWasSaved', this.destination.id); this.unchanged = true;
this.uiStore.stateIsDirty = false; this.$props.eventBus.$emit('destinationWasSaved', this.destination.id);
this.uiStore.stateIsDirty = false;
}
}, },
}, },
}); });

View File

@@ -1,6 +1,5 @@
import { INodeCredentials, INodeParameters, MessageEventBusDestinationOptions } from 'n8n-workflow'; import { INodeCredentials, INodeParameters, MessageEventBusDestinationOptions } from 'n8n-workflow';
import { INodeUi, IRestApi } from '../../Interface'; import { INodeUi } from '../../Interface';
import { useLogStreamingStore } from '../../stores/logStreamingStore';
export function destinationToFakeINodeUi( export function destinationToFakeINodeUi(
destination: MessageEventBusDestinationOptions, destination: MessageEventBusDestinationOptions,
@@ -20,39 +19,3 @@ export function destinationToFakeINodeUi(
}, },
} as INodeUi; } as INodeUi;
} }
export async function saveDestinationToDb(
restApi: IRestApi,
destination: MessageEventBusDestinationOptions,
) {
const logStreamingStore = useLogStreamingStore();
if (destination.id) {
const data: MessageEventBusDestinationOptions = {
...destination,
subscribedEvents: logStreamingStore.getSelectedEvents(destination.id),
};
try {
await restApi.makeRestApiRequest('POST', '/eventbus/destination', data);
} catch (error) {
console.log(error);
}
logStreamingStore.updateDestination(destination);
}
}
export async function sendTestMessage(
restApi: IRestApi,
destination: MessageEventBusDestinationOptions,
) {
if (destination.id) {
try {
const sendResult = await restApi.makeRestApiRequest('GET', '/eventbus/testmessage', {
id: destination.id,
});
return sendResult;
} catch (error) {
console.log(error);
}
return false;
}
}

View File

@@ -1,5 +1,13 @@
import { deepCopy, MessageEventBusDestinationOptions } from 'n8n-workflow'; import { deepCopy, MessageEventBusDestinationOptions } from 'n8n-workflow';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import {
deleteDestinationFromDb,
getDestinationsFromBackend,
getEventNamesFromBackend,
saveDestinationToDb,
sendTestMessageToDestination,
} from '../api/eventbus.ee';
import { useRootStore } from './n8nRootStore';
export interface EventSelectionItem { export interface EventSelectionItem {
selected: boolean; selected: boolean;
@@ -8,18 +16,19 @@ export interface EventSelectionItem {
label: string; label: string;
} }
export interface EventSelectionGroup extends EventSelectionItem { interface EventSelectionGroup extends EventSelectionItem {
children: EventSelectionItem[]; children: EventSelectionItem[];
} }
export interface TreeAndSelectionStoreItem { interface DestinationStoreItem {
destination: MessageEventBusDestinationOptions; destination: MessageEventBusDestinationOptions;
selectedEvents: Set<string>; selectedEvents: Set<string>;
eventGroups: EventSelectionGroup[]; eventGroups: EventSelectionGroup[];
isNew: boolean;
} }
export interface DestinationSettingsStore { export interface DestinationSettingsStore {
[key: string]: TreeAndSelectionStoreItem; [key: string]: DestinationStoreItem;
} }
export const useLogStreamingStore = defineStore('logStreaming', { export const useLogStreamingStore = defineStore('logStreaming', {
@@ -51,13 +60,15 @@ export const useLogStreamingStore = defineStore('logStreaming', {
return destinations; return destinations;
}, },
updateDestination(destination: MessageEventBusDestinationOptions) { updateDestination(destination: MessageEventBusDestinationOptions) {
this.$patch((state) => { if (destination.id && destination.id in this.items) {
if (destination.id && destination.id in this.items) { this.$patch((state) => {
state.items[destination.id].destination = destination; if (destination.id && destination.id in this.items) {
} state.items[destination.id].destination = destination;
// to trigger refresh }
state.items = deepCopy(state.items); // to trigger refresh
}); state.items = deepCopy(state.items);
});
}
}, },
removeDestination(destinationId: string) { removeDestination(destinationId: string) {
if (!destinationId) return; if (!destinationId) return;
@@ -159,7 +170,8 @@ export const useLogStreamingStore = defineStore('logStreaming', {
destination, destination,
selectedEvents: new Set<string>(), selectedEvents: new Set<string>(),
eventGroups: [], eventGroups: [],
} as TreeAndSelectionStoreItem; isNew: false,
} as DestinationStoreItem;
} }
this.items[destination.id]?.selectedEvents?.clear(); this.items[destination.id]?.selectedEvents?.clear();
if (destination.subscribedEvents) { if (destination.subscribedEvents) {
@@ -173,6 +185,44 @@ export const useLogStreamingStore = defineStore('logStreaming', {
); );
} }
}, },
async saveDestination(destination: MessageEventBusDestinationOptions): Promise<boolean> {
if (destination.id) {
const rootStore = useRootStore();
const selectedEvents = this.getSelectedEvents(destination.id);
try {
await saveDestinationToDb(rootStore.getRestApiContext, destination, selectedEvents);
this.updateDestination(destination);
return true;
} catch (e) {
return false;
}
}
return false;
},
async sendTestMessage(destination: MessageEventBusDestinationOptions) {
if (destination.id) {
const rootStore = useRootStore();
const testResult = await sendTestMessageToDestination(
rootStore.getRestApiContext,
destination,
);
return testResult;
}
return false;
},
async fetchEventNames(): Promise<string[]> {
const rootStore = useRootStore();
return getEventNamesFromBackend(rootStore.getRestApiContext);
},
async fetchDestinations(): Promise<MessageEventBusDestinationOptions[]> {
const rootStore = useRootStore();
return getDestinationsFromBackend(rootStore.getRestApiContext);
},
async deleteDestination(destinationId: string) {
const rootStore = useRootStore();
await deleteDestinationFromDb(rootStore.getRestApiContext, destinationId);
this.removeDestination(destinationId);
},
}, },
}); });

View File

@@ -90,7 +90,6 @@ import { useSettingsStore } from '../stores/settings';
import { useUIStore } from '../stores/ui'; import { useUIStore } from '../stores/ui';
import { LOG_STREAM_MODAL_KEY, EnterpriseEditionFeature } from '../constants'; import { LOG_STREAM_MODAL_KEY, EnterpriseEditionFeature } from '../constants';
import Vue from 'vue'; import Vue from 'vue';
import { restApi } from '../mixins/restApi';
import { import {
deepCopy, deepCopy,
defaultMessageEventBusDestinationOptions, defaultMessageEventBusDestinationOptions,
@@ -99,7 +98,7 @@ import {
import PageViewLayout from '@/components/layouts/PageViewLayout.vue'; import PageViewLayout from '@/components/layouts/PageViewLayout.vue';
import EventDestinationCard from '@/components/SettingsLogStreaming/EventDestinationCard.ee.vue'; import EventDestinationCard from '@/components/SettingsLogStreaming/EventDestinationCard.ee.vue';
export default mixins(restApi).extend({ export default mixins().extend({
name: 'SettingsLogStreamingView', name: 'SettingsLogStreamingView',
props: {}, props: {},
components: { components: {
@@ -125,7 +124,7 @@ export default mixins(restApi).extend({
this.uiStore.nodeViewInitialized = false; this.uiStore.nodeViewInitialized = false;
// fetch Destination data from the backend // fetch Destination data from the backend
await this.getDestinationDataFromREST(); await this.getDestinationDataFromBackend();
// since we are not really integrated into the hooks, we listen to the store and refresh the destinations // since we are not really integrated into the hooks, we listen to the store and refresh the destinations
this.logStreamingStore.$onAction(({ name, after }) => { this.logStreamingStore.$onAction(({ name, after }) => {
@@ -174,18 +173,18 @@ export default mixins(restApi).extend({
}, },
}, },
methods: { methods: {
async getDestinationDataFromREST(): Promise<any> { async getDestinationDataFromBackend(): Promise<void> {
this.logStreamingStore.clearEventNames(); this.logStreamingStore.clearEventNames();
this.logStreamingStore.clearDestinationItemTrees(); this.logStreamingStore.clearDestinationItemTrees();
this.allDestinations = []; this.allDestinations = [];
const eventNamesData = await this.restApi().makeRestApiRequest('get', '/eventbus/eventnames'); const eventNamesData = await this.logStreamingStore.fetchEventNames();
if (eventNamesData) { if (eventNamesData) {
for (const eventName of eventNamesData) { for (const eventName of eventNamesData) {
this.logStreamingStore.addEventName(eventName); this.logStreamingStore.addEventName(eventName);
} }
} }
const destinationData: MessageEventBusDestinationOptions[] = const destinationData: MessageEventBusDestinationOptions[] =
await this.restApi().makeRestApiRequest('get', '/eventbus/destination'); await this.logStreamingStore.fetchDestinations();
if (destinationData) { if (destinationData) {
for (const destination of destinationData) { for (const destination of destinationData) {
this.logStreamingStore.addDestination(destination); this.logStreamingStore.addDestination(destination);
@@ -218,11 +217,7 @@ export default mixins(restApi).extend({
}, },
async onRemove(destinationId?: string) { async onRemove(destinationId?: string) {
if (!destinationId) return; if (!destinationId) return;
await this.restApi().makeRestApiRequest( await this.logStreamingStore.deleteDestination(destinationId);
'DELETE',
`/eventbus/destination?id=${destinationId}`,
);
this.logStreamingStore.removeDestination(destinationId);
const foundNode = this.workflowsStore.getNodeByName(destinationId); const foundNode = this.workflowsStore.getNodeByName(destinationId);
if (foundNode) { if (foundNode) {
this.workflowsStore.removeNode(foundNode); this.workflowsStore.removeNode(foundNode);