From 4d3ff091aa1c06032ce41ec5d82ee5c445a29687 Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Mon, 5 Apr 2021 09:21:58 -0300 Subject: [PATCH 01/97] feat: docker images Signed-off-by: Carlos Alexandro Becker --- .editorconfig | 6 +++- .github/workflows/docker-images-rpi.yml | 40 ------------------------- .github/workflows/docker-images.yml | 35 +++++++++++++--------- docker/images/n8n-rpi/Dockerfile | 21 ------------- docker/images/n8n-rpi/README.md | 22 -------------- docker/images/n8n/README.md | 4 +-- 6 files changed, 28 insertions(+), 100 deletions(-) delete mode 100644 .github/workflows/docker-images-rpi.yml delete mode 100644 docker/images/n8n-rpi/Dockerfile delete mode 100644 docker/images/n8n-rpi/README.md diff --git a/.editorconfig b/.editorconfig index 5d02a5688b..c6f30f2512 100644 --- a/.editorconfig +++ b/.editorconfig @@ -12,4 +12,8 @@ indent_style = space indent_size = 2 [*.ts] -quote_type = single \ No newline at end of file +quote_type = single + +[*.yml] +indent_style = space +indent_size = 2 diff --git a/.github/workflows/docker-images-rpi.yml b/.github/workflows/docker-images-rpi.yml deleted file mode 100644 index 1eeb66ecdb..0000000000 --- a/.github/workflows/docker-images-rpi.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Docker Image CI - Rpi - -on: - push: - tags: - - n8n@* - workflow_dispatch: - inputs: - version: - description: 'n8n version to build docker image for.' - required: true - default: '0.112.0' - -jobs: - armv7_job: - runs-on: ubuntu-18.04 - name: Build on ARMv7 (Rpi) - steps: - - uses: actions/checkout@v1 - - name: Get the version - id: vars - run: echo ::set-output name=tag::$(echo ${GITHUB_REF:14}) - - - name: Log in to Docker registry - run: docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }} - - - name: Set up Docker Buildx - uses: crazy-max/ghaction-docker-buildx@v3 - with: - buildx-version: latest - qemu-version: latest - - name: Run Buildx (push image) - if: success() - run: | - docker buildx build \ - --platform linux/arm/v7 \ - --build-arg N8N_VERSION=${{github.event.inputs.version || steps.vars.outputs.tag}} \ - -t ${{ secrets.DOCKER_USERNAME }}/n8n:${{github.event.inputs.version || steps.vars.outputs.tag}}-rpi \ - -t ${{ secrets.DOCKER_USERNAME }}/n8n:latest-rpi \ - --output type=image,push=true docker/images/n8n-rpi diff --git a/.github/workflows/docker-images.yml b/.github/workflows/docker-images.yml index 1a9b81d09f..a6d8496772 100644 --- a/.github/workflows/docker-images.yml +++ b/.github/workflows/docker-images.yml @@ -19,20 +19,27 @@ jobs: - name: Log in to Docker registry run: docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }} + - name: Set up Docker Buildx + uses: crazy-max/ghaction-docker-buildx@v3 + with: + buildx-version: latest + qemu-version: latest + - name: Build the Docker image of version - run: docker build --build-arg N8N_VERSION=${{steps.vars.outputs.tag}} -t n8nio/n8n:${{steps.vars.outputs.tag}} docker/images/n8n - - name: Push Docker image of version - run: docker push n8nio/n8n:${{steps.vars.outputs.tag}} - - name: Tag Docker image with latest - run: docker tag n8nio/n8n:${{steps.vars.outputs.tag}} n8nio/n8n:latest - - name: Push docker images of latest - run: docker push n8nio/n8n:latest + if: success() + run: | + docker buildx build \ + --platform linux/amd64,linux/arm64,linux/arm/v7 \ + --build-arg N8N_VERSION=${{steps.vars.outputs.tag}} \ + -t ${{ secrets.DOCKER_USERNAME }}/n8n:${{steps.vars.outputs.tag}} \ + -t ${{ secrets.DOCKER_USERNAME }}/n8n:latest \ + --output type=image,push=true docker/images/n8n - name: Build the Docker image of version (Debian) - run: docker build --build-arg N8N_VERSION=${{steps.vars.outputs.tag}} -t n8nio/n8n:${{steps.vars.outputs.tag}}-debian docker/images/n8n-debian - - name: Push Docker image of version (Debian) - run: docker push n8nio/n8n:${{steps.vars.outputs.tag}}-debian - - name: Tag Docker image with latest (Debian) - run: docker tag n8nio/n8n:${{steps.vars.outputs.tag}}-debian n8nio/n8n:latest-debian - - name: Push docker images of latest (Debian) - run: docker push n8nio/n8n:latest-debian + run: | + docker buildx build \ + --platform linux/amd64 \ + --build-arg N8N_VERSION=${{steps.vars.outputs.tag}} \ + -t ${{ secrets.DOCKER_USERNAME }}/n8n:${{steps.vars.outputs.tag}}-debian \ + -t ${{ secrets.DOCKER_USERNAME }}/n8n:latest-debian \ + --output type=image,push=true docker/images/n8n-debian diff --git a/docker/images/n8n-rpi/Dockerfile b/docker/images/n8n-rpi/Dockerfile deleted file mode 100644 index 329b7e7dfe..0000000000 --- a/docker/images/n8n-rpi/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -FROM arm32v7/node:14.15 - -ARG N8N_VERSION - -RUN if [ -z "$N8N_VERSION" ] ; then echo "The N8N_VERSION argument is missing!" ; exit 1; fi - -RUN \ - apt-get update && \ - apt-get -y install graphicsmagick gosu - -RUN npm_config_user=root npm install -g full-icu n8n@${N8N_VERSION} - -ENV NODE_ICU_DATA /usr/local/lib/node_modules/full-icu -ENV NODE_ENV production - -WORKDIR /data - -USER root - -CMD chown -R node:node /home/node/.n8n \ -&& gosu node n8n diff --git a/docker/images/n8n-rpi/README.md b/docker/images/n8n-rpi/README.md deleted file mode 100644 index cc15b0c9d8..0000000000 --- a/docker/images/n8n-rpi/README.md +++ /dev/null @@ -1,22 +0,0 @@ -## n8n - Raspberry PI Docker Image - -Dockerfile to build n8n for Raspberry PI. - -For information about how to run n8n with Docker check the generic -[Docker-Readme](https://github.com/n8n-io/n8n/tree/master/docker/images/n8n/README.md) - - -``` -docker build --build-arg N8N_VERSION= -t n8nio/n8n: . - -# For example: -docker build --build-arg N8N_VERSION=0.43.0 -t n8nio/n8n:0.43.0-rpi . -``` - -``` -docker run -it --rm \ - --name n8n \ - -p 5678:5678 \ - -v ~/.n8n:/home/node/.n8n \ - n8nio/n8n:0.70.0-rpi -``` diff --git a/docker/images/n8n/README.md b/docker/images/n8n/README.md index ef0d7123e7..4c0fff5ceb 100644 --- a/docker/images/n8n/README.md +++ b/docker/images/n8n/README.md @@ -226,10 +226,10 @@ docker run -it --rm \ ## Build Docker-Image ``` -docker build --build-arg N8N_VERSION= -t n8nio/n8n: . +docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 --build-arg N8N_VERSION= -t n8nio/n8n: . # For example: -docker build --build-arg N8N_VERSION=0.18.1 -t n8nio/n8n:0.18.1 . +docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 --build-arg N8N_VERSION=0.114.0 -t n8nio/n8n:0.114.0 . ``` From 061e990d87dd1da1b5a136b9cfeaa31c9c316db8 Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Mon, 5 Apr 2021 10:22:04 -0300 Subject: [PATCH 02/97] fix: workflow Signed-off-by: Carlos Alexandro Becker --- .github/workflows/docker-images.yml | 57 +++++++++++++++-------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/.github/workflows/docker-images.yml b/.github/workflows/docker-images.yml index a6d8496772..8b9e32e0bf 100644 --- a/.github/workflows/docker-images.yml +++ b/.github/workflows/docker-images.yml @@ -6,40 +6,41 @@ on: - n8n@* jobs: - build: - runs-on: ubuntu-latest - steps: - uses: actions/checkout@v1 - name: Get the version id: vars run: echo ::set-output name=tag::$(echo ${GITHUB_REF:14}) - - name: Log in to Docker registry - run: docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }} - + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx - uses: crazy-max/ghaction-docker-buildx@v3 + uses: docker/setup-buildx-action@v1 + - name: Login to DockerHub + uses: docker/login-action@v1 with: - buildx-version: latest - qemu-version: latest - - - name: Build the Docker image of version - if: success() - run: | - docker buildx build \ - --platform linux/amd64,linux/arm64,linux/arm/v7 \ - --build-arg N8N_VERSION=${{steps.vars.outputs.tag}} \ - -t ${{ secrets.DOCKER_USERNAME }}/n8n:${{steps.vars.outputs.tag}} \ - -t ${{ secrets.DOCKER_USERNAME }}/n8n:latest \ - --output type=image,push=true docker/images/n8n - - - name: Build the Docker image of version (Debian) - run: | - docker buildx build \ - --platform linux/amd64 \ - --build-arg N8N_VERSION=${{steps.vars.outputs.tag}} \ - -t ${{ secrets.DOCKER_USERNAME }}/n8n:${{steps.vars.outputs.tag}}-debian \ - -t ${{ secrets.DOCKER_USERNAME }}/n8n:latest-debian \ - --output type=image,push=true docker/images/n8n-debian + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + - name: Build + uses: docker/build-push-action@v2 + with: + context: ./docker/images/n8n + build-args: | + N8N_VERSION=${{steps.vars.outputs.tag}} + platforms: linux/amd64,linux/arm64,linux/arm/v7 + push: true + tags: | + ${{ secrets.DOCKER_USERNAME }}/n8n:${{ steps.vars.outputs.tag }} + ${{ secrets.DOCKER_USERNAME }}/n8n:latest + - name: Build (debian) + uses: docker/build-push-action@v2 + with: + context: ./docker/images/n8n-debian + build-args: | + N8N_VERSION=${{ steps.vars.outputs.tag }} + platforms: linux/amd64,linux/arm64,linux/arm/v7 + push: true + tags: | + ${{ secrets.DOCKER_USERNAME }}/n8n:${{ steps.vars.outputs.tag }}-debian + ${{ secrets.DOCKER_USERNAME }}/n8n:latest-debian From 3667b0dd01f82046549b795b98b88983bd7c7fbb Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 5 Jun 2021 15:43:54 -0500 Subject: [PATCH 03/97] :sparkles: Add Git node (#1820) * :sparkles: Add Git-Node * :shirt: Fix lint issue * :art: add git icon * :zap: Fix indentation in package.json files * :zap: Add support for pushTags * :zap: Add support for addConfig, fetch, listConfig and status * :zap: Add support for clone * :zap: Remove not needed code * :zap: Add proper continueOnFail support & alphabetize options * :bug: Remove console.log * :zap: Improve Git Node * :zap: Improve Git Node * :whale: Add git to Docker images * :zap: Auto create folder if not exists and clarify addConfig mode Co-authored-by: Ben Hesseldieck --- docker/images/n8n-custom/Dockerfile | 2 +- docker/images/n8n-debian/Dockerfile | 2 +- docker/images/n8n-rpi/Dockerfile | 2 +- .../credentials/GitPassword.credentials.ts | 28 ++ packages/nodes-base/nodes/Git/Git.node.ts | 437 ++++++++++++++++++ .../Git/descriptions/AddConfigDescription.ts | 71 +++ .../nodes/Git/descriptions/AddDescription.ts | 22 + .../Git/descriptions/CloneDescription.ts | 22 + .../Git/descriptions/CommitDescription.ts | 45 ++ .../nodes/Git/descriptions/LogDescription.ts | 64 +++ .../nodes/Git/descriptions/PushDescription.ts | 30 ++ .../nodes/Git/descriptions/TagDescription.ts | 21 + .../nodes/Git/descriptions/index.ts | 7 + packages/nodes-base/nodes/Git/git.svg | 15 + packages/nodes-base/package.json | 3 + 15 files changed, 768 insertions(+), 3 deletions(-) create mode 100644 packages/nodes-base/credentials/GitPassword.credentials.ts create mode 100644 packages/nodes-base/nodes/Git/Git.node.ts create mode 100644 packages/nodes-base/nodes/Git/descriptions/AddConfigDescription.ts create mode 100644 packages/nodes-base/nodes/Git/descriptions/AddDescription.ts create mode 100644 packages/nodes-base/nodes/Git/descriptions/CloneDescription.ts create mode 100644 packages/nodes-base/nodes/Git/descriptions/CommitDescription.ts create mode 100644 packages/nodes-base/nodes/Git/descriptions/LogDescription.ts create mode 100644 packages/nodes-base/nodes/Git/descriptions/PushDescription.ts create mode 100644 packages/nodes-base/nodes/Git/descriptions/TagDescription.ts create mode 100644 packages/nodes-base/nodes/Git/descriptions/index.ts create mode 100644 packages/nodes-base/nodes/Git/git.svg diff --git a/docker/images/n8n-custom/Dockerfile b/docker/images/n8n-custom/Dockerfile index 05d08a7db5..9136e15b17 100644 --- a/docker/images/n8n-custom/Dockerfile +++ b/docker/images/n8n-custom/Dockerfile @@ -29,7 +29,7 @@ FROM node:14.15-alpine USER root -RUN apk add --update graphicsmagick tzdata tini su-exec +RUN apk add --update graphicsmagick tzdata tini su-exec git WORKDIR /data diff --git a/docker/images/n8n-debian/Dockerfile b/docker/images/n8n-debian/Dockerfile index bfe10565aa..95c79828e4 100644 --- a/docker/images/n8n-debian/Dockerfile +++ b/docker/images/n8n-debian/Dockerfile @@ -6,7 +6,7 @@ RUN if [ -z "$N8N_VERSION" ] ; then echo "The N8N_VERSION argument is missing!" RUN \ apt-get update && \ - apt-get -y install graphicsmagick gosu + apt-get -y install graphicsmagick gosu git # Set a custom user to not have n8n run as root USER root diff --git a/docker/images/n8n-rpi/Dockerfile b/docker/images/n8n-rpi/Dockerfile index 329b7e7dfe..8a3f94838e 100644 --- a/docker/images/n8n-rpi/Dockerfile +++ b/docker/images/n8n-rpi/Dockerfile @@ -6,7 +6,7 @@ RUN if [ -z "$N8N_VERSION" ] ; then echo "The N8N_VERSION argument is missing!" RUN \ apt-get update && \ - apt-get -y install graphicsmagick gosu + apt-get -y install graphicsmagick gosu git RUN npm_config_user=root npm install -g full-icu n8n@${N8N_VERSION} diff --git a/packages/nodes-base/credentials/GitPassword.credentials.ts b/packages/nodes-base/credentials/GitPassword.credentials.ts new file mode 100644 index 0000000000..aae97789d5 --- /dev/null +++ b/packages/nodes-base/credentials/GitPassword.credentials.ts @@ -0,0 +1,28 @@ +import { + ICredentialType, + NodePropertyTypes, +} from 'n8n-workflow'; + +export class GitPassword implements ICredentialType { + name = 'gitPassword'; + displayName = 'Git'; + properties = [ + { + displayName: 'Username', + name: 'username', + type: 'string' as NodePropertyTypes, + default: '', + decription: 'The username to authenticate with.', + }, + { + displayName: 'Password', + name: 'password', + type: 'string' as NodePropertyTypes, + typeOptions: { + password: true, + }, + default: '', + description: 'The password to use in combination with the user', + }, + ]; +} diff --git a/packages/nodes-base/nodes/Git/Git.node.ts b/packages/nodes-base/nodes/Git/Git.node.ts new file mode 100644 index 0000000000..f4e6ef4b16 --- /dev/null +++ b/packages/nodes-base/nodes/Git/Git.node.ts @@ -0,0 +1,437 @@ +import { IExecuteFunctions } from 'n8n-core'; +import { + IDataObject, + INodeExecutionData, + INodeType, + INodeTypeDescription, +} from 'n8n-workflow'; + +import { + addConfigFields, + addFields, + cloneFields, + commitFields, + logFields, + pushFields, + tagFields, +} from './descriptions'; + +import simpleGit, { + LogOptions, + SimpleGit, + SimpleGitOptions, +} from 'simple-git'; + +import { + access, + mkdir, +} from 'fs/promises'; + +import { URL } from 'url'; + +export class Git implements INodeType { + description: INodeTypeDescription = { + displayName: 'Git', + name: 'git', + icon: 'file:git.svg', + group: ['transform'], + version: 1, + description: 'Control git.', + defaults: { + name: 'Git', + color: '#808080', + }, + inputs: ['main'], + outputs: ['main'], + credentials: [ + { + name: 'gitPassword', + required: true, + displayOptions: { + show: { + authentication: [ + 'gitPassword', + ], + }, + }, + }, + ], + properties: [ + { + displayName: 'Authentication', + name: 'authentication', + type: 'options', + options: [ + { + name: 'Authenticate', + value: 'gitPassword', + }, + { + name: 'None', + value: 'none', + }, + ], + displayOptions: { + show: { + operation: [ + 'clone', + 'push', + ], + }, + }, + default: 'none', + description: 'The way to authenticate.', + }, + { + displayName: 'Operation', + name: 'operation', + type: 'options', + default: 'log', + description: 'Operation to perform', + options: [ + { + name: 'Add', + value: 'add', + description: 'Add a file or folder to commit', + }, + { + name: 'Add Config', + value: 'addConfig', + description: 'Add configuration property', + }, + { + name: 'Clone', + value: 'clone', + description: 'Clone a repository', + }, + { + name: 'Commit', + value: 'commit', + description: 'Commit files or folders to git', + }, + { + name: 'Fetch', + value: 'fetch', + description: 'Fetch from remote repository', + }, + { + name: 'List Config', + value: 'listConfig', + description: 'Return current configuration', + }, + { + name: 'Log', + value: 'log', + description: 'Return git commit history', + }, + { + name: 'Pull', + value: 'pull', + description: 'Pull from remote repository', + }, + { + name: 'Push', + value: 'push', + description: 'Push to remote repository', + }, + { + name: 'Push Tags', + value: 'pushTags', + description: 'Push Tags to remote repository', + }, + { + name: 'Status', + value: 'status', + description: 'Return status of current repository', + }, + { + name: 'Tag', + value: 'tag', + description: 'Create a new tag', + }, + { + name: 'User Setup', + value: 'userSetup', + description: 'Set the user', + }, + ], + }, + + { + displayName: 'Repository Path', + name: 'repositoryPath', + type: 'string', + displayOptions: { + hide: { + operation: [ + 'clone', + ], + }, + }, + default: '', + placeholder: '/tmp/repository', + required: true, + description: 'Local path of the git repository to operate on.', + }, + { + displayName: 'New Repository Path', + name: 'repositoryPath', + type: 'string', + displayOptions: { + show: { + operation: [ + 'clone', + ], + }, + }, + default: '', + placeholder: '/tmp/repository', + required: true, + description: 'Local path to which the git repository should be cloned into.', + }, + + ...addFields, + ...addConfigFields, + ...cloneFields, + ...commitFields, + ...logFields, + ...pushFields, + ...tagFields, + // ...userSetupFields, + ], + }; + + + async execute(this: IExecuteFunctions): Promise { + const items = this.getInputData(); + + + const prepareRepository = (repositoryPath: string): string => { + const authentication = this.getNodeParameter('authentication', 0) as string; + + if (authentication === 'gitPassword') { + const gitCredentials = this.getCredentials('gitPassword') as IDataObject; + + const url = new URL(repositoryPath); + url.username = gitCredentials.username as string; + url.password = gitCredentials.password as string; + + return url.toString(); + } + + return repositoryPath; + }; + + const operation = this.getNodeParameter('operation', 0) as string; + let item: INodeExecutionData; + const returnItems: INodeExecutionData[] = []; + for (let itemIndex = 0; itemIndex < items.length; itemIndex++) { + try { + item = items[itemIndex]; + + const repositoryPath = this.getNodeParameter('repositoryPath', itemIndex, '') as string; + const options = this.getNodeParameter('options', itemIndex, {}) as IDataObject; + + if (operation === 'clone') { + // Create repository folder if it does not exist + try { + await access(repositoryPath); + } catch (error) { + await mkdir(repositoryPath); + } + } + + const gitOptions: Partial = { + baseDir: repositoryPath, + }; + + const git: SimpleGit = simpleGit(gitOptions) + // Tell git not to ask for any information via the terminal like for + // example the username. As nobody will be able to answer it would + // n8n keep on waiting forever. + .env('GIT_TERMINAL_PROMPT', '0'); + + if (operation === 'add') { + // ---------------------------------- + // add + // ---------------------------------- + + const pathsToAdd = this.getNodeParameter('pathsToAdd', itemIndex, '') as string; + + await git.add(pathsToAdd.split(',')); + + returnItems.push({ json: { success: true } }); + + } else if (operation === 'addConfig') { + // ---------------------------------- + // addConfig + // ---------------------------------- + + const key = this.getNodeParameter('key', itemIndex, '') as string; + const value = this.getNodeParameter('value', itemIndex, '') as string; + let append = false; + + if (options.mode === 'append') { + append = true; + } + + await git.addConfig(key, value, append); + returnItems.push({ json: { success: true } }); + + } else if (operation === 'clone') { + // ---------------------------------- + // clone + // ---------------------------------- + + let sourceRepository = this.getNodeParameter('sourceRepository', itemIndex, '') as string; + sourceRepository = prepareRepository(sourceRepository); + + await git.clone(sourceRepository, '.'); + + returnItems.push({ json: { success: true } }); + + } else if (operation === 'commit') { + // ---------------------------------- + // commit + // ---------------------------------- + + const message = this.getNodeParameter('message', itemIndex, '') as string; + + let pathsToAdd: string[] | undefined = undefined; + if (options.files !== undefined) { + pathsToAdd = (options.pathsToAdd as string).split(','); + } + + await git.commit(message, pathsToAdd); + + returnItems.push({ json: { success: true } }); + + } else if (operation === 'fetch') { + // ---------------------------------- + // fetch + // ---------------------------------- + + await git.fetch(); + returnItems.push({ json: { success: true } }); + + } else if (operation === 'log') { + // ---------------------------------- + // log + // ---------------------------------- + + const logOptions: LogOptions = {}; + + const returnAll = this.getNodeParameter('returnAll', itemIndex, false) as boolean; + if (returnAll === false) { + logOptions.maxCount = this.getNodeParameter('limit', itemIndex, 100) as number; + } + if (options.file) { + logOptions.file = options.file as string; + } + + const log = await git.log(logOptions); + + // @ts-ignore + returnItems.push(...this.helpers.returnJsonArray(log.all)); + + } else if (operation === 'pull') { + // ---------------------------------- + // pull + // ---------------------------------- + + await git.pull(); + returnItems.push({ json: { success: true } }); + + } else if (operation === 'push') { + // ---------------------------------- + // push + // ---------------------------------- + + if (options.repository) { + const targetRepository = prepareRepository(options.targetRepository as string); + await git.push(targetRepository); + } else { + const authentication = this.getNodeParameter('authentication', 0) as string; + if (authentication === 'gitPassword') { + // Try to get remote repository path from git repository itself to add + // authentication data + const config = await git.listConfig(); + let targetRepository; + for (const fileName of Object.keys(config.values)) { + if (config.values[fileName]['remote.origin.url']) { + targetRepository = config.values[fileName]['remote.origin.url']; + break; + } + } + + targetRepository = prepareRepository(targetRepository as string); + await git.push(targetRepository); + } else { + await git.push(); + } + } + + returnItems.push({ json: { success: true } }); + + } else if (operation === 'pushTags') { + // ---------------------------------- + // pushTags + // ---------------------------------- + + await git.pushTags(); + returnItems.push({ json: { success: true } }); + + } else if (operation === 'listConfig') { + // ---------------------------------- + // listConfig + // ---------------------------------- + + const config = await git.listConfig(); + + const data = []; + for (const fileName of Object.keys(config.values)) { + data.push({ + _file: fileName, + ...config.values[fileName], + }); + } + + // @ts-ignore + returnItems.push(...this.helpers.returnJsonArray(data)); + + } else if (operation === 'status') { + // ---------------------------------- + // status + // ---------------------------------- + + const status = await git.status(); + + // @ts-ignore + returnItems.push(...this.helpers.returnJsonArray([status])); + + } else if (operation === 'tag') { + // ---------------------------------- + // tag + // ---------------------------------- + + const name = this.getNodeParameter('name', itemIndex, '') as string; + + await git.addTag(name); + returnItems.push({ json: { success: true } }); + + } + + } catch (error) { + + if (this.continueOnFail()) { + returnItems.push({ json: { error: error.toString() } }); + continue; + } + + throw error; + } + } + + return this.prepareOutputData(returnItems); + } +} diff --git a/packages/nodes-base/nodes/Git/descriptions/AddConfigDescription.ts b/packages/nodes-base/nodes/Git/descriptions/AddConfigDescription.ts new file mode 100644 index 0000000000..db336d5b9e --- /dev/null +++ b/packages/nodes-base/nodes/Git/descriptions/AddConfigDescription.ts @@ -0,0 +1,71 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const addConfigFields = [ + { + displayName: 'Key', + name: 'key', + type: 'string', + displayOptions: { + show: { + operation: [ + 'addConfig', + ], + }, + }, + default: '', + placeholder: 'user.email', + description: 'Name of the key to set.', + required: true, + }, + { + displayName: 'Value', + name: 'value', + type: 'string', + displayOptions: { + show: { + operation: [ + 'addConfig', + ], + }, + }, + default: '', + placeholder: 'name@example.com', + description: 'Value of the key to set.', + required: true, + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + displayOptions: { + show: { + operation: [ + 'addConfig', + ], + }, + }, + placeholder: 'Add Option', + default: {}, + options: [ + { + displayName: 'Mode', + name: 'mode', + type: 'options', + options: [ + { + name: 'Append', + value: 'append', + }, + { + name: 'Set', + value: 'set', + }, + ], + default: 'set', + description: 'Append setting rather than set it in the local config.', + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Git/descriptions/AddDescription.ts b/packages/nodes-base/nodes/Git/descriptions/AddDescription.ts new file mode 100644 index 0000000000..478d3f4de6 --- /dev/null +++ b/packages/nodes-base/nodes/Git/descriptions/AddDescription.ts @@ -0,0 +1,22 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const addFields = [ + { + displayName: 'Paths to Add', + name: 'pathsToAdd', + type: 'string', + displayOptions: { + show: { + operation: [ + 'add', + ], + }, + }, + default: '', + placeholder: 'README.md', + description: 'Comma separated list of paths (absolute or relative to Repository Path) of files or folders to add.', + required: true, + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Git/descriptions/CloneDescription.ts b/packages/nodes-base/nodes/Git/descriptions/CloneDescription.ts new file mode 100644 index 0000000000..21546e9eb5 --- /dev/null +++ b/packages/nodes-base/nodes/Git/descriptions/CloneDescription.ts @@ -0,0 +1,22 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const cloneFields = [ + { + displayName: 'Source Repository', + name: 'sourceRepository', + type: 'string', + displayOptions: { + show: { + operation: [ + 'clone', + ], + }, + }, + default: '', + placeholder: 'https://github.com/n8n-io/n8n', + description: 'The URL or path of the repository to clone.', + required: true, + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Git/descriptions/CommitDescription.ts b/packages/nodes-base/nodes/Git/descriptions/CommitDescription.ts new file mode 100644 index 0000000000..5f955a2a58 --- /dev/null +++ b/packages/nodes-base/nodes/Git/descriptions/CommitDescription.ts @@ -0,0 +1,45 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const commitFields = [ + { + displayName: 'Message', + name: 'message', + type: 'string', + displayOptions: { + show: { + operation: [ + 'commit', + ], + }, + }, + default: '', + description: 'The commit message to use.', + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + displayOptions: { + show: { + operation: [ + 'commit', + ], + }, + }, + placeholder: 'Add Option', + default: {}, + options: [ + { + displayName: 'Paths to Add', + name: 'pathsToAdd', + type: 'string', + default: '', + placeholder: '/data/file1.json', + description: `Comma separated list of paths (absolute or relative to Repository Path) of
+ files or folders to commit. If not set will all "added" files and folders be committed.`, + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Git/descriptions/LogDescription.ts b/packages/nodes-base/nodes/Git/descriptions/LogDescription.ts new file mode 100644 index 0000000000..f17e903e5d --- /dev/null +++ b/packages/nodes-base/nodes/Git/descriptions/LogDescription.ts @@ -0,0 +1,64 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const logFields = [ + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + operation: [ + 'log', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + operation: [ + 'log', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 100, + }, + default: 100, + description: 'How many results to return.', + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + displayOptions: { + show: { + operation: [ + 'log', + ], + }, + }, + placeholder: 'Add Option', + default: {}, + options: [ + { + displayName: 'File', + name: 'file', + type: 'string', + default: 'README.md', + description: 'The path (absolute or relative to Repository Path) of file or folder to get the history of.', + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Git/descriptions/PushDescription.ts b/packages/nodes-base/nodes/Git/descriptions/PushDescription.ts new file mode 100644 index 0000000000..797559b6d5 --- /dev/null +++ b/packages/nodes-base/nodes/Git/descriptions/PushDescription.ts @@ -0,0 +1,30 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const pushFields = [ + { + displayName: 'Options', + name: 'options', + type: 'collection', + displayOptions: { + show: { + operation: [ + 'push', + ], + }, + }, + placeholder: 'Add Option', + default: {}, + options: [ + { + displayName: 'Target Repository', + name: 'targetRepository', + type: 'string', + default: '', + placeholder: 'https://github.com/n8n-io/n8n', + description: 'The URL or path of the repository to push to.', + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Git/descriptions/TagDescription.ts b/packages/nodes-base/nodes/Git/descriptions/TagDescription.ts new file mode 100644 index 0000000000..bfd0f39fb0 --- /dev/null +++ b/packages/nodes-base/nodes/Git/descriptions/TagDescription.ts @@ -0,0 +1,21 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const tagFields = [ + { + displayName: 'Name', + name: 'name', + type: 'string', + displayOptions: { + show: { + operation: [ + 'tag', + ], + }, + }, + default: '', + description: 'The name of the tag to create.', + required: true, + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Git/descriptions/index.ts b/packages/nodes-base/nodes/Git/descriptions/index.ts new file mode 100644 index 0000000000..568f5df05e --- /dev/null +++ b/packages/nodes-base/nodes/Git/descriptions/index.ts @@ -0,0 +1,7 @@ +export * from './AddDescription'; +export * from './AddConfigDescription'; +export * from './CloneDescription'; +export * from './CommitDescription'; +export * from './LogDescription'; +export * from './PushDescription'; +export * from './TagDescription'; diff --git a/packages/nodes-base/nodes/Git/git.svg b/packages/nodes-base/nodes/Git/git.svg new file mode 100644 index 0000000000..2e42bc7d4d --- /dev/null +++ b/packages/nodes-base/nodes/Git/git.svg @@ -0,0 +1,15 @@ + + + + + + + + diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index a52a1781e6..3617a667f5 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -88,6 +88,7 @@ "dist/credentials/GetResponseOAuth2Api.credentials.js", "dist/credentials/GhostAdminApi.credentials.js", "dist/credentials/GhostContentApi.credentials.js", + "dist/credentials/GitPassword.credentials.js", "dist/credentials/GithubApi.credentials.js", "dist/credentials/GithubOAuth2Api.credentials.js", "dist/credentials/GitlabApi.credentials.js", @@ -369,6 +370,7 @@ "dist/nodes/GetResponse/GetResponse.node.js", "dist/nodes/GetResponse/GetResponseTrigger.node.js", "dist/nodes/Ghost/Ghost.node.js", + "dist/nodes/Git/Git.node.js", "dist/nodes/Github/Github.node.js", "dist/nodes/Github/GithubTrigger.node.js", "dist/nodes/Gitlab/Gitlab.node.js", @@ -650,6 +652,7 @@ "request": "^2.88.2", "rhea": "^1.0.11", "rss-parser": "^3.7.0", + "simple-git": "^2.36.2", "snowflake-sdk": "^1.5.3", "ssh2-sftp-client": "^5.2.1", "tmp-promise": "^3.0.2", From a73a460d8a3e244f66d09a6fe7c39b12fdc3baac Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Sun, 6 Jun 2021 00:00:56 +0300 Subject: [PATCH 04/97] :arrow_up: Set xlsx@0.17.0 on n8n-nodes-base (#1864) Snyk has created this PR to upgrade xlsx from 0.16.9 to 0.17.0. See this package in npm: https://www.npmjs.com/package/xlsx See this project in Snyk: https://app.snyk.io/org/janober/project/a08454f4-33a1-49bc-bb2a-f31792e94f42?utm_source=github&utm_medium=upgrade-pr --- packages/nodes-base/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 3617a667f5..4ca13f2d3a 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -658,7 +658,7 @@ "tmp-promise": "^3.0.2", "uuid": "^3.4.0", "vm2": "^3.6.10", - "xlsx": "^0.16.7", + "xlsx": "^0.17.0", "xml2js": "^0.4.23" }, "jest": { From 114fd3b3a6bfa01727e21ee65d08c0096a436904 Mon Sep 17 00:00:00 2001 From: Ricardo Espinoza Date: Sun, 6 Jun 2021 14:54:49 -0400 Subject: [PATCH 05/97] :sparkles: Extend Pipedrive node (#1868) * Implementation of fetures to fetch data from Pipedrive API e user can select by dropdown * Search operation to Deals * Add custom fields for deal and person to select by dropdown * :zap: Improvements to #1845 Co-authored-by: Rodrigo Correia --- .../nodes/Pipedrive/GenericFunctions.ts | 2 +- .../nodes/Pipedrive/Pipedrive.node.ts | 732 +++++++++++++++--- 2 files changed, 643 insertions(+), 91 deletions(-) diff --git a/packages/nodes-base/nodes/Pipedrive/GenericFunctions.ts b/packages/nodes-base/nodes/Pipedrive/GenericFunctions.ts index 2352a7689e..fae5a70ad7 100644 --- a/packages/nodes-base/nodes/Pipedrive/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Pipedrive/GenericFunctions.ts @@ -98,7 +98,7 @@ export async function pipedriveApiRequest(this: IHookFunctions | IExecuteFunctio additionalData: responseData.additional_data, data: responseData.data, }; - } catch(error) { + } catch (error) { throw new NodeApiError(this.getNode(), error); } } diff --git a/packages/nodes-base/nodes/Pipedrive/Pipedrive.node.ts b/packages/nodes-base/nodes/Pipedrive/Pipedrive.node.ts index cc95485ab7..a04be3cfe1 100644 --- a/packages/nodes-base/nodes/Pipedrive/Pipedrive.node.ts +++ b/packages/nodes-base/nodes/Pipedrive/Pipedrive.node.ts @@ -223,6 +223,11 @@ export class Pipedrive implements INodeType { value: 'getAll', description: 'Get data of all deals', }, + { + name: 'Search', + value: 'search', + description: 'Search a deal', + }, { name: 'Update', value: 'update', @@ -530,6 +535,13 @@ export class Pipedrive implements INodeType { default: 0, description: 'ID of the deal this activity will be associated with', }, + { + displayName: 'Due Date', + name: 'due_date', + type: 'dateTime', + default: '', + description: 'Due Date to activity be done YYYY-MM-DD', + }, { displayName: 'Note', name: 'note', @@ -544,8 +556,11 @@ export class Pipedrive implements INodeType { { displayName: 'Organization ID', name: 'org_id', - type: 'number', - default: 0, + type: 'options', + typeOptions: { + loadOptionsMethod: 'getOrganizationIds', + }, + default: '', description: 'ID of the organization this activity will be associated with', }, { @@ -558,9 +573,12 @@ export class Pipedrive implements INodeType { { displayName: 'User ID', name: 'user_id', - type: 'number', - default: 0, - description: 'ID of the user whom the activity will be assigned to. If omitted, the activity will be assigned to the authorized user.', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getUserIds', + }, + default: '', + description: 'ID of the active user whom the activity will be assigned to. If omitted, the activity will be assigned to the authorized user.', }, { displayName: 'Custom Properties', @@ -642,7 +660,6 @@ export class Pipedrive implements INodeType { required: true, description: 'ID of the activity to get.', }, - // ---------------------------------- // activity:update // ---------------------------------- @@ -688,6 +705,13 @@ export class Pipedrive implements INodeType { default: 0, description: 'ID of the deal this activity will be associated with', }, + { + displayName: 'Due Date', + name: 'due_date', + type: 'dateTime', + default: '', + description: 'Due Date to activity be done YYYY-MM-DD', + }, { displayName: 'Done', name: 'done', @@ -720,8 +744,11 @@ export class Pipedrive implements INodeType { { displayName: 'Organization ID', name: 'org_id', - type: 'number', - default: 0, + type: 'options', + typeOptions: { + loadOptionsMethod: 'getOrganizationIds', + }, + default: '', description: 'ID of the organization this activity will be associated with', }, { @@ -749,9 +776,12 @@ export class Pipedrive implements INodeType { { displayName: 'User ID', name: 'user_id', - type: 'number', - default: 0, - description: 'ID of the user whom the activity will be assigned to. If omitted, the activity will be assigned to the authorized user.', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getUserIds', + }, + default: '', + description: 'ID of the active user whom the activity will be assigned to. If omitted, the activity will be assigned to the authorized user.', }, { displayName: 'Custom Properties', @@ -858,7 +888,10 @@ export class Pipedrive implements INodeType { { displayName: 'Property Name', name: 'name', - type: 'string', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getDealCustomFields', + }, default: '', description: 'Name of the property to set.', }, @@ -892,8 +925,11 @@ export class Pipedrive implements INodeType { { displayName: 'Organization ID', name: 'org_id', - type: 'number', - default: 0, + type: 'options', + typeOptions: { + loadOptionsMethod: 'getOrganizationIds', + }, + default: '', description: 'ID of the organization this deal will be associated with.', }, { @@ -917,9 +953,12 @@ export class Pipedrive implements INodeType { { displayName: 'Stage ID', name: 'stage_id', - type: 'number', - default: 0, - description: 'ID of the stage this deal will be placed in a pipeline. If omitted, the deal will be placed in the first stage of the default pipeline.', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getStageIds', + }, + default: '', + description: 'ID of the stage this deal will be placed in a pipeline. If omitted, the deal will be placed in the first stage of the default pipeline. (PIPELINE > STAGE)', }, { displayName: 'Status', @@ -949,9 +988,12 @@ export class Pipedrive implements INodeType { { displayName: 'User ID', name: 'user_id', - type: 'number', - default: 0, - description: 'ID of the user who will be marked as the owner of this deal. If omitted, the authorized user ID will be used.', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getUserIds', + }, + default: '', + description: 'ID of the active user whom the activity will be assigned to. If omitted, the activity will be assigned to the authorized user.', }, { displayName: 'Value', @@ -1109,9 +1151,12 @@ export class Pipedrive implements INodeType { { displayName: 'Property Name', name: 'name', - type: 'string', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getDealCustomFields', + }, default: '', - description: 'Name of the property to set.', + description: 'Name of the custom field to set.', }, { displayName: 'Property Value', @@ -1124,6 +1169,16 @@ export class Pipedrive implements INodeType { }, ], }, + { + displayName: 'User ID', + name: 'user_id', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getUserIds', + }, + default: '', + description: 'ID of the active user whom the activity will be assigned to. If omitted, the activity will be assigned to the authorized user.', + }, { displayName: 'Label', name: 'label', @@ -1143,8 +1198,11 @@ export class Pipedrive implements INodeType { { displayName: 'Organization ID', name: 'org_id', - type: 'number', - default: 0, + type: 'options', + typeOptions: { + loadOptionsMethod: 'getOrganizationIds', + }, + default: '', description: 'ID of the organization this deal will be associated with.', }, { @@ -1168,9 +1226,12 @@ export class Pipedrive implements INodeType { { displayName: 'Stage ID', name: 'stage_id', - type: 'number', - default: 0, - description: 'ID of the stage this deal will be placed in a pipeline. If omitted, the deal will be placed in the first stage of the default pipeline.', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getStageIds', + }, + default: '', + description: 'ID of the stage this deal will be placed in a pipeline. If omitted, the deal will be placed in the first stage of the default pipeline. (PIPELINE > STAGE)', }, { displayName: 'Status', @@ -1230,7 +1291,164 @@ export class Pipedrive implements INodeType { }, ], }, - + // ---------------------------------- + // deal:search + // ---------------------------------- + { + displayName: 'Term', + name: 'term', + type: 'string', + required: true, + displayOptions: { + show: { + operation: [ + 'search', + ], + resource: [ + 'deal', + ], + }, + }, + default: '', + description: 'The search term to look for. Minimum 2 characters (or 1 if using exact_match).', + }, + { + displayName: 'Exact Match', + name: 'exactMatch', + type: 'boolean', + displayOptions: { + show: { + operation: [ + 'search', + ], + resource: [ + 'deal', + ], + }, + }, + default: false, + description: 'When enabled, only full exact matches against the given term are returned. It is not case sensitive.', + }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + operation: [ + 'search', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + operation: [ + 'search', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 500, + }, + default: 100, + description: 'How many results to return.', + }, { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'search', + ], + resource: [ + 'deal', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'Include Fields', + name: 'includeFields', + type: 'string', + default: '', + description: 'Supports including optional fields in the results which are not provided by default. Example: deal.cc_email', + }, + { + displayName: 'Organization ID', + name: 'organizationId', + type: 'string', + default: '', + description: 'Will filter Deals by the provided Organization ID.', + }, + { + displayName: 'Person ID', + name: 'personId', + type: 'string', + default: '', + description: 'Will filter Deals by the provided Person ID.', + }, + { + displayName: 'Search Fields', + name: 'fields', + type: 'multiOptions', + options: [ + { + name: 'Custom Fields', + value: 'custom_fields', + }, + { + name: 'Notes', + value: 'notes', + }, + { + name: 'Title', + value: 'title', + }, + ], + default: [ + 'custom_fields', + 'notes', + 'title', + ], + description: 'A comma-separated string array. The fields to perform the search from. Defaults to all of them.', + }, + { + displayName: 'Status', + name: 'status', + type: 'options', + options: [ + { + name: 'Open', + value: 'open', + }, + { + name: 'Won', + value: 'won', + }, + { + name: 'Lost', + value: 'lost', + }, + ], + default: 'open', + description: 'The status of the deal. If not provided it will automatically be set to "open".', + }, + ], + }, // ---------------------------------- @@ -1294,9 +1512,12 @@ export class Pipedrive implements INodeType { { displayName: 'Organization ID', name: 'org_id', - type: 'number', - default: 0, - description: 'ID of the organization this file will be associated with.', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getOrganizationIds', + }, + default: '', + description: 'ID of the organization this deal will be associated with.', }, { displayName: 'Person ID', @@ -1429,47 +1650,50 @@ export class Pipedrive implements INodeType { }, description: 'The content of the note to create', }, - { - displayName: 'Additional Fields', - name: 'additionalFields', - type: 'collection', - placeholder: 'Add Field', - displayOptions: { - show: { - operation: [ - 'create', - 'getAll', - ], - resource: [ - 'note', - ], - }, - }, - default: {}, - options: [ - { - displayName: 'Deal ID', - name: 'deal_id', - type: 'number', - default: 0, - description: 'ID of the deal this note will be associated with', - }, - { - displayName: 'Organization ID', - name: 'org_id', - type: 'number', - default: 0, - description: 'ID of the organization this note will be associated with.', - }, - { - displayName: 'Person ID', - name: 'person_id', - type: 'number', - default: 0, - description: 'ID of the person this note will be associated with.', - }, - ], - }, + // { + // displayName: 'Additional Fields', + // name: 'additionalFields', + // type: 'collection', + // placeholder: 'Add Field', + // displayOptions: { + // show: { + // operation: [ + // 'create', + // 'getAll', + // ], + // resource: [ + // 'note', + // ], + // }, + // }, + // default: {}, + // options: [ + // { + // displayName: 'Deal ID', + // name: 'deal_id', + // type: 'number', + // default: 0, + // description: 'ID of the deal this note will be associated with', + // }, + // { + // displayName: 'Organization ID', + // name: 'org_id', + // type: 'options', + // typeOptions: { + // loadOptionsMethod: 'getOrganizationIds', + // }, + // default: '', + // description: 'ID of the organization this deal will be associated with.', + // }, + // { + // displayName: 'Person ID', + // name: 'person_id', + // type: 'number', + // default: 0, + // description: 'ID of the person this note will be associated with.', + // }, + // ], + // }, // ---------------------------------- // note:delete @@ -1573,9 +1797,12 @@ export class Pipedrive implements INodeType { { displayName: 'Organization ID', name: 'org_id', - type: 'number', - default: 0, - description: 'ID of the organization this note will be associated with.', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getOrganizationIds', + }, + default: '', + description: 'ID of the organization this deal will be associated with.', }, { displayName: 'Person ID', @@ -1913,9 +2140,12 @@ export class Pipedrive implements INodeType { { displayName: 'Property Name', name: 'name', - type: 'string', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getPersonCustomFields', + }, default: '', - description: 'Name of the property to set.', + description: 'Name of the custom field to set.', }, { displayName: 'Property Value', @@ -1950,9 +2180,12 @@ export class Pipedrive implements INodeType { { displayName: 'Organization ID', name: 'org_id', - type: 'number', - default: 0, - description: 'ID of the organization this person will belong to.', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getOrganizationIds', + }, + default: '', + description: 'ID of the organization this deal will be associated with.', }, { displayName: 'Phone', @@ -2085,9 +2318,12 @@ export class Pipedrive implements INodeType { { displayName: 'Property Name', name: 'name', - type: 'string', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getPersonCustomFields', + }, default: '', - description: 'Name of the property to set.', + description: 'Name of the custom field to set.', }, { displayName: 'Property Value', @@ -2129,9 +2365,12 @@ export class Pipedrive implements INodeType { { displayName: 'Organization ID', name: 'org_id', - type: 'number', - default: 0, - description: 'ID of the organization this person will belong to.', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getOrganizationIds', + }, + default: '', + description: 'ID of the organization this deal will be associated with.', }, { displayName: 'Phone', @@ -2220,7 +2459,6 @@ export class Pipedrive implements INodeType { show: { operation: [ 'getAll', - 'search', ], }, }, @@ -2235,7 +2473,6 @@ export class Pipedrive implements INodeType { show: { operation: [ 'getAll', - 'search', ], returnAll: [ false, @@ -2397,9 +2634,12 @@ export class Pipedrive implements INodeType { { displayName: 'Organization ID', name: 'org_id', - type: 'number', - default: 0, - description: 'ID of the organization this note will be associated with.', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getOrganizationIds', + }, + default: '', + description: 'ID of the organization this deal will be associated with.', }, { displayName: 'Person ID', @@ -2410,11 +2650,243 @@ export class Pipedrive implements INodeType { }, ], }, + // ---------------------------------- + // activity:getAll + // ---------------------------------- + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'activity', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'Done', + name: 'done', + type: 'boolean', + default: false, + description: 'Whether the Activity is done or not. 0 = Not done, 1 = Done. If omitted returns both Done and Not done activities.', + }, + { + displayName: 'End Date', + name: 'end_date', + type: 'dateTime', + default: '', + description: 'Use the Activity due date where you wish to stop fetching Activities from. Insert due date in YYYY-MM-DD format.', + }, + { + displayName: 'Filter ID ', + name: 'filterId', + type: 'string', + default: '', + description: 'The ID of the Filter to use (will narrow down results if used together with user_id parameter)', + }, + { + displayName: 'Star Date', + name: 'start_date', + type: 'dateTime', + default: '', + description: 'Use the Activity due date where you wish to begin fetching Activities from. Insert due date in YYYY-MM-DD format.', + }, + { + displayName: 'Type', + name: 'type', + type: 'multiOptions', + typeOptions: { + loadOptionsMethod: 'getActivityTypes', + }, + default: [], + description: 'Type of the Activity.', + }, + { + displayName: 'User ID', + name: 'user_id', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getUserIds', + }, + default: '', + description: 'The ID of the User whose Activities will be fetched. If omitted, the User associated with the API token will be used. If 0, Activities for all company Users will be fetched based on the permission sets.', + }, + ], + }, ], }; methods = { loadOptions: { + // Get all Organizations to display them to user so that he can + // select them easily + async getActivityTypes(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const { data } = await pipedriveApiRequest.call(this, 'GET', '/activityTypes', {}); + for (const activity of data) { + returnData.push({ + name: activity.name, + value: activity.key_string, + }); + } + + returnData.sort((a, b) => { + const aName = a.name.toLowerCase(); + const bName = b.name.toLowerCase(); + if (aName < bName) { return -1; } + if (aName > bName) { return 1; } + return 0; + }); + + return returnData; + }, + // Get all Organizations to display them to user so that he can + // select them easily + async getOrganizationIds(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const { data } = await pipedriveApiRequest.call(this, 'GET', '/organizations', {}); + for (const org of data) { + returnData.push({ + name: org.name, + value: org.id, + }); + } + + returnData.sort((a, b) => { + const aName = a.name.toLowerCase(); + const bName = b.name.toLowerCase(); + if (aName < bName) { return -1; } + if (aName > bName) { return 1; } + return 0; + }); + + return returnData; + }, + // Get all Organizations to display them to user so that he can + // select them easily + async getUserIds(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const { data } = await pipedriveApiRequest.call(this, 'GET', '/users', {}); + for (const user of data) { + if (user.active_flag === true) { + returnData.push({ + name: user.name, + value: user.id, + }); + } + } + + returnData.sort((a, b) => { + const aName = a.name.toLowerCase(); + const bName = b.name.toLowerCase(); + if (aName < bName) { return -1; } + if (aName > bName) { return 1; } + return 0; + }); + + return returnData; + }, + // Get all Stages to display them to user so that he can + // select them easily + async getStageIds(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const { data } = await pipedriveApiRequest.call(this, 'GET', '/stages', {}); + for (const stage of data) { + returnData.push({ + name: `${stage.pipeline_name} > ${stage.name}`, + value: stage.id, + }); + } + + returnData.sort((a, b) => { + const aName = a.name.toLowerCase(); + const bName = b.name.toLowerCase(); + if (aName < bName) { return -1; } + if (aName > bName) { return 1; } + return 0; + }); + + return returnData; + }, + // Get all the Organization Custom Fields to display them to user so that he can + // select them easily + async getOrganizationCustomFields(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const { data } = await pipedriveApiRequest.call(this, 'GET', '/organizationFields', {}); + for (const field of data) { + if (field.key.length === 40) { + returnData.push({ + name: field.name, + value: field.key, + }); + } + } + + returnData.sort((a, b) => { + const aName = a.name.toLowerCase(); + const bName = b.name.toLowerCase(); + if (aName < bName) { return -1; } + if (aName > bName) { return 1; } + return 0; + }); + + return returnData; + }, + // Get all the Deal Custom Fields to display them to user so that he can + // select them easily + async getDealCustomFields(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const { data } = await pipedriveApiRequest.call(this, 'GET', '/dealFields', {}); + for (const field of data) { + if (field.key.length === 40) { + returnData.push({ + name: field.name, + value: field.key, + }); + } + } + + returnData.sort((a, b) => { + const aName = a.name.toLowerCase(); + const bName = b.name.toLowerCase(); + if (aName < bName) { return -1; } + if (aName > bName) { return 1; } + return 0; + }); + + return returnData; + }, + // Get all the Person Custom Fields to display them to user so that he can + // select them easily + async getPersonCustomFields(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const { data } = await pipedriveApiRequest.call(this, 'GET', '/personFields', {}); + for (const field of data) { + if (field.key.length === 40) { + returnData.push({ + name: field.name, + value: field.key, + }); + } + } + + returnData.sort((a, b) => { + const aName = a.name.toLowerCase(); + const bName = b.name.toLowerCase(); + if (aName < bName) { return -1; } + if (aName > bName) { return 1; } + return 0; + }); + + return returnData; + }, // Get all the filters to display them to user so that he can // select them easily async getFilters(this: ILoadOptionsFunctions): Promise { @@ -2428,6 +2900,15 @@ export class Pipedrive implements INodeType { value: filterId, }); } + + returnData.sort((a, b) => { + const aName = a.name.toLowerCase(); + const bName = b.name.toLowerCase(); + if (aName < bName) { return -1; } + if (aName > bName) { return 1; } + return 0; + }); + return returnData; }, // Get all the person labels to display them to user so that he can @@ -2448,6 +2929,15 @@ export class Pipedrive implements INodeType { } } } + + returnData.sort((a, b) => { + const aName = a.name.toLowerCase(); + const bName = b.name.toLowerCase(); + if (aName < bName) { return -1; } + if (aName > bName) { return 1; } + return 0; + }); + if (operation === 'update') { returnData.push({ name: 'No Label', @@ -2474,6 +2964,15 @@ export class Pipedrive implements INodeType { } } } + + returnData.sort((a, b) => { + const aName = a.name.toLowerCase(); + const bName = b.name.toLowerCase(); + if (aName < bName) { return -1; } + if (aName > bName) { return 1; } + return 0; + }); + if (operation === 'update') { returnData.push({ name: 'No Label', @@ -2500,6 +2999,15 @@ export class Pipedrive implements INodeType { } } } + + returnData.sort((a, b) => { + const aName = a.name.toLowerCase(); + const bName = b.name.toLowerCase(); + if (aName < bName) { return -1; } + if (aName > bName) { return 1; } + return 0; + }); + if (operation === 'update') { returnData.push({ name: 'No Label', @@ -2606,6 +3114,13 @@ export class Pipedrive implements INodeType { qs.limit = this.getNodeParameter('limit', i) as number; } + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + addAdditionalFields(qs, additionalFields); + + if (qs.type) { + qs.type = (qs.type as string[]).join(','); + } + endpoint = `/activities`; } else if (operation === 'update') { @@ -2695,6 +3210,43 @@ export class Pipedrive implements INodeType { if (body.label === 'null') { body.label = null; } + } else if (operation === 'search') { + // ---------------------------------- + // deal:search + // ---------------------------------- + + requestMethod = 'GET'; + + qs.term = this.getNodeParameter('term', i) as string; + returnAll = this.getNodeParameter('returnAll', i) as boolean; + qs.exact_match = this.getNodeParameter('exactMatch', i) as boolean; + if (returnAll === false) { + qs.limit = this.getNodeParameter('limit', i) as number; + } + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + if (additionalFields.fields) { + qs.fields = (additionalFields.fields as string[]).join(','); + } + + if (additionalFields.organizationId) { + qs.organization_id = parseInt(additionalFields.organizationId as string, 10); + } + + if (additionalFields.includeFields) { + qs.include_fields = additionalFields.includeFields as string; + } + + if (additionalFields.personId) { + qs.person_id = parseInt(additionalFields.personId as string, 10); + } + if (additionalFields.status) { + qs.status = additionalFields.status as string; + } + + endpoint = `/deals/search`; + } } else if (resource === 'file') { if (operation === 'create') { From 26bdc5c9245b1dcffdcb543eee3c91352ae1b3e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Sun, 6 Jun 2021 21:00:57 +0200 Subject: [PATCH 06/97] :bug: Fix settings in AWS Transcribe node (#1860) * Fixe uninitialized object when settings enabled * :shirt: Fix linter warning * :zap: Fix options name * :fire: Remove unused setting * :zap: Improvements Co-authored-by: Alexander Mustafin Co-authored-by: ricardo --- .../nodes/Aws/Transcribe/AwsTranscribe.node.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/nodes-base/nodes/Aws/Transcribe/AwsTranscribe.node.ts b/packages/nodes-base/nodes/Aws/Transcribe/AwsTranscribe.node.ts index 788e69f0e9..23ee1e0e2c 100644 --- a/packages/nodes-base/nodes/Aws/Transcribe/AwsTranscribe.node.ts +++ b/packages/nodes-base/nodes/Aws/Transcribe/AwsTranscribe.node.ts @@ -426,6 +426,7 @@ export class AwsTranscribe implements INodeType { Media: { MediaFileUri: mediaFileUri, }, + Settings: {}, }; if (detectLang) { @@ -438,16 +439,16 @@ export class AwsTranscribe implements INodeType { Object.assign(body.Settings, { ChannelIdentification: options.channelIdentification }); } - if (options.MaxAlternatives) { + if (options.maxAlternatives) { Object.assign(body.Settings, { - ShowAlternatives: options.maxAlternatives, + ShowAlternatives: true, MaxAlternatives: options.maxAlternatives, }); - } + } - if (options.showSpeakerLabels) { + if (options.maxSpeakerLabels) { Object.assign(body.Settings, { - ShowSpeakerLabels: options.showSpeakerLabels, + ShowSpeakerLabels: true, MaxSpeakerLabels: options.maxSpeakerLabels, }); } From 09e14987f02af424480911216d7bb2bd4a3537d3 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Sun, 6 Jun 2021 14:53:48 -0500 Subject: [PATCH 07/97] :bug: Display issue that view crashes with large requests --- .../src/components/Error/NodeViewError.vue | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/editor-ui/src/components/Error/NodeViewError.vue b/packages/editor-ui/src/components/Error/NodeViewError.vue index 2c8cc2f056..ccb5532463 100644 --- a/packages/editor-ui/src/components/Error/NodeViewError.vue +++ b/packages/editor-ui/src/components/Error/NodeViewError.vue @@ -37,10 +37,11 @@ Data below may contain sensitive information. Proceed with caution when sharing.
- + + + The exact cause can sadly not displayed right now as the returned data is too large. +
@@ -67,13 +71,14 @@ - - diff --git a/packages/editor-ui/src/components/NodeCreateList.vue b/packages/editor-ui/src/components/NodeCreateList.vue deleted file mode 100644 index a00b3ff2d9..0000000000 --- a/packages/editor-ui/src/components/NodeCreateList.vue +++ /dev/null @@ -1,172 +0,0 @@ - - - - - diff --git a/packages/editor-ui/src/components/NodeCreator.vue b/packages/editor-ui/src/components/NodeCreator.vue deleted file mode 100644 index 7090d5749c..0000000000 --- a/packages/editor-ui/src/components/NodeCreator.vue +++ /dev/null @@ -1,104 +0,0 @@ - - - - - diff --git a/packages/editor-ui/src/components/NodeCreator/CategoryItem.vue b/packages/editor-ui/src/components/NodeCreator/CategoryItem.vue new file mode 100644 index 0000000000..3f4dff39ba --- /dev/null +++ b/packages/editor-ui/src/components/NodeCreator/CategoryItem.vue @@ -0,0 +1,42 @@ + + + + + + \ No newline at end of file diff --git a/packages/editor-ui/src/components/NodeCreator/CreatorItem.vue b/packages/editor-ui/src/components/NodeCreator/CreatorItem.vue new file mode 100644 index 0000000000..a024c2ec4d --- /dev/null +++ b/packages/editor-ui/src/components/NodeCreator/CreatorItem.vue @@ -0,0 +1,57 @@ + + + + + \ No newline at end of file diff --git a/packages/editor-ui/src/components/NodeCreator/ItemIterator.vue b/packages/editor-ui/src/components/NodeCreator/ItemIterator.vue new file mode 100644 index 0000000000..7cf00057ef --- /dev/null +++ b/packages/editor-ui/src/components/NodeCreator/ItemIterator.vue @@ -0,0 +1,94 @@ + + + + + + diff --git a/packages/editor-ui/src/components/NodeCreator/MainPanel.vue b/packages/editor-ui/src/components/NodeCreator/MainPanel.vue new file mode 100644 index 0000000000..bd7f665dbd --- /dev/null +++ b/packages/editor-ui/src/components/NodeCreator/MainPanel.vue @@ -0,0 +1,332 @@ + + + + + diff --git a/packages/editor-ui/src/components/NodeCreator/NoResults.vue b/packages/editor-ui/src/components/NodeCreator/NoResults.vue new file mode 100644 index 0000000000..c03823bfb2 --- /dev/null +++ b/packages/editor-ui/src/components/NodeCreator/NoResults.vue @@ -0,0 +1,126 @@ + + + + + + diff --git a/packages/editor-ui/src/components/NodeCreator/NoResultsIcon.vue b/packages/editor-ui/src/components/NodeCreator/NoResultsIcon.vue new file mode 100644 index 0000000000..697b1a42c7 --- /dev/null +++ b/packages/editor-ui/src/components/NodeCreator/NoResultsIcon.vue @@ -0,0 +1,22 @@ + \ No newline at end of file diff --git a/packages/editor-ui/src/components/NodeCreator/NodeCreator.vue b/packages/editor-ui/src/components/NodeCreator/NodeCreator.vue new file mode 100644 index 0000000000..4c9eccf5e0 --- /dev/null +++ b/packages/editor-ui/src/components/NodeCreator/NodeCreator.vue @@ -0,0 +1,101 @@ + + + + + diff --git a/packages/editor-ui/src/components/NodeCreator/NodeItem.vue b/packages/editor-ui/src/components/NodeCreator/NodeItem.vue new file mode 100644 index 0000000000..06f4d4f4be --- /dev/null +++ b/packages/editor-ui/src/components/NodeCreator/NodeItem.vue @@ -0,0 +1,86 @@ + + + + + diff --git a/packages/editor-ui/src/components/NodeCreator/SearchBar.vue b/packages/editor-ui/src/components/NodeCreator/SearchBar.vue new file mode 100644 index 0000000000..482650f31a --- /dev/null +++ b/packages/editor-ui/src/components/NodeCreator/SearchBar.vue @@ -0,0 +1,124 @@ + + + + + \ No newline at end of file diff --git a/packages/editor-ui/src/components/NodeCreator/SubcategoryItem.vue b/packages/editor-ui/src/components/NodeCreator/SubcategoryItem.vue new file mode 100644 index 0000000000..2ca06e3a21 --- /dev/null +++ b/packages/editor-ui/src/components/NodeCreator/SubcategoryItem.vue @@ -0,0 +1,58 @@ + + + + + + \ No newline at end of file diff --git a/packages/editor-ui/src/components/NodeCreator/SubcategoryPanel.vue b/packages/editor-ui/src/components/NodeCreator/SubcategoryPanel.vue new file mode 100644 index 0000000000..01af81b4a1 --- /dev/null +++ b/packages/editor-ui/src/components/NodeCreator/SubcategoryPanel.vue @@ -0,0 +1,96 @@ + + + + + \ No newline at end of file diff --git a/packages/editor-ui/src/components/NodeCreator/helpers.ts b/packages/editor-ui/src/components/NodeCreator/helpers.ts new file mode 100644 index 0000000000..ae194443b6 --- /dev/null +++ b/packages/editor-ui/src/components/NodeCreator/helpers.ts @@ -0,0 +1,176 @@ +import { CORE_NODES_CATEGORY, CUSTOM_NODES_CATEGORY, SUBCATEGORY_DESCRIPTIONS, UNCATEGORIZED_CATEGORY, UNCATEGORIZED_SUBCATEGORY, REGULAR_NODE_FILTER, TRIGGER_NODE_FILTER, ALL_NODE_FILTER } from '@/constants'; +import { INodeCreateElement, ICategoriesWithNodes, INodeItemProps } from '@/Interface'; +import { INodeTypeDescription } from 'n8n-workflow'; + + +export const getCategoriesWithNodes = (nodeTypes: INodeTypeDescription[]): ICategoriesWithNodes => { + return nodeTypes.reduce( + (accu: ICategoriesWithNodes, nodeType: INodeTypeDescription) => { + if (!nodeType.codex || !nodeType.codex.categories) { + accu[UNCATEGORIZED_CATEGORY][UNCATEGORIZED_SUBCATEGORY].nodes.push({ + type: 'node', + category: UNCATEGORIZED_CATEGORY, + key: `${UNCATEGORIZED_CATEGORY}_${nodeType.name}`, + properties: { + subcategory: UNCATEGORIZED_SUBCATEGORY, + nodeType, + }, + includedByTrigger: nodeType.group.includes('trigger'), + includedByRegular: !nodeType.group.includes('trigger'), + }); + return accu; + } + nodeType.codex.categories.forEach((_category: string) => { + const category = _category.trim(); + const subcategory = + nodeType.codex && + nodeType.codex.subcategories && + nodeType.codex.subcategories[category] + ? nodeType.codex.subcategories[category][0] + : UNCATEGORIZED_SUBCATEGORY; + if (!accu[category]) { + accu[category] = {}; + } + if (!accu[category][subcategory]) { + accu[category][subcategory] = { + triggerCount: 0, + regularCount: 0, + nodes: [], + }; + } + const isTrigger = nodeType.group.includes('trigger'); + if (isTrigger) { + accu[category][subcategory].triggerCount++; + } + if (!isTrigger) { + accu[category][subcategory].regularCount++; + } + accu[category][subcategory].nodes.push({ + type: 'node', + key: `${category}_${nodeType.name}`, + category, + properties: { + nodeType, + subcategory, + }, + includedByTrigger: isTrigger, + includedByRegular: !isTrigger, + }); + }); + return accu; + }, + { + [UNCATEGORIZED_CATEGORY]: { + [UNCATEGORIZED_SUBCATEGORY]: { + triggerCount: 0, + regularCount: 0, + nodes: [], + }, + }, + }, + ); +}; + +const getCategories = (categoriesWithNodes: ICategoriesWithNodes): string[] => { + const categories = Object.keys(categoriesWithNodes); + const sorted = categories.filter( + (category: string) => + category !== CORE_NODES_CATEGORY && category !== CUSTOM_NODES_CATEGORY && category !== UNCATEGORIZED_CATEGORY, + ); + sorted.sort(); + + return [CORE_NODES_CATEGORY, CUSTOM_NODES_CATEGORY, ...sorted, UNCATEGORIZED_CATEGORY]; +}; + +export const getCategorizedList = (categoriesWithNodes: ICategoriesWithNodes): INodeCreateElement[] => { + const categories = getCategories(categoriesWithNodes); + + return categories.reduce( + (accu: INodeCreateElement[], category: string) => { + if (!categoriesWithNodes[category]) { + return accu; + } + + const categoryEl: INodeCreateElement = { + type: 'category', + key: category, + category, + properties: { + expanded: false, + }, + }; + + const subcategories = Object.keys(categoriesWithNodes[category]); + if (subcategories.length === 1) { + const subcategory = categoriesWithNodes[category][ + subcategories[0] + ]; + if (subcategory.triggerCount > 0) { + categoryEl.includedByTrigger = subcategory.triggerCount > 0; + } + if (subcategory.regularCount > 0) { + categoryEl.includedByRegular = subcategory.regularCount > 0; + } + return [...accu, categoryEl, ...subcategory.nodes]; + } + + subcategories.sort(); + const subcategorized = subcategories.reduce( + (accu: INodeCreateElement[], subcategory: string) => { + const subcategoryEl: INodeCreateElement = { + type: 'subcategory', + key: `${category}_${subcategory}`, + category, + properties: { + subcategory, + description: SUBCATEGORY_DESCRIPTIONS[category][subcategory], + }, + includedByTrigger: categoriesWithNodes[category][subcategory].triggerCount > 0, + includedByRegular: categoriesWithNodes[category][subcategory].regularCount > 0, + }; + + if (subcategoryEl.includedByTrigger) { + categoryEl.includedByTrigger = true; + } + if (subcategoryEl.includedByRegular) { + categoryEl.includedByRegular = true; + } + + accu.push(subcategoryEl); + return accu; + }, + [], + ); + + return [...accu, categoryEl, ...subcategorized]; + }, + [], + ); +}; + +export const matchesSelectType = (el: INodeCreateElement, selectedType: string) => { + if (selectedType === REGULAR_NODE_FILTER && el.includedByRegular) { + return true; + } + if (selectedType === TRIGGER_NODE_FILTER && el.includedByTrigger) { + return true; + } + + return selectedType === ALL_NODE_FILTER; +}; + +const matchesAlias = (nodeType: INodeTypeDescription, filter: string): boolean => { + if (!nodeType.codex || !nodeType.codex.alias) { + return false; + } + + return nodeType.codex.alias.reduce((accu: boolean, alias: string) => { + return accu || alias.toLowerCase().indexOf(filter) > -1; + }, false); +}; + +export const matchesNodeType = (el: INodeCreateElement, filter: string) => { + const nodeType = (el.properties as INodeItemProps).nodeType; + + return nodeType.displayName.toLowerCase().indexOf(filter) !== -1 || matchesAlias(nodeType, filter); +}; \ No newline at end of file diff --git a/packages/editor-ui/src/components/NodeIcon.vue b/packages/editor-ui/src/components/NodeIcon.vue index d32a1a40ef..bf13e2ef7b 100644 --- a/packages/editor-ui/src/components/NodeIcon.vue +++ b/packages/editor-ui/src/components/NodeIcon.vue @@ -1,7 +1,7 @@