Implement design system (#2050)

* split up main, sass imports, import new nds

* migrate most buttons

* update sizes based on feedback

* update copy buttons

* update executions list

* fix issues

* force message box buttons

* update warning color

* update more buttons

* wrap message box buttons

* update last component

* lint fixes

* add build report step

* breakout imports

* set package.json

* fix notification bug

* clean up imports

* use build directories directly

* update imports

* remove xl size

* update number inputs

* fix input width

* update line height, fix icon bug

* fix up editor

* fix spacing between buttons

* Reset line height

* revert changes to this

* revert changes

* clean up button sizes

* change to outline

* update select height

* update tooltip

* remove build report step

* clean up impl

* remove regenerator runtime

* add design system repo

* apply editorconfig

* apply editor config prettier

* lint issue

* switch to tabs

* switch to single space

* update eslintrc

* remove git modules

* update sass package

* support dart sass

* add build

* update dependency

* update contributing.md

* set repo

* update versions

* add tslint step

* update spacing to spaces, add dev step

* add test step

* add test step

* update browser lint rc

* remove .github

* delete .gitignore

* set comment for icons

* remove preview link

* update button interface

* update types

* set types

* clean up intro

* update intro

* remove assets

* move into preview

* remove headline comment

* reduce theme build

* loading executions

* match deps versions

* match deps versions

* fix lint issues

* fix lint issues

* update callback

* disable codacy for docs.css

* fix storybook issues

* add design system to docker image

* update spacing around delete sort button

* set line height to stop juggling headline

* update sizes

* clean up vars

* fix scss issues

* update button vars

* add shade color

* fix button without click

* fix buttons bug

* fix bug with executions list

* clean up theme

* update link styling

* fix typo

* run prettier

* 🎨 code format

* 🎨 code format

* 🔥 remove empty files

*  N8n 2284 new inputs (#2075)

* implement inputs

* prettier fixes

* revert unnessary change

* move input components and tooltip

* remove form elements

* move select

* update input placements

* update sizes

* update credentails

* clean up select size

* fix caret issue

* update inputs

* clean up select

* fix tags dropdown border

* clean up tags input

* fix workflow name bug

* clean up select here

* add sizes template

* fix option caret

* fix input sizes

* update date input size

* remove tags input override

* update prop

* update input size

* center run data inputs

* update disabled colors

* update execution header

* update scrollbar

* update text area spacing

* fix items in header

* update run data tooltip

* remove popover

* update prefix positions

* add filterable demo

* address design issues

* fix input issues, flip boolean input to text

* update input sufffix colors

* remove override

* speed up switch, fix toggle spacing issue

* update icon

* remove icon classes

* clean up inputs

* clean up inputs with icons

* update input spacing again

* update suffix position

* build

* Add support for xlarge inputs

* fix input issues

* fix input issue

* update listeners

* update number inputs for settings

* update append/prepend spacing

* clean up inputs, set expression input as text

* fix type errors

* fix workflow number input

* fix tags dropdown bug

* fix bugs

* fix menu item bug

* remove font weight from link element

* remove default

* fix select option

* fix contrast issues

* allow overflow x for multi selects

* fix icon

* update options select

* fix issue that resolves expression to null

* update how actions are centered

* fix up selects

* update selects to support limiting size

* update option styles

*  Apply suggestions BHesseldieck

Co-authored-by: Ben Hesseldieck <1849459+BHesseldieck@users.noreply.github.com>

* 🎨 code format

Co-authored-by: Jan <janober@users.noreply.github.com>
Co-authored-by: Ben Hesseldieck <1849459+BHesseldieck@users.noreply.github.com>
Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com>

*  Revert "🔥 remove empty files"

This reverts commit e91ace4e52403f4a6b00b7be68b86fc48b7d8fef.

*  Remove private from n8n-design-system package

* 🎨 Change to spaces to stay consistent with editorconfig & others
package files

*  Fix year in license

Co-authored-by: Ben Hesseldieck <1849459+BHesseldieck@users.noreply.github.com>
Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com>
Co-authored-by: Jan <janober@users.noreply.github.com>
Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
This commit is contained in:
Mutasem Aldmour
2021-08-29 13:36:17 +02:00
committed by GitHub
parent 8dd0d547a2
commit 5bd8f7c93e
240 changed files with 22656 additions and 1214 deletions

View File

@@ -28,9 +28,7 @@
</el-row>
<div class="action-buttons">
<el-button type="success" @click="closeDialog">
Close
</el-button>
<n8n-button @click="closeDialog" label="Close" />
</div>
</div>
</el-dialog>

View File

@@ -1,14 +1,13 @@
<template>
<div v-if="windowVisible" class="binary-data-window">
<el-button
<n8n-button
@click.stop="closeWindow"
size="small"
class="binary-data-window-back"
title="Back to overview page"
icon="el-icon-arrow-left"
>
Back to list
</el-button>
icon="arrow-left"
label="Back to list"
/>
<div class="binary-data-window-wrapper">
<div v-if="!binaryData">
@@ -103,6 +102,7 @@ export default mixins(
text-align: center;
.binary-data-window-wrapper {
margin-top: .5em;
padding: 0 1em;
height: calc(100% - 50px);
@@ -112,10 +112,6 @@ export default mixins(
}
}
.binary-data-window-back {
margin: 0 0 0.5em 0;
}
.binary-data {
background-color: #fff;

View File

@@ -7,16 +7,23 @@
<parameter-input-list :parameters="getProperties" :nodeValues="nodeValues" :path="path" :hideDelete="hideDelete" @valueChanged="valueChanged" />
<div v-if="parameterOptions.length > 0 && !isReadOnly">
<el-button v-if="parameter.options.length === 1" size="small" class="add-option" @click="optionSelected(parameter.options[0].name)">{{ getPlaceholderText }}</el-button>
<el-select v-else v-model="selectedOption" :placeholder="getPlaceholderText" size="small" class="add-option" @change="optionSelected" filterable>
<el-option
v-for="item in parameterOptions"
:key="item.name"
:label="item.displayName"
:value="item.name">
</el-option>
</el-select>
<div v-if="parameterOptions.length > 0 && !isReadOnly" class="param-options">
<n8n-button
v-if="parameter.options.length === 1"
fullWidth
@click="optionSelected(parameter.options[0].name)"
:label="getPlaceholderText"
/>
<div v-else class="add-option">
<n8n-select v-model="selectedOption" :placeholder="getPlaceholderText" size="small" @change="optionSelected" filterable>
<n8n-option
v-for="item in parameterOptions"
:key="item.name"
:label="item.displayName"
:value="item.name">
</n8n-option>
</n8n-select>
</div>
</div>
</div>
@@ -177,11 +184,10 @@ export default mixins(
<style lang="scss">
.collection-parameter {
padding: 0em 0 0em 2em;
padding-left: 2em;
.add-option {
margin-top: 0.5em;
width: 100%;
.param-options {
padding-top: 0.5em;
}
.no-items-exist {

View File

@@ -30,14 +30,14 @@
Credential type:
</el-col>
<el-col :span="18">
<el-select v-model="credentialType" filterable placeholder="Select Type" size="small" ref="credentialsDropdown">
<el-option
<n8n-select v-model="credentialType" filterable placeholder="Select Type" size="medium" ref="credentialsDropdown">
<n8n-option
v-for="item in credentialTypes"
:key="item.name"
:label="item.displayName"
:value="item.name">
</el-option>
</el-select>
</n8n-option>
</n8n-select>
</el-col>
</el-row>
</div>
@@ -307,7 +307,12 @@ export default mixins(
<style lang="scss">
.credentials-edit-wrapper {
.credential-type-item {
padding-bottom: 1em;
> .el-row {
display: flex;
align-items: center;
}
padding-bottom: 8px;
}
@media (min-width: 1200px){

View File

@@ -1,36 +1,36 @@
<template>
<div @keydown.stop class="credentials-input-wrapper">
<el-row>
<el-row class="credential-name-wrapper">
<el-col :span="6" class="headline-regular">
Credentials Name:
<el-tooltip class="credentials-info" placement="top" effect="light">
<n8n-tooltip class="credentials-info" placement="top" >
<div slot="content" v-html="helpTexts.credentialsName"></div>
<font-awesome-icon icon="question-circle" />
</el-tooltip>
</n8n-tooltip>
</el-col>
<el-col :span="18">
<el-input size="small" type="text" v-model="name"></el-input>
<n8n-input v-model="name" type="text" size="medium"></n8n-input>
</el-col>
</el-row>
<br />
<div class="headline" v-if="credentialProperties.length">
Credential Data:
<el-tooltip class="credentials-info" placement="top" effect="light">
<n8n-tooltip class="credentials-info" placement="top" >
<div slot="content" v-html="helpTexts.credentialsData"></div>
<font-awesome-icon icon="question-circle" />
</el-tooltip>
</n8n-tooltip>
</div>
<div v-for="parameter in credentialProperties" :key="parameter.name">
<el-row class="parameter-wrapper">
<el-col :span="6" class="parameter-name">
{{parameter.displayName}}:
<el-tooltip placement="top" class="parameter-info" v-if="parameter.description" effect="light">
<div slot="content" v-html="addTargetBlank(parameter.description)"></div>
<n8n-tooltip placement="top" class="parameter-info" v-if="parameter.description" >
<div slot="content" v-html="parameter.description"></div>
<font-awesome-icon icon="question-circle"/>
</el-tooltip>
</n8n-tooltip>
</el-col>
<el-col :span="18">
<parameter-input :parameter="parameter" :value="propertyValue[parameter.name]" :path="parameter.name" :isCredential="true" :displayOptions="true" @valueChanged="valueChanged" />
<parameter-input :parameter="parameter" :value="propertyValue[parameter.name]" :path="parameter.name" :isCredential="true" :displayOptions="true" @valueChanged="valueChanged" inputSize="medium" />
</el-col>
</el-row>
</div>
@@ -41,15 +41,11 @@
</el-col>
<el-col :span="18">
<span v-if="requiredPropertiesFilled === false">
<el-button title="Connect OAuth Credentials" circle :disabled="true">
<font-awesome-icon icon="redo" />
</el-button>
<n8n-icon-button title="Connect OAuth Credentials" icon="redo" :disabled="true" size="large" />
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>
<n8n-icon-button title="Reconnect OAuth Credentials" @click.stop="oAuthCredentialAuthorize()" icon="redo" size="large" />
Connected
</span>
<span v-else>
@@ -57,9 +53,7 @@
<img :src="basePath + 'google-signin.png'" class="google-icon clickable" alt="Sign in with Google" @click.stop="oAuthCredentialAuthorize()" />
</span>
<span v-else>
<el-button title="Connect OAuth Credentials" @click.stop="oAuthCredentialAuthorize()" circle>
<font-awesome-icon icon="sign-in-alt" />
</el-button>
<n8n-icon-button title="Connect OAuth Credentials" @click.stop="oAuthCredentialAuthorize()" icon="sign-in-alt" size="large" />
Not connected
</span>
</span>
@@ -69,11 +63,11 @@
<font-awesome-icon icon="angle-up" class="minimize-button minimize-icon" />
OAuth Callback URL
</div>
<el-tooltip v-if="!isMinimized" class="item" effect="light" content="Click to copy Callback URL" placement="right">
<n8n-tooltip v-if="!isMinimized" class="item" content="Click to copy Callback URL" placement="right">
<div class="callback-url left-ellipsis clickable" @click="copyCallbackUrl">
{{oAuthCallbackUrl}}
</div>
</el-tooltip>
</n8n-tooltip>
</div>
</el-col>
@@ -82,10 +76,10 @@
<el-row class="nodes-access-wrapper">
<el-col :span="6" class="headline">
Nodes with access:
<el-tooltip class="credentials-info" placement="top" effect="light">
<n8n-tooltip class="credentials-info" placement="top" >
<div slot="content" v-html="helpTexts.nodesWithAccess"></div>
<font-awesome-icon icon="question-circle" />
</el-tooltip>
</n8n-tooltip>
</el-col>
<el-col :span="18">
<el-transfer
@@ -104,12 +98,8 @@
</el-row>
<div class="action-buttons">
<el-button type="success" @click="updateCredentials(true)" v-if="credentialDataDynamic">
Save
</el-button>
<el-button type="success" @click="createCredentials(true)" v-else>
Create
</el-button>
<n8n-button type="success" @click="updateCredentials(true)" label="Save" size="large" v-if="credentialDataDynamic" />
<n8n-button @click="createCredentials(true)" label="Create" size="large" v-else />
</div>
</div>
@@ -527,6 +517,11 @@ export default mixins(
<style lang="scss">
.credentials-input-wrapper {
.credential-name-wrapper {
display: flex;
align-items: center;
}
.action-buttons {
margin-top: 2em;
text-align: right;
@@ -536,6 +531,11 @@ export default mixins(
font-weight: 600;
color: $--color-primary;
margin-bottom: 1em;
line-height: 1.5;
}
.headline-regular {
line-height: 1.5;
}
.nodes-access-wrapper {
@@ -558,7 +558,9 @@ export default mixins(
}
.parameter-wrapper {
line-height: 3em;
display: flex;
align-items: center;
margin: 8px 0;
.parameter-name {
position: relative;

View File

@@ -7,12 +7,15 @@
Your saved credentials:
</div>
<el-button title="Create New Credentials" class="new-credentials-button" @click="createCredential()">
<font-awesome-icon icon="plus" />
<div class="next-icon-text">
Add New
</div>
</el-button>
<div class="new-credentials-button">
<n8n-button
title="Create New Credentials"
icon="plus"
label="Add New"
size="large"
@click="createCredential()"
/>
</div>
<el-table :data="credentials" :default-sort = "{prop: 'name', order: 'ascending'}" stripe @row-click="editCredential" max-height="450" v-loading="isDataLoading">
<el-table-column property="name" label="Name" class-name="clickable" sortable></el-table-column>
@@ -27,8 +30,10 @@
label="Operations"
width="120">
<template slot-scope="scope">
<el-button title="Edit Credentials" @click.stop="editCredential(scope.row)" icon="el-icon-edit" circle></el-button>
<el-button title="Delete Credentials" @click.stop="deleteCredential(scope.row)" type="danger" icon="el-icon-delete" circle></el-button>
<div class="cred-operations">
<n8n-icon-button title="Edit Credentials" @click.stop="editCredential(scope.row)" icon="pen" />
<n8n-icon-button title="Delete Credentials" @click.stop="deleteCredential(scope.row)" icon="trash" />
</div>
</template>
</el-table-column>
</el-table>
@@ -173,7 +178,7 @@ export default mixins(
});
</script>
<style lang="scss">
<style lang="scss" scoped>
.new-credentials-button {
float: right;
@@ -181,4 +186,10 @@ export default mixins(
top: -15px;
}
.cred-operations {
> * {
margin-left: 10px;
}
}
</style>

View File

@@ -8,7 +8,7 @@
>
<template v-slot:content>
<el-row>
<el-input
<n8n-input
v-model="name"
ref="nameInput"
placeholder="Enter workflow name"
@@ -29,8 +29,10 @@
</el-row>
</template>
<template v-slot:footer="{ close }">
<el-button size="small" @click="save" :loading="isSaving">Save</el-button>
<el-button size="small" @click="close" :disabled="isSaving">Cancel</el-button>
<div :class="$style.footer">
<n8n-button @click="save" :loading="isSaving" label="Save" float="right" />
<n8n-button type="outline" @click="close" :disabled="isSaving" label="Cancel" float="right" />
</div>
</template>
</Modal>
</template>
@@ -123,3 +125,11 @@ export default mixins(showMessage, workflowHelpers).extend({
},
});
</script>
<style lang="scss" module>
.footer {
> * {
margin-left: var(--spacing-3xs);
}
}
</style>

View File

@@ -37,9 +37,9 @@
<span class="box-card__subtitle">Data below may contain sensitive information. Proceed with caution when sharing.</span>
</div>
<div>
<el-button v-if="displayCause" class="copy-button" @click="copyCause" circle type="text" title="Copy to clipboard">
<font-awesome-icon icon="copy" />
</el-button>
<div class="copy-button" v-if="displayCause">
<n8n-icon-button @click="copyCause" title="Copy to Clipboard" icon="copy" />
</div>
<vue-json-pretty
v-if="displayCause"
:data="error.cause"
@@ -179,7 +179,6 @@ details[open] {
.copy-button {
position: absolute;
font-size: 1.1rem;
right: 50px;
z-index: 1000;
}

View File

@@ -3,34 +3,30 @@
<el-dialog :visible="dialogVisible" append-to-body width="80%" :title="`Workflow Executions ${combinedExecutions.length}/${finishedExecutionsCountEstimated === true ? '~' : ''}${combinedExecutionsCount}`" :before-close="closeDialog">
<div class="filters">
<el-row>
<el-col :span="4" class="filter-headline">
<el-col :span="2" class="filter-headline">
Filters:
</el-col>
<el-col :span="6">
<el-select v-model="filter.workflowId" placeholder="Select Workflow" size="small" filterable @change="handleFilterChanged">
<el-option
<el-col :span="7">
<n8n-select v-model="filter.workflowId" placeholder="Select Workflow" size="medium" filterable @change="handleFilterChanged">
<n8n-option
v-for="item in workflows"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</n8n-option>
</n8n-select>
</el-col>
<el-col :span="2">&nbsp;
</el-col>
<el-col :span="4">
<el-select v-model="filter.status" placeholder="Select Status" size="small" filterable @change="handleFilterChanged">
<el-option
<el-col :span="5" :offset="1">
<n8n-select v-model="filter.status" placeholder="Select Status" size="medium" filterable @change="handleFilterChanged">
<n8n-option
v-for="item in statuses"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</n8n-option>
</n8n-select>
</el-col>
<el-col :span="4">&nbsp;
</el-col>
<el-col :span="4" class="autorefresh">
<el-col :span="4" :offset="5" class="autorefresh">
<el-checkbox v-model="autoRefresh" @change="handleAutoRefreshToggle">Auto refresh</el-checkbox>
</el-col>
</el-row>
@@ -39,7 +35,7 @@
<div class="selection-options">
<span v-if="checkAll === true || isIndeterminate === true">
Selected: {{numSelected}} / <span v-if="finishedExecutionsCountEstimated === true">~</span>{{finishedExecutionsCount}}
<el-button type="danger" title="Delete Selected" icon="el-icon-delete" size="mini" @click="handleDeleteSelected" circle></el-button>
<n8n-icon-button title="Delete Selected" icon="trash" size="small" @click="handleDeleteSelected" />
</span>
</div>
@@ -76,10 +72,10 @@
</span>
</template>
</el-table-column>
<el-table-column label="Status" width="120" align="center">
<el-table-column label="Status" width="122" align="center">
<template slot-scope="scope" align="center">
<el-tooltip placement="top" effect="light">
<n8n-tooltip placement="top" >
<div slot="content" v-html="statusTooltipText(scope.row)"></div>
<span class="status-badge running" v-if="scope.row.waitTill">
@@ -97,13 +93,18 @@
<span class="status-badge warning" v-else>
Unknown
</span>
</el-tooltip>
</n8n-tooltip>
<el-dropdown trigger="click" @command="handleRetryClick">
<span class="el-dropdown-link">
<el-button class="retry-button" v-bind:class="{ warning: scope.row.stoppedAt === null }" circle v-if="scope.row.stoppedAt !== undefined && !scope.row.finished && scope.row.retryOf === undefined && scope.row.retrySuccessId === undefined && scope.row.waitTill === undefined" type="text" size="small" title="Retry execution">
<font-awesome-icon icon="redo" />
</el-button>
<span class="retry-button">
<n8n-icon-button
v-if="scope.row.stoppedAt !== undefined && !scope.row.finished && scope.row.retryOf === undefined && scope.row.retrySuccessId === undefined && !scope.row.waitTill"
type="light"
:theme="scope.row.stoppedAt === null ? 'warning': 'danger'"
size="small"
title="Retry execution"
icon="redo"
/>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :command="{command: 'currentlySaved', row: scope.row}">Retry with currently saved workflow</el-dropdown-item>
@@ -131,24 +132,20 @@
</el-table-column>
<el-table-column label="" width="100" align="center">
<template slot-scope="scope">
<span v-if="scope.row.stoppedAt === undefined || scope.row.waitTill" class="execution-actions">
<el-button circle title="Stop Execution" @click.stop="stopExecution(scope.row.id)" :loading="stoppingExecutions.includes(scope.row.id)" size="mini">
<font-awesome-icon icon="stop" />
</el-button>
</span>
<span v-if="scope.row.stoppedAt !== undefined && scope.row.id" class="execution-actions">
<el-button circle title="Open Past Execution" @click.stop="displayExecution(scope.row)" size="mini">
<font-awesome-icon icon="folder-open" />
</el-button>
</span>
<div class="actions-container">
<span v-if="scope.row.stoppedAt === undefined || scope.row.waitTill">
<n8n-icon-button icon="stop" title="Stop Execution" @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" title="Open Past Execution" @click.stop="displayExecution(scope.row)" />
</span>
</div>
</template>
</el-table-column>
</el-table>
<div class="load-more" v-if="finishedExecutionsCount > finishedExecutions.length || finishedExecutionsCountEstimated === true">
<el-button title="Load More" @click="loadMore()" size="small" :disabled="isDataLoading">
<font-awesome-icon icon="sync" /> Load More
</el-button>
<n8n-button icon="sync" title="Load More" label="Load More" @click="loadMore()" :loading="isDataLoading" />
</div>
</el-dialog>
@@ -697,13 +694,7 @@ export default mixins(
}
.retry-button {
color: $--custom-error-text;
background-color: $--custom-error-background;
margin-left: 5px;
&.warning {
background-color: $--custom-warning-background;
color: $--custom-warning-text;
}
}
.selection-options {
@@ -714,30 +705,26 @@ export default mixins(
position: relative;
display: inline-block;
padding: 0 10px;
height: 30px;
line-height: 30px;
height: 22.6px;
line-height: 22.6px;
border-radius: 15px;
text-align: center;
font-weight: 400;
font-size: 12px;
&.error {
background-color: $--custom-error-background;
color: $--custom-error-text;
}
&.running {
background-color: $--custom-running-background;
color: $--custom-running-text;
background-color: var(--color-danger-tint-1);
color: var(--color-danger);
}
&.success {
background-color: $--custom-success-background;
color: $--custom-success-text;
background-color: var(--color-success-tint-1);
color: var(--color-success);
}
&.warning {
background-color: $--custom-warning-background;
color: $--custom-warning-text;
&.running, &.warning {
background-color: var(--color-warning-tint-2);
color: var(--color-warning);
}
}
@@ -745,6 +732,10 @@ export default mixins(
font-weight: bold;
}
.actions-container > * {
margin-left: 5px;
}
</style>
<style lang="scss">

View File

@@ -28,11 +28,6 @@ export default Vue.extend({
<style lang="scss" scoped>
$--horiz-padding: 15px;
*,
*::after {
box-sizing: border-box;
}
input {
border: 1px solid transparent;
padding: 0 $--horiz-padding - 2px; // -2px for borders
@@ -62,7 +57,7 @@ div.el-input {
}
&:hover {
input {
input:not(:focus) {
border: $--custom-input-border-shadow
}
}

View File

@@ -58,9 +58,3 @@ export default Vue.extend({
},
});
</script>
<style lang="scss" scoped>
.el-input input.el-input__inner {
border: 1px solid $--color-primary !important;
}
</style>

View File

@@ -117,6 +117,7 @@ export default mixins(
<style scoped lang="scss">
.editor-description {
line-height: 1.5;
font-weight: bold;
padding: 0 0 0.5em 0.2em;;
}
@@ -158,12 +159,14 @@ export default mixins(
.headline {
font-size: 1.35em;
font-weight: 600;
line-height: 1.5;
}
.sub-headline {
font-weight: 600;
font-size: 1.1em;
text-align: center;
line-height: 1.5;
padding-top: 1.5em;
color: $--color-primary;
}

View File

@@ -12,7 +12,7 @@
<div class="parameter-item-wrapper">
<div class="delete-option" v-if="!isReadOnly">
<font-awesome-icon icon="trash" class="reset-icon clickable" title="Delete Item" @click="deleteOption(property.name, index)" />
<div v-if="sortable">
<div v-if="sortable" class="sort-icon">
<font-awesome-icon v-if="index !== 0" icon="angle-up" class="clickable" title="Move up" @click="moveOptionUp(property.name, index)" />
<font-awesome-icon v-if="index !== (values[property.name].length -1)" icon="angle-down" class="clickable" title="Move down" @click="moveOptionDown(property.name, index)" />
</div>
@@ -32,15 +32,17 @@
</div>
<div v-if="parameterOptions.length > 0 && !isReadOnly">
<el-button v-if="parameter.options.length === 1" size="small" class="add-option" @click="optionSelected(parameter.options[0].name)">{{ getPlaceholderText }}</el-button>
<el-select v-else v-model="selectedOption" :placeholder="getPlaceholderText" size="small" class="add-option" @change="optionSelected" filterable>
<el-option
v-for="item in parameterOptions"
:key="item.name"
:label="item.displayName"
:value="item.name">
</el-option>
</el-select>
<n8n-button v-if="parameter.options.length === 1" fullWidth @click="optionSelected(parameter.options[0].name)" :label="getPlaceholderText" />
<div v-else class="add-option">
<n8n-select v-model="selectedOption" :placeholder="getPlaceholderText" size="small" @change="optionSelected" filterable>
<n8n-option
v-for="item in parameterOptions"
:key="item.name"
:label="item.displayName"
:value="item.name">
</n8n-option>
</n8n-select>
</div>
</div>
</div>
@@ -217,10 +219,6 @@ export default mixins(genericHelpers)
<style scoped lang="scss">
.add-option {
width: 100%;
}
.fixed-collection-parameter {
padding: 0 0 0 1em;
}
@@ -240,7 +238,7 @@ export default mixins(genericHelpers)
z-index: 999;
color: #f56c6c;
left: 0;
top: 0;
top: .5em;
width: 15px;
height: 100%;
}
@@ -265,4 +263,8 @@ export default mixins(genericHelpers)
.no-items-exist {
margin: 0.8em 0;
}
.sort-icon {
margin-top: .5em;
}
</style>

View File

@@ -97,10 +97,10 @@ export default mixins(titleChange).extend({
.execution-icon {
&.success {
color: $--custom-success-text-light;
color: var(--color-success);
}
&.warning {
color: $--custom-running-text;
color: var(--color-warning);
}
}

View File

@@ -1,5 +1,5 @@
<template>
<el-tooltip class="primary-color" placement="bottom-end" effect="light">
<n8n-tooltip class="primary-color" placement="bottom-end" >
<div slot="content">
You're viewing the log of a previous execution. You cannot<br />
make changes since this execution already occured. Make changes<br />
@@ -9,5 +9,5 @@
<font-awesome-icon icon="exclamation-triangle" />
Read only
</span>
</el-tooltip>
</template>
</n8n-tooltip>
</template>

View File

@@ -77,10 +77,6 @@ export default mixins(
&.expanded {
padding-left: $--sidebar-expanded-width;
}
* {
box-sizing: border-box;
}
}
.top-menu {

View File

@@ -492,7 +492,7 @@ export default mixins(
<style lang="scss">
.about-icon {
padding-left: 5px;
margin-left: 5px;
}
#collapse-change-button {
@@ -605,7 +605,7 @@ a.logo {
}
.el-menu-item.updates {
color: $--sidebar-inactive-color;
color: $--sidebar-inactive-color;
.item-title-root {
font-size: 13px;
top: 0 !important;

View File

@@ -87,7 +87,7 @@ export default Vue.extend({
},
closeDialog(callback?: () => void) {
this.$store.commit('ui/closeTopModal');
if (callback) {
if (typeof callback === 'function') {
callback();
}
},
@@ -146,9 +146,4 @@ export default Vue.extend({
.modal-content > .el-row {
margin-bottom: 15px;
}
.modal-footer > .el-button {
float: right;
margin-left: 5px;
}
</style>

View File

@@ -3,10 +3,10 @@
<div class="parameter-name">
{{parameter.displayName}}:
<el-tooltip class="parameter-info" placement="top" v-if="parameter.description" effect="light">
<div slot="content" v-html="addTargetBlank(parameter.description)"></div>
<n8n-tooltip v-if="parameter.description" class="parameter-info" placement="top" >
<div slot="content" v-html="parameter.description"></div>
<font-awesome-icon icon="question-circle" />
</el-tooltip>
</n8n-tooltip>
</div>
<div v-for="(value, index) in values" :key="index" class="duplicate-parameter-item" :class="parameter.type">
@@ -21,7 +21,7 @@
<collection-parameter :parameter="parameter" :values="value" :nodeValues="nodeValues" :path="getPath(index)" :hideDelete="hideDelete" @valueChanged="valueChanged" />
</div>
<div v-else>
<parameter-input class="duplicate-parameter-input-item" :parameter="parameter" :value="value" :displayOptions="true" :path="getPath(index)" @valueChanged="valueChanged" />
<parameter-input class="duplicate-parameter-input-item" :parameter="parameter" :value="value" :displayOptions="true" :path="getPath(index)" @valueChanged="valueChanged" inputSize="small" />
</div>
</div>
@@ -29,7 +29,7 @@
<div v-if="values && Object.keys(values).length === 0 || isReadOnly" class="no-items-exist">
Currently no items exist
</div>
<el-button v-if="!isReadOnly" size="small" class="add-item" @click="addItem()">{{ addButtonText }}</el-button>
<n8n-button v-if="!isReadOnly" fullWidth @click="addItem()" :label="addButtonText" />
</div>
</div>
@@ -141,10 +141,6 @@ export default mixins(genericHelpers)
margin: 0.5em 0 0em 2em;
}
.add-item {
width: 100%;
}
.delete-item {
display: none;
position: absolute;

View File

@@ -2,18 +2,18 @@
<div class="node-wrapper" :style="nodePosition">
<div class="node-default" :ref="data.name" :style="nodeStyle" :class="nodeClass" @dblclick="setNodeActive" @click.left="mouseLeftClick" v-touch:start="touchStart" v-touch:end="touchEnd">
<div v-if="hasIssues" class="node-info-icon node-issues">
<el-tooltip placement="top" effect="light">
<n8n-tooltip placement="top" >
<div slot="content" v-html="nodeIssues"></div>
<font-awesome-icon icon="exclamation-triangle" />
</el-tooltip>
</n8n-tooltip>
</div>
<el-badge v-else :hidden="workflowDataItems === 0" class="node-info-icon data-count" :value="workflowDataItems"></el-badge>
<div v-if="waiting" class="node-info-icon waiting">
<el-tooltip placement="top" effect="light">
<n8n-tooltip placement="top">
<div slot="content" v-html="waiting"></div>
<font-awesome-icon icon="clock" />
</el-tooltip>
</n8n-tooltip>
</div>
<div class="node-executing-info" title="Node is executing">
@@ -218,6 +218,7 @@ export default mixins(externalHooks, nodeBase, nodeHelpers, workflowHelpers).ext
height: 100px;
.node-description {
line-height: 1.5;
position: absolute;
bottom: -55px;
left: -50px;
@@ -307,7 +308,7 @@ export default mixins(externalHooks, nodeBase, nodeHelpers, workflowHelpers).ext
.node-info-icon {
position: absolute;
top: -18px;
top: -14px;
right: 12px;
z-index: 11;
@@ -350,9 +351,8 @@ export default mixins(externalHooks, nodeBase, nodeHelpers, workflowHelpers).ext
text-align: center;
.option {
width: 20px;
width: 28px;
display: inline-block;
padding: 0 0.3em;
&.touch {
display: none;

View File

@@ -279,15 +279,15 @@ export default mixins(externalHooks).extend({
</script>
<style lang="scss" scoped>
/deep/ .el-tabs__item {
::v-deep .el-tabs__item {
padding: 0;
}
/deep/ .el-tabs__active-bar {
::v-deep .el-tabs__active-bar {
height: 1px;
}
/deep/ .el-tabs__nav-wrap::after {
::v-deep .el-tabs__nav-wrap::after {
height: 1px;
}
@@ -321,7 +321,7 @@ export default mixins(externalHooks).extend({
text-align: center;
background-color: $--node-creator-select-background-color;
/deep/ .el-tabs > div {
::v-deep .el-tabs > div {
margin-bottom: 0;
.el-tabs__nav {

View File

@@ -92,7 +92,7 @@ export default Vue.extend({
</script>
<style scoped lang="scss">
/deep/ *, *:before, *:after {
::v-deep *, *:before, *:after {
box-sizing: border-box;
}

View File

@@ -7,30 +7,33 @@
</div>
<div v-for="credentialTypeDescription in credentialTypesNodeDescriptionDisplayed" :key="credentialTypeDescription.name" class="credential-data">
<el-row v-if="displayCredentials(credentialTypeDescription)">
<el-row v-if="displayCredentials(credentialTypeDescription)" class="credential-parameter-wrapper">
<el-col :span="10" class="parameter-name">
{{credentialTypeNames[credentialTypeDescription.name]}}:
</el-col>
<el-col :span="12" class="parameter-value" :class="getIssues(credentialTypeDescription.name).length?'has-issues':''">
<div class="credential-issues">
<el-tooltip placement="top" effect="light">
<div slot="content" v-html="'Issues:<br />&nbsp;&nbsp;- ' + getIssues(credentialTypeDescription.name).join('<br />&nbsp;&nbsp;- ')"></div>
<font-awesome-icon icon="exclamation-triangle" />
</el-tooltip>
</div>
<div :style="credentialInputWrapperStyle(credentialTypeDescription.name)">
<el-select v-model="credentials[credentialTypeDescription.name]" :disabled="isReadOnly" @change="credentialSelected(credentialTypeDescription.name)" placeholder="Select Credential" size="small">
<el-option
<n8n-select v-model="credentials[credentialTypeDescription.name]" :disabled="isReadOnly" @change="credentialSelected(credentialTypeDescription.name)" placeholder="Select Credential" size="small">
<n8n-option
v-for="(item, index) in credentialOptions[credentialTypeDescription.name]"
:key="item.name + '_' + index"
:label="item.name"
:value="item.name">
</el-option>
</el-select>
</n8n-option>
</n8n-select>
</div>
<div class="credential-issues">
<n8n-tooltip placement="top" >
<div slot="content" v-html="'Issues:<br />&nbsp;&nbsp;- ' + getIssues(credentialTypeDescription.name).join('<br />&nbsp;&nbsp;- ')"></div>
<font-awesome-icon icon="exclamation-triangle" />
</n8n-tooltip>
</div>
</el-col>
<el-col :span="2" class="parameter-value">
<el-col :span="2" class="parameter-value credential-action">
<font-awesome-icon v-if="credentials[credentialTypeDescription.name]" icon="pen" @click="updateCredentials(credentialTypeDescription.name)" class="update-credentials clickable" title="Update Credentials" />
</el-col>
@@ -289,11 +292,6 @@ export default mixins(
.credential-issues {
display: inline-block;
}
.el-input input:hover {
border-width: 1px;
border-color: #ff8080;
border-style: solid;
}
}
.headline {
@@ -301,15 +299,24 @@ export default mixins(
margin-bottom: 0.7em;
}
.credential-parameter-wrapper {
display: flex;
align-items: center;
}
.parameter-name {
line-height: 2em;
font-weight: 400;
}
.update-credentials {
position: absolute;
top: 7px;
right: 3px;
.parameter-value {
display: flex;
align-items: center;
}
.credential-action {
display: flex;
justify-content: center;
align-items: center;
}
}

View File

@@ -4,10 +4,10 @@
<span v-if="node">
<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">
<n8n-tooltip class="clickable" placement="top" >
<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>
</n8n-tooltip>
</a>
</span>
<span v-else>No node active</span>
@@ -521,16 +521,6 @@ export default mixins(
color: #555;
border-radius: 2px 0 0 2px;
textarea {
font-size: 0.9em;
line-height: 1.5em;
margin: 0.2em 0;
}
textarea:hover {
line-height: 1.5em;
}
.header-side-menu {
padding: 1em 0 1em 1.8em;
font-size: 1.35em;
@@ -579,51 +569,28 @@ export default mixins(
padding-bottom: 1em;
}
.add-option > .el-input input::placeholder {
color: #fff;
font-weight: 600;
.add-option {
i.el-select__caret {
color: var(--color-foreground-xlight);
}
.el-input .el-input__inner {
&,
&:hover,
&:focus {
border-radius: 20px;
color: var(--color-foreground-xlight);
font-weight: 600;
background-color: var(--color-primary);
border-color: var(--color-primary);
text-align: center;
}
&::placeholder {
color: var(--color-foreground-xlight);
opacity: 1; /** Firefox */
}
}
}
.el-button,
.add-option > .el-input .el-input__inner,
.add-option > .el-input .el-input__inner:hover
{
background-color: $--color-primary;
color: #fff;
text-align: center;
height: 38px;
}
.el-button,
.add-option > .el-input .el-input__inner
{
border: 1px solid $--color-primary;
border-radius: 17px;
height: 38px;
}
}
.el-input-number,
input.el-input__inner {
font-size: 0.9em;
line-height: 28px;
height: 28px;
}
.el-input-number {
padding: 0 10px;
}
.el-input--prefix .el-input__inner {
padding: 0 28px;
}
.el-input__prefix {
left: 2px;
top: 1px;
}
.el-select.add-option .el-input .el-select__caret {
color: #fff;
}
}
@@ -650,14 +617,15 @@ export default mixins(
}
.parameter-wrapper {
line-height: 2.7em;
padding: 0 1em;
}
.parameter-name {
line-height: 2.7em;
line-height: 1.5;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
align-self: center;
}
.color-reset-button-wrapper {

View File

@@ -17,7 +17,7 @@
</el-row>
</div>
<el-tooltip v-for="(webhook, index) in webhooksNode" :key="index" class="item" effect="light" content="Click to copy Webhook URL" placement="left">
<n8n-tooltip v-for="(webhook, index) in webhooksNode" :key="index" class="item" content="Click to copy Webhook URL" placement="left">
<div class="webhook-wrapper">
<div class="http-field">
<div class="http-method">
@@ -30,7 +30,7 @@
</div>
</div>
</div>
</el-tooltip>
</n8n-tooltip>
</div>
</el-collapse-transition>
@@ -217,6 +217,7 @@ export default mixins(
}
.webhook-wrapper {
line-height: 1.5;
position: relative;
margin: 1em 0 0.5em 0;
background-color: #fff;

View File

@@ -1,8 +1,18 @@
<template>
<div @keydown.stop :class="parameterInputClasses">
<expression-edit :dialogVisible="expressionEditDialogVisible" :value="value" :parameter="parameter" :path="path" @closeDialog="closeExpressionEditDialog" @valueChanged="expressionUpdated"></expression-edit>
<div class="parameter-input ignore-key-press" :style="parameterInputWrapperStyle">
<div v-if="['json', 'string'].includes(parameter.type) || remoteParameterOptionsLoadingIssues !== null">
<div class="parameter-input ignore-key-press" :style="parameterInputWrapperStyle" @click="openExpressionEdit">
<n8n-input
v-if="isValueExpression && showExpressionAsTextInput"
:size="inputSize"
:value="expressionDisplayValue"
:disabled="isReadOnly"
:title="displayTitle"
@keydown.stop
/>
<div v-else-if="['json', 'string'].includes(parameter.type) || remoteParameterOptionsLoadingIssues !== null">
<code-edit :dialogVisible="codeEditDialogVisible" :value="value" :parameter="parameter" @closeDialog="closeCodeEditDialog" @valueChanged="expressionUpdated"></code-edit>
<text-edit :dialogVisible="textEditDialogVisible" :value="value" :parameter="parameter" @closeDialog="closeTextEditDialog" @valueChanged="expressionUpdated"></text-edit>
@@ -10,37 +20,88 @@
<prism-editor v-if="!codeEditDialogVisible" :lineNumbers="true" :readonly="true" :code="displayValue" language="js"></prism-editor>
</div>
<el-input v-else v-model="tempValue" ref="inputField" size="small" :type="getStringInputType" :rows="getArgument('rows')" :value="displayValue" :disabled="!isValueExpression && isReadOnly" @change="valueChanged" @keydown.stop @focus="setFocus" :title="displayTitle" :placeholder="isValueExpression?'':parameter.placeholder">
<font-awesome-icon v-if="!isValueExpression && !isReadOnly" slot="suffix" icon="external-link-alt" class="edit-window-button clickable" title="Open Edit Window" @click="displayEditDialog()" />
</el-input>
</div>
<div v-else-if="parameter.type === 'dateTime'">
<el-date-picker
<n8n-input
v-else
v-model="tempValue"
ref="inputField"
type="datetime"
size="small"
:size="inputSize"
:type="getStringInputType"
:rows="getArgument('rows')"
:value="displayValue"
:title="displayTitle"
:disabled="isReadOnly"
:placeholder="parameter.placeholder?parameter.placeholder:'Select date and time'"
:picker-options="dateTimePickerOptions"
@change="valueChanged"
@focus="setFocus"
@keydown.stop
@focus="setFocus"
:title="displayTitle"
:placeholder="isValueExpression?'':parameter.placeholder"
>
</el-date-picker>
<div slot="suffix" class="expand-input-icon-container">
<font-awesome-icon v-if="!isValueExpression && !isReadOnly" icon="external-link-alt" class="edit-window-button clickable" title="Open Edit Window" @click="displayEditDialog()" />
</div>
</n8n-input>
</div>
<div v-else-if="parameter.type === 'number'">
<!-- <el-slider :value="value" @input="valueChanged"></el-slider> -->
<el-input-number ref="inputField" size="small" :value="displayValue" :max="getArgument('maxValue')" :min="getArgument('minValue')" :precision="getArgument('numberPrecision')" :step="getArgument('numberStepSize')" :disabled="isReadOnly" @change="valueChanged" @focus="setFocus" @keydown.stop :title="displayTitle" :placeholder="parameter.placeholder"></el-input-number>
<div v-else-if="parameter.type === 'color'" ref="inputField" class="color-input">
<el-color-picker
size="small"
class="color-picker"
:value="displayValue"
:disabled="isReadOnly"
@focus="setFocus"
@change="valueChanged"
:title="displayTitle"
:show-alpha="getArgument('showAlpha')"
/>
<n8n-input
v-model="tempValue"
:size="inputSize"
type="text"
:value="tempValue"
:disabled="isReadOnly"
@change="valueChanged"
@keydown.stop
@focus="setFocus"
:title="displayTitle"
/>
</div>
<el-select
<el-date-picker
v-else-if="parameter.type === 'dateTime'"
v-model="tempValue"
ref="inputField"
type="datetime"
:size="inputSize"
:value="displayValue"
:title="displayTitle"
:disabled="isReadOnly"
:placeholder="parameter.placeholder?parameter.placeholder:'Select date and time'"
:picker-options="dateTimePickerOptions"
@change="valueChanged"
@focus="setFocus"
@keydown.stop
/>
<n8n-input-number
v-else-if="parameter.type === 'number'"
ref="inputField" :size="inputSize"
:value="displayValue"
:controls="false"
:max="getArgument('maxValue')"
:min="getArgument('minValue')"
:precision="getArgument('numberPrecision')"
:step="getArgument('numberStepSize')"
:disabled="isReadOnly"
@change="valueChanged"
@focus="setFocus"
@keydown.stop
:title="displayTitle"
:placeholder="parameter.placeholder"
/>
<n8n-select
v-else-if="parameter.type === 'options'"
ref="inputField"
size="small"
:size="inputSize"
filterable
:value="displayValue"
:loading="remoteParameterOptionsLoading"
@@ -50,21 +111,23 @@
@keydown.stop
@focus="setFocus"
>
<el-option
<n8n-option
v-for="option in parameterOptions"
:value="option.value"
:key="option.value"
:label="option.name"
>
<div class="option-headline">{{ option.name }}</div>
<div v-if="option.description" class="option-description" v-html="option.description"></div>
</el-option>
</el-select>
<div class="list-option">
<div class="option-headline">{{ option.name }}</div>
<div v-if="option.description" class="option-description" v-html="option.description"></div>
</div>
</n8n-option>
</n8n-select>
<el-select
<n8n-select
v-else-if="parameter.type === 'multiOptions'"
ref="inputField"
size="small"
:size="inputSize"
filterable
multiple
:value="displayValue"
@@ -75,22 +138,32 @@
@focus="setFocus"
:title="displayTitle"
>
<el-option v-for="option in parameterOptions" :value="option.value" :key="option.value" :label="option.name" >
<div class="option-headline">{{ option.name }}</div>
<div v-if="option.description" class="option-description" v-html="option.description"></div>
</el-option>
</el-select>
<n8n-option v-for="option in parameterOptions" :value="option.value" :key="option.value" :label="option.name" >
<div class="list-option">
<div class="option-headline">{{ option.name }}</div>
<div v-if="option.description" class="option-description" v-html="option.description"></div>
</div>
</n8n-option>
</n8n-select>
<div v-else-if="parameter.type === 'color'" ref="inputField" class="color-input">
<el-color-picker :value="displayValue" :disabled="isReadOnly" @change="valueChanged" size="small" class="color-picker" @focus="setFocus" :title="displayTitle" :show-alpha="getArgument('showAlpha')"></el-color-picker>
<el-input v-model="tempValue" size="small" type="text" :value="tempValue" :disabled="isReadOnly" @change="valueChanged" @keydown.stop @focus="setFocus" :title="displayTitle" ></el-input>
</div>
<div v-else-if="parameter.type === 'boolean'">
<el-switch ref="inputField" :value="displayValue" @change="valueChanged" active-color="#13ce66" :disabled="isValueExpression || isReadOnly"></el-switch>
<div class="expression-info clickable" @click="expressionEditDialogVisible = true">Edit Expression</div>
</div>
<el-switch
v-else-if="parameter.type === 'boolean'"
class="switch-input"
ref="inputField"
active-color="#13ce66"
:value="displayValue"
:disabled="isReadOnly"
@change="valueChanged"
/>
</div>
<div class="parameter-issues" v-if="getIssues.length">
<n8n-tooltip placement="top" >
<div slot="content" v-html="'Issues:<br />&nbsp;&nbsp;- ' + getIssues.join('<br />&nbsp;&nbsp;- ')"></div>
<font-awesome-icon icon="exclamation-triangle" />
</n8n-tooltip>
</div>
<div class="parameter-options" v-if="displayOptionsComputed">
<el-dropdown trigger="click" @command="optionSelected" size="mini">
<span class="el-dropdown-link">
@@ -103,13 +176,6 @@
<el-dropdown-item command="resetValue" :disabled="isDefault" divided>Reset Value</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
<div class="parameter-issues" v-if="getIssues.length">
<el-tooltip placement="top" effect="light">
<div slot="content" v-html="'Issues:<br />&nbsp;&nbsp;- ' + getIssues.join('<br />&nbsp;&nbsp;- ')"></div>
<font-awesome-icon icon="exclamation-triangle" />
</el-tooltip>
</div>
</div>
@@ -163,6 +229,7 @@ export default mixins(
'path', // string
'value',
'isCredential', // boolean
'inputSize',
],
data () {
return {
@@ -221,6 +288,11 @@ export default mixins(
},
},
computed: {
showExpressionAsTextInput(): boolean {
const types = ['number', 'boolean', 'dateTime', 'options', 'multiOptions'];
return types.includes(this.parameter.type);
},
dependentParametersValues (): string | null {
const loadOptionsDependsOn = this.getArgument('loadOptionsDependsOn') as string[] | undefined;
@@ -295,6 +367,20 @@ export default mixins(
return returnValue;
},
expressionDisplayValue (): string {
const value = this.displayValue;
// address type errors for text input
if (typeof value === 'number' || typeof value === 'boolean') {
return JSON.stringify(value);
}
if (value === null) {
return '';
}
return value;
},
displayOptionsComputed (): boolean {
if (this.isReadOnly === true) {
return false;
@@ -417,6 +503,12 @@ export default mixins(
},
parameterInputClasses () {
const classes = [];
const rows = this.getArgument('rows');
const isTextarea = this.parameter.type === 'string' && rows !== undefined;
if (!isTextarea) {
classes.push('parameter-value-container');
}
if (this.isValueExpression) {
classes.push('expression');
}
@@ -507,6 +599,11 @@ export default mixins(
expressionUpdated (value: string) {
this.valueChanged(value);
},
openExpressionEdit() {
if (this.isValueExpression) {
this.expressionEditDialogVisible = true;
}
},
setFocus () {
if (this.isValueExpression) {
this.expressionEditDialogVisible = true;
@@ -572,12 +669,18 @@ export default mixins(
if (command === 'resetValue') {
this.valueChanged(this.parameter.default);
} else if (command === 'addExpression') {
this.valueChanged(`=${this.value}`);
if (this.parameter.type === 'number' || this.parameter.type === 'boolean') {
this.valueChanged(`={{${this.value}}}`);
}
else {
this.valueChanged(`=${this.value}`);
}
this.expressionEditDialogVisible = true;
} else if (command === 'removeExpression') {
this.valueChanged(this.expressionValueComputed || null);
this.valueChanged(this.expressionValueComputed !== undefined ? this.expressionValueComputed : null);
} else if (command === 'refreshOptions') {
this.loadRemoteParameterOptions();
this.loadRemoteParameterOptions();
}
},
},
@@ -631,6 +734,20 @@ export default mixins(
<style scoped lang="scss">
.switch-input {
margin: 5px 0;
}
.parameter-value-container {
display: flex;
align-items: center;
}
.parameter-actions {
display: inline-flex;
align-items: center;
}
.parameter-input {
display: inline-block;
}
@@ -649,20 +766,13 @@ export default mixins(
font-size: 1.2em;
}
.color-input {
background-color: $--custom-input-background;
border-radius: 16px;
line-height: 2.2em;
::v-deep .color-input {
display: flex;
.el-input {
width: 90px;
}
.color-picker {
float: left;
z-index: 10;
.el-color-picker__trigger {
border: none;
}
}
</style>
<style lang="scss">
@@ -670,93 +780,50 @@ export default mixins(
.ql-editor {
padding: 6px;
line-height: 26px;
background-color: #f0f0f0;
}
.expression-info {
display: none;
}
.expression {
.expression-info {
display: inline-block;
background-color: #441133;
color: #fff;
font-size: 0.7em;
line-height: 2.5em;
padding: 0 0.5em;
margin-left: 1em;
border-radius: 3px;
textarea[disabled], input[disabled] {
cursor: pointer !important;
}
.el-switch__core {
border: 1px dashed $--custom-expression-text;
}
.el-input > .el-input__inner,
.el-select > .el-input__inner,
.el-textarea textarea,
.el-textarea textarea:active,
.el-textarea textarea:focus,
.el-textarea textarea:hover,
.el-input-number,
.color-input {
border: 1px dashed $--custom-expression-text;
color: $--custom-expression-text;
background-color: $--custom-expression-background;
}
.el-input-number input,
.color-input .el-input__inner {
background-color: $--custom-expression-background;
}
// Overwrite again for number and color inputs to not create
// a second border inside of the already existing one
.color-input .el-input > .el-input__inner,
.el-input-number .el-input > .el-input__inner {
border: none;
background-color: none;
}
--input-border-color: #{$--custom-expression-text};
--input-border-style: dashed;
--input-background-color: #{$--custom-expression-background};
--disabled-border: #{$--custom-expression-text};
}
.has-issues {
.el-textarea textarea,
.el-textarea textarea:active,
.el-textarea textarea:focus,
.el-textarea textarea:hover,
.el-input-number input,
.el-input-number input:active,
.el-input-number input:focus,
.el-input-number input:hover,
.el-input-number [role="button"],
.el-input-number [role="button"]:active,
.el-input-number [role="button"]:focus,
.el-input-number [role="button"]:hover,
.el-input input,
.el-input input:active,
.el-input input:focus,
.el-input input:hover {
border-width: 1px;
border-color: #ff8080;
border-style: solid;
}
--input-border-color: var(--color-danger);
}
.el-dropdown {
color: #999;
}
.option-headline {
font-weight: 600;
}
li:not(.selected) .option-description {
color: $--custom-font-very-light;
}
.option-description {
font-weight: 400;
.list-option {
max-width: 340px;
margin: 6px 0;
white-space: normal;
max-width: 350px;
margin-top: -4px;
.option-headline {
font-weight: var(--font-weight-bold);
line-height: var(--font-line-height-regular);
overflow-wrap: break-word;
}
.option-description {
margin-top: 2px;
font-size: var(--font-size-2xs);
font-weight: var(--font-weight-regular);
line-height: var(--font-line-height-xloose);
color: $--custom-font-very-light;
}
}
.edit-window-button {
@@ -767,4 +834,10 @@ li:not(.selected) .option-description {
display: inline;
}
.expand-input-icon-container {
display: flex;
height: 100%;
align-items: center;
}
</style>

View File

@@ -1,14 +1,14 @@
<template>
<el-row class="parameter-wrapper">
<el-row class="parameter-wrapper" :class="{'multi-line': isMultiLineParameter}">
<el-col :span="isMultiLineParameter ? 24 : 10" class="parameter-name" :class="{'multi-line': isMultiLineParameter}">
<span class="title" :title="parameter.displayName">{{parameter.displayName}}</span>:
<el-tooltip class="parameter-info" placement="top" v-if="parameter.description" effect="light">
<div slot="content" v-html="addTargetBlank(parameter.description)"></div>
<n8n-tooltip class="parameter-info" placement="top" v-if="parameter.description" >
<div slot="content" v-html="parameter.description"></div>
<font-awesome-icon icon="question-circle" />
</el-tooltip>
</n8n-tooltip>
</el-col>
<el-col :span="isMultiLineParameter ? 24 : 14" class="parameter-value">
<parameter-input :parameter="parameter" :value="value" :displayOptions="displayOptions" :path="path" @valueChanged="valueChanged" />
<parameter-input :parameter="parameter" :value="value" :displayOptions="displayOptions" :path="path" @valueChanged="valueChanged" inputSize="small" />
</el-col>
</el-row>
</template>
@@ -74,7 +74,12 @@ export default Vue
<style lang="scss">
.parameter-wrapper {
line-height: 2.5em;
display: flex;
align-items: center;
&.multi-line {
flex-direction: column;
}
.option {
margin: 1em;
@@ -82,12 +87,10 @@ export default Vue
.parameter-info {
background-color: #ffffffaa;
border-radius: 6px;
display: none;
padding: 4px;
position: absolute;
right: 0px;
top: 8px;
right: 2px;
top: 1px;
}
.parameter-name {

View File

@@ -30,10 +30,10 @@
/>
</div>
{{parameter.displayName}}:
<el-tooltip placement="top" class="parameter-info" v-if="parameter.description" effect="light">
<div slot="content" v-html="addTargetBlank(parameter.description)"></div>
<n8n-tooltip placement="top" class="parameter-info" v-if="parameter.description" >
<div slot="content" v-html="parameter.description"></div>
<font-awesome-icon icon="question-circle"/>
</el-tooltip>
</n8n-tooltip>
</div>
<div>
<collection-parameter
@@ -294,6 +294,7 @@ export default mixins(
.parameter-item {
position: relative;
margin: 8px 0;
>.delete-option {
left: -0.9em;
@@ -310,9 +311,10 @@ export default mixins(
color: $--custom-font-black;
margin: 0.3em 0;
padding: 0.8em;
line-height: 1.5;
& a {
color: $--color-primary;
a {
font-weight: var(--font-weight-bold);
}
}
}

View File

@@ -1,7 +1,7 @@
<template>
<span>
<div class="push-connection-lost primary-color" v-if="!pushConnectionActive">
<el-tooltip placement="bottom-end" effect="light">
<n8n-tooltip placement="bottom-end" >
<div slot="content">
Cannot connect to server.<br />
It is either down or you have a connection issue. <br />
@@ -10,7 +10,7 @@
<span>
<font-awesome-icon icon="exclamation-triangle" />&nbsp; Connection lost
</span>
</el-tooltip>
</n8n-tooltip>
</div>
<slot v-else />
</span>

View File

@@ -2,72 +2,76 @@
<div class="run-data-view" v-loading="workflowRunning">
<BinaryDataDisplay :windowVisible="binaryDataDisplayVisible" :displayData="binaryDataDisplayData" @close="closeBinaryDataDisplay"/>
<el-button
<div
v-if="node && !isReadOnly"
:disabled="workflowRunning"
@click.stop="runWorkflow(node.name, 'RunData.ExecuteNodeButton')"
class="execute-node-button"
: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"/>
<font-awesome-icon v-else icon="spinner" spin />
</div>
Execute Node
</el-button>
<n8n-button
:title="`Executes this ${node.name} node after executing any previous nodes that have not yet returned data`"
:loading="workflowRunning"
icon="play-circle"
label="Execute Node"
@click.stop="runWorkflow(node.name, 'RunData.ExecuteNodeButton')"
/>
</div>
<div class="header">
<div class="title-text">
<strong v-if="dataCount < maxDisplayItems">
Items: {{ dataCount }}
</strong>
<strong v-else>Items:
<el-select v-model="maxDisplayItems" @click.stop>
<el-option v-for="option in maxDisplayItemsOptions" :label="option" :value="option" :key="option" />
</el-select>&nbsp;/
{{ dataCount }}
</strong>
<div v-else class="title-text">
<strong>Items:</strong>
<span class="opts">
<n8n-select size="mini" v-model="maxDisplayItems" @click.stop>
<n8n-option v-for="option in maxDisplayItemsOptions" :label="option" :value="option" :key="option" />
</n8n-select>
</span>&nbsp;/
<strong>{{ dataCount }}</strong>
</div>
&nbsp;
<el-popover
<n8n-tooltip
v-if="runMetadata"
placement="right"
width="400"
trigger="hover"
>
<strong>Start Time:</strong> {{runMetadata.startTime}}<br/>
<strong>Execution Time:</strong> {{runMetadata.executionTime}} ms
<font-awesome-icon icon="info-circle" class="primary-color" slot="reference" />
</el-popover>
<div slot="content">
<strong>Start Time:</strong> {{runMetadata.startTime}}<br/>
<strong>Execution Time:</strong> {{runMetadata.executionTime}} ms
</div>
<font-awesome-icon icon="info-circle" class="primary-color" />
</n8n-tooltip>
<span v-if="maxOutputIndex > 0">
| Output:
<el-select v-model="outputIndex" @click.stop>
<el-option v-for="option in (maxOutputIndex + 1)" :label="getOutputName(option-1)" :value="option -1" :key="option">
</el-option>
</el-select>
| Output:&nbsp;
</span>
<span class="opts" v-if="maxOutputIndex > 0" >
<n8n-select size="mini" v-model="outputIndex" @click.stop>
<n8n-option v-for="option in (maxOutputIndex + 1)" :label="getOutputName(option-1)" :value="option -1" :key="option">
</n8n-option>
</n8n-select>
</span>
<span v-if="maxRunIndex > 0">
| Data of Execution:
<el-select v-model="runIndex" @click.stop>
<el-option v-for="option in (maxRunIndex + 1)" :label="option + '/' + (maxRunIndex+1)" :value="option-1" :key="option">
</el-option>
</el-select>
<span v-if="maxRunIndex > 0">
| Data of Execution:&nbsp;
</span>
<span class="opts">
<n8n-select v-if="maxRunIndex > 0" size="mini" v-model="runIndex" @click.stop>
<n8n-option v-for="option in (maxRunIndex + 1)" :label="option + '/' + (maxRunIndex+1)" :value="option-1" :key="option">
</n8n-option>
</n8n-select>
</span>
</div>
<div v-if="node && workflowRunData !== null && workflowRunData.hasOwnProperty(node.name) && !workflowRunData[node.name][runIndex].error" class="title-data-display-selector" @click.stop>
<div v-if="hasNodeRun && !hasRunError" class="title-data-display-selector" @click.stop>
<el-radio-group v-model="displayMode" size="mini">
<el-radio-button label="JSON" :disabled="showData === false"></el-radio-button>
<el-radio-button label="Table"></el-radio-button>
<el-radio-button label="Binary" v-if="binaryData.length !== 0"></el-radio-button>
</el-radio-group>
</div>
<div class="select-button" v-if="displayMode === 'JSON' && state.path !== deselectedPlaceholder">
<div v-if="hasNodeRun && !hasRunError && displayMode === 'JSON' && state.path !== deselectedPlaceholder" class="select-button">
<el-dropdown trigger="click" @command="handleCopyClick">
<span class="el-dropdown-link">
<el-button class="retry-button" circle type="text" size="small" title="Copy">
<font-awesome-icon icon="copy" />
</el-button>
<n8n-icon-button title="Copy to Clipboard" icon="copy" />
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :command="{command: 'itemPath'}">Copy Item Path</el-dropdown-item>
@@ -75,7 +79,6 @@
<el-dropdown-item :command="{command: 'value'}">Copy Value</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
<div class="data-display-content">
@@ -84,7 +87,7 @@
<NodeErrorView :error="workflowRunData[node.name][runIndex].error" />
</div>
<span v-else>
<div v-if="showData === false" class="to-much-data">
<div v-if="showData === false" class="too-much-data">
<h3>
Node returned a large amount of data
</h3>
@@ -96,10 +99,11 @@
If you do decide to display it, avoid the JSON view!
</div>
<el-button size="small" @click="displayMode = 'Table';showData = true;">
<font-awesome-icon icon="eye"/>
Display Data Anyway
</el-button>
<n8n-button
icon="eye"
label="Display Data Anyway"
@click="displayMode = 'Table';showData = true;"
/>
</div>
<div v-else-if="['JSON', 'Table'].includes(displayMode)">
<div v-if="jsonData.length === 0" class="no-data">
@@ -169,11 +173,8 @@
<div class="value">{{binaryData.mimeType}}</div>
</div>
<!-- <el-button @click="displayBinaryData(binaryData)"> -->
<div class="binary-data-show-data-button-wrapper">
<el-button size="mini" class="binary-data-show-data-button" @click="displayBinaryData(index, key)">
Show Binary Data
</el-button>
<n8n-button size="small" label="Show Binary Data" class="binary-data-show-data-button" @click="displayBinaryData(index, key)" />
</div>
</div>
@@ -270,6 +271,12 @@ export default mixins(
};
},
computed: {
hasNodeRun(): boolean {
return Boolean(this.node && this.workflowRunData && this.workflowRunData.hasOwnProperty(this.node.name));
},
hasRunError(): boolean {
return Boolean(this.node && this.workflowRunData && this.workflowRunData[this.node.name] && this.workflowRunData[this.node.name][this.runIndex] && this.workflowRunData[this.node.name][this.runIndex].error);
},
workflowRunning (): boolean {
return this.$store.getters.isActionActive('workflowRunning');
},
@@ -649,6 +656,7 @@ export default mixins(
left: 0;
right: 0;
overflow-y: auto;
line-height: 1.5;
.binary-data-row {
display: inline-flex;
@@ -680,11 +688,6 @@ export default mixins(
.binary-data-show-data-button-wrapper {
margin-top: 1.5em;
text-align: center;
width: 100%;
.binary-data-show-data-button {
width: 130px;
}
}
.label {
@@ -718,6 +721,8 @@ export default mixins(
}
.json-data {
line-height: 1.5;
&.vjs-tree {
color: $--custom-input-font;
}
@@ -730,7 +735,7 @@ export default mixins(
margin: 1em;
}
.to-much-data {
.too-much-data {
margin: 1em;
text-align: center;
@@ -767,27 +772,16 @@ export default mixins(
position: absolute;
top: 10px;
right: 10px;
height: 30px;
width: 140px;
padding: 7px;
border-radius: 13px;
color: $--color-primary;
border: 1px solid $--color-primary;
background-color: #fff;
}
.execute-node-button:hover {
transform: scale(1.05);
}
.run-icon-button {
display: inline-block;
width: 20px;
}
.header {
padding-top: 10px;
padding-left: 10px;
display: flex;
align-items: center;
height: 40px;
.select-button {
height: 30px;
top: 50px;
@@ -799,8 +793,8 @@ export default mixins(
}
.title-text {
display: inline-block;
line-height: 30px;
display: inline-flex;
align-items: center;
}
.title-data-display-selector {
@@ -808,7 +802,6 @@ export default mixins(
left: calc(50% - 105px);
width: 210px;
display: inline-block;
line-height: 30px;
text-align: center;
.entry.active {
@@ -816,22 +809,9 @@ export default mixins(
}
}
.el-select {
.opts {
width: 80px;
z-index: 1;
.el-input__suffix-inner {
// TODO: Not sure why I have to do that. Invesigate when I have some time
position: absolute;
top: -5px;
right: 0;
}
input.el-input__inner {
border: 1px solid $--color-primary;
height: 25px;
line-height: 25px;
}
}
}
}

View File

@@ -1,14 +1,10 @@
<template>
<el-button :disabled="isWorkflowSaving" :class="{saved: isSaved}" size="small" @click="save">
<font-awesome-icon v-if="isWorkflowSaving" icon="spinner" spin />
<span v-else-if="isDirty || isNewWorkflow">
Save
</span>
<span v-else>Saved</span>
</el-button>
<span :class="$style.container">
<n8n-button v-if="isDirty || isNewWorkflow" label="Save" :disabled="isWorkflowSaving" @click="save" />
<span :class="$style.saved" v-else>Saved</span>
</span>
</template>
<script lang="ts">
import mixins from "vue-typed-mixins";
import { mapGetters } from "vuex";
@@ -39,27 +35,17 @@ export default mixins(workflowHelpers).extend({
});
</script>
<style lang="scss" scoped>
.el-button {
<style lang="scss" module>
.container {
width: 65px;
// override disabled colors
color: white;
background-color: $--color-primary;
&:hover:not(.saved) {
color: white;
background-color: $--color-primary;
}
&.saved {
color: $--custom-font-very-light;
font-size: 12px;
font-weight: 600;
line-height: 12px;
text-align: center;
background-color: unset;
pointer-events: none;
}
}
</style>
.saved {
color: $--custom-font-very-light;
font-size: 12px;
font-weight: 600;
line-height: 12px;
text-align: center;
padding: var(--spacing-2xs) var(--spacing-xs);
}
</style>

View File

@@ -1,6 +1,6 @@
<template>
<div :class="{'tags-container': true, focused}" @keydown.stop v-click-outside="onClickOutside">
<el-select
<n8n-select
:popperAppendToBody="false"
:value="appliedTags"
:loading="isLoading"
@@ -14,8 +14,9 @@
ref="select"
loading-text="..."
popper-class="tags-dropdown"
size="medium"
>
<el-option
<n8n-option
v-if="options.length === 0 && filter && createEnabled"
:key="CREATE_KEY"
:value="CREATE_KEY"
@@ -24,15 +25,15 @@
>
<font-awesome-icon icon="plus-circle" />
<span>Create tag "{{ filter }}"</span>
</el-option>
<el-option v-else-if="options.length === 0" value="message" disabled>
</n8n-option>
<n8n-option v-else-if="options.length === 0" value="message" disabled>
<span v-if="createEnabled">Type to create a tag</span>
<span v-else-if="allTags.length > 0">No matching tags exist</span>
<span v-else>No tags exist</span>
</el-option>
</n8n-option>
<!-- key is id+index for keyboard navigation to work well with filter -->
<el-option
<n8n-option
v-for="(tag, i) in options"
:value="tag.id"
:key="tag.id + '_' + i"
@@ -41,11 +42,11 @@
ref="tag"
/>
<el-option :key="MANAGE_KEY" :value="MANAGE_KEY" class="ops manage-tags">
<n8n-option :key="MANAGE_KEY" :value="MANAGE_KEY" class="ops manage-tags">
<font-awesome-icon icon="cog" />
<span>Manage tags</span>
</el-option>
</el-select>
</n8n-option>
</n8n-select>
</div>
</template>
@@ -235,31 +236,12 @@ export default mixins(showMessage).extend({
<style lang="scss" scoped>
$--max-input-height: 60px;
$--border-radius: 20px;
.tags-container {
overflow: hidden;
border: 1px solid transparent;
border-radius: $--border-radius;
&.focused {
border: 1px solid $--color-primary;
}
}
/deep/ .el-select {
::v-deep .el-select {
.el-select__tags {
max-height: $--max-input-height;
border-radius: $--border-radius;
overflow-y: scroll;
overflow-x: hidden;
// firefox fix for scrollbars
scrollbar-color: $--scrollbar-thumb-color transparent;
}
.el-input.is-focus {
border-radius: $--border-radius;
}
input {
@@ -283,10 +265,6 @@ $--border-radius: 20px;
min-width: $--dropdown-width !important;
max-width: $--dropdown-width;
*,*:after {
box-sizing: border-box;
}
.el-tag {
white-space: normal;
}
@@ -303,6 +281,10 @@ $--border-radius: 20px;
ul {
padding: 0;
max-height: $--dropdown-height - $--item-height;
::-webkit-scrollbar {
display: none;
}
}
&:after {
@@ -365,6 +347,7 @@ $--border-radius: 20px;
position: absolute;
bottom: 0;
min-width: $--dropdown-width;
border-top: 1px solid var(--color-foreground-base);
}
}
}

View File

@@ -9,7 +9,7 @@
your flows
</div>
</div>
<el-button ref="create" @click="$emit('enableCreate')"> Create a tag </el-button>
<n8n-button label="Create a tag" size="large" @click="$emit('enableCreate')" />
</el-col>
</div>
</template>
@@ -58,4 +58,4 @@ $--footer-spacing: 45px;
font-size: 14px;
line-height: 21px;
}
</style>
</style>

View File

@@ -24,7 +24,7 @@
</el-row>
</template>
<template v-slot:footer="{ close }">
<el-button size="small" @click="close">Done</el-button>
<n8n-button label="Done" @click="close" float="right" />
</template>
</Modal>
</template>

View File

@@ -13,13 +13,13 @@
<template slot-scope="scope">
<div class="name" :key="scope.row.id" @keydown.stop>
<transition name="fade" mode="out-in">
<el-input
<n8n-input
v-if="scope.row.create || scope.row.update"
:value="newName"
:maxlength="maxLength"
@input="onNewNameChange"
ref="nameInput"
></el-input>
></n8n-input>
<span v-else-if="scope.row.delete">
<span>Are you sure you want to delete this tag?</span>
<input ref="deleteHiddenInput" class="hidden" />
@@ -44,22 +44,20 @@
<template slot-scope="scope">
<transition name="fade" mode="out-in">
<div class="ops" v-if="scope.row.create">
<el-button title="Cancel" @click.stop="cancel" size="small" plain :disabled="isSaving">Cancel</el-button>
<el-button title="Create Tag" @click.stop="apply" size="small" :loading="isSaving">
Create tag
</el-button>
<n8n-button label="Cancel" @click.stop="cancel" type="outline" :disabled="isSaving" />
<n8n-button label="Create tag" @click.stop="apply" :loading="isSaving" />
</div>
<div class="ops" v-else-if="scope.row.update">
<el-button title="Cancel" @click.stop="cancel" size="small" plain :disabled="isSaving">Cancel</el-button>
<el-button title="Save Tag" @click.stop="apply" size="small" :loading="isSaving">Save changes</el-button>
<n8n-button label="Cancel" @click.stop="cancel" type="outline" :disabled="isSaving" />
<n8n-button label="Save changes" @click.stop="apply" :loading="isSaving" />
</div>
<div class="ops" v-else-if="scope.row.delete">
<el-button title="Cancel" @click.stop="cancel" size="small" plain :disabled="isSaving">Cancel</el-button>
<el-button title="Delete Tag" @click.stop="apply" size="small" :loading="isSaving">Delete tag</el-button>
<n8n-button label="Cancel" @click.stop="cancel" type="outline" :disabled="isSaving" />
<n8n-button label="Delete tag" @click.stop="apply" :loading="isSaving" />
</div>
<div class="ops main" v-else-if="!scope.row.disable">
<el-button title="Edit Tag" @click.stop="enableUpdate(scope.row)" icon="el-icon-edit" circle></el-button>
<el-button title="Delete Tag" @click.stop="enableDelete(scope.row)" icon="el-icon-delete" circle></el-button>
<n8n-icon-button title="Edit Tag" @click.stop="enableUpdate(scope.row)" icon="pen" />
<n8n-icon-button title="Delete Tag" @click.stop="enableDelete(scope.row)" icon="trash" />
</div>
</transition>
</template>
@@ -170,11 +168,6 @@ export default Vue.extend({
min-height: 45px;
display: flex;
align-items: center;
/deep/ input {
border: 1px solid $--color-primary;
background: white;
}
}
.ops {
@@ -183,8 +176,9 @@ export default Vue.extend({
align-items: center;
display: flex;
flex-wrap: nowrap;
float: right;
> .el-button {
> * {
margin: 2px;
}
}
@@ -199,22 +193,17 @@ export default Vue.extend({
opacity: 0;
}
.ops.main > .el-button {
.ops.main {
display: none;
float: right;
margin-left: 2px;
}
/deep/ tr.disabled {
::v-deep tr.disabled {
pointer-events: none;
}
/deep/ tr:hover .ops:not(.disabled) .el-button {
display: block;
}
/deep/ .el-input.is-disabled > input {
border: none;
tr:hover .ops:not(.disabled) {
display: flex;
}
.fade-enter-active,
@@ -225,4 +214,4 @@ export default Vue.extend({
.fade-leave-to {
opacity: 0;
}
</style>
</style>

View File

@@ -1,7 +1,7 @@
<template>
<el-row class="tags-header">
<el-col :span="10">
<el-input
<n8n-input
placeholder="Search tags"
:value="search"
@input="onSearchChange"
@@ -9,14 +9,11 @@
clearable
:maxlength="maxLength"
>
<i slot="prefix" class="el-input__icon el-icon-search"></i>
</el-input>
<font-awesome-icon slot="prefix" icon="search" />
</n8n-input>
</el-col>
<el-col :span="14">
<el-button @click="onAddNew" :disabled="disabled" plain>
<font-awesome-icon icon="plus" />
<div class="next-icon-text">Add new</div>
</el-button>
<n8n-button @click="onAddNew" :disabled="disabled" icon="plus" label="Add new" size="large" float="right" />
</el-col>
</el-row>
</template>
@@ -53,8 +50,4 @@ export default Vue.extend({
.tags-header {
margin-bottom: 15px;
}
.el-button {
float: right;
}
</style>
</style>

View File

@@ -7,7 +7,7 @@
{{parameter.displayName}}:
</div>
<div class="text-editor" @keydown.stop @keydown.esc="closeDialog()">
<el-input v-model="tempValue" type="textarea" ref="inputField" :value="value" :placeholder="parameter.placeholder" @change="valueChanged" @keydown.stop="noOp" rows="15" />
<n8n-input v-model="tempValue" type="textarea" ref="inputField" :value="value" :placeholder="parameter.placeholder" @change="valueChanged" @keydown.stop="noOp" :rows="15" />
</div>
</div>

View File

@@ -1,7 +1,7 @@
<template>
<div @keydown.stop class="variable-selector-wrapper">
<div class="input-wrapper">
<el-input placeholder="Variable filter..." v-model="variableFilter" ref="inputField" size="small" type="text"></el-input>
<n8n-input placeholder="Variable filter..." v-model="variableFilter" ref="inputField" size="small" type="text"></n8n-input>
</div>
<div class="result-wrapper">

View File

@@ -123,7 +123,7 @@ export default Vue.extend({
font-weight: 600;
font-size: 0.8em;
white-space: nowrap;
overflow-x: hidden;
overflow: hidden;
text-overflow: ellipsis;
}
.headline {

View File

@@ -1,8 +1,8 @@
<template functional>
<el-tooltip effect="light" content=" " placement="top" >
<n8n-tooltip content=" " placement="top" >
<div slot="content"><slot /></div>
<font-awesome-icon :class="$style['icon']" icon="exclamation-triangle"></font-awesome-icon>
</el-tooltip>
</n8n-tooltip>
</template>
@@ -12,4 +12,4 @@
height: 18px;
color: $--warning-tooltip-color;
}
</style>
</style>

View File

@@ -12,10 +12,10 @@
</el-switch>
<div class="could-not-be-started" v-if="couldNotBeStarted">
<el-tooltip placement="top">
<n8n-tooltip placement="top">
<div @click="displayActivationError" slot="content">The workflow is set to be active but could not be started.<br />Click to display error message.</div>
<font-awesome-icon @click="displayActivationError" icon="exclamation-triangle" />
</el-tooltip>
</n8n-tooltip>
</div>
</div>
</template>
@@ -185,7 +185,7 @@ export default mixins(
margin-left: 0.5em;
}
/deep/ .el-loading-spinner {
::v-deep .el-loading-spinner {
margin-top: -10px;
}
</style>

View File

@@ -19,9 +19,9 @@
/>
</div>
<div class="search-filter">
<el-input placeholder="Search workflows..." ref="inputFieldFilter" v-model="filterText">
<i slot="prefix" class="el-input__icon el-icon-search"></i>
</el-input>
<n8n-input placeholder="Search workflows..." ref="inputFieldFilter" v-model="filterText">
<font-awesome-icon slot="prefix" icon="search"></font-awesome-icon>
</n8n-input>
</div>
</div>
</template>

View File

@@ -1,133 +1,132 @@
<template>
<span>
<el-dialog class="workflow-settings" :visible="dialogVisible" append-to-body width="65%" title="Workflow Settings" :before-close="closeDialog">
<el-dialog class="workflow-settings" custom-class="classic" :visible="dialogVisible" append-to-body width="65%" title="Workflow Settings" :before-close="closeDialog">
<div v-loading="isLoading">
<el-row>
<el-col :span="10" class="setting-name">
Error Workflow:
<el-tooltip class="setting-info" placement="top" effect="light">
<n8n-tooltip class="setting-info" placement="top" >
<div slot="content" v-html="helpTexts.errorWorkflow"></div>
<font-awesome-icon icon="question-circle" />
</el-tooltip>
</n8n-tooltip>
</el-col>
<el-col :span="14" class="ignore-key-press">
<el-select v-model="workflowSettings.errorWorkflow" placeholder="Select Workflow" size="small" filterable>
<el-option
<n8n-select v-model="workflowSettings.errorWorkflow" placeholder="Select Workflow" size="medium" filterable :limit-popper-width="true">
<n8n-option
v-for="item in workflows"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</n8n-option>
</n8n-select>
</el-col>
</el-row>
<el-row>
<el-col :span="10" class="setting-name">
Timezone:
<el-tooltip class="setting-info" placement="top" effect="light">
<n8n-tooltip class="setting-info" placement="top" >
<div slot="content" v-html="helpTexts.timezone"></div>
<font-awesome-icon icon="question-circle" />
</el-tooltip>
</n8n-tooltip>
</el-col>
<el-col :span="14" class="ignore-key-press">
<el-select v-model="workflowSettings.timezone" placeholder="Select Timezone" size="small" filterable>
<el-option
<n8n-select v-model="workflowSettings.timezone" placeholder="Select Timezone" size="medium" filterable :limit-popper-width="true">
<n8n-option
v-for="timezone of timezones"
:key="timezone.key"
:label="timezone.value"
:value="timezone.key">
</el-option>
</el-select>
</n8n-option>
</n8n-select>
</el-col>
</el-row>
<el-row>
<el-col :span="10" class="setting-name">
Save Data Error Execution:
<el-tooltip class="setting-info" placement="top" effect="light">
<n8n-tooltip class="setting-info" placement="top" >
<div slot="content" v-html="helpTexts.saveDataErrorExecution"></div>
<font-awesome-icon icon="question-circle" />
</el-tooltip>
</n8n-tooltip>
</el-col>
<el-col :span="14" class="ignore-key-press">
<el-select v-model="workflowSettings.saveDataErrorExecution" placeholder="Select Option" size="small" filterable>
<el-option
<n8n-select v-model="workflowSettings.saveDataErrorExecution" placeholder="Select Option" size="medium" filterable :limit-popper-width="true">
<n8n-option
v-for="option of saveDataErrorExecutionOptions"
:key="option.key"
:label="option.value"
:value="option.key">
</el-option>
</el-select>
</n8n-option>
</n8n-select>
</el-col>
</el-row>
<el-row>
<el-col :span="10" class="setting-name">
Save Data Success Execution:
<el-tooltip class="setting-info" placement="top" effect="light">
<n8n-tooltip class="setting-info" placement="top" >
<div slot="content" v-html="helpTexts.saveDataSuccessExecution"></div>
<font-awesome-icon icon="question-circle" />
</el-tooltip>
</n8n-tooltip>
</el-col>
<el-col :span="14" class="ignore-key-press">
<el-select v-model="workflowSettings.saveDataSuccessExecution" placeholder="Select Option" size="small" filterable>
<el-option
<n8n-select v-model="workflowSettings.saveDataSuccessExecution" placeholder="Select Option" size="medium" filterable :limit-popper-width="true">
<n8n-option
v-for="option of saveDataSuccessExecutionOptions"
:key="option.key"
:label="option.value"
:value="option.key">
</el-option>
</el-select>
</n8n-option>
</n8n-select>
</el-col>
</el-row>
<el-row>
<el-col :span="10" class="setting-name">
Save Manual Executions:
<el-tooltip class="setting-info" placement="top" effect="light">
<n8n-tooltip class="setting-info" placement="top" >
<div slot="content" v-html="helpTexts.saveManualExecutions"></div>
<font-awesome-icon icon="question-circle" />
</el-tooltip>
</n8n-tooltip>
</el-col>
<el-col :span="14" class="ignore-key-press">
<el-select v-model="workflowSettings.saveManualExecutions" placeholder="Select Option" size="small" filterable>
<el-option
<n8n-select v-model="workflowSettings.saveManualExecutions" placeholder="Select Option" size="medium" filterable :limit-popper-width="true">
<n8n-option
v-for="option of saveManualOptions"
:key="option.key"
:label="option.value"
:value="option.key">
</el-option>
</el-select>
</n8n-option>
</n8n-select>
</el-col>
</el-row>
<el-row>
<el-col :span="10" class="setting-name">
Save Execution Progress:
<el-tooltip class="setting-info" placement="top" effect="light">
<n8n-tooltip class="setting-info" placement="top" >
<div slot="content" v-html="helpTexts.saveExecutionProgress"></div>
<font-awesome-icon icon="question-circle" />
</el-tooltip>
</n8n-tooltip>
</el-col>
<el-col :span="14" class="ignore-key-press">
<el-select v-model="workflowSettings.saveExecutionProgress" placeholder="Select Option" size="small" filterable>
<el-option
<n8n-select v-model="workflowSettings.saveExecutionProgress" placeholder="Select Option" size="medium" filterable :limit-popper-width="true">
<n8n-option
v-for="option of saveExecutionProgressOptions"
:key="option.key"
:label="option.value"
:value="option.key">
</el-option>
</el-select>
</n8n-option>
</n8n-select>
</el-col>
</el-row>
<el-row>
<el-col :span="10" class="setting-name">
Timeout Workflow:
<el-tooltip class="setting-info" placement="top" effect="light">
<n8n-tooltip class="setting-info" placement="top" >
<div slot="content" v-html="helpTexts.executionTimeoutToggle"></div>
<font-awesome-icon icon="question-circle" />
</el-tooltip>
</n8n-tooltip>
</el-col>
<el-col :span="14">
<div>
<el-switch ref="inputField" :value="workflowSettings.executionTimeout > -1" @change="toggleTimeout" active-color="#13ce66"></el-switch>
<div class="expression-info clickable" @click="expressionEditDialogVisible = true">Edit Expression</div>
</div>
</el-col>
</el-row>
@@ -135,29 +134,30 @@
<el-row>
<el-col :span="10" class="setting-name">
Timeout After:
<el-tooltip class="setting-info" placement="top" effect="light">
<n8n-tooltip class="setting-info" placement="top" >
<div slot="content" v-html="helpTexts.executionTimeout"></div>
<font-awesome-icon icon="question-circle" />
</el-tooltip>
</n8n-tooltip>
</el-col>
<el-col :span="4">
<el-input-number size="small" v-model="timeoutHMS.hours" :min="0" placeholder="hours" type="number" class="el-input_inner"></el-input-number><br />
<div class="timeout-setting-name">hours</div>
<n8n-input size="medium" :value="timeoutHMS.hours" @input="(value) => setTimeout('hours', value)" :min="0">
<template slot="append">hours</template>
</n8n-input>
</el-col>
<el-col :span="4">
<el-input-number size="small" v-model="timeoutHMS.minutes" :min="0" placeholder="minutes" type="number" class="el-input_inner"></el-input-number><br />
<div class="timeout-setting-name">minutes</div>
<el-col :span="4" class="timeout-input">
<n8n-input size="medium" :value="timeoutHMS.minutes" @input="(value) => setTimeout('minutes', value)" :min="0" :max="60">
<template slot="append">minutes</template>
</n8n-input>
</el-col>
<el-col :span="4">
<el-input-number size="small" v-model="timeoutHMS.seconds" :min="0" placeholder="seconds" type="number" class="el-input_inner"></el-input-number><br />
<div class="timeout-setting-name">seconds</div>
<el-col :span="4" class="timeout-input">
<n8n-input size="medium" :value="timeoutHMS.seconds" @input="(value) => setTimeout('seconds', value)" :min="0" :max="60">
<template slot="append">seconds</template>
</n8n-input>
</el-col>
</el-row>
</div>
<div class="action-buttons">
<el-button type="success" @click="saveSettings">
Save
</el-button>
<n8n-button label="Save" size="large" @click="saveSettings" />
</div>
</div>
</el-dialog>
@@ -237,6 +237,14 @@ export default mixins(
this.$emit('closeDialog');
return false;
},
setTimeout (key: string, value: string) {
const time = value ? parseInt(value, 10) : 0;
this.timeoutHMS = {
...this.timeoutHMS,
[key]: time,
};
},
async loadSaveDataErrorExecutionOptions () {
this.saveDataErrorExecutionOptions.length = 0;
this.saveDataErrorExecutionOptions.push.apply( // eslint-disable-line no-useless-call
@@ -471,7 +479,7 @@ export default mixins(
});
this.closeDialog();
this.$externalHooks().run('workflowSettings.saveSettings', { oldSettings });
},
toggleTimeout() {
@@ -518,9 +526,8 @@ export default mixins(
}
}
.timeout-setting-name {
text-align: center;
width: calc(100% - 20px);
.timeout-input {
margin-left: 5px;
}
</style>

View File

@@ -7,6 +7,7 @@ function broadcast(componentName: string, eventName: string, params: any) { // t
if (name === componentName) {
// @ts-ignore
// eslint-disable-next-line prefer-spread
child.$emit.apply(child, [eventName].concat(params));
} else {
// @ts-ignore
@@ -30,6 +31,7 @@ export default Vue.extend({
}
if (parent) {
// @ts-ignore
// eslint-disable-next-line prefer-spread
parent.$emit.apply(parent, [eventName].concat(params));
}
},
@@ -37,4 +39,4 @@ export default Vue.extend({
broadcast.call(this, componentName, eventName, params);
},
},
});
});

View File

@@ -59,6 +59,7 @@ export const genericHelpers = mixins(showMessage).extend({
return;
}
// @ts-ignore
this.loadingService = this.$loading(
{
lock: true,

View File

@@ -1,4 +1,4 @@
import { Notification } from 'element-ui';
// @ts-ignore
import { ElNotificationComponent, ElNotificationOptions } from 'element-ui/types/notification';
import mixins from 'vue-typed-mixins';
@@ -13,10 +13,11 @@ export const showMessage = mixins(externalHooks).extend({
messageData.position = 'bottom-right';
}
return Notification(messageData);
return this.$notify(messageData);
},
$showWarning(title: string, message: string, config?: {onClick?: () => void, duration?: number, customClass?: string, closeOnClick?: boolean}) {
// eslint-disable-next-line prefer-const
let notification: ElNotificationComponent;
if (config && config.closeOnClick) {
const cb = config.onClick;

View File

@@ -546,8 +546,7 @@ export const workflowHelpers = mixins(
async dataHasChanged(id: string) {
const currentData = await this.getWorkflowDataToSave();
let data: IWorkflowDb;
data = await this.restApi().getWorkflow(id);
const data: IWorkflowDb = await this.restApi().getWorkflow(id);
if(data !== undefined) {
const x = {

View File

@@ -2,16 +2,11 @@
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue';
import './plugins';
import 'prismjs';
import 'prismjs/themes/prism.css';
import 'vue-prism-editor/dist/VuePrismEditor.css';
import 'vue-json-pretty/lib/styles.css';
import Vue2TouchEvents from 'vue2-touch-events';
import * as ElementUI from 'element-ui';
// @ts-ignore
import locale from 'element-ui/lib/locale/lang/en';
import './n8n-theme.scss';
import App from '@/App.vue';
@@ -19,188 +14,8 @@ import router from './router';
import { runExternalHook } from './components/mixins/externalHooks';
// @ts-ignore
import vClickOutside from 'v-click-outside';
import Fragment from 'vue-fragment';
import { library } from '@fortawesome/fontawesome-svg-core';
import {
faAngleDoubleLeft,
faAngleDown,
faAngleRight,
faAngleUp,
faArrowLeft,
faArrowRight,
faAt,
faBook,
faBug,
faCalendar,
faCheck,
faChevronDown,
faChevronUp,
faCode,
faCodeBranch,
faCog,
faCogs,
faClock,
faClone,
faCloud,
faCloudDownloadAlt,
faCopy,
faCut,
faDotCircle,
faEdit,
faEnvelope,
faEye,
faExclamationTriangle,
faExpand,
faExternalLinkAlt,
faExchangeAlt,
faFile,
faFileArchive,
faFileCode,
faFileDownload,
faFileExport,
faFileImport,
faFilePdf,
faFolderOpen,
faGift,
faHdd,
faHome,
faHourglass,
faImage,
faInbox,
faInfo,
faInfoCircle,
faKey,
faMapSigns,
faNetworkWired,
faPause,
faPauseCircle,
faPen,
faPlay,
faPlayCircle,
faPlus,
faPlusCircle,
faQuestion,
faQuestionCircle,
faRedo,
faRss,
faSave,
faSearch,
faSearchMinus,
faSearchPlus,
faServer,
faSignInAlt,
faSlidersH,
faSpinner,
faStop,
faSun,
faSync,
faSyncAlt,
faTable,
faTasks,
faTerminal,
faThLarge,
faTimes,
faTrash,
faUndo,
faUsers,
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import { store } from './store';
Vue.use(Vue2TouchEvents);
Vue.use(ElementUI, { locale });
Vue.use(vClickOutside);
library.add(faAngleDoubleLeft);
library.add(faAngleDown);
library.add(faAngleRight);
library.add(faAngleUp);
library.add(faArrowLeft);
library.add(faArrowRight);
library.add(faAt);
library.add(faBook);
library.add(faBug);
library.add(faCalendar);
library.add(faCheck);
library.add(faChevronDown);
library.add(faChevronUp);
library.add(faCode);
library.add(faCodeBranch);
library.add(faCog);
library.add(faCogs);
library.add(faClock);
library.add(faClone);
library.add(faCloud);
library.add(faCloudDownloadAlt);
library.add(faCopy);
library.add(faCut);
library.add(faDotCircle);
library.add(faEdit);
library.add(faEnvelope);
library.add(faEye);
library.add(faExclamationTriangle);
library.add(faExpand);
library.add(faExternalLinkAlt);
library.add(faExchangeAlt);
library.add(faFile);
library.add(faFileArchive);
library.add(faFileCode);
library.add(faFileDownload);
library.add(faFileExport);
library.add(faFileImport);
library.add(faFilePdf);
library.add(faFolderOpen);
library.add(faGift);
library.add(faHdd);
library.add(faHome);
library.add(faHourglass);
library.add(faImage);
library.add(faInbox);
library.add(faInfo);
library.add(faInfoCircle);
library.add(faKey);
library.add(faMapSigns);
library.add(faNetworkWired);
library.add(faPause);
library.add(faPauseCircle);
library.add(faPen);
library.add(faPlay);
library.add(faPlayCircle);
library.add(faPlus);
library.add(faPlusCircle);
library.add(faQuestion);
library.add(faQuestionCircle);
library.add(faRedo);
library.add(faRss);
library.add(faSave);
library.add(faSearch);
library.add(faSearchMinus);
library.add(faSearchPlus);
library.add(faServer);
library.add(faSignInAlt);
library.add(faSlidersH);
library.add(faSpinner);
library.add(faStop);
library.add(faSun);
library.add(faSync);
library.add(faSyncAlt);
library.add(faTable);
library.add(faTasks);
library.add(faTerminal);
library.add(faThLarge);
library.add(faTimes);
library.add(faTrash);
library.add(faUndo);
library.add(faUsers);
Vue.component('font-awesome-icon', FontAwesomeIcon);
Vue.use(Fragment.Plugin);
Vue.config.productionTip = false;
router.afterEach((to, from) => {
runExternalHook('main.routeChange', store, { from, to });

View File

@@ -18,16 +18,6 @@ $--custom-expression-background: #f7f5ff;
$--custom-window-sidebar-top : #fff5f2;
$--custom-error-background : #ffe5e5;
$--custom-error-text : #eb2222;
$--custom-running-background : #ffffe5;
$--custom-running-text : #eb9422;
$--custom-success-background : #e3f0e4;
$--custom-success-text-light: #2f4;
$--custom-success-text : #40c351;
$--custom-warning-background : #ffffe5;
$--custom-warning-text : #eb9422;
// Badge
$--badge-danger-color: #f45959;
$--badge-danger-background-color: #fef0f0;
@@ -74,9 +64,6 @@ $--breakpoint-sm: 992px;
$--breakpoint-md: 1200px;
$--breakpoint-lg: 1920px;
// scrollbars
$--scrollbar-thumb-color: lighten($--color-primary, 20%);
// tags
$--tag-background-color: #dce1e9;
$--tag-text-color: #3d3f46;

View File

@@ -1,35 +1,9 @@
// https://github.com/ElemeFE/element/blob/dev/packages/theme-chalk/src/table.scss
@import "./n8n-theme-variables";
$--font-path: '~element-ui/lib/theme-chalk/fonts';
@import "~element-ui/packages/theme-chalk/src/index";
@import "~element-ui/lib/theme-chalk/display.css";
@import "~n8n-design-system/theme/dist/index.css";
body {
font-family: 'Open Sans', sans-serif;
font-weight: 300;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: $--custom-node-view-background;
margin: 0;
overscroll-behavior-x: none;
padding: 0;
}
input {
font-family: 'Open Sans', sans-serif;
font-weight: 400;
}
button {
font-family: 'Open Sans', sans-serif;
font-weight: 600;
}
h1, h2, h3, h4, h5, h6 {
color: #555;
}
.clickable {
@@ -159,8 +133,11 @@ h1, h2, h3, h4, h5, h6 {
left: 60px;
top: 1px;
}
}
&:hover, &:focus {
background-color: #fff0ef;
}
}
}
.el-menu--vertical {
.el-menu-item {
@@ -210,128 +187,6 @@ h1, h2, h3, h4, h5, h6 {
}
}
// Select input
.el-scrollbar {
background-color: #fff;
}
.el-select-dropdown__item {
font-size: 0.8em;
color: #555;
height: auto;
line-height: 1.8em;
margin: 0.25em 0;
padding: 0.25em 1em;
}
.el-select-dropdown__item.selected {
font-weight: normal;
}
.el-select-dropdown__item + .el-select-dropdown__item {
border-top: 1px solid #ddd;
}
.el-dropdown-menu__item {
color: $--color-primary;
}
// Color-Picker
.color-picker {
.el-color-picker__trigger {
border: none;
background: none;
padding: 2px 0 0 4px;
.el-color-picker__icon {
color: $--color-primary;
left: 14px;
}
}
.el-color-picker__color {
position: relative;
top: 2px;
width: 20px;
height: 20px;
border: none;
}
.el-color-picker__color:hover {
transform: scale(1.1);
}
.el-color-picker__color-inner {
border: none;
border-radius: 11px;
}
}
// Date selector
.el-date-editor.el-input {
width: 100%;
}
// Select input
.el-select {
width: 100%;
.el-tag {
color: $--custom-input-font;
.el-tag__close.el-icon-close {
background-color: $--custom-input-font;
&:hover {
background-color: $--custom-input-font;
transform: scale(0.8);
}
}
}
}
.el-switch__label {
color: #fff;
}
// Input
.el-input__inner {
border-radius: 20px;
text-overflow: ellipsis;
}
.el-input--small .el-input__inner {
border-radius: 13px;
}
.el-input__inner,
.el-input__inner:hover {
background-color: $--custom-input-background;
color: $--custom-input-font;
border: none;
outline: 0;
}
// Number Input
.el-input-number {
background-color: $--custom-input-background;
border-radius: 16px;
width: calc(100% - 20px);
.el-input-number__decrease,
.el-input-number__increase {
border: none;
color: #fff;
background-color: $--custom-table-background-main;
width: 20px;
height: 20px;
line-height: 20px;
border-radius: 10px;
margin: 3px;
}
.el-input-number__decrease:hover,
.el-input-number__increase:hover {
transform: scale(1.1);
}
.el-input-number__decrease.is-disabled,
.el-input-number__increase.is-disabled {
background-color: $--custom-input-background-disabled;
}
}
// Transfer list (nodes)
.el-transfer {
.el-transfer-panel {
@@ -354,63 +209,6 @@ h1, h2, h3, h4, h5, h6 {
}
}
// Buttons
.el-button,
.el-button:active,
.el-button:focus {
border: none;
border-radius: 20px;
color: #fff;
font-weight: 600;
background-color: $--color-primary;
.next-icon-text {
display: inline-block;
margin-left: 10px;
}
}
.el-button.el-button--mini:not(.is-circle) {
padding: 7px 10px;
}
.el-button:hover {
background-color: $--color-primary;
color: #fff;
transform: scale(1.05);
}
.el-input.is-disabled .el-input__inner,
.el-button.is-disabled,
.el-button.is-disabled:hover,
.el-button.is-disabled:focus {
background-color: $--custom-input-background-disabled;
border-color: #555;
color: $--custom-input-font-disabled;
}
.el-button.is-plain,.el-button.is-plain:hover {
color: $--color-primary;
border: 1px solid $--color-primary;
background-color: #fff;
}
// Textarea
.ql-editor,
.el-textarea textarea,
.el-textarea textarea:active,
.el-textarea textarea:focus,
.el-textarea textarea:hover {
background-color: $--custom-input-background;
color: $--custom-input-font;
border: none;
border-radius: 3px;
outline: 0;
padding: 0.8em 1em;
line-height: 1.5em;
}
.el-textarea.is-disabled .el-textarea__inner {
background-color: $--custom-input-background-disabled;
color: $--custom-input-font-disabled;
}
// Tabs
.type-selector:focus,
.el-tabs__header:focus,
@@ -450,14 +248,6 @@ h1, h2, h3, h4, h5, h6 {
color: #555;
}
// Tooltip
.el-tooltip__popper.is-light {
border: none;
-webkit-box-shadow: 0px 0px 12px 0px rgba(0,0,0,0.15);
-moz-box-shadow: 0px 0px 12px 0px rgba(0,0,0,0.15);
box-shadow: 0px 0px 12px 0px rgba(0,0,0,0.15);
}
// Notification
.el-notification {
border-radius: 0;
@@ -469,36 +259,6 @@ h1, h2, h3, h4, h5, h6 {
}
// Custom scrollbar
::-webkit-scrollbar {
width: 12px;
height: 12px;
}
::-webkit-scrollbar-track {
border-radius: 6px;
}
::-webkit-scrollbar-track:hover {
background: #ddd;
}
::-webkit-scrollbar-thumb {
border-radius: 6px;
background: $--scrollbar-thumb-color;
}
::-webkit-scrollbar-thumb:hover {
background: $--color-primary;
}
.el-dialog__wrapper {
&::-webkit-scrollbar-track,
&::-webkit-scrollbar-track:hover {
background: #fff;
}
&::-webkit-scrollbar-thumb {
background: $--color-primary;
border-radius: 6px;
}
}
.tags-container {
.el-tag {
color: $--tag-text-color;

View File

@@ -0,0 +1,158 @@
// @ts-nocheck
import Vue from "vue";
import Fragment from 'vue-fragment';
import "regenerator-runtime/runtime";
import Drawer from 'element-ui/lib/drawer';
import Dialog from 'element-ui/lib/dialog';
import Dropdown from 'element-ui/lib/dropdown';
import DropdownMenu from 'element-ui/lib/dropdown-menu';
import DropdownItem from 'element-ui/lib/dropdown-item';
import Menu from 'element-ui/lib/menu';
import Submenu from 'element-ui/lib/submenu';
import MenuItem from 'element-ui/lib/menu-item';
import Radio from 'element-ui/lib/radio';
import RadioGroup from 'element-ui/lib/radio-group';
import RadioButton from 'element-ui/lib/radio-button';
import Checkbox from 'element-ui/lib/checkbox';
import Switch from 'element-ui/lib/switch';
import Select from 'element-ui/lib/select';
import Option from 'element-ui/lib/option';
import OptionGroup from 'element-ui/lib/option-group';
import ButtonGroup from 'element-ui/lib/button-group';
import Table from 'element-ui/lib/table';
import TableColumn from 'element-ui/lib/table-column';
import DatePicker from 'element-ui/lib/date-picker';
import Tabs from 'element-ui/lib/tabs';
import TabPane from 'element-ui/lib/tab-pane';
import Tag from 'element-ui/lib/tag';
import Row from 'element-ui/lib/row';
import Col from 'element-ui/lib/col';
import Badge from 'element-ui/lib/badge';
import Card from 'element-ui/lib/card';
import ColorPicker from 'element-ui/lib/color-picker';
import Transfer from 'element-ui/lib/transfer';
import Container from 'element-ui/lib/container';
import Loading from 'element-ui/lib/loading';
import MessageBox from 'element-ui/lib/message-box';
import Message from 'element-ui/lib/message';
import Notification from 'element-ui/lib/notification';
import CollapseTransition from 'element-ui/lib/transitions/collapse-transition';
// @ts-ignore
import lang from 'element-ui/lib/locale/lang/en';
// @ts-ignore
import locale from 'element-ui/lib/locale';
import {
N8nIconButton,
N8nButton,
N8nInput,
N8nInputLabel,
N8nInputNumber,
N8nSelect,
N8nOption,
} from 'n8n-design-system';
import { ElMessageBoxOptions } from "element-ui/types/message-box";
Vue.use(Fragment.Plugin);
// n8n design system
Vue.use(N8nButton);
Vue.use(N8nIconButton);
Vue.use(N8nInput);
Vue.use(N8nInputLabel);
Vue.use(N8nInputNumber);
Vue.use(N8nSelect);
Vue.use(N8nOption);
// element io
locale.use(lang);
Vue.use(Dialog);
Vue.use(Drawer);
Vue.use(Dropdown);
Vue.use(DropdownMenu);
Vue.use(DropdownItem);
Vue.use(Menu);
Vue.use(Submenu);
Vue.use(MenuItem);
Vue.use(Radio);
Vue.use(RadioGroup);
Vue.use(RadioButton);
Vue.use(Checkbox);
Vue.use(Switch);
Vue.use(Select);
Vue.use(Option);
Vue.use(OptionGroup);
Vue.use(ButtonGroup);
Vue.use(Table);
Vue.use(TableColumn);
Vue.use(DatePicker);
Vue.use(Tabs);
Vue.use(TabPane);
Vue.use(Tag);
Vue.use(Row);
Vue.use(Col);
Vue.use(Badge);
Vue.use(Card);
Vue.use(ColorPicker);
Vue.use(Transfer);
Vue.use(Container);
Vue.component(CollapseTransition.name, CollapseTransition);
Vue.use(Loading.directive);
Vue.prototype.$loading = Loading.service;
Vue.prototype.$msgbox = MessageBox;
Vue.prototype.$alert = async (message: string, configOrTitle: string | ElMessageBoxOptions | undefined, config: ElMessageBoxOptions | undefined) => {
let temp = config || (typeof configOrTitle === 'object' ? configOrTitle : {});
temp = {
...temp,
roundButton: true,
cancelButtonClass: 'btn--cancel',
confirmButtonClass: 'btn--confirm',
};
if (typeof configOrTitle === 'string') {
return await MessageBox.alert(message, configOrTitle, temp);
}
return await MessageBox.alert(message, temp);
};
Vue.prototype.$confirm = async (message: string, configOrTitle: string | ElMessageBoxOptions | undefined, config: ElMessageBoxOptions | undefined) => {
let temp = config || (typeof configOrTitle === 'object' ? configOrTitle : {});
temp = {
...temp,
roundButton: true,
cancelButtonClass: 'btn--cancel',
confirmButtonClass: 'btn--confirm',
};
if (typeof configOrTitle === 'string') {
return await MessageBox.confirm(message, configOrTitle, temp);
}
return await MessageBox.confirm(message, temp);
};
Vue.prototype.$prompt = async (message: string, configOrTitle: string | ElMessageBoxOptions | undefined, config: ElMessageBoxOptions | undefined) => {
let temp = config || (typeof configOrTitle === 'object' ? configOrTitle : {});
temp = {
...temp,
roundButton: true,
cancelButtonClass: 'btn--cancel',
confirmButtonClass: 'btn--confirm',
};
if (typeof configOrTitle === 'string') {
return await MessageBox.prompt(message, configOrTitle, temp);
}
return await MessageBox.prompt(message, temp);
};
Vue.prototype.$notify = Notification;
Vue.prototype.$message = Message;

View File

@@ -0,0 +1,8 @@
import Vue from "vue";
import Vue2TouchEvents from 'vue2-touch-events';
// @ts-ignore
import vClickOutside from 'v-click-outside';
Vue.use(Vue2TouchEvents);
Vue.use(vClickOutside);

View File

@@ -0,0 +1,172 @@
import Vue from 'vue';
import { library } from '@fortawesome/fontawesome-svg-core';
import {
faAngleDoubleLeft,
faAngleDown,
faAngleRight,
faAngleUp,
faArrowLeft,
faArrowRight,
faAt,
faBook,
faBug,
faCalendar,
faCheck,
faChevronDown,
faChevronUp,
faCode,
faCodeBranch,
faCog,
faCogs,
faClock,
faClone,
faCloud,
faCloudDownloadAlt,
faCopy,
faCut,
faDotCircle,
faEdit,
faEnvelope,
faEye,
faExclamationTriangle,
faExpand,
faExternalLinkAlt,
faExchangeAlt,
faFile,
faFileArchive,
faFileCode,
faFileDownload,
faFileExport,
faFileImport,
faFilePdf,
faFolderOpen,
faGift,
faHdd,
faHome,
faHourglass,
faImage,
faInbox,
faInfo,
faInfoCircle,
faKey,
faMapSigns,
faNetworkWired,
faPause,
faPauseCircle,
faPen,
faPlay,
faPlayCircle,
faPlus,
faPlusCircle,
faQuestion,
faQuestionCircle,
faRedo,
faRss,
faSave,
faSearch,
faSearchMinus,
faSearchPlus,
faServer,
faSignInAlt,
faSlidersH,
faSpinner,
faStop,
faSun,
faSync,
faSyncAlt,
faTable,
faTasks,
faTerminal,
faThLarge,
faTimes,
faTrash,
faUndo,
faUsers,
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
library.add(faAngleDoubleLeft);
library.add(faAngleDown);
library.add(faAngleRight);
library.add(faAngleUp);
library.add(faArrowLeft);
library.add(faArrowRight);
library.add(faAt);
library.add(faBook);
library.add(faBug);
library.add(faCalendar);
library.add(faCheck);
library.add(faChevronDown);
library.add(faChevronUp);
library.add(faCode);
library.add(faCodeBranch);
library.add(faCog);
library.add(faCogs);
library.add(faClock);
library.add(faClone);
library.add(faCloud);
library.add(faCloudDownloadAlt);
library.add(faCopy);
library.add(faCut);
library.add(faDotCircle);
library.add(faEdit);
library.add(faEnvelope);
library.add(faEye);
library.add(faExclamationTriangle);
library.add(faExpand);
library.add(faExternalLinkAlt);
library.add(faExchangeAlt);
library.add(faFile);
library.add(faFileArchive);
library.add(faFileCode);
library.add(faFileDownload);
library.add(faFileExport);
library.add(faFileImport);
library.add(faFilePdf);
library.add(faFolderOpen);
library.add(faGift);
library.add(faHdd);
library.add(faHome);
library.add(faHourglass);
library.add(faImage);
library.add(faInbox);
library.add(faInfo);
library.add(faInfoCircle);
library.add(faKey);
library.add(faMapSigns);
library.add(faNetworkWired);
library.add(faPause);
library.add(faPauseCircle);
library.add(faPen);
library.add(faPlay);
library.add(faPlayCircle);
library.add(faPlus);
library.add(faPlusCircle);
library.add(faQuestion);
library.add(faQuestionCircle);
library.add(faRedo);
library.add(faRss);
library.add(faSave);
library.add(faSearch);
library.add(faSearchMinus);
library.add(faSearchPlus);
library.add(faServer);
library.add(faSignInAlt);
library.add(faSlidersH);
library.add(faSpinner);
library.add(faStop);
library.add(faSun);
library.add(faSync);
library.add(faSyncAlt);
library.add(faTable);
library.add(faTasks);
library.add(faTerminal);
library.add(faThLarge);
library.add(faTimes);
library.add(faTrash);
library.add(faUndo);
library.add(faUsers);
Vue.component('font-awesome-icon', FontAwesomeIcon);

View File

@@ -0,0 +1,3 @@
import './icons';
import './directives';
import './compontents';

View File

@@ -32,7 +32,7 @@
</div>
<DataDisplay @valueChanged="valueChanged"/>
<div v-if="!createNodeActive && !isReadOnly" class="node-creator-button" title="Add Node" @click="openNodeCreator">
<el-button icon="el-icon-plus" circle></el-button>
<n8n-icon-button size="xlarge" icon="plus" />
</div>
<node-creator
:active="createNodeActive"
@@ -59,52 +59,44 @@
</button>
</div>
<div class="workflow-execute-wrapper" v-if="!isReadOnly">
<el-button
type="text"
<n8n-button
@click.stop="runWorkflow()"
class="workflow-run-button"
:class="{'running': workflowRunning}"
:disabled="workflowRunning"
:loading="workflowRunning"
:label="runButtonText"
size="large"
icon="play-circle"
title="Executes the Workflow from the Start or Webhook Node."
>
<div class="run-icon">
<font-awesome-icon icon="spinner" spin v-if="workflowRunning"/>
<font-awesome-icon icon="play-circle" v-else/>
</div>
:type="workflowRunning ? 'light' : 'primary'"
/>
{{runButtonText}}
</el-button>
<el-button
<n8n-icon-button
v-if="workflowRunning === true && !executionWaitingForWebhook"
circle
type="text"
@click.stop="stopExecution()"
icon="stop"
size="large"
class="stop-execution"
type="light"
:title="stopExecutionInProgress ? 'Stopping current execution':'Stop current execution'"
>
<font-awesome-icon icon="stop" :class="{'fa-spin': stopExecutionInProgress}"/>
</el-button>
<el-button
:loading="stopExecutionInProgress"
@click.stop="stopExecution()"
/>
<n8n-icon-button
v-if="workflowRunning === true && executionWaitingForWebhook === true"
circle
type="text"
@click.stop="stopWaitingForWebhook()"
class="stop-execution"
icon="stop"
size="large"
title="Stop waiting for Webhook call"
>
<font-awesome-icon icon="stop" :class="{'fa-spin': stopExecutionInProgress}"/>
</el-button>
<el-button
type="light"
@click.stop="stopWaitingForWebhook()"
/>
<n8n-icon-button
v-if="!isReadOnly && workflowExecution && !workflowRunning"
circle
type="text"
@click.stop="clearExecutionData()"
class="clear-execution"
title="Deletes the current Execution Data."
>
<font-awesome-icon icon="trash" class="clear-execution-icon" />
</el-button>
icon="trash"
size="large"
@click.stop="clearExecutionData()"
/>
</div>
<Modals />
</div>
@@ -2313,13 +2305,6 @@ export default mixins(
.node-creator-button button {
position: relative;
background: $--color-primary;
font-size: 1.4em;
color: #fff;
}
.node-creator-button:hover button {
transform: scale(1.05);
}
.node-view-root {
@@ -2376,20 +2361,8 @@ export default mixins(
width: 300px;
text-align: center;
.run-icon {
display: inline-block;
transform: scale(1.4);
margin-right: 0.5em;
}
.workflow-run-button {
padding: 12px;
}
.stop-execution,
.workflow-run-button.running {
color: $--color-primary;
background-color: $--color-primary-light;
> * {
margin-inline-end: 0.625rem;
}
}