🔀 Merge branch 'master' into Doc-Link-to-Node-Credentials-Modal

This commit is contained in:
Jan Oberhauser
2020-08-27 09:35:22 +02:00
79 changed files with 7685 additions and 719 deletions

View File

@@ -417,3 +417,5 @@ export interface ITimeoutHMS {
minutes: number;
seconds: number;
}
export type WorkflowTitleStatus = 'EXECUTING' | 'IDLE' | 'ERROR';

View File

@@ -1,6 +1,6 @@
<template>
<div v-if="dialogVisible" @keydown.stop>
<el-dialog :visible="dialogVisible" append-to-body width="55%" :title="title" :nodeType="nodeType" :before-close="closeDialog">
<el-dialog :visible="dialogVisible" append-to-body width="75%" :title="title" :nodeType="nodeType" :before-close="closeDialog">
<div name="title" class="titleContainer" slot="title">
<div id="left">{{title}}</div>
<div id="right">
@@ -271,7 +271,7 @@ export default mixins(
this.$showMessage({
title: 'Credentials created',
message: `The credential "${eventData.data.name}" got created!`,
message: `"${eventData.data.name}" credentials were successfully created!`,
type: 'success',
});
@@ -284,7 +284,7 @@ export default mixins(
this.$showMessage({
title: 'Credentials updated',
message: `The credential "${eventData.data.name}" got updated!`,
message: `"${eventData.data.name}" credentials were successfully updated!`,
type: 'success',
});

View File

@@ -44,19 +44,19 @@
<el-button title="Connect OAuth Credentials" circle :disabled="true">
<font-awesome-icon icon="redo" />
</el-button>
Not all required credential properties are filled
Enter all required properties
</span>
<span v-else-if="isOAuthConnected === true">
<el-button title="Reconnect OAuth Credentials" @click.stop="oAuthCredentialAuthorize()" circle>
<font-awesome-icon icon="redo" />
</el-button>
Is connected
Connected
</span>
<span v-else>
<el-button title="Connect OAuth Credentials" @click.stop="oAuthCredentialAuthorize()" circle>
<font-awesome-icon icon="sign-in-alt" />
</el-button>
Is NOT connected
Not connected
</span>
<div v-if="credentialProperties.length">
@@ -91,7 +91,7 @@
<div v-if="nodesAccess.length === 0" class="no-nodes-access">
<strong>
Important!
Important
</strong><br />
Add at least one node which has access to the credentials!
</div>
@@ -163,8 +163,8 @@ export default mixins(
isMinimized: true,
helpTexts: {
credentialsData: 'The credentials to set.',
credentialsName: 'The name the credentials should be saved as. Use a name<br />which makes it clear to what exactly they give access to.<br />For credentials of an Email account that could be the Email address itself.',
nodesWithAccess: 'The nodes which allowed to use this credentials.',
credentialsName: 'A recognizable label for the credentials. Descriptive names work <br />best here, so you can easily select it from a list later.',
nodesWithAccess: 'Nodes with access to these credentials.',
},
credentialDataTemp: null as ICredentialsDecryptedResponse | null,
nodesAccess: [] as string[],
@@ -256,7 +256,7 @@ export default mixins(
this.$showMessage({
title: 'Copied',
message: `The callback URL got copied!`,
message: `Callback URL was successfully copied!`,
type: 'success',
});
},
@@ -401,7 +401,7 @@ export default mixins(
this.$showMessage({
title: 'Connected',
message: 'Got connected!',
message: 'Connected successfully!',
type: 'success',
});
}

View File

@@ -124,7 +124,7 @@ export default mixins(
try {
this.credentials = JSON.parse(JSON.stringify(this.$store.getters.allCredentials));
} catch (error) {
this.$showError(error, 'Proble loading credentials', 'There was a problem loading the credentials:');
this.$showError(error, 'Problem loading credentials', 'There was a problem loading the credentials:');
this.isDataLoading = false;
return;
}
@@ -138,7 +138,7 @@ export default mixins(
},
async deleteCredential (credential: ICredentialsResponse) {
const deleteConfirmed = await this.confirmMessage(`Are you sure that you want to delete the credentials "${credential.name}"?`, 'Delete Credentials?', 'warning', 'Yes, delete!');
const deleteConfirmed = await this.confirmMessage(`Are you sure you want to delete "${credential.name}" credentials?`, 'Delete Credentials?', 'warning', 'Yes, delete!');
if (deleteConfirmed === false) {
return;

View File

@@ -12,14 +12,15 @@
<font-awesome-icon icon="check" class="execution-icon success" v-if="executionFinished" title="Execution was successful" />
<font-awesome-icon icon="times" class="execution-icon error" v-else title="Execution did fail" />
</span>
of Workflow
of
<span class="workflow-name clickable" title="Open Workflow">
<span @click="openWorkflow(workflowExecution.workflowId)">"{{workflowName}}"</span>
</span>
workflow
</span>
<span index="workflow-name" class="current-workflow" v-if="!isReadOnly">
<span v-if="currentWorkflow">Workflow: <span class="workflow-name">{{workflowName}}</span></span>
<span v-else class="workflow-not-saved">Workflow not saved!</span>
<span v-else class="workflow-not-saved">Workflow was not saved!</span>
</span>
<span class="saving-workflow" v-if="isWorkflowSaving">
@@ -32,9 +33,9 @@
<div class="push-connection-lost" v-if="!isPushConnectionActive">
<el-tooltip placement="bottom-end" effect="light">
<div slot="content">
Server connection could not be established.<br />
The server is down or there is a connection problem.<br />
It will reconnect automatically as soon as the backend can be reached.
Cannot connect to server.<br />
It is either down or you have a connection issue. <br />
It should reconnect automatically once the issue is resolved.
</div>
<span>
<font-awesome-icon icon="exclamation-triangle" />&nbsp;
@@ -50,9 +51,8 @@
<div class="read-only" v-if="isReadOnly">
<el-tooltip placement="bottom-end" effect="light">
<div slot="content">
A past execution gets displayed. For that reason no data<br />
can be changed. To make changes or to execute it again open<br />
the workflow by clicking on it`s name on the left.
You're viewing the log of a previous execution. You cannot<br />
make changes since this execution already occured. Make changes<br /> to this workflow by clicking on it`s name on the left.
</div>
<span>
<font-awesome-icon icon="exclamation-triangle" />
@@ -84,6 +84,7 @@ import { genericHelpers } from '@/components/mixins/genericHelpers';
import { pushConnection } from '@/components/mixins/pushConnection';
import { restApi } from '@/components/mixins/restApi';
import { showMessage } from '@/components/mixins/showMessage';
import { titleChange } from '@/components/mixins/titleChange';
import { workflowHelpers } from '@/components/mixins/workflowHelpers';
import { saveAs } from 'file-saver';
@@ -95,6 +96,7 @@ export default mixins(
pushConnection,
restApi,
showMessage,
titleChange,
workflowHelpers,
)
.extend({
@@ -155,6 +157,7 @@ export default mixins(
},
methods: {
async openWorkflow (workflowId: string) {
this.$titleSet(this.workflowName, 'IDLE');
// Change to other workflow
this.$router.push({
name: 'NodeViewExisting',
@@ -162,7 +165,6 @@ export default mixins(
});
},
},
async mounted () {
// Initialize the push connection
this.pushConnect();

View File

@@ -179,6 +179,7 @@ import WorkflowSettings from '@/components/WorkflowSettings.vue';
import { genericHelpers } from '@/components/mixins/genericHelpers';
import { restApi } from '@/components/mixins/restApi';
import { showMessage } from '@/components/mixins/showMessage';
import { titleChange } from '@/components/mixins/titleChange';
import { workflowHelpers } from '@/components/mixins/workflowHelpers';
import { workflowSave } from '@/components/mixins/workflowSave';
import { workflowRun } from '@/components/mixins/workflowRun';
@@ -191,6 +192,7 @@ export default mixins(
genericHelpers,
restApi,
showMessage,
titleChange,
workflowHelpers,
workflowRun,
workflowSave,
@@ -417,7 +419,8 @@ export default mixins(
this.$showError(error, 'Problem deleting the workflow', 'There was a problem deleting the workflow:');
return;
}
// Reset tab title since workflow is deleted.
this.$titleReset();
this.$showMessage({
title: 'Workflow got deleted',
message: `The workflow "${this.workflowName}" got deleted!`,

View File

@@ -13,7 +13,7 @@
<div class="node-create-list-wrapper">
<div class="node-create-list">
<div v-if="filteredNodeTypes.length === 0" class="no-results">
No node found which matches active filter!
🙃 no nodes matching your search criteria
</div>
<node-create-item :active="index === activeNodeTypeIndex" :nodeType="nodeType" v-for="(nodeType, index) in filteredNodeTypes" v-bind:key="nodeType.name" @nodeTypeSelected="nodeTypeSelected"></node-create-item>
</div>

View File

@@ -5,7 +5,7 @@
<display-with-change :key-name="'name'" @valueChanged="valueChanged"></display-with-change>
<a v-if="nodeType" :href="'http://n8n.io/nodes/' + nodeType.name" target="_blank" class="node-info">
<el-tooltip class="clickable" placement="top" effect="light">
<div slot="content" v-html="'<strong>Node Description:</strong><br />' + nodeTypeDescription + '<br /><br /><strong>For more information and usage examples click!</strong>'"></div>
<div slot="content" v-html="'<strong>Node Description:</strong><br />' + nodeTypeDescription + '<br /><br /><strong>Click the \'?\' icon to open this node on n8n.io </strong>'"></div>
<font-awesome-icon icon="question-circle" />
</el-tooltip>
</a>
@@ -22,7 +22,7 @@
<node-webhooks :node="node" :nodeType="nodeType" />
<parameter-input-list :parameters="parametersNoneSetting" :hideDelete="true" :nodeValues="nodeValues" path="parameters" @valueChanged="valueChanged" />
<div v-if="parametersNoneSetting.length === 0">
The node does not have any parameters.
This node does not have any parameters.
</div>
</el-tab-pane>
<el-tab-pane label="Settings">
@@ -162,15 +162,15 @@ export default mixins(
},
default: '',
noDataExpression: true,
description: 'Notes to save with the node.',
description: 'Optional note to save with the node.',
},
{
displayName: 'Notes In Flow',
displayName: 'Display note in flow?',
name: 'notesInFlow',
type: 'boolean',
default: false,
noDataExpression: true,
description: 'If activated it will display the above notes in the flow as subtitle.',
description: 'If active, the note above will display in the flow as a subtitle.',
},
{
displayName: 'Node Color',
@@ -186,7 +186,7 @@ export default mixins(
type: 'boolean',
default: false,
noDataExpression: true,
description: 'If activated and the node does not have any data for the first output,<br />it returns an empty item anyway. Be careful setting this on<br />IF-Nodes as it could easily cause an infinite loop.',
description: 'If active, the node will return an empty item even if the <br />node returns no data during an initial execution. Be careful setting <br />this on IF-Nodes as it could cause an infinite loop.',
},
{
displayName: 'Execute Once',
@@ -194,7 +194,7 @@ export default mixins(
type: 'boolean',
default: false,
noDataExpression: true,
description: 'Instead of executing once per item does it only execute once with the data of the first item.',
description: 'If active, the node executes only once, with data<br /> from the first item it recieves. ',
},
{
displayName: 'Retry On Fail',
@@ -202,7 +202,7 @@ export default mixins(
type: 'boolean',
default: false,
noDataExpression: true,
description: 'If activated it will automatically retry the node again multiple times.',
description: 'If active, the node tries to execute a failed attempt <br /> multiple times until it succeeds.',
},
{
displayName: 'Max. Tries',
@@ -221,7 +221,7 @@ export default mixins(
},
},
noDataExpression: true,
description: 'How often it should try to execute the node before it should fail.',
description: 'Number of times Retry On Fail should attempt to execute the node <br />before stopping and returning the execution as failed.',
},
{
displayName: 'Wait Between Tries',
@@ -240,7 +240,7 @@ export default mixins(
},
},
noDataExpression: true,
description: 'How long to wait between ties. Value in ms.',
description: 'How long to wait between each attempt. Value in ms.',
},
{
displayName: 'Continue On Fail',
@@ -248,7 +248,7 @@ export default mixins(
type: 'boolean',
default: false,
noDataExpression: true,
description: 'If activated and the node fails the workflow will simply continue running.<br />It will then simply pass through the input data so the workflow has<br />to be set up to handle the case that different data gets returned.',
description: 'If active, the workflow continues even if this node\'s <br /execution fails. When this occurs, the node passes along input data from<br />previous nodes - so your workflow should account for unexpected output data.',
},
] as INodeProperties[],

View File

@@ -88,7 +88,7 @@ export default mixins(
this.$showMessage({
title: 'Copied',
message: `The webhook URL got copied!`,
message: `The webhook URL was successfully copied!`,
type: 'success',
});
},

View File

@@ -7,7 +7,7 @@
:disabled="workflowRunning"
@click.stop="runWorkflow(node.name)"
class="execute-node-button"
:title="`Executes node ${node.name} and all not already executed nodes before it.`"
:title="`Executes this ${node.name} node after executing any previous nodes that have not yet returned data`"
>
<div class="run-icon-button">
<font-awesome-icon v-if="!workflowRunning" icon="play-circle"/>
@@ -72,14 +72,14 @@
<span v-else>
<div v-if="showData === false" class="to-much-data">
<h3>
Node contains large amount of data
Node returned a large amount of data
</h3>
<div class="text">
The node contains {{parseInt(dataSize/1024).toLocaleString()}} KB of data.<br />
Displaying it could cause problems!<br />
<br />
If you decide to display it anyway avoid the JSON view!
If you do decide to display it, avoid the JSON view!
</div>
<el-button size="small" @click="displayMode = 'Table';showData = true;">
@@ -162,7 +162,7 @@
<div>
<strong>No data</strong><br />
<br />
To display data execute the node first by pressing the execute button above.
Data returned by this node will display here<br />
</div>
</div>
</div>

View File

@@ -34,6 +34,7 @@ import WorkflowActivator from '@/components/WorkflowActivator.vue';
import { restApi } from '@/components/mixins/restApi';
import { genericHelpers } from '@/components/mixins/genericHelpers';
import { showMessage } from '@/components/mixins/showMessage';
import { titleChange } from '@/components/mixins/titleChange';
import { IWorkflowShortResponse } from '@/Interface';
import mixins from 'vue-typed-mixins';
@@ -42,6 +43,7 @@ export default mixins(
genericHelpers,
restApi,
showMessage,
titleChange,
).extend({
name: 'WorkflowOpen',
props: [
@@ -89,6 +91,7 @@ export default mixins(
},
openWorkflow (data: IWorkflowShortResponse, column: any) { // tslint:disable-line:no-any
if (column.label !== 'Active') {
this.$titleSet(data.name, 'IDLE');
this.$emit('openWorkflow', data.id);
}
},

View File

@@ -10,12 +10,14 @@ import {
import { nodeHelpers } from '@/components/mixins/nodeHelpers';
import { showMessage } from '@/components/mixins/showMessage';
import { titleChange } from '@/components/mixins/titleChange';
import mixins from 'vue-typed-mixins';
export const pushConnection = mixins(
nodeHelpers,
showMessage,
titleChange,
)
.extend({
data () {
@@ -147,7 +149,6 @@ export const pushConnection = mixins(
*/
pushMessageReceived (event: Event, isRetry?: boolean): boolean {
const retryAttempts = 5;
let receivedData: IPushData;
try {
// @ts-ignore
@@ -201,13 +202,15 @@ export const pushConnection = mixins(
const runDataExecuted = pushData.data;
// @ts-ignore
const workflow = this.getWorkflow();
if (runDataExecuted.finished !== true) {
// There was a problem with executing the workflow
let errorMessage = 'There was a problem executing the workflow!';
if (runDataExecuted.data.resultData.error && runDataExecuted.data.resultData.error.message) {
errorMessage = `There was a problem executing the workflow:<br /><strong>"${runDataExecuted.data.resultData.error.message}"</strong>`;
}
this.$titleSet(workflow.name, 'ERROR');
this.$showMessage({
title: 'Problem executing workflow',
message: errorMessage,
@@ -215,6 +218,7 @@ export const pushConnection = mixins(
});
} else {
// Workflow did execute without a problem
this.$titleSet(workflow.name, 'IDLE');
this.$showMessage({
title: 'Workflow got executed',
message: 'Workflow did get executed successfully!',

View File

@@ -0,0 +1,31 @@
import Vue from 'vue';
import {
WorkflowTitleStatus,
} from '../../Interface';
export const titleChange = Vue.extend({
methods: {
/**
* Change title of n8n tab
*
* @param {string} workflow Name of workflow
* @param {WorkflowTitleStatus} status Status of workflow
*/
$titleSet(workflow: string, status: WorkflowTitleStatus) {
let icon = '⚠️';
if (status === 'EXECUTING') {
icon = '🔄';
} else if (status === 'IDLE') {
icon = '▶️';
}
window.document.title = `n8n - ${icon} ${workflow}`;
},
$titleReset() {
document.title = `n8n - Workflow Automation`;
},
},
});

View File

@@ -14,10 +14,12 @@ import { restApi } from '@/components/mixins/restApi';
import { workflowHelpers } from '@/components/mixins/workflowHelpers';
import mixins from 'vue-typed-mixins';
import { titleChange } from './titleChange';
export const workflowRun = mixins(
restApi,
workflowHelpers,
titleChange,
).extend({
methods: {
// Starts to executes a workflow on server.
@@ -27,6 +29,7 @@ export const workflowRun = mixins(
// because then it can not receive the data as it executes.
throw new Error('No active connection to server. It is maybe down.');
}
const workflow = this.getWorkflow();
this.$store.commit('addActiveAction', 'workflowRunning');
@@ -55,6 +58,7 @@ export const workflowRun = mixins(
}
const workflow = this.getWorkflow();
this.$titleSet(workflow.name as string, 'EXECUTING');
try {
// Check first if the workflow has any issues before execute it
@@ -78,6 +82,7 @@ export const workflowRun = mixins(
type: 'error',
duration: 0,
});
this.$titleSet(workflow.name as string, 'ERROR');
return;
}
}
@@ -165,8 +170,9 @@ export const workflowRun = mixins(
};
this.$store.commit('setWorkflowExecutionData', executionData);
return await this.runWorkflowApi(startRunData);
return await this.runWorkflowApi(startRunData);
} catch (error) {
this.$titleSet(workflow.name as string, 'ERROR');
this.$showError(error, 'Problem running workflow', 'There was a problem running the workflow:');
return undefined;
}

View File

@@ -115,6 +115,8 @@ import { mouseSelect } from '@/components/mixins/mouseSelect';
import { moveNodeWorkflow } from '@/components/mixins/moveNodeWorkflow';
import { restApi } from '@/components/mixins/restApi';
import { showMessage } from '@/components/mixins/showMessage';
import { titleChange } from '@/components/mixins/titleChange';
import { workflowHelpers } from '@/components/mixins/workflowHelpers';
import { workflowRun } from '@/components/mixins/workflowRun';
@@ -165,6 +167,7 @@ export default mixins(
moveNodeWorkflow,
restApi,
showMessage,
titleChange,
workflowHelpers,
workflowRun,
)
@@ -1324,6 +1327,8 @@ export default mixins(
}
if (workflowId !== null) {
const workflow = await this.restApi().getWorkflow(workflowId);
this.$titleSet(workflow.name, 'IDLE');
// Open existing workflow
await this.openWorkflow(workflowId);
} else {