refactor(editor): Migrate nodeBase mixin to composable (no-changelog) (#9742)

This commit is contained in:
Alex Grozav
2024-06-18 16:35:26 +03:00
committed by GitHub
parent c58621ab79
commit b0d7cfa2ab
6 changed files with 1015 additions and 702 deletions

View File

@@ -178,7 +178,8 @@
</template>
<script lang="ts">
import { type CSSProperties, defineComponent } from 'vue';
import { defineComponent } from 'vue';
import type { PropType, CSSProperties } from 'vue';
import { mapStores } from 'pinia';
import xss from 'xss';
import { useStorage } from '@/composables/useStorage';
@@ -192,7 +193,7 @@ import {
SIMULATE_TRIGGER_NODE_TYPE,
WAIT_TIME_UNLIMITED,
} from '@/constants';
import { nodeBase } from '@/mixins/nodeBase';
import { NodeConnectionType, NodeHelpers } from 'n8n-workflow';
import type {
ConnectionTypes,
ExecutionSummary,
@@ -201,8 +202,8 @@ import type {
INodeTypeDescription,
ITaskData,
NodeOperationError,
Workflow,
} from 'n8n-workflow';
import { NodeConnectionType, NodeHelpers } from 'n8n-workflow';
import NodeIcon from '@/components/NodeIcon.vue';
import TitledList from '@/components/TitledList.vue';
@@ -222,6 +223,10 @@ import { useExternalHooks } from '@/composables/useExternalHooks';
import { usePinnedData } from '@/composables/usePinnedData';
import { useDeviceSupport } from 'n8n-design-system';
import { useDebounce } from '@/composables/useDebounce';
import type { BrowserJsPlumbInstance } from '@jsplumb/browser-ui';
import { useCanvasStore } from '@/stores/canvas.store';
import { useHistoryStore } from '@/stores/history.store';
import { useNodeBase } from '@/composables/useNodeBase';
export default defineComponent({
name: 'Node',
@@ -230,7 +235,6 @@ export default defineComponent({
FontAwesomeIcon,
NodeIcon,
},
mixins: [nodeBase],
props: {
isProductionExecutionPreview: {
type: Boolean,
@@ -244,6 +248,33 @@ export default defineComponent({
type: Boolean,
default: false,
},
name: {
type: String,
required: true,
},
instance: {
type: Object as PropType<BrowserJsPlumbInstance>,
required: true,
},
isReadOnly: {
type: Boolean,
},
isActive: {
type: Boolean,
},
hideActions: {
type: Boolean,
},
disableSelecting: {
type: Boolean,
},
showCustomTooltip: {
type: Boolean,
},
workflow: {
type: Object as PropType<Workflow>,
required: true,
},
},
emits: {
run: null,
@@ -251,7 +282,7 @@ export default defineComponent({
removeNode: null,
toggleDisableNode: null,
},
setup(props) {
setup(props, { emit }) {
const workflowsStore = useWorkflowsStore();
const contextMenu = useContextMenu();
const externalHooks = useExternalHooks();
@@ -261,12 +292,21 @@ export default defineComponent({
const deviceSupport = useDeviceSupport();
const { callDebounced } = useDebounce();
const nodeBase = useNodeBase({
name: props.name,
instance: props.instance,
workflowObject: props.workflow,
isReadOnly: props.isReadOnly,
emit: emit as (event: string, ...args: unknown[]) => void,
});
return {
contextMenu,
externalHooks,
nodeHelpers,
pinnedData,
deviceSupport,
...nodeBase,
callDebounced,
};
},
@@ -281,7 +321,20 @@ export default defineComponent({
};
},
computed: {
...mapStores(useNodeTypesStore, useNDVStore, useUIStore, useWorkflowsStore),
...mapStores(
useNodeTypesStore,
useCanvasStore,
useNDVStore,
useUIStore,
useWorkflowsStore,
useHistoryStore,
),
data(): INodeUi | null {
return this.workflowsStore.getNodeByName(this.name);
},
nodeId(): string {
return this.data?.id || '';
},
showPinnedDataInfo(): boolean {
return this.pinnedData.hasData.value && !this.isProductionExecutionPreview;
},
@@ -678,6 +731,16 @@ export default defineComponent({
}
},
mounted() {
// Initialize the node
if (this.data !== null) {
try {
this.addNode(this.data);
} catch (error) {
// This breaks when new nodes are loaded into store but workflow tab is not currently active
// Shouldn't affect anything
}
}
setTimeout(() => {
this.setSubtitle();
}, 0);

View File

@@ -103,10 +103,10 @@
</template>
<script lang="ts">
import { defineComponent, ref, type StyleValue } from 'vue';
import { defineComponent, ref } from 'vue';
import type { PropType, StyleValue } from 'vue';
import { mapStores } from 'pinia';
import { nodeBase } from '@/mixins/nodeBase';
import { isNumber, isString } from '@/utils/typeGuards';
import type {
INodeUi,
@@ -115,7 +115,7 @@ import type {
XYPosition,
} from '@/Interface';
import type { INodeTypeDescription } from 'n8n-workflow';
import type { INodeTypeDescription, Workflow } from 'n8n-workflow';
import { QUICKSTART_NOTE_NAME } from '@/constants';
import { useUIStore } from '@/stores/ui.store';
import { useWorkflowsStore } from '@/stores/workflows.store';
@@ -126,10 +126,13 @@ import { useDeviceSupport } from 'n8n-design-system';
import { GRID_SIZE } from '@/utils/nodeViewUtils';
import { useToast } from '@/composables/useToast';
import { assert } from '@/utils/assert';
import type { BrowserJsPlumbInstance } from '@jsplumb/browser-ui';
import { useCanvasStore } from '@/stores/canvas.store';
import { useHistoryStore } from '@/stores/history.store';
import { useNodeBase } from '@/composables/useNodeBase';
export default defineComponent({
name: 'Sticky',
mixins: [nodeBase],
props: {
nodeViewScale: {
type: Number,
@@ -139,9 +142,36 @@ export default defineComponent({
type: Number,
default: GRID_SIZE,
},
name: {
type: String,
required: true,
},
instance: {
type: Object as PropType<BrowserJsPlumbInstance>,
required: true,
},
isReadOnly: {
type: Boolean,
},
isActive: {
type: Boolean,
},
hideActions: {
type: Boolean,
},
disableSelecting: {
type: Boolean,
},
showCustomTooltip: {
type: Boolean,
},
workflow: {
type: Object as PropType<Workflow>,
required: true,
},
},
emits: { removeNode: null, nodeSelected: null },
setup() {
setup(props, { emit }) {
const deviceSupport = useDeviceSupport();
const toast = useToast();
const colorPopoverTrigger = ref<HTMLDivElement>();
@@ -156,12 +186,21 @@ export default defineComponent({
}
});
const nodeBase = useNodeBase({
name: props.name,
instance: props.instance,
workflowObject: props.workflow,
isReadOnly: props.isReadOnly,
emit: emit as (event: string, ...args: unknown[]) => void,
});
return {
deviceSupport,
toast,
colorPopoverTrigger,
contextMenu,
forceActions,
...nodeBase,
setForceActions,
};
},
@@ -172,7 +211,20 @@ export default defineComponent({
};
},
computed: {
...mapStores(useNodeTypesStore, useNDVStore, useUIStore, useWorkflowsStore),
...mapStores(
useNodeTypesStore,
useUIStore,
useNDVStore,
useCanvasStore,
useWorkflowsStore,
useHistoryStore,
),
data(): INodeUi | null {
return this.workflowsStore.getNodeByName(this.name);
},
nodeId(): string {
return this.data?.id || '';
},
defaultText(): string {
if (!this.nodeType) {
return '';
@@ -239,6 +291,17 @@ export default defineComponent({
return this.uiStore.isActionActive('workflowRunning');
},
},
mounted() {
// Initialize the node
if (this.data !== null) {
try {
this.addNode(this.data);
} catch (error) {
// This breaks when new nodes are loaded into store but workflow tab is not currently active
// Shouldn't affect anything
}
}
},
methods: {
onShowPopover() {
this.setForceActions(true);
@@ -274,7 +337,7 @@ export default defineComponent({
onMarkdownClick(link: HTMLAnchorElement) {
if (link) {
const isOnboardingNote = this.name === QUICKSTART_NOTE_NAME;
const isWelcomeVideo = link.querySelector('img[alt="n8n quickstart video"');
const isWelcomeVideo = link.querySelector('img[alt="n8n quickstart video"]');
const type =
isOnboardingNote && isWelcomeVideo
? 'welcome_video'