🔀 Merge master

This commit is contained in:
Iván Ovejero
2021-12-06 09:41:15 +01:00
32 changed files with 1345 additions and 286 deletions

View File

@@ -141,7 +141,7 @@
<n8n-icon-button icon="stop" size="small" :title="$baseText('executionsList.stopExecution')" @click.stop="stopExecution(scope.row.id)" :loading="stoppingExecutions.includes(scope.row.id)" />
</span>
<span v-if="scope.row.stoppedAt !== undefined && scope.row.id" >
<n8n-icon-button icon="folder-open" size="small" :title="$baseText('executionsList.openPastExecution')" @click.stop="displayExecution(scope.row)" />
<n8n-icon-button icon="folder-open" size="small" :title="$baseText('executionsList.openPastExecution')" @click.stop="(e) => displayExecution(scope.row, e)" />
</span>
</div>
</template>
@@ -329,7 +329,14 @@ export default mixins(
return false;
},
convertToDisplayDate,
displayExecution (execution: IExecutionShortResponse) {
displayExecution (execution: IExecutionShortResponse, e: PointerEvent) {
if (e.metaKey || e.ctrlKey) {
const route = this.$router.resolve({name: 'ExecutionById', params: {id: execution.id}});
window.open(route.href, '_blank');
return;
}
this.$router.push({
name: 'ExecutionById',
params: { id: execution.id },

View File

@@ -1,5 +1,5 @@
<template>
<div :class="{'node-wrapper': true, selected: isSelected}" :style="nodePosition">
<div class="node-wrapper" :style="nodePosition">
<div class="select-background" v-show="isSelected"></div>
<div :class="{'node-default': true, 'touch-active': isTouchActive, 'is-touch-device': isTouchDevice}" :data-name="data.name" :ref="data.name">
<div :class="nodeClass" :style="nodeStyle" @dblclick="setNodeActive" @click.left="mouseLeftClick" v-touch:start="touchStart" v-touch:end="touchEnd">
@@ -544,8 +544,7 @@ export default mixins(externalHooks, nodeBase, nodeHelpers, renderText, workflow
</style>
<style lang="scss">
/** node */
.node-wrapper.selected {
.jtk-endpoint {
z-index: 2;
}
@@ -576,32 +575,31 @@ export default mixins(externalHooks, nodeBase, nodeHelpers, renderText, workflow
z-index: 4;
}
/** node endpoints */
.jtk-endpoint {
z-index:5;
}
.jtk-connector.jtk-hover {
z-index: 6;
}
.disabled-linethrough {
.jtk-endpoint.plus-endpoint {
z-index: 6;
}
.jtk-endpoint.jtk-hover {
.jtk-endpoint.dot-output-endpoint {
z-index: 7;
}
.jtk-overlay {
z-index:7;
z-index: 7;
}
.disabled-linethrough {
z-index: 8;
}
.jtk-connector.jtk-dragging {
z-index: 8;
}
.jtk-endpoint.jtk-drag-active {
.jtk-drag-active.dot-output-endpoint, .jtk-drag-active.rect-input-endpoint {
z-index: 9;
}
@@ -618,3 +616,87 @@ export default mixins(externalHooks, nodeBase, nodeHelpers, renderText, workflow
}
</style>
<style lang="scss">
$--stalklength: 40px;
$--box-size-medium: 24px;
$--box-size-small: 18px;
.plus-endpoint {
cursor: pointer;
.plus-stalk {
border-top: 2px solid var(--color-foreground-dark);
position: absolute;
width: $--stalklength;
height: 0;
right: 100%;
top: calc(50% - 1px);
pointer-events: none;
.connection-run-items-label {
position: relative;
width: 100%;
span {
display: none;
left: calc(50% + 4px);
}
}
}
.plus-container {
color: var(--color-foreground-xdark);
border: 2px solid var(--color-foreground-xdark);
background-color: var(--color-background-xlight);
border-radius: var(--border-radius-base);
height: $--box-size-medium;
width: $--box-size-medium;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: var(--font-size-2xs);
position: absolute;
top: 0;
right: 0;
pointer-events: none;
&.small {
height: $--box-size-small;
width: $--box-size-small;
font-size: 8px;
}
.fa-plus {
width: 1em;
}
}
.drop-hover-message {
font-weight: var(--font-weight-bold);
font-size: var(--font-size-2xs);
line-height: var(--font-line-height-regular);
color: var(--color-text-light);
position: absolute;
top: -6px;
left: calc(100% + 8px);
width: 200px;
display: none;
}
&.hidden > * {
display: none;
}
&.success .plus-stalk {
border-color: var(--color-success-light);
span {
display: inline;
}
}
}
</style>

View File

@@ -49,28 +49,74 @@
value="0"
/>
<n8n-option
label="1"
label="1. I get stuck too quickly to achieve much"
value="1"
/>
<n8n-option
label="2"
label="2. I can code some useful things, but I spend a lot of time stuck"
value="2"
/>
<n8n-option
label="3"
label="3. I know enough to be dangerous, but I'm no expert"
value="3"
/>
<n8n-option
label="4"
label="4. I can figure most things out"
value="4"
/>
<n8n-option
:label="`5 (${$baseText('personalizationModal.proCoder')})`"
label="5. I can do almost anything I want, easily (pro coder)"
value="5"
/>
</n8n-select>
</n8n-input-label>
<n8n-input-label label="Which areas do you mainly work in?">
<n8n-select :value="values[WORK_AREA_KEY]" multiple placeholder="Select..." @change="(value) => onInput(WORK_AREA_KEY, value)">
<n8n-option :value="FINANCE_WORK_AREA" label="Finance" />
<n8n-option :value="HR_WORK_AREA" label="HR" />
<n8n-option :value="IT_ENGINEERING_WORK_AREA" label="IT / Engineering" />
<n8n-option :value="LEGAL_WORK_AREA" label="Legal" />
<n8n-option :value="MARKETING_WORK_AREA" label="Marketing" />
<n8n-option :value="OPS_WORK_AREA" label="Operations" />
<n8n-option :value="PRODUCT_WORK_AREA" label="Product" />
<n8n-option :value="SALES_BUSINESSDEV_WORK_AREA" label="Sales / Bizdev" />
<n8n-option :value="SECURITY_WORK_AREA" label="Security" />
<n8n-option :value="SUPPORT_WORK_AREA" label="Support" />
<n8n-option :value="EXECUTIVE_WORK_AREA" label="Executive team" />
<n8n-option :value="OTHER_WORK_AREA_OPTION" label="Other (please specify)" />
<n8n-option :value="NOT_APPLICABLE_WORK_AREA" label="I'm not using n8n for work" />
</n8n-select>
</n8n-input-label>
<n8n-input
v-if="otherWorkAreaFieldVisible"
:value="values[OTHER_WORK_AREA_KEY]"
placeholder="Specify your work area"
@input="(value) => onInput(OTHER_WORK_AREA_KEY, value)"
/>
<section v-if="showAllIndustryQuestions">
<n8n-input-label label="Which industries is your company in?">
<n8n-select :value="values[COMPANY_INDUSTRY_KEY]" multiple placeholder="Select..." @change="(value) => onInput(COMPANY_INDUSTRY_KEY, value)">
<n8n-option :value="E_COMMERCE_INDUSTRY" label="eCommerce" />
<n8n-option :value="AUTOMATION_CONSULTING_INDUSTRY" label="Automation consulting" />
<n8n-option :value="SYSTEM_INTEGRATION_INDUSTRY" label="Systems integration" />
<n8n-option :value="GOVERNMENT_INDUSTRY" label="Government" />
<n8n-option :value="LEGAL_INDUSTRY" label="Legal" />
<n8n-option :value="HEALTHCARE_INDUSTRY" label="Healthcare" />
<n8n-option :value="FINANCE_INDUSTRY" label="Finance" />
<n8n-option :value="SECURITY_INDUSTRY" label="Security" />
<n8n-option :value="SAAS_INDUSTRY" label="SaaS" />
<n8n-option :value="OTHER_INDUSTRY_OPTION" label="Other (please specify)" />
</n8n-select>
</n8n-input-label>
<n8n-input
v-if="otherCompanyIndustryFieldVisible"
:value="values[OTHER_COMPANY_INDUSTRY_KEY]"
placeholder="Specify your company's industry"
@input="(value) => onInput(OTHER_COMPANY_INDUSTRY_KEY, value)"
/>
<n8n-input-label :label="$baseText('personalizationModal.howBigIsYourCompany')">
<n8n-select :value="values[COMPANY_SIZE_KEY]" :placeholder="$baseText('personalizationModal.select')" @change="(value) => onInput(COMPANY_SIZE_KEY, value)">
<n8n-option
@@ -99,6 +145,8 @@
/>
</n8n-select>
</n8n-input-label>
</section>
</div>
</template>
<template v-slot:footer>
@@ -114,29 +162,42 @@
import mixins from "vue-typed-mixins";
import {
PERSONALIZATION_MODAL_KEY,
AUTOMATION_CONSULTING_WORK_AREA,
FINANCE_WORK_AREA,
HR_WORK_AREA,
IT_ENGINEERING_WORK_AREA,
LEGAL_WORK_AREA,
MARKETING_WORK_AREA,
PRODUCT_WORK_AREA,
SALES_BUSINESSDEV_WORK_AREA,
SECURITY_WORK_AREA,
SUPPORT_WORK_AREA,
OPS_WORK_AREA,
OTHER_WORK_AREA_OPTION,
AUTOMATION_CONSULTING_INDUSTRY,
CODING_SKILL_KEY,
COMPANY_INDUSTRY_KEY,
COMPANY_SIZE_100_499,
COMPANY_SIZE_1000_OR_MORE,
COMPANY_SIZE_20_OR_LESS,
COMPANY_SIZE_20_99,
COMPANY_SIZE_100_499,
COMPANY_SIZE_500_999,
COMPANY_SIZE_1000_OR_MORE,
COMPANY_SIZE_PERSONAL_USE,
WORK_AREA_KEY,
COMPANY_SIZE_KEY,
CODING_SKILL_KEY,
COMPANY_SIZE_PERSONAL_USE,
E_COMMERCE_INDUSTRY,
EXECUTIVE_WORK_AREA,
FINANCE_INDUSTRY,
FINANCE_WORK_AREA,
GOVERNMENT_INDUSTRY,
HEALTHCARE_INDUSTRY,
HR_WORK_AREA,
IT_ENGINEERING_WORK_AREA,
LEGAL_INDUSTRY,
LEGAL_WORK_AREA,
MARKETING_WORK_AREA,
NOT_APPLICABLE_WORK_AREA,
OPS_WORK_AREA,
OTHER_COMPANY_INDUSTRY_KEY,
OTHER_INDUSTRY_OPTION,
OTHER_WORK_AREA_KEY,
OTHER_WORK_AREA_OPTION,
PERSONALIZATION_MODAL_KEY,
PRODUCT_WORK_AREA,
SAAS_INDUSTRY,
SALES_BUSINESSDEV_WORK_AREA,
SECURITY_INDUSTRY,
SECURITY_WORK_AREA,
SUPPORT_WORK_AREA,
SYSTEM_INTEGRATION_INDUSTRY,
WORK_AREA_KEY,
} from "../constants";
import { workflowHelpers } from "@/components/mixins/workflowHelpers";
import { showMessage } from "@/components/mixins/showMessage";
@@ -155,14 +216,17 @@ export default mixins(showMessage, renderText, workflowHelpers).extend({
isSaving: false,
PERSONALIZATION_MODAL_KEY,
otherWorkAreaFieldVisible: false,
otherCompanyIndustryFieldVisible: false,
showAllIndustryQuestions: true,
modalBus: new Vue(),
values: {
[WORK_AREA_KEY]: null,
[COMPANY_SIZE_KEY]: null,
[CODING_SKILL_KEY]: null,
[OTHER_WORK_AREA_KEY]: null,
[COMPANY_INDUSTRY_KEY]: null,
[OTHER_COMPANY_INDUSTRY_KEY]: null,
} as IPersonalizationSurveyAnswers,
AUTOMATION_CONSULTING_WORK_AREA,
FINANCE_WORK_AREA,
HR_WORK_AREA,
IT_ENGINEERING_WORK_AREA,
@@ -171,19 +235,33 @@ export default mixins(showMessage, renderText, workflowHelpers).extend({
PRODUCT_WORK_AREA,
SALES_BUSINESSDEV_WORK_AREA,
SECURITY_WORK_AREA,
EXECUTIVE_WORK_AREA,
SUPPORT_WORK_AREA,
OPS_WORK_AREA,
OTHER_WORK_AREA_OPTION,
NOT_APPLICABLE_WORK_AREA,
COMPANY_SIZE_20_OR_LESS,
COMPANY_SIZE_20_99,
COMPANY_SIZE_100_499,
COMPANY_SIZE_500_999,
COMPANY_SIZE_1000_OR_MORE,
COMPANY_SIZE_PERSONAL_USE,
E_COMMERCE_INDUSTRY,
AUTOMATION_CONSULTING_INDUSTRY,
SYSTEM_INTEGRATION_INDUSTRY,
GOVERNMENT_INDUSTRY,
LEGAL_INDUSTRY,
HEALTHCARE_INDUSTRY,
FINANCE_INDUSTRY,
SECURITY_INDUSTRY,
SAAS_INDUSTRY,
OTHER_INDUSTRY_OPTION,
WORK_AREA_KEY,
COMPANY_SIZE_KEY,
CODING_SKILL_KEY,
COMPANY_INDUSTRY_KEY,
OTHER_WORK_AREA_KEY,
OTHER_COMPANY_INDUSTRY_KEY,
};
},
computed: {
@@ -196,14 +274,26 @@ export default mixins(showMessage, renderText, workflowHelpers).extend({
this.modalBus.$emit('close');
},
onInput(name: IPersonalizationSurveyKeys, value: string) {
if (name === WORK_AREA_KEY && value === OTHER_WORK_AREA_OPTION) {
if (name === WORK_AREA_KEY && value.includes(OTHER_WORK_AREA_OPTION)) {
this.otherWorkAreaFieldVisible = true;
}
else if (name === WORK_AREA_KEY && value.includes(NOT_APPLICABLE_WORK_AREA)) {
this.showAllIndustryQuestions = false;
}
else if (name === WORK_AREA_KEY) {
this.otherWorkAreaFieldVisible = false;
this.showAllIndustryQuestions = true;
this.values[OTHER_WORK_AREA_KEY] = null;
}
if (name === COMPANY_INDUSTRY_KEY && value.includes(OTHER_INDUSTRY_OPTION)) {
this.otherCompanyIndustryFieldVisible = true;
}
else if (name === COMPANY_INDUSTRY_KEY) {
this.otherCompanyIndustryFieldVisible = false;
this.values[OTHER_COMPANY_INDUSTRY_KEY] = null;
}
this.values[name] = value;
},
async save(): Promise<void> {
@@ -229,7 +319,7 @@ export default mixins(showMessage, renderText, workflowHelpers).extend({
<style lang="scss" module>
.container {
> div:not(:last-child) {
> div, section > div:not(:last-child) {
margin-bottom: var(--spacing-m);
}
}
@@ -247,4 +337,5 @@ export default mixins(showMessage, renderText, workflowHelpers).extend({
height: 140px;
}
</style>

View File

@@ -136,11 +136,18 @@ export default mixins(
this.filterTagIds.push(tagId);
}
},
async openWorkflow (data: IWorkflowShortResponse, column: any) { // tslint:disable-line:no-any
async openWorkflow (data: IWorkflowShortResponse, column: any, cell: any, e: PointerEvent) { // tslint:disable-line:no-any
if (column.label !== 'Active') {
const currentWorkflowId = this.$store.getters.workflowId;
if (e.metaKey || e.ctrlKey) {
const route = this.$router.resolve({name: 'NodeViewExisting', params: {name: data.id}});
window.open(route.href, '_blank');
return;
}
if (data.id === currentWorkflowId) {
this.$showMessage({
title: this.$baseText('workflowOpen.showMessage.title'),

View File

@@ -11,6 +11,7 @@ import { Endpoint } from 'jsplumb';
import {
INodeTypeDescription,
} from 'n8n-workflow';
import { getStyleTokenValue } from '../helpers';
export const nodeBase = mixins(
deviceSupportHelpers,
@@ -68,13 +69,14 @@ export const nodeBase = mixins(
endpointStyle: CanvasHelpers.getInputEndpointStyle(nodeTypeData, '--color-foreground-xdark'),
endpointHoverStyle: CanvasHelpers.getInputEndpointStyle(nodeTypeData, '--color-primary'),
isSource: false,
isTarget: !this.isReadOnly,
isTarget: !this.isReadOnly && nodeTypeData.inputs.length > 1, // only enabled for nodes with multiple inputs.. otherwise attachment handled by connectionDrag event in NodeView,
parameters: {
nodeIndex: this.nodeIndex,
type: inputName,
index,
},
enabled: !this.isReadOnly && nodeTypeData.inputs.length > 1, // only enabled for nodes with multiple inputs.. otherwise attachment handled by connectionDrag event in NodeView
enabled: !this.isReadOnly, // enabled in default case to allow dragging
cssClass: 'rect-input-endpoint',
dragAllowedWhenFull: true,
dropOptions: {
tolerance: 'touch',
@@ -92,7 +94,9 @@ export const nodeBase = mixins(
const endpoint: Endpoint = this.instance.addEndpoint(this.nodeId, newEndpointData);
endpoint.__meta = {
nodeName: node.name,
nodeId: this.nodeId,
index: i,
totalEndpoints: nodeTypeData.inputs.length,
};
// TODO: Activate again if it makes sense. Currently makes problems when removing
@@ -140,6 +144,7 @@ export const nodeBase = mixins(
type: inputName,
index,
},
cssClass: 'dot-output-endpoint',
dragAllowedWhenFull: false,
dragProxy: ['Rectangle', { width: 1, height: 1, strokeWidth: 0 }],
};
@@ -151,11 +156,53 @@ export const nodeBase = mixins(
];
}
const endpoint: Endpoint = this.instance.addEndpoint(this.nodeId, newEndpointData);
const endpoint: Endpoint = this.instance.addEndpoint(this.nodeId, {...newEndpointData});
endpoint.__meta = {
nodeName: node.name,
nodeId: this.nodeId,
index: i,
totalEndpoints: nodeTypeData.outputs.length,
};
if (!this.isReadOnly) {
const plusEndpointData: IEndpointOptions = {
uuid: CanvasHelpers.getOutputEndpointUUID(this.nodeIndex, index),
anchor: anchorPosition,
maxConnections: -1,
endpoint: 'N8nPlus',
isSource: true,
isTarget: false,
enabled: !this.isReadOnly,
endpointStyle: {
fill: getStyleTokenValue('--color-xdark'),
outlineStroke: 'none',
hover: false,
showOutputLabel: nodeTypeData.outputs.length === 1,
size: nodeTypeData.outputs.length >= 3 ? 'small' : 'medium',
},
endpointHoverStyle: {
fill: getStyleTokenValue('--color-primary'),
outlineStroke: 'none',
hover: true, // hack to distinguish hover state
},
parameters: {
nodeIndex: this.nodeIndex,
type: inputName,
index,
},
cssClass: 'plus-draggable-endpoint',
dragAllowedWhenFull: false,
dragProxy: ['Rectangle', { width: 1, height: 1, strokeWidth: 0 }],
};
const plusEndpoint: Endpoint = this.instance.addEndpoint(this.nodeId, plusEndpointData);
plusEndpoint.__meta = {
nodeName: node.name,
nodeId: this.nodeId,
index: i,
totalEndpoints: nodeTypeData.outputs.length,
};
}
});
},
__makeInstanceDraggable(node: INodeUi) {

View File

@@ -165,7 +165,7 @@ export const pushConnection = mixins(
if (receivedData.type === 'sendConsoleMessage') {
const pushData = receivedData.data;
console.log(pushData.source, pushData.message); // eslint-disable-line no-console
console.log(pushData.source, ...pushData.messages); // eslint-disable-line no-console
return true;
}