feat(editor): Supress validation errors for freshly added nodes (#5149)
* feat(editor): Supress validation errors when node is added from node creator * Supress initial errors also for resource locator inputs * Use nodeMetadata prop to store node's `pristine` state * Revert `setNodeParameters` check for `nodeMetadata` * Rename getIsNodePristine to isNodePristine
This commit is contained in:
@@ -27,10 +27,11 @@
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
<div v-else :class="issues.length ? $style.hasIssues : $style.input">
|
||||
<div v-else :class="issues.length && !hideIssues ? $style.hasIssues : $style.input">
|
||||
<n8n-select
|
||||
:value="getSelectedId(credentialTypeDescription.name)"
|
||||
@change="(value) => onCredentialSelected(credentialTypeDescription.name, value)"
|
||||
@blur="$emit('blur', 'credentials')"
|
||||
:placeholder="getSelectPlaceholder(credentialTypeDescription.name, issues)"
|
||||
size="small"
|
||||
>
|
||||
@@ -49,7 +50,7 @@
|
||||
</n8n-option>
|
||||
</n8n-select>
|
||||
|
||||
<div :class="$style.warning" v-if="issues.length">
|
||||
<div :class="$style.warning" v-if="issues.length && !hideIssues">
|
||||
<n8n-tooltip placement="top">
|
||||
<template #content>
|
||||
<titled-list
|
||||
@@ -82,6 +83,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType } from 'vue';
|
||||
import { restApi } from '@/mixins/restApi';
|
||||
import {
|
||||
ICredentialsResponse,
|
||||
@@ -108,11 +110,23 @@ import { useCredentialsStore } from '@/stores/credentials';
|
||||
|
||||
export default mixins(genericHelpers, nodeHelpers, restApi, showMessage).extend({
|
||||
name: 'NodeCredentials',
|
||||
props: [
|
||||
'readonly',
|
||||
'node', // INodeUi
|
||||
'overrideCredType', // cred type
|
||||
],
|
||||
props: {
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
node: {
|
||||
type: Object as PropType<INodeUi>,
|
||||
required: true,
|
||||
},
|
||||
overrideCredType: {
|
||||
type: String,
|
||||
},
|
||||
hideIssues: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
TitledList,
|
||||
},
|
||||
|
||||
@@ -93,14 +93,18 @@
|
||||
:hideDelete="true"
|
||||
:nodeValues="nodeValues"
|
||||
:isReadOnly="isReadOnly"
|
||||
:hiddenIssuesInputs="hiddenIssuesInputs"
|
||||
path="parameters"
|
||||
@valueChanged="valueChanged"
|
||||
@activate="onWorkflowActivate"
|
||||
@parameterBlur="onParameterBlur"
|
||||
>
|
||||
<node-credentials
|
||||
:node="node"
|
||||
:readonly="isReadOnly"
|
||||
@credentialSelected="credentialSelected"
|
||||
@blur="onParameterBlur"
|
||||
:hide-issues="hiddenIssuesInputs.includes('credentials')"
|
||||
/>
|
||||
</parameter-input-list>
|
||||
<div v-if="parametersNoneSetting.length === 0" class="no-parameters">
|
||||
@@ -124,16 +128,20 @@
|
||||
:parameters="parametersSetting"
|
||||
:nodeValues="nodeValues"
|
||||
:isReadOnly="isReadOnly"
|
||||
:hiddenIssuesInputs="hiddenIssuesInputs"
|
||||
path="parameters"
|
||||
@valueChanged="valueChanged"
|
||||
@parameterBlur="onParameterBlur"
|
||||
/>
|
||||
<parameter-input-list
|
||||
:parameters="nodeSettings"
|
||||
:hideDelete="true"
|
||||
:nodeValues="nodeValues"
|
||||
:isReadOnly="isReadOnly"
|
||||
:hiddenIssuesInputs="hiddenIssuesInputs"
|
||||
path=""
|
||||
@valueChanged="valueChanged"
|
||||
@parameterBlur="onParameterBlur"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -414,6 +422,7 @@ export default mixins(externalHooks, nodeHelpers).extend({
|
||||
COMMUNITY_NODES_INSTALLATION_DOCS_URL,
|
||||
CUSTOM_NODES_DOCS_URL,
|
||||
MAIN_NODE_PANEL_WIDTH,
|
||||
hiddenIssuesInputs: [] as string[],
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
@@ -445,10 +454,25 @@ export default mixins(externalHooks, nodeHelpers).extend({
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
populateHiddenIssuesSet() {
|
||||
if (!this.node || !this.workflowsStore.isNodePristine(this.node.name)) return;
|
||||
|
||||
this.hiddenIssuesInputs.push('credentials');
|
||||
this.parametersNoneSetting.forEach((parameter) => {
|
||||
this.hiddenIssuesInputs.push(parameter.name);
|
||||
});
|
||||
|
||||
this.workflowsStore.setNodePristine(this.node.name, false);
|
||||
},
|
||||
onParameterBlur(parameterName: string) {
|
||||
this.hiddenIssuesInputs = this.hiddenIssuesInputs.filter((name) => name !== parameterName);
|
||||
},
|
||||
onWorkflowActivate() {
|
||||
this.hiddenIssuesInputs = [];
|
||||
this.$emit('activate');
|
||||
},
|
||||
onNodeExecute() {
|
||||
this.hiddenIssuesInputs = [];
|
||||
this.$emit('execute');
|
||||
},
|
||||
setValue(name: string, value: NodeParameterValue) {
|
||||
@@ -457,7 +481,7 @@ export default mixins(externalHooks, nodeHelpers).extend({
|
||||
|
||||
let isArray = false;
|
||||
if (lastNamePart !== undefined && lastNamePart.includes('[')) {
|
||||
// It incldues an index so we have to extract it
|
||||
// It includes an index so we have to extract it
|
||||
const lastNameParts = lastNamePart.match(/(.*)\[(\d+)\]$/);
|
||||
if (lastNameParts) {
|
||||
nameParts.push(lastNameParts[1]);
|
||||
@@ -835,6 +859,7 @@ export default mixins(externalHooks, nodeHelpers).extend({
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.populateHiddenIssuesSet();
|
||||
this.setNodeValues();
|
||||
if (this.eventBus) {
|
||||
(this.eventBus as Vue).$on('openSettings', () => {
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
:activeDrop="activeDrop"
|
||||
:forceShowExpression="forceShowExpression"
|
||||
:hint="hint"
|
||||
:hide-issues="hideIssues"
|
||||
@valueChanged="valueChanged"
|
||||
@textInput="onTextInput"
|
||||
@focus="onFocus"
|
||||
@@ -119,6 +120,10 @@ export default mixins(showMessage).extend({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
hideIssues: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
parameter: {
|
||||
type: Object as PropType<INodeProperties>,
|
||||
},
|
||||
@@ -197,6 +202,7 @@ export default mixins(showMessage).extend({
|
||||
if (!this.parameter.noDataExpression) {
|
||||
this.ndvStore.setMappableNDVInputFocus('');
|
||||
}
|
||||
this.$emit('blur');
|
||||
},
|
||||
onMenuExpanded(expanded: boolean) {
|
||||
this.menuExpanded = expanded;
|
||||
|
||||
@@ -93,11 +93,13 @@
|
||||
|
||||
<parameter-input-full
|
||||
:parameter="parameter"
|
||||
:hide-issues="hiddenIssuesInputs.includes(parameter.name)"
|
||||
:value="getParameterValue(nodeValues, parameter.name, path)"
|
||||
:displayOptions="true"
|
||||
:path="getPath(parameter.name)"
|
||||
:isReadOnly="isReadOnly"
|
||||
@valueChanged="valueChanged"
|
||||
@blur="onParameterBlur(parameter.name)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -108,13 +110,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {
|
||||
deepCopy,
|
||||
INodeParameters,
|
||||
INodeProperties,
|
||||
INodeTypeDescription,
|
||||
NodeParameterValue,
|
||||
} from 'n8n-workflow';
|
||||
import { deepCopy, INodeParameters, INodeProperties, NodeParameterValue } from 'n8n-workflow';
|
||||
|
||||
import { INodeUi, IUpdateInformation } from '@/Interface';
|
||||
|
||||
@@ -126,8 +122,8 @@ import ImportParameter from '@/components/ImportParameter.vue';
|
||||
import { get, set } from 'lodash';
|
||||
|
||||
import mixins from 'vue-typed-mixins';
|
||||
import { Component } from 'vue';
|
||||
import { mapState, mapStores } from 'pinia';
|
||||
import { Component, PropType } from 'vue';
|
||||
import { mapStores } from 'pinia';
|
||||
import { useNDVStore } from '@/stores/ndv';
|
||||
import { useNodeTypesStore } from '@/stores/nodeTypes';
|
||||
|
||||
@@ -140,14 +136,36 @@ export default mixins(workflowHelpers).extend({
|
||||
CollectionParameter: () => import('./CollectionParameter.vue') as Promise<Component>,
|
||||
ImportParameter,
|
||||
},
|
||||
props: [
|
||||
'nodeValues', // INodeParameters
|
||||
'parameters', // INodeProperties
|
||||
'path', // string
|
||||
'hideDelete', // boolean
|
||||
'indent',
|
||||
'isReadOnly',
|
||||
],
|
||||
props: {
|
||||
nodeValues: {
|
||||
type: Object as PropType<INodeParameters>,
|
||||
required: true,
|
||||
},
|
||||
parameters: {
|
||||
type: Array as PropType<INodeProperties[]>,
|
||||
required: true,
|
||||
},
|
||||
path: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
hideDelete: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
indent: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
hiddenIssuesInputs: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapStores(useNodeTypesStore, useNDVStore),
|
||||
nodeTypeVersion(): number | null {
|
||||
@@ -187,6 +205,9 @@ export default mixins(workflowHelpers).extend({
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onParameterBlur(parameterName: string) {
|
||||
this.$emit('parameterBlur', parameterName);
|
||||
},
|
||||
getCredentialsDependencies() {
|
||||
const dependencies = new Set();
|
||||
const nodeType = this.nodeTypesStore.getNodeType(
|
||||
|
||||
@@ -684,6 +684,7 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({
|
||||
if (!this.isSearchable || this.currentQueryError) {
|
||||
this.showResourceDropdown = false;
|
||||
}
|
||||
this.$emit('blur');
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user