feat: migrate editor-ui to Vite.js and various DX improvements (N8N-2277) (#4061)

* feat: Added vite.js dependencies.

* chore: Removed tests folder to follow same structure as design-system

* chore: Removed unused testing config.

* chore: Created vite.js index.html

* refactor: Updated scss structure and imports.

* refactor: Updated workflow building.

* fix: Cleared up all workflow dependency cycles. Added proper package.json imports config.

* feat: Got a working build using Vite. Need to fix issues next.

* fix: Progress! Getting process.env error.

* fix: Changed process.env to import.meta.env.

* fix: Fixed circular imports that used require(). Fixed monaco editor.

* chore: Removed commented code.

* chore: Cleaned up package.json

* feat: Made necessary changes to replace base path in css files.

* feat: Serve CSS files for `editor-ui` Vite migration (#4069)

 Serve CSS files for Vite migration

* chore: Fixed package-lock.json.

* fix: Fixed build after centralized tsconfig update.

* fix: Removed lodash-es replacement.

* fix: Commented out vitest test command.

* style: Fixed linting issues.

* fix: Added lodash-es hotfix back.

* chore: Updated package-lock.json

* refactor: Renamed all n8n scss variables to no longer be defined as private.

* feat(editor): add application-wide el-button replacement.

* fix(editor): Fix import in page alert after merge.

* chore(editor): update package-lock.json.

* fix: Case sensitive lodash-es replacement for vue-agile.

* fix: add alias for lodash-es camelcase import.

* fix: add patch-package support for fixing quill

* feat: add patch-package on postinstall

* fix: update quill patch path.

* refactor: rename quill patch

* fix: update quill version.

* fix: update quill patch

* fix: fix linting rules after installing eslint in design-system

* fix: update date picker button to have primary color

* test: update callout component snapshots

* fix(editor): fix linting issues in editor after enabling eslint

* fix(cli): add /assets/* to auth ignore endpoints in server

* chore: update package-lock.json

* chore: update package-lock.json

* fix(editor): fix linting issues

* feat: add vite-legacy support

* fix: update workflow package interface imports to type imports.

* chore: update package-lock.json

* fix(editor) fix importing translations other than english

* fix(editor): remove test command until vitest is added

* fix: increase memory allocation for vite build

* fix: add patch-package patches to n8n-custom docker build

* fix: add performance and load time improvements

* fix: add proper typing to setNodeType

* chore: update package-lock.json

* style: use generic type for reduce in setNodeType

Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
This commit is contained in:
Alex Grozav 2022-09-23 17:14:28 +03:00 committed by GitHub
parent e709cb5fe2
commit 27e2ce0470
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
248 changed files with 6220 additions and 10845 deletions

View file

@ -9,6 +9,7 @@ RUN \
COPY turbo.json package.json package-lock.json tsconfig.json ./
COPY packages ./packages
COPY patches ./patches
RUN chown -R node:node .
RUN npm config set legacy-peer-deps true

15698
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -11,6 +11,7 @@
"lint": "turbo run lint",
"lintfix": "turbo run lintfix",
"optimize-svg": "find ./packages -name '*.svg' ! -name 'pipedrive.svg' -print0 | xargs -0 -P16 -L20 npx svgo",
"postinstall": "patch-package",
"start": "run-script-os",
"start:default": "cd packages/cli/bin && ./n8n",
"start:tunnel": "./packages/cli/bin/n8n start --tunnel",
@ -21,6 +22,7 @@
"worker": "./packages/cli/bin/n8n worker"
},
"devDependencies": {
"patch-package": "^6.4.7",
"rimraf": "^3.0.2",
"run-script-os": "^1.0.7",
"turbo": "1.2.15"

View file

@ -147,6 +147,7 @@ import {
WebhookServer,
WorkflowExecuteAdditionalData,
} from '.';
import glob from 'fast-glob';
import { ResponseError } from './ResponseHelper';
require('body-parser-xml')(bodyParser);
@ -389,6 +390,7 @@ class App {
const excludeEndpoints = config.getEnv('security.excludeEndpoints');
const ignoredEndpoints = [
'assets',
'healthz',
'metrics',
this.endpointWebhook,
@ -1753,11 +1755,28 @@ class App {
const editorUiPath = require.resolve('n8n-editor-ui');
const filePath = pathJoin(pathDirname(editorUiPath), 'dist', 'index.html');
const n8nPath = config.getEnv('path');
const basePathRegEx = /\/%BASE_PATH%\//g;
let readIndexFile = readFileSync(filePath, 'utf8');
readIndexFile = readIndexFile.replace(/\/%BASE_PATH%\//g, n8nPath);
readIndexFile = readIndexFile.replace(basePathRegEx, n8nPath);
readIndexFile = readIndexFile.replace(/\/favicon.ico/g, `${n8nPath}favicon.ico`);
const cssPath = pathJoin(pathDirname(editorUiPath), 'dist', '**/*.css');
const cssFiles: Record<string, string> = {};
glob.sync(cssPath).forEach((filePath) => {
let readFile = readFileSync(filePath, 'utf8');
readFile = readFile.replace(basePathRegEx, n8nPath);
cssFiles[filePath.replace(pathJoin(pathDirname(editorUiPath), 'dist'), '')] = readFile;
});
const jsPath = pathJoin(pathDirname(editorUiPath), 'dist', '**/*.js');
const jsFiles: Record<string, string> = {};
glob.sync(jsPath).forEach((filePath) => {
let readFile = readFileSync(filePath, 'utf8');
readFile = readFile.replace(basePathRegEx, n8nPath);
jsFiles[filePath.replace(pathJoin(pathDirname(editorUiPath), 'dist'), '')] = readFile;
});
const hooksUrls = config.getEnv('externalFrontendHooksUrls');
let scriptsString = '';
@ -1793,6 +1812,14 @@ class App {
res.send(readIndexFile);
});
this.app.get('/assets/*.css', async (req: express.Request, res: express.Response) => {
res.type('text/css').send(cssFiles[req.url]);
});
this.app.get('/assets/*.js', async (req: express.Request, res: express.Response) => {
res.type('text/javascript').send(jsFiles[req.url]);
});
// Serve the website
this.app.use(
'/',

View file

@ -1,36 +0,0 @@
'use strict';
const gulp = require('gulp');
const sass = require('gulp-dart-sass');
const autoprefixer = require('gulp-autoprefixer');
const cleanCSS = require('gulp-clean-css');
gulp.task('build:theme', gulp.series([compileTheme, copyThemeFonts]));
gulp.task(
'watch:theme',
gulp.series([
'build:theme',
() => {
gulp.watch('./theme/src/**/*.scss', gulp.series(['build:theme']));
},
]),
);
function compileTheme() {
return gulp
.src('./theme/src/index.scss')
.pipe(sass.sync())
.pipe(
autoprefixer({
browsers: ['ie > 9', 'last 2 versions'],
cascade: false,
}),
)
.pipe(cleanCSS())
.pipe(gulp.dest('./theme/dist'));
}
function copyThemeFonts() {
return gulp.src('./theme/src/fonts/**').pipe(gulp.dest('./theme/dist/fonts'));
}

View file

@ -13,19 +13,15 @@
"url": "git+https://github.com/n8n-io/n8n.git"
},
"scripts": {
"build": "npm run build:theme",
"build:vue": "vite build",
"build": "vite build",
"build:vue:typecheck": "vue-tsc --emitDeclarationOnly",
"dev": "npm run watch:theme",
"test": "vitest run",
"test:ci": "vitest run --coverage",
"test:dev": "vitest",
"build:storybook": "build-storybook",
"storybook": "start-storybook -p 6006",
"lint": "tslint -p tsconfig.json -c tslint.json && eslint .",
"lintfix": "tslint --fix -p tsconfig.json -c tslint.json && eslint . --fix",
"build:theme": "gulp build:theme",
"watch:theme": "gulp watch:theme"
"lintfix": "tslint --fix -p tsconfig.json -c tslint.json && eslint . --fix"
},
"peerDependencies": {
"@fortawesome/fontawesome-svg-core": "1.x",
@ -54,10 +50,9 @@
"babel-loader": "^8.2.2",
"c8": "7.11.0",
"core-js": "^3.6.5",
"gulp": "^4.0.0",
"gulp-autoprefixer": "^4.0.0",
"gulp-clean-css": "^4.3.0",
"gulp-dart-sass": "^1.0.2",
"eslint": "^8.0.0",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-vue": "^7.16.0",
"jsdom": "19.0.0",
"markdown-it": "^12.3.2",
"markdown-it-emoji": "^2.0.0",

View file

@ -47,9 +47,9 @@ import Vue from 'vue';
export default Vue.extend({
name: 'n8n-action-toggle',
components: {
ElDropdown,
ElDropdownMenu,
ElDropdownItem,
ElDropdown, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
ElDropdownMenu, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
ElDropdownItem, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
N8nIcon,
},
props: {

View file

@ -45,7 +45,7 @@ export default Vue.extend({
},
},
components: {
Avatar,
Avatar, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
},
computed: {
initials() {

View file

@ -96,25 +96,25 @@ export default Vue.extend({
return this.disabled ? 'true' : 'false';
},
classes(): string {
return `button ${this.$style['button']} ${this.$style[this.type]}` +
return `button ${this.$style.button} ${this.$style[this.type]}` +
`${this.size ? ` ${this.$style[this.size]}` : ''}` +
`${this.outline ? ` ${this.$style['outline']}` : ''}` +
`${this.loading ? ` ${this.$style['loading']}` : ''}` +
`${this.outline ? ` ${this.$style.outline}` : ''}` +
`${this.loading ? ` ${this.$style.loading}` : ''}` +
`${this.float ? ` ${this.$style[`float-${this.float}`]}` : ''}` +
`${this.text ? ` ${this.$style['text']}` : ''}` +
`${this.disabled ? ` ${this.$style['disabled']}` : ''}` +
`${this.block ? ` ${this.$style['block']}` : ''}` +
`${this.active ? ` ${this.$style['active']}` : ''}` +
`${this.icon || this.loading ? ` ${this.$style['icon']}` : ''}` +
`${this.square ? ` ${this.$style['square']}` : ''}`;
`${this.text ? ` ${this.$style.text}` : ''}` +
`${this.disabled ? ` ${this.$style.disabled}` : ''}` +
`${this.block ? ` ${this.$style.block}` : ''}` +
`${this.active ? ` ${this.$style.active}` : ''}` +
`${this.icon || this.loading ? ` ${this.$style.icon}` : ''}` +
`${this.square ? ` ${this.$style.square}` : ''}`;
},
},
});
</script>
<style lang="scss" module>
@import '../../../theme/src/mixins/utils';
@import '../../../theme/src/common/var';
@import '../../css/mixins/utils';
@import '../../css/common/var';
.button {
display: inline-block;

View file

@ -0,0 +1,3 @@
import ElButton from "./ElButton.vue";
export default ElButton;

View file

@ -19,7 +19,6 @@
<script lang="ts">
import Vue from 'vue';
import N8nIcon from '../N8nIcon';
import N8nText from '../N8nText';
const CALLOUT_DEFAULT_ICONS: { [key: string]: string } = {
info: 'info-circle',
@ -32,7 +31,6 @@ export default Vue.extend({
name: 'n8n-callout',
components: {
N8nIcon,
N8nText,
},
props: {
theme: {
@ -43,14 +41,14 @@ export default Vue.extend({
},
icon: {
type: String,
default: 'info-circle'
default: 'info-circle',
},
},
computed: {
classes(): string[] {
return [
'n8n-callout',
this.$style['callout'],
this.$style.callout,
this.$style[this.theme],
];
},
@ -61,7 +59,7 @@ export default Vue.extend({
return this.icon;
},
}
},
});
</script>

View file

@ -6,7 +6,7 @@ exports[`components > N8nCallout > should render additional slots correctly 1`]
<div class=\\"_icon_p74de_40\\">
<n8n-icon-stub icon=\\"code-branch\\" size=\\"large\\"></n8n-icon-stub>
</div>
<n8n-text-stub size=\\"small\\" tag=\\"span\\">This is a secondary callout.</n8n-text-stub>&nbsp; <n8n-link-stub size=\\"small\\">Do something!</n8n-link-stub>
<n8n-text-stub size=\\"small\\">This is a secondary callout.</n8n-text-stub>&nbsp; <n8n-link-stub size=\\"small\\">Do something!</n8n-link-stub>
</div>
<n8n-link-stub theme=\\"secondary\\" size=\\"small\\" bold=\\"true\\" underline=\\"true\\" to=\\"https://n8n.io\\">Learn more</n8n-link-stub>
</div>"
@ -18,7 +18,7 @@ exports[`components > N8nCallout > should render custom theme correctly 1`] = `
<div class=\\"_icon_p74de_40\\">
<n8n-icon-stub icon=\\"code-branch\\" size=\\"large\\"></n8n-icon-stub>
</div>
<n8n-text-stub size=\\"small\\" tag=\\"span\\">This is a secondary callout.</n8n-text-stub>&nbsp;
<n8n-text-stub size=\\"small\\">This is a secondary callout.</n8n-text-stub>&nbsp;
</div>
</div>"
`;
@ -29,7 +29,7 @@ exports[`components > N8nCallout > should render danger theme correctly 1`] = `
<div class=\\"_icon_p74de_40\\">
<n8n-icon-stub icon=\\"times-circle\\" size=\\"large\\"></n8n-icon-stub>
</div>
<n8n-text-stub size=\\"small\\" tag=\\"span\\">This is a danger callout.</n8n-text-stub>&nbsp;
<n8n-text-stub size=\\"small\\">This is a danger callout.</n8n-text-stub>&nbsp;
</div>
</div>"
`;
@ -40,7 +40,7 @@ exports[`components > N8nCallout > should render info theme correctly 1`] = `
<div class=\\"_icon_p74de_40\\">
<n8n-icon-stub icon=\\"info-circle\\" size=\\"large\\"></n8n-icon-stub>
</div>
<n8n-text-stub size=\\"small\\" tag=\\"span\\">This is an info callout.</n8n-text-stub>&nbsp;
<n8n-text-stub size=\\"small\\">This is an info callout.</n8n-text-stub>&nbsp;
</div>
</div>"
`;
@ -51,7 +51,7 @@ exports[`components > N8nCallout > should render secondary theme correctly 1`] =
<div class=\\"_icon_p74de_40\\">
<n8n-icon-stub icon=\\"info-circle\\" size=\\"medium\\"></n8n-icon-stub>
</div>
<n8n-text-stub size=\\"small\\" tag=\\"span\\">This is a secondary callout.</n8n-text-stub>&nbsp;
<n8n-text-stub size=\\"small\\">This is a secondary callout.</n8n-text-stub>&nbsp;
</div>
</div>"
`;
@ -62,7 +62,7 @@ exports[`components > N8nCallout > should render success theme correctly 1`] = `
<div class=\\"_icon_p74de_40\\">
<n8n-icon-stub icon=\\"check-circle\\" size=\\"large\\"></n8n-icon-stub>
</div>
<n8n-text-stub size=\\"small\\" tag=\\"span\\">This is a success callout.</n8n-text-stub>&nbsp;
<n8n-text-stub size=\\"small\\">This is a success callout.</n8n-text-stub>&nbsp;
</div>
</div>"
`;
@ -73,7 +73,7 @@ exports[`components > N8nCallout > should render warning theme correctly 1`] = `
<div class=\\"_icon_p74de_40\\">
<n8n-icon-stub icon=\\"exclamation-triangle\\" size=\\"large\\"></n8n-icon-stub>
</div>
<n8n-text-stub size=\\"small\\" tag=\\"span\\">This is a warning callout.</n8n-text-stub>&nbsp;
<n8n-text-stub size=\\"small\\">This is a warning callout.</n8n-text-stub>&nbsp;
</div>
</div>"
`;

View file

@ -24,7 +24,7 @@ import N8nInputLabel from '../N8nInputLabel';
export default Vue.extend({
name: 'n8n-checkbox',
components: {
ElCheckbox,
ElCheckbox, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
N8nInputLabel,
},
props: {
@ -59,7 +59,7 @@ export default Vue.extend({
onChange(event: Event) {
this.$emit("input", event);
},
}
},
});
</script>

View file

@ -179,7 +179,7 @@ export default mixins(Locale).extend({
},
methods: {
getValidationError(): ReturnType<IValidator['validate']> {
const rules = (this.validationRules || []) as (Rule | RuleGroup)[];
const rules = (this.validationRules || []) as Array<Rule | RuleGroup>;
const validators = {
...VALIDATORS,
...(this.validators || {}),

View file

@ -67,7 +67,7 @@ export default Vue.extend({
});
if (this.eventBus) {
this.eventBus.$on('submit', this.onSubmit);
this.eventBus.$on('submit', this.onSubmit); // eslint-disable-line @typescript-eslint/unbound-method
}
},
computed: {
@ -75,11 +75,11 @@ export default Vue.extend({
return (this.inputs as IFormInput[]).filter(
(input) => typeof input.shouldDisplay === 'function'
? input.shouldDisplay(this.values)
: true
: true,
);
},
isReadyToSubmit(): boolean {
for (let key in this.validity) {
for (const key in this.validity) {
if (!this.validity[key]) {
return false;
}
@ -92,9 +92,9 @@ export default Vue.extend({
onInput(name: string, value: any) {
this.values = {
...this.values,
[name]: value,
[name]: value, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
};
this.$emit('input', {name, value});
this.$emit('input', {name, value}); // eslint-disable-line @typescript-eslint/no-unsafe-assignment
},
onValidate(name: string, valid: boolean) {
Vue.set(this.validity, name, valid);
@ -102,7 +102,7 @@ export default Vue.extend({
onSubmit() {
this.showValidationWarnings = true;
if (this.isReadyToSubmit) {
const toSubmit = (this.filteredInputs as IFormInput[]).reduce<{ [key: string]: unknown }>((accu, input) => {
const toSubmit = (this.filteredInputs ).reduce<{ [key: string]: unknown }>((accu, input) => {
if (this.values[input.name]) {
accu[input.name] = this.values[input.name];
}

View file

@ -47,7 +47,7 @@ export default Vue.extend({
applied.push(this.bold? 'bold': 'regular');
return applied.map((c) => (this.$style as { [key: string]: string })[c]);
}
},
},
});
</script>

View file

@ -29,7 +29,7 @@ import Vue from 'vue';
export default Vue.extend({
name: 'n8n-input',
components: {
ElInput,
ElInput, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
},
props: {
value: {

View file

@ -1,7 +1,7 @@
<script lang="ts">
import N8nInputNumber from 'element-ui/lib/input-number';
N8nInputNumber.name = 'n8n-input-number';
N8nInputNumber.name = 'n8n-input-number'; // eslint-disable-line @typescript-eslint/no-unsafe-member-access
export default N8nInputNumber;
</script>

View file

@ -48,8 +48,8 @@ import Vue from 'vue';
export default Vue.extend({
name: 'n8n-loading',
components: {
ElSkeleton,
ElSkeletonItem,
ElSkeleton, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
ElSkeletonItem, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
},
props: {
animated: {

View file

@ -25,9 +25,13 @@
<script lang="ts">
import N8nLoading from '../N8nLoading';
import Markdown from 'markdown-it';
const markdownLink = require('markdown-it-link-attributes');
const markdownEmoji = require('markdown-it-emoji');
const markdownTasklists = require('markdown-it-task-lists');
// @ts-ignore
import markdownLink from 'markdown-it-link-attributes';
// @ts-ignore
import markdownEmoji from 'markdown-it-emoji';
// @ts-ignore
import markdownTasklists from 'markdown-it-task-lists';
import xss, { friendlyAttrValue } from 'xss';
import { escapeMarkdown } from '../../utils/markdown';
@ -143,8 +147,8 @@ export default Vue.extend({
}
// Return nothing, means keep the default handling measure
},
onTag: function (tag, html, options) {
if (tag === 'img' && html.includes(`alt="workflow-screenshot"`)) {
onTag (tag, code, options) {
if (tag === 'img' && code.includes(`alt="workflow-screenshot"`)) {
return '';
}
// return nothing, keep tag
@ -156,10 +160,10 @@ export default Vue.extend({
},
data() {
return {
md: new Markdown(this.options.markdown)
.use(markdownLink, this.options.linkAttributes)
md: new Markdown(this.options.markdown) // eslint-disable-line @typescript-eslint/no-unsafe-member-access
.use(markdownLink, this.options.linkAttributes) // eslint-disable-line @typescript-eslint/no-unsafe-member-access
.use(markdownEmoji)
.use(markdownTasklists, this.options.tasklists),
.use(markdownTasklists, this.options.tasklists), // eslint-disable-line @typescript-eslint/no-unsafe-member-access
};
},
methods: {
@ -177,8 +181,8 @@ export default Vue.extend({
}
}
this.$emit('markdown-click', clickedLink, event);
}
}
},
},
});
</script>

View file

@ -37,7 +37,7 @@ export default Vue.extend({
},
},
components: {
ElMenu,
ElMenu, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
},
});
</script>

View file

@ -1,7 +1,7 @@
<script lang="ts">
import ElMenuItem from 'element-ui/lib/menu-item';
ElMenuItem.name = 'n8n-menu-item';
ElMenuItem.name = 'n8n-menu-item'; // eslint-disable-line @typescript-eslint/no-unsafe-member-access
export default ElMenuItem;
</script>

View file

@ -58,7 +58,7 @@ export default Vue.extend({
classes(): string[] {
return [
'notice',
this.$style['notice'],
this.$style.notice,
this.$style[this.theme],
];
},

View file

@ -1,7 +1,7 @@
<script lang="ts">
import ElOption from 'element-ui/lib/option';
ElOption.name = 'n8n-option';
ElOption.name = 'n8n-option'; // eslint-disable-line @typescript-eslint/no-unsafe-member-access
export default ElOption;
</script>

View file

@ -1,7 +1,7 @@
<script lang="ts">
import ElPopover from 'element-ui/lib/popover';
ElPopover.name = 'n8n-popover';
ElPopover.name = 'n8n-popover'; // eslint-disable-line @typescript-eslint/no-unsafe-member-access
export default ElPopover;
</script>

View file

@ -12,6 +12,7 @@
</template>
<script lang="ts">
/* eslint-disable @typescript-eslint/unbound-method */
import Vue from 'vue';
function closestNumber(value: number, divisor: number): number {
@ -94,7 +95,7 @@ export default Vue.extend({
enabledDirections() {
const availableDirections = Object.keys(directionsCursorMaps);
if(this.isResizingEnabled === false) return [];
if(!this.isResizingEnabled) return [];
if(this.supportedDirections.length === 0) return availableDirections;
return this.supportedDirections;

View file

@ -39,7 +39,7 @@ export default Vue.extend({
return false;
}
if (typeof this.to === 'string') {
return this.to.startsWith('/');
return (this.to as string).startsWith('/');
}
return this.to !== undefined;
@ -49,7 +49,7 @@ export default Vue.extend({
return this.newWindow;
}
if (typeof this.to === 'string') {
return !this.to.startsWith('/');
return !(this.to as string).startsWith('/');
}
return true;
},

View file

@ -38,7 +38,7 @@ export interface IProps {
export default Vue.extend({
name: 'n8n-select',
components: {
ElSelect,
ElSelect, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
},
props: {
value: {

View file

@ -23,13 +23,13 @@ export default Vue.extend({
props: {
size: {
type: String,
validator: function (value: string): boolean {
validator (value: string): boolean {
return ['small', 'medium', 'large'].includes(value);
},
},
type: {
type: String,
validator: function (value: string): boolean {
validator (value: string): boolean {
return ['dots', 'ring'].includes(value);
},
default: 'dots',

View file

@ -144,8 +144,8 @@ export default mixins(Locale).extend({
},
styles(): { height: string, width: string } {
return {
height: this.resHeight + 'px',
width: this.resWidth + 'px',
height: `${this.resHeight}px`,
width: `${this.resWidth}px`,
};
},
shouldShowFooter(): boolean {

View file

@ -57,7 +57,8 @@ export default Vue.extend({
const width = container.clientWidth;
const scrollWidth = container.scrollWidth;
// @ts-ignore
this.scrollPosition = event.srcElement.scrollLeft;
this.scrollPosition = event.srcElement.scrollLeft; // eslint-disable-line @typescript-eslint/no-unsafe-assignment
this.canScrollRight = scrollWidth - width > this.scrollPosition;
});

View file

@ -55,7 +55,7 @@ export default Vue.extend({
applied.push(this.bold? 'bold': 'regular');
return applied.map((c) => (this.$style as { [key: string]: string })[c]);
}
},
},
});
</script>

View file

@ -1,7 +1,7 @@
<script lang="ts">
import ElTooltip from 'element-ui/lib/tooltip';
ElTooltip.name = 'n8n-tooltip';
ElTooltip.name = 'n8n-tooltip'; // eslint-disable-line @typescript-eslint/no-unsafe-member-access
export default ElTooltip;
</script>

View file

@ -29,6 +29,7 @@
</template>
<script lang="ts">
/* tslint:disable: @typescript-eslint/no-unsafe-assignment */
import Vue from 'vue';
import N8nUserInfo from '../N8nUserInfo';
import { IUser } from '../../types';
@ -42,8 +43,8 @@ export default mixins(Locale).extend({
name: 'n8n-user-select',
components: {
N8nUserInfo,
ElSelect,
ElOption,
ElSelect, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
ElOption, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
},
props: {
users: {
@ -104,7 +105,7 @@ export default mixins(Locale).extend({
});
},
sortedUsers(): IUser[] {
return [...(this.fitleredUsers as IUser[])].sort((a: IUser, b: IUser) => {
return [...(this.fitleredUsers )].sort((a: IUser, b: IUser) => {
if (a.lastName && b.lastName && a.lastName !== b.lastName) {
return a.lastName > b.lastName ? 1 : -1;
}

View file

@ -36,6 +36,11 @@ import Locale from '../../mixins/locale';
import mixins from 'vue-typed-mixins';
import { t } from '../../locale';
export interface IUserListAction {
label: string;
value: string;
}
export default mixins(Locale).extend({
name: 'n8n-users-list',
components: {
@ -102,19 +107,19 @@ export default mixins(Locale).extend({
}
}
return a.email! > b.email! ? 1 : -1;
return a.email > b.email ? 1 : -1;
});
},
},
methods: {
getActions(user: IUser): Array<{ label: string, value: string }> {
const DELETE = {
label: this.deleteLabel,
getActions(user: IUser): IUserListAction[] {
const DELETE: IUserListAction = {
label: this.deleteLabel as string,
value: 'delete',
};
const REINVITE = {
label: this.reinviteLabel,
const REINVITE: IUserListAction = {
label: this.reinviteLabel as string,
value: 'reinvite',
};

View file

@ -64,7 +64,7 @@ export default Vue.extend({
},
beforeDestroy() {
if (this.$props.enabled) {
this.$data.observer.disconnect();
this.$data.observer.disconnect(); // eslint-disable-line
}
},
});

View file

@ -0,0 +1,3 @@
@forward "common/var.scss";
@import "common/transition.scss";
@import "icon.scss";

View file

@ -10,3 +10,12 @@
@use "./input.scss";
@use "./scrollbar.scss";
@use "./popper";
.el-picker-panel__footer {
.el-picker-panel__link-btn {
&:last-child {
background: var(--color-primary);
color: var(--color-foreground-xlight)
}
}
}

Some files were not shown because too many files have changed in this diff Show more