Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 2 commits into from
Jan 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions packages/editor-ui/src/api/eventbus.ee.ts
Original file line number Diff line number Diff line change
@@ -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}`);
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,23 +51,21 @@ import mixins from 'vue-typed-mixins';
import { EnterpriseEditionFeature } from '@/constants';
import { showMessage } from '@/mixins/showMessage';
import { useLogStreamingStore } from '../../stores/logStreamingStore';
import { restApi } from '@/mixins/restApi';
import Vue from 'vue';
import { mapStores } from 'pinia';
import {
deepCopy,
defaultMessageEventBusDestinationOptions,
MessageEventBusDestinationOptions,
} from 'n8n-workflow';
import { saveDestinationToDb } from './Helpers.ee';
import { BaseTextKey } from '../../plugins/i18n';

export const DESTINATION_LIST_ITEM_ACTIONS = {
OPEN: 'open',
DELETE: 'delete',
};

export default mixins(showMessage, restApi).extend({
export default mixins(showMessage).extend({
data() {
return {
EnterpriseEditionFeature,
Expand Down Expand Up @@ -142,7 +140,7 @@ export default mixins(showMessage, restApi).extend({
this.saveDestination();
},
async saveDestination() {
await saveDestinationToDb(this.restApi(), this.nodeParameters);
await this.logStreamingStore.saveDestination(this.nodeParameters);
},
async onAction(action: string) {
if (action === DESTINATION_LIST_ITEM_ACTIONS.OPEN) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,6 @@ import mixins from 'vue-typed-mixins';
import { useLogStreamingStore } from '../../stores/logStreamingStore';
import { useNDVStore } from '../../stores/ndv';
import { useWorkflowsStore } from '../../stores/workflows';
import { restApi } from '../../mixins/restApi';
import ParameterInputList from '@/components/ParameterInputList.vue';
import NodeCredentials from '@/components/NodeCredentials.vue';
import { IMenuItem, INodeUi, ITab, IUpdateInformation } from '../../Interface';
Expand All @@ -200,7 +199,7 @@ import Modal from '@/components/Modal.vue';
import { showMessage } from '@/mixins/showMessage';
import { useUIStore } from '../../stores/ui';
import { useUsersStore } from '../../stores/users';
import { destinationToFakeINodeUi, saveDestinationToDb, sendTestMessage } from './Helpers.ee';
import { destinationToFakeINodeUi } from './Helpers.ee';
import {
webhookModalDescription,
sentryModalDescription,
Expand All @@ -212,7 +211,7 @@ import SaveButton from '../SaveButton.vue';
import EventSelection from '@/components/SettingsLogStreaming/EventSelection.ee.vue';
import { Checkbox } from 'element-ui';

export default mixins(showMessage, restApi).extend({
export default mixins(showMessage).extend({
name: 'event-destination-settings-modal',
props: {
modalName: String,
Expand Down Expand Up @@ -427,12 +426,14 @@ export default mixins(showMessage, restApi).extend({
this.nodeParameters = deepCopy(nodeParameters);
this.workflowsStore.updateNodeProperties({
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() {
this.testMessageResult = await sendTestMessage(this.restApi(), this.nodeParameters);
this.testMessageResult = await this.logStreamingStore.sendTestMessage(this.nodeParameters);
this.testMessageSent = true;
},
async removeThis() {
Expand Down Expand Up @@ -467,12 +468,14 @@ export default mixins(showMessage, restApi).extend({
if (this.unchanged || !this.destination.id) {
return;
}
await saveDestinationToDb(this.restApi(), this.nodeParameters);
this.hasOnceBeenSaved = true;
this.testMessageSent = false;
this.unchanged = true;
this.$props.eventBus.$emit('destinationWasSaved', this.destination.id);
this.uiStore.stateIsDirty = false;
const saveResult = await this.logStreamingStore.saveDestination(this.nodeParameters);
if (saveResult === true) {
this.hasOnceBeenSaved = true;
this.testMessageSent = false;
this.unchanged = true;
this.$props.eventBus.$emit('destinationWasSaved', this.destination.id);
this.uiStore.stateIsDirty = false;
}
},
},
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { INodeCredentials, INodeParameters, MessageEventBusDestinationOptions } from 'n8n-workflow';
import { INodeUi, IRestApi } from '../../Interface';
import { useLogStreamingStore } from '../../stores/logStreamingStore';
import { INodeUi } from '../../Interface';

export function destinationToFakeINodeUi(
destination: MessageEventBusDestinationOptions,
Expand All @@ -20,39 +19,3 @@ export function destinationToFakeINodeUi(
},
} 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;
}
}
72 changes: 61 additions & 11 deletions packages/editor-ui/src/stores/logStreamingStore.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import { deepCopy, MessageEventBusDestinationOptions } from 'n8n-workflow';
import { defineStore } from 'pinia';
import {
deleteDestinationFromDb,
getDestinationsFromBackend,
getEventNamesFromBackend,
saveDestinationToDb,
sendTestMessageToDestination,
} from '../api/eventbus.ee';
import { useRootStore } from './n8nRootStore';

export interface EventSelectionItem {
selected: boolean;
Expand All @@ -8,18 +16,19 @@ export interface EventSelectionItem {
label: string;
}

export interface EventSelectionGroup extends EventSelectionItem {
interface EventSelectionGroup extends EventSelectionItem {
children: EventSelectionItem[];
}

export interface TreeAndSelectionStoreItem {
interface DestinationStoreItem {
destination: MessageEventBusDestinationOptions;
selectedEvents: Set<string>;
eventGroups: EventSelectionGroup[];
isNew: boolean;
}

export interface DestinationSettingsStore {
[key: string]: TreeAndSelectionStoreItem;
[key: string]: DestinationStoreItem;
}

export const useLogStreamingStore = defineStore('logStreaming', {
Expand Down Expand Up @@ -51,13 +60,15 @@ export const useLogStreamingStore = defineStore('logStreaming', {
return destinations;
},
updateDestination(destination: MessageEventBusDestinationOptions) {
this.$patch((state) => {
if (destination.id && destination.id in this.items) {
state.items[destination.id].destination = destination;
}
// to trigger refresh
state.items = deepCopy(state.items);
});
if (destination.id && destination.id in this.items) {
this.$patch((state) => {
if (destination.id && destination.id in this.items) {
state.items[destination.id].destination = destination;
}
// to trigger refresh
state.items = deepCopy(state.items);
});
}
},
removeDestination(destinationId: string) {
if (!destinationId) return;
Expand Down Expand Up @@ -159,7 +170,8 @@ export const useLogStreamingStore = defineStore('logStreaming', {
destination,
selectedEvents: new Set<string>(),
eventGroups: [],
} as TreeAndSelectionStoreItem;
isNew: false,
} as DestinationStoreItem;
}
this.items[destination.id]?.selectedEvents?.clear();
if (destination.subscribedEvents) {
Expand All @@ -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);
},
},
});

Expand Down
17 changes: 6 additions & 11 deletions packages/editor-ui/src/views/SettingsLogStreamingView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ import { useSettingsStore } from '../stores/settings';
import { useUIStore } from '../stores/ui';
import { LOG_STREAM_MODAL_KEY, EnterpriseEditionFeature } from '../constants';
import Vue from 'vue';
import { restApi } from '../mixins/restApi';
import {
deepCopy,
defaultMessageEventBusDestinationOptions,
Expand All @@ -99,7 +98,7 @@ import {
import PageViewLayout from '@/components/layouts/PageViewLayout.vue';
import EventDestinationCard from '@/components/SettingsLogStreaming/EventDestinationCard.ee.vue';

export default mixins(restApi).extend({
export default mixins().extend({
name: 'SettingsLogStreamingView',
props: {},
components: {
Expand All @@ -125,7 +124,7 @@ export default mixins(restApi).extend({
this.uiStore.nodeViewInitialized = false;

// 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
this.logStreamingStore.$onAction(({ name, after }) => {
Expand Down Expand Up @@ -174,18 +173,18 @@ export default mixins(restApi).extend({
},
},
methods: {
async getDestinationDataFromREST(): Promise<any> {
async getDestinationDataFromBackend(): Promise<void> {
this.logStreamingStore.clearEventNames();
this.logStreamingStore.clearDestinationItemTrees();
this.allDestinations = [];
const eventNamesData = await this.restApi().makeRestApiRequest('get', '/eventbus/eventnames');
const eventNamesData = await this.logStreamingStore.fetchEventNames();
if (eventNamesData) {
for (const eventName of eventNamesData) {
this.logStreamingStore.addEventName(eventName);
}
}
const destinationData: MessageEventBusDestinationOptions[] =
await this.restApi().makeRestApiRequest('get', '/eventbus/destination');
await this.logStreamingStore.fetchDestinations();
if (destinationData) {
for (const destination of destinationData) {
this.logStreamingStore.addDestination(destination);
Expand Down Expand Up @@ -218,11 +217,7 @@ export default mixins(restApi).extend({
},
async onRemove(destinationId?: string) {
if (!destinationId) return;
await this.restApi().makeRestApiRequest(
'DELETE',
`/eventbus/destination?id=${destinationId}`,
);
this.logStreamingStore.removeDestination(destinationId);
await this.logStreamingStore.deleteDestination(destinationId);
const foundNode = this.workflowsStore.getNodeByName(destinationId);
if (foundNode) {
this.workflowsStore.removeNode(foundNode);
Expand Down