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
8 changed files with 225 additions and 170 deletions

View File

@@ -106,24 +106,6 @@
/>
</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
v-if="showDisabledLinethrough"
:class="{
@@ -143,6 +125,54 @@
{{ nodeSubtitle }}
</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>
</template>
@@ -437,12 +467,10 @@ export default defineComponent({
}
return issues;
},
nodeDisabledIcon(): string {
if (this.data.disabled === false) {
return 'pause';
} else {
return 'play';
}
nodeDisabledTitle(): string {
return this.data.disabled
? this.$locale.baseText('node.enable')
: this.$locale.baseText('node.disable');
},
position(): XYPosition {
return this.node ? this.node.position : [0, 0];
@@ -680,6 +708,7 @@ export default defineComponent({
});
}
},
executeNode() {
this.$emit('runWorkflow', this.data.name, 'Node.executeNode');
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) {
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 {
position: absolute;
width: 100%;
@@ -803,15 +887,6 @@ export default defineComponent({
}
}
&.touch-active,
&:hover,
&.menu-open {
.node-options {
pointer-events: all;
opacity: 1;
}
}
.node-executing-info {
display: none;
position: absolute;
@@ -868,65 +943,6 @@ export default defineComponent({
.waiting {
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 {
@@ -935,20 +951,12 @@ export default defineComponent({
--node-height: 75px;
.node-default {
.node-options {
background: color-mix(in srgb, var(--color-canvas-background) 80%, transparent);
height: 25px;
}
.node-icon {
scale: 0.75;
}
}
.node-default {
.node-box {
border: 2px solid var(--color-foreground-xdark);
//background-color: $node-background-type-other;
border-radius: 50px;
&.executing {
@@ -1027,11 +1035,6 @@ export default defineComponent({
left: var(--configurable-node-icon-offset);
}
.node-options {
left: 0;
height: 25px;
}
.node-executing-info {
left: -67px;
}
@@ -1172,10 +1175,6 @@ export default defineComponent({
z-index: 100;
}
.node-options {
z-index: 10;
}
.drop-add-node-label {
z-index: 10;
}