Skip to content

Commit 2782534

Browse files
gandreinielsmr
andauthored
feat(editor): Update Node Details View header tabs structure (#9425)
Co-authored-by: Elias Meire <[email protected]>
1 parent a7d3e59 commit 2782534

File tree

5 files changed

+234
-203
lines changed

5 files changed

+234
-203
lines changed

packages/design-system/src/components/N8nInputLabel/InputLabel.vue

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
v-if="tooltipText && label"
2323
:class="[$style.infoIcon, showTooltip ? $style.visible : $style.hidden]"
2424
>
25-
<N8nTooltip placement="top" :popper-class="$style.tooltipPopper">
25+
<N8nTooltip placement="top" :popper-class="$style.tooltipPopper" :show-after="300">
2626
<N8nIcon icon="question-circle" size="small" />
2727
<template #content>
2828
<div v-html="addTargetBlank(tooltipText)" />
@@ -90,6 +90,10 @@ const addTargetBlank = (html: string) =>
9090
.inputLabel:hover {
9191
.infoIcon {
9292
opacity: 1;
93+
94+
&:hover {
95+
color: var(--color-text-base);
96+
}
9397
}
9498
9599
.options {
@@ -117,7 +121,7 @@ const addTargetBlank = (html: string) =>
117121
display: flex;
118122
align-items: center;
119123
color: var(--color-text-light);
120-
padding-left: var(--spacing-4xs);
124+
margin-left: var(--spacing-4xs);
121125
z-index: 1;
122126
}
123127

packages/design-system/src/components/N8nTabs/Tabs.vue

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@
2626
>
2727
<div>
2828
{{ option.label }}
29-
<span :class="$style.external"
30-
><N8nIcon icon="external-link-alt" size="small"
31-
/></span>
29+
<span :class="$style.external">
30+
<N8nIcon icon="external-link-alt" size="xsmall" />
31+
</span>
3232
</div>
3333
</a>
3434
<RouterLink
@@ -45,7 +45,7 @@
4545
:data-test-id="`tab-${option.value}`"
4646
@click="() => handleTabClick(option.value)"
4747
>
48-
<N8nIcon v-if="option.icon" :icon="option.icon" size="medium" />
48+
<N8nIcon v-if="option.icon" :icon="option.icon" size="small" />
4949
<span v-if="option.label">{{ option.label }}</span>
5050
</div>
5151
</n8n-tooltip>
@@ -140,6 +140,7 @@ const scrollRight = () => scroll(50);
140140
color: var(--color-text-base);
141141
font-weight: var(--font-weight-bold);
142142
display: flex;
143+
align-items: center;
143144
width: 100%;
144145
position: absolute;
145146
overflow-x: scroll;
@@ -155,24 +156,30 @@ const scrollRight = () => scroll(50);
155156
}
156157
157158
.tab {
159+
--active-tab-border-width: 2px;
158160
display: block;
159-
padding: 0 var(--spacing-s) var(--spacing-2xs) var(--spacing-s);
160-
padding-bottom: var(--spacing-2xs);
161+
padding: 0 var(--spacing-s);
162+
padding-bottom: calc(var(--spacing-2xs) + var(--active-tab-border-width));
161163
font-size: var(--font-size-s);
162164
cursor: pointer;
163165
white-space: nowrap;
164166
color: var(--color-text-base);
165167
&:hover {
166168
color: var(--color-primary);
167169
}
170+
171+
span + span {
172+
margin-left: var(--spacing-4xs);
173+
}
168174
}
169175
170176
.activeTab {
171177
color: var(--color-primary);
172-
border-bottom: var(--color-primary) 2px solid;
178+
padding-bottom: var(--spacing-2xs);
179+
border-bottom: var(--color-primary) var(--active-tab-border-width) solid;
173180
}
174181
175-
.alignRight {
182+
.alignRight:not(.alignRight + .alignRight) {
176183
margin-left: auto;
177184
}
178185
@@ -182,15 +189,12 @@ const scrollRight = () => scroll(50);
182189
183190
&:hover {
184191
color: var(--color-primary);
185-
186-
.external {
187-
display: inline-block;
188-
}
189192
}
190193
}
191194
192195
.external {
193-
display: none;
196+
display: inline-block;
197+
margin-left: var(--spacing-5xs);
194198
}
195199
196200
.button {

packages/editor-ui/src/components/NodeSettings.vue

Lines changed: 69 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@
3131
</div>
3232
<NodeSettingsTabs
3333
v-if="node && nodeValid"
34-
v-model="openPanel"
34+
:model-value="openPanel"
3535
:node-type="nodeType"
3636
:push-ref="pushRef"
37+
@update:model-value="onTabSelect"
3738
/>
3839
</div>
3940
<div v-if="node && !nodeValid" class="node-is-not-valid">
@@ -126,7 +127,7 @@
126127
<n8n-notice
127128
:content="
128129
$locale.baseText('nodeSettings.useTheHttpRequestNode', {
129-
interpolate: { nodeTypeDisplayName: nodeType.displayName },
130+
interpolate: { nodeTypeDisplayName: nodeType?.displayName ?? '' },
130131
})
131132
"
132133
/>
@@ -186,6 +187,7 @@ import type {
186187
INodeProperties,
187188
NodeParameterValue,
188189
ConnectionTypes,
190+
NodeParameterValueType,
189191
} from 'n8n-workflow';
190192
import {
191193
NodeHelpers,
@@ -357,16 +359,16 @@ export default defineComponent({
357359
return [];
358360
}
359361
360-
return this.nodeType.properties;
362+
return this.nodeType?.properties ?? [];
361363
},
362364
outputPanelEditMode(): { enabled: boolean; value: string } {
363365
return this.ndvStore.outputPanelEditMode;
364366
},
365367
isCommunityNode(): boolean {
366-
return isCommunityPackageName(this.node?.type);
368+
return !!this.node && isCommunityPackageName(this.node.type);
367369
},
368370
isTriggerNode(): boolean {
369-
return this.nodeTypesStore.isTriggerNode(this.node?.type);
371+
return !!this.node && this.nodeTypesStore.isTriggerNode(this.node.type);
370372
},
371373
workflowOwnerName(): string {
372374
return this.workflowsEEStore.getWorkflowOwnerName(`${this.workflowsStore.workflowId}`);
@@ -425,7 +427,7 @@ export default defineComponent({
425427
return {
426428
nodeValid: true,
427429
nodeColor: null,
428-
openPanel: 'params',
430+
openPanel: 'params' as 'params' | 'settings',
429431
nodeValues: {
430432
color: '#ff0000',
431433
alwaysOutputData: false,
@@ -466,10 +468,10 @@ export default defineComponent({
466468
importCurlEventBus.off('setHttpNodeParameters', this.setHttpNodeParameters);
467469
},
468470
methods: {
469-
setHttpNodeParameters(parameters: Record<string, unknown>) {
471+
setHttpNodeParameters(parameters: NodeParameterValueType) {
470472
try {
471473
this.valueChanged({
472-
node: this.node.name,
474+
node: this.node?.name,
473475
name: 'parameters',
474476
value: parameters,
475477
});
@@ -649,8 +651,10 @@ export default defineComponent({
649651
// Data is on top level
650652
if (value === null) {
651653
// Property should be deleted
652-
const { [lastNamePart]: removedNodeValue, ...remainingNodeValues } = this.nodeValues;
653-
this.nodeValues = remainingNodeValues;
654+
if (lastNamePart) {
655+
const { [lastNamePart]: removedNodeValue, ...remainingNodeValues } = this.nodeValues;
656+
this.nodeValues = remainingNodeValues;
657+
}
654658
} else {
655659
// Value should be set
656660
this.nodeValues = {
@@ -666,17 +670,21 @@ export default defineComponent({
666670
| INodeParameters
667671
| INodeParameters[];
668672
669-
const { [lastNamePart]: removedNodeValue, ...remainingNodeValues } = tempValue;
670-
tempValue = remainingNodeValues;
673+
if (lastNamePart && !Array.isArray(tempValue)) {
674+
const { [lastNamePart]: removedNodeValue, ...remainingNodeValues } = tempValue;
675+
tempValue = remainingNodeValues;
676+
}
671677
672-
if (isArray && (tempValue as INodeParameters[]).length === 0) {
678+
if (isArray && Array.isArray(tempValue) && tempValue.length === 0) {
673679
// If a value from an array got delete and no values are left
674680
// delete also the parent
675681
lastNamePart = nameParts.pop();
676682
tempValue = get(this.nodeValues, nameParts.join('.')) as INodeParameters;
677-
const { [lastNamePart]: removedArrayNodeValue, ...remainingArrayNodeValues } =
678-
tempValue;
679-
tempValue = remainingArrayNodeValues;
683+
if (lastNamePart) {
684+
const { [lastNamePart]: removedArrayNodeValue, ...remainingArrayNodeValues } =
685+
tempValue;
686+
tempValue = remainingArrayNodeValues;
687+
}
680688
}
681689
} else {
682690
// Value should be set
@@ -734,6 +742,11 @@ export default defineComponent({
734742
// Save the node name before we commit the change because
735743
// we need the old name to rename the node properly
736744
const nodeNameBefore = parameterData.node || this.node?.name;
745+
746+
if (!nodeNameBefore) {
747+
return;
748+
}
749+
737750
const node = this.workflowsStore.getNodeByName(nodeNameBefore);
738751
739752
if (node === null) {
@@ -776,44 +789,46 @@ export default defineComponent({
776789
// we do not edit it directly
777790
nodeParameters = deepCopy(nodeParameters);
778791
779-
for (const parameterName of Object.keys(parameterData.value)) {
780-
//@ts-ignore
781-
newValue = parameterData.value[parameterName];
782-
783-
// Remove the 'parameters.' from the beginning to just have the
784-
// actual parameter name
785-
const parameterPath = parameterName.split('.').slice(1).join('.');
786-
787-
// Check if the path is supposed to change an array and if so get
788-
// the needed data like path and index
789-
const parameterPathArray = parameterPath.match(/(.*)\[(\d+)\]$/);
790-
791-
// Apply the new value
792-
//@ts-ignore
793-
if (parameterData[parameterName] === undefined && parameterPathArray !== null) {
794-
// Delete array item
795-
const path = parameterPathArray[1];
796-
const index = parameterPathArray[2];
797-
const data = get(nodeParameters, path);
798-
799-
if (Array.isArray(data)) {
800-
data.splice(parseInt(index, 10), 1);
801-
set(nodeParameters as object, path, data);
802-
}
803-
} else {
804-
if (newValue === undefined) {
805-
unset(nodeParameters as object, parameterPath);
792+
if (parameterData.value && typeof parameterData.value === 'object') {
793+
for (const parameterName of Object.keys(parameterData.value)) {
794+
//@ts-ignore
795+
newValue = parameterData.value[parameterName];
796+
797+
// Remove the 'parameters.' from the beginning to just have the
798+
// actual parameter name
799+
const parameterPath = parameterName.split('.').slice(1).join('.');
800+
801+
// Check if the path is supposed to change an array and if so get
802+
// the needed data like path and index
803+
const parameterPathArray = parameterPath.match(/(.*)\[(\d+)\]$/);
804+
805+
// Apply the new value
806+
//@ts-ignore
807+
if (parameterData[parameterName] === undefined && parameterPathArray !== null) {
808+
// Delete array item
809+
const path = parameterPathArray[1];
810+
const index = parameterPathArray[2];
811+
const data = get(nodeParameters, path);
812+
813+
if (Array.isArray(data)) {
814+
data.splice(parseInt(index, 10), 1);
815+
set(nodeParameters as object, path, data);
816+
}
806817
} else {
807-
set(nodeParameters as object, parameterPath, newValue);
818+
if (newValue === undefined) {
819+
unset(nodeParameters as object, parameterPath);
820+
} else {
821+
set(nodeParameters as object, parameterPath, newValue);
822+
}
808823
}
809-
}
810824
811-
void this.externalHooks.run('nodeSettings.valueChanged', {
812-
parameterPath,
813-
newValue,
814-
parameters: this.parameters,
815-
oldNodeParameters,
816-
});
825+
void this.externalHooks.run('nodeSettings.valueChanged', {
826+
parameterPath,
827+
newValue,
828+
parameters: this.parameters,
829+
oldNodeParameters,
830+
});
831+
}
817832
}
818833
819834
// Get the parameters with the now new defaults according to the
@@ -1144,6 +1159,9 @@ export default defineComponent({
11441159
openSettings() {
11451160
this.openPanel = 'settings';
11461161
},
1162+
onTabSelect(tab: 'params' | 'settings') {
1163+
this.openPanel = tab;
1164+
},
11471165
},
11481166
});
11491167
</script>

0 commit comments

Comments
 (0)