feat: Replace new Vue() with custom event bus (no-changelog) (#5780)

* refactor: replace new Vue() with custom event bus (no-changelog)

* fix: export types from design system main

* fix: update component types

* fix: update form inputs event bus
This commit is contained in:
Alex Grozav 2023-04-06 16:32:45 +03:00 committed by GitHub
parent 89c12fc1a7
commit 5651a52364
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
67 changed files with 347 additions and 210 deletions

View file

@ -7,7 +7,8 @@
"name": "Mutasem Aldmour",
"email": "mutasem@n8n.io"
},
"main": "src/main.js",
"main": "src/main.ts",
"import": "src/main.ts",
"repository": {
"type": "git",
"url": "git+https://github.com/n8n-io/n8n.git"

View file

@ -43,6 +43,7 @@ import N8nFormInputs from '../N8nFormInputs';
import N8nHeading from '../N8nHeading';
import N8nLink from '../N8nLink';
import N8nButton from '../N8nButton';
import { createEventBus } from '../../utils';
export default Vue.extend({
name: 'n8n-form-box',
@ -81,7 +82,7 @@ export default Vue.extend({
},
data() {
return {
formBus: new Vue(),
formBus: createEventBus(),
};
},
methods: {
@ -92,7 +93,7 @@ export default Vue.extend({
this.$emit('submit', e);
},
onButtonClick() {
this.formBus.$emit('submit');
this.formBus.emit('submit');
},
onSecondaryButtonClick(event: Event) {
this.$emit('secondaryClick', event);

View file

@ -37,10 +37,11 @@
</template>
<script lang="ts">
import Vue from 'vue';
import Vue, { PropType } from 'vue';
import N8nFormInput from '../N8nFormInput';
import type { IFormInput } from '../../types';
import ResizeObserver from '../ResizeObserver';
import { EventBus } from '@/utils';
export default Vue.extend({
name: 'n8n-form-inputs',
@ -56,7 +57,7 @@ export default Vue.extend({
},
},
eventBus: {
type: Vue,
type: Object as PropType<EventBus>,
},
columnView: {
type: Boolean,
@ -83,7 +84,7 @@ export default Vue.extend({
});
if (this.eventBus) {
this.eventBus.$on('submit', this.onSubmit); // eslint-disable-line @typescript-eslint/unbound-method
this.eventBus.on('submit', this.onSubmit); // eslint-disable-line @typescript-eslint/unbound-method
}
},
computed: {

View file

@ -52,7 +52,7 @@ export default Vue.extend({
applied.push(this.bold ? 'bold' : 'regular');
return applied.map((c) => (this.$style as { [key: string]: string })[c]);
return applied.map((c) => this.$style[c]);
},
},
});

View file

@ -6,7 +6,6 @@
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
name: 'n8n-text',
props: {
@ -67,7 +66,7 @@ export default Vue.extend({
applied.push(this.bold ? 'bold' : 'regular');
return applied.map((c) => (this.$style as { [key: string]: string })[c]);
return applied.map((c) => this.$style[c]);
},
},
});

View file

@ -1,18 +0,0 @@
import Vue from 'vue';
import * as locale from './locale';
declare module 'vue/types/vue' {
interface Vue {
$style: Record<string, string>;
t: (key: string, options?: object) => string;
}
}
declare module 'n8n-design-system' {
export * from './components';
export { N8nUsersList, N8nUserSelect } from './components';
export { locale };
}
export * from './types';
export { locale } from './locale';

View file

@ -1,4 +1,6 @@
import * as locale from './locale';
import designSystemComponents from './plugins/n8nComponents';
export * from './types';
export * from './utils';
export { locale, designSystemComponents };

View file

@ -0,0 +1,7 @@
import * as Vue from 'vue';
declare module 'vue/types/vue' {
interface Vue {
$style: Record<string, string>;
}
}

View file

@ -1,4 +1,4 @@
export * from './button';
export * from './form';
export * from './user';
export * from './menu';
export * from './button';

View file

@ -0,0 +1,62 @@
import { createEventBus } from '../event-bus';
describe('createEventBus()', () => {
const eventBus = createEventBus();
describe('on()', () => {
it('should register event handler', () => {
const handler = vi.fn();
const eventName = 'test';
eventBus.on(eventName, handler);
eventBus.emit(eventName, {});
expect(handler).toHaveBeenCalled();
});
it('should return unregister fn', () => {
const handler = vi.fn();
const eventName = 'test';
const unregister = eventBus.on(eventName, handler);
unregister();
eventBus.emit(eventName, {});
expect(handler).not.toHaveBeenCalled();
});
});
describe('off()', () => {
it('should register event handler', () => {
const handler = vi.fn();
const eventName = 'test';
eventBus.on(eventName, handler);
eventBus.off(eventName, handler);
eventBus.emit(eventName, {});
expect(handler).not.toHaveBeenCalled();
});
});
describe('emit()', () => {
it('should call handlers with given event', () => {
const handlerA = vi.fn();
const handlerB = vi.fn();
const eventName = 'test';
const event = new Event(eventName);
eventBus.on(eventName, handlerA);
eventBus.on(eventName, handlerB);
eventBus.emit(eventName, event);
expect(handlerA).toHaveBeenCalledWith(event);
expect(handlerB).toHaveBeenCalledWith(event);
});
});
});

View file

@ -0,0 +1,47 @@
// eslint-disable-next-line @typescript-eslint/ban-types
export type CallbackFn = Function;
export type UnregisterFn = () => void;
export function createEventBus() {
const handlers = new Map<string, CallbackFn[]>();
function off(eventName: string, fn: CallbackFn) {
const eventFns = handlers.get(eventName);
if (eventFns) {
eventFns.splice(eventFns.indexOf(fn) >>> 0, 1);
}
}
function on(eventName: string, fn: CallbackFn): UnregisterFn {
let eventFns = handlers.get(eventName);
if (!eventFns) {
eventFns = [fn];
} else {
eventFns.push(fn);
}
handlers.set(eventName, eventFns);
return () => off(eventName, fn);
}
function emit<T = Event>(eventName: string, event?: T) {
const eventFns = handlers.get(eventName);
if (eventFns) {
eventFns.slice().forEach(async (handler) => {
await handler(event);
});
}
}
return {
on,
off,
emit,
};
}
export type EventBus = ReturnType<typeof createEventBus>;

View file

@ -1,3 +1,4 @@
export * from './event-bus';
export * from './markdown';
export * from './uid';
export * from './valueByPath';

View file

@ -16,7 +16,7 @@ export default mergeConfig(
},
build: {
lib: {
entry: resolve(__dirname, 'src', 'main.js'),
entry: resolve(__dirname, 'src', 'main.ts'),
name: 'N8nDesignSystem',
fileName: (format) => `n8n-design-system.${format}.js`,
},

View file

@ -60,6 +60,7 @@ import { ABOUT_MODAL_KEY } from '../constants';
import { mapStores } from 'pinia';
import { useSettingsStore } from '@/stores/settings';
import { useRootStore } from '@/stores/n8nRootStore';
import { createEventBus } from '@/event-bus';
export default Vue.extend({
name: 'About',
@ -69,7 +70,7 @@ export default Vue.extend({
data() {
return {
ABOUT_MODAL_KEY,
modalBus: new Vue(),
modalBus: createEventBus(),
};
},
computed: {
@ -77,7 +78,7 @@ export default Vue.extend({
},
methods: {
closeDialog() {
this.modalBus.$emit('close');
this.modalBus.emit('close');
},
},
});

View file

@ -49,6 +49,7 @@ import { mapStores } from 'pinia';
import { useUIStore } from '@/stores/ui';
import { useWorkflowsStore } from '@/stores/workflows';
import { useNodeTypesStore } from '@/stores/nodeTypes';
import { createEventBus } from '@/event-bus';
export default Vue.extend({
name: 'ActivationModal',
@ -60,7 +61,7 @@ export default Vue.extend({
return {
WORKFLOW_ACTIVE_MODAL_KEY,
checked: false,
modalBus: new Vue(),
modalBus: createEventBus(),
};
},
methods: {

View file

@ -33,11 +33,11 @@ import mixins from 'vue-typed-mixins';
import { showMessage } from '@/mixins/showMessage';
import Modal from './Modal.vue';
import Vue from 'vue';
import { IFormInputs } from '@/Interface';
import { CHANGE_PASSWORD_MODAL_KEY } from '../constants';
import { mapStores } from 'pinia';
import { useUsersStore } from '@/stores/users';
import { createEventBus } from '@/event-bus';
export default mixins(showMessage).extend({
components: { Modal },
@ -50,8 +50,8 @@ export default mixins(showMessage).extend({
data() {
return {
config: null as null | IFormInputs,
formBus: new Vue(),
modalBus: new Vue(),
formBus: createEventBus(),
modalBus: createEventBus(),
password: '',
loading: false,
CHANGE_PASSWORD_MODAL_KEY,
@ -133,14 +133,14 @@ export default mixins(showMessage).extend({
message: this.$locale.baseText('auth.changePassword.passwordUpdatedMessage'),
});
this.modalBus.$emit('close');
this.modalBus.emit('close');
} catch (error) {
this.$showError(error, this.$locale.baseText('auth.changePassword.error'));
}
this.loading = false;
},
onSubmitClick() {
this.formBus.$emit('submit');
this.formBus.emit('submit');
},
},
});

View file

@ -14,7 +14,7 @@ import { linterExtension } from './linter';
import { completerExtension } from './completer';
import { CODE_NODE_EDITOR_THEME } from './theme';
import { workflowHelpers } from '@/mixins/workflowHelpers'; // for json field completions
import { codeNodeEditorEventBus } from '@/event-bus/code-node-editor-event-bus';
import { codeNodeEditorEventBus } from '@/event-bus';
import { CODE_NODE_TYPE } from '@/constants';
import { ALL_ITEMS_PLACEHOLDER, EACH_ITEM_PLACEHOLDER } from './constants';
import { mapStores } from 'pinia';
@ -133,10 +133,10 @@ export default mixins(linterExtension, completerExtension, workflowHelpers).exte
},
},
destroyed() {
codeNodeEditorEventBus.$off('error-line-number', this.highlightLine);
codeNodeEditorEventBus.off('error-line-number', this.highlightLine);
},
mounted() {
codeNodeEditorEventBus.$on('error-line-number', this.highlightLine);
codeNodeEditorEventBus.on('error-line-number', this.highlightLine);
const stateBasedExtensions = [
this.linterCompartment.of(this.linterExtension()),

View file

@ -88,7 +88,6 @@
</template>
<script lang="ts">
import Vue from 'vue';
import Modal from './Modal.vue';
import {
COMMUNITY_PACKAGE_INSTALL_MODAL_KEY,
@ -100,6 +99,7 @@ import mixins from 'vue-typed-mixins';
import { showMessage } from '@/mixins/showMessage';
import { mapStores } from 'pinia';
import { useCommunityNodesStore } from '@/stores/communityNodes';
import { createEventBus } from '@/event-bus';
export default mixins(showMessage).extend({
name: 'CommunityPackageInstallModal',
@ -111,7 +111,7 @@ export default mixins(showMessage).extend({
loading: false,
packageName: '',
userAgreed: false,
modalBus: new Vue(),
modalBus: createEventBus(),
checkboxWarning: false,
infoTextErrorMessage: '',
COMMUNITY_PACKAGE_INSTALL_MODAL_KEY,
@ -143,7 +143,7 @@ export default mixins(showMessage).extend({
// TODO: We need to fetch a fresh list of installed packages until proper response is implemented on the back-end
await this.communityNodesStore.fetchInstalledPackages();
this.loading = false;
this.modalBus.$emit('close');
this.modalBus.emit('close');
this.$showMessage({
title: this.$locale.baseText('settings.communityNodes.messages.install.success'),
type: 'success',

View file

@ -35,7 +35,6 @@
</template>
<script>
import Vue from 'vue';
import mixins from 'vue-typed-mixins';
import Modal from './Modal.vue';
import {
@ -45,6 +44,7 @@ import {
import { showMessage } from '@/mixins/showMessage';
import { mapStores } from 'pinia';
import { useCommunityNodesStore } from '@/stores/communityNodes';
import { createEventBus } from '@/event-bus';
export default mixins(showMessage).extend({
name: 'CommunityPackageManageConfirmModal',
@ -67,7 +67,7 @@ export default mixins(showMessage).extend({
data() {
return {
loading: false,
modalBus: new Vue(),
modalBus: createEventBus(),
COMMUNITY_PACKAGE_CONFIRM_MODAL_KEY,
COMMUNITY_PACKAGE_MANAGE_ACTIONS,
};
@ -151,7 +151,7 @@ export default mixins(showMessage).extend({
);
} finally {
this.loading = false;
this.modalBus.$emit('close');
this.modalBus.emit('close');
}
},
async onUpdate() {
@ -187,7 +187,7 @@ export default mixins(showMessage).extend({
);
} finally {
this.loading = false;
this.modalBus.$emit('close');
this.modalBus.emit('close');
}
},
},

View file

@ -33,7 +33,6 @@
</template>
<script lang="ts">
import Vue from 'vue';
import mixins from 'vue-typed-mixins';
import { IN8nPromptResponse } from '@/Interface';
@ -43,6 +42,7 @@ import Modal from './Modal.vue';
import { mapStores } from 'pinia';
import { useSettingsStore } from '@/stores/settings';
import { useRootStore } from '@/stores/n8nRootStore';
import { createEventBus } from '@/event-bus';
export default mixins(workflowHelpers).extend({
components: { Modal },
@ -51,7 +51,7 @@ export default mixins(workflowHelpers).extend({
data() {
return {
email: '',
modalBus: new Vue(),
modalBus: createEventBus(),
};
},
computed: {
@ -100,7 +100,7 @@ export default mixins(workflowHelpers).extend({
type: 'success',
});
}
this.modalBus.$emit('close');
this.modalBus.emit('close');
}
},
},

View file

@ -143,7 +143,7 @@ import { CREDENTIAL_EDIT_MODAL_KEY, EnterpriseEditionFeature } from '@/constants
import { IDataObject } from 'n8n-workflow';
import FeatureComingSoon from '../FeatureComingSoon.vue';
import { getCredentialPermissions, IPermissions } from '@/permissions';
import { IMenuItem } from 'n8n-design-system';
import { createEventBus, IMenuItem } from 'n8n-design-system';
import { mapStores } from 'pinia';
import { useUIStore } from '@/stores/ui';
import { useSettingsStore } from '@/stores/settings';
@ -195,7 +195,7 @@ export default mixins(showMessage, nodeHelpers).extend({
credentialId: '',
credentialName: '',
credentialData: {} as ICredentialDataDecryptedObject,
modalBus: new Vue(),
modalBus: createEventBus(),
nodeAccess: {} as NodeAccessMap,
isDeleting: false,
isSaving: false,
@ -645,7 +645,7 @@ export default mixins(showMessage, nodeHelpers).extend({
};
},
closeDialog() {
this.modalBus.$emit('close');
this.modalBus.emit('close');
},
getParentTypes(name: string): string[] {

View file

@ -178,7 +178,7 @@ export default mixins(showMessage).extend({
},
goToUsersSettings() {
this.$router.push({ name: VIEWS.USERS_SETTINGS });
this.modalBus.$emit('close');
this.modalBus.emit('close');
},
goToUpgrade() {
const linkUrlTranslationKey = this.uiStore.contextBasedTranslationKeys

View file

@ -58,7 +58,6 @@
</template>
<script lang="ts">
import Vue from 'vue';
import mixins from 'vue-typed-mixins';
import Modal from './Modal.vue';
import { CREDENTIAL_SELECT_MODAL_KEY } from '../constants';
@ -67,6 +66,7 @@ import { mapStores } from 'pinia';
import { useUIStore } from '@/stores/ui';
import { useWorkflowsStore } from '@/stores/workflows';
import { useCredentialsStore } from '@/stores/credentials';
import { createEventBus } from '@/event-bus';
export default mixins(externalHooks).extend({
name: 'CredentialsSelectModal',
@ -88,7 +88,7 @@ export default mixins(externalHooks).extend({
},
data() {
return {
modalBus: new Vue(),
modalBus: createEventBus(),
selected: '',
loading: true,
CREDENTIAL_SELECT_MODAL_KEY,
@ -102,7 +102,7 @@ export default mixins(externalHooks).extend({
this.selected = type;
},
openCredentialType() {
this.modalBus.$emit('close');
this.modalBus.emit('close');
this.uiStore.openNewCredential(this.selected);
const telemetryPayload = {

View file

@ -74,10 +74,10 @@ import mixins from 'vue-typed-mixins';
import { showMessage } from '@/mixins/showMessage';
import Modal from './Modal.vue';
import Vue from 'vue';
import { IUser } from '../Interface';
import { mapStores } from 'pinia';
import { useUsersStore } from '@/stores/users';
import { createEventBus } from '@/event-bus';
export default mixins(showMessage).extend({
components: {
@ -94,7 +94,7 @@ export default mixins(showMessage).extend({
},
data() {
return {
modalBus: new Vue(),
modalBus: createEventBus(),
loading: false,
operation: '',
deleteConfirmText: '',
@ -175,7 +175,7 @@ export default mixins(showMessage).extend({
message,
});
this.modalBus.$emit('close');
this.modalBus.emit('close');
} catch (error) {
this.$showError(error, this.$locale.baseText('settings.users.userDeletedError'));
}

View file

@ -49,7 +49,6 @@
</template>
<script lang="ts">
import Vue from 'vue';
import mixins from 'vue-typed-mixins';
import { MAX_WORKFLOW_NAME_LENGTH, PLACEHOLDER_EMPTY_WORKFLOW_ID } from '@/constants';
@ -64,6 +63,7 @@ import { useWorkflowsStore } from '@/stores/workflows';
import { IWorkflowDataUpdate } from '@/Interface';
import { getWorkflowPermissions, IPermissions } from '@/permissions';
import { useUsersStore } from '@/stores/users';
import { createEventBus } from '@/event-bus';
export default mixins(showMessage, workflowHelpers, restApi).extend({
components: { TagsDropdown, Modal },
@ -76,8 +76,8 @@ export default mixins(showMessage, workflowHelpers, restApi).extend({
name: '',
currentTagIds,
isSaving: false,
modalBus: new Vue(),
dropdownBus: new Vue(),
modalBus: createEventBus(),
dropdownBus: createEventBus(),
MAX_WORKFLOW_NAME_LENGTH,
prevTagIds: currentTagIds,
};
@ -112,7 +112,7 @@ export default mixins(showMessage, workflowHelpers, restApi).extend({
},
methods: {
focusOnSelect() {
this.dropdownBus.$emit('focus');
this.dropdownBus.emit('focus');
},
focusOnNameInput() {
const input = this.$refs.nameInput as HTMLElement;
@ -195,7 +195,7 @@ export default mixins(showMessage, workflowHelpers, restApi).extend({
}
},
closeDialog(): void {
this.modalBus.$emit('close');
this.modalBus.emit('close');
},
},
});

View file

@ -11,6 +11,7 @@ import Vue from 'vue';
import ExecutionsList from '@/components/ExecutionsList.vue';
import Modal from '@/components/Modal.vue';
import { EXECUTIONS_MODAL_KEY } from '@/constants';
import { createEventBus } from '@/event-bus';
export default Vue.extend({
name: 'ExecutionsModal',
@ -20,13 +21,13 @@ export default Vue.extend({
},
data() {
return {
modalBus: new Vue(),
modalBus: createEventBus(),
EXECUTIONS_MODAL_KEY,
};
},
methods: {
onCloseModal() {
this.modalBus.$emit('close');
this.modalBus.emit('close');
},
},
});

View file

@ -16,13 +16,22 @@
</template>
<script lang="ts">
import Vue from 'vue';
import Vue, { PropType } from 'vue';
import ExpandableInputBase from './ExpandableInputBase.vue';
import { EventBus } from '@/event-bus';
export default Vue.extend({
components: { ExpandableInputBase },
name: 'ExpandableInputEdit',
props: ['value', 'placeholder', 'maxlength', 'autofocus', 'eventBus'],
props: {
value: {},
placeholder: {},
maxlength: {},
autofocus: {},
eventBus: {
type: Object as PropType<EventBus>,
},
},
mounted() {
// autofocus on input element is not reliable
if (this.$props.autofocus && this.$refs.input) {
@ -30,7 +39,7 @@ export default Vue.extend({
}
if (this.$props.eventBus) {
this.$props.eventBus.$on('focus', () => {
this.$props.eventBus.on('focus', () => {
this.focus();
});
}

View file

@ -32,7 +32,7 @@ import {
import { n8nCompletionSources } from '@/plugins/codemirror/completions/addCompletions';
import { expressionInputHandler } from '@/plugins/codemirror/inputHandlers/expression.inputHandler';
import { highlighter } from '@/plugins/codemirror/resolvableHighlighter';
import { htmlEditorEventBus } from '@/event-bus/html-editor-event-bus';
import { htmlEditorEventBus } from '@/event-bus';
import { expressionManager } from '@/mixins/expressionManager';
import { theme } from './theme';
import { nonTakenRanges } from './utils';
@ -256,7 +256,7 @@ export default mixins(expressionManager).extend({
},
mounted() {
htmlEditorEventBus.$on('format-html', this.format);
htmlEditorEventBus.on('format-html', this.format);
let doc = this.html;
@ -272,7 +272,7 @@ export default mixins(expressionManager).extend({
},
destroyed() {
htmlEditorEventBus.$off('format-html', this.format);
htmlEditorEventBus.off('format-html', this.format);
},
});
</script>

View file

@ -40,7 +40,6 @@
</template>
<script lang="ts">
import Vue from 'vue';
import Modal from './Modal.vue';
import {
IMPORT_CURL_MODAL_KEY,
@ -53,6 +52,7 @@ import { INodeUi } from '@/Interface';
import { mapStores } from 'pinia';
import { useUIStore } from '@/stores/ui';
import { useNDVStore } from '@/stores/ndv';
import { createEventBus } from '@/event-bus';
export default mixins(showMessage).extend({
name: 'ImportCurlModal',
@ -63,7 +63,7 @@ export default mixins(showMessage).extend({
return {
IMPORT_CURL_MODAL_KEY,
curlCommand: '',
modalBus: new Vue(),
modalBus: createEventBus(),
};
},
computed: {
@ -74,7 +74,7 @@ export default mixins(showMessage).extend({
},
methods: {
closeDialog(): void {
this.modalBus.$emit('close');
this.modalBus.emit('close');
},
onInput(value: string): void {
this.curlCommand = value;

View file

@ -24,6 +24,7 @@
import Vue from 'vue';
import ExpandableInputEdit from '@/components/ExpandableInput/ExpandableInputEdit.vue';
import ExpandableInputPreview from '@/components/ExpandableInput/ExpandableInputPreview.vue';
import { createEventBus } from '@/event-bus';
export default Vue.extend({
name: 'InlineTextEdit',
@ -34,7 +35,7 @@ export default Vue.extend({
newValue: '',
escPressed: false,
disabled: false,
inputBus: new Vue(),
inputBus: createEventBus(),
};
},
methods: {
@ -72,7 +73,7 @@ export default Vue.extend({
this.$data.disabled = false;
if (!updated) {
this.$data.inputBus.$emit('focus');
this.$data.inputBus.emit('focus');
}
};

View file

@ -69,13 +69,13 @@ import mixins from 'vue-typed-mixins';
import { showMessage } from '@/mixins/showMessage';
import { copyPaste } from '@/mixins/copyPaste';
import Modal from './Modal.vue';
import Vue from 'vue';
import { IFormInputs, IInviteResponse, IUser } from '@/Interface';
import { VALID_EMAIL_REGEX, INVITE_USER_MODAL_KEY } from '@/constants';
import { ROLE } from '@/utils';
import { mapStores } from 'pinia';
import { useUsersStore } from '@/stores/users';
import { useSettingsStore } from '@/stores/settings';
import { createEventBus } from '@/event-bus';
const NAME_EMAIL_FORMAT_REGEX = /^.* <(.*)>$/;
@ -101,8 +101,8 @@ export default mixins(showMessage, copyPaste).extend({
data() {
return {
config: null as IFormInputs | null,
formBus: new Vue(),
modalBus: new Vue(),
formBus: createEventBus(),
modalBus: createEventBus(),
emails: '',
showInviteUrls: null as IInviteResponse[] | null,
loading: false,
@ -279,7 +279,7 @@ export default mixins(showMessage, copyPaste).extend({
if (successfulUrlInvites.length > 1) {
this.showInviteUrls = successfulUrlInvites;
} else {
this.modalBus.$emit('close');
this.modalBus.emit('close');
}
} catch (error) {
this.$showError(error, this.$locale.baseText('settings.users.usersInvitedError'));
@ -307,7 +307,7 @@ export default mixins(showMessage, copyPaste).extend({
});
},
onSubmitClick() {
this.formBus.$emit('submit');
this.formBus.emit('submit');
},
onCopyInviteLink(user: IUser) {
if (user.inviteAcceptUrl && this.showInviteUrls) {

View file

@ -138,7 +138,7 @@ export default mixins(pushConnection, workflowHelpers).extend({
} else {
this.$router.push({ name: VIEWS.EXECUTION_HOME, params: { name: routeWorkflowId } });
}
// this.modalBus.$emit('closeAll');
// this.modalBus.emit('closeAll');
this.activeHeaderTab = MAIN_HEADER_TABS.EXECUTIONS;
break;
default:

View file

@ -160,6 +160,7 @@ import { getWorkflowPermissions, IPermissions } from '@/permissions';
import { useUsersStore } from '@/stores/users';
import { useUsageStore } from '@/stores/usage';
import { BaseTextKey } from '@/plugins/i18n';
import { createEventBus } from '@/event-bus';
const hasChanged = (prev: string[], curr: string[]) => {
if (prev.length !== curr.length) {
@ -187,7 +188,7 @@ export default mixins(workflowHelpers, titleChange).extend({
isTagsEditEnabled: false,
isNameEditEnabled: false,
appliedTagIds: [],
tagsEditBus: new Vue(),
tagsEditBus: createEventBus(),
MAX_WORKFLOW_NAME_LENGTH,
tagsSaving: false,
EnterpriseEditionFeature,
@ -328,7 +329,7 @@ export default mixins(workflowHelpers, titleChange).extend({
setTimeout(() => {
// allow name update to occur before disabling name edit
this.$data.isNameEditEnabled = false;
this.$data.tagsEditBus.$emit('focus');
this.$data.tagsEditBus.emit('focus');
}, 0);
},
async onTagsUpdate(tags: string[]) {

View file

@ -43,9 +43,10 @@
</template>
<script lang="ts">
import Vue from 'vue';
import Vue, { PropType } from 'vue';
import { useUIStore } from '@/stores/ui';
import { mapStores } from 'pinia';
import { EventBus } from '@/event-bus';
export default Vue.extend({
name: 'Modal',
@ -60,7 +61,7 @@ export default Vue.extend({
type: String,
},
eventBus: {
type: Vue,
type: Object as PropType<EventBus>,
},
showClose: {
type: Boolean,
@ -121,11 +122,11 @@ export default Vue.extend({
window.addEventListener('keydown', this.onWindowKeydown);
if (this.$props.eventBus) {
this.$props.eventBus.$on('close', () => {
this.$props.eventBus.on('close', () => {
this.closeDialog();
});
this.$props.eventBus.$on('closeAll', () => {
this.$props.eventBus.on('closeAll', () => {
this.uiStore.closeAllModals();
});
}

View file

@ -21,7 +21,8 @@
<script lang="ts">
import { useUIStore } from '@/stores/ui';
import { mapStores } from 'pinia';
import Vue from 'vue';
import Vue, { PropType } from 'vue';
import { EventBus } from '@/event-bus';
export default Vue.extend({
name: 'ModalDrawer',
@ -33,7 +34,7 @@ export default Vue.extend({
type: Function,
},
eventBus: {
type: Vue,
type: Object as PropType<EventBus>,
},
direction: {
type: String,
@ -54,7 +55,7 @@ export default Vue.extend({
window.addEventListener('keydown', this.onWindowKeydown);
if (this.$props.eventBus) {
this.$props.eventBus.$on('close', () => {
this.$props.eventBus.on('close', () => {
this.close();
});
}

View file

@ -24,13 +24,14 @@
</template>
<script setup lang="ts">
import Vue, { onMounted, reactive, toRefs, onBeforeUnmount } from 'vue';
import { onMounted, reactive, toRefs, onBeforeUnmount } from 'vue';
import { externalHooks } from '@/mixins/externalHooks';
import { EventBus } from '@/event-bus';
export interface Props {
placeholder: string;
value: string;
eventBus?: Vue;
eventBus?: EventBus;
}
withDefaults(defineProps<Props>(), {

View file

@ -142,7 +142,6 @@ import NodeSettings from '@/components/NodeSettings.vue';
import NDVDraggablePanels from './NDVDraggablePanels.vue';
import mixins from 'vue-typed-mixins';
import Vue from 'vue';
import OutputPanel from './OutputPanel.vue';
import InputPanel from './InputPanel.vue';
import TriggerPanel from './TriggerPanel.vue';
@ -155,7 +154,7 @@ import {
} from '@/constants';
import { workflowActivate } from '@/mixins/workflowActivate';
import { pinData } from '@/mixins/pinData';
import { dataPinningEventBus } from '@/event-bus/data-pinning-event-bus';
import { createEventBus, dataPinningEventBus } from '@/event-bus';
import { mapStores } from 'pinia';
import { useWorkflowsStore } from '@/stores/workflows';
import { useNDVStore } from '@/stores/ndv';
@ -198,7 +197,7 @@ export default mixins(
},
data() {
return {
settingsEventBus: new Vue(),
settingsEventBus: createEventBus(),
runInputIndex: -1,
runOutputIndex: -1,
isLinkingEnabled: true,
@ -212,7 +211,7 @@ export default mixins(
};
},
mounted() {
dataPinningEventBus.$on(
dataPinningEventBus.on(
'data-pinning-discovery',
({ isTooltipVisible }: { isTooltipVisible: boolean }) => {
this.pinDataDiscoveryTooltipVisible = isTooltipVisible;
@ -220,7 +219,7 @@ export default mixins(
);
},
destroyed() {
dataPinningEventBus.$off('data-pinning-discovery');
dataPinningEventBus.off('data-pinning-discovery');
},
computed: {
...mapStores(useNodeTypesStore, useNDVStore, useUIStore, useWorkflowsStore, useSettingsStore),
@ -596,7 +595,7 @@ export default mixins(
}, 1000);
},
openSettings() {
this.settingsEventBus.$emit('openSettings');
this.settingsEventBus.emit('openSettings');
},
valueChanged(parameterData: IUpdateInformation) {
this.$emit('valueChanged', parameterData);
@ -622,7 +621,7 @@ export default mixins(
const { value } = this.outputPanelEditMode;
if (!this.isValidPinDataSize(value)) {
dataPinningEventBus.$emit('data-pinning-error', {
dataPinningEventBus.emit('data-pinning-error', {
errorType: 'data-too-large',
source: 'on-ndv-close-modal',
});
@ -630,7 +629,7 @@ export default mixins(
}
if (!this.isValidPinDataJSON(value)) {
dataPinningEventBus.$emit('data-pinning-error', {
dataPinningEventBus.emit('data-pinning-error', {
errorType: 'invalid-json',
source: 'on-ndv-close-modal',
});

View file

@ -24,7 +24,7 @@ import { INodeTypeDescription } from 'n8n-workflow';
import mixins from 'vue-typed-mixins';
import { workflowRun } from '@/mixins/workflowRun';
import { pinData } from '@/mixins/pinData';
import { dataPinningEventBus } from '@/event-bus/data-pinning-event-bus';
import { dataPinningEventBus } from '@/event-bus';
import { mapStores } from 'pinia';
import { useWorkflowsStore } from '@/stores/workflows';
import { useNDVStore } from '@/stores/ndv';
@ -195,7 +195,7 @@ export default mixins(workflowRun, pinData).extend({
);
if (shouldUnpinAndExecute) {
dataPinningEventBus.$emit('data-unpinning', { source: 'unpin-and-execute-modal' });
dataPinningEventBus.emit('data-unpinning', { source: 'unpin-and-execute-modal' });
this.workflowsStore.unpinData({ node: this.node });
}
}

View file

@ -205,6 +205,7 @@ import { useHistoryStore } from '@/stores/history';
import { RenameNodeCommand } from '@/models/history';
import useWorkflowsEEStore from '@/stores/workflows.ee';
import { useCredentialsStore } from '@/stores/credentials';
import { EventBus } from '@/event-bus';
export default mixins(externalHooks, nodeHelpers).extend({
name: 'NodeSettings',
@ -322,7 +323,9 @@ export default mixins(externalHooks, nodeHelpers).extend({
},
},
props: {
eventBus: {},
eventBus: {
type: Object as PropType<EventBus>,
},
dragging: {
type: Boolean,
},
@ -897,7 +900,7 @@ export default mixins(externalHooks, nodeHelpers).extend({
this.populateHiddenIssuesSet();
this.setNodeValues();
if (this.eventBus) {
(this.eventBus as Vue).$on('openSettings', () => {
this.eventBus.on('openSettings', () => {
this.openPanel = 'settings';
});
}

View file

@ -48,8 +48,6 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { ONBOARDING_CALL_SIGNUP_MODAL_KEY, VALID_EMAIL_REGEX } from '@/constants';
import Modal from './Modal.vue';
@ -57,6 +55,7 @@ import mixins from 'vue-typed-mixins';
import { showMessage } from '@/mixins/showMessage';
import { mapStores } from 'pinia';
import { useUIStore } from '@/stores/ui';
import { createEventBus } from '@/event-bus';
export default mixins(showMessage).extend({
components: {
@ -67,7 +66,7 @@ export default mixins(showMessage).extend({
data() {
return {
email: '',
modalBus: new Vue(),
modalBus: createEventBus(),
ONBOARDING_CALL_SIGNUP_MODAL_KEY,
showError: false,
okToClose: false,
@ -98,7 +97,7 @@ export default mixins(showMessage).extend({
message: this.$locale.baseText('onboardingCallSignupSucess.message'),
});
this.okToClose = true;
this.modalBus.$emit('close');
this.modalBus.emit('close');
} catch (e) {
this.$showError(
e,
@ -111,7 +110,7 @@ export default mixins(showMessage).extend({
},
async onCancel() {
this.okToClose = true;
this.modalBus.$emit('close');
this.modalBus.emit('close');
},
onModalClose() {
return this.okToClose;

View file

@ -373,7 +373,7 @@ import { useWorkflowsStore } from '@/stores/workflows';
import { useNDVStore } from '@/stores/ndv';
import { useNodeTypesStore } from '@/stores/nodeTypes';
import { useCredentialsStore } from '@/stores/credentials';
import { htmlEditorEventBus } from '@/event-bus/html-editor-event-bus';
import { htmlEditorEventBus } from '@/event-bus';
export default mixins(
externalHooks,
@ -1106,7 +1106,7 @@ export default mixins(
}
this.loadRemoteParameterOptions();
} else if (command === 'formatHtml') {
htmlEditorEventBus.$emit('format-html');
htmlEditorEventBus.emit('format-html');
}
if (this.node && (command === 'addExpression' || command === 'removeExpression')) {

View file

@ -127,7 +127,6 @@ import { workflowHelpers } from '@/mixins/workflowHelpers';
import { showMessage } from '@/mixins/showMessage';
import Modal from './Modal.vue';
import { IFormInputs, IPersonalizationLatestVersion, IUser } from '@/Interface';
import Vue from 'vue';
import { getAccountAge } from '@/utils';
import { GenericValue } from 'n8n-workflow';
import { mapStores } from 'pinia';
@ -135,6 +134,7 @@ import { useUIStore } from '@/stores/ui';
import { useSettingsStore } from '@/stores/settings';
import { useRootStore } from '@/stores/n8nRootStore';
import { useUsersStore } from '@/stores/users';
import { createEventBus } from '@/event-bus';
export default mixins(showMessage, workflowHelpers).extend({
components: { Modal },
@ -146,8 +146,8 @@ export default mixins(showMessage, workflowHelpers).extend({
otherWorkAreaFieldVisible: false,
otherCompanyIndustryFieldVisible: false,
showAllIndustryQuestions: true,
modalBus: new Vue(),
formBus: new Vue(),
modalBus: createEventBus(),
formBus: createEventBus(),
};
},
computed: {
@ -605,10 +605,10 @@ export default mixins(showMessage, workflowHelpers).extend({
},
methods: {
closeDialog() {
this.modalBus.$emit('close');
this.modalBus.emit('close');
},
onSave() {
this.formBus.$emit('submit');
this.formBus.emit('submit');
},
async onSubmit(values: IPersonalizationLatestVersion): Promise<void> {
this.$data.isSaving = true;

View file

@ -493,7 +493,7 @@ import { genericHelpers } from '@/mixins/genericHelpers';
import { nodeHelpers } from '@/mixins/nodeHelpers';
import { pinData } from '@/mixins/pinData';
import { CodeEditor } from '@/components/forms';
import { dataPinningEventBus } from '@/event-bus/data-pinning-event-bus';
import { dataPinningEventBus } from '@/event-bus';
import { clearJsonKey, executionDataToJson, stringSizeInBytes } from '@/utils';
import { isEmpty } from '@/utils';
import { useWorkflowsStore } from '@/stores/workflows';
@ -595,8 +595,8 @@ export default mixins(externalHooks, genericHelpers, nodeHelpers, pinData).exten
this.init();
if (!this.isPaneTypeInput) {
this.eventBus.$on('data-pinning-error', this.onDataPinningError);
this.eventBus.$on('data-unpinning', this.onDataUnpinning);
this.eventBus.on('data-pinning-error', this.onDataPinningError);
this.eventBus.on('data-unpinning', this.onDataUnpinning);
this.showPinDataDiscoveryTooltip(this.jsonData);
}
@ -609,8 +609,8 @@ export default mixins(externalHooks, genericHelpers, nodeHelpers, pinData).exten
},
destroyed() {
this.hidePinDataDiscoveryTooltip();
this.eventBus.$off('data-pinning-error', this.onDataPinningError);
this.eventBus.$off('data-unpinning', this.onDataUnpinning);
this.eventBus.off('data-pinning-error', this.onDataPinningError);
this.eventBus.off('data-unpinning', this.onDataUnpinning);
},
computed: {
...mapStores(useNodeTypesStore, useNDVStore, useWorkflowsStore),
@ -908,7 +908,7 @@ export default mixins(externalHooks, genericHelpers, nodeHelpers, pinData).exten
setTimeout(() => {
this.isControlledPinDataTooltip = true;
this.pinDataDiscoveryTooltipVisible = true;
this.eventBus.$emit('data-pinning-discovery', { isTooltipVisible: true });
this.eventBus.emit('data-pinning-discovery', { isTooltipVisible: true });
}, 500); // Wait for NDV to open
}
},
@ -916,7 +916,7 @@ export default mixins(externalHooks, genericHelpers, nodeHelpers, pinData).exten
if (this.pinDataDiscoveryTooltipVisible) {
this.isControlledPinDataTooltip = false;
this.pinDataDiscoveryTooltipVisible = false;
this.eventBus.$emit('data-pinning-discovery', { isTooltipVisible: false });
this.eventBus.emit('data-pinning-discovery', { isTooltipVisible: false });
}
},
pinDataDiscoveryComplete() {

View file

@ -51,7 +51,7 @@ import mixins from 'vue-typed-mixins';
import { EnterpriseEditionFeature } from '@/constants';
import { showMessage } from '@/mixins/showMessage';
import { useLogStreamingStore } from '../../stores/logStreamingStore';
import Vue from 'vue';
import Vue, { PropType } from 'vue';
import { mapStores } from 'pinia';
import {
deepCopy,
@ -59,6 +59,7 @@ import {
MessageEventBusDestinationOptions,
} from 'n8n-workflow';
import { BaseTextKey } from '../../plugins/i18n';
import { EventBus } from '@/event-bus';
export const DESTINATION_LIST_ITEM_ACTIONS = {
OPEN: 'open',
@ -75,7 +76,7 @@ export default mixins(showMessage).extend({
components: {},
props: {
eventBus: {
type: Vue,
type: Object as PropType<EventBus>,
},
destination: {
type: Object,
@ -91,7 +92,7 @@ export default mixins(showMessage).extend({
deepCopy(defaultMessageEventBusDestinationOptions),
this.destination,
);
this.eventBus.$on('destinationWasSaved', () => {
this.eventBus.on('destinationWasSaved', () => {
const updatedDestination = this.logStreamingStore.getDestination(this.destination.id);
if (updatedDestination) {
this.nodeParameters = Object.assign(

View file

@ -193,7 +193,7 @@ import {
defaultMessageEventBusDestinationSyslogOptions,
defaultMessageEventBusDestinationSentryOptions,
} from 'n8n-workflow';
import Vue from 'vue';
import Vue, { PropType } from 'vue';
import { LOG_STREAM_MODAL_KEY } from '../../constants';
import Modal from '@/components/Modal.vue';
import { showMessage } from '@/mixins/showMessage';
@ -210,6 +210,7 @@ import InlineNameEdit from '../InlineNameEdit.vue';
import SaveButton from '../SaveButton.vue';
import EventSelection from '@/components/SettingsLogStreaming/EventSelection.ee.vue';
import { Checkbox } from 'element-ui';
import { createEventBus, EventBus } from '@/event-bus';
export default mixins(showMessage).extend({
name: 'event-destination-settings-modal',
@ -221,7 +222,7 @@ export default mixins(showMessage).extend({
},
isNew: Boolean,
eventBus: {
type: Vue,
type: Object as PropType<EventBus>,
},
},
components: {
@ -248,7 +249,7 @@ export default mixins(showMessage).extend({
webhookDescription: webhookModalDescription,
sentryDescription: sentryModalDescription,
syslogDescription: syslogModalDescription,
modalBus: new Vue(),
modalBus: createEventBus(),
headerLabel: this.$props.destination.label,
testMessageSent: false,
testMessageResult: false,
@ -450,7 +451,7 @@ export default mixins(showMessage).extend({
if (deleteConfirmed === false) {
return;
} else {
this.$props.eventBus.$emit('remove', this.destination.id);
this.$props.eventBus.emit('remove', this.destination.id);
this.uiStore.closeModal(LOG_STREAM_MODAL_KEY);
this.uiStore.stateIsDirty = false;
}
@ -461,7 +462,7 @@ export default mixins(showMessage).extend({
this.logStreamingStore.removeDestination(this.nodeParameters.id!);
}
this.ndvStore.activeNodeName = null;
this.$props.eventBus.$emit('closing', this.destination.id);
this.$props.eventBus.emit('closing', this.destination.id);
this.uiStore.stateIsDirty = false;
},
async saveDestination() {
@ -473,7 +474,7 @@ export default mixins(showMessage).extend({
this.hasOnceBeenSaved = true;
this.testMessageSent = false;
this.unchanged = true;
this.$props.eventBus.$emit('destinationWasSaved', this.destination.id);
this.$props.eventBus.emit('destinationWasSaved', this.destination.id);
this.uiStore.stateIsDirty = false;
}
},

View file

@ -64,13 +64,22 @@ import { showMessage } from '@/mixins/showMessage';
import { mapStores } from 'pinia';
import { useUIStore } from '@/stores/ui';
import { useTagsStore } from '@/stores/tags';
import { EventBus } from '@/event-bus';
import { PropType } from 'vue';
const MANAGE_KEY = '__manage';
const CREATE_KEY = '__create';
export default mixins(showMessage).extend({
name: 'TagsDropdown',
props: ['placeholder', 'currentTagIds', 'createEnabled', 'eventBus'],
props: {
placeholder: {},
currentTagIds: {},
createEnabled: {},
eventBus: {
type: Object as PropType<EventBus>,
},
},
data() {
return {
filter: '',
@ -109,7 +118,7 @@ export default mixins(showMessage).extend({
}
if (this.$props.eventBus) {
this.$props.eventBus.$on('focus', () => {
this.$props.eventBus.on('focus', () => {
this.focusOnInput();
this.focusOnTopOption();
});

View file

@ -40,6 +40,7 @@ import Modal from '@/components/Modal.vue';
import { TAGS_MANAGER_MODAL_KEY } from '../../constants';
import { mapStores } from 'pinia';
import { useTagsStore } from '@/stores/tags';
import { createEventBus } from '@/event-bus';
export default mixins(showMessage).extend({
name: 'TagsManager',
@ -51,7 +52,7 @@ export default mixins(showMessage).extend({
return {
tagIds,
isCreating: false,
modalBus: new Vue(),
modalBus: createEventBus(),
TAGS_MANAGER_MODAL_KEY,
};
},
@ -176,7 +177,7 @@ export default mixins(showMessage).extend({
} else if (!this.hasTags) {
this.onEnableCreate();
} else {
this.modalBus.$emit('close');
this.modalBus.emit('close');
}
},
},

View file

@ -63,10 +63,10 @@ import ModalDrawer from './ModalDrawer.vue';
import mixins from 'vue-typed-mixins';
import { workflowHelpers } from '@/mixins/workflowHelpers';
import Vue from 'vue';
import { mapStores } from 'pinia';
import { useSettingsStore } from '@/stores/settings';
import { useRootStore } from '@/stores/n8nRootStore';
import { createEventBus } from '@/event-bus';
const DEFAULT_TITLE = 'How likely are you to recommend n8n to a friend or colleague?';
const GREAT_FEEDBACK_TITLE =
@ -114,7 +114,7 @@ export default mixins(workflowHelpers).extend({
},
showButtons: true,
VALUE_SURVEY_MODAL_KEY,
modalBus: new Vue(),
modalBus: createEventBus(),
};
},
methods: {
@ -178,7 +178,7 @@ export default mixins(workflowHelpers).extend({
this.form.email = '';
this.showButtons = true;
}, 1000);
this.modalBus.$emit('close');
this.modalBus.emit('close');
}
},
},

View file

@ -59,7 +59,6 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { IVariableSelectorOption, IVariableItemSelected } from '@/Interface';
import { externalHooks } from '@/mixins/externalHooks';
import mixins from 'vue-typed-mixins';

View file

@ -355,6 +355,7 @@ import { useSettingsStore } from '@/stores/settings';
import { useRootStore } from '@/stores/n8nRootStore';
import useWorkflowsEEStore from '@/stores/workflows.ee';
import { useUsersStore } from '@/stores/users';
import { createEventBus } from '@/event-bus';
export default mixins(externalHooks, genericHelpers, restApi, showMessage).extend({
name: 'WorkflowSettings',
@ -407,7 +408,7 @@ export default mixins(externalHooks, genericHelpers, restApi, showMessage).exten
executionTimeout: 0,
maxExecutionTimeout: 0,
timeoutHMS: { hours: 0, minutes: 0, seconds: 0 } as ITimeoutHMS,
modalBus: new Vue(),
modalBus: createEventBus(),
WORKFLOW_SETTINGS_MODAL_KEY,
};
},
@ -528,7 +529,7 @@ export default mixins(externalHooks, genericHelpers, restApi, showMessage).exten
: str.replace(/[^0-9,\s]/g, '');
},
closeDialog() {
this.modalBus.$emit('close');
this.modalBus.emit('close');
this.$externalHooks().run('workflowSettings.dialogVisibleChanged', { dialogVisible: false });
},
setTimeout(key: string, value: string) {

View file

@ -123,7 +123,6 @@
</template>
<script lang="ts">
import Vue from 'vue';
import Modal from './Modal.vue';
import {
EnterpriseEditionFeature,
@ -135,7 +134,7 @@ import { IUser, IWorkflowDb, UIState } from '@/Interface';
import { getWorkflowPermissions, IPermissions } from '@/permissions';
import mixins from 'vue-typed-mixins';
import { showMessage } from '@/mixins/showMessage';
import { nodeViewEventBus } from '@/event-bus/node-view-event-bus';
import { createEventBus, nodeViewEventBus } from '@/event-bus';
import { mapStores } from 'pinia';
import { useSettingsStore } from '@/stores/settings';
import { useUIStore } from '@/stores/ui';
@ -168,7 +167,7 @@ export default mixins(showMessage).extend({
return {
WORKFLOW_SHARE_MODAL_KEY,
loading: true,
modalBus: new Vue(),
modalBus: createEventBus(),
sharedWith: [...(workflow.sharedWith || [])] as Array<Partial<IUser>>,
EnterpriseEditionFeature,
};
@ -262,7 +261,7 @@ export default mixins(showMessage).extend({
const saveWorkflowPromise = () => {
return new Promise<string>((resolve) => {
if (this.workflow.id === PLACEHOLDER_EMPTY_WORKFLOW_ID) {
nodeViewEventBus.$emit('saveWorkflow', () => {
nodeViewEventBus.emit('saveWorkflow', () => {
resolve(this.workflow.id);
});
} else {
@ -299,7 +298,7 @@ export default mixins(showMessage).extend({
} catch (error) {
this.$showError(error, this.$locale.baseText('workflows.shareModal.onSave.error.title'));
} finally {
this.modalBus.$emit('close');
this.modalBus.emit('close');
this.loading = false;
}
},
@ -428,7 +427,7 @@ export default mixins(showMessage).extend({
console.error(failure);
}
});
this.modalBus.$emit('close');
this.modalBus.emit('close');
},
trackTelemetry(data: ITelemetryTrackProperties) {
this.$telemetry.track('User selected sharee to remove', {

View file

@ -1,3 +0,0 @@
import Vue from 'vue';
export const codeNodeEditorEventBus = new Vue();

View file

@ -0,0 +1,3 @@
import { createEventBus } from '@/event-bus';
export const codeNodeEditorEventBus = createEventBus();

View file

@ -1,3 +0,0 @@
import Vue from 'vue';
export const dataPinningEventBus = new Vue();

View file

@ -0,0 +1,3 @@
import { createEventBus } from '@/event-bus';
export const dataPinningEventBus = createEventBus();

View file

@ -1,3 +0,0 @@
import Vue from 'vue';
export const htmlEditorEventBus = new Vue();

View file

@ -0,0 +1,3 @@
import { createEventBus } from '@/event-bus';
export const htmlEditorEventBus = createEventBus();

View file

@ -0,0 +1,5 @@
export * from 'n8n-design-system/utils/event-bus';
export * from './code-node-editor';
export * from './data-pinning';
export * from './html-editor';
export * from './node-view';

View file

@ -1,3 +0,0 @@
import Vue from 'vue';
export const nodeViewEventBus = new Vue();

View file

@ -0,0 +1,3 @@
import { createEventBus } from '@/event-bus';
export const nodeViewEventBus = createEventBus();

View file

@ -25,7 +25,7 @@ import {
import mixins from 'vue-typed-mixins';
import { WORKFLOW_SETTINGS_MODAL_KEY } from '@/constants';
import { getTriggerNodeServiceName } from '@/utils';
import { codeNodeEditorEventBus } from '@/event-bus/code-node-editor-event-bus';
import { codeNodeEditorEventBus } from '@/event-bus';
import { mapStores } from 'pinia';
import { useUIStore } from '@/stores/ui';
import { useWorkflowsStore } from '@/stores/workflows';
@ -335,7 +335,7 @@ export const pushConnection = mixins(
runDataExecuted.data.resultData.error &&
runDataExecuted.data.resultData.error.lineNumber;
codeNodeEditorEventBus.$emit('error-line-number', lineNumber || 'final');
codeNodeEditorEventBus.emit('error-line-number', lineNumber || 'final');
const workflow = this.getCurrentWorkflow();
if (runDataExecuted.waitTill !== undefined) {

View file

@ -1,7 +1,7 @@
import { INodeUi } from '@/Interface';
import { IConnection } from 'n8n-workflow';
import Vue from 'vue';
import { XYPosition } from '../Interface';
import { createEventBus } from '@/event-bus';
// Command names don't serve any particular purpose in the app
// but they make it easier to identify each command on stack
@ -21,7 +21,7 @@ export enum COMMANDS {
// this timeout in between canvas actions
// (0 is usually enough but leaving this just in case)
const CANVAS_ACTION_TIMEOUT = 10;
export const historyBus = new Vue();
export const historyBus = createEventBus();
export abstract class Undoable {}
@ -75,7 +75,7 @@ export class MoveNodeCommand extends Command {
async revert(): Promise<void> {
return new Promise<void>((resolve) => {
historyBus.$emit('nodeMove', {
historyBus.emit('nodeMove', {
nodeName: this.nodeName,
position: this.oldPosition,
});
@ -102,7 +102,7 @@ export class AddNodeCommand extends Command {
async revert(): Promise<void> {
return new Promise<void>((resolve) => {
historyBus.$emit('revertAddNode', { node: this.node });
historyBus.emit('revertAddNode', { node: this.node });
resolve();
});
}
@ -126,7 +126,7 @@ export class RemoveNodeCommand extends Command {
async revert(): Promise<void> {
return new Promise<void>((resolve) => {
historyBus.$emit('revertRemoveNode', { node: this.node });
historyBus.emit('revertRemoveNode', { node: this.node });
resolve();
});
}
@ -156,7 +156,7 @@ export class AddConnectionCommand extends Command {
async revert(): Promise<void> {
return new Promise<void>((resolve) => {
historyBus.$emit('revertAddConnection', { connection: this.connectionData });
historyBus.emit('revertAddConnection', { connection: this.connectionData });
resolve();
});
}
@ -187,7 +187,7 @@ export class RemoveConnectionCommand extends Command {
async revert(): Promise<void> {
return new Promise<void>((resolve) => {
setTimeout(() => {
historyBus.$emit('revertRemoveConnection', { connection: this.connectionData });
historyBus.emit('revertRemoveConnection', { connection: this.connectionData });
resolve();
}, CANVAS_ACTION_TIMEOUT);
});
@ -218,7 +218,7 @@ export class EnableNodeToggleCommand extends Command {
async revert(): Promise<void> {
return new Promise<void>((resolve) => {
historyBus.$emit('enableNodeToggle', {
historyBus.emit('enableNodeToggle', {
nodeName: this.nodeName,
isDisabled: this.oldState,
});
@ -251,7 +251,7 @@ export class RenameNodeCommand extends Command {
async revert(): Promise<void> {
return new Promise<void>((resolve) => {
historyBus.$emit('revertRenameNode', {
historyBus.emit('revertRenameNode', {
currentName: this.currentName,
newName: this.newName,
});

View file

@ -57,7 +57,7 @@ import {
getWorkflows,
} from '@/api/workflows';
import { useUIStore } from './ui';
import { dataPinningEventBus } from '@/event-bus/data-pinning-event-bus';
import { dataPinningEventBus } from '@/event-bus';
import {
isJsonKeyObject,
getPairedItemsMapping,
@ -462,7 +462,7 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
setWorkflowPinData(pinData: IPinData): void {
Vue.set(this.workflow, 'pinData', pinData || {});
dataPinningEventBus.$emit('pin-data', pinData || {});
dataPinningEventBus.emit('pin-data', pinData || {});
},
setWorkflowTagIds(tags: string[]): void {
@ -523,7 +523,7 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
const uiStore = useUIStore();
uiStore.stateIsDirty = true;
dataPinningEventBus.$emit('pin-data', { [payload.node.name]: storedPinData });
dataPinningEventBus.emit('pin-data', { [payload.node.name]: storedPinData });
},
unpinData(payload: { node: INodeUi }): void {
@ -537,7 +537,7 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
const uiStore = useUIStore();
uiStore.stateIsDirty = true;
dataPinningEventBus.$emit('unpin-data', { [payload.node.name]: undefined });
dataPinningEventBus.emit('unpin-data', { [payload.node.name]: undefined });
},
addConnection(data: { connection: IConnection[] }): void {

View file

@ -266,7 +266,7 @@ import { useUIStore } from '@/stores/ui';
import { useSettingsStore } from '@/stores/settings';
import { useUsersStore } from '@/stores/users';
import { Route, RawLocation } from 'vue-router';
import { nodeViewEventBus } from '@/event-bus/node-view-event-bus';
import { dataPinningEventBus, nodeViewEventBus } from '@/event-bus';
import { useWorkflowsStore } from '@/stores/workflows';
import { useRootStore } from '@/stores/n8nRootStore';
import { useNDVStore } from '@/stores/ndv';
@ -276,7 +276,6 @@ import { useNodeTypesStore } from '@/stores/nodeTypes';
import { useCredentialsStore } from '@/stores/credentials';
import { useTagsStore } from '@/stores/tags';
import { useNodeCreatorStore } from '@/stores/nodeCreator';
import { dataPinningEventBus } from '@/event-bus/data-pinning-event-bus';
import { useCanvasStore } from '@/stores/canvas';
import useWorkflowsEEStore from '@/stores/workflows.ee';
import * as NodeViewUtils from '@/utils/nodeViewUtils';
@ -3976,17 +3975,17 @@ export default mixins(
this.$root.$on('newWorkflow', this.newWorkflow);
this.$root.$on('importWorkflowData', this.onImportWorkflowDataEvent);
this.$root.$on('importWorkflowUrl', this.onImportWorkflowUrlEvent);
historyBus.$on('nodeMove', this.onMoveNode);
historyBus.$on('revertAddNode', this.onRevertAddNode);
historyBus.$on('revertRemoveNode', this.onRevertRemoveNode);
historyBus.$on('revertAddConnection', this.onRevertAddConnection);
historyBus.$on('revertRemoveConnection', this.onRevertRemoveConnection);
historyBus.$on('revertRenameNode', this.onRevertNameChange);
historyBus.$on('enableNodeToggle', this.onRevertEnableToggle);
historyBus.on('nodeMove', this.onMoveNode);
historyBus.on('revertAddNode', this.onRevertAddNode);
historyBus.on('revertRemoveNode', this.onRevertRemoveNode);
historyBus.on('revertAddConnection', this.onRevertAddConnection);
historyBus.on('revertRemoveConnection', this.onRevertRemoveConnection);
historyBus.on('revertRenameNode', this.onRevertNameChange);
historyBus.on('enableNodeToggle', this.onRevertEnableToggle);
dataPinningEventBus.$on('pin-data', this.addPinDataConnections);
dataPinningEventBus.$on('unpin-data', this.removePinDataConnections);
nodeViewEventBus.$on('saveWorkflow', this.saveCurrentWorkflowExternal);
dataPinningEventBus.on('pin-data', this.addPinDataConnections);
dataPinningEventBus.on('unpin-data', this.removePinDataConnections);
nodeViewEventBus.on('saveWorkflow', this.saveCurrentWorkflowExternal);
this.canvasStore.isDemo = this.isDemo;
},
@ -3999,17 +3998,17 @@ export default mixins(
this.$root.$off('newWorkflow', this.newWorkflow);
this.$root.$off('importWorkflowData', this.onImportWorkflowDataEvent);
this.$root.$off('importWorkflowUrl', this.onImportWorkflowUrlEvent);
historyBus.$off('nodeMove', this.onMoveNode);
historyBus.$off('revertAddNode', this.onRevertAddNode);
historyBus.$off('revertRemoveNode', this.onRevertRemoveNode);
historyBus.$off('revertAddConnection', this.onRevertAddConnection);
historyBus.$off('revertRemoveConnection', this.onRevertRemoveConnection);
historyBus.$off('revertRenameNode', this.onRevertNameChange);
historyBus.$off('enableNodeToggle', this.onRevertEnableToggle);
historyBus.off('nodeMove', this.onMoveNode);
historyBus.off('revertAddNode', this.onRevertAddNode);
historyBus.off('revertRemoveNode', this.onRevertRemoveNode);
historyBus.off('revertAddConnection', this.onRevertAddConnection);
historyBus.off('revertRemoveConnection', this.onRevertRemoveConnection);
historyBus.off('revertRenameNode', this.onRevertNameChange);
historyBus.off('enableNodeToggle', this.onRevertEnableToggle);
dataPinningEventBus.$off('pin-data', this.addPinDataConnections);
dataPinningEventBus.$off('unpin-data', this.removePinDataConnections);
nodeViewEventBus.$off('saveWorkflow', this.saveCurrentWorkflowExternal);
dataPinningEventBus.off('pin-data', this.addPinDataConnections);
dataPinningEventBus.off('unpin-data', this.removePinDataConnections);
nodeViewEventBus.off('saveWorkflow', this.saveCurrentWorkflowExternal);
},
destroyed() {
this.resetWorkspace();

View file

@ -169,6 +169,7 @@ import { useUsersStore } from '@/stores/users';
import { useSettingsStore } from '@/stores/settings';
import { getLdapSynchronizations } from '@/api/ldap';
import { N8N_CONTACT_EMAIL, N8N_SALES_EMAIL } from '@/constants';
import { createEventBus } from '@/event-bus';
type FormValues = {
loginEnabled: boolean;
@ -221,7 +222,7 @@ export default mixins(showMessage).extend({
loadingTable: false,
hasAnyChanges: false,
formInputs: null as null | IFormInputs,
formBus: new Vue(),
formBus: createEventBus(),
readyToSubmit: false,
page: 0,
loginEnabled: false,
@ -354,7 +355,7 @@ export default mixins(showMessage).extend({
}
},
onSaveClick() {
this.formBus.$emit('submit');
this.formBus.emit('submit');
},
async onTestConnectionClick() {
this.loadingTestConnection = true;

View file

@ -89,7 +89,6 @@ import { useLogStreamingStore } from '../stores/logStreamingStore';
import { useSettingsStore } from '../stores/settings';
import { useUIStore } from '../stores/ui';
import { LOG_STREAM_MODAL_KEY, EnterpriseEditionFeature } from '../constants';
import Vue from 'vue';
import {
deepCopy,
defaultMessageEventBusDestinationOptions,
@ -97,6 +96,7 @@ import {
} from 'n8n-workflow';
import PageViewLayout from '@/components/layouts/PageViewLayout.vue';
import EventDestinationCard from '@/components/SettingsLogStreaming/EventDestinationCard.ee.vue';
import { createEventBus } from '@/event-bus';
export default mixins().extend({
name: 'SettingsLogStreamingView',
@ -107,7 +107,7 @@ export default mixins().extend({
},
data() {
return {
eventBus: new Vue(),
eventBus: createEventBus(),
destinations: Array<MessageEventBusDestinationOptions>,
disableLicense: false,
allDestinations: [] as MessageEventBusDestinationOptions[],
@ -135,15 +135,15 @@ export default mixins().extend({
}
});
// refresh when a modal closes
this.eventBus.$on('destinationWasSaved', async () => {
this.eventBus.on('destinationWasSaved', async () => {
this.$forceUpdate();
});
// listen to remove emission
this.eventBus.$on('remove', async (destinationId: string) => {
this.eventBus.on('remove', async (destinationId: string) => {
await this.onRemove(destinationId);
});
// listen to modal closing and remove nodes from store
this.eventBus.$on('closing', async (destinationId: string) => {
this.eventBus.on('closing', async (destinationId: string) => {
this.workflowsStore.removeAllNodes({ setStateDirty: false, removePinData: true });
this.uiStore.stateIsDirty = false;
});

View file

@ -65,8 +65,8 @@ import { useUIStore } from '@/stores/ui';
import { useUsersStore } from '@/stores/users';
import { useSettingsStore } from '@/stores/settings';
import { mapStores } from 'pinia';
import Vue from 'vue';
import mixins from 'vue-typed-mixins';
import { createEventBus } from '@/event-bus';
export default mixins(showMessage).extend({
name: 'SettingsPersonalView',
@ -74,7 +74,7 @@ export default mixins(showMessage).extend({
return {
hasAnyChanges: false,
formInputs: null as null | IFormInputs,
formBus: new Vue(),
formBus: createEventBus(),
readyToSubmit: false,
};
},
@ -160,7 +160,7 @@ export default mixins(showMessage).extend({
}
},
onSaveClick() {
this.formBus.$emit('submit');
this.formBus.emit('submit');
},
openPasswordModal() {
this.uiStore.openModal(CHANGE_PASSWORD_MODAL_KEY);