feat(editor): Add delete and disable button to nodes on hover (#8482)

This commit is contained in:
Elias Meire 2024-02-02 16:02:41 +01:00 committed by GitHub
parent 4b3659f04f
commit 994754bf39
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 225 additions and 170 deletions

View file

@ -28,6 +28,8 @@ describe('Canvas Actions', () => {
WorkflowPage.actions.addNodeToCanvas(EDIT_FIELDS_SET_NODE_NAME); WorkflowPage.actions.addNodeToCanvas(EDIT_FIELDS_SET_NODE_NAME);
WorkflowPage.getters.nodeViewBackground().click(600, 200, { force: true }); WorkflowPage.getters.nodeViewBackground().click(600, 200, { force: true });
cy.get('.jtk-connector').should('have.length', 1); cy.get('.jtk-connector').should('have.length', 1);
WorkflowPage.getters.nodeViewBackground().click(600, 400, { force: true });
WorkflowPage.actions.addNodeToCanvas(EDIT_FIELDS_SET_NODE_NAME); WorkflowPage.actions.addNodeToCanvas(EDIT_FIELDS_SET_NODE_NAME);
// Change connection from Set to Set1 // Change connection from Set to Set1
@ -154,17 +156,43 @@ describe('Canvas Actions', () => {
WorkflowPage.getters.nodeConnections().should('have.length', 0); WorkflowPage.getters.nodeConnections().should('have.length', 0);
}); });
it('should execute node', () => { describe('Node hover actions', () => {
WorkflowPage.actions.addNodeToCanvas(MANUAL_TRIGGER_NODE_NAME); it('should execute node', () => {
WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME); WorkflowPage.actions.addNodeToCanvas(MANUAL_TRIGGER_NODE_NAME);
WorkflowPage.getters WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME);
.canvasNodes() WorkflowPage.getters
.last() .canvasNodes()
.find('[data-test-id="execute-node-button"]') .last()
.click({ force: true }); .findChildByTestId('execute-node-button')
WorkflowPage.getters.successToast().should('contain', 'Node executed successfully'); .click({ force: true });
WorkflowPage.actions.executeNode(CODE_NODE_NAME); WorkflowPage.actions.executeNode(CODE_NODE_NAME);
WorkflowPage.getters.successToast().should('contain', 'Node executed successfully'); WorkflowPage.getters.successToast().should('have.length', 2);
WorkflowPage.getters.successToast().should('contain.text', 'Node executed successfully');
});
it('should disable and enable node', () => {
WorkflowPage.actions.addNodeToCanvas(MANUAL_TRIGGER_NODE_NAME);
WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME);
const disableButton = WorkflowPage.getters
.canvasNodes()
.last()
.findChildByTestId('disable-node-button');
disableButton.click({ force: true });
WorkflowPage.getters.disabledNodes().should('have.length', 1);
disableButton.click({ force: true });
WorkflowPage.getters.disabledNodes().should('have.length', 0);
});
it('should delete node', () => {
WorkflowPage.actions.addNodeToCanvas(MANUAL_TRIGGER_NODE_NAME);
WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME);
WorkflowPage.getters
.canvasNodes()
.last()
.find('[data-test-id="delete-node-button"]')
.click({ force: true });
WorkflowPage.getters.canvasNodes().should('have.length', 1);
});
}); });
it('should copy selected nodes', () => { it('should copy selected nodes', () => {

View file

@ -313,21 +313,38 @@ describe('Canvas Node Manipulation and Navigation', () => {
WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME); WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME);
cy.get('body').type('{esc}'); cy.get('body').type('{esc}');
cy.get('body').type('{esc}'); cy.get('body').type('{esc}');
WorkflowPage.actions.selectAll();
// Keyboard shortcut // Keyboard shortcut
WorkflowPage.actions.selectAll();
WorkflowPage.actions.hitDisableNodeShortcut(); WorkflowPage.actions.hitDisableNodeShortcut();
WorkflowPage.getters.disabledNodes().should('have.length', 2); WorkflowPage.getters.disabledNodes().should('have.length', 2);
WorkflowPage.actions.hitDisableNodeShortcut(); WorkflowPage.actions.hitDisableNodeShortcut();
WorkflowPage.getters.disabledNodes().should('have.length', 0); WorkflowPage.getters.disabledNodes().should('have.length', 0);
WorkflowPage.actions.deselectAll();
WorkflowPage.getters.canvasNodeByName(MANUAL_TRIGGER_NODE_DISPLAY_NAME).click();
WorkflowPage.actions.hitDisableNodeShortcut();
WorkflowPage.getters.disabledNodes().should('have.length', 1);
WorkflowPage.actions.selectAll();
WorkflowPage.actions.hitDisableNodeShortcut();
WorkflowPage.getters.disabledNodes().should('have.length', 2);
// Context menu // Context menu
WorkflowPage.actions.openContextMenu(); WorkflowPage.actions.selectAll();
WorkflowPage.actions.contextMenuAction('toggle_activation');
WorkflowPage.getters.disabledNodes().should('have.length', 2);
WorkflowPage.actions.openContextMenu(); WorkflowPage.actions.openContextMenu();
WorkflowPage.actions.contextMenuAction('toggle_activation'); WorkflowPage.actions.contextMenuAction('toggle_activation');
WorkflowPage.getters.disabledNodes().should('have.length', 0); WorkflowPage.getters.disabledNodes().should('have.length', 0);
WorkflowPage.actions.openContextMenu();
WorkflowPage.actions.contextMenuAction('toggle_activation');
WorkflowPage.getters.disabledNodes().should('have.length', 2);
WorkflowPage.actions.deselectAll();
WorkflowPage.getters.canvasNodeByName(MANUAL_TRIGGER_NODE_DISPLAY_NAME).click();
WorkflowPage.actions.openContextMenu();
WorkflowPage.actions.contextMenuAction('toggle_activation');
WorkflowPage.getters.disabledNodes().should('have.length', 1);
WorkflowPage.actions.selectAll();
WorkflowPage.actions.openContextMenu();
WorkflowPage.actions.contextMenuAction('toggle_activation');
WorkflowPage.getters.disabledNodes().should('have.length', 2);
}); });
it('should rename node (context menu or shortcut)', () => { it('should rename node (context menu or shortcut)', () => {

View file

@ -106,24 +106,6 @@
/> />
</div> </div>
<div v-if="!isReadOnly" v-show="!hideActions" class="node-options no-select-on-click">
<n8n-icon-button
data-test-id="execute-node-button"
type="tertiary"
text
icon="play"
:disabled="workflowRunning || isConfigNode"
:title="$locale.baseText('node.testStep')"
@click="executeNode"
/>
<n8n-icon-button
data-test-id="overflow-node-button"
type="tertiary"
text
icon="ellipsis-h"
@click="(e: MouseEvent) => openContextMenu(e, 'node-button')"
/>
</div>
<div <div
v-if="showDisabledLinethrough" v-if="showDisabledLinethrough"
:class="{ :class="{
@ -143,6 +125,54 @@
{{ nodeSubtitle }} {{ nodeSubtitle }}
</div> </div>
</div> </div>
<div
v-if="!isReadOnly"
v-show="!hideActions"
class="node-options no-select-on-click"
@contextmenu.stop
@mousedown.stop
>
<div class="node-options-inner">
<n8n-icon-button
v-if="!isConfigNode"
data-test-id="execute-node-button"
type="tertiary"
text
size="small"
icon="play"
:disabled="workflowRunning"
:title="$locale.baseText('node.testStep')"
@click="executeNode"
/>
<n8n-icon-button
data-test-id="disable-node-button"
type="tertiary"
text
size="small"
icon="power-off"
:title="nodeDisabledTitle"
@click="toggleDisableNode"
/>
<n8n-icon-button
data-test-id="delete-node-button"
type="tertiary"
size="small"
text
icon="trash"
:title="$locale.baseText('node.delete')"
@click="deleteNode"
/>
<n8n-icon-button
data-test-id="overflow-node-button"
type="tertiary"
size="small"
text
icon="ellipsis-h"
@click="(e: MouseEvent) => openContextMenu(e, 'node-button')"
/>
</div>
</div>
</div> </div>
</template> </template>
@ -437,12 +467,10 @@ export default defineComponent({
} }
return issues; return issues;
}, },
nodeDisabledIcon(): string { nodeDisabledTitle(): string {
if (this.data.disabled === false) { return this.data.disabled
return 'pause'; ? this.$locale.baseText('node.enable')
} else { : this.$locale.baseText('node.disable');
return 'play';
}
}, },
position(): XYPosition { position(): XYPosition {
return this.node ? this.node.position : [0, 0]; return this.node ? this.node.position : [0, 0];
@ -680,6 +708,7 @@ export default defineComponent({
}); });
} }
}, },
executeNode() { executeNode() {
this.$emit('runWorkflow', this.data.name, 'Node.executeNode'); this.$emit('runWorkflow', this.data.name, 'Node.executeNode');
this.$telemetry.track('User clicked node hover button', { this.$telemetry.track('User clicked node hover button', {
@ -689,6 +718,25 @@ export default defineComponent({
}); });
}, },
deleteNode() {
this.$telemetry.track('User clicked node hover button', {
node_type: this.data.type,
button_name: 'delete',
workflow_id: this.workflowsStore.workflowId,
});
this.$emit('removeNode', this.data.name);
},
toggleDisableNode() {
this.$telemetry.track('User clicked node hover button', {
node_type: this.data.type,
button_name: 'disable',
workflow_id: this.workflowsStore.workflowId,
});
this.$emit('toggleDisableNode', this.data);
},
onClick(event: MouseEvent) { onClick(event: MouseEvent) {
void this.callDebounced(this.onClickDebounced, { debounceTime: 50, trailing: true }, event); void this.callDebounced(this.onClickDebounced, { debounceTime: 50, trailing: true }, event);
}, },
@ -778,6 +826,42 @@ export default defineComponent({
} }
} }
&.touch-active,
&:hover,
&.menu-open {
.node-options {
opacity: 1;
}
}
.node-options {
:deep(.button) {
--button-font-color: var(--color-text-light);
--button-border-radius: 0;
}
cursor: default;
position: absolute;
bottom: 100%;
z-index: 11;
min-width: 100%;
display: flex;
left: calc(-1 * var(--spacing-4xs));
right: calc(-1 * var(--spacing-4xs));
justify-content: center;
align-items: center;
padding-bottom: var(--spacing-2xs);
font-size: var(--font-size-s);
opacity: 0;
transition: opacity 100ms ease-in;
&-inner {
display: flex;
align-items: center;
background-color: var(--color-canvas-background);
border-radius: var(--border-radius-base);
}
}
.node-default { .node-default {
position: absolute; position: absolute;
width: 100%; width: 100%;
@ -803,15 +887,6 @@ export default defineComponent({
} }
} }
&.touch-active,
&:hover,
&.menu-open {
.node-options {
pointer-events: all;
opacity: 1;
}
}
.node-executing-info { .node-executing-info {
display: none; display: none;
position: absolute; position: absolute;
@ -868,65 +943,6 @@ export default defineComponent({
.waiting { .waiting {
color: var(--color-secondary); color: var(--color-secondary);
} }
.node-options {
--node-options-height: 26px;
:deep(.button) {
--button-font-color: var(--color-text-light);
}
position: absolute;
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--spacing-2xs);
transition: opacity 100ms ease-in;
opacity: 0;
pointer-events: none;
top: calc(-1 * (var(--node-options-height) + var(--spacing-4xs)));
left: 0;
width: var(--node-width);
height: var(--node-options-height);
font-size: var(--font-size-s);
z-index: 10;
text-align: center;
.option {
display: inline-block;
&.touch {
display: none;
}
&:hover {
color: $color-primary;
}
.execute-icon {
position: relative;
font-size: var(----font-size-xl);
}
}
&:after {
content: '';
display: block;
position: absolute;
left: 0;
right: 0;
top: -1rem;
bottom: -1rem;
z-index: -1;
}
}
&.is-touch-device .node-options {
left: -25px;
width: 150px;
.option.touch {
display: initial;
}
}
} }
&--config { &--config {
@ -935,20 +951,12 @@ export default defineComponent({
--node-height: 75px; --node-height: 75px;
.node-default { .node-default {
.node-options {
background: color-mix(in srgb, var(--color-canvas-background) 80%, transparent);
height: 25px;
}
.node-icon { .node-icon {
scale: 0.75; scale: 0.75;
} }
}
.node-default {
.node-box { .node-box {
border: 2px solid var(--color-foreground-xdark); border: 2px solid var(--color-foreground-xdark);
//background-color: $node-background-type-other;
border-radius: 50px; border-radius: 50px;
&.executing { &.executing {
@ -1027,11 +1035,6 @@ export default defineComponent({
left: var(--configurable-node-icon-offset); left: var(--configurable-node-icon-offset);
} }
.node-options {
left: 0;
height: 25px;
}
.node-executing-info { .node-executing-info {
left: -67px; left: -67px;
} }
@ -1172,10 +1175,6 @@ export default defineComponent({
z-index: 100; z-index: 100;
} }
.node-options {
z-index: 10;
}
.drop-add-node-label { .drop-add-node-label {
z-index: 10; z-index: 10;
} }

View file

@ -4,7 +4,7 @@ exports[`useContextMenu > Read-only mode > should return the correct actions whe
[ [
{ {
"id": "open", "id": "open",
"label": "Open node...", "label": "Open...",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"↵", "↵",
@ -14,12 +14,12 @@ exports[`useContextMenu > Read-only mode > should return the correct actions whe
{ {
"disabled": true, "disabled": true,
"id": "execute", "id": "execute",
"label": "Test node", "label": "Test step",
}, },
{ {
"disabled": true, "disabled": true,
"id": "rename", "id": "rename",
"label": "Rename node", "label": "Rename",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"F2", "F2",
@ -29,7 +29,7 @@ exports[`useContextMenu > Read-only mode > should return the correct actions whe
{ {
"disabled": true, "disabled": true,
"id": "toggle_activation", "id": "toggle_activation",
"label": "Deactivate node", "label": "Deactivate",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"D", "D",
@ -39,7 +39,7 @@ exports[`useContextMenu > Read-only mode > should return the correct actions whe
{ {
"disabled": true, "disabled": true,
"id": "toggle_pin", "id": "toggle_pin",
"label": "Pin node", "label": "Pin",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"p", "p",
@ -48,7 +48,7 @@ exports[`useContextMenu > Read-only mode > should return the correct actions whe
}, },
{ {
"id": "copy", "id": "copy",
"label": "Copy node", "label": "Copy",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"C", "C",
@ -59,7 +59,7 @@ exports[`useContextMenu > Read-only mode > should return the correct actions whe
{ {
"disabled": true, "disabled": true,
"id": "duplicate", "id": "duplicate",
"label": "Duplicate node", "label": "Duplicate",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"D", "D",
@ -88,7 +88,7 @@ exports[`useContextMenu > Read-only mode > should return the correct actions whe
"disabled": true, "disabled": true,
"divided": true, "divided": true,
"id": "delete", "id": "delete",
"label": "Delete node", "label": "Delete",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"Del", "Del",
@ -117,7 +117,7 @@ exports[`useContextMenu > Read-only mode > should return the correct actions whe
}, },
{ {
"id": "copy", "id": "copy",
"label": "Copy sticky note", "label": "Copy",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"C", "C",
@ -128,7 +128,7 @@ exports[`useContextMenu > Read-only mode > should return the correct actions whe
{ {
"disabled": true, "disabled": true,
"id": "duplicate", "id": "duplicate",
"label": "Duplicate sticky note", "label": "Duplicate",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"D", "D",
@ -157,7 +157,7 @@ exports[`useContextMenu > Read-only mode > should return the correct actions whe
"disabled": true, "disabled": true,
"divided": true, "divided": true,
"id": "delete", "id": "delete",
"label": "Delete sticky note", "label": "Delete",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"Del", "Del",
@ -171,7 +171,7 @@ exports[`useContextMenu > should return the correct actions opening the menu fro
[ [
{ {
"id": "open", "id": "open",
"label": "Open node...", "label": "Open...",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"↵", "↵",
@ -181,12 +181,12 @@ exports[`useContextMenu > should return the correct actions opening the menu fro
{ {
"disabled": false, "disabled": false,
"id": "execute", "id": "execute",
"label": "Test node", "label": "Test step",
}, },
{ {
"disabled": false, "disabled": false,
"id": "rename", "id": "rename",
"label": "Rename node", "label": "Rename",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"F2", "F2",
@ -196,7 +196,7 @@ exports[`useContextMenu > should return the correct actions opening the menu fro
{ {
"disabled": false, "disabled": false,
"id": "toggle_activation", "id": "toggle_activation",
"label": "Deactivate node", "label": "Deactivate",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"D", "D",
@ -206,7 +206,7 @@ exports[`useContextMenu > should return the correct actions opening the menu fro
{ {
"disabled": true, "disabled": true,
"id": "toggle_pin", "id": "toggle_pin",
"label": "Pin node", "label": "Pin",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"p", "p",
@ -215,7 +215,7 @@ exports[`useContextMenu > should return the correct actions opening the menu fro
}, },
{ {
"id": "copy", "id": "copy",
"label": "Copy node", "label": "Copy",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"C", "C",
@ -226,7 +226,7 @@ exports[`useContextMenu > should return the correct actions opening the menu fro
{ {
"disabled": true, "disabled": true,
"id": "duplicate", "id": "duplicate",
"label": "Duplicate node", "label": "Duplicate",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"D", "D",
@ -255,7 +255,7 @@ exports[`useContextMenu > should return the correct actions opening the menu fro
"disabled": false, "disabled": false,
"divided": true, "divided": true,
"id": "delete", "id": "delete",
"label": "Delete node", "label": "Delete",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"Del", "Del",
@ -269,7 +269,7 @@ exports[`useContextMenu > should return the correct actions when right clicking
[ [
{ {
"id": "open", "id": "open",
"label": "Open node...", "label": "Open...",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"↵", "↵",
@ -279,12 +279,12 @@ exports[`useContextMenu > should return the correct actions when right clicking
{ {
"disabled": false, "disabled": false,
"id": "execute", "id": "execute",
"label": "Test node", "label": "Test step",
}, },
{ {
"disabled": false, "disabled": false,
"id": "rename", "id": "rename",
"label": "Rename node", "label": "Rename",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"F2", "F2",
@ -294,7 +294,7 @@ exports[`useContextMenu > should return the correct actions when right clicking
{ {
"disabled": false, "disabled": false,
"id": "toggle_activation", "id": "toggle_activation",
"label": "Deactivate node", "label": "Deactivate",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"D", "D",
@ -304,7 +304,7 @@ exports[`useContextMenu > should return the correct actions when right clicking
{ {
"disabled": true, "disabled": true,
"id": "toggle_pin", "id": "toggle_pin",
"label": "Pin node", "label": "Pin",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"p", "p",
@ -313,7 +313,7 @@ exports[`useContextMenu > should return the correct actions when right clicking
}, },
{ {
"id": "copy", "id": "copy",
"label": "Copy node", "label": "Copy",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"C", "C",
@ -324,7 +324,7 @@ exports[`useContextMenu > should return the correct actions when right clicking
{ {
"disabled": true, "disabled": true,
"id": "duplicate", "id": "duplicate",
"label": "Duplicate node", "label": "Duplicate",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"D", "D",
@ -353,7 +353,7 @@ exports[`useContextMenu > should return the correct actions when right clicking
"disabled": false, "disabled": false,
"divided": true, "divided": true,
"id": "delete", "id": "delete",
"label": "Delete node", "label": "Delete",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"Del", "Del",
@ -382,7 +382,7 @@ exports[`useContextMenu > should return the correct actions when right clicking
}, },
{ {
"id": "copy", "id": "copy",
"label": "Copy sticky note", "label": "Copy",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"C", "C",
@ -393,7 +393,7 @@ exports[`useContextMenu > should return the correct actions when right clicking
{ {
"disabled": true, "disabled": true,
"id": "duplicate", "id": "duplicate",
"label": "Duplicate sticky note", "label": "Duplicate",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"D", "D",
@ -422,7 +422,7 @@ exports[`useContextMenu > should return the correct actions when right clicking
"disabled": false, "disabled": false,
"divided": true, "divided": true,
"id": "delete", "id": "delete",
"label": "Delete sticky note", "label": "Delete",
"shortcut": { "shortcut": {
"keys": [ "keys": [
"Del", "Del",

View file

@ -617,13 +617,18 @@ export function useNodeHelpers() {
if (trackHistory) { if (trackHistory) {
historyStore.startRecordingUndo(); historyStore.startRecordingUndo();
} }
const newDisabledState = nodes.some((node) => !node.disabled);
for (const node of nodes) { for (const node of nodes) {
const oldState = node.disabled; if (newDisabledState === node.disabled) {
continue;
}
// Toggle disabled flag // Toggle disabled flag
const updateInformation = { const updateInformation = {
name: node.name, name: node.name,
properties: { properties: {
disabled: !oldState, disabled: newDisabledState,
} as IDataObject, } as IDataObject,
} as INodeUpdatePropertiesInformation; } as INodeUpdatePropertiesInformation;
@ -640,7 +645,7 @@ export function useNodeHelpers() {
updateNodesInputIssues(); updateNodesInputIssues();
if (trackHistory) { if (trackHistory) {
historyStore.pushCommandToUndo( historyStore.pushCommandToUndo(
new EnableNodeToggleCommand(node.name, oldState === true, node.disabled === true), new EnableNodeToggleCommand(node.name, node.disabled === true, newDisabledState),
); );
} }
} }

View file

@ -841,9 +841,11 @@
"node.thisIsATriggerNode": "This is a Trigger node. <a target=\"_blank\" href=\"https://docs.n8n.io/workflows/components/nodes/\">Learn more</a>", "node.thisIsATriggerNode": "This is a Trigger node. <a target=\"_blank\" href=\"https://docs.n8n.io/workflows/components/nodes/\">Learn more</a>",
"node.activateDeactivateNode": "Activate/Deactivate Node", "node.activateDeactivateNode": "Activate/Deactivate Node",
"node.changeColor": "Change color", "node.changeColor": "Change color",
"node.disabled": "Disabled", "node.disabled": "Deactivated",
"node.testStep": "Test Step", "node.testStep": "Test step",
"node.deleteNode": "Delete node", "node.disable": "Deactivate",
"node.enable": "Activate",
"node.delete": "Delete",
"node.issues": "Issues", "node.issues": "Issues",
"node.nodeIsExecuting": "Node is executing", "node.nodeIsExecuting": "Node is executing",
"node.nodeIsWaitingTill": "Node is waiting until {date} {time}", "node.nodeIsWaitingTill": "Node is waiting until {date} {time}",
@ -1104,16 +1106,16 @@
"contextMenu.sticky": "sticky note | sticky notes", "contextMenu.sticky": "sticky note | sticky notes",
"contextMenu.selectAll": "Select all", "contextMenu.selectAll": "Select all",
"contextMenu.deselectAll": "Clear selection", "contextMenu.deselectAll": "Clear selection",
"contextMenu.duplicate": "Duplicate {subject} | Duplicate {count} {subject}", "contextMenu.duplicate": "Duplicate | Duplicate {count} {subject}",
"contextMenu.open": "Open node...", "contextMenu.open": "Open...",
"contextMenu.test": "Test node", "contextMenu.test": "Test step",
"contextMenu.rename": "Rename node", "contextMenu.rename": "Rename",
"contextMenu.copy": "Copy {subject} | Copy {count} {subject}", "contextMenu.copy": "Copy | Copy {count} {subject}",
"contextMenu.deactivate": "Deactivate {subject} | Deactivate {count} {subject}", "contextMenu.deactivate": "Deactivate | Deactivate {count} {subject}",
"contextMenu.activate": "Activate node | Activate {count} nodes", "contextMenu.activate": "Activate | Activate {count} nodes",
"contextMenu.pin": "Pin node | Pin {count} nodes", "contextMenu.pin": "Pin | Pin {count} nodes",
"contextMenu.unpin": "Unpin node | Unpin {count} nodes", "contextMenu.unpin": "Unpin | Unpin {count} nodes",
"contextMenu.delete": "Delete {subject} | Delete {count} {subject}", "contextMenu.delete": "Delete | Delete {count} {subject}",
"contextMenu.addNode": "Add node", "contextMenu.addNode": "Add node",
"contextMenu.addSticky": "Add sticky note", "contextMenu.addSticky": "Add sticky note",
"contextMenu.editSticky": "Edit sticky note", "contextMenu.editSticky": "Edit sticky note",

View file

@ -151,6 +151,7 @@ import {
faTools, faTools,
faProjectDiagram, faProjectDiagram,
faStream, faStream,
faPowerOff,
} from '@fortawesome/free-solid-svg-icons'; } from '@fortawesome/free-solid-svg-icons';
import { faVariable, faXmark, faVault } from './custom'; import { faVariable, faXmark, faVault } from './custom';
import { faStickyNote } from '@fortawesome/free-regular-svg-icons'; import { faStickyNote } from '@fortawesome/free-regular-svg-icons';
@ -315,6 +316,7 @@ export const FontAwesomePlugin: Plugin<{}> = {
addIcon(faGem); addIcon(faGem);
addIcon(faXmark); addIcon(faXmark);
addIcon(faDownload); addIcon(faDownload);
addIcon(faPowerOff);
app.component('FontAwesomeIcon', FontAwesomeIcon); app.component('FontAwesomeIcon', FontAwesomeIcon);
}, },

View file

@ -61,6 +61,8 @@
@runWorkflow="onRunNode" @runWorkflow="onRunNode"
@moved="onNodeMoved" @moved="onNodeMoved"
@run="onNodeRun" @run="onNodeRun"
@removeNode="(name) => removeNode(name, true)"
@toggleDisableNode="(node) => toggleActivationNodes([node])"
> >
<template #custom-tooltip> <template #custom-tooltip>
<span <span