From 4ae0f5b6fba65bfa8f236657d89358f53e465c69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Mon, 11 Apr 2022 15:12:13 +0200 Subject: [PATCH 01/85] fix(editor): Fix i18n issues (#3072) * :bug: Fix `defaultLocale` watcher * :zap: Improve error handling for headers * :pencil2: Improve naming * :bug: Fix hiring banner check * :zap: Flatten base text keys * :zap: Fix miscorrected key * :zap: Implement pluralization * :pencil2: Update docs * :truck: Move headers fetching to `App.vue` * fix hiring banner * :zap: Fix missing import * :pencil2: Alphabetize translations * :zap: Switch to async check * feat(editor): Refactor Output Panel + fix i18n issues (#3097) * update main panel * finish up tabs * fix docs link * add icon * update node settings * clean up settings * add rename modal * fix component styles * fix spacing * truncate name * remove mixin * fix spacing * fix spacing * hide docs url * fix bug * fix renaming * refactor tabs out * refactor execute button * refactor header * add more views * fix error view * fix workflow rename bug * rename component * fix small screen bug * move items, fix positions * add hover state * show selector on empty state * add empty run state * fix binary view * 1 item * add vjs styles * show empty row for every item * refactor tabs * add branch names * fix spacing * fix up spacing * add run selector * fix positioning * clean up * increase width of selector * fix up spacing * fix copy button * fix branch naming; type issues * fix docs in custom nodes * add type * hide items when run selector is shown * increase selector size * add select prepend * clean up a bit * Add pagination * add stale icon * enable stale data in execution run * Revert "enable stale data in execution run" 8edb68dbffa0aa0d8189117e1a53381cb2c27608 * move metadata to its own state * fix smaller size * add scroll buttons * update tabs on resize * update stale data on rename * remove metadata on delete * hide x * change title colors * binary data classes * remove duplicate css * add colors * delete unused keys * use event bus * update styles of pagination * fix ts issues * fix ts issues * use chevron icons * fix design with download button * add back to canvas button * add trigger warning disabled * show trigger warning tooltip * update button labels for triggers * update node output message * fix add-option bug * add page selector * fix pagination selector bug * fix executions bug * remove hint * add json colors * add colors for json * add color json keys * fix select options bug * update keys * address comments * update name limit * align pencil * update icon size * update radio buttons height * address comments * fix pencil bug * change buttons alignment * fully center * change order of buttons * add no output message in branch * scroll to top * change active state * fix page size * all items * update expression background * update naming * align pencil * update modal background * add schedule group * update schedule nodes messages * use ellpises for last chars * fix spacing * fix tabs issue * fix too far data bug * fix executions bug * fix table wrapping * fix rename bug * add padding * handle unkown errors * add sticky header * ignore empty input, trim node name * nudge lightness of color * center buttons * update pagination * set colors of title * increase table font, fix alignment * fix pencil bug * fix spacing * use date now * address pagination issues * delete unused keys * update keys sort * fix prepend * fix radio button position * Revert "fix radio button position" ae42781786f2e6dcfb00d1be770b19a67f533bdf Co-authored-by: Mutasem Co-authored-by: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com> --- packages/cli/src/Server.ts | 11 +- .../src/components/N8nIcon/Icon.vue | 3 + .../components/N8nInfoTip/InfoTip.stories.js | 10 +- .../src/components/N8nInfoTip/InfoTip.vue | 63 +- .../N8nRadioButtons/RadioButton.vue | 66 + .../N8nRadioButtons/RadioButtons.stories.js | 51 + .../N8nRadioButtons/RadioButtons.vue | 49 + .../src/components/N8nRadioButtons/index.js | 3 + .../src/components/N8nSelect/Select.vue | 71 +- .../src/components/N8nTabs/Tabs.stories.js | 54 + .../src/components/N8nTabs/Tabs.vue | 192 ++ .../src/components/N8nTabs/index.js | 3 + .../design-system/src/components/index.js | 8 + .../src/components/utils/helpers.ts | 2 +- .../src/styleguide/colors.stories.mdx | 12 + packages/design-system/theme/src/_tokens.scss | 15 +- .../design-system/theme/src/common/var.scss | 4 +- packages/design-system/theme/src/index.scss | 2 +- .../design-system/theme/src/pagination.scss | 20 +- packages/editor-ui/src/App.vue | 18 +- packages/editor-ui/src/Interface.ts | 13 + .../editor-ui/src/components/DataDisplay.vue | 151 +- .../src/components/DisplayWithChange.vue | 128 -- .../src/components/ExpressionEdit.vue | 2 +- .../ExecutionDetails/ExecutionDetails.vue | 8 +- .../components/MainHeader/WorkflowDetails.vue | 8 +- .../src/components/NodeExecuteButton.vue | 65 + .../editor-ui/src/components/NodeSettings.vue | 162 +- .../editor-ui/src/components/NodeTabs.vue | 85 + .../editor-ui/src/components/NodeTitle.vue | 135 ++ packages/editor-ui/src/components/RunData.vue | 1029 +++++---- ...{WorkflowNameShort.vue => ShortenName.vue} | 2 +- .../TagsManager/TagsView/TagsView.vue | 10 +- .../src/components/mixins/nodeHelpers.ts | 3 + packages/editor-ui/src/n8n-theme.scss | 30 +- packages/editor-ui/src/plugins/components.ts | 11 +- .../src/plugins/i18n/docs/ADDENDUM.md | 68 +- .../editor-ui/src/plugins/i18n/docs/README.md | 127 +- packages/editor-ui/src/plugins/i18n/index.ts | 6 +- .../src/plugins/i18n/locales/en.json | 1852 +++++++---------- packages/editor-ui/src/plugins/icons.ts | 2 + packages/editor-ui/src/store.ts | 15 + packages/editor-ui/src/views/NodeView.vue | 45 +- packages/nodes-base/nodes/Cron/Cron.node.ts | 2 +- .../nodes/Interval/Interval.node.ts | 2 +- 45 files changed, 2579 insertions(+), 2039 deletions(-) create mode 100644 packages/design-system/src/components/N8nRadioButtons/RadioButton.vue create mode 100644 packages/design-system/src/components/N8nRadioButtons/RadioButtons.stories.js create mode 100644 packages/design-system/src/components/N8nRadioButtons/RadioButtons.vue create mode 100644 packages/design-system/src/components/N8nRadioButtons/index.js create mode 100644 packages/design-system/src/components/N8nTabs/Tabs.stories.js create mode 100644 packages/design-system/src/components/N8nTabs/Tabs.vue create mode 100644 packages/design-system/src/components/N8nTabs/index.js delete mode 100644 packages/editor-ui/src/components/DisplayWithChange.vue create mode 100644 packages/editor-ui/src/components/NodeExecuteButton.vue create mode 100644 packages/editor-ui/src/components/NodeTabs.vue create mode 100644 packages/editor-ui/src/components/NodeTitle.vue rename packages/editor-ui/src/components/{WorkflowNameShort.vue => ShortenName.vue} (96%) diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index d27ca2da11..14aff9569f 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -30,7 +30,7 @@ /* eslint-disable no-await-in-loop */ import express from 'express'; -import { readFileSync } from 'fs'; +import { readFileSync, promises } from 'fs'; import { readFile } from 'fs/promises'; import _, { cloneDeep } from 'lodash'; import { dirname as pathDirname, join as pathJoin, resolve as pathResolve } from 'path'; @@ -1503,10 +1503,17 @@ class App { async (req: express.Request, res: express.Response): Promise => { const packagesPath = pathJoin(__dirname, '..', '..', '..'); const headersPath = pathJoin(packagesPath, 'nodes-base', 'dist', 'nodes', 'headers'); + + try { + await promises.access(`${headersPath}.js`); + } catch (_) { + return; // no headers available + } + try { return require(headersPath); } catch (error) { - res.status(500).send('Failed to find headers file'); + res.status(500).send('Failed to load headers file'); } }, ), diff --git a/packages/design-system/src/components/N8nIcon/Icon.vue b/packages/design-system/src/components/N8nIcon/Icon.vue index 8ffe65edec..b89b43a57e 100644 --- a/packages/design-system/src/components/N8nIcon/Icon.vue +++ b/packages/design-system/src/components/N8nIcon/Icon.vue @@ -2,6 +2,7 @@ diff --git a/packages/design-system/src/components/N8nInfoTip/InfoTip.stories.js b/packages/design-system/src/components/N8nInfoTip/InfoTip.stories.js index 382a46dac6..f61d1d9f9d 100644 --- a/packages/design-system/src/components/N8nInfoTip/InfoTip.stories.js +++ b/packages/design-system/src/components/N8nInfoTip/InfoTip.stories.js @@ -11,7 +11,13 @@ const Template = (args, { argTypes }) => ({ N8nInfoTip, }, template: - 'Need help doing something? Open docs', + 'Need help doing something? Open docs', }); -export const InputLabel = Template.bind({}); +export const Note = Template.bind({}); + +export const Tooltip = Template.bind({}); +Tooltip.args = { + type: 'tooltip', + tooltipPlacement: 'right', +}; diff --git a/packages/design-system/src/components/N8nInfoTip/InfoTip.vue b/packages/design-system/src/components/N8nInfoTip/InfoTip.vue index 75a56f49e4..4d26093f47 100644 --- a/packages/design-system/src/components/N8nInfoTip/InfoTip.vue +++ b/packages/design-system/src/components/N8nInfoTip/InfoTip.vue @@ -1,23 +1,48 @@ - @@ -81,7 +81,7 @@ import mixins from "vue-typed-mixins"; import { mapGetters } from "vuex"; import { MAX_WORKFLOW_NAME_LENGTH } from "@/constants"; -import WorkflowNameShort from "@/components/WorkflowNameShort.vue"; +import ShortenName from "@/components/ShortenName.vue"; import TagsContainer from "@/components/TagsContainer.vue"; import PushConnectionTracker from "@/components/PushConnectionTracker.vue"; import WorkflowActivator from "@/components/WorkflowActivator.vue"; @@ -105,7 +105,7 @@ export default mixins(workflowHelpers).extend({ components: { TagsContainer, PushConnectionTracker, - WorkflowNameShort, + ShortenName, WorkflowActivator, SaveButton, TagsDropdown, diff --git a/packages/editor-ui/src/components/NodeExecuteButton.vue b/packages/editor-ui/src/components/NodeExecuteButton.vue new file mode 100644 index 0000000000..e478da18e1 --- /dev/null +++ b/packages/editor-ui/src/components/NodeExecuteButton.vue @@ -0,0 +1,65 @@ + + + diff --git a/packages/editor-ui/src/components/NodeSettings.vue b/packages/editor-ui/src/components/NodeSettings.vue index 0d59691cf9..5f4a76c0dc 100644 --- a/packages/editor-ui/src/components/NodeSettings.vue +++ b/packages/editor-ui/src/components/NodeSettings.vue @@ -1,17 +1,15 @@ @@ -59,12 +55,11 @@ import { IUpdateInformation, } from '@/Interface'; -import { ElTabPane } from "element-ui/types/tab-pane"; - -import DisplayWithChange from '@/components/DisplayWithChange.vue'; +import NodeTitle from '@/components/NodeTitle.vue'; import ParameterInputFull from '@/components/ParameterInputFull.vue'; import ParameterInputList from '@/components/ParameterInputList.vue'; import NodeCredentials from '@/components/NodeCredentials.vue'; +import NodeTabs from '@/components/NodeTabs.vue'; import NodeWebhooks from '@/components/NodeWebhooks.vue'; import { get, set, unset } from 'lodash'; @@ -73,21 +68,23 @@ import { genericHelpers } from '@/components/mixins/genericHelpers'; import { nodeHelpers } from '@/components/mixins/nodeHelpers'; import mixins from 'vue-typed-mixins'; +import NodeExecuteButton from './NodeExecuteButton.vue'; export default mixins( externalHooks, genericHelpers, nodeHelpers, ) - .extend({ name: 'NodeSettings', components: { - DisplayWithChange, + NodeTitle, NodeCredentials, ParameterInputFull, ParameterInputList, + NodeTabs, NodeWebhooks, + NodeExecuteButton, }, computed: { nodeType (): INodeTypeDescription | null { @@ -150,14 +147,16 @@ export default mixins( return this.nodeType.properties; }, - workflowRunning (): boolean { - return this.$store.getters.isActionActive('workflowRunning'); + }, + props: { + eventBus: { }, }, data () { return { nodeValid: true, nodeColor: null, + openPanel: 'params', nodeValues: { color: '#ff0000', alwaysOutputData: false, @@ -271,7 +270,9 @@ export default mixins( }, }, methods: { - noOp () {}, + onNodeExecute () { + this.$emit('execute'); + }, setValue (name: string, value: NodeParameterValue) { const nameParts = name.split('.'); let lastNamePart: string | undefined = nameParts.pop(); @@ -337,6 +338,13 @@ export default mixins( this.$externalHooks().run('nodeSettings.credentialSelected', { updateInformation }); }, + nameChanged(name: string) { + // @ts-ignore + this.valueChanged({ + value: name, + name: 'name', + }); + }, valueChanged (parameterData: IUpdateInformation) { let newValue: NodeParameterValue; if (parameterData.hasOwnProperty('value')) { @@ -362,7 +370,6 @@ export default mixins( }; this.$emit('valueChanged', sendData); - this.$store.commit('setActiveNode', newValue); } else if (parameterData.name.startsWith('parameters.')) { // A node parameter changed @@ -514,20 +521,25 @@ export default mixins( this.nodeValid = false; } }, - handleTabClick(tab: ElTabPane) { - if(tab.label === 'Settings') { - this.$telemetry.track('User viewed node settings', { node_type: this.node ? this.node.type : '', workflow_id: this.$store.getters.workflowId }); - } - }, }, mounted () { this.setNodeValues(); + if (this.eventBus) { + (this.eventBus as Vue).$on('openSettings', () => { + this.openPanel = 'settings'; + }); + } }, }); - + diff --git a/packages/editor-ui/src/components/RunData.vue b/packages/editor-ui/src/components/RunData.vue index 43091926db..ad2348b266 100644 --- a/packages/editor-ui/src/components/RunData.vue +++ b/packages/editor-ui/src/components/RunData.vue @@ -1,73 +1,52 @@ @@ -225,6 +241,7 @@ import { IBinaryDisplayData, IExecutionResponse, INodeUi, + ITab, ITableData, } from '@/Interface'; @@ -234,15 +251,16 @@ import { } from '@/constants'; import BinaryDataDisplay from '@/components/BinaryDataDisplay.vue'; +import WarningTooltip from '@/components/WarningTooltip.vue'; import NodeErrorView from '@/components/Error/NodeErrorView.vue'; import { copyPaste } from '@/components/mixins/copyPaste'; import { externalHooks } from "@/components/mixins/externalHooks"; import { genericHelpers } from '@/components/mixins/genericHelpers'; import { nodeHelpers } from '@/components/mixins/nodeHelpers'; -import { workflowRun } from '@/components/mixins/workflowRun'; import mixins from 'vue-typed-mixins'; +import Vue from 'vue/types/umd'; import { saveAs } from 'file-saver'; @@ -254,7 +272,6 @@ export default mixins( externalHooks, genericHelpers, nodeHelpers, - workflowRun, ) .extend({ name: 'RunData', @@ -262,13 +279,14 @@ export default mixins( BinaryDataDisplay, NodeErrorView, VueJsonPretty, + WarningTooltip, }, data () { return { binaryDataPreviewActive: false, dataSize: 0, deselectedPlaceholder, - displayMode: this.$locale.baseText('runData.table'), + displayMode: 'table', state: { value: '' as object | number | string, path: deselectedPlaceholder, @@ -276,18 +294,48 @@ export default mixins( runIndex: 0, showData: false, outputIndex: 0, - maxDisplayItems: 25 as number | null, binaryDataDisplayVisible: false, binaryDataDisplayData: null as IBinaryDisplayData | null, MAX_DISPLAY_DATA_SIZE, MAX_DISPLAY_ITEMS_AUTO_ALL, + currentPage: 1, + pageSize: 10, + pageSizes: [10, 25, 50, 100], }; }, mounted() { this.init(); }, computed: { + nodeType (): INodeTypeDescription | null { + if (this.node) { + return this.$store.getters.nodeType(this.node.type, this.node.typeVersion); + } + return null; + }, + isTriggerNode (): boolean { + return !!(this.nodeType && this.nodeType.group.includes('trigger')); + }, + isPollingTypeNode (): boolean { + return !!(this.nodeType && this.nodeType.polling); + }, + isScheduleTrigger (): boolean { + return !!(this.nodeType && this.nodeType.group.includes('schedule')); + }, + buttons(): Array<{label: string, value: string}> { + const defaults = [ + { label: this.$locale.baseText('runData.table'), value: 'table'}, + { label: this.$locale.baseText('runData.json'), value: 'json'}, + ]; + if (this.binaryData.length) { + return [ ...defaults, + { label: this.$locale.baseText('runData.binary'), value: 'binary'}, + ]; + } + + return defaults; + }, hasNodeRun(): boolean { return Boolean(this.node && this.workflowRunData && this.workflowRunData.hasOwnProperty(this.node.name)); }, @@ -305,19 +353,15 @@ export default mixins( return null; } const executionData: IRunExecutionData = this.workflowExecution.data; - return executionData.resultData.runData; - }, - maxDisplayItemsOptions (): number[] { - const options = [25, 50, 100, 250, 500, 1000].filter(option => option <= this.dataCount); - if (!options.includes(this.dataCount)) { - options.push(this.dataCount); + if (executionData && executionData.resultData) { + return executionData.resultData.runData; } - return options; + return null; }, node (): INodeUi | null { return this.$store.getters.activeNode; }, - runMetadata () { + runTaskData (): ITaskData | null { if (!this.node || this.workflowExecution === null) { return null; } @@ -332,40 +376,33 @@ export default mixins( return null; } - const taskData: ITaskData = runData[this.node.name][this.runIndex]; + return runData[this.node.name][this.runIndex]; + }, + runMetadata (): {executionTime: number, startTime: string} | null { + if (!this.runTaskData) { + return null; + } return { - executionTime: taskData.executionTime, - startTime: new Date(taskData.startTime).toLocaleString(), + executionTime: this.runTaskData.executionTime, + startTime: new Date(this.runTaskData.startTime).toLocaleString(), }; }, + staleData(): boolean { + if (!this.node) { + return false; + } + const updatedAt = this.$store.getters.getParametersLastUpdated(this.node.name); + if (!updatedAt || !this.runTaskData) { + return false; + } + const runAt = this.runTaskData.startTime; + return updatedAt > runAt; + }, dataCount (): number { - if (this.node === null) { - return 0; - } - - const runData: IRunData | null = this.workflowRunData; - - if (runData === null || !runData.hasOwnProperty(this.node.name)) { - return 0; - } - - if (runData[this.node.name].length <= this.runIndex) { - return 0; - } - - if (runData[this.node.name][this.runIndex].hasOwnProperty('error')) { - return 1; - } - - if (!runData[this.node.name][this.runIndex].hasOwnProperty('data') || - runData[this.node.name][this.runIndex].data === undefined - ) { - return 0; - } - - const inputData = this.getMainInputData(runData[this.node.name][this.runIndex].data!, this.outputIndex); - - return inputData.length; + return this.getDataCount(this.runIndex, this.outputIndex); + }, + dataSizeInMB(): string { + return (this.dataSize / 1024 / 1000).toLocaleString(); }, maxOutputIndex (): number { if (this.node === null) { @@ -407,29 +444,22 @@ export default mixins( return 0; }, - jsonData (): IDataObject[] { + inputData (): INodeExecutionData[] { let inputData = this.getNodeInputData(this.node, this.runIndex, this.outputIndex); if (inputData.length === 0 || !Array.isArray(inputData)) { return []; } - if (this.maxDisplayItems !== null) { - inputData = inputData.slice(0, this.maxDisplayItems); - } + const offset = this.pageSize * (this.currentPage - 1); + inputData = inputData.slice(offset, offset + this.pageSize); - return this.convertToJson(inputData); + return inputData; + }, + jsonData (): IDataObject[] { + return this.convertToJson(this.inputData); }, tableData (): ITableData | undefined { - let inputData = this.getNodeInputData(this.node, this.runIndex, this.outputIndex); - if (inputData.length === 0) { - return undefined; - } - - if (this.maxDisplayItems !== null) { - inputData = inputData.slice(0,this.maxDisplayItems); - } - - return this.convertToTable(inputData); + return this.convertToTable(this.inputData); }, binaryData (): IBinaryKeyData[] { if (this.node === null) { @@ -438,17 +468,106 @@ export default mixins( return this.getBinaryData(this.workflowRunData, this.node.name, this.runIndex, this.outputIndex); }, + branches (): ITab[] { + function capitalize(name: string) { + return name.charAt(0).toLocaleUpperCase() + name.slice(1); + } + const branches: ITab[] = []; + for (let i = 0; i <= this.maxOutputIndex; i++) { + const itemsCount = this.getDataCount(this.runIndex, i); + const items = this.$locale.baseText(itemsCount === 1 ? 'ndv.output.item': 'ndv.output.items'); + let outputName = this.getOutputName(i); + if (`${outputName}` === `${i}`) { + outputName = `${this.$locale.baseText('ndv.output')} ${outputName}`; + } + else { + outputName = capitalize(`${this.getOutputName(i)} ${this.$locale.baseText('ndv.output.branch')}`); + } + branches.push({ + label: itemsCount ? `${outputName} (${itemsCount} ${items})` : outputName, + value: i, + }); + } + return branches; + }, }, methods: { + onPageSizeChange(pageSize: number) { + this.pageSize = pageSize; + const maxPage = Math.ceil(this.dataCount / this.pageSize); + if (maxPage < this.currentPage) { + this.currentPage = maxPage; + } + }, + onDisplayModeChange(displayMode: string) { + const previous = this.displayMode; + this.displayMode = displayMode; + + const dataContainer = this.$refs.dataContainer; + if (dataContainer) { + const dataDisplay = (dataContainer as Element).children[0]; + + if (dataDisplay){ + dataDisplay.scrollTo(0, 0); + } + } + + this.closeBinaryDataDisplay(); + this.$externalHooks().run('runData.displayModeChanged', { newValue: displayMode, oldValue: previous }); + if(this.node) { + const nodeType = this.node ? this.node.type : ''; + this.$telemetry.track('User changed node output view mode', { old_mode: previous, new_mode: displayMode, node_type: nodeType, workflow_id: this.$store.getters.workflowId }); + } + }, + getRunLabel(option: number) { + let itemsCount = 0; + for (let i = 0; i <= this.maxOutputIndex; i++) { + itemsCount += this.getDataCount(option - 1, i); + } + const items = this.$locale.baseText(itemsCount === 1 ? 'ndv.output.item': 'ndv.output.items'); + const itemsLabel = itemsCount > 0 ? ` (${itemsCount} ${items})` : ''; + return option + this.$locale.baseText('ndv.output.of') + (this.maxRunIndex+1) + itemsLabel; + }, + getDataCount(runIndex: number, outputIndex: number) { + if (this.node === null) { + return 0; + } + + const runData: IRunData | null = this.workflowRunData; + + if (runData === null || !runData.hasOwnProperty(this.node.name)) { + return 0; + } + + if (runData[this.node.name].length <= runIndex) { + return 0; + } + + if (runData[this.node.name][runIndex].hasOwnProperty('error')) { + return 1; + } + + if (!runData[this.node.name][runIndex].hasOwnProperty('data') || + runData[this.node.name][runIndex].data === undefined + ) { + return 0; + } + + const inputData = this.getMainInputData(runData[this.node.name][runIndex].data!, outputIndex); + + return inputData.length; + }, + openSettings() { + this.$emit('openSettings'); + }, init() { // Reset the selected output index every time another node gets selected this.outputIndex = 0; - this.maxDisplayItems = 25; this.refreshDataSize(); - if (this.displayMode === this.$locale.baseText('runData.binary')) { + if (this.displayMode === 'binary') { this.closeBinaryDataDisplay(); if (this.binaryData.length === 0) { - this.displayMode = this.$locale.baseText('runData.table'); + this.displayMode = 'table'; } } }, @@ -562,7 +681,7 @@ export default mixins( return outputIndex + 1; } - const nodeType = this.$store.getters.nodeType(this.node.type, this.node.typeVersion) as INodeTypeDescription | null; + const nodeType = this.nodeType; if (!nodeType || !nodeType.outputNames || nodeType.outputNames.length <= outputIndex) { return outputIndex + 1; } @@ -643,7 +762,8 @@ export default mixins( // Check how much data there is to display const inputData = this.getNodeInputData(this.node, this.runIndex, this.outputIndex); - const jsonItems = inputData.slice(0, this.maxDisplayItems || inputData.length).map(item => item.json); + const offset = this.pageSize * (this.currentPage - 1); + const jsonItems = inputData.slice(offset, offset + this.pageSize).map(item => item.json); this.dataSize = JSON.stringify(jsonItems).length; @@ -660,14 +780,6 @@ export default mixins( jsonData () { this.refreshDataSize(); }, - displayMode (newValue, oldValue) { - this.closeBinaryDataDisplay(); - this.$externalHooks().run('runData.displayModeChanged', { newValue, oldValue }); - if(this.node) { - const nodeType = this.node ? this.node.type : ''; - this.$telemetry.track('User changed node output view mode', { old_mode: oldValue, new_mode: newValue, node_type: nodeType, workflow_id: this.$store.getters.workflowId }); - } - }, maxRunIndex () { this.runIndex = Math.min(this.runIndex, this.maxRunIndex); }, @@ -675,188 +787,279 @@ export default mixins( }); - + + diff --git a/packages/editor-ui/src/components/WorkflowNameShort.vue b/packages/editor-ui/src/components/ShortenName.vue similarity index 96% rename from packages/editor-ui/src/components/WorkflowNameShort.vue rename to packages/editor-ui/src/components/ShortenName.vue index eb9b73c063..dca88204b1 100644 --- a/packages/editor-ui/src/components/WorkflowNameShort.vue +++ b/packages/editor-ui/src/components/ShortenName.vue @@ -11,7 +11,7 @@ const DEFAULT_WORKFLOW_NAME_LIMIT = 25; const WORKFLOW_NAME_END_COUNT_TO_KEEP = 4; export default Vue.extend({ - name: "WorkflowNameShort", + name: "ShortenName", props: ["name", "limit"], computed: { shortenedName(): string { diff --git a/packages/editor-ui/src/components/TagsManager/TagsView/TagsView.vue b/packages/editor-ui/src/components/TagsManager/TagsView/TagsView.vue index ce0121e204..d4a42fc26b 100644 --- a/packages/editor-ui/src/components/TagsManager/TagsView/TagsView.vue +++ b/packages/editor-ui/src/components/TagsManager/TagsView/TagsView.vue @@ -57,15 +57,7 @@ export default Vue.extend({ }, rows(): ITagRow[] { const getUsage = (count: number | undefined) => count && count > 0 - ? this.$locale.baseText( - count > 1 ? - 'tagsView.inUse.plural' : 'tagsView.inUse.singular', - { - interpolate: { - count: count.toString(), - }, - }, - ) + ? this.$locale.baseText('tagsView.inUse', { adjustToNumber: count }) : this.$locale.baseText('tagsView.notBeingUsed'); const disabled = this.isCreateEnabled || this.$data.updateId || this.$data.deleteId; diff --git a/packages/editor-ui/src/components/mixins/nodeHelpers.ts b/packages/editor-ui/src/components/mixins/nodeHelpers.ts index f4c33408cb..6335a7e4c5 100644 --- a/packages/editor-ui/src/components/mixins/nodeHelpers.ts +++ b/packages/editor-ui/src/components/mixins/nodeHelpers.ts @@ -287,6 +287,9 @@ export const nodeHelpers = mixins( return []; } const executionData: IRunExecutionData = this.$store.getters.getWorkflowExecution.data; + if (!executionData || !executionData.resultData) { // unknown status + return []; + } const runData = executionData.resultData.runData; if (runData === null || runData[node.name] === undefined || diff --git a/packages/editor-ui/src/n8n-theme.scss b/packages/editor-ui/src/n8n-theme.scss index acd8ab1c75..120c2cb8a8 100644 --- a/packages/editor-ui/src/n8n-theme.scss +++ b/packages/editor-ui/src/n8n-theme.scss @@ -120,9 +120,6 @@ .el-tabs__nav:focus { outline: none; } -.el-tabs__item { - color: #555; -} .el-tabs__item.is-active { font-weight: bold; } @@ -185,3 +182,30 @@ } } } + +.add-option { + > * { + border: none; + } + + i.el-select__caret { + color: var(--color-foreground-xlight); + } + .el-input .el-input__inner { + &, + &:hover, + &:focus { + border-radius: 20px; + color: var(--color-foreground-xlight); + font-weight: 600; + background-color: var(--color-primary); + border-color: var(--color-primary); + text-align: center; + } + + &::placeholder { + color: var(--color-foreground-xlight); + opacity: 1; /** Firefox */ + } + } +} diff --git a/packages/editor-ui/src/plugins/components.ts b/packages/editor-ui/src/plugins/components.ts index 9a6cca9964..e902e1580c 100644 --- a/packages/editor-ui/src/plugins/components.ts +++ b/packages/editor-ui/src/plugins/components.ts @@ -41,6 +41,8 @@ import { Message, Notification, CollapseTransition, + Pagination, + Popover, N8nActionBox, N8nAvatar, @@ -60,8 +62,10 @@ import { N8nMenu, N8nMenuItem, N8nOption, + N8nRadioButtons, N8nSelect, N8nSpinner, + N8nTabs, N8nFormInputs, N8nFormBox, N8nSquareButton, @@ -81,7 +85,7 @@ Vue.use(N8nAvatar); Vue.use(N8nButton); Vue.component('n8n-form-box', N8nFormBox); Vue.component('n8n-form-inputs', N8nFormInputs); -Vue.use('n8n-icon', N8nIcon); +Vue.component('n8n-icon', N8nIcon); Vue.use(N8nIconButton); Vue.use(N8nInfoTip); Vue.use(N8nInput); @@ -96,8 +100,10 @@ Vue.use(N8nMenuItem); Vue.use(N8nOption); Vue.use(N8nSelect); Vue.use(N8nSpinner); +Vue.use(N8nRadioButtons); Vue.component('n8n-square-button', N8nSquareButton); Vue.use(N8nTags); +Vue.component('n8n-tabs', N8nTabs); Vue.use(N8nTag); Vue.component('n8n-text', N8nText); Vue.use(N8nTooltip); @@ -130,6 +136,9 @@ Vue.use(Badge); Vue.use(Card); Vue.use(ColorPicker); Vue.use(Container); +Vue.use(Pagination); +Vue.use(Popover); + Vue.use(VueAgile); Vue.component(CollapseTransition.name, CollapseTransition); diff --git a/packages/editor-ui/src/plugins/i18n/docs/ADDENDUM.md b/packages/editor-ui/src/plugins/i18n/docs/ADDENDUM.md index 8c19e032d2..644b26269c 100644 --- a/packages/editor-ui/src/plugins/i18n/docs/ADDENDUM.md +++ b/packages/editor-ui/src/plugins/i18n/docs/ADDENDUM.md @@ -2,16 +2,24 @@ ## Base text -### Interpolation +### Pluralization -Certain base text strings use [interpolation](https://kazupon.github.io/vue-i18n/guide/formatting.html#named-formatting) to allow for a variable to be passed in, signalled by curly braces: +Certain base text strings accept [singular and plural versions](https://kazupon.github.io/vue-i18n/guide/pluralization.html) separated by a `|` character: ```json { - "stopExecution": { - "message": "The execution with the ID {activeExecutionId} got stopped!", - "title": "Execution stopped" - } + "tagsView.inUse": "{count} workflow | {count} workflows", +} +``` + +### Interpolation + +Certain base text strings use [interpolation](https://kazupon.github.io/vue-i18n/guide/formatting.html#named-formatting) to allow for a variable between curly braces: + +```json +{ + "stopExecution.message": "The execution with the ID {activeExecutionId} got stopped!", + "stopExecution.title": "Execution stopped" } ``` @@ -19,10 +27,8 @@ When translating a string containing an interpolated variable, leave the variabl ```json { - "stopExecution": { - "message": "Die Ausführung mit der ID {activeExecutionId} wurde gestoppt", - "title": "Execution stopped" - } + "stopExecution.message": "Die Ausführung mit der ID {activeExecutionId} wurde gestoppt", + "stopExecution.title": "Execution stopped" } ``` @@ -32,18 +38,12 @@ As a convenience, the base text file may contain the special key `reusableBaseTe ```json { - "reusableBaseText": { - "save": "🇩🇪 Save", - }, - "duplicateWorkflowDialog": { - "enterWorkflowName": "🇩🇪 Enter workflow name", - "save": "@:reusableBaseText.save", - }, - "saveButton": { - "save": "@:reusableBaseText.save", - "saving": "🇩🇪 Saving", - "saved": "🇩🇪 Saved", - }, + "reusableBaseText.save": "🇩🇪 Save", + "duplicateWorkflowDialog.enterWorkflowName": "🇩🇪 Enter workflow name", + "duplicateWorkflowDialog.save": "@:reusableBaseText.save", + "saveButton.save": "@:reusableBaseText.save", + "saveButton.saving": "🇩🇪 Saving", + "saveButton.saved": "🇩🇪 Saved", } ``` @@ -92,23 +92,27 @@ Currently only the keys `oauth.clientId` and `oauth.clientSecret` are supported ```json { - "reusableDynamicText": { - "oauth2": { - "clientId": "🇩🇪 Client ID", - "clientSecret": "🇩🇪 Client Secret", - } - } + "reusableDynamicText.oauth2.clientId": "🇩🇪 Client ID", + "reusableDynamicText.oauth2.clientSecret": "🇩🇪 Client Secret", } ``` ### Special cases -`eventTriggerDescription` is a dynamic node property that is not part of node parameters. To translate it, set the `eventTriggerDescription` key at the root level of the `nodeView` property in the node translation file. +`eventTriggerDescription` and `activationMessage` are dynamic node properties that are not part of node parameters. To translate them, set the key at the root level of the `nodeView` property in the node translation file. + +Webhook node: ```json { - "nodeView": { - "eventTriggerDescription": "🇩🇪 Waiting for you to call the Test URL" - } + "nodeView.eventTriggerDescription": "🇩🇪 Waiting for you to call the Test URL", +} +``` + +Cron node: + +```json +{ + "nodeView.activationMessage": "🇩🇪 'Your cron trigger will now trigger executions on the schedule you have defined." } ``` diff --git a/packages/editor-ui/src/plugins/i18n/docs/README.md b/packages/editor-ui/src/plugins/i18n/docs/README.md index cdee3d747d..125d5a73be 100644 --- a/packages/editor-ui/src/plugins/i18n/docs/README.md +++ b/packages/editor-ui/src/plugins/i18n/docs/README.md @@ -6,6 +6,7 @@ n8n allows for internalization of the majority of UI text: - base text, e.g. menu display items in the left-hand sidebar menu, - node text, e.g. parameter display names and placeholders in the node view, +- credential text, e.g. parameter display names and placeholders in the credential modal, - header text, e.g. node display names and descriptions at various spots. Currently, n8n does _not_ allow for internalization of: @@ -55,12 +56,10 @@ Base text is rendered with no dependencies, i.e. base text is fixed and does not The base text file for each locale is located at `/packages/editor-ui/src/plugins/i18n/locales/` and is named `{localeIdentifier}.json`. Keys in the base text file can be Vue component dirs, Vue component names, and references to symbols in those Vue components. These keys are added by the team as the UI is modified or expanded. ```json -"nodeCreator": { - "categoryNames": { - "analytics": "🇩🇪 Analytics", - "communication": "🇩🇪 Communication", - "coreNodes": "🇩🇪 Core Nodes" - } +{ + "nodeCreator.categoryNames.analytics": "🇩🇪 Analytics", + "nodeCreator.categoryNames.communication": "🇩🇪 Communication", + "nodeCreator.categoryNames.coreNodes": "🇩🇪 Core Nodes" } ``` @@ -98,9 +97,9 @@ A credential translation file is placed at `/nodes-base/credentials/translations ``` credentials └── translations - └── de - ├── githubApi.json - └── githubOAuth2Api.json + └── de + ├── githubApi.json + └── githubOAuth2Api.json ``` Every credential must have its own credential translation file. @@ -123,9 +122,9 @@ GitHub ├── GitHub.node.ts ├── GitHubTrigger.node.ts └── translations - └── de - ├── github.json - └── githubTrigger.json + └── de + ├── github.json + └── githubTrigger.json ``` Every node must have its own node translation file. @@ -184,16 +183,10 @@ The object for each node credential parameter allows for the keys `displayName`, ```json { - "server": { - "displayName": "🇩🇪 Github Server", - "description": "🇩🇪 The server to connect to. Only has to be set if Github Enterprise is used.", - }, - "user": { - "placeholder": "🇩🇪 Hans", - }, - "accessToken": { - "placeholder": "🇩🇪 123", - }, + "server.displayName": "🇩🇪 Github Server", + "server.description": "🇩🇪 The server to connect to. Only has to be set if Github Enterprise is used.", + "user.placeholder": "🇩🇪 Hans", + "accessToken.placeholder": "🇩🇪 123", } ``` @@ -224,10 +217,8 @@ export class Github implements INodeType { ```json { - "header": { - "displayName": "🇩🇪 GitHub", - "description": "🇩🇪 Consume GitHub API", - }, + "header.displayName": "🇩🇪 GitHub", + "header.description": "🇩🇪 Consume GitHub API", } ``` @@ -264,11 +255,7 @@ export class Github implements INodeType { ```json { - "nodeView": { - "resource": { - "displayName": "🇩🇪 Resource", - }, - }, + "nodeView.resource.displayName": "🇩🇪 Resource", } ``` @@ -291,13 +278,9 @@ Allowed keys: `displayName`, `description`, `placeholder` ```json { - "nodeView": { - "owner": { - "displayName": "🇩🇪 Repository Owner", - "placeholder": "🇩🇪 n8n-io", - "description": "🇩🇪 Owner of the repository", - }, - }, + "nodeView.owner.displayName": "🇩🇪 Repository Owner", + "nodeView.owner.placeholder": "🇩🇪 n8n-io", + "nodeView.owner.description": "🇩🇪 Owner of the repository", } ``` @@ -333,20 +316,10 @@ Allowed subkeys: `options.{optionName}.displayName` and `options.{optionName}.de ```json { - "nodeView": { - "resource": { - "displayName": "🇩🇪 Resource", - "description": "🇩🇪 Resource to operate on", - "options": { - "file": { - "displayName": "🇩🇪 File", - }, - "issue": { - "displayName": "🇩🇪 Issue", - }, - }, - }, - }, + "nodeView.resource.displayName": "🇩🇪 Resource", + "nodeView.resource.description": "🇩🇪 Resource to operate on", + "nodeView.resource.options.file.displayName": "🇩🇪 File", + "nodeView.resource.options.issue.displayName": "🇩🇪 Issue", } ``` @@ -394,19 +367,11 @@ Example of `collection` parameter: ```json { - "nodeView": { - "labels": { - "displayName": "🇩🇪 Labels", - "multipleValueButtonText": "🇩🇪 Add Label", - "options": { - "label": { - "displayName": "🇩🇪 Label", - "description": "🇩🇪 Label to add to issue", - "placeholder": "🇩🇪 Some placeholder" - } - } - } - } + "nodeView.labels.displayName": "🇩🇪 Labels", + "nodeView.labels.multipleValueButtonText": "🇩🇪 Add Label", + "nodeView.labels.options.label.displayName": "🇩🇪 Label", + "nodeView.labels.options.label.description": "🇩🇪 Label to add to issue", + "nodeView.labels.options.label.placeholder": "🇩🇪 Some placeholder" } ``` @@ -461,29 +426,15 @@ Example of `fixedCollection` parameter: ```json { - "nodeView": { - "additionalParameters": { - "displayName": "🇩🇪 Additional Parameters", - "placeholder": "🇩🇪 Add Field", - "options": { - "author": { - "displayName": "🇩🇪 Author", - "values": { - "name": { - "displayName": "🇩🇪 Name", - "description": "🇩🇪 Name of the author of the commit", - "placeholder": "🇩🇪 Jan" - }, - "email": { - "displayName": "🇩🇪 Email", - "description": "🇩🇪 Email of the author of the commit", - "placeholder": "🇩🇪 jan@n8n.io" - } - } - }, - } - } - } + "nodeView.additionalParameters.displayName": "🇩🇪 Additional Parameters", + "nodeView.additionalParameters.placeholder": "🇩🇪 Add Field", + "nodeView.additionalParameters.options.author.displayName": "🇩🇪 Author", + "nodeView.additionalParameters.options.author.values.name.displayName": "🇩🇪 Name", + "nodeView.additionalParameters.options.author.values.name.description": "🇩🇪 Name of the author of the commit", + "nodeView.additionalParameters.options.author.values.name.placeholder": "🇩🇪 Jan", + "nodeView.additionalParameters.options.author.values.email.displayName": "🇩🇪 Email", + "nodeView.additionalParameters.options.author.values.email.description": "🇩🇪 Email of the author of the commit", + "nodeView.additionalParameters.options.author.values.email.placeholder": "🇩🇪 jan@n8n.io", } ``` diff --git a/packages/editor-ui/src/plugins/i18n/index.ts b/packages/editor-ui/src/plugins/i18n/index.ts index fe1d681bfa..89e064c830 100644 --- a/packages/editor-ui/src/plugins/i18n/index.ts +++ b/packages/editor-ui/src/plugins/i18n/index.ts @@ -63,8 +63,12 @@ export class I18nClass { */ baseText( key: string, - options?: { interpolate: { [key: string]: string } }, + options?: { adjustToNumber: number; interpolate: { [key: string]: string } }, ): string { + if (options && options.adjustToNumber) { + return this.i18n.tc(key, options.adjustToNumber, options && options.interpolate).toString(); + } + return this.i18n.t(key, options && options.interpolate).toString(); } diff --git a/packages/editor-ui/src/plugins/i18n/locales/en.json b/packages/editor-ui/src/plugins/i18n/locales/en.json index 4405081688..b37ca0f446 100644 --- a/packages/editor-ui/src/plugins/i18n/locales/en.json +++ b/packages/editor-ui/src/plugins/i18n/locales/en.json @@ -1,1093 +1,22 @@ { - "about": { - "aboutN8n": "About n8n", - "close": "Close", - "license": "License", - "n8nVersion": "n8n Version", - "n8nLicense": "Sustainable Use License", - "sourceCode": "Source Code" - }, - "binaryDataDisplay": { - "backToList": "Back to list", - "backToOverviewPage": "Back to overview page", - "noDataFoundToDisplay": "No data found to display", - "yourBrowserDoesNotSupport": "Your browser does not support the video element. Kindly update it to latest version." - }, - "codeEdit": { - "edit": "Edit" - }, - "collectionParameter": { - "choose": "Choose...", - "noProperties": "No properties" - }, - "credentialEdit": { - "credentialConfig": { - "accountConnected": "Account connected", - "clickToCopy": "Click To Copy", - "connectionTestedSuccessfully": "Connection tested successfully", - "couldntConnectWithTheseSettings": "Couldn’t connect with these settings", - "needHelpFillingOutTheseFields": "Need help filling out these fields?", - "oAuthRedirectUrl": "OAuth Redirect URL", - "openDocs": "Open docs", - "pleaseCheckTheErrorsBelow": "Please check the errors below", - "reconnect": "reconnect", - "reconnectOAuth2Credential": "Reconnect OAuth2 Credential", - "redirectUrlCopiedToClipboard": "Redirect URL copied to clipboard", - "retry": "Retry", - "retryCredentialTest": "Retry credential test", - "retrying": "Retrying", - "subtitle": "In {appName}, use the URL above when prompted to enter an OAuth callback or redirect URL", - "theServiceYouReConnectingTo": "the service you're connecting to" - }, - "credentialEdit": { - "confirmMessage": { - "beforeClose1": { - "cancelButtonText": "Keep Editing", - "confirmButtonText": "Close", - "headline": "Close without saving?", - "message": "Are you sure you want to throw away the changes you made to the {credentialDisplayName} credential?" - }, - "beforeClose2": { - "cancelButtonText": "Keep Editing", - "confirmButtonText": "Close", - "headline": "Close without connecting?", - "message": "You need to connect your credential for it to work" - }, - "deleteCredential": { - "cancelButtonText": "", - "confirmButtonText": "Yes, delete", - "headline": "Delete Credential?", - "message": "Are you sure you want to delete \"{savedCredentialName}\"?" - } - }, - "connection": "Connection", - "couldNotFindCredentialOfType": "Could not find credential of type", - "couldNotFindCredentialWithId": "Could not find credential with ID", - "details": "Details", - "delete": "Delete", - "saving": "Saving", - "showError": { - "createCredential": { - "title": "Problem creating credential" - }, - "deleteCredential": { - "title": "Problem deleting credential" - }, - "generateAuthorizationUrl": { - "message": "There was a problem generating the authorization URL", - "title": "OAuth Authorization Error" - }, - "loadCredential": { - "title": "Problem loading credential" - }, - "updateCredential": { - "title": "Problem updating credential" - } - }, - "showMessage": { - "title": "Credential deleted" - }, - "testing": "Testing" - }, - "credentialInfo": { - "allowUseBy": "Allow use by", - "created": "Created", - "id": "ID", - "lastModified": "Last modified" - }, - "oAuthButton": { - "connectMyAccount": "Connect my account", - "signInWithGoogle": "Sign in with Google" - } - }, - "credentialSelectModal": { - "addNewCredential": "Add new credential", - "continue": "Continue", - "searchForApp": "Search for app...", - "selectAnAppOrServiceToConnectTo": "Select an app or service to connect to" - }, - "credentialsList": { - "addNew": "Add New", - "confirmMessage": { - "cancelButtonText": "", - "confirmButtonText": "Yes, delete", - "headline": "Delete Credential?", - "message": "Are you sure you want to delete {credentialName}?" - }, - "createNewCredential": "Create New Credential", - "created": "Created", - "credentials": "Credentials", - "deleteCredential": "Delete Credential", - "editCredential": "Edit Credential", - "name": "@:reusableBaseText.name", - "operations": "Operations", - "showError": { - "deleteCredential": { - "title": "Problem deleting credential" - } - }, - "showMessage": { - "title": "Credential deleted" - }, - "type": "Type", - "updated": "Updated", - "yourSavedCredentials": "Your saved credentials", - "errorLoadingCredentials": "Error loading credentials" - }, - "dataDisplay": { - "needHelp": "Need help?", - "nodeDocumentation": "Node Documentation", - "openDocumentationFor": "Open {nodeTypeDisplayName} documentation" - }, - "displayWithChange": { - "cancelEdit": "Cancel Edit", - "clickToChange": "Click to Change", - "setValue": "Set Value" - }, - "duplicateWorkflowDialog": { - "cancel": "@:reusableBaseText.cancel", - "chooseOrCreateATag": "Choose or create a tag", - "duplicateWorkflow": "Duplicate Workflow", - "enterWorkflowName": "Enter workflow name", - "save": "@:reusableBaseText.save", - "showMessage": { - "message": "Please enter a name.", - "title": "Name missing" - } - }, - "executionDetails": { - "executionFailed": "Execution failed", - "executionId": "Execution ID", - "executionWaiting": "Execution waiting", - "executionWasSuccessful": "Execution was successful", - "openWorkflow": "Open Workflow", - "of": "of", - "workflow": "workflow", - "readOnly": { - "readOnly": "Read only", - "youreViewingTheLogOf": "You're viewing the log of a previous execution. You cannot
\n\t\tmake changes since this execution already occurred. Make changes
\n\t\tto this workflow by clicking on its name on the left." - } - }, - "executionsList": { - "allWorkflows": "All Workflows", - "anyStatus": "Any Status", - "autoRefresh": "Auto refresh", - "confirmMessage": { - "cancelButtonText": "", - "confirmButtonText": "Yes, delete", - "headline": "Delete Executions?", - "message": "Are you sure that you want to delete the {numSelected} selected execution(s)?" - }, - "deleteSelected": "Delete Selected", - "error": "Error", - "filters": "Filters", - "loadMore": "Load More", - "mode": "Mode", - "modes": { - "error": "error", - "integrated": "integrated", - "manual": "manual", - "retry": "retry", - "trigger": "trigger", - "webhook": "webhook" - }, - "name": "@:reusableBaseText.name", - "openPastExecution": "Open Past Execution", - "retryExecution": "Retry execution", - "retryOf": "Retry of", - "retryWithCurrentlySavedWorkflow": "Retry with currently saved workflow", - "retryWithOriginalworkflow": "Retry with original workflow", - "running": "Running", - "runningTime": "Running Time", - "selectStatus": "Select Status", - "selectWorkflow": "Select Workflow", - "selected": "Selected", - "showError": { - "handleDeleteSelected": { - "title": "Problem deleting executions" - }, - "loadMore": { - "title": "Problem loading workflows" - }, - "loadWorkflows": { - "title": "Problem loading workflows" - }, - "refreshData": { - "title": "Problem loading data" - }, - "retryExecution": { - "title": "Problem with retry" - }, - "stopExecution": { - "title": "Problem stopping execution" - } - }, - "showMessage": { - "handleDeleteSelected": { - "title": "Execution deleted" - }, - "retrySuccessfulFalse": { - "title": "Retry unsuccessful" - }, - "retrySuccessfulTrue": { - "title": "Retry successful" - }, - "stopExecution": { - "message": "Execution ID {activeExecutionId}", - "title": "Execution stopped" - } - }, - "startedAtId": "Started At / ID", - "status": "Status", - "statusTooltipText": { - "theWorkflowExecutionFailed": "The workflow execution failed.", - "theWorkflowExecutionFailedButTheRetryWasSuccessful": "The workflow execution failed but the retry {entryRetrySuccessId} was successful.", - "theWorkflowExecutionIsProbablyStillRunning": "The workflow execution is probably still running but it may have crashed and n8n cannot safely tell. ", - "theWorkflowExecutionWasARetryOfAndFailed": "The workflow execution was a retry of {entryRetryOf} and failed.
New retries have to be started from the original execution.", - "theWorkflowExecutionWasARetryOfAndItWasSuccessful": "The workflow execution was a retry of {entryRetryOf} and it was successful.", - "theWorkflowExecutionWasSuccessful": "The worklow execution was successful.", - "theWorkflowIsCurrentlyExecuting": "The worklow is currently executing.", - "theWorkflowIsWaitingIndefinitely": "The workflow is waiting indefinitely for an incoming webhook call.", - "theWorkflowIsWaitingTill": "The worklow is waiting till {waitDateDate} {waitDateTime}." - }, - "stopExecution": "Stop Execution", - "success": "Success", - "successRetry": "Success retry", - "unknown": "Unknown", - "unsavedWorkflow": "[UNSAVED WORKFLOW]", - "waiting": "Waiting", - "workflowExecutions": "Workflow Executions" - }, - "expressionEdit": { - "editExpression": "Edit Expression", - "expression": "Expression", - "result": "Result", - "variableSelector": "Variable Selector" - }, - "fixedCollectionParameter": { - "choose": "Choose...", - "currentlyNoItemsExist": "Currently no items exist", - "deleteItem": "Delete item", - "moveDown": "Move down", - "moveUp": "Move up" - }, - "genericHelpers": { - "loading": "Loading", - "min": "min", - "sec": "sec", - "showMessage": { - "message": "This is a read-only version of the workflow. To make changes, either open the original workflow or save it under a new name.", - "title": "Workflow cannot be changed" - } - }, - "mainSidebar": { - "aboutN8n": "About n8n", - "confirmMessage": { - "workflowDelete": { - "cancelButtonText": "", - "confirmButtonText": "Yes, delete", - "headline": "Delete Workflow?", - "message": "Are you sure that you want to delete '{workflowName}'?" - }, - "workflowNew": { - "cancelButtonText": "Leave without saving", - "confirmButtonText": "Save", - "headline": "Save changes before leaving?", - "message": "If you don't save, you will lose your changes." - } - }, - "credentials": "Credentials", - "delete": "Delete", - "download": "Download", - "duplicate": "Duplicate", - "executions": "Executions", - "help": "Help", - "helpMenuItems": { - "course": "Course", - "documentation": "Documentation", - "forum": "Forum" - }, - "importFromFile": "Import from File", - "importFromUrl": "Import from URL", - "new": "New", - "newTemplate": "New from template", - "open": "Open", - "prompt": { - "cancel": "@:reusableBaseText.cancel", - "import": "Import", - "importWorkflowFromUrl": "Import Workflow from URL", - "invalidUrl": "Invalid URL", - "workflowUrl": "Workflow URL" - }, - "save": "@:reusableBaseText.save", - "settings": "Settings", - "showError": { - "stopExecution": { - "title": "Problem stopping execution" - } - }, - "showMessage": { - "handleFileImport": { - "message": "The file does not contain valid JSON data", - "title": "Could not import file" - }, - "handleSelect1": { - "title": "Workflow deleted" - }, - "handleSelect2": { - "title": "Workflow created" - }, - "handleSelect3": { - "title": "Workflow created" - }, - "stopExecution": { - "title": "Execution stopped" - } - }, - "templates": "Templates", - "workflows": "Workflows" - }, - "multipleParameter": { - "addItem": "Add item", - "currentlyNoItemsExist": "Currently no items exist", - "deleteItem": "Delete item", - "moveDown": "Move down", - "moveUp": "Move up" - }, - "noTagsView": { - "readyToOrganizeYourWorkflows": "Ready to organize your workflows?", - "withWorkflowTagsYouReFree": "With workflow tags, you're free to create the perfect tagging system for your flows" - }, - "node": { - "activateDeactivateNode": "Activate/Deactivate Node", - "deleteNode": "Delete Node", - "disabled": "Disabled", - "duplicateNode": "Duplicate Node", - "editNode": "Edit Node", - "executeNode": "Execute Node", - "issues": "Issues", - "nodeIsExecuting": "Node is executing", - "nodeIsWaitingTill": "Node is waiting until {date} {time}", - "theNodeIsWaitingIndefinitelyForAnIncomingWebhookCall": "The node is waiting for an incoming webhook call (indefinitely)", - "waitingForYouToCreateAnEventIn": "Waiting for you to create an event in {nodeType}" - }, - "nodeCreator": { - "categoryNames": { - "analytics": "Analytics", - "communication": "Communication", - "coreNodes": "Core Nodes", - "customNodes": "Custom Nodes", - "dataStorage": "Data & Storage", - "development": "Development", - "financeAccounting": "Finance & Accounting", - "marketingContent": "Marketing & Content", - "miscellaneous": "Miscellaneous", - "productivity": "Productivity", - "sales": "Sales", - "suggestedNodes": "Suggested Nodes ✨", - "utility": "Utility" - }, - "mainPanel": { - "all": "All", - "regular": "Regular", - "trigger": "Trigger" - }, - "noResults": { - "dontWorryYouCanProbablyDoItWithThe": "Don’t worry, you can probably do it with the", - "httpRequest": "HTTP Request", - "node": "node", - "or": "or", - "requestTheNode": "Request the node", - "wantUsToMakeItFaster": "Want us to make it faster?", - "weDidntMakeThatYet": "We didn't make that... yet", - "webhook": "Webhook" - }, - "searchBar": { - "searchNodes": "Search nodes..." - }, - "subcategoryDescriptions": { - "dataTransformation": "Manipulate data fields, run code", - "files": "Work with CSV, XML, text, images etc.", - "flow": "Branches, core triggers, merge data", - "helpers": "HTTP Requests (API calls), date and time, scrape HTML" - }, - "subcategoryNames": { - "dataTransformation": "Data Transformation", - "files": "Files", - "flow": "Flow", - "helpers": "Helpers" - } - }, - "nodeCredentials": { - "createNew": "Create New", - "credentialFor": "Credential for {credentialType}", - "issues": "Issues", - "selectCredential": "Select Credential", - "showMessage": { - "message": "Nodes that used credential \"{oldCredentialName}\" have been updated to use \"{newCredentialName}\"", - "title": "Node credential updated" - }, - "updateCredential": "Update Credential" - }, - "nodeErrorView": { - "cause": "Cause", - "copyToClipboard": "Copy to Clipboard", - "dataBelowMayContain": "Data below may contain sensitive information. Proceed with caution when sharing.", - "details": "Details", - "error": "ERROR", - "httpCode": "HTTP Code", - "showMessage": { - "title": "Copied to clipboard" - }, - "stack": "Stack", - "theErrorCauseIsTooLargeToBeDisplayed": "The error cause is too large to be displayed", - "time": "Time" - }, - "nodeBase": { - "clickToAddNodeOrDragToConnect": "Click to add node
or drag to connect" - }, - "nodeSettings": { - "alwaysOutputData": { - "description": "If active, will output a single, empty item when the output would have been empty. Use to prevent the workflow finishing on this node.", - "displayName": "Always Output Data" - }, - "clickOnTheQuestionMarkIcon": "Click the '?' icon to open this node on n8n.io", - "continueOnFail": { - "description": "If active, the workflow continues even if this node's execution fails. When this occurs, the node passes along input data from previous nodes - so your workflow should account for unexpected output data.", - "displayName": "Continue On Fail" - }, - "executeOnce": { - "description": "If active, the node executes only once, with data from the first item it receives", - "displayName": "Execute Once" - }, - "maxTries": { - "description": "Number of times to attempt to execute the node before failing the execution", - "displayName": "Max. Tries" - }, - "noDescriptionFound": "No description found", - "nodeDescription": "Node Description", - "notes": { - "description": "Optional note to save with the node", - "displayName": "Notes" - }, - "notesInFlow": { - "description": "If active, the note above will display in the flow as a subtitle", - "displayName": "Display note in flow?" - }, - "parameters": "Parameters", - "retryOnFail": { - "description": "If active, the node tries to execute again when it fails", - "displayName": "Retry On Fail" - }, - "settings": "Settings", - "theNodeIsNotValidAsItsTypeIsUnknown": "The node is not valid as its type ({nodeType}) is unknown", - "thisNodeDoesNotHaveAnyParameters": "This node does not have any parameters", - "waitBetweenTries": { - "description": "How long to wait between each attempt (in milliseconds)", - "displayName": "Wait Between Tries (ms)" - } - }, - "nodeView": { - "addNode": "Add node", - "confirmMessage": { - "beforeRouteLeave": { - "cancelButtonText": "Leave without saving", - "confirmButtonText": "Save", - "headline": "Save changes before leaving?", - "message": "If you don't save, you will lose your changes." - }, - "initView": { - "cancelButtonText": "Leave without saving", - "confirmButtonText": "Save", - "headline": "Save changes before leaving?", - "message": "If you don't save, you will lose your changes." - }, - "receivedCopyPasteData": { - "cancelButtonText": "", - "confirmButtonText": "Yes, import", - "headline": "Import Workflow?", - "message": "Workflow will be imported from
{plainTextData}" - } - }, - "couldntImportWorkflow": "Could not import workflow", - "deletesTheCurrentExecutionData": "Deletes the current execution data", - "executesTheWorkflowFromTheStartOrWebhookNode": "Executes the workflow from the 'start' or 'webhook' node", - "itLooksLikeYouHaveBeenEditingSomething": "It looks like you made some edits. If you leave before saving, your changes will be lost.", - "loadingTemplate": "Loading template", - "moreInfo": "More info", - "noNodesGivenToAdd": "No nodes to add specified", - "prompt": { - "cancel": "@:reusableBaseText.cancel", - "invalidName": "Invalid Name", - "newName": "New Name", - "rename": "Rename", - "renameNode": "Rename Node" - }, - "redirecting": "Redirecting", - "refresh": "Refresh", - "resetZoom": "Reset Zoom", - "runButtonText": { - "executeWorkflow": "Execute Workflow", - "executingWorkflow": "Executing Workflow", - "waitingForTriggerEvent": "Waiting for Trigger Event" - }, - "showError": { - "getWorkflowDataFromUrl": { - "title": "Problem loading workflow" - }, - "importWorkflowData": { - "title": "Problem importing workflow" - }, - "mounted1": { - "message": "There was a problem loading init data", - "title": "Init Problem" - }, - "mounted2": { - "message": "There was a problem initializing the workflow", - "title": "Init Problem" - }, - "openExecution": { - "title": "Problem loading execution" - }, - "openWorkflow": { - "title": "Problem opening workflow" - }, - "stopExecution": { - "title": "Problem stopping execution" - }, - "stopWaitingForWebhook": { - "title": "Problem deleting test webhook" - } - }, - "showMessage": { - "addNodeButton": { - "message": "'{nodeTypeName}' is an unknown node type", - "title": "Could not create node" - }, - "keyDown": { - "title": "Workflow created" - }, - "showMaxNodeTypeError": { - "message": { - "plural": "Only {maxNodes} '{nodeTypeDataDisplayName}' nodes are allowed in a workflow", - "singular": "Only {maxNodes} '{nodeTypeDataDisplayName}' node is allowed in a workflow" - }, - "title": "Could not create node" - }, - "stopExecutionCatch": { - "message": "It completed before it could be stopped", - "title": "Workflow finished executing" - }, - "stopExecutionTry": { - "title": "Execution stopped" - }, - "stopWaitingForWebhook": { - "title": "Webhook deleted" - } - }, - "stopCurrentExecution": "Stop current execution", - "stopWaitingForWebhookCall": "Stop waiting for webhook call", - "stoppingCurrentExecution": "Stopping current execution", - "thereWasAProblemLoadingTheNodeParametersOfNode": "There was a problem loading the parameters of the node", - "thisExecutionHasntFinishedYet": "This execution hasn't finished yet", - "toSeeTheLatestStatus": "to see the latest status", - "workflowTemplateWithIdCouldNotBeFound": "Workflow template with ID \"{templateId}\" could not be found", - "workflowWithIdCouldNotBeFound": "Workflow with ID \"{workflowId}\" could not be found", - "zoomIn": "Zoom In", - "zoomOut": "Zoom Out", - "zoomToFit": "Zoom to Fit" - }, - "nodeWebhooks": { - "clickToCopyWebhookUrls": "Click to copy webhook URLs", - "clickToDisplayWebhookUrls": "Click to display webhook URLs", - "clickToHideWebhookUrls": "Click to hide webhook URLs", - "invalidExpression": "[INVALID EXPRESSION]", - "productionUrl": "Production URL", - "showMessage": { - "title": "URL copied" - }, - "testUrl": "Test URL", - "webhookUrls": "Webhook URLs" - }, - "parameterInput": { - "addExpression": "Add Expression", - "error": "ERROR", - "issues": "Issues", - "loadingOptions": "Loading options...", - "openEditWindow": "Open Edit Window", - "parameter": "Parameter: \"{shortPath}\"", - "parameterHasExpression": "Parameter: \"{shortPath}\" has an expression", - "parameterHasIssues": "Parameter: \"{shortPath}\" has issues", - "parameterHasIssuesAndExpression": "Parameter: \"{shortPath}\" has issues and an expression", - "parameterOptions": "Parameter Options", - "refreshList": "Refresh List", - "removeExpression": "Remove Expression", - "resetValue": "Reset Value", - "selectDateAndTime": "Select date and time", - "select": "Select" - }, - "parameterInputExpanded": { - "openDocs": "Open docs", - "thisFieldIsRequired": "This field is required" - }, - "parameterInputList": { - "delete": "Delete", - "deleteParameter": "Delete Parameter", - "parameterOptions": "Parameter Options" - }, - "personalizationModal": { - "automationConsulting": "Automation consulting", - "continue": "Continue", - "customizeN8n": "Customize n8n to you", - "eCommerce": "eCommerce", - "errorWhileSubmittingResults": "Error while submitting results", - "executiveTeam": "Executive team", - "financeOrInsurance": "Finance / Insurance", - "getStarted": "Get started", - "government": "Government", - "healthcare": "Healthcare", - "howAreYourCodingSkills": "How are your coding skills?", - "howBigIsYourCompany": "How big is your company?", - "hr": "HR", - "it": "IT", - "iCanCodeSomeUsefulThingsBut": "2. I can code some useful things, but I spend a lot of time stuck", - "iCanDoAlmostAnythingIWant": "5. I can do almost anything I want, easily (pro coder)", - "iCanFigureMostThingsOut": "4. I can figure most things out", - "iGetStuckTooQuicklyToAchieveMuch": "1. I get stuck too quickly to achieve much", - "iKnowEnoughToBeDangerousBut": "3. I know enough to be dangerous, but I'm no expert", - "imNotUsingN8nForWork": "I'm not using n8n for work", - "individualConsumers": "Customers are individual consumers", - "smallBusinesses": "Customers are small businesses (under 20 employees)", - "mediumBusinesses": "Customers are medium businesses (20-499 employees)", - "largeBusinesses": "Customers are large businesses (500+ employees)", - "whatKindOfCustomersDoYouServe": "What kind of customers do you serve?", - "cloudInfrastructure": "Cloud infrastructure", - "itSupport": "IT support", - "networkingOrCommunication": "Networking / Communication", - "itEngineering": "IT / Engineering", - "legal": "Legal", - "lessThan20People": "Less than 20 people", - "lookOutForThingsMarked": "Look out for things marked with a ✨. They are personalized to make n8n more relevant to you.", - "marketing": "Marketing", - "media": "Media", - "manufacturing": "Manufacturing", - "managedServiceProvider": "Managed service provider", - "digitalAgencyOrConsultant": "Digital agency/consultant", - "automationAgencyOrConsultant": "Automation agency/consultant", - "neverCoded": "0. Never coded", - "operations": "Operations", - "otherPleaseSpecify": "Other (please specify)", - "other": "Other", - "people": "people", - "proCoder": "Pro coder", - "physicalRetailOrServices": "Physical retail or services", - "realEstateOrConstruction": "Real estate / Construction", - "saas": "SaaS", - "education": "Education", - "salesBizDev": "Sales / Bizdev", - "salesBusinessDevelopment": "Sales / Business Development", - "security": "Security", - "select": "Select...", - "specifyYourCompanysIndustry": "Specify your company's industry", - "specifyYourWorkArea": "Specify your work area", - "support": "Support", - "systemsIntegration": "Systems Integration", - "systemsIntegrator": "Systems Integrator", - "thanks": "Thanks!", - "telecoms": "Telecoms", - "theseQuestionsHelpUs": "These questions help us tailor n8n to you", - "whichIndustriesIsYourCompanyIn": "Which industries is your company in?", - "whatBestDescribesYourCompany": "What best describes your company?", - "whatDoesYourCompanyFocusOn": "Which services does your company focus on?", - "pleaseSpecifyYourCompanyFocus": "Please specify your company focus", - "whatAreYouLookingToAutomate": "What are you looking to automate?", - "customerIntegrations": "Customer integrations", - "customerSupport": "Customer support", - "financeOrAccounting": "Finance / Accounting", - "product": "Product (e.g. fast prototyping)", - "salesAndMarketing": "Sales and Marketing", - "notSureYet": "Not sure yet", - "specifyYourAutomationGoal": "Please specify your automation goal" - }, - "pushConnection": { - "showMessage": { - "title": "Workflow executed successfully" - } - }, - "pushConnectionTracker": { - "cannotConnectToServer": "You have a connection issue or the server is down.
n8n should reconnect automatically once the issue is resolved.", - "connectionLost": "Connection lost" - }, - "reusableBaseText": { - "cancel": "Cancel", - "name": "Name", - "save": "Save" - }, - "reusableDynamicText": { - "oauth2": { - "clientId": "Client ID", - "clientSecret": "Client Secret" - } - }, - "runData": { - "binary": "Binary", - "copyItemPath": "Copy Item Path", - "copyParameterPath": "Copy Parameter Path", - "copyToClipboard": "Copy to Clipboard", - "copyValue": "Copy Value", - "dataOfExecution": "Data of Execution", - "dataReturnedByThisNodeWillDisplayHere": "Data returned by this node will display here", - "displayDataAnyway": "Display Data Anyway", - "entriesExistButThey": "Entries exist but they do not contain any JSON data", - "executeNode": "Execute Node", - "executesThisNodeAfterExecuting": "Executes this {nodeName} node after executing any previous nodes that have not yet returned data", - "executionTime": "Execution Time", - "fileExtension": "File Extension", - "fileName": "File Name", - "items": "Items", - "json": "JSON", - "mimeType": "Mime Type", - "ms": "ms", - "noBinaryDataFound": "No binary data found", - "noData": "No data", - "noTextDataFound": "No text data found", - "nodeReturnedALargeAmountOfData": "Node returned a large amount of data", - "output": "Output", - "downloadBinaryData": "Download", - "showBinaryData": "View", - "startTime": "Start Time", - "table": "Table", - "theNodeContains": "The node contains {numberOfKb} KB of data.
Displaying it could cause problems.

If you do decide to display it, consider avoiding the JSON view." - }, - "saveButton": { - "save": "@:reusableBaseText.save", - "saved": "Saved", - "saving": "Saving" - }, - "showMessage": { - "cancel": "@:reusableBaseText.cancel", - "ok": "OK", - "showDetails": "Show Details" - }, - "tagsDropdown": { - "createTag": "Create tag \"{filter}\"", - "manageTags": "Manage tags", - "noMatchingTagsExist": "No matching tags exist", - "noTagsExist": "No tags exist", - "showError": { - "message": "A problem occurred when trying to create the '{name}' tag", - "title": "Could not create tag" - }, - "typeToCreateATag": "Type to create a tag" - }, - "tagsManager": { - "couldNotDeleteTag": "Could not delete tag", - "done": "Done", - "manageTags": "Manage tags", - "showError": { - "onCreate": { - "message": "A problem occurred when trying to create the tag '{escapedName}'", - "title": "Could not create tag" - }, - "onDelete": { - "message": "A problem occurred when trying to delete the tag '{escapedName}'", - "title": "Could not delete tag" - }, - "onUpdate": { - "message": "A problem occurred when trying to update the tag '{escapedName}'", - "title": "Could not update tag" - } - }, - "showMessage": { - "onDelete": { - "title": "Tag deleted" - }, - "onUpdate": { - "title": "Tag updated" - } - }, - "tagNameCannotBeEmpty": "Tag name cannot be empty" - }, - "tagsTable": { - "areYouSureYouWantToDeleteThisTag": "Are you sure you want to delete this tag?", - "cancel": "@:reusableBaseText.cancel", - "createTag": "Create tag", - "deleteTag": "Delete tag", - "editTag": "Edit Tag", - "name": "@:reusableBaseText.name", - "noMatchingTagsExist": "No matching tags exist", - "saveChanges": "Save changes?", - "usage": "Usage" - }, - "tagsTableHeader": { - "addNew": "Add new", - "searchTags": "Search Tags" - }, - "tagsView": { - "inUse": { - "plural": "{count} workflows", - "singular": "{count} workflow" - }, - "notBeingUsed": "Not being used" - }, - "template": { - "buttons": { - "goBackButton": "Go back", - "useThisWorkflowButton": "Use this workflow" - }, - "details": { - "appsInTheWorkflow": "Apps in this workflow", - "appsInTheCollection": "This collection features", - "by": "by", - "categories": "Categories", - "created": "Created", - "details": "Details", - "times": "times", - "viewed": "Viewed" - } - }, - "templates": { - "allCategories": "All Categories", - "categoriesHeading": "Categories", - "collection": "Collection", - "collections": "Collections", - "collectionsNotFound": "Collection could not be found", - "endResult": "Share your own useful workflows through your n8n.io account", - "heading": "Workflow templates", - "newButton": "New blank workflow", - "noSearchResults": "Nothing found. Try adjusting your search to see more.", - "searchPlaceholder": "Search workflows", - "workflow": "Workflow", - "workflows": "Workflows", - "workflowsNotFound": "Workflow could not be found", - "connectionWarning": "⚠️ There was a problem fetching workflow templates. Check your internet connection." - }, - "textEdit": { - "edit": "Edit" - }, - "timeAgo": { - "daysAgo": "%s days ago", - "hoursAgo": "%s hours ago", - "inDays": "in %s days", - "inHours": "in %s hours", - "inMinutes": "in %s minutes", - "inMonths": "in %s months", - "inOneDay": "in 1 day", - "inOneHour": "in 1 hour", - "inOneMinute": "in 1 minute", - "inOneMonth": "in 1 month", - "inOneWeek": "in 1 week", - "inOneYear": "in 1 year", - "inWeeks": "in %s weeks", - "inYears": "in %s years", - "justNow": "Just now", - "minutesAgo": "%s minutes ago", - "monthsAgo": "%s months ago", - "oneDayAgo": "1 day ago", - "oneHourAgo": "1 hour ago", - "oneMinuteAgo": "1 minute ago", - "oneMonthAgo": "1 month ago", - "oneWeekAgo": "1 week ago", - "oneYearAgo": "1 year ago", - "rightNow": "Right now", - "weeksAgo": "%s weeks ago", - "yearsAgo": "%s years ago" - }, - "updatesPanel": { - "andIs": "and is", - "behindTheLatest": "behind the latest and greatest n8n", - "howToUpdateYourN8nVersion": "How to update your n8n version", - "version": "{numberOfVersions} version{howManySuffix}", - "weVeBeenBusy": "We’ve been busy ✨", - "youReOnVersion": "You’re on {currentVersionName}, which was released" - }, - "variableSelector": { - "context": "Context", - "currentNode": "Current Node", - "nodes": "Nodes", - "outputData": "Output Data", - "parameters": "Parameters", - "variableFilter": "Variable filter..." - }, - "variableSelectorItem": { - "empty": "--- EMPTY ---", - "selectItem": "Select Item" - }, - "versionCard": { - "breakingChanges": "Breaking changes", - "released": "Released", - "securityUpdate": "Security update", - "thisVersionHasASecurityIssue": "This version has a security issue.
It is listed here for completeness.", - "unknown": "unknown", - "version": "Version" - }, - "workflowActivator": { - "activateWorkflow": "Activate workflow", - "deactivateWorkflow": "Deactivate workflow", - "showError": { - "title": "Workflow could not be {newStateName}" - }, - "showMessage": { - "activeChangedNodesIssuesExistTrue": { - "message": "Please resolve outstanding issues before you activate it", - "title": "Problem activating workflow" - }, - "activeChangedWorkflowIdUndefined": { - "message": "Please save it before activating", - "title": "Problem activating workflow" - }, - "displayActivationError": { - "message": { - "catchBlock": "Sorry there was a problem requesting the error", - "errorDataNotUndefined": "The following error occurred on workflow activation:
{message}", - "errorDataUndefined": "Unknown error" - }, - "title": "Problem activating workflow" - } - }, - "theWorkflowIsSetToBeActiveBut": "The workflow is activated but could not be started.
Click to display error message.", - "thisWorkflowHasNoTriggerNodes": "This workflow has no trigger nodes that require activation" - }, - "workflowDetails": { - "active": "Active", - "addTag": "Add tag", - "showMessage": { - "message": "Please enter a name, or press 'esc' to go back to the old one", - "title": "Name missing" - }, - "chooseOrCreateATag": "Choose or create a tag" - }, - "workflowHelpers": { - "showMessage": { - "title": "Problem saving workflow" - } - }, - "workflowOpen": { - "active": "Active", - "confirmMessage": { - "cancelButtonText": "Leave without saving", - "confirmButtonText": "Save", - "headline": "Save changes before leaving?", - "message": "If you don't save, you will lose your changes." - }, - "created": "Created", - "name": "@:reusableBaseText.name", - "openWorkflow": "Open Workflow", - "filterWorkflows": "Filter by tags", - "searchWorkflows": "Search workflows...", - "showError": { - "title": "Problem loading workflows" - }, - "showMessage": { - "message": "This is the current workflow", - "title": "Workflow already open" - }, - "updated": "Updated", - "couldNotLoadActiveWorkflows": "Could not load active workflows" - }, - "workflowRun": { - "noActiveConnectionToTheServer": "Lost connection to the server", - "showError": { - "title": "Problem running workflow" - }, - "showMessage": { - "message": "Please fix them before executing", - "title": "Workflow has issues" - } - }, - "workflowSettings": { - "defaultTimezone": "Default - {defaultTimezoneValue}", - "defaultTimezoneNotValid": "Default Timezone not valid", - "errorWorkflow": "Error Workflow", - "helpTexts": { - "errorWorkflow": "A second workflow to run if the current one fails.
The second workflow should an 'Error Trigger' node.", - "executionTimeout": "How long the workflow should wait before timing out", - "executionTimeoutToggle": "Whether to cancel workflow execution after a defined time", - "saveDataErrorExecution": "Whether to save data of executions that fail", - "saveDataSuccessExecution": "Whether to save data of executions that finish successfully", - "saveExecutionProgress": "Whether to save data after each node execution. This allows you to resume from where execution stopped if there is an error, but may increase latency.", - "saveManualExecutions": "Whether to save data of executions that are started manually from the editor", - "timezone": "The timezone in which the workflow should run. Used by 'cron' node, for example." - }, - "hours": "hours", - "minutes": "minutes", - "noWorkflow": "- No Workflow -", - "save": "@:reusableBaseText.save", - "saveDataErrorExecution": "Save failed executions", - "saveDataErrorExecutionOptions": { - "defaultSave": "Default - {defaultValue}", - "doNotSave": "Do not save", - "save": "@:reusableBaseText.save" - }, - "saveDataSuccessExecution": "Save successful executions", - "saveDataSuccessExecutionOptions": { - "defaultSave": "Default - {defaultValue}", - "doNotSave": "Do not save", - "save": "@:reusableBaseText.save" - }, - "saveExecutionProgress": "Save execution progress", - "saveExecutionProgressOptions": { - "defaultSave": "Default - {defaultValue}", - "no": "No", - "yes": "Yes" - }, - "saveManualExecutions": "Save manual executions", - "saveManualOptions": { - "defaultSave": "Default - {defaultValue}", - "no": "No", - "yes": "Yes" - }, - "seconds": "seconds", - "selectOption": "Select Option", - "settingsFor": "Settings for {workflowName} (#{workflowId})", - "showError": { - "saveSettings1": { - "errorMessage": "Timeout is activated but set to 0", - "message": "There was a problem saving the settings", - "title": "Problem saving settings" - }, - "saveSettings2": { - "errorMessage": "Maximum Timeout is: {hours} hours, {minutes} minutes, {seconds} seconds", - "message": "The timeout is longer than allowed", - "title": "Problem saving settings" - }, - "saveSettings3": { - "title": "Problem saving settings" - } - }, - "showMessage": { - "saveSettings": { - "title": "Workflow settings saved" - } - }, - "timeoutAfter": "Timeout After", - "timeoutWorkflow": "Timeout Workflow", - "timezone": "Timezone" - }, - "activationModal": { - "workflowActivated": "Workflow activated", - "theseExecutionsWillNotShowUp": "These executions will not show up immediately in the editor,", - "butYouCanSeeThem": "but you can see them in the", - "executionList": "execution list", - "ifYouChooseTo": "if you choose to", - "saveExecutions": "save executions.", - "dontShowAgain": "Don't show again", - "yourTriggersWillNowFire": "Your triggers will now fire production executions automatically.", - "yourTriggerWillNowFire": "Your trigger will now fire production executions automatically.", - "yourWorkflowWillNowRegularlyCheck": "Your workflow will now regularly check {serviceName} for events and trigger executions for them.", - "yourWorkflowWillNowListenForEvents": "Your workflow will now listen for events from {serviceName} and trigger executions.", - "gotIt": "Got it" - }, - "workflowPreview": { - "showError": { - "previewError": { - "message": "Unable to preview workflow", - "title": "Preview error" - }, - "missingWorkflow": "Missing workflow", - "arrayEmpty": "Must have an array of nodes" - } - }, + "about.aboutN8n": "About n8n", + "about.close": "Close", + "about.license": "License", + "about.n8nLicense": "Sustainable Use License", + "about.n8nVersion": "n8n Version", + "about.sourceCode": "Source Code", + "activationModal.butYouCanSeeThem": "but you can see them in the", + "activationModal.dontShowAgain": "Don't show again", + "activationModal.executionList": "execution list", + "activationModal.gotIt": "Got it", + "activationModal.ifYouChooseTo": "if you choose to", + "activationModal.saveExecutions": "save executions.", + "activationModal.theseExecutionsWillNotShowUp": "These executions will not show up immediately in the editor,", + "activationModal.workflowActivated": "Workflow activated", + "activationModal.yourTriggerWillNowFire": "Your trigger will now fire production executions automatically.", + "activationModal.yourTriggersWillNowFire": "Your triggers will now fire production executions automatically.", + "activationModal.yourWorkflowWillNowListenForEvents": "Your workflow will now listen for events from {serviceName} and trigger executions.", + "activationModal.yourWorkflowWillNowRegularlyCheck": "Your workflow will now regularly check {serviceName} for events and trigger executions for them.", "auth.changePassword": "Change Password", "auth.changePassword.currentPassword": "Current Password", "auth.changePassword.error": "Problem changing the password", @@ -1107,22 +36,22 @@ "auth.role": "Role", "auth.roles.member": "Member", "auth.roles.owner": "Owner", - "auth.setup.setupOwner": "Set up owner account", - "auth.setup.skipOwnerSetupQuestion": "Skip owner account setup?", - "auth.setup.skipSetup": "Skip setup", - "auth.setup.goBack": "Go back", "auth.setup.confirmOwnerSetup": "Set up owner account?", - "auth.setup.setupConfirmation.oneWorkflowCount": "{count} existing workflow", - "auth.setup.setupConfirmation.oneCredentialCount": "{count} credential", - "auth.setup.setupConfirmation.workflowsCount": "{count} existing workflows", - "auth.setup.setupConfirmation.credentialsCount": "{count} credentials", - "auth.setup.setupConfirmation.concatEntities": "{workflows} and {credentials}", "auth.setup.confirmOwnerSetupMessage": "To give others access to your {entities}, you’ll need to share these account details with them. Or you can continue as before with no account, by going back and skipping this setup. More info", "auth.setup.createAccount": "Create account", - "auth.setup.skipSetupTemporarily": "Skip setup for now", + "auth.setup.goBack": "Go back", "auth.setup.next": "Next", "auth.setup.ownerAccountBenefits": "Setting up an owner account allows you to invite others, and prevents people using n8n without an account", "auth.setup.settingUpOwnerError": "Problem setting up owner", + "auth.setup.setupConfirmation.concatEntities": "{workflows} and {credentials}", + "auth.setup.setupConfirmation.credentialsCount": "{count} credentials", + "auth.setup.setupConfirmation.oneCredentialCount": "{count} credential", + "auth.setup.setupConfirmation.oneWorkflowCount": "{count} existing workflow", + "auth.setup.setupConfirmation.workflowsCount": "{count} existing workflows", + "auth.setup.setupOwner": "Set up owner account", + "auth.setup.skipOwnerSetupQuestion": "Skip owner account setup?", + "auth.setup.skipSetup": "Skip setup", + "auth.setup.skipSetupTemporarily": "Skip setup for now", "auth.signin": "Sign in", "auth.signin.error": "Problem logging in", "auth.signout": "Sign out", @@ -1132,9 +61,175 @@ "auth.signup.setupYourAccount": "Set up your account", "auth.signup.setupYourAccountError": "Problem setting up your account", "auth.signup.tokenValidationError": "Issue validating invite token", + "binaryDataDisplay.backToList": "Back to list", + "binaryDataDisplay.backToOverviewPage": "Back to overview page", + "binaryDataDisplay.noDataFoundToDisplay": "No data found to display", + "binaryDataDisplay.yourBrowserDoesNotSupport": "Your browser does not support the video element. Kindly update it to latest version.", + "codeEdit.edit": "Edit", + "collectionParameter.choose": "Choose...", + "collectionParameter.noProperties": "No properties", + "credentialEdit.credentialConfig.accountConnected": "Account connected", + "credentialEdit.credentialConfig.clickToCopy": "Click To Copy", + "credentialEdit.credentialConfig.connectionTestedSuccessfully": "Connection tested successfully", + "credentialEdit.credentialConfig.couldntConnectWithTheseSettings": "Couldn’t connect with these settings", + "credentialEdit.credentialConfig.needHelpFillingOutTheseFields": "Need help filling out these fields?", + "credentialEdit.credentialConfig.oAuthRedirectUrl": "OAuth Redirect URL", + "credentialEdit.credentialConfig.openDocs": "Open docs", + "credentialEdit.credentialConfig.pleaseCheckTheErrorsBelow": "Please check the errors below", + "credentialEdit.credentialConfig.reconnect": "reconnect", + "credentialEdit.credentialConfig.reconnectOAuth2Credential": "Reconnect OAuth2 Credential", + "credentialEdit.credentialConfig.redirectUrlCopiedToClipboard": "Redirect URL copied to clipboard", + "credentialEdit.credentialConfig.retry": "Retry", + "credentialEdit.credentialConfig.retryCredentialTest": "Retry credential test", + "credentialEdit.credentialConfig.retrying": "Retrying", + "credentialEdit.credentialConfig.subtitle": "In {appName}, use the URL above when prompted to enter an OAuth callback or redirect URL", + "credentialEdit.credentialConfig.theServiceYouReConnectingTo": "the service you're connecting to", + "credentialEdit.credentialEdit.confirmMessage.beforeClose1.cancelButtonText": "Keep Editing", + "credentialEdit.credentialEdit.confirmMessage.beforeClose1.confirmButtonText": "Close", + "credentialEdit.credentialEdit.confirmMessage.beforeClose1.headline": "Close without saving?", + "credentialEdit.credentialEdit.confirmMessage.beforeClose1.message": "Are you sure you want to throw away the changes you made to the {credentialDisplayName} credential?", + "credentialEdit.credentialEdit.confirmMessage.beforeClose2.cancelButtonText": "Keep Editing", + "credentialEdit.credentialEdit.confirmMessage.beforeClose2.confirmButtonText": "Close", + "credentialEdit.credentialEdit.confirmMessage.beforeClose2.headline": "Close without connecting?", + "credentialEdit.credentialEdit.confirmMessage.beforeClose2.message": "You need to connect your credential for it to work", + "credentialEdit.credentialEdit.confirmMessage.deleteCredential.cancelButtonText": "", + "credentialEdit.credentialEdit.confirmMessage.deleteCredential.confirmButtonText": "Yes, delete", + "credentialEdit.credentialEdit.confirmMessage.deleteCredential.headline": "Delete Credential?", + "credentialEdit.credentialEdit.confirmMessage.deleteCredential.message": "Are you sure you want to delete \"{savedCredentialName}\"?", + "credentialEdit.credentialEdit.connection": "Connection", + "credentialEdit.credentialEdit.couldNotFindCredentialOfType": "Could not find credential of type", + "credentialEdit.credentialEdit.couldNotFindCredentialWithId": "Could not find credential with ID", + "credentialEdit.credentialEdit.delete": "Delete", + "credentialEdit.credentialEdit.details": "Details", + "credentialEdit.credentialEdit.saving": "Saving", + "credentialEdit.credentialEdit.showError.createCredential.title": "Problem creating credential", + "credentialEdit.credentialEdit.showError.deleteCredential.title": "Problem deleting credential", + "credentialEdit.credentialEdit.showError.generateAuthorizationUrl.message": "There was a problem generating the authorization URL", + "credentialEdit.credentialEdit.showError.generateAuthorizationUrl.title": "OAuth Authorization Error", + "credentialEdit.credentialEdit.showError.loadCredential.title": "Problem loading credential", + "credentialEdit.credentialEdit.showError.updateCredential.title": "Problem updating credential", + "credentialEdit.credentialEdit.showMessage.title": "Credential deleted", + "credentialEdit.credentialEdit.testing": "Testing", + "credentialEdit.credentialInfo.allowUseBy": "Allow use by", + "credentialEdit.credentialInfo.created": "Created", + "credentialEdit.credentialInfo.id": "ID", + "credentialEdit.credentialInfo.lastModified": "Last modified", + "credentialEdit.oAuthButton.connectMyAccount": "Connect my account", + "credentialEdit.oAuthButton.signInWithGoogle": "Sign in with Google", + "credentialSelectModal.addNewCredential": "Add new credential", + "credentialSelectModal.continue": "Continue", + "credentialSelectModal.searchForApp": "Search for app...", + "credentialSelectModal.selectAnAppOrServiceToConnectTo": "Select an app or service to connect to", + "credentialsList.addNew": "Add New", + "credentialsList.confirmMessage.cancelButtonText": "", + "credentialsList.confirmMessage.confirmButtonText": "Yes, delete", + "credentialsList.confirmMessage.headline": "Delete Credential?", + "credentialsList.confirmMessage.message": "Are you sure you want to delete {credentialName}?", + "credentialsList.createNewCredential": "Create New Credential", + "credentialsList.created": "Created", + "credentialsList.credentials": "Credentials", + "credentialsList.deleteCredential": "Delete Credential", + "credentialsList.editCredential": "Edit Credential", + "credentialsList.errorLoadingCredentials": "Error loading credentials", + "credentialsList.name": "@:reusableBaseText.name", + "credentialsList.operations": "Operations", + "credentialsList.showError.deleteCredential.title": "Problem deleting credential", + "credentialsList.showMessage.title": "Credential deleted", + "credentialsList.type": "Type", + "credentialsList.updated": "Updated", + "credentialsList.yourSavedCredentials": "Your saved credentials", + "dataDisplay.needHelp": "Need help?", + "dataDisplay.nodeDocumentation": "Node Documentation", + "dataDisplay.openDocumentationFor": "Open {nodeTypeDisplayName} documentation", + "displayWithChange.cancelEdit": "Cancel Edit", + "displayWithChange.clickToChange": "Click to Change", + "displayWithChange.setValue": "Set Value", + "duplicateWorkflowDialog.cancel": "@:reusableBaseText.cancel", + "duplicateWorkflowDialog.chooseOrCreateATag": "Choose or create a tag", + "duplicateWorkflowDialog.duplicateWorkflow": "Duplicate Workflow", + "duplicateWorkflowDialog.enterWorkflowName": "Enter workflow name", + "duplicateWorkflowDialog.save": "@:reusableBaseText.save", + "duplicateWorkflowDialog.showMessage.message": "Please enter a name.", + "duplicateWorkflowDialog.showMessage.title": "Name missing", "error": "Error", "error.goBack": "Go back", "error.pageNotFound": "Oops, couldn’t find that", + "executionDetails.executionFailed": "Execution failed", + "executionDetails.executionId": "Execution ID", + "executionDetails.executionWaiting": "Execution waiting", + "executionDetails.executionWasSuccessful": "Execution was successful", + "executionDetails.of": "of", + "executionDetails.openWorkflow": "Open Workflow", + "executionDetails.readOnly.readOnly": "Read only", + "executionDetails.readOnly.youreViewingTheLogOf": "You're viewing the log of a previous execution. You cannot
\n\t\tmake changes since this execution already occurred. Make changes
\n\t\tto this workflow by clicking on its name on the left.", + "executionDetails.workflow": "workflow", + "executionsList.allWorkflows": "All Workflows", + "executionsList.anyStatus": "Any Status", + "executionsList.autoRefresh": "Auto refresh", + "executionsList.confirmMessage.cancelButtonText": "", + "executionsList.confirmMessage.confirmButtonText": "Yes, delete", + "executionsList.confirmMessage.headline": "Delete Executions?", + "executionsList.confirmMessage.message": "Are you sure that you want to delete the {numSelected} selected execution(s)?", + "executionsList.deleteSelected": "Delete Selected", + "executionsList.error": "Error", + "executionsList.filters": "Filters", + "executionsList.loadMore": "Load More", + "executionsList.mode": "Mode", + "executionsList.modes.error": "error", + "executionsList.modes.integrated": "integrated", + "executionsList.modes.manual": "manual", + "executionsList.modes.retry": "retry", + "executionsList.modes.trigger": "trigger", + "executionsList.modes.webhook": "webhook", + "executionsList.name": "@:reusableBaseText.name", + "executionsList.openPastExecution": "Open Past Execution", + "executionsList.retryExecution": "Retry execution", + "executionsList.retryOf": "Retry of", + "executionsList.retryWithCurrentlySavedWorkflow": "Retry with currently saved workflow", + "executionsList.retryWithOriginalworkflow": "Retry with original workflow", + "executionsList.running": "Running", + "executionsList.runningTime": "Running Time", + "executionsList.selectStatus": "Select Status", + "executionsList.selectWorkflow": "Select Workflow", + "executionsList.selected": "Selected", + "executionsList.showError.handleDeleteSelected.title": "Problem deleting executions", + "executionsList.showError.loadMore.title": "Problem loading executions", + "executionsList.showError.loadWorkflows.title": "Problem loading workflows", + "executionsList.showError.refreshData.title": "Problem loading data", + "executionsList.showError.retryExecution.title": "Problem with retry", + "executionsList.showError.stopExecution.title": "Problem stopping execution", + "executionsList.showMessage.handleDeleteSelected.title": "Execution deleted", + "executionsList.showMessage.retrySuccessfulFalse.title": "Retry unsuccessful", + "executionsList.showMessage.retrySuccessfulTrue.title": "Retry successful", + "executionsList.showMessage.stopExecution.message": "Execution ID {activeExecutionId}", + "executionsList.showMessage.stopExecution.title": "Execution stopped", + "executionsList.startedAtId": "Started At / ID", + "executionsList.status": "Status", + "executionsList.statusTooltipText.theWorkflowExecutionFailed": "The workflow execution failed.", + "executionsList.statusTooltipText.theWorkflowExecutionFailedButTheRetryWasSuccessful": "The workflow execution failed but the retry {entryRetrySuccessId} was successful.", + "executionsList.statusTooltipText.theWorkflowExecutionIsProbablyStillRunning": "The workflow execution is probably still running but it may have crashed and n8n cannot safely tell. ", + "executionsList.statusTooltipText.theWorkflowExecutionWasARetryOfAndFailed": "The workflow execution was a retry of {entryRetryOf} and failed.
New retries have to be started from the original execution.", + "executionsList.statusTooltipText.theWorkflowExecutionWasARetryOfAndItWasSuccessful": "The workflow execution was a retry of {entryRetryOf} and it was successful.", + "executionsList.statusTooltipText.theWorkflowExecutionWasSuccessful": "The worklow execution was successful.", + "executionsList.statusTooltipText.theWorkflowIsCurrentlyExecuting": "The worklow is currently executing.", + "executionsList.statusTooltipText.theWorkflowIsWaitingIndefinitely": "The workflow is waiting indefinitely for an incoming webhook call.", + "executionsList.statusTooltipText.theWorkflowIsWaitingTill": "The worklow is waiting till {waitDateDate} {waitDateTime}.", + "executionsList.stopExecution": "Stop Execution", + "executionsList.success": "Success", + "executionsList.successRetry": "Success retry", + "executionsList.unknown": "Unknown", + "executionsList.unsavedWorkflow": "[UNSAVED WORKFLOW]", + "executionsList.waiting": "Waiting", + "executionsList.workflowExecutions": "Workflow Executions", + "expressionEdit.editExpression": "Edit Expression", + "expressionEdit.expression": "Expression", + "expressionEdit.result": "Result", + "expressionEdit.variableSelector": "Variable Selector", + "fixedCollectionParameter.choose": "Choose...", + "fixedCollectionParameter.currentlyNoItemsExist": "Currently no items exist", + "fixedCollectionParameter.deleteItem": "Delete item", + "fixedCollectionParameter.moveDown": "Move down", + "fixedCollectionParameter.moveUp": "Move up", "forgotPassword": "Forgot my password", "forgotPassword.emailSentIfExists": "We’ve emailed {email} (if there’s a matching account)", "forgotPassword.getRecoveryLink": "Email me a recovery link", @@ -1144,8 +239,370 @@ "forgotPassword.returnToSignIn": "Back to sign in", "forgotPassword.sendingEmailError": "Problem sending email", "forgotPassword.smtpErrorContactAdministrator": "Please contact your administrator (problem with your SMTP setup)", + "genericHelpers.loading": "Loading", + "genericHelpers.min": "min", + "genericHelpers.sec": "sec", + "genericHelpers.showMessage.message": "This is a read-only version of the workflow. To make changes, either open the original workflow or save it under a new name.", + "genericHelpers.showMessage.title": "Workflow cannot be changed", + "mainSidebar.aboutN8n": "About n8n", + "mainSidebar.confirmMessage.workflowDelete.cancelButtonText": "", + "mainSidebar.confirmMessage.workflowDelete.confirmButtonText": "Yes, delete", + "mainSidebar.confirmMessage.workflowDelete.headline": "Delete Workflow?", + "mainSidebar.confirmMessage.workflowDelete.message": "Are you sure that you want to delete '{workflowName}'?", + "mainSidebar.confirmMessage.workflowNew.cancelButtonText": "Leave without saving", + "mainSidebar.confirmMessage.workflowNew.confirmButtonText": "Save", + "mainSidebar.confirmMessage.workflowNew.headline": "Save changes before leaving?", + "mainSidebar.confirmMessage.workflowNew.message": "If you don't save, you will lose your changes.", + "mainSidebar.credentials": "Credentials", + "mainSidebar.delete": "Delete", + "mainSidebar.download": "Download", + "mainSidebar.duplicate": "Duplicate", + "mainSidebar.executions": "Executions", + "mainSidebar.help": "Help", + "mainSidebar.helpMenuItems.course": "Course", + "mainSidebar.helpMenuItems.documentation": "Documentation", + "mainSidebar.helpMenuItems.forum": "Forum", + "mainSidebar.importFromFile": "Import from File", + "mainSidebar.importFromUrl": "Import from URL", + "mainSidebar.new": "New", + "mainSidebar.newTemplate": "New from template", + "mainSidebar.open": "Open", + "mainSidebar.prompt.cancel": "@:reusableBaseText.cancel", + "mainSidebar.prompt.import": "Import", + "mainSidebar.prompt.importWorkflowFromUrl": "Import Workflow from URL", + "mainSidebar.prompt.invalidUrl": "Invalid URL", + "mainSidebar.prompt.workflowUrl": "Workflow URL", + "mainSidebar.save": "@:reusableBaseText.save", + "mainSidebar.settings": "Settings", + "mainSidebar.showError.stopExecution.title": "Problem stopping execution", + "mainSidebar.showMessage.handleFileImport.message": "The file does not contain valid JSON data", + "mainSidebar.showMessage.handleFileImport.title": "Could not import file", + "mainSidebar.showMessage.handleSelect1.title": "Workflow deleted", + "mainSidebar.showMessage.handleSelect2.title": "Workflow created", + "mainSidebar.showMessage.handleSelect3.title": "Workflow created", + "mainSidebar.showMessage.stopExecution.title": "Execution stopped", + "mainSidebar.templates": "Templates", + "mainSidebar.workflows": "Workflows", + "multipleParameter.addItem": "Add item", + "multipleParameter.currentlyNoItemsExist": "Currently no items exist", + "multipleParameter.deleteItem": "Delete item", + "multipleParameter.moveDown": "Move down", + "multipleParameter.moveUp": "Move up", + "ndv.backToCanvas": "Back to canvas", + "ndv.backToCanvas.waitingForTriggerWarning": "Waiting for a Trigger node to execute. Close this view to see the Workflow Canvas.", + "ndv.execute.executeNode": "Execute node", + "ndv.execute.executing": "Executing", + "ndv.execute.fetchEvent": "Fetch Event", + "ndv.execute.listenForEvent": "Listen For Event", + "ndv.output": "Output", + "ndv.output.all": "all", + "ndv.output.branch": "Branch", + "ndv.output.emptyInput": "This input item is empty. {name} will still execute when it recieves an empty item.", + "ndv.output.emptyOutput": "This output item is empty.", + "ndv.output.executing": "Executing node...", + "ndv.output.item": "item", + "ndv.output.items": "items", + "ndv.output.noOutputData.message": "n8n stops executing the workflow when a node has no output data. You can change this default behaviour via", + "ndv.output.noOutputData.message.settings": "Settings", + "ndv.output.noOutputData.message.settingsOption": "> “Always Output Data”.", + "ndv.output.noOutputData.title": "No output data returned", + "ndv.output.noOutputDataInBranch": "No output data in this branch", + "ndv.output.of": " of ", + "ndv.output.pageSize": "Page Size", + "ndv.output.pollEventNodeHint": "Fetch an event to output data", + "ndv.output.run": "Run", + "ndv.output.runNodeHint": "Execute this node to output data", + "ndv.output.staleDataWarning": "Node parameters have changed.
Execute node again to refresh output.", + "ndv.output.tooMuchData.message": "The node contains {size} MB of data. Displaying it may cause problems.
If you do decide to display it, avoid the JSON view.", + "ndv.output.tooMuchData.showDataAnyway": "Show data anyway", + "ndv.output.tooMuchData.title": "Output data is huge!", + "ndv.output.triggerEventNodeHint": "Listen for an event to output data", + "ndv.title.cancel": "Cancel", + "ndv.title.rename": "Rename", + "ndv.title.renameNode": "Rename node", + "noTagsView.readyToOrganizeYourWorkflows": "Ready to organize your workflows?", + "noTagsView.withWorkflowTagsYouReFree": "With workflow tags, you're free to create the perfect tagging system for your flows", + "node.activateDeactivateNode": "Activate/Deactivate Node", + "node.deleteNode": "Delete Node", + "node.disabled": "Disabled", + "node.duplicateNode": "Duplicate Node", + "node.editNode": "Edit Node", + "node.executeNode": "Execute Node", + "node.issues": "Issues", + "node.nodeIsExecuting": "Node is executing", + "node.nodeIsWaitingTill": "Node is waiting until {date} {time}", + "node.theNodeIsWaitingIndefinitelyForAnIncomingWebhookCall": "The node is waiting for an incoming webhook call (indefinitely)", + "node.waitingForYouToCreateAnEventIn": "Waiting for you to create an event in {nodeType}", + "nodeBase.clickToAddNodeOrDragToConnect": "Click to add node
or drag to connect", + "nodeCreator.categoryNames.analytics": "Analytics", + "nodeCreator.categoryNames.communication": "Communication", + "nodeCreator.categoryNames.coreNodes": "Core Nodes", + "nodeCreator.categoryNames.customNodes": "Custom Nodes", + "nodeCreator.categoryNames.dataStorage": "Data & Storage", + "nodeCreator.categoryNames.development": "Development", + "nodeCreator.categoryNames.financeAccounting": "Finance & Accounting", + "nodeCreator.categoryNames.marketingContent": "Marketing & Content", + "nodeCreator.categoryNames.miscellaneous": "Miscellaneous", + "nodeCreator.categoryNames.productivity": "Productivity", + "nodeCreator.categoryNames.sales": "Sales", + "nodeCreator.categoryNames.suggestedNodes": "Suggested Nodes ✨", + "nodeCreator.categoryNames.utility": "Utility", + "nodeCreator.mainPanel.all": "All", + "nodeCreator.mainPanel.regular": "Regular", + "nodeCreator.mainPanel.trigger": "Trigger", + "nodeCreator.noResults.dontWorryYouCanProbablyDoItWithThe": "Don’t worry, you can probably do it with the", + "nodeCreator.noResults.httpRequest": "HTTP Request", + "nodeCreator.noResults.node": "node", + "nodeCreator.noResults.or": "or", + "nodeCreator.noResults.requestTheNode": "Request the node", + "nodeCreator.noResults.wantUsToMakeItFaster": "Want us to make it faster?", + "nodeCreator.noResults.weDidntMakeThatYet": "We didn't make that... yet", + "nodeCreator.noResults.webhook": "Webhook", + "nodeCreator.searchBar.searchNodes": "Search nodes...", + "nodeCreator.subcategoryDescriptions.dataTransformation": "Manipulate data fields, run code", + "nodeCreator.subcategoryDescriptions.files": "Work with CSV, XML, text, images etc.", + "nodeCreator.subcategoryDescriptions.flow": "Branches, core triggers, merge data", + "nodeCreator.subcategoryDescriptions.helpers": "HTTP Requests (API calls), date and time, scrape HTML", + "nodeCreator.subcategoryNames.dataTransformation": "Data Transformation", + "nodeCreator.subcategoryNames.files": "Files", + "nodeCreator.subcategoryNames.flow": "Flow", + "nodeCreator.subcategoryNames.helpers": "Helpers", + "nodeCredentials.createNew": "Create New", + "nodeCredentials.credentialFor": "Credential for {credentialType}", + "nodeCredentials.issues": "Issues", + "nodeCredentials.selectCredential": "Select Credential", + "nodeCredentials.showMessage.message": "Nodes that used credential \"{oldCredentialName}\" have been updated to use \"{newCredentialName}\"", + "nodeCredentials.showMessage.title": "Node credential updated", + "nodeCredentials.updateCredential": "Update Credential", + "nodeErrorView.cause": "Cause", + "nodeErrorView.copyToClipboard": "Copy to Clipboard", + "nodeErrorView.dataBelowMayContain": "Data below may contain sensitive information. Proceed with caution when sharing.", + "nodeErrorView.details": "Details", + "nodeErrorView.error": "ERROR", + "nodeErrorView.httpCode": "HTTP Code", + "nodeErrorView.showMessage.title": "Copied to clipboard", + "nodeErrorView.stack": "Stack", + "nodeErrorView.theErrorCauseIsTooLargeToBeDisplayed": "The error cause is too large to be displayed", + "nodeErrorView.time": "Time", + "nodeSettings.alwaysOutputData.description": "If active, will output a single, empty item when the output would have been empty. Use to prevent the workflow finishing on this node.", + "nodeSettings.alwaysOutputData.displayName": "Always Output Data", + "nodeSettings.clickOnTheQuestionMarkIcon": "Click the '?' icon to open this node on n8n.io", + "nodeSettings.continueOnFail.description": "If active, the workflow continues even if this node's execution fails. When this occurs, the node passes along input data from previous nodes - so your workflow should account for unexpected output data.", + "nodeSettings.continueOnFail.displayName": "Continue On Fail", + "nodeSettings.docs": "Docs", + "nodeSettings.executeOnce.description": "If active, the node executes only once, with data from the first item it receives", + "nodeSettings.executeOnce.displayName": "Execute Once", + "nodeSettings.maxTries.description": "Number of times to attempt to execute the node before failing the execution", + "nodeSettings.maxTries.displayName": "Max. Tries", + "nodeSettings.noDescriptionFound": "No description found", + "nodeSettings.nodeDescription": "Node Description", + "nodeSettings.notes.description": "Optional note to save with the node", + "nodeSettings.notes.displayName": "Notes", + "nodeSettings.notesInFlow.description": "If active, the note above will display in the flow as a subtitle", + "nodeSettings.notesInFlow.displayName": "Display note in flow?", + "nodeSettings.parameters": "Parameters", + "nodeSettings.retryOnFail.description": "If active, the node tries to execute again when it fails", + "nodeSettings.retryOnFail.displayName": "Retry On Fail", + "nodeSettings.theNodeIsNotValidAsItsTypeIsUnknown": "The node is not valid as its type ({nodeType}) is unknown", + "nodeSettings.thisNodeDoesNotHaveAnyParameters": "This node does not have any parameters", + "nodeSettings.waitBetweenTries.description": "How long to wait between each attempt (in milliseconds)", + "nodeSettings.waitBetweenTries.displayName": "Wait Between Tries (ms)", + "nodeView.addNode": "Add node", + "nodeView.confirmMessage.beforeRouteLeave.cancelButtonText": "Leave without saving", + "nodeView.confirmMessage.beforeRouteLeave.confirmButtonText": "Save", + "nodeView.confirmMessage.beforeRouteLeave.headline": "Save changes before leaving?", + "nodeView.confirmMessage.beforeRouteLeave.message": "If you don't save, you will lose your changes.", + "nodeView.confirmMessage.initView.cancelButtonText": "Leave without saving", + "nodeView.confirmMessage.initView.confirmButtonText": "Save", + "nodeView.confirmMessage.initView.headline": "Save changes before leaving?", + "nodeView.confirmMessage.initView.message": "If you don't save, you will lose your changes.", + "nodeView.confirmMessage.receivedCopyPasteData.cancelButtonText": "", + "nodeView.confirmMessage.receivedCopyPasteData.confirmButtonText": "Yes, import", + "nodeView.confirmMessage.receivedCopyPasteData.headline": "Import Workflow?", + "nodeView.confirmMessage.receivedCopyPasteData.message": "Workflow will be imported from
{plainTextData}", + "nodeView.couldntImportWorkflow": "Could not import workflow", + "nodeView.deletesTheCurrentExecutionData": "Deletes the current execution data", + "nodeView.executesTheWorkflowFromTheStartOrWebhookNode": "Executes the workflow from the 'start' or 'webhook' node", + "nodeView.itLooksLikeYouHaveBeenEditingSomething": "It looks like you made some edits. If you leave before saving, your changes will be lost.", + "nodeView.loadingTemplate": "Loading template", + "nodeView.moreInfo": "More info", + "nodeView.noNodesGivenToAdd": "No nodes to add specified", + "nodeView.prompt.cancel": "@:reusableBaseText.cancel", + "nodeView.prompt.invalidName": "Invalid Name", + "nodeView.prompt.newName": "New Name", + "nodeView.prompt.rename": "Rename", + "nodeView.prompt.renameNode": "Rename Node", + "nodeView.redirecting": "Redirecting", + "nodeView.refresh": "Refresh", + "nodeView.resetZoom": "Reset Zoom", + "nodeView.runButtonText.executeWorkflow": "Execute Workflow", + "nodeView.runButtonText.executingWorkflow": "Executing Workflow", + "nodeView.runButtonText.waitingForTriggerEvent": "Waiting for Trigger Event", + "nodeView.showError.getWorkflowDataFromUrl.title": "Problem loading workflow", + "nodeView.showError.importWorkflowData.title": "Problem importing workflow", + "nodeView.showError.mounted1.message": "There was a problem loading init data", + "nodeView.showError.mounted1.title": "Init Problem", + "nodeView.showError.mounted2.message": "There was a problem initializing the workflow", + "nodeView.showError.mounted2.title": "Init Problem", + "nodeView.showError.openExecution.title": "Problem loading execution", + "nodeView.showError.openWorkflow.title": "Problem opening workflow", + "nodeView.showError.stopExecution.title": "Problem stopping execution", + "nodeView.showError.stopWaitingForWebhook.title": "Problem deleting test webhook", + "nodeView.showMessage.addNodeButton.message": "'{nodeTypeName}' is an unknown node type", + "nodeView.showMessage.addNodeButton.title": "Could not create node", + "nodeView.showMessage.keyDown.title": "Workflow created", + "nodeView.showMessage.showMaxNodeTypeError.message": "Only {count} '{nodeTypeDataDisplayName}' node is allowed in a workflow | Only {count} '{nodeTypeDataDisplayName}' nodes are allowed in a workflow", + "nodeView.showMessage.showMaxNodeTypeError.title": "Could not create node", + "nodeView.showMessage.stopExecutionCatch.message": "It completed before it could be stopped", + "nodeView.showMessage.stopExecutionCatch.title": "Workflow finished executing", + "nodeView.showMessage.stopExecutionTry.title": "Execution stopped", + "nodeView.showMessage.stopWaitingForWebhook.title": "Webhook deleted", + "nodeView.stopCurrentExecution": "Stop current execution", + "nodeView.stopWaitingForWebhookCall": "Stop waiting for webhook call", + "nodeView.stoppingCurrentExecution": "Stopping current execution", + "nodeView.thereWasAProblemLoadingTheNodeParametersOfNode": "There was a problem loading the parameters of the node", + "nodeView.thisExecutionHasntFinishedYet": "This execution hasn't finished yet", + "nodeView.toSeeTheLatestStatus": "to see the latest status", + "nodeView.workflowTemplateWithIdCouldNotBeFound": "Workflow template with ID \"{templateId}\" could not be found", + "nodeView.workflowWithIdCouldNotBeFound": "Workflow with ID \"{workflowId}\" could not be found", + "nodeView.zoomIn": "Zoom In", + "nodeView.zoomOut": "Zoom Out", + "nodeView.zoomToFit": "Zoom to Fit", + "nodeWebhooks.clickToCopyWebhookUrls": "Click to copy webhook URLs", + "nodeWebhooks.clickToDisplayWebhookUrls": "Click to display webhook URLs", + "nodeWebhooks.clickToHideWebhookUrls": "Click to hide webhook URLs", + "nodeWebhooks.invalidExpression": "[INVALID EXPRESSION]", + "nodeWebhooks.productionUrl": "Production URL", + "nodeWebhooks.showMessage.title": "URL copied", + "nodeWebhooks.testUrl": "Test URL", + "nodeWebhooks.webhookUrls": "Webhook URLs", "openWorkflow.workflowImportError": "Could not import workflow", "openWorkflow.workflowNotFoundError": "Could not find workflow", + "parameterInput.addExpression": "Add Expression", + "parameterInput.error": "ERROR", + "parameterInput.issues": "Issues", + "parameterInput.loadingOptions": "Loading options...", + "parameterInput.openEditWindow": "Open Edit Window", + "parameterInput.parameter": "Parameter: \"{shortPath}\"", + "parameterInput.parameterHasExpression": "Parameter: \"{shortPath}\" has an expression", + "parameterInput.parameterHasIssues": "Parameter: \"{shortPath}\" has issues", + "parameterInput.parameterHasIssuesAndExpression": "Parameter: \"{shortPath}\" has issues and an expression", + "parameterInput.parameterOptions": "Parameter Options", + "parameterInput.refreshList": "Refresh List", + "parameterInput.removeExpression": "Remove Expression", + "parameterInput.resetValue": "Reset Value", + "parameterInput.select": "Select", + "parameterInput.selectDateAndTime": "Select date and time", + "parameterInputExpanded.openDocs": "Open docs", + "parameterInputExpanded.thisFieldIsRequired": "This field is required", + "parameterInputList.delete": "Delete", + "parameterInputList.deleteParameter": "Delete Parameter", + "parameterInputList.parameterOptions": "Parameter Options", + "personalizationModal.automationAgencyOrConsultant": "Automation agency/consultant", + "personalizationModal.automationConsulting": "Automation consulting", + "personalizationModal.cloudInfrastructure": "Cloud infrastructure", + "personalizationModal.continue": "Continue", + "personalizationModal.customerIntegrations": "Customer integrations", + "personalizationModal.customerSupport": "Customer support", + "personalizationModal.customizeN8n": "Customize n8n to you", + "personalizationModal.digitalAgencyOrConsultant": "Digital agency/consultant", + "personalizationModal.eCommerce": "eCommerce", + "personalizationModal.education": "Education", + "personalizationModal.errorWhileSubmittingResults": "Error while submitting results", + "personalizationModal.executiveTeam": "Executive team", + "personalizationModal.financeOrAccounting": "Finance / Accounting", + "personalizationModal.financeOrInsurance": "Finance / Insurance", + "personalizationModal.getStarted": "Get started", + "personalizationModal.government": "Government", + "personalizationModal.healthcare": "Healthcare", + "personalizationModal.howAreYourCodingSkills": "How are your coding skills?", + "personalizationModal.howBigIsYourCompany": "How big is your company?", + "personalizationModal.hr": "HR", + "personalizationModal.iCanCodeSomeUsefulThingsBut": "2. I can code some useful things, but I spend a lot of time stuck", + "personalizationModal.iCanDoAlmostAnythingIWant": "5. I can do almost anything I want, easily (pro coder)", + "personalizationModal.iCanFigureMostThingsOut": "4. I can figure most things out", + "personalizationModal.iGetStuckTooQuicklyToAchieveMuch": "1. I get stuck too quickly to achieve much", + "personalizationModal.iKnowEnoughToBeDangerousBut": "3. I know enough to be dangerous, but I'm no expert", + "personalizationModal.imNotUsingN8nForWork": "I'm not using n8n for work", + "personalizationModal.individualConsumers": "Customers are individual consumers", + "personalizationModal.it": "IT", + "personalizationModal.itEngineering": "IT / Engineering", + "personalizationModal.itSupport": "IT support", + "personalizationModal.largeBusinesses": "Customers are large businesses (500+ employees)", + "personalizationModal.legal": "Legal", + "personalizationModal.lessThan20People": "Less than 20 people", + "personalizationModal.lookOutForThingsMarked": "Look out for things marked with a ✨. They are personalized to make n8n more relevant to you.", + "personalizationModal.managedServiceProvider": "Managed service provider", + "personalizationModal.manufacturing": "Manufacturing", + "personalizationModal.marketing": "Marketing", + "personalizationModal.media": "Media", + "personalizationModal.mediumBusinesses": "Customers are medium businesses (20-499 employees)", + "personalizationModal.networkingOrCommunication": "Networking / Communication", + "personalizationModal.neverCoded": "0. Never coded", + "personalizationModal.notSureYet": "Not sure yet", + "personalizationModal.operations": "Operations", + "personalizationModal.other": "Other", + "personalizationModal.otherPleaseSpecify": "Other (please specify)", + "personalizationModal.people": "people", + "personalizationModal.physicalRetailOrServices": "Physical retail or services", + "personalizationModal.pleaseSpecifyYourCompanyFocus": "Please specify your company focus", + "personalizationModal.proCoder": "Pro coder", + "personalizationModal.product": "Product (e.g. fast prototyping)", + "personalizationModal.realEstateOrConstruction": "Real estate / Construction", + "personalizationModal.saas": "SaaS", + "personalizationModal.salesAndMarketing": "Sales and Marketing", + "personalizationModal.salesBizDev": "Sales / Bizdev", + "personalizationModal.salesBusinessDevelopment": "Sales / Business Development", + "personalizationModal.security": "Security", + "personalizationModal.select": "Select...", + "personalizationModal.smallBusinesses": "Customers are small businesses (under 20 employees)", + "personalizationModal.specifyYourAutomationGoal": "Please specify your automation goal", + "personalizationModal.specifyYourCompanysIndustry": "Specify your company's industry", + "personalizationModal.specifyYourWorkArea": "Specify your work area", + "personalizationModal.support": "Support", + "personalizationModal.systemsIntegration": "Systems Integration", + "personalizationModal.systemsIntegrator": "Systems Integrator", + "personalizationModal.telecoms": "Telecoms", + "personalizationModal.thanks": "Thanks!", + "personalizationModal.theseQuestionsHelpUs": "These questions help us tailor n8n to you", + "personalizationModal.whatAreYouLookingToAutomate": "What are you looking to automate?", + "personalizationModal.whatBestDescribesYourCompany": "What best describes your company?", + "personalizationModal.whatDoesYourCompanyFocusOn": "Which services does your company focus on?", + "personalizationModal.whatKindOfCustomersDoYouServe": "What kind of customers do you serve?", + "personalizationModal.whichIndustriesIsYourCompanyIn": "Which industries is your company in?", + "pushConnection.showMessage.title": "Workflow executed successfully", + "pushConnectionTracker.cannotConnectToServer": "You have a connection issue or the server is down.
n8n should reconnect automatically once the issue is resolved.", + "pushConnectionTracker.connectionLost": "Connection lost", + "reusableBaseText.cancel": "Cancel", + "reusableBaseText.name": "Name", + "reusableBaseText.save": "Save", + "reusableDynamicText.oauth2.clientId": "Client ID", + "reusableDynamicText.oauth2.clientSecret": "Client Secret", + "runData.binary": "Binary", + "runData.copyItemPath": "Copy Item Path", + "runData.copyParameterPath": "Copy Parameter Path", + "runData.copyToClipboard": "Copy to Clipboard", + "runData.copyValue": "Copy Value", + "runData.downloadBinaryData": "Download", + "runData.executeNode": "Execute Node", + "runData.executionTime": "Execution Time", + "runData.fileExtension": "File Extension", + "runData.fileName": "File Name", + "runData.items": "Items", + "runData.json": "JSON", + "runData.mimeType": "Mime Type", + "runData.ms": "ms", + "runData.noBinaryDataFound": "No binary data found", + "runData.noData": "No data", + "runData.noTextDataFound": "No text data found", + "runData.nodeReturnedALargeAmountOfData": "Node returned a large amount of data", + "runData.output": "Output", + "runData.showBinaryData": "View", + "runData.startTime": "Start Time", + "runData.table": "Table", + "saveButton.save": "@:reusableBaseText.save", + "saveButton.saved": "Saved", + "saveButton.saving": "Saving", "settings": "Settings", "settings.goBack": "Go back", "settings.personal": "Personal", @@ -1188,10 +645,203 @@ "settings.users.userInvitedError": "User could not be invited", "settings.users.userReinviteError": "Could not reinvite user", "settings.users.userToTransferTo": "User to transfer to", + "settings.users.usersEmailedError": "Couldn't send invite email", "settings.users.usersInvited": "Users invited", "settings.users.usersInvitedError": "Could not invite users", - "settings.users.usersEmailedError": "Couldn't send invite email", "settings.version": "Version", + "showMessage.cancel": "@:reusableBaseText.cancel", + "showMessage.ok": "OK", + "showMessage.showDetails": "Show Details", "startupError": "Error connecting to n8n", - "startupError.message": "Could not connect to server. Refresh to try again" + "startupError.message": "Could not connect to server. Refresh to try again", + "tagsDropdown.createTag": "Create tag \"{filter}\"", + "tagsDropdown.manageTags": "Manage tags", + "tagsDropdown.noMatchingTagsExist": "No matching tags exist", + "tagsDropdown.noTagsExist": "No tags exist", + "tagsDropdown.showError.message": "A problem occurred when trying to create the '{name}' tag", + "tagsDropdown.showError.title": "Could not create tag", + "tagsDropdown.typeToCreateATag": "Type to create a tag", + "tagsManager.couldNotDeleteTag": "Could not delete tag", + "tagsManager.done": "Done", + "tagsManager.manageTags": "Manage tags", + "tagsManager.showError.onCreate.message": "A problem occurred when trying to create the tag '{escapedName}'", + "tagsManager.showError.onCreate.title": "Could not create tag", + "tagsManager.showError.onDelete.message": "A problem occurred when trying to delete the tag '{escapedName}'", + "tagsManager.showError.onDelete.title": "Could not delete tag", + "tagsManager.showError.onUpdate.message": "A problem occurred when trying to update the tag '{escapedName}'", + "tagsManager.showError.onUpdate.title": "Could not update tag", + "tagsManager.showMessage.onDelete.title": "Tag deleted", + "tagsManager.showMessage.onUpdate.title": "Tag updated", + "tagsManager.tagNameCannotBeEmpty": "Tag name cannot be empty", + "tagsTable.areYouSureYouWantToDeleteThisTag": "Are you sure you want to delete this tag?", + "tagsTable.cancel": "@:reusableBaseText.cancel", + "tagsTable.createTag": "Create tag", + "tagsTable.deleteTag": "Delete tag", + "tagsTable.editTag": "Edit Tag", + "tagsTable.name": "@:reusableBaseText.name", + "tagsTable.noMatchingTagsExist": "No matching tags exist", + "tagsTable.saveChanges": "Save changes?", + "tagsTable.usage": "Usage", + "tagsTableHeader.addNew": "Add new", + "tagsTableHeader.searchTags": "Search Tags", + "tagsView.inUse": "{count} workflow | {count} workflows", + "tagsView.notBeingUsed": "Not being used", + "template.buttons.goBackButton": "Go back", + "template.buttons.useThisWorkflowButton": "Use this workflow", + "template.details.appsInTheCollection": "This collection features", + "template.details.appsInTheWorkflow": "Apps in this workflow", + "template.details.by": "by", + "template.details.categories": "Categories", + "template.details.created": "Created", + "template.details.details": "Details", + "template.details.times": "times", + "template.details.viewed": "Viewed", + "templates.allCategories": "All Categories", + "templates.categoriesHeading": "Categories", + "templates.collection": "Collection", + "templates.collections": "Collections", + "templates.collectionsNotFound": "Collection could not be found", + "templates.connectionWarning": "⚠️ There was a problem fetching workflow templates. Check your internet connection.", + "templates.endResult": "Share your own useful workflows through your n8n.io account", + "templates.heading": "Workflow templates", + "templates.newButton": "New blank workflow", + "templates.noSearchResults": "Nothing found. Try adjusting your search to see more.", + "templates.searchPlaceholder": "Search workflows", + "templates.workflow": "Workflow", + "templates.workflows": "Workflows", + "templates.workflowsNotFound": "Workflow could not be found", + "textEdit.edit": "Edit", + "timeAgo.daysAgo": "%s days ago", + "timeAgo.hoursAgo": "%s hours ago", + "timeAgo.inDays": "in %s days", + "timeAgo.inHours": "in %s hours", + "timeAgo.inMinutes": "in %s minutes", + "timeAgo.inMonths": "in %s months", + "timeAgo.inOneDay": "in 1 day", + "timeAgo.inOneHour": "in 1 hour", + "timeAgo.inOneMinute": "in 1 minute", + "timeAgo.inOneMonth": "in 1 month", + "timeAgo.inOneWeek": "in 1 week", + "timeAgo.inOneYear": "in 1 year", + "timeAgo.inWeeks": "in %s weeks", + "timeAgo.inYears": "in %s years", + "timeAgo.justNow": "Just now", + "timeAgo.minutesAgo": "%s minutes ago", + "timeAgo.monthsAgo": "%s months ago", + "timeAgo.oneDayAgo": "1 day ago", + "timeAgo.oneHourAgo": "1 hour ago", + "timeAgo.oneMinuteAgo": "1 minute ago", + "timeAgo.oneMonthAgo": "1 month ago", + "timeAgo.oneWeekAgo": "1 week ago", + "timeAgo.oneYearAgo": "1 year ago", + "timeAgo.rightNow": "Right now", + "timeAgo.weeksAgo": "%s weeks ago", + "timeAgo.yearsAgo": "%s years ago", + "updatesPanel.andIs": "and is", + "updatesPanel.behindTheLatest": "behind the latest and greatest n8n", + "updatesPanel.howToUpdateYourN8nVersion": "How to update your n8n version", + "updatesPanel.version": "{numberOfVersions} version{howManySuffix}", + "updatesPanel.weVeBeenBusy": "We’ve been busy ✨", + "updatesPanel.youReOnVersion": "You’re on {currentVersionName}, which was released", + "variableSelector.context": "Context", + "variableSelector.currentNode": "Current Node", + "variableSelector.nodes": "Nodes", + "variableSelector.outputData": "Output Data", + "variableSelector.parameters": "Parameters", + "variableSelector.variableFilter": "Variable filter...", + "variableSelectorItem.empty": "--- EMPTY ---", + "variableSelectorItem.selectItem": "Select Item", + "versionCard.breakingChanges": "Breaking changes", + "versionCard.released": "Released", + "versionCard.securityUpdate": "Security update", + "versionCard.thisVersionHasASecurityIssue": "This version has a security issue.
It is listed here for completeness.", + "versionCard.unknown": "unknown", + "versionCard.version": "Version", + "workflowActivator.activateWorkflow": "Activate workflow", + "workflowActivator.deactivateWorkflow": "Deactivate workflow", + "workflowActivator.showError.title": "Workflow could not be {newStateName}", + "workflowActivator.showMessage.activeChangedNodesIssuesExistTrue.message": "Please resolve outstanding issues before you activate it", + "workflowActivator.showMessage.activeChangedNodesIssuesExistTrue.title": "Problem activating workflow", + "workflowActivator.showMessage.activeChangedWorkflowIdUndefined.message": "Please save it before activating", + "workflowActivator.showMessage.activeChangedWorkflowIdUndefined.title": "Problem activating workflow", + "workflowActivator.showMessage.displayActivationError.message.catchBlock": "Sorry there was a problem requesting the error", + "workflowActivator.showMessage.displayActivationError.message.errorDataNotUndefined": "The following error occurred on workflow activation:
{message}", + "workflowActivator.showMessage.displayActivationError.message.errorDataUndefined": "Unknown error", + "workflowActivator.showMessage.displayActivationError.title": "Problem activating workflow", + "workflowActivator.theWorkflowIsSetToBeActiveBut": "The workflow is activated but could not be started.
Click to display error message.", + "workflowActivator.thisWorkflowHasNoTriggerNodes": "This workflow has no trigger nodes that require activation", + "workflowDetails.active": "Active", + "workflowDetails.addTag": "Add tag", + "workflowDetails.chooseOrCreateATag": "Choose or create a tag", + "workflowDetails.showMessage.message": "Please enter a name, or press 'esc' to go back to the old one", + "workflowDetails.showMessage.title": "Name missing", + "workflowHelpers.showMessage.title": "Problem saving workflow", + "workflowOpen.active": "Active", + "workflowOpen.confirmMessage.cancelButtonText": "Leave without saving", + "workflowOpen.confirmMessage.confirmButtonText": "Save", + "workflowOpen.confirmMessage.headline": "Save changes before leaving?", + "workflowOpen.confirmMessage.message": "If you don't save, you will lose your changes.", + "workflowOpen.couldNotLoadActiveWorkflows": "Could not load active workflows", + "workflowOpen.created": "Created", + "workflowOpen.filterWorkflows": "Filter by tags", + "workflowOpen.name": "@:reusableBaseText.name", + "workflowOpen.openWorkflow": "Open Workflow", + "workflowOpen.searchWorkflows": "Search workflows...", + "workflowOpen.showError.title": "Problem loading workflows", + "workflowOpen.showMessage.message": "This is the current workflow", + "workflowOpen.showMessage.title": "Workflow already open", + "workflowOpen.updated": "Updated", + "workflowPreview.showError.arrayEmpty": "Must have an array of nodes", + "workflowPreview.showError.missingWorkflow": "Missing workflow", + "workflowPreview.showError.previewError.message": "Unable to preview workflow", + "workflowPreview.showError.previewError.title": "Preview error", + "workflowRun.noActiveConnectionToTheServer": "Lost connection to the server", + "workflowRun.showError.title": "Problem running workflow", + "workflowRun.showMessage.message": "Please fix them before executing", + "workflowRun.showMessage.title": "Workflow has issues", + "workflowSettings.defaultTimezone": "Default - {defaultTimezoneValue}", + "workflowSettings.defaultTimezoneNotValid": "Default Timezone not valid", + "workflowSettings.errorWorkflow": "Error Workflow", + "workflowSettings.helpTexts.errorWorkflow": "A second workflow to run if the current one fails.
The second workflow should an 'Error Trigger' node.", + "workflowSettings.helpTexts.executionTimeout": "How long the workflow should wait before timing out", + "workflowSettings.helpTexts.executionTimeoutToggle": "Whether to cancel workflow execution after a defined time", + "workflowSettings.helpTexts.saveDataErrorExecution": "Whether to save data of executions that fail", + "workflowSettings.helpTexts.saveDataSuccessExecution": "Whether to save data of executions that finish successfully", + "workflowSettings.helpTexts.saveExecutionProgress": "Whether to save data after each node execution. This allows you to resume from where execution stopped if there is an error, but may increase latency.", + "workflowSettings.helpTexts.saveManualExecutions": "Whether to save data of executions that are started manually from the editor", + "workflowSettings.helpTexts.timezone": "The timezone in which the workflow should run. Used by 'cron' node, for example.", + "workflowSettings.hours": "hours", + "workflowSettings.minutes": "minutes", + "workflowSettings.noWorkflow": "- No Workflow -", + "workflowSettings.save": "@:reusableBaseText.save", + "workflowSettings.saveDataErrorExecution": "Save failed executions", + "workflowSettings.saveDataErrorExecutionOptions.defaultSave": "Default - {defaultValue}", + "workflowSettings.saveDataErrorExecutionOptions.doNotSave": "Do not save", + "workflowSettings.saveDataErrorExecutionOptions.save": "@:reusableBaseText.save", + "workflowSettings.saveDataSuccessExecution": "Save successful executions", + "workflowSettings.saveDataSuccessExecutionOptions.defaultSave": "Default - {defaultValue}", + "workflowSettings.saveDataSuccessExecutionOptions.doNotSave": "Do not save", + "workflowSettings.saveDataSuccessExecutionOptions.save": "@:reusableBaseText.save", + "workflowSettings.saveExecutionProgress": "Save execution progress", + "workflowSettings.saveExecutionProgressOptions.defaultSave": "Default - {defaultValue}", + "workflowSettings.saveExecutionProgressOptions.no": "No", + "workflowSettings.saveExecutionProgressOptions.yes": "Yes", + "workflowSettings.saveManualExecutions": "Save manual executions", + "workflowSettings.saveManualOptions.defaultSave": "Default - {defaultValue}", + "workflowSettings.saveManualOptions.no": "No", + "workflowSettings.saveManualOptions.yes": "Yes", + "workflowSettings.seconds": "seconds", + "workflowSettings.selectOption": "Select Option", + "workflowSettings.settingsFor": "Settings for {workflowName} (#{workflowId})", + "workflowSettings.showError.saveSettings1.errorMessage": "Timeout is activated but set to 0", + "workflowSettings.showError.saveSettings1.message": "There was a problem saving the settings", + "workflowSettings.showError.saveSettings1.title": "Problem saving settings", + "workflowSettings.showError.saveSettings2.errorMessage": "Maximum Timeout is: {hours} hours, {minutes} minutes, {seconds} seconds", + "workflowSettings.showError.saveSettings2.message": "The timeout is longer than allowed", + "workflowSettings.showError.saveSettings2.title": "Problem saving settings", + "workflowSettings.showError.saveSettings3.title": "Problem saving settings", + "workflowSettings.showMessage.saveSettings.title": "Workflow settings saved", + "workflowSettings.timeoutAfter": "Timeout After", + "workflowSettings.timeoutWorkflow": "Timeout Workflow", + "workflowSettings.timezone": "Timezone" } diff --git a/packages/editor-ui/src/plugins/icons.ts b/packages/editor-ui/src/plugins/icons.ts index 22908d518d..f7c86d9ec4 100644 --- a/packages/editor-ui/src/plugins/icons.ts +++ b/packages/editor-ui/src/plugins/icons.ts @@ -61,6 +61,7 @@ import { faPause, faPauseCircle, faPen, + faPencilAlt, faPlay, faPlayCircle, faPlus, @@ -158,6 +159,7 @@ addIcon(faNetworkWired); addIcon(faPause); addIcon(faPauseCircle); addIcon(faPen); +addIcon(faPencilAlt); addIcon(faPlay); addIcon(faPlayCircle); addIcon(faPlus); diff --git a/packages/editor-ui/src/store.ts b/packages/editor-ui/src/store.ts index 418a22a33f..d465d9fce7 100644 --- a/packages/editor-ui/src/store.ts +++ b/packages/editor-ui/src/store.ts @@ -90,6 +90,7 @@ const state: IRootState = { }, sidebarMenuItems: [], instanceId: '', + nodeMetadata: {}, }; const modules = { @@ -328,6 +329,9 @@ export const store = new Vuex.Store({ if (state.lastSelectedNode === nameData.old) { state.lastSelectedNode = nameData.new; } + + Vue.set(state.nodeMetadata, nameData.new, state.nodeMetadata[nameData.old]); + Vue.delete(state.nodeMetadata, nameData.old); }, resetAllNodesIssues (state) { @@ -418,6 +422,8 @@ export const store = new Vuex.Store({ state.workflow.nodes.push(nodeData); }, removeNode (state, node: INodeUi) { + Vue.delete(state.nodeMetadata, node.name); + for (let i = 0; i < state.workflow.nodes.length; i++) { if (state.workflow.nodes[i].name === node.name) { state.workflow.nodes.splice(i, 1); @@ -470,6 +476,11 @@ export const store = new Vuex.Store({ state.stateIsDirty = true; Vue.set(node, 'parameters', updateInformation.value); + + if (!state.nodeMetadata[node.name]) { + Vue.set(state.nodeMetadata, node.name, {}); + } + Vue.set(state.nodeMetadata[node.name], 'parametersLastUpdatedAt', Date.now()); }, // Node-Index @@ -666,6 +677,10 @@ export const store = new Vuex.Store({ return state.activeExecutions; }, + getParametersLastUpdated: (state): ((name: string) => number | undefined) => { + return (nodeName: string) => state.nodeMetadata[nodeName] && state.nodeMetadata[nodeName].parametersLastUpdatedAt; + }, + getBaseUrl: (state): string => { return state.baseUrl; }, diff --git a/packages/editor-ui/src/views/NodeView.vue b/packages/editor-ui/src/views/NodeView.vue index f30472ee79..18c4b83c73 100644 --- a/packages/editor-ui/src/views/NodeView.vue +++ b/packages/editor-ui/src/views/NodeView.vue @@ -33,7 +33,7 @@ > - +
@@ -170,7 +170,6 @@ import { import { mapGetters } from 'vuex'; import { - loadLanguage, addNodeTranslation, addHeaders, } from '@/plugins/i18n'; @@ -232,9 +231,6 @@ export default mixins( deep: true, }, - async defaultLocale (newLocale, oldLocale) { - loadLanguage(newLocale); - }, }, async beforeRouteLeave(to, from, next) { const result = this.$store.getters.getStateIsDirty; @@ -271,7 +267,7 @@ export default mixins( defaultLocale (): string { return this.$store.getters.defaultLocale; }, - englishLocale(): boolean { + isEnglishLocale(): boolean { return this.defaultLocale === 'en'; }, ...mapGetters(['nativelyNumberSuffixedDefaults']), @@ -348,6 +344,7 @@ export default mixins( pullConnActiveNodeName: null as string | null, pullConnActive: false, dropPrevented: false, + renamingActive: false, }; }, beforeDestroy () { @@ -378,7 +375,7 @@ export default mixins( type?: string, }) { const allNodeNamesOnCanvas = this.$store.getters.allNodes.map((n: INodeUi) => n.name); - originalName = this.englishLocale ? originalName : this.translateName(type, originalName); + originalName = this.isEnglishLocale ? originalName : this.translateName(type, originalName); if ( !allNodeNamesOnCanvas.includes(originalName) && @@ -388,7 +385,7 @@ export default mixins( } let natives: string[] = this.nativelyNumberSuffixedDefaults; - natives = this.englishLocale ? natives : natives.map(name => { + natives = this.isEnglishLocale ? natives : natives.map(name => { const type = name.toLowerCase().replace('_', ''); return this.translateName(type, name); }); @@ -1260,15 +1257,10 @@ export default mixins( const maxNodes = nodeTypeData.maxNodes; this.$showMessage({ title: this.$locale.baseText('nodeView.showMessage.showMaxNodeTypeError.title'), - message: this.$locale.baseText( - maxNodes === 1 - ? 'nodeView.showMessage.showMaxNodeTypeError.message.singular' - : 'nodeView.showMessage.showMaxNodeTypeError.message.plural', + message: this.$locale.baseText('nodeView.showMessage.showMaxNodeTypeError.message', { - interpolate: { - maxNodes: maxNodes!.toString(), - nodeTypeDataDisplayName: nodeTypeData.displayName, - }, + adjustToNumber: maxNodes, + interpolate: { nodeTypeDataDisplayName: nodeTypeData.displayName }, }, ), type: 'error', @@ -2244,6 +2236,13 @@ export default mixins( if (currentName === newName) { return; } + + const activeNodeName = this.activeNode && this.activeNode.name; + const isActive = activeNodeName === currentName; + if (isActive) { + this.renamingActive = true; + } + // Check if node-name is unique else find one that is newName = this.getUniqueNodeName({ originalName: newName, @@ -2271,6 +2270,11 @@ export default mixins( // Make sure that the node is selected again this.deselectAllNodes(); this.nodeSelectedByName(newName); + + if (isActive) { + this.$store.commit('setActiveNode', newName); + this.renamingActive = false; + } }, deleteEveryEndpoint () { // Check as it does not exist on first load @@ -2744,15 +2748,6 @@ export default mixins( try { await Promise.all(loadPromises); - - if (this.defaultLocale !== 'en') { - try { - const headers = await this.restApi().getNodeTranslationHeaders(); - addHeaders(headers, this.defaultLocale); - } catch (_) { - // no headers available - } - } } catch (error) { this.$showError( error, diff --git a/packages/nodes-base/nodes/Cron/Cron.node.ts b/packages/nodes-base/nodes/Cron/Cron.node.ts index 4a6cfa7d02..54782b08f5 100644 --- a/packages/nodes-base/nodes/Cron/Cron.node.ts +++ b/packages/nodes-base/nodes/Cron/Cron.node.ts @@ -22,7 +22,7 @@ export class Cron implements INodeType { displayName: 'Cron', name: 'cron', icon: 'fa:calendar', - group: ['trigger'], + group: ['trigger', 'schedule'], version: 1, description: 'Triggers the workflow at a specific time', eventTriggerDescription: '', diff --git a/packages/nodes-base/nodes/Interval/Interval.node.ts b/packages/nodes-base/nodes/Interval/Interval.node.ts index c71317bdd0..61b78455b6 100644 --- a/packages/nodes-base/nodes/Interval/Interval.node.ts +++ b/packages/nodes-base/nodes/Interval/Interval.node.ts @@ -12,7 +12,7 @@ export class Interval implements INodeType { displayName: 'Interval', name: 'interval', icon: 'fa:hourglass', - group: ['trigger'], + group: ['trigger', 'schedule'], version: 1, description: 'Triggers the workflow in a given interval', eventTriggerDescription: '', From fa0ae77924acdb1fa12dc9adaf9d7d8a313649f9 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 11 Apr 2022 15:20:53 +0200 Subject: [PATCH 02/85] :arrow_up: Update package-lock.json file --- package-lock.json | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index d015e3bc59..0ab55ad483 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40219,9 +40219,9 @@ } }, "node_modules/libphonenumber-js": { - "version": "1.9.50", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.50.tgz", - "integrity": "sha512-cCzQPChw2XbordcO2LKiw5Htx5leHVfFk/EXkxNHqJfFo7Fndcb1kF5wPJpc316vCJhhikedYnVysMh3Sc7Ocw==" + "version": "1.9.51", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.51.tgz", + "integrity": "sha512-MGidRDs7s2nUybwrB/UjZT4nPXZPYQZQTu/sF3/O2v/DocmD8N6G+a9kwDt2qm7DaOo35XRt7hAIbYL+ml942Q==" }, "node_modules/libqp": { "version": "1.1.0", @@ -47486,9 +47486,9 @@ "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" }, "node_modules/react-helmet-async": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.2.3.tgz", - "integrity": "sha512-mCk2silF53Tq/YaYdkl2sB+/tDoPnaxN7dFS/6ZLJb/rhUY2EWGI5Xj2b4jHppScMqY45MbgPSwTxDchKpZ5Kw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.3.0.tgz", + "integrity": "sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==", "dependencies": { "@babel/runtime": "^7.12.5", "invariant": "^2.2.4", @@ -47497,8 +47497,8 @@ "shallowequal": "^1.1.0" }, "peerDependencies": { - "react": "^16.6.0 || ^17.0.0", - "react-dom": "^16.6.0 || ^17.0.0" + "react": "^16.6.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/react-inspector": { @@ -89651,9 +89651,9 @@ } }, "libphonenumber-js": { - "version": "1.9.50", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.50.tgz", - "integrity": "sha512-cCzQPChw2XbordcO2LKiw5Htx5leHVfFk/EXkxNHqJfFo7Fndcb1kF5wPJpc316vCJhhikedYnVysMh3Sc7Ocw==" + "version": "1.9.51", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.51.tgz", + "integrity": "sha512-MGidRDs7s2nUybwrB/UjZT4nPXZPYQZQTu/sF3/O2v/DocmD8N6G+a9kwDt2qm7DaOo35XRt7hAIbYL+ml942Q==" }, "libqp": { "version": "1.1.0", @@ -95526,9 +95526,9 @@ "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" }, "react-helmet-async": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.2.3.tgz", - "integrity": "sha512-mCk2silF53Tq/YaYdkl2sB+/tDoPnaxN7dFS/6ZLJb/rhUY2EWGI5Xj2b4jHppScMqY45MbgPSwTxDchKpZ5Kw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.3.0.tgz", + "integrity": "sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==", "requires": { "@babel/runtime": "^7.12.5", "invariant": "^2.2.4", From e440f8d45c29ed6bd012784133e1bd4b86156b9d Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 11 Apr 2022 13:21:47 +0000 Subject: [PATCH 03/85] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n-workflow@0.?= =?UTF-8?q?95.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/workflow/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/workflow/package.json b/packages/workflow/package.json index 2f41e0c92f..d6b83c6cce 100644 --- a/packages/workflow/package.json +++ b/packages/workflow/package.json @@ -1,6 +1,6 @@ { "name": "n8n-workflow", - "version": "0.94.0", + "version": "0.95.0", "description": "Workflow base code of n8n", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From 2b8a880fe8b8f1327e053000a86fde7e70d089c1 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 11 Apr 2022 13:21:55 +0000 Subject: [PATCH 04/85] :arrow_up: Set n8n-workflow@0.95.0 on n8n-core --- packages/core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/package.json b/packages/core/package.json index d44ae74fd0..28f9cfea12 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -52,7 +52,7 @@ "form-data": "^4.0.0", "lodash.get": "^4.4.2", "mime-types": "^2.1.27", - "n8n-workflow": "~0.94.0", + "n8n-workflow": "~0.95.0", "oauth-1.0a": "^2.2.6", "p-cancelable": "^2.0.0", "qs": "^6.10.1", From 27927526ad993f752e03103eb10274ca1ef14173 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 11 Apr 2022 13:21:56 +0000 Subject: [PATCH 05/85] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n-core@0.113.?= =?UTF-8?q?0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/package.json b/packages/core/package.json index 28f9cfea12..0327d7005e 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "n8n-core", - "version": "0.112.0", + "version": "0.113.0", "description": "Core functionality of n8n", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From 748bae9eb9f1b0a1b6b7617babb986f0f6c9f25f Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 11 Apr 2022 13:22:03 +0000 Subject: [PATCH 06/85] :arrow_up: Set n8n-core@0.113.0 and n8n-workflow@0.95.0 on n8n-node-dev --- packages/node-dev/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/node-dev/package.json b/packages/node-dev/package.json index d9248e3894..35a5ab68f7 100644 --- a/packages/node-dev/package.json +++ b/packages/node-dev/package.json @@ -61,8 +61,8 @@ "change-case": "^4.1.1", "copyfiles": "^2.1.1", "inquirer": "^7.0.1", - "n8n-core": "~0.112.0", - "n8n-workflow": "~0.94.0", + "n8n-core": "~0.113.0", + "n8n-workflow": "~0.95.0", "oauth-1.0a": "^2.2.6", "replace-in-file": "^6.0.0", "request": "^2.88.2", From 0469c6135f1d246393b54bdfbde4ebc1dc302475 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 11 Apr 2022 13:22:03 +0000 Subject: [PATCH 07/85] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n-node-dev@0.?= =?UTF-8?q?52.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/node-dev/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/node-dev/package.json b/packages/node-dev/package.json index 35a5ab68f7..c2a4c17063 100644 --- a/packages/node-dev/package.json +++ b/packages/node-dev/package.json @@ -1,6 +1,6 @@ { "name": "n8n-node-dev", - "version": "0.51.0", + "version": "0.52.0", "description": "CLI to simplify n8n credentials/node development", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From 24fdf292fa89d7945df79959d2c696cfa89651c8 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 11 Apr 2022 13:24:40 +0000 Subject: [PATCH 08/85] :arrow_up: Set n8n-core@0.113.0 and n8n-workflow@0.95.0 on n8n-nodes-base --- packages/nodes-base/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index cad6ad0ac9..b5021c6162 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -713,7 +713,7 @@ "@types/xml2js": "^0.4.3", "gulp": "^4.0.0", "jest": "^27.4.7", - "n8n-workflow": "~0.94.0", + "n8n-workflow": "~0.95.0", "nodelinter": "^0.1.9", "ts-jest": "^27.1.3", "tslint": "^6.1.2", @@ -755,7 +755,7 @@ "mqtt": "4.2.6", "mssql": "^6.2.0", "mysql2": "~2.3.0", - "n8n-core": "~0.112.0", + "n8n-core": "~0.113.0", "node-ssh": "^12.0.0", "nodemailer": "^6.5.0", "pdf-parse": "^1.1.1", From e1588150916b2ce64525f9100d0f5fba35f9dd7f Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 11 Apr 2022 13:24:41 +0000 Subject: [PATCH 09/85] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n-nodes-base@?= =?UTF-8?q?0.170.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 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 b5021c6162..a3d4d5bf69 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -1,6 +1,6 @@ { "name": "n8n-nodes-base", - "version": "0.169.1", + "version": "0.170.0", "description": "Base nodes of n8n", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From 9d8639af9767860d482aac018a9f0cbf157ee65c Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 11 Apr 2022 13:25:23 +0000 Subject: [PATCH 10/85] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n-design-syst?= =?UTF-8?q?em@0.17.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/design-system/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/design-system/package.json b/packages/design-system/package.json index 66a6007464..438377c930 100644 --- a/packages/design-system/package.json +++ b/packages/design-system/package.json @@ -1,6 +1,6 @@ { "name": "n8n-design-system", - "version": "0.16.0", + "version": "0.17.0", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", "author": { From a3a3aab8d01112e60622214ea9e42e24658c56e5 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 11 Apr 2022 13:25:32 +0000 Subject: [PATCH 11/85] :arrow_up: Set n8n-design-system@0.17.0 and n8n-workflow@0.95.0 on n8n-editor-ui --- packages/editor-ui/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/editor-ui/package.json b/packages/editor-ui/package.json index 897000cb91..d04e2ed6c8 100644 --- a/packages/editor-ui/package.json +++ b/packages/editor-ui/package.json @@ -26,7 +26,7 @@ "dependencies": { "@fontsource/open-sans": "^4.5.0", "luxon": "^2.3.0", - "n8n-design-system": "~0.16.0", + "n8n-design-system": "~0.17.0", "monaco-editor": "^0.29.1", "timeago.js": "^4.0.2", "v-click-outside": "^3.1.2", @@ -77,7 +77,7 @@ "lodash.debounce": "^4.0.8", "lodash.get": "^4.4.2", "lodash.set": "^4.3.2", - "n8n-workflow": "~0.94.0", + "n8n-workflow": "~0.95.0", "monaco-editor-webpack-plugin": "^5.0.0", "normalize-wheel": "^1.0.1", "prismjs": "^1.17.1", From 83a634c337d16638d53b516db4ca406beef6f335 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 11 Apr 2022 13:25:33 +0000 Subject: [PATCH 12/85] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n-editor-ui@0?= =?UTF-8?q?.139.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/editor-ui/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor-ui/package.json b/packages/editor-ui/package.json index d04e2ed6c8..36c93e3fea 100644 --- a/packages/editor-ui/package.json +++ b/packages/editor-ui/package.json @@ -1,6 +1,6 @@ { "name": "n8n-editor-ui", - "version": "0.138.0", + "version": "0.139.0", "description": "Workflow Editor UI for n8n", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From ccebf6827901b0f9b8c33af223b65e02771afbca Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 11 Apr 2022 13:27:10 +0000 Subject: [PATCH 13/85] :arrow_up: Set n8n-core@0.113.0, n8n-editor-ui@0.139.0, n8n-nodes-base@0.170.0 and n8n-workflow@0.95.0 on n8n --- packages/cli/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 7ee8937c8c..34110ff521 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -125,10 +125,10 @@ "lodash.get": "^4.4.2", "lodash.merge": "^4.6.2", "mysql2": "~2.3.0", - "n8n-core": "~0.112.0", - "n8n-editor-ui": "~0.138.0", - "n8n-nodes-base": "~0.169.1", - "n8n-workflow": "~0.94.0", + "n8n-core": "~0.113.0", + "n8n-editor-ui": "~0.139.0", + "n8n-nodes-base": "~0.170.0", + "n8n-workflow": "~0.95.0", "nodemailer": "^6.7.1", "oauth-1.0a": "^2.2.6", "open": "^7.0.0", From 6c38b79f254df7f881f4e2211e65a10fadcc55d8 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 11 Apr 2022 13:27:11 +0000 Subject: [PATCH 14/85] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n@0.172.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 34110ff521..fd59ce973d 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "n8n", - "version": "0.171.1", + "version": "0.172.0", "description": "n8n Workflow Automation Tool", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From 50868c2a95638551aa48c21d4dd8bfbed56f3687 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 11 Apr 2022 15:36:35 +0200 Subject: [PATCH 15/85] :books: Update CHANGELOG.md with version 0.171.1 and 0.172.0 --- CHANGELOG.md | 50 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bfa044c6e..c2b318329f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,27 +1,45 @@ -# [0.171.0](https://github.com/n8n-io/n8n/compare/n8n@0.170.0...n8n@0.171.0) (2022-04-03) - +# [0.172.0](https://github.com/n8n-io/n8n/compare/n8n@0.171.1...n8n@0.172.0) (2022-04-11) ### Bug Fixes -* **core:** Fix crash on webhook when last node did not return data ([c50d04a](https://github.com/n8n-io/n8n/commit/c50d04af9eb033d82860c336fc7350b5c3f22242)) -* **EmailReadImap Node:** Fix issue that crashed process if node was configured wrong ([#3079](https://github.com/n8n-io/n8n/issues/3079)) ([85f15d4](https://github.com/n8n-io/n8n/commit/85f15d49896d876fa3ab84e9fa1846f856851274)) -* **Google Tasks Node:** Fix "Show Completed" option and hide title field where not needed ([#2741](https://github.com/n8n-io/n8n/issues/2741)) ([9d703e3](https://github.com/n8n-io/n8n/commit/9d703e366b8e191e0f588469892ebb7b6d03c1d3)) -* **NocoDB Node:** Fix pagination ([#3081](https://github.com/n8n-io/n8n/issues/3081)) ([5f44b0d](https://github.com/n8n-io/n8n/commit/5f44b0dad5254fe9f985b314db8f7d43ab48c712)) -* **Salesforce Node:** Fix issue that "status" did not get used for Case => Create & Update ([#2212](https://github.com/n8n-io/n8n/issues/2212)) ([1018146](https://github.com/n8n-io/n8n/commit/1018146f21c47eda9f888bd19e92d1106c49267a)) - +- **Action Network Node:** Fix pagination issue and add credential test ([#3011](https://github.com/n8n-io/n8n/issues/3011)) ([9ef339e](https://github.com/n8n-io/n8n/commit/9ef339e5257e4aa79600554c815cb32fd226753d)) +- **core:** Set correct timezone in luxon ([#3115](https://github.com/n8n-io/n8n/issues/3115)) ([3763f81](https://github.com/n8n-io/n8n/commit/3763f815bd14dcc45786efb9b97bb85695bbf734)) +- **editor:** Fix i18n issues ([#3072](https://github.com/n8n-io/n8n/issues/3072)) ([4ae0f5b](https://github.com/n8n-io/n8n/commit/4ae0f5b6fba65bfa8f236657d89358f53e465c69)), closes [#3097](https://github.com/n8n-io/n8n/issues/3097) ### Features -* **editor:** Add download button for binary data ([#2992](https://github.com/n8n-io/n8n/issues/2992)) ([13a9db7](https://github.com/n8n-io/n8n/commit/13a9db774576a00d4e3ce1988557654d00067073)) -* **Emelia Node:** Add Campaign > Duplicate functionality ([#3000](https://github.com/n8n-io/n8n/issues/3000)) ([0b08be1](https://github.com/n8n-io/n8n/commit/0b08be1c0b2961f235fc2446a36afe3995b4d847)), closes [#3065](https://github.com/n8n-io/n8n/issues/3065) [#2741](https://github.com/n8n-io/n8n/issues/2741) [#3075](https://github.com/n8n-io/n8n/issues/3075) -* **FTP Node:** Add option to recursively create directories on rename ([#3001](https://github.com/n8n-io/n8n/issues/3001)) ([39a6f41](https://github.com/n8n-io/n8n/commit/39a6f417203b76cfa2c68816c49e86dc7236aba4)) -* **Mautic Node:** Add credential test and allow trailing slash in host ([#3080](https://github.com/n8n-io/n8n/issues/3080)) ([0a75539](https://github.com/n8n-io/n8n/commit/0a75539cc3d696a8946d7db5ff5842ff54835134)) -* **Microsoft Teams Node:** Add chat message support ([#2635](https://github.com/n8n-io/n8n/issues/2635)) ([984f62d](https://github.com/n8n-io/n8n/commit/984f62df9ed92cdf297b3b56300c9f23bf128d2d)) -* **Mocean Node:** Add "Delivery Report URL" option and credential tests ([#3075](https://github.com/n8n-io/n8n/issues/3075)) ([c89d2b1](https://github.com/n8n-io/n8n/commit/c89d2b10f2461ff8e90209b8f29c222f9430dba5)) -* **ServiceNow Node:** Add basicAuth support and fix getColumns loadOptions ([#2712](https://github.com/n8n-io/n8n/issues/2712)) ([2c72584](https://github.com/n8n-io/n8n/commit/2c72584b55521b437baa20ddad7c919807fd9f8f)), closes [#2741](https://github.com/n8n-io/n8n/issues/2741) [#3075](https://github.com/n8n-io/n8n/issues/3075) [#3000](https://github.com/n8n-io/n8n/issues/3000) [#3065](https://github.com/n8n-io/n8n/issues/3065) [#2741](https://github.com/n8n-io/n8n/issues/2741) [#3075](https://github.com/n8n-io/n8n/issues/3075) [#3071](https://github.com/n8n-io/n8n/issues/3071) [#3001](https://github.com/n8n-io/n8n/issues/3001) [#2635](https://github.com/n8n-io/n8n/issues/2635) [#3080](https://github.com/n8n-io/n8n/issues/3080) [#3061](https://github.com/n8n-io/n8n/issues/3061) [#3081](https://github.com/n8n-io/n8n/issues/3081) [#2582](https://github.com/n8n-io/n8n/issues/2582) [#2212](https://github.com/n8n-io/n8n/issues/2212) -* **Strava Node:** Add "Get Streams" operation ([#2582](https://github.com/n8n-io/n8n/issues/2582)) ([6bbb4df](https://github.com/n8n-io/n8n/commit/6bbb4df05925362404f844a23a695f186d27b72e)) +- **editor:** Refactor Node Output Panel [PR#3097](https://github.com/PR/issues/3097) +- **Magento 2 Node:** Add credential tests ([#3086](https://github.com/n8n-io/n8n/issues/3086)) ([a11b00a](https://github.com/n8n-io/n8n/commit/a11b00a0374359f0ba8fe91a1df402f32de61b15)) +- **PayPal Node:** Add auth test, fix typo and update API URL ([#3084](https://github.com/n8n-io/n8n/issues/3084)) ([c7a037e](https://github.com/n8n-io/n8n/commit/c7a037e9feed94b641e6aab92301c8a647a2934c)), closes [PR#2568](https://github.com/PR/issues/2568) +## [0.171.1](https://github.com/n8n-io/n8n/compare/n8n@0.171.0...n8n@0.171.1) (2022-04-06) +### Bug Fixes + +* **core:** Fix issue with current executions not getting displayed ([#3093](https://github.com/n8n-io/n8n/issues/3093)) ([4af5168](https://github.com/n8n-io/n8n/commit/4af5168b3bc92578dc807bab1c11e3d90e151928)) +* **core:** Fix issue with falsely skip authorizing ([#3087](https://github.com/n8n-io/n8n/issues/3087)) ([358a683](https://github.com/n8n-io/n8n/commit/358a683f381aa8eb7edd4886d6bdfe7ada61ec35)) +* **WooCommerce Node:** Fix pagination issue with "Get All" operation ([#2529](https://github.com/n8n-io/n8n/issues/2529)) ([c2a5e0d](https://github.com/n8n-io/n8n/commit/c2a5e0d1b6a89cb7397b93bbb0f0be9be0df9c86)) + +# [0.171.0](https://github.com/n8n-io/n8n/compare/n8n@0.170.0...n8n@0.171.0) (2022-04-03) + +### Bug Fixes + +- **core:** Fix crash on webhook when last node did not return data ([c50d04a](https://github.com/n8n-io/n8n/commit/c50d04af9eb033d82860c336fc7350b5c3f22242)) +- **EmailReadImap Node:** Fix issue that crashed process if node was configured wrong ([#3079](https://github.com/n8n-io/n8n/issues/3079)) ([85f15d4](https://github.com/n8n-io/n8n/commit/85f15d49896d876fa3ab84e9fa1846f856851274)) +- **Google Tasks Node:** Fix "Show Completed" option and hide title field where not needed ([#2741](https://github.com/n8n-io/n8n/issues/2741)) ([9d703e3](https://github.com/n8n-io/n8n/commit/9d703e366b8e191e0f588469892ebb7b6d03c1d3)) +- **NocoDB Node:** Fix pagination ([#3081](https://github.com/n8n-io/n8n/issues/3081)) ([5f44b0d](https://github.com/n8n-io/n8n/commit/5f44b0dad5254fe9f985b314db8f7d43ab48c712)) +- **Salesforce Node:** Fix issue that "status" did not get used for Case => Create & Update ([#2212](https://github.com/n8n-io/n8n/issues/2212)) ([1018146](https://github.com/n8n-io/n8n/commit/1018146f21c47eda9f888bd19e92d1106c49267a)) + +### Features + +- **editor:** Add download button for binary data ([#2992](https://github.com/n8n-io/n8n/issues/2992)) ([13a9db7](https://github.com/n8n-io/n8n/commit/13a9db774576a00d4e3ce1988557654d00067073)) +- **Emelia Node:** Add Campaign > Duplicate functionality ([#3000](https://github.com/n8n-io/n8n/issues/3000)) ([0b08be1](https://github.com/n8n-io/n8n/commit/0b08be1c0b2961f235fc2446a36afe3995b4d847)), closes [#3065](https://github.com/n8n-io/n8n/issues/3065) [#2741](https://github.com/n8n-io/n8n/issues/2741) [#3075](https://github.com/n8n-io/n8n/issues/3075) +- **FTP Node:** Add option to recursively create directories on rename ([#3001](https://github.com/n8n-io/n8n/issues/3001)) ([39a6f41](https://github.com/n8n-io/n8n/commit/39a6f417203b76cfa2c68816c49e86dc7236aba4)) +- **Mautic Node:** Add credential test and allow trailing slash in host ([#3080](https://github.com/n8n-io/n8n/issues/3080)) ([0a75539](https://github.com/n8n-io/n8n/commit/0a75539cc3d696a8946d7db5ff5842ff54835134)) +- **Microsoft Teams Node:** Add chat message support ([#2635](https://github.com/n8n-io/n8n/issues/2635)) ([984f62d](https://github.com/n8n-io/n8n/commit/984f62df9ed92cdf297b3b56300c9f23bf128d2d)) +- **Mocean Node:** Add "Delivery Report URL" option and credential tests ([#3075](https://github.com/n8n-io/n8n/issues/3075)) ([c89d2b1](https://github.com/n8n-io/n8n/commit/c89d2b10f2461ff8e90209b8f29c222f9430dba5)) +- **ServiceNow Node:** Add basicAuth support and fix getColumns loadOptions ([#2712](https://github.com/n8n-io/n8n/issues/2712)) ([2c72584](https://github.com/n8n-io/n8n/commit/2c72584b55521b437baa20ddad7c919807fd9f8f)), closes [#2741](https://github.com/n8n-io/n8n/issues/2741) [#3075](https://github.com/n8n-io/n8n/issues/3075) [#3000](https://github.com/n8n-io/n8n/issues/3000) [#3065](https://github.com/n8n-io/n8n/issues/3065) [#2741](https://github.com/n8n-io/n8n/issues/2741) [#3075](https://github.com/n8n-io/n8n/issues/3075) [#3071](https://github.com/n8n-io/n8n/issues/3071) [#3001](https://github.com/n8n-io/n8n/issues/3001) [#2635](https://github.com/n8n-io/n8n/issues/2635) [#3080](https://github.com/n8n-io/n8n/issues/3080) [#3061](https://github.com/n8n-io/n8n/issues/3061) [#3081](https://github.com/n8n-io/n8n/issues/3081) [#2582](https://github.com/n8n-io/n8n/issues/2582) [#2212](https://github.com/n8n-io/n8n/issues/2212) +- **Strava Node:** Add "Get Streams" operation ([#2582](https://github.com/n8n-io/n8n/issues/2582)) ([6bbb4df](https://github.com/n8n-io/n8n/commit/6bbb4df05925362404f844a23a695f186d27b72e)) # [0.170.0](https://github.com/n8n-io/n8n/compare/n8n@0.169.0...n8n@0.170.0) (2022-03-27) From 4955133b11a65f1e4145cb9a1b73632cd91f03bb Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Tue, 12 Apr 2022 19:45:53 +0200 Subject: [PATCH 16/85] :zap: Fix n8n-node-dev publish issue --- packages/node-dev/tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/node-dev/tsconfig.json b/packages/node-dev/tsconfig.json index 5eb49a044e..7e3845accb 100644 --- a/packages/node-dev/tsconfig.json +++ b/packages/node-dev/tsconfig.json @@ -14,6 +14,7 @@ "declaration": true, "outDir": "./dist/", "target": "es2019", + "useUnknownInCatchVariables": false, "sourceMap": true }, "include": [ From ecd3bbfcd3c8d77ad32c6c0b77225d18bd84f827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Thu, 14 Apr 2022 08:32:27 +0200 Subject: [PATCH 17/85] :zap: Fix credential formatting issues (#3134) * :shirt: Autofix creds lint issues * :shirt: Manually fix creds lint issues * :shirt: Fix indentation * :pencil2: Fix typo * :shirt: Fix indentation * :pencil2: Fix typo --- .../credentials/AgileCrmApi.credentials.ts | 2 +- .../credentials/Amqp.credentials.ts | 2 +- .../credentials/AsanaOAuth2Api.credentials.ts | 1 - .../credentials/BitlyOAuth2Api.credentials.ts | 3 +-- .../credentials/BitwardenApi.credentials.ts | 6 ++--- .../credentials/BubbleApi.credentials.ts | 4 ++-- .../ClickUpOAuth2Api.credentials.ts | 1 - .../credentials/ContentfulApi.credentials.ts | 6 ++--- .../credentials/CrateDb.credentials.ts | 16 ++++++------- .../credentials/CustomerIoApi.credentials.ts | 6 ++--- .../credentials/ERPNextApi.credentials.ts | 6 ++--- .../FacebookGraphAppApi.credentials.ts | 2 +- .../credentials/FormIoApi.credentials.ts | 6 ++--- .../GetResponseOAuth2Api.credentials.ts | 1 - .../credentials/GitPassword.credentials.ts | 2 +- .../credentials/GoogleApi.credentials.ts | 4 ++-- .../credentials/GotifyApi.credentials.ts | 6 ++--- .../credentials/GristApi.credentials.ts | 4 ++-- .../credentials/HaloPSAApi.credentials.ts | 7 +++--- .../HarvestOAuth2Api.credentials.ts | 1 - .../HubspotDeveloperApi.credentials.ts | 1 - .../HubspotOAuth2Api.credentials.ts | 1 - .../credentials/Kafka.credentials.ts | 10 ++++---- .../credentials/KoBoToolboxApi.credentials.ts | 2 +- .../LinkedInOAuth2Api.credentials.ts | 2 +- .../credentials/MailgunApi.credentials.ts | 3 +-- .../MailjetEmailApi.credentials.ts | 2 +- .../credentials/MarketstackApi.credentials.ts | 2 +- .../credentials/MicrosoftSql.credentials.ts | 4 ++-- .../credentials/MongoDb.credentials.ts | 2 -- .../credentials/MonicaCrmApi.credentials.ts | 6 ++--- .../credentials/Mqtt.credentials.ts | 24 +++++++++---------- .../credentials/MySql.credentials.ts | 2 +- .../credentials/OAuth1Api.credentials.ts | 2 +- .../credentials/OAuth2Api.credentials.ts | 3 +-- .../credentials/PaddleApi.credentials.ts | 2 +- .../PagerDutyOAuth2Api.credentials.ts | 1 - .../PhilipsHueOAuth2Api.credentials.ts | 1 - .../credentials/Postgres.credentials.ts | 18 +++++++------- .../credentials/QuestDb.credentials.ts | 16 ++++++------- .../credentials/RabbitMQ.credentials.ts | 10 ++++---- .../credentials/RocketchatApi.credentials.ts | 2 +- .../nodes-base/credentials/S3.credentials.ts | 4 ++-- .../SalesforceJwtApi.credentials.ts | 2 +- .../SalesforceOAuth2Api.credentials.ts | 1 - .../credentials/SeaTableApi.credentials.ts | 10 ++++---- .../credentials/Sftp.credentials.ts | 4 ++-- .../credentials/Signl4Api.credentials.ts | 2 +- .../credentials/Snowflake.credentials.ts | 6 ++--- .../credentials/TelegramApi.credentials.ts | 2 +- .../credentials/TimescaleDb.credentials.ts | 18 +++++++------- .../credentials/TwistOAuth2Api.credentials.ts | 1 - .../WebflowOAuth2Api.credentials.ts | 3 +-- .../credentials/WooCommerceApi.credentials.ts | 2 +- .../credentials/ZendeskApi.credentials.ts | 2 +- .../ZendeskOAuth2Api.credentials.ts | 5 ++-- .../credentials/ZohoOAuth2Api.credentials.ts | 12 +++++----- 57 files changed, 129 insertions(+), 147 deletions(-) diff --git a/packages/nodes-base/credentials/AgileCrmApi.credentials.ts b/packages/nodes-base/credentials/AgileCrmApi.credentials.ts index e18ff85b55..80da37d290 100644 --- a/packages/nodes-base/credentials/AgileCrmApi.credentials.ts +++ b/packages/nodes-base/credentials/AgileCrmApi.credentials.ts @@ -26,7 +26,7 @@ export class AgileCrmApi implements ICredentialType { type: 'string', default: '', placeholder: 'example', - description: 'If the domain is https://example.agilecrm.com "example" would have to be entered.', + description: 'If the domain is https://example.agilecrm.com "example" would have to be entered', }, ]; } diff --git a/packages/nodes-base/credentials/Amqp.credentials.ts b/packages/nodes-base/credentials/Amqp.credentials.ts index 4c243088d1..81816fe07a 100644 --- a/packages/nodes-base/credentials/Amqp.credentials.ts +++ b/packages/nodes-base/credentials/Amqp.credentials.ts @@ -41,7 +41,7 @@ export class Amqp implements ICredentialType { name: 'transportType', type: 'string', default: '', - description: 'Optional Transport Type to use.', + description: 'Optional Transport Type to use', }, ]; } diff --git a/packages/nodes-base/credentials/AsanaOAuth2Api.credentials.ts b/packages/nodes-base/credentials/AsanaOAuth2Api.credentials.ts index 3bb966f2ec..918425eb64 100644 --- a/packages/nodes-base/credentials/AsanaOAuth2Api.credentials.ts +++ b/packages/nodes-base/credentials/AsanaOAuth2Api.credentials.ts @@ -42,7 +42,6 @@ export class AsanaOAuth2Api implements ICredentialType { name: 'authentication', type: 'hidden', default: 'body', - description: 'Resource to consume.', }, ]; } diff --git a/packages/nodes-base/credentials/BitlyOAuth2Api.credentials.ts b/packages/nodes-base/credentials/BitlyOAuth2Api.credentials.ts index b5bdd1a557..2db80630c8 100644 --- a/packages/nodes-base/credentials/BitlyOAuth2Api.credentials.ts +++ b/packages/nodes-base/credentials/BitlyOAuth2Api.credentials.ts @@ -54,7 +54,7 @@ export class BitlyOAuth2Api implements ICredentialType { name: 'authQueryParameters', type: 'hidden', default: '', - description: 'For some services additional query parameters have to be set which can be defined here.', + description: 'For some services additional query parameters have to be set which can be defined here', placeholder: '', }, { @@ -62,7 +62,6 @@ export class BitlyOAuth2Api implements ICredentialType { name: 'authentication', type: 'hidden', default: 'body', - description: 'Resource to consume.', }, ]; } diff --git a/packages/nodes-base/credentials/BitwardenApi.credentials.ts b/packages/nodes-base/credentials/BitwardenApi.credentials.ts index 680c38be0e..376d6d6546 100644 --- a/packages/nodes-base/credentials/BitwardenApi.credentials.ts +++ b/packages/nodes-base/credentials/BitwardenApi.credentials.ts @@ -29,17 +29,17 @@ export class BitwardenApi implements ICredentialType { default: 'cloudHosted', options: [ { - name: 'Cloud-hosted', + name: 'Cloud-Hosted', value: 'cloudHosted', }, { - name: 'Self-hosted', + name: 'Self-Hosted', value: 'selfHosted', }, ], }, { - displayName: 'Self-hosted domain', + displayName: 'Self-Hosted Domain', name: 'domain', type: 'string', default: '', diff --git a/packages/nodes-base/credentials/BubbleApi.credentials.ts b/packages/nodes-base/credentials/BubbleApi.credentials.ts index 7428acbfd5..1f91de6cb1 100644 --- a/packages/nodes-base/credentials/BubbleApi.credentials.ts +++ b/packages/nodes-base/credentials/BubbleApi.credentials.ts @@ -43,11 +43,11 @@ export class BubbleApi implements ICredentialType { default: 'bubbleHosted', options: [ { - name: 'Bubble-hosted', + name: 'Bubble-Hosted', value: 'bubbleHosted', }, { - name: 'Self-hosted', + name: 'Self-Hosted', value: 'selfHosted', }, ], diff --git a/packages/nodes-base/credentials/ClickUpOAuth2Api.credentials.ts b/packages/nodes-base/credentials/ClickUpOAuth2Api.credentials.ts index cfabf116e0..b9ed95ea28 100644 --- a/packages/nodes-base/credentials/ClickUpOAuth2Api.credentials.ts +++ b/packages/nodes-base/credentials/ClickUpOAuth2Api.credentials.ts @@ -42,7 +42,6 @@ export class ClickUpOAuth2Api implements ICredentialType { name: 'authentication', type: 'hidden', default: 'body', - description: 'Resource to consume.', }, ]; } diff --git a/packages/nodes-base/credentials/ContentfulApi.credentials.ts b/packages/nodes-base/credentials/ContentfulApi.credentials.ts index 0889cee7dd..de8903cbe2 100644 --- a/packages/nodes-base/credentials/ContentfulApi.credentials.ts +++ b/packages/nodes-base/credentials/ContentfulApi.credentials.ts @@ -15,17 +15,17 @@ export class ContentfulApi implements ICredentialType { type: 'string', default: '', required: true, - description: 'The id for the Contentful space.', + description: 'The ID for the Contentful space', }, { - displayName: 'Content Delivery API Access token', + displayName: 'Content Delivery API Access Token', name: 'ContentDeliveryaccessToken', type: 'string', default: '', description: 'Access token that has access to the space. Can be left empty if only Delivery API should be used.', }, { - displayName: 'Content Preview API Access token', + displayName: 'Content Preview API Access Token', name: 'ContentPreviewaccessToken', type: 'string', default: '', diff --git a/packages/nodes-base/credentials/CrateDb.credentials.ts b/packages/nodes-base/credentials/CrateDb.credentials.ts index 9904e2ad7c..a1a94ee6d2 100644 --- a/packages/nodes-base/credentials/CrateDb.credentials.ts +++ b/packages/nodes-base/credentials/CrateDb.credentials.ts @@ -38,23 +38,23 @@ export class CrateDb implements ICredentialType { type: 'options', options: [ { - name: 'disable', - value: 'disable', - }, - { - name: 'allow', + name: 'Allow', value: 'allow', }, { - name: 'require', + name: 'Disable', + value: 'disable', + }, + { + name: 'Require', value: 'require', }, { - name: 'verify (not implemented)', + name: 'Verify (Not Implemented)', value: 'verify', }, { - name: 'verify-full (not implemented)', + name: 'Verify-Full (Not Implemented)', value: 'verify-full', }, ], diff --git a/packages/nodes-base/credentials/CustomerIoApi.credentials.ts b/packages/nodes-base/credentials/CustomerIoApi.credentials.ts index efe81d6093..5158dcf47a 100644 --- a/packages/nodes-base/credentials/CustomerIoApi.credentials.ts +++ b/packages/nodes-base/credentials/CustomerIoApi.credentials.ts @@ -14,7 +14,7 @@ export class CustomerIoApi implements ICredentialType { name: 'trackingApiKey', type: 'string', default: '', - description: 'Required for tracking API.', + description: 'Required for tracking API', required: true, }, { @@ -22,14 +22,14 @@ export class CustomerIoApi implements ICredentialType { name: 'trackingSiteId', type: 'string', default: '', - description: 'Required for tracking API.', + description: 'Required for tracking API', }, { displayName: 'App API Key', name: 'appApiKey', type: 'string', default: '', - description: 'Required for App API.', + description: 'Required for App API', }, ]; } diff --git a/packages/nodes-base/credentials/ERPNextApi.credentials.ts b/packages/nodes-base/credentials/ERPNextApi.credentials.ts index ffe6f9ac96..6ca1016457 100644 --- a/packages/nodes-base/credentials/ERPNextApi.credentials.ts +++ b/packages/nodes-base/credentials/ERPNextApi.credentials.ts @@ -27,11 +27,11 @@ export class ERPNextApi implements ICredentialType { default: 'cloudHosted', options: [ { - name: 'Cloud-hosted', + name: 'Cloud-Hosted', value: 'cloudHosted', }, { - name: 'Self-hosted', + name: 'Self-Hosted', value: 'selfHosted', }, ], @@ -57,7 +57,7 @@ export class ERPNextApi implements ICredentialType { type: 'string', default: '', placeholder: 'https://www.mydomain.com', - description: 'Fully qualified domain name of self-hosted ERPNext instance.', + description: 'Fully qualified domain name of self-hosted ERPNext instance', displayOptions: { show: { environment: [ diff --git a/packages/nodes-base/credentials/FacebookGraphAppApi.credentials.ts b/packages/nodes-base/credentials/FacebookGraphAppApi.credentials.ts index 0ffbb29c81..ae32c1882e 100644 --- a/packages/nodes-base/credentials/FacebookGraphAppApi.credentials.ts +++ b/packages/nodes-base/credentials/FacebookGraphAppApi.credentials.ts @@ -16,7 +16,7 @@ export class FacebookGraphAppApi implements ICredentialType { name: 'appSecret', type: 'string', default: '', - description: '(Optional) When the app secret is set the node will verify this signature to validate the integrity and origin of the payload.', + description: '(Optional) When the app secret is set the node will verify this signature to validate the integrity and origin of the payload', }, ]; } diff --git a/packages/nodes-base/credentials/FormIoApi.credentials.ts b/packages/nodes-base/credentials/FormIoApi.credentials.ts index e7a4f5cad1..bd1ce48b35 100644 --- a/packages/nodes-base/credentials/FormIoApi.credentials.ts +++ b/packages/nodes-base/credentials/FormIoApi.credentials.ts @@ -15,17 +15,17 @@ export class FormIoApi implements ICredentialType { default: 'cloudHosted', options: [ { - name: 'Cloud-hosted', + name: 'Cloud-Hosted', value: 'cloudHosted', }, { - name: 'Self-hosted', + name: 'Self-Hosted', value: 'selfHosted', }, ], }, { - displayName: 'Self-hosted domain', + displayName: 'Self-Hosted Domain', name: 'domain', type: 'string', default: '', diff --git a/packages/nodes-base/credentials/GetResponseOAuth2Api.credentials.ts b/packages/nodes-base/credentials/GetResponseOAuth2Api.credentials.ts index 97248b5461..9bd8e6a61e 100644 --- a/packages/nodes-base/credentials/GetResponseOAuth2Api.credentials.ts +++ b/packages/nodes-base/credentials/GetResponseOAuth2Api.credentials.ts @@ -41,7 +41,6 @@ export class GetResponseOAuth2Api implements ICredentialType { name: 'authentication', type: 'hidden', default: 'header', - description: 'Resource to consume.', }, ]; } diff --git a/packages/nodes-base/credentials/GitPassword.credentials.ts b/packages/nodes-base/credentials/GitPassword.credentials.ts index 284ca3386c..5a0b42cd6a 100644 --- a/packages/nodes-base/credentials/GitPassword.credentials.ts +++ b/packages/nodes-base/credentials/GitPassword.credentials.ts @@ -13,7 +13,7 @@ export class GitPassword implements ICredentialType { name: 'username', type: 'string', default: '', - description: 'The username to authenticate with.', + description: 'The username to authenticate with', }, { displayName: 'Password', diff --git a/packages/nodes-base/credentials/GoogleApi.credentials.ts b/packages/nodes-base/credentials/GoogleApi.credentials.ts index bf177281b9..870c2a5070 100644 --- a/packages/nodes-base/credentials/GoogleApi.credentials.ts +++ b/packages/nodes-base/credentials/GoogleApi.credentials.ts @@ -15,7 +15,7 @@ export class GoogleApi implements ICredentialType { name: 'email', type: 'string', default: '', - description: 'The Google Service account similar to user-808@project.iam.gserviceaccount.com.', + description: 'The Google Service account similar to user-808@project.iam.gserviceaccount.com', required: true, }, { @@ -45,7 +45,7 @@ export class GoogleApi implements ICredentialType { ], }, }, - description: 'The email address of the user for which the application is requesting delegated access.', + description: 'The email address of the user for which the application is requesting delegated access', }, ]; } diff --git a/packages/nodes-base/credentials/GotifyApi.credentials.ts b/packages/nodes-base/credentials/GotifyApi.credentials.ts index a5df10ec01..b2feca18da 100644 --- a/packages/nodes-base/credentials/GotifyApi.credentials.ts +++ b/packages/nodes-base/credentials/GotifyApi.credentials.ts @@ -13,21 +13,21 @@ export class GotifyApi implements ICredentialType { name: 'appApiToken', type: 'string', default: '', - description: '(Optional) Needed for message creation.', + description: '(Optional) Needed for message creation', }, { displayName: 'Client API Token', name: 'clientApiToken', type: 'string', default: '', - description: '(Optional) Needed for everything (delete, getAll) but message creation.', + description: '(Optional) Needed for everything (delete, getAll) but message creation', }, { displayName: 'URL', name: 'url', type: 'string', default: '', - description: 'The URL of the Gotify host.', + description: 'The URL of the Gotify host', }, ]; } diff --git a/packages/nodes-base/credentials/GristApi.credentials.ts b/packages/nodes-base/credentials/GristApi.credentials.ts index bf6ef314be..e7e4645035 100644 --- a/packages/nodes-base/credentials/GristApi.credentials.ts +++ b/packages/nodes-base/credentials/GristApi.credentials.ts @@ -30,7 +30,7 @@ export class GristApi implements ICredentialType { value: 'paid', }, { - name: 'Self-hosted', + name: 'Self-Hosted', value: 'selfHosted', }, ], @@ -51,7 +51,7 @@ export class GristApi implements ICredentialType { }, }, { - displayName: 'Self-hosted URL', + displayName: 'Self-Hosted URL', name: 'selfHostedUrl', type: 'string', default: '', diff --git a/packages/nodes-base/credentials/HaloPSAApi.credentials.ts b/packages/nodes-base/credentials/HaloPSAApi.credentials.ts index 43552fe716..1424a8cc9a 100644 --- a/packages/nodes-base/credentials/HaloPSAApi.credentials.ts +++ b/packages/nodes-base/credentials/HaloPSAApi.credentials.ts @@ -22,8 +22,7 @@ export class HaloPSAApi implements ICredentialType { value: 'hostedHalo', }, ], - default: '', - description: 'Hosting Type', + default: 'onPremise', }, { displayName: 'HaloPSA Authorisation Server URL', @@ -38,7 +37,7 @@ export class HaloPSAApi implements ICredentialType { type: 'string', default: '', required: true, - description: `The Resource server is available at your "Halo Web Application url/api"`, + description: 'The Resource server is available at your "Halo Web Application url/api"', }, { displayName: 'Client ID', @@ -46,7 +45,7 @@ export class HaloPSAApi implements ICredentialType { type: 'string', default: '', required: true, - description: 'Must be your application client id', + description: 'Must be your application client ID', }, { displayName: 'Client Secret', diff --git a/packages/nodes-base/credentials/HarvestOAuth2Api.credentials.ts b/packages/nodes-base/credentials/HarvestOAuth2Api.credentials.ts index 294ce9ef95..9a9a454f8d 100644 --- a/packages/nodes-base/credentials/HarvestOAuth2Api.credentials.ts +++ b/packages/nodes-base/credentials/HarvestOAuth2Api.credentials.ts @@ -42,7 +42,6 @@ export class HarvestOAuth2Api implements ICredentialType { name: 'authentication', type: 'hidden', default: 'body', - description: 'Resource to consume.', }, ]; } diff --git a/packages/nodes-base/credentials/HubspotDeveloperApi.credentials.ts b/packages/nodes-base/credentials/HubspotDeveloperApi.credentials.ts index d71b49d095..cba087f307 100644 --- a/packages/nodes-base/credentials/HubspotDeveloperApi.credentials.ts +++ b/packages/nodes-base/credentials/HubspotDeveloperApi.credentials.ts @@ -45,7 +45,6 @@ export class HubspotDeveloperApi implements ICredentialType { name: 'authentication', type: 'hidden', default: 'body', - description: 'Resource to consume.', }, { displayName: 'Developer API Key', diff --git a/packages/nodes-base/credentials/HubspotOAuth2Api.credentials.ts b/packages/nodes-base/credentials/HubspotOAuth2Api.credentials.ts index 8c5402f0ce..c2f6cf7e49 100644 --- a/packages/nodes-base/credentials/HubspotOAuth2Api.credentials.ts +++ b/packages/nodes-base/credentials/HubspotOAuth2Api.credentials.ts @@ -57,7 +57,6 @@ export class HubspotOAuth2Api implements ICredentialType { name: 'authentication', type: 'hidden', default: 'body', - description: 'Resource to consume.', }, ]; } diff --git a/packages/nodes-base/credentials/Kafka.credentials.ts b/packages/nodes-base/credentials/Kafka.credentials.ts index 17ce59f2e0..526640d20d 100644 --- a/packages/nodes-base/credentials/Kafka.credentials.ts +++ b/packages/nodes-base/credentials/Kafka.credentials.ts @@ -46,7 +46,7 @@ export class Kafka implements ICredentialType { }, }, default: '', - description: 'Optional username if authenticated is required.', + description: 'Optional username if authenticated is required', }, { displayName: 'Password', @@ -63,10 +63,10 @@ export class Kafka implements ICredentialType { password: true, }, default: '', - description: 'Optional password if authenticated is required.', + description: 'Optional password if authenticated is required', }, { - displayName: 'SASL mechanism', + displayName: 'SASL Mechanism', name: 'saslMechanism', type: 'options', displayOptions: { @@ -78,7 +78,7 @@ export class Kafka implements ICredentialType { }, options: [ { - name: 'plain', + name: 'Plain', value: 'plain', }, { @@ -91,7 +91,7 @@ export class Kafka implements ICredentialType { }, ], default: 'plain', - description: 'The SASL mechanism.', + description: 'The SASL mechanism', }, ]; } diff --git a/packages/nodes-base/credentials/KoBoToolboxApi.credentials.ts b/packages/nodes-base/credentials/KoBoToolboxApi.credentials.ts index 9fdb6bf8c6..91b1384045 100644 --- a/packages/nodes-base/credentials/KoBoToolboxApi.credentials.ts +++ b/packages/nodes-base/credentials/KoBoToolboxApi.credentials.ts @@ -10,7 +10,7 @@ export class KoBoToolboxApi implements ICredentialType { documentationUrl = 'koBoToolbox'; properties = [ { - displayName: 'API root URL', + displayName: 'API Root URL', name: 'URL', type: 'string' as NodePropertyTypes, default: 'https://kf.kobotoolbox.org/', diff --git a/packages/nodes-base/credentials/LinkedInOAuth2Api.credentials.ts b/packages/nodes-base/credentials/LinkedInOAuth2Api.credentials.ts index b5b005f37b..100e9ec779 100644 --- a/packages/nodes-base/credentials/LinkedInOAuth2Api.credentials.ts +++ b/packages/nodes-base/credentials/LinkedInOAuth2Api.credentials.ts @@ -17,7 +17,7 @@ export class LinkedInOAuth2Api implements ICredentialType { name: 'organizationSupport', type: 'boolean', default: true, - description: 'Request permissions to post as an orgaization.', + description: 'Whether to request permissions to post as an organization', }, { displayName: 'Authorization URL', diff --git a/packages/nodes-base/credentials/MailgunApi.credentials.ts b/packages/nodes-base/credentials/MailgunApi.credentials.ts index d81b339d84..e9fbb633dd 100644 --- a/packages/nodes-base/credentials/MailgunApi.credentials.ts +++ b/packages/nodes-base/credentials/MailgunApi.credentials.ts @@ -24,14 +24,13 @@ export class MailgunApi implements ICredentialType { }, ], default: 'api.mailgun.net', - description: 'The configured mailgun API domain.', + description: 'The configured mailgun API domain', }, { displayName: 'Email Domain', name: 'emailDomain', type: 'string', default: '', - description: '.', }, { displayName: 'API Key', diff --git a/packages/nodes-base/credentials/MailjetEmailApi.credentials.ts b/packages/nodes-base/credentials/MailjetEmailApi.credentials.ts index cefcc89aeb..a6b5888d86 100644 --- a/packages/nodes-base/credentials/MailjetEmailApi.credentials.ts +++ b/packages/nodes-base/credentials/MailjetEmailApi.credentials.ts @@ -25,7 +25,7 @@ export class MailjetEmailApi implements ICredentialType { name: 'sandboxMode', type: 'boolean', default: false, - description: 'Allow to run the API call in a Sandbox mode, where all validations of the payload will be done without delivering the message', + description: 'Whether to allow to run the API call in a Sandbox mode, where all validations of the payload will be done without delivering the message', }, ]; } diff --git a/packages/nodes-base/credentials/MarketstackApi.credentials.ts b/packages/nodes-base/credentials/MarketstackApi.credentials.ts index 4960f46a0e..eacf49ac01 100644 --- a/packages/nodes-base/credentials/MarketstackApi.credentials.ts +++ b/packages/nodes-base/credentials/MarketstackApi.credentials.ts @@ -19,7 +19,7 @@ export class MarketstackApi implements ICredentialType { name: 'useHttps', type: 'boolean', default: false, - description: 'Use HTTPS (paid plans only).', + description: 'Whether to use HTTPS (paid plans only)', }, ]; } diff --git a/packages/nodes-base/credentials/MicrosoftSql.credentials.ts b/packages/nodes-base/credentials/MicrosoftSql.credentials.ts index 2b09904e18..f2f63dd951 100644 --- a/packages/nodes-base/credentials/MicrosoftSql.credentials.ts +++ b/packages/nodes-base/credentials/MicrosoftSql.credentials.ts @@ -55,14 +55,14 @@ export class MicrosoftSql implements ICredentialType { name: 'connectTimeout', type: 'number', default: 15000, - description: 'Connection timeout in ms.', + description: 'Connection timeout in ms', }, { displayName: 'Request Timeout', name: 'requestTimeout', type: 'number', default: 15000, - description: ' Request timeout in ms.', + description: 'Request timeout in ms', }, ]; } diff --git a/packages/nodes-base/credentials/MongoDb.credentials.ts b/packages/nodes-base/credentials/MongoDb.credentials.ts index 896a28c0b3..ba2958a095 100644 --- a/packages/nodes-base/credentials/MongoDb.credentials.ts +++ b/packages/nodes-base/credentials/MongoDb.credentials.ts @@ -22,7 +22,6 @@ export class MongoDb implements ICredentialType { }, ], default: 'values', - description: 'The operation to perform.', }, { displayName: 'Connection String', @@ -37,7 +36,6 @@ export class MongoDb implements ICredentialType { }, default: '', placeholder: 'mongodb://:@localhost:27017/?authSource=admin&readPreference=primary&appname=n8n&ssl=false', - required: false, description: `If provided, the value here will be used as a MongoDB connection string, and the MongoDB credentials will be ignored`, }, diff --git a/packages/nodes-base/credentials/MonicaCrmApi.credentials.ts b/packages/nodes-base/credentials/MonicaCrmApi.credentials.ts index 45d400a7df..112cab38ca 100644 --- a/packages/nodes-base/credentials/MonicaCrmApi.credentials.ts +++ b/packages/nodes-base/credentials/MonicaCrmApi.credentials.ts @@ -15,17 +15,17 @@ export class MonicaCrmApi implements ICredentialType { default: 'cloudHosted', options: [ { - name: 'Cloud-hosted', + name: 'Cloud-Hosted', value: 'cloudHosted', }, { - name: 'Self-hosted', + name: 'Self-Hosted', value: 'selfHosted', }, ], }, { - displayName: 'Self-hosted domain', + displayName: 'Self-Hosted Domain', name: 'domain', type: 'string', default: '', diff --git a/packages/nodes-base/credentials/Mqtt.credentials.ts b/packages/nodes-base/credentials/Mqtt.credentials.ts index f841d37500..054d7ad784 100644 --- a/packages/nodes-base/credentials/Mqtt.credentials.ts +++ b/packages/nodes-base/credentials/Mqtt.credentials.ts @@ -15,15 +15,15 @@ export class Mqtt implements ICredentialType { type: 'options', options: [ { - name: 'mqtt', + name: 'Mqtt', value: 'mqtt', }, { - name: 'mqtts', + name: 'Mqtts', value: 'mqtts', }, { - name: 'ws', + name: 'Ws', value: 'ws', }, ], @@ -61,14 +61,14 @@ export class Mqtt implements ICredentialType { name: 'clean', type: 'boolean', default: true, - description: `Set to false to receive QoS 1 and 2 messages while offline.`, + description: 'Whether to use clean session - set to false to receive QoS 1 and 2 messages while offline', }, { displayName: 'Client ID', name: 'clientId', type: 'string', default: '', - description: 'Client ID. If left empty, one is autogenrated for you', + description: 'Client ID. If left empty, one is autogenerated for you.', }, { displayName: 'SSL', @@ -88,7 +88,7 @@ export class Mqtt implements ICredentialType { }, }, default: true, - description: 'Passwordless connection with certificates (SASL mechanism EXTERNAL)', + description: 'Whether to use passwordless connection with certificates (SASL mechanism EXTERNAL)', }, { displayName: 'CA Certificates', @@ -105,12 +105,12 @@ export class Mqtt implements ICredentialType { }, }, default: '', - description: 'SSL CA Certificates to use.', + description: 'SSL CA Certificates to use', }, { displayName: 'Reject Unauthorized Certificate', name: 'rejectUnauthorized', - type: 'boolean', + type: 'boolean', displayOptions: { show: { ssl: [ @@ -121,8 +121,8 @@ export class Mqtt implements ICredentialType { ], }, } as IDisplayOptions, - default: '', - description: 'Validate Certificate.', + default: false, + description: 'Whether to validate Certificate', }, { displayName: 'Client Certificate', @@ -142,7 +142,7 @@ export class Mqtt implements ICredentialType { }, } as IDisplayOptions, default: '', - description: 'SSL Client Certificate to use.', + description: 'SSL Client Certificate to use', }, { displayName: 'Client Key', @@ -162,7 +162,7 @@ export class Mqtt implements ICredentialType { }, }, default: '', - description: 'SSL Client Key to use.', + description: 'SSL Client Key to use', }, ]; } diff --git a/packages/nodes-base/credentials/MySql.credentials.ts b/packages/nodes-base/credentials/MySql.credentials.ts index 3e38bfa82f..1f91f0d91a 100644 --- a/packages/nodes-base/credentials/MySql.credentials.ts +++ b/packages/nodes-base/credentials/MySql.credentials.ts @@ -47,7 +47,7 @@ export class MySql implements ICredentialType { name: 'connectTimeout', type: 'number', default: 10000, - description: 'The milliseconds before a timeout occurs during the initial connection to the MySQL server.', + description: 'The milliseconds before a timeout occurs during the initial connection to the MySQL server', }, { displayName: 'SSL', diff --git a/packages/nodes-base/credentials/OAuth1Api.credentials.ts b/packages/nodes-base/credentials/OAuth1Api.credentials.ts index 614afbc65a..bbcb0bce99 100644 --- a/packages/nodes-base/credentials/OAuth1Api.credentials.ts +++ b/packages/nodes-base/credentials/OAuth1Api.credentials.ts @@ -61,7 +61,7 @@ export class OAuth1Api implements ICredentialType { value: 'HMAC-SHA512', }, ], - default: '', + default: 'HMAC-SHA1', required: true, }, ]; diff --git a/packages/nodes-base/credentials/OAuth2Api.credentials.ts b/packages/nodes-base/credentials/OAuth2Api.credentials.ts index 222444f7a5..b6c1781e81 100644 --- a/packages/nodes-base/credentials/OAuth2Api.credentials.ts +++ b/packages/nodes-base/credentials/OAuth2Api.credentials.ts @@ -51,7 +51,7 @@ export class OAuth2Api implements ICredentialType { name: 'authQueryParameters', type: 'string', default: '', - description: 'For some services additional query parameters have to be set which can be defined here.', + description: 'For some services additional query parameters have to be set which can be defined here', placeholder: 'access_type=offline', }, { @@ -71,7 +71,6 @@ export class OAuth2Api implements ICredentialType { }, ], default: 'header', - description: 'Resource to consume.', }, ]; } diff --git a/packages/nodes-base/credentials/PaddleApi.credentials.ts b/packages/nodes-base/credentials/PaddleApi.credentials.ts index 464c249f24..9b60d34e86 100644 --- a/packages/nodes-base/credentials/PaddleApi.credentials.ts +++ b/packages/nodes-base/credentials/PaddleApi.credentials.ts @@ -21,7 +21,7 @@ export class PaddleApi implements ICredentialType { default: '', }, { - displayName: 'Use Sandbox environment API', + displayName: 'Use Sandbox Environment API', name: 'sandbox', type: 'boolean', default: false, diff --git a/packages/nodes-base/credentials/PagerDutyOAuth2Api.credentials.ts b/packages/nodes-base/credentials/PagerDutyOAuth2Api.credentials.ts index 46e214bf49..a14961d303 100644 --- a/packages/nodes-base/credentials/PagerDutyOAuth2Api.credentials.ts +++ b/packages/nodes-base/credentials/PagerDutyOAuth2Api.credentials.ts @@ -40,7 +40,6 @@ export class PagerDutyOAuth2Api implements ICredentialType { name: 'authentication', type: 'hidden', default: 'header', - description: 'Method of authentication.', }, ]; } diff --git a/packages/nodes-base/credentials/PhilipsHueOAuth2Api.credentials.ts b/packages/nodes-base/credentials/PhilipsHueOAuth2Api.credentials.ts index c93712e4c5..c5ed89b6f6 100644 --- a/packages/nodes-base/credentials/PhilipsHueOAuth2Api.credentials.ts +++ b/packages/nodes-base/credentials/PhilipsHueOAuth2Api.credentials.ts @@ -46,7 +46,6 @@ export class PhilipsHueOAuth2Api implements ICredentialType { name: 'authentication', type: 'hidden', default: 'header', - description: 'Method of authentication.', }, ]; } diff --git a/packages/nodes-base/credentials/Postgres.credentials.ts b/packages/nodes-base/credentials/Postgres.credentials.ts index 304c4f700e..ccf0bc0827 100644 --- a/packages/nodes-base/credentials/Postgres.credentials.ts +++ b/packages/nodes-base/credentials/Postgres.credentials.ts @@ -41,7 +41,7 @@ export class Postgres implements ICredentialType { name: 'allowUnauthorizedCerts', type: 'boolean', default: false, - description: 'Connect even if SSL certificate validation is not possible.', + description: 'Whether to connect even if SSL certificate validation is not possible', }, { displayName: 'SSL', @@ -56,23 +56,23 @@ export class Postgres implements ICredentialType { }, options: [ { - name: 'disable', - value: 'disable', - }, - { - name: 'allow', + name: 'Allow', value: 'allow', }, { - name: 'require', + name: 'Disable', + value: 'disable', + }, + { + name: 'Require', value: 'require', }, { - name: 'verify (not implemented)', + name: 'Verify (Not Implemented)', value: 'verify', }, { - name: 'verify-full (not implemented)', + name: 'Verify-Full (Not Implemented)', value: 'verify-full', }, ], diff --git a/packages/nodes-base/credentials/QuestDb.credentials.ts b/packages/nodes-base/credentials/QuestDb.credentials.ts index ebf8828d25..fe629aff43 100644 --- a/packages/nodes-base/credentials/QuestDb.credentials.ts +++ b/packages/nodes-base/credentials/QuestDb.credentials.ts @@ -38,23 +38,23 @@ export class QuestDb implements ICredentialType { type: 'options', options: [ { - name: 'disable', - value: 'disable', - }, - { - name: 'allow', + name: 'Allow', value: 'allow', }, { - name: 'require', + name: 'Disable', + value: 'disable', + }, + { + name: 'Require', value: 'require', }, { - name: 'verify (not implemented)', + name: 'Verify (Not Implemented)', value: 'verify', }, { - name: 'verify-full (not implemented)', + name: 'Verify-Full (Not Implemented)', value: 'verify-full', }, ], diff --git a/packages/nodes-base/credentials/RabbitMQ.credentials.ts b/packages/nodes-base/credentials/RabbitMQ.credentials.ts index 416522c903..225362c3dd 100644 --- a/packages/nodes-base/credentials/RabbitMQ.credentials.ts +++ b/packages/nodes-base/credentials/RabbitMQ.credentials.ts @@ -63,7 +63,7 @@ export class RabbitMQ implements ICredentialType { }, }, default: true, - description: 'Passwordless connection with certificates (SASL mechanism EXTERNAL)', + description: 'Whether to use passwordless connection with certificates (SASL mechanism EXTERNAL)', }, { displayName: 'CA Certificates', @@ -80,7 +80,7 @@ export class RabbitMQ implements ICredentialType { }, }, default: '', - description: 'SSL CA Certificates to use.', + description: 'SSL CA Certificates to use', }, { displayName: 'Client Certificate', @@ -100,7 +100,7 @@ export class RabbitMQ implements ICredentialType { }, } as IDisplayOptions, default: '', - description: 'SSL Client Certificate to use.', + description: 'SSL Client Certificate to use', }, { displayName: 'Client Key', @@ -120,7 +120,7 @@ export class RabbitMQ implements ICredentialType { }, }, default: '', - description: 'SSL Client Key to use.', + description: 'SSL Client Key to use', }, { displayName: 'Passphrase', @@ -140,7 +140,7 @@ export class RabbitMQ implements ICredentialType { }, }, default: '', - description: 'SSL passphrase to use.', + description: 'SSL passphrase to use', }, // { // displayName: 'Client ID', diff --git a/packages/nodes-base/credentials/RocketchatApi.credentials.ts b/packages/nodes-base/credentials/RocketchatApi.credentials.ts index 68f1deb71b..d4a62db3bc 100644 --- a/packages/nodes-base/credentials/RocketchatApi.credentials.ts +++ b/packages/nodes-base/credentials/RocketchatApi.credentials.ts @@ -10,7 +10,7 @@ export class RocketchatApi implements ICredentialType { documentationUrl = 'rocketchat'; properties: INodeProperties[] = [ { - displayName: 'User Id', + displayName: 'User ID', name: 'userId', type: 'string', default: '', diff --git a/packages/nodes-base/credentials/S3.credentials.ts b/packages/nodes-base/credentials/S3.credentials.ts index 976f5910ed..4e18842391 100644 --- a/packages/nodes-base/credentials/S3.credentials.ts +++ b/packages/nodes-base/credentials/S3.credentials.ts @@ -10,7 +10,7 @@ export class S3 implements ICredentialType { documentationUrl = 's3'; properties: INodeProperties[] = [ { - displayName: 'S3 endpoint', + displayName: 'S3 Endpoint', name: 'endpoint', type: 'string', default: '', @@ -37,7 +37,7 @@ export class S3 implements ICredentialType { }, }, { - displayName: 'Force path style', + displayName: 'Force Path Style', name: 'forcePathStyle', type: 'boolean', default: false, diff --git a/packages/nodes-base/credentials/SalesforceJwtApi.credentials.ts b/packages/nodes-base/credentials/SalesforceJwtApi.credentials.ts index 58c2df5d4b..8d1d15ec9b 100644 --- a/packages/nodes-base/credentials/SalesforceJwtApi.credentials.ts +++ b/packages/nodes-base/credentials/SalesforceJwtApi.credentials.ts @@ -30,7 +30,7 @@ export class SalesforceJwtApi implements ICredentialType { type: 'string', default: '', required: true, - description: 'Consumer Key from Salesforce Connected App.', + description: 'Consumer Key from Salesforce Connected App', }, { displayName: 'Username', diff --git a/packages/nodes-base/credentials/SalesforceOAuth2Api.credentials.ts b/packages/nodes-base/credentials/SalesforceOAuth2Api.credentials.ts index 3fd9daf8d4..517fde6f5b 100644 --- a/packages/nodes-base/credentials/SalesforceOAuth2Api.credentials.ts +++ b/packages/nodes-base/credentials/SalesforceOAuth2Api.credentials.ts @@ -58,7 +58,6 @@ export class SalesforceOAuth2Api implements ICredentialType { name: 'authentication', type: 'hidden', default: 'header', - description: 'Method of authentication.', }, ]; } diff --git a/packages/nodes-base/credentials/SeaTableApi.credentials.ts b/packages/nodes-base/credentials/SeaTableApi.credentials.ts index 7b0221161c..a61b539961 100644 --- a/packages/nodes-base/credentials/SeaTableApi.credentials.ts +++ b/packages/nodes-base/credentials/SeaTableApi.credentials.ts @@ -24,17 +24,17 @@ export class SeaTableApi implements ICredentialType { default: 'cloudHosted', options: [ { - name: 'Cloud-hosted', + name: 'Cloud-Hosted', value: 'cloudHosted', }, { - name: 'Self-hosted', + name: 'Self-Hosted', value: 'selfHosted', }, ], }, { - displayName: 'Self-hosted domain', + displayName: 'Self-Hosted Domain', name: 'domain', type: 'string', default: '', @@ -57,8 +57,8 @@ export class SeaTableApi implements ICredentialType { displayName: 'Timezone', name: 'timezone', type: 'options', - default: 'Europe/Berlin', - description: `Seatable server's timezone`, + default: '', + description: 'Seatable server\'s timezone', options: [ ...timezones, ], diff --git a/packages/nodes-base/credentials/Sftp.credentials.ts b/packages/nodes-base/credentials/Sftp.credentials.ts index 1ff95bd42a..e8c6511adf 100644 --- a/packages/nodes-base/credentials/Sftp.credentials.ts +++ b/packages/nodes-base/credentials/Sftp.credentials.ts @@ -46,7 +46,7 @@ export class Sftp implements ICredentialType { alwaysOpenEditWindow: true, }, default: '', - description: 'String that contains a private key for either key-based or hostbased user authentication (OpenSSH format).', + description: 'String that contains a private key for either key-based or hostbased user authentication (OpenSSH format)', }, { displayName: 'Passphrase', @@ -56,7 +56,7 @@ export class Sftp implements ICredentialType { }, type: 'string', default: '', - description: 'For an encrypted private key, this is the passphrase used to decrypt it.', + description: 'For an encrypted private key, this is the passphrase used to decrypt it', }, ]; } diff --git a/packages/nodes-base/credentials/Signl4Api.credentials.ts b/packages/nodes-base/credentials/Signl4Api.credentials.ts index 871b621ac1..29bad1b7d8 100644 --- a/packages/nodes-base/credentials/Signl4Api.credentials.ts +++ b/packages/nodes-base/credentials/Signl4Api.credentials.ts @@ -13,7 +13,7 @@ export class Signl4Api implements ICredentialType { name: 'teamSecret', type: 'string', default: '', - description: 'The team secret is the last part of your SIGNL4 webhook URL.', + description: 'The team secret is the last part of your SIGNL4 webhook URL', }, ]; } diff --git a/packages/nodes-base/credentials/Snowflake.credentials.ts b/packages/nodes-base/credentials/Snowflake.credentials.ts index 195b1027a1..747409f500 100644 --- a/packages/nodes-base/credentials/Snowflake.credentials.ts +++ b/packages/nodes-base/credentials/Snowflake.credentials.ts @@ -13,14 +13,14 @@ export class Snowflake implements ICredentialType { name: 'account', type: 'string', default: '', - description: 'Enter the name of your Snowflake account.', + description: 'Enter the name of your Snowflake account', }, { displayName: 'Database', name: 'database', type: 'string', default: '', - description: 'Specify the database you want to use after creating the connection.', + description: 'Specify the database you want to use after creating the connection', }, { displayName: 'Warehouse', @@ -63,7 +63,7 @@ export class Snowflake implements ICredentialType { name: 'clientSessionKeepAlive', type: 'boolean', default: false, - description: `By default, client connections typically time out approximately 3-4 hours after the most recent query was executed. If the parameter clientSessionKeepAlive is set to true, the client’s connection to the server will be kept alive indefinitely, even if no queries are executed.`, + description: 'Whether to keep alive the client session. By default, client connections typically time out approximately 3-4 hours after the most recent query was executed. If the parameter clientSessionKeepAlive is set to true, the client’s connection to the server will be kept alive indefinitely, even if no queries are executed.', }, ]; } diff --git a/packages/nodes-base/credentials/TelegramApi.credentials.ts b/packages/nodes-base/credentials/TelegramApi.credentials.ts index 4634f11b0e..cc82458072 100644 --- a/packages/nodes-base/credentials/TelegramApi.credentials.ts +++ b/packages/nodes-base/credentials/TelegramApi.credentials.ts @@ -14,7 +14,7 @@ export class TelegramApi implements ICredentialType { name: 'accessToken', type: 'string', default: '', - description: 'Chat with the bot father to obtain the access token.', + description: 'Chat with the bot father to obtain the access token', }, ]; } diff --git a/packages/nodes-base/credentials/TimescaleDb.credentials.ts b/packages/nodes-base/credentials/TimescaleDb.credentials.ts index 91616a27ee..1ad133fe5b 100644 --- a/packages/nodes-base/credentials/TimescaleDb.credentials.ts +++ b/packages/nodes-base/credentials/TimescaleDb.credentials.ts @@ -40,7 +40,7 @@ export class TimescaleDb implements ICredentialType { name: 'allowUnauthorizedCerts', type: 'boolean', default: false, - description: 'Connect even if SSL certificate validation is not possible.', + description: 'Whether to connect even if SSL certificate validation is not possible', }, { displayName: 'SSL', @@ -55,23 +55,23 @@ export class TimescaleDb implements ICredentialType { }, options: [ { - name: 'disable', - value: 'disable', - }, - { - name: 'allow', + name: 'Allow', value: 'allow', }, { - name: 'require', + name: 'Disable', + value: 'disable', + }, + { + name: 'Require', value: 'require', }, { - name: 'verify (not implemented)', + name: 'Verify (Not Implemented)', value: 'verify', }, { - name: 'verify-full (not implemented)', + name: 'Verify-Full (Not Implemented)', value: 'verify-full', }, ], diff --git a/packages/nodes-base/credentials/TwistOAuth2Api.credentials.ts b/packages/nodes-base/credentials/TwistOAuth2Api.credentials.ts index dcdd5afa90..3f0011ac49 100644 --- a/packages/nodes-base/credentials/TwistOAuth2Api.credentials.ts +++ b/packages/nodes-base/credentials/TwistOAuth2Api.credentials.ts @@ -51,7 +51,6 @@ export class TwistOAuth2Api implements ICredentialType { name: 'authentication', type: 'hidden', default: 'body', - description: 'Resource to consume.', }, ]; } diff --git a/packages/nodes-base/credentials/WebflowOAuth2Api.credentials.ts b/packages/nodes-base/credentials/WebflowOAuth2Api.credentials.ts index dd352db2f7..653b114c2e 100644 --- a/packages/nodes-base/credentials/WebflowOAuth2Api.credentials.ts +++ b/packages/nodes-base/credentials/WebflowOAuth2Api.credentials.ts @@ -36,7 +36,7 @@ export class WebflowOAuth2Api implements ICredentialType { name: 'authQueryParameters', type: 'hidden', default: '', - description: 'For some services additional query parameters have to be set which can be defined here.', + description: 'For some services additional query parameters have to be set which can be defined here', placeholder: '', }, { @@ -44,7 +44,6 @@ export class WebflowOAuth2Api implements ICredentialType { name: 'authentication', type: 'hidden', default: 'body', - description: '', }, ]; } diff --git a/packages/nodes-base/credentials/WooCommerceApi.credentials.ts b/packages/nodes-base/credentials/WooCommerceApi.credentials.ts index bb9636de09..346f332c90 100644 --- a/packages/nodes-base/credentials/WooCommerceApi.credentials.ts +++ b/packages/nodes-base/credentials/WooCommerceApi.credentials.ts @@ -32,7 +32,7 @@ export class WooCommerceApi implements ICredentialType { name: 'includeCredentialsInQuery', type: 'boolean', default: false, - description: `Occasionally, some servers may not parse the Authorization header correctly (if you see a “Consumer key is missing” error when authenticating over SSL, you have a server issue). In this case, you may provide the consumer key/secret as query string parameters instead.`, + description: 'Whether credentials should be included in the query. Occasionally, some servers may not parse the Authorization header correctly (if you see a “Consumer key is missing” error when authenticating over SSL, you have a server issue). In this case, you may provide the consumer key/secret as query string parameters instead.', }, ]; } diff --git a/packages/nodes-base/credentials/ZendeskApi.credentials.ts b/packages/nodes-base/credentials/ZendeskApi.credentials.ts index a20fa0479e..879b59c63d 100644 --- a/packages/nodes-base/credentials/ZendeskApi.credentials.ts +++ b/packages/nodes-base/credentials/ZendeskApi.credentials.ts @@ -12,7 +12,7 @@ export class ZendeskApi implements ICredentialType { displayName: 'Subdomain', name: 'subdomain', type: 'string', - description: 'The subdomain of your Zendesk work environment.', + description: 'The subdomain of your Zendesk work environment', placeholder: 'company', default: '', }, diff --git a/packages/nodes-base/credentials/ZendeskOAuth2Api.credentials.ts b/packages/nodes-base/credentials/ZendeskOAuth2Api.credentials.ts index e76ca697fd..e37a1f125a 100644 --- a/packages/nodes-base/credentials/ZendeskOAuth2Api.credentials.ts +++ b/packages/nodes-base/credentials/ZendeskOAuth2Api.credentials.ts @@ -22,7 +22,7 @@ export class ZendeskOAuth2Api implements ICredentialType { type: 'string', default: '', placeholder: 'n8n', - description: 'The subdomain of your Zendesk work environment.', + description: 'The subdomain of your Zendesk work environment', required: true, }, { @@ -66,7 +66,7 @@ export class ZendeskOAuth2Api implements ICredentialType { name: 'authQueryParameters', type: 'hidden', default: '', - description: 'For some services additional query parameters have to be set which can be defined here.', + description: 'For some services additional query parameters have to be set which can be defined here', placeholder: '', }, { @@ -74,7 +74,6 @@ export class ZendeskOAuth2Api implements ICredentialType { name: 'authentication', type: 'hidden', default: 'body', - description: 'Resource to consume.', }, ]; } diff --git a/packages/nodes-base/credentials/ZohoOAuth2Api.credentials.ts b/packages/nodes-base/credentials/ZohoOAuth2Api.credentials.ts index 1f19687980..811efaeee3 100644 --- a/packages/nodes-base/credentials/ZohoOAuth2Api.credentials.ts +++ b/packages/nodes-base/credentials/ZohoOAuth2Api.credentials.ts @@ -35,14 +35,14 @@ export class ZohoOAuth2Api implements ICredentialType { name: 'accessTokenUrl', type: 'options', options: [ - { - name: 'US - https://accounts.zoho.com/oauth/v2/token', - value: 'https://accounts.zoho.com/oauth/v2/token', - }, { name: 'AU - https://accounts.zoho.com.au/oauth/v2/token', value: 'https://accounts.zoho.com.au/oauth/v2/token', }, + { + name: 'CN - https://accounts.zoho.com.cn/oauth/v2/token', + value: 'https://accounts.zoho.com.cn/oauth/v2/token', + }, { name: 'EU - https://accounts.zoho.eu/oauth/v2/token', value: 'https://accounts.zoho.eu/oauth/v2/token', @@ -52,8 +52,8 @@ export class ZohoOAuth2Api implements ICredentialType { value: 'https://accounts.zoho.in/oauth/v2/token', }, { - name: 'CN - https://accounts.zoho.com.cn/oauth/v2/token', - value: 'https://accounts.zoho.com.cn/oauth/v2/token', + name: 'US - https://accounts.zoho.com/oauth/v2/token', + value: 'https://accounts.zoho.com/oauth/v2/token', }, ], default: 'https://accounts.zoho.com/oauth/v2/token', From 445f26cc6beb141d534fa76e94797174c1fffc28 Mon Sep 17 00:00:00 2001 From: Alex Grozav Date: Thu, 14 Apr 2022 09:51:29 +0300 Subject: [PATCH 18/85] :zap: Add executeWorkflow input-output notice. (#3095) --- .../nodes/ExecuteWorkflow/ExecuteWorkflow.node.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/nodes-base/nodes/ExecuteWorkflow/ExecuteWorkflow.node.ts b/packages/nodes-base/nodes/ExecuteWorkflow/ExecuteWorkflow.node.ts index 07e5d222fe..b374b18739 100644 --- a/packages/nodes-base/nodes/ExecuteWorkflow/ExecuteWorkflow.node.ts +++ b/packages/nodes-base/nodes/ExecuteWorkflow/ExecuteWorkflow.node.ts @@ -141,6 +141,12 @@ export class ExecuteWorkflow implements INodeType { required: true, description: 'The URL from which to load the workflow from.', }, + { + displayName: 'Any data you pass into this node will be output by the start node of the workflow to be executed. More info', + name: 'executeWorkflowNotice', + type: 'notice', + default: '', + }, ], }; From 3e5d981f3f664b964a971ed8ff29ba9faa564976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Thu, 14 Apr 2022 09:02:12 +0200 Subject: [PATCH 19/85] :zap: Remove non-null assertions for `Db` collections (#3111) * :blue_book: Remove unions to `null` * :zap: Track `Db` initialization state * :fire: Remove non-null assertions * :shirt: Remove lint exceptions * :fire: Remove leftover assertion --- packages/cli/commands/execute.ts | 3 +-- packages/cli/commands/executeBatch.ts | 2 +- packages/cli/commands/export/credentials.ts | 2 +- packages/cli/commands/export/workflow.ts | 2 +- packages/cli/commands/import/credentials.ts | 9 +++---- packages/cli/commands/import/workflow.ts | 8 +++--- packages/cli/commands/list/workflow.ts | 3 +-- packages/cli/commands/start.ts | 6 ++--- packages/cli/commands/update/workflow.ts | 3 +-- .../cli/commands/user-management/reset.ts | 25 +++++++++--------- packages/cli/commands/worker.ts | 4 +-- packages/cli/src/ActiveWorkflowRunner.ts | 16 ++++++------ packages/cli/src/CredentialsHelper.ts | 17 +++++------- packages/cli/src/Db.ts | 17 ++++-------- packages/cli/src/GenericHelpers.ts | 4 +-- packages/cli/src/Interfaces.ts | 20 +++++++------- packages/cli/src/Server.ts | 2 +- .../UserManagement/UserManagementHelper.ts | 10 +++---- packages/cli/src/UserManagement/auth/jwt.ts | 2 +- .../email/UserManagementMailer.ts | 1 - .../cli/src/UserManagement/routes/auth.ts | 5 ++-- packages/cli/src/UserManagement/routes/me.ts | 7 +++-- .../cli/src/UserManagement/routes/owner.ts | 8 +++--- .../UserManagement/routes/passwordReset.ts | 10 +++---- .../cli/src/UserManagement/routes/users.ts | 22 ++++++++-------- packages/cli/src/WaitTracker.ts | 8 +++--- packages/cli/src/WorkflowCredentials.ts | 4 +-- .../cli/src/WorkflowExecuteAdditionalData.ts | 26 ++++++++----------- packages/cli/src/WorkflowHelpers.ts | 12 ++++----- packages/cli/src/WorkflowRunner.ts | 4 +-- packages/cli/src/api/credentials.api.ts | 20 +++++++------- 31 files changed, 130 insertions(+), 152 deletions(-) diff --git a/packages/cli/commands/execute.ts b/packages/cli/commands/execute.ts index ed8737bc2b..c2b51e78a4 100644 --- a/packages/cli/commands/execute.ts +++ b/packages/cli/commands/execute.ts @@ -108,8 +108,7 @@ export class Execute extends Command { if (flags.id) { // Id of workflow is given workflowId = flags.id; - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - workflowData = await Db.collections.Workflow!.findOne(workflowId); + workflowData = await Db.collections.Workflow.findOne(workflowId); if (workflowData === undefined) { console.info(`The workflow with the id "${workflowId}" does not exist.`); process.exit(1); diff --git a/packages/cli/commands/executeBatch.ts b/packages/cli/commands/executeBatch.ts index 26f4edb594..8a0f1a9baf 100644 --- a/packages/cli/commands/executeBatch.ts +++ b/packages/cli/commands/executeBatch.ts @@ -297,7 +297,7 @@ export class ExecuteBatch extends Command { let allWorkflows; - const query = Db.collections.Workflow!.createQueryBuilder('workflows'); + const query = Db.collections.Workflow.createQueryBuilder('workflows'); if (ids.length > 0) { query.andWhere(`workflows.id in (:...ids)`, { ids }); diff --git a/packages/cli/commands/export/credentials.ts b/packages/cli/commands/export/credentials.ts index 70cff781e1..ab34c9d968 100644 --- a/packages/cli/commands/export/credentials.ts +++ b/packages/cli/commands/export/credentials.ts @@ -119,7 +119,7 @@ export class ExportCredentialsCommand extends Command { } // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const credentials = await Db.collections.Credentials!.find(findQuery); + const credentials = await Db.collections.Credentials.find(findQuery); if (flags.decrypted) { const encryptionKey = await UserSettings.getEncryptionKey(); diff --git a/packages/cli/commands/export/workflow.ts b/packages/cli/commands/export/workflow.ts index 39514c0398..958efe9c2d 100644 --- a/packages/cli/commands/export/workflow.ts +++ b/packages/cli/commands/export/workflow.ts @@ -111,7 +111,7 @@ export class ExportWorkflowsCommand extends Command { } // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const workflows = await Db.collections.Workflow!.find(findQuery); + const workflows = await Db.collections.Workflow.find(findQuery); if (workflows.length === 0) { throw new Error('No workflows found with specified filters.'); diff --git a/packages/cli/commands/import/credentials.ts b/packages/cli/commands/import/credentials.ts index 98f735fe5d..eb08f1a0de 100644 --- a/packages/cli/commands/import/credentials.ts +++ b/packages/cli/commands/import/credentials.ts @@ -2,7 +2,6 @@ /* eslint-disable @typescript-eslint/no-shadow */ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable no-await-in-loop */ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable no-console */ @@ -150,7 +149,7 @@ export class ImportCredentialsCommand extends Command { } private async initOwnerCredentialRole() { - const ownerCredentialRole = await Db.collections.Role!.findOne({ + const ownerCredentialRole = await Db.collections.Role.findOne({ where: { name: 'owner', scope: 'credential' }, }); @@ -180,11 +179,11 @@ export class ImportCredentialsCommand extends Command { } private async getOwner() { - const ownerGlobalRole = await Db.collections.Role!.findOne({ + const ownerGlobalRole = await Db.collections.Role.findOne({ where: { name: 'owner', scope: 'global' }, }); - const owner = await Db.collections.User!.findOne({ globalRole: ownerGlobalRole }); + const owner = await Db.collections.User.findOne({ globalRole: ownerGlobalRole }); if (!owner) { throw new Error(`Failed to find owner. ${FIX_INSTRUCTION}`); @@ -194,7 +193,7 @@ export class ImportCredentialsCommand extends Command { } private async getAssignee(userId: string) { - const user = await Db.collections.User!.findOne(userId); + const user = await Db.collections.User.findOne(userId); if (!user) { throw new Error(`Failed to find user with ID ${userId}`); diff --git a/packages/cli/commands/import/workflow.ts b/packages/cli/commands/import/workflow.ts index f07a26c4f0..bb277400c1 100644 --- a/packages/cli/commands/import/workflow.ts +++ b/packages/cli/commands/import/workflow.ts @@ -157,7 +157,7 @@ export class ImportWorkflowsCommand extends Command { } private async initOwnerWorkflowRole() { - const ownerWorkflowRole = await Db.collections.Role!.findOne({ + const ownerWorkflowRole = await Db.collections.Role.findOne({ where: { name: 'owner', scope: 'workflow' }, }); @@ -187,11 +187,11 @@ export class ImportWorkflowsCommand extends Command { } private async getOwner() { - const ownerGlobalRole = await Db.collections.Role!.findOne({ + const ownerGlobalRole = await Db.collections.Role.findOne({ where: { name: 'owner', scope: 'global' }, }); - const owner = await Db.collections.User!.findOne({ globalRole: ownerGlobalRole }); + const owner = await Db.collections.User.findOne({ globalRole: ownerGlobalRole }); if (!owner) { throw new Error(`Failed to find owner. ${FIX_INSTRUCTION}`); @@ -201,7 +201,7 @@ export class ImportWorkflowsCommand extends Command { } private async getAssignee(userId: string) { - const user = await Db.collections.User!.findOne(userId); + const user = await Db.collections.User.findOne(userId); if (!user) { throw new Error(`Failed to find user with ID ${userId}`); diff --git a/packages/cli/commands/list/workflow.ts b/packages/cli/commands/list/workflow.ts index 19075bef0f..8d35ba7fab 100644 --- a/packages/cli/commands/list/workflow.ts +++ b/packages/cli/commands/list/workflow.ts @@ -42,8 +42,7 @@ export class ListWorkflowCommand extends Command { findQuery.active = flags.active === 'true'; } - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const workflows = await Db.collections.Workflow!.find(findQuery); + const workflows = await Db.collections.Workflow.find(findQuery); if (flags.onlyId) { workflows.forEach((workflow) => console.log(workflow.id)); } else { diff --git a/packages/cli/commands/start.ts b/packages/cli/commands/start.ts index 5eab0995e1..dc9045d830 100644 --- a/packages/cli/commands/start.ts +++ b/packages/cli/commands/start.ts @@ -217,7 +217,7 @@ export class Start extends Command { } // Load settings from database and set them to config. - const databaseSettings = await Db.collections.Settings!.find({ loadOnStartup: true }); + const databaseSettings = await Db.collections.Settings.find({ loadOnStartup: true }); databaseSettings.forEach((setting) => { config.set(setting.key, JSON.parse(setting.value)); }); @@ -287,8 +287,8 @@ export class Start extends Command { if (dbType === 'sqlite') { const shouldRunVacuum = config.getEnv('database.sqlite.executeVacuumOnStartup'); if (shouldRunVacuum) { - // eslint-disable-next-line @typescript-eslint/no-floating-promises, @typescript-eslint/no-non-null-assertion - await Db.collections.Execution!.query('VACUUM;'); + // eslint-disable-next-line @typescript-eslint/no-floating-promises + await Db.collections.Execution.query('VACUUM;'); } } diff --git a/packages/cli/commands/update/workflow.ts b/packages/cli/commands/update/workflow.ts index 7c598b4e82..735e016da7 100644 --- a/packages/cli/commands/update/workflow.ts +++ b/packages/cli/commands/update/workflow.ts @@ -72,8 +72,7 @@ export class UpdateWorkflowCommand extends Command { findQuery.active = true; } - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - await Db.collections.Workflow!.update(findQuery, updateQuery); + await Db.collections.Workflow.update(findQuery, updateQuery); console.info('Done'); } catch (e) { console.error('Error updating database. See log messages for details.'); diff --git a/packages/cli/commands/user-management/reset.ts b/packages/cli/commands/user-management/reset.ts index 404e5a8df1..1dda361b0e 100644 --- a/packages/cli/commands/user-management/reset.ts +++ b/packages/cli/commands/user-management/reset.ts @@ -1,5 +1,4 @@ /* eslint-disable no-console */ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ import Command from '@oclif/command'; import { Not } from 'typeorm'; @@ -27,33 +26,33 @@ export class Reset extends Command { try { const owner = await this.getInstanceOwner(); - const ownerWorkflowRole = await Db.collections.Role!.findOneOrFail({ + const ownerWorkflowRole = await Db.collections.Role.findOneOrFail({ name: 'owner', scope: 'workflow', }); - const ownerCredentialRole = await Db.collections.Role!.findOneOrFail({ + const ownerCredentialRole = await Db.collections.Role.findOneOrFail({ name: 'owner', scope: 'credential', }); - await Db.collections.SharedWorkflow!.update( + await Db.collections.SharedWorkflow.update( { user: { id: Not(owner.id) }, role: ownerWorkflowRole }, { user: owner }, ); - await Db.collections.SharedCredentials!.update( + await Db.collections.SharedCredentials.update( { user: { id: Not(owner.id) }, role: ownerCredentialRole }, { user: owner }, ); - await Db.collections.User!.delete({ id: Not(owner.id) }); - await Db.collections.User!.save(Object.assign(owner, this.defaultUserProps)); + await Db.collections.User.delete({ id: Not(owner.id) }); + await Db.collections.User.save(Object.assign(owner, this.defaultUserProps)); - await Db.collections.Settings!.update( + await Db.collections.Settings.update( { key: 'userManagement.isInstanceOwnerSetUp' }, { value: 'false' }, ); - await Db.collections.Settings!.update( + await Db.collections.Settings.update( { key: 'userManagement.skipInstanceOwnerSetup' }, { value: 'false' }, ); @@ -68,19 +67,19 @@ export class Reset extends Command { } private async getInstanceOwner(): Promise { - const globalRole = await Db.collections.Role!.findOneOrFail({ + const globalRole = await Db.collections.Role.findOneOrFail({ name: 'owner', scope: 'global', }); - const owner = await Db.collections.User!.findOne({ globalRole }); + const owner = await Db.collections.User.findOne({ globalRole }); if (owner) return owner; const user = new User(); - await Db.collections.User!.save(Object.assign(user, { ...this.defaultUserProps, globalRole })); + await Db.collections.User.save(Object.assign(user, { ...this.defaultUserProps, globalRole })); - return Db.collections.User!.findOneOrFail({ globalRole }); + return Db.collections.User.findOneOrFail({ globalRole }); } } diff --git a/packages/cli/commands/worker.ts b/packages/cli/commands/worker.ts index 5da36884e4..020e25c28f 100644 --- a/packages/cli/commands/worker.ts +++ b/packages/cli/commands/worker.ts @@ -119,7 +119,7 @@ export class Worker extends Command { async runJob(job: Bull.Job, nodeTypes: INodeTypes): Promise { const jobData = job.data as IBullJobData; - const executionDb = await Db.collections.Execution!.findOne(jobData.executionId); + const executionDb = await Db.collections.Execution.findOne(jobData.executionId); if (!executionDb) { LoggerProxy.error('Worker failed to find execution data in database. Cannot continue.', { @@ -139,7 +139,7 @@ export class Worker extends Command { const findOptions = { select: ['id', 'staticData'], } as FindOneOptions; - const workflowData = await Db.collections.Workflow!.findOne( + const workflowData = await Db.collections.Workflow.findOne( currentExecutionDb.workflowData.id, findOptions, ); diff --git a/packages/cli/src/ActiveWorkflowRunner.ts b/packages/cli/src/ActiveWorkflowRunner.ts index d24671a8b3..a62ab43e2f 100644 --- a/packages/cli/src/ActiveWorkflowRunner.ts +++ b/packages/cli/src/ActiveWorkflowRunner.ts @@ -69,7 +69,7 @@ export class ActiveWorkflowRunner { // NOTE // Here I guess we can have a flag on the workflow table like hasTrigger // so intead of pulling all the active wehhooks just pull the actives that have a trigger - const workflowsData: IWorkflowDb[] = (await Db.collections.Workflow!.find({ + const workflowsData: IWorkflowDb[] = (await Db.collections.Workflow.find({ where: { active: true }, relations: ['shared', 'shared.user', 'shared.user.globalRole'], })) as IWorkflowDb[]; @@ -256,7 +256,7 @@ export class ActiveWorkflowRunner { }); } - const workflowData = await Db.collections.Workflow!.findOne(webhook.workflowId, { + const workflowData = await Db.collections.Workflow.findOne(webhook.workflowId, { relations: ['shared', 'shared.user', 'shared.user.globalRole'], }); if (workflowData === undefined) { @@ -332,7 +332,7 @@ export class ActiveWorkflowRunner { * @memberof ActiveWorkflowRunner */ async getWebhookMethods(path: string): Promise { - const webhooks = (await Db.collections.Webhook?.find({ webhookPath: path })) as IWebhookDb[]; + const webhooks = await Db.collections.Webhook?.find({ webhookPath: path }); // Gather all request methods in string array const webhookMethods: string[] = webhooks.map((webhook) => webhook.method); @@ -349,12 +349,12 @@ export class ActiveWorkflowRunner { let activeWorkflows: WorkflowEntity[] = []; if (!user || user.globalRole.name === 'owner') { - activeWorkflows = await Db.collections.Workflow!.find({ + activeWorkflows = await Db.collections.Workflow.find({ select: ['id'], where: { active: true }, }); } else { - const shared = await Db.collections.SharedWorkflow!.find({ + const shared = await Db.collections.SharedWorkflow.find({ relations: ['workflow'], where: whereClause({ user, @@ -379,7 +379,7 @@ export class ActiveWorkflowRunner { * @memberof ActiveWorkflowRunner */ async isActive(id: string): Promise { - const workflow = await Db.collections.Workflow!.findOne(id); + const workflow = await Db.collections.Workflow.findOne(id); return !!workflow?.active; } @@ -512,7 +512,7 @@ export class ActiveWorkflowRunner { * @memberof ActiveWorkflowRunner */ async removeWorkflowWebhooks(workflowId: string): Promise { - const workflowData = await Db.collections.Workflow!.findOne(workflowId, { + const workflowData = await Db.collections.Workflow.findOne(workflowId, { relations: ['shared', 'shared.user', 'shared.user.globalRole'], }); if (workflowData === undefined) { @@ -715,7 +715,7 @@ export class ActiveWorkflowRunner { let workflowInstance: Workflow; try { if (workflowData === undefined) { - workflowData = (await Db.collections.Workflow!.findOne(workflowId, { + workflowData = (await Db.collections.Workflow.findOne(workflowId, { relations: ['shared', 'shared.user', 'shared.user.globalRole'], })) as IWorkflowDb; } diff --git a/packages/cli/src/CredentialsHelper.ts b/packages/cli/src/CredentialsHelper.ts index 27f838fffe..6477504b87 100644 --- a/packages/cli/src/CredentialsHelper.ts +++ b/packages/cli/src/CredentialsHelper.ts @@ -235,13 +235,11 @@ export class CredentialsHelper extends ICredentialsHelper { } const credential = userId - ? await Db.collections - .SharedCredentials!.findOneOrFail({ - relations: ['credentials'], - where: { credentials: { id: nodeCredential.id, type }, user: { id: userId } }, - }) - .then((shared) => shared.credentials) - : await Db.collections.Credentials!.findOneOrFail({ id: nodeCredential.id, type }); + ? await Db.collections.SharedCredentials.findOneOrFail({ + relations: ['credentials'], + where: { credentials: { id: nodeCredential.id, type }, user: { id: userId } }, + }).then((shared) => shared.credentials) + : await Db.collections.Credentials.findOneOrFail({ id: nodeCredential.id, type }); if (!credential) { throw new Error( @@ -445,7 +443,7 @@ export class CredentialsHelper extends ICredentialsHelper { type, }; - await Db.collections.Credentials!.update(findQuery, newCredentialsData); + await Db.collections.Credentials.update(findQuery, newCredentialsData); } getCredentialTestFunction( @@ -721,8 +719,7 @@ export async function getCredentialForUser( credentialId: string, user: User, ): Promise { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const sharedCredential = await Db.collections.SharedCredentials!.findOne({ + const sharedCredential = await Db.collections.SharedCredentials.findOne({ relations: ['credentials'], where: whereClause({ user, diff --git a/packages/cli/src/Db.ts b/packages/cli/src/Db.ts index 3ce8b993f9..5d9008ce75 100644 --- a/packages/cli/src/Db.ts +++ b/packages/cli/src/Db.ts @@ -1,3 +1,4 @@ +/* eslint-disable import/no-mutable-exports */ /* eslint-disable import/no-cycle */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/restrict-template-expressions */ @@ -28,18 +29,8 @@ import { postgresMigrations } from './databases/postgresdb/migrations'; import { mysqlMigrations } from './databases/mysqldb/migrations'; import { sqliteMigrations } from './databases/sqlite/migrations'; -export const collections: IDatabaseCollections = { - Credentials: null, - Execution: null, - Workflow: null, - Webhook: null, - Tag: null, - Role: null, - User: null, - SharedCredentials: null, - SharedWorkflow: null, - Settings: null, -}; +export let isInitialized = false; +export const collections = {} as IDatabaseCollections; let connection: Connection; @@ -202,5 +193,7 @@ export async function init( collections.SharedWorkflow = linkRepository(entities.SharedWorkflow); collections.Settings = linkRepository(entities.Settings); + isInitialized = true; + return collections; } diff --git a/packages/cli/src/GenericHelpers.ts b/packages/cli/src/GenericHelpers.ts index 82b24af246..21093f52da 100644 --- a/packages/cli/src/GenericHelpers.ts +++ b/packages/cli/src/GenericHelpers.ts @@ -165,8 +165,8 @@ export async function generateUniqueName( const found: Array = entityType === 'workflow' - ? await Db.collections.Workflow!.find(findConditions) - : await Db.collections.Credentials!.find(findConditions); + ? await Db.collections.Workflow.find(findConditions) + : await Db.collections.Credentials.find(findConditions); // name is unique if (found.length === 0) { diff --git a/packages/cli/src/Interfaces.ts b/packages/cli/src/Interfaces.ts index cf8362838a..53d96621dd 100644 --- a/packages/cli/src/Interfaces.ts +++ b/packages/cli/src/Interfaces.ts @@ -72,16 +72,16 @@ export interface ICredentialsOverwrite { } export interface IDatabaseCollections { - Credentials: Repository | null; - Execution: Repository | null; - Workflow: Repository | null; - Webhook: Repository | null; - Tag: Repository | null; - Role: Repository | null; - User: Repository | null; - SharedCredentials: Repository | null; - SharedWorkflow: Repository | null; - Settings: Repository | null; + Credentials: Repository; + Execution: Repository; + Workflow: Repository; + Webhook: Repository; + Tag: Repository; + Role: Repository; + User: Repository; + SharedCredentials: Repository; + SharedWorkflow: Repository; + Settings: Repository; } export interface IWebhookDb { diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index 14aff9569f..68155d0fd7 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -671,7 +671,7 @@ class App { // eslint-disable-next-line consistent-return this.app.use((req: express.Request, res: express.Response, next: express.NextFunction) => { - if (Db.collections.Workflow === null) { + if (!Db.isInitialized) { const error = new ResponseHelper.ResponseError('Database is not ready!', undefined, 503); return ResponseHelper.sendErrorResponse(res, error); } diff --git a/packages/cli/src/UserManagement/UserManagementHelper.ts b/packages/cli/src/UserManagement/UserManagementHelper.ts index 6c8defa448..59b29f69d7 100644 --- a/packages/cli/src/UserManagement/UserManagementHelper.ts +++ b/packages/cli/src/UserManagement/UserManagementHelper.ts @@ -15,7 +15,7 @@ import * as config from '../../config'; import { getWebhookBaseUrl } from '../WebhookHelpers'; export async function getWorkflowOwner(workflowId: string | number): Promise { - const sharedWorkflow = await Db.collections.SharedWorkflow!.findOneOrFail({ + const sharedWorkflow = await Db.collections.SharedWorkflow.findOneOrFail({ where: { workflow: { id: workflowId } }, relations: ['user', 'user.globalRole'], }); @@ -33,7 +33,7 @@ export function isEmailSetUp(): boolean { } async function getInstanceOwnerRole(): Promise { - const ownerRole = await Db.collections.Role!.findOneOrFail({ + const ownerRole = await Db.collections.Role.findOneOrFail({ where: { name: 'owner', scope: 'global', @@ -45,7 +45,7 @@ async function getInstanceOwnerRole(): Promise { export async function getInstanceOwner(): Promise { const ownerRole = await getInstanceOwnerRole(); - const owner = await Db.collections.User!.findOneOrFail({ + const owner = await Db.collections.User.findOneOrFail({ relations: ['globalRole'], where: { globalRole: ownerRole, @@ -121,7 +121,7 @@ export function sanitizeUser(user: User, withoutKeys?: string[]): PublicUser { } export async function getUserById(userId: string): Promise { - const user = await Db.collections.User!.findOneOrFail(userId, { + const user = await Db.collections.User.findOneOrFail(userId, { relations: ['globalRole'], }); return user; @@ -174,7 +174,7 @@ export async function checkPermissionsForExecution( } // Check for the user's permission to all used credentials - const credentialCount = await Db.collections.SharedCredentials!.count({ + const credentialCount = await Db.collections.SharedCredentials.count({ where: { user: { id: userId }, credentials: In(ids), diff --git a/packages/cli/src/UserManagement/auth/jwt.ts b/packages/cli/src/UserManagement/auth/jwt.ts index a247ad62b5..97d2e30ef0 100644 --- a/packages/cli/src/UserManagement/auth/jwt.ts +++ b/packages/cli/src/UserManagement/auth/jwt.ts @@ -37,7 +37,7 @@ export function issueJWT(user: User): JwtToken { } export async function resolveJwtContent(jwtPayload: JwtPayload): Promise { - const user = await Db.collections.User!.findOne(jwtPayload.id, { + const user = await Db.collections.User.findOne(jwtPayload.id, { relations: ['globalRole'], }); diff --git a/packages/cli/src/UserManagement/email/UserManagementMailer.ts b/packages/cli/src/UserManagement/email/UserManagementMailer.ts index 5b706aadfc..cda715a7c7 100644 --- a/packages/cli/src/UserManagement/email/UserManagementMailer.ts +++ b/packages/cli/src/UserManagement/email/UserManagementMailer.ts @@ -60,7 +60,6 @@ export class UserManagementMailer { let template = await getTemplate('invite', 'invite.html'); template = replaceStrings(template, inviteEmailData); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const result = await this.mailer?.sendMail({ emailRecipients: inviteEmailData.email, subject: 'You have been invited to n8n', diff --git a/packages/cli/src/UserManagement/routes/auth.ts b/packages/cli/src/UserManagement/routes/auth.ts index 628bade65d..a5d865eac0 100644 --- a/packages/cli/src/UserManagement/routes/auth.ts +++ b/packages/cli/src/UserManagement/routes/auth.ts @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable import/no-cycle */ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ import { Request, Response } from 'express'; import { IDataObject } from 'n8n-workflow'; @@ -32,7 +31,7 @@ export function authenticationMethods(this: N8nApp): void { let user; try { - user = await Db.collections.User!.findOne( + user = await Db.collections.User.findOne( { email: req.body.email, }, @@ -91,7 +90,7 @@ export function authenticationMethods(this: N8nApp): void { } try { - user = await Db.collections.User!.findOneOrFail({ relations: ['globalRole'] }); + user = await Db.collections.User.findOneOrFail({ relations: ['globalRole'] }); } catch (error) { throw new Error( 'No users found in database - did you wipe the users table? Create at least one user.', diff --git a/packages/cli/src/UserManagement/routes/me.ts b/packages/cli/src/UserManagement/routes/me.ts index dbe3e1e952..54f471bb81 100644 --- a/packages/cli/src/UserManagement/routes/me.ts +++ b/packages/cli/src/UserManagement/routes/me.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable import/no-cycle */ import express from 'express'; @@ -53,7 +52,7 @@ export function meNamespace(this: N8nApp): void { await validateEntity(newUser); - const user = await Db.collections.User!.save(newUser); + const user = await Db.collections.User.save(newUser); Logger.info('User updated successfully', { userId: user.id }); @@ -99,7 +98,7 @@ export function meNamespace(this: N8nApp): void { req.user.password = await hashPassword(validPassword); - const user = await Db.collections.User!.save(req.user); + const user = await Db.collections.User.save(req.user); Logger.info('Password updated successfully', { userId: user.id }); await issueCookie(res, user); @@ -135,7 +134,7 @@ export function meNamespace(this: N8nApp): void { ); } - await Db.collections.User!.save({ + await Db.collections.User.save({ id: req.user.id, personalizationAnswers, }); diff --git a/packages/cli/src/UserManagement/routes/owner.ts b/packages/cli/src/UserManagement/routes/owner.ts index 06c8605a49..f97237a9c6 100644 --- a/packages/cli/src/UserManagement/routes/owner.ts +++ b/packages/cli/src/UserManagement/routes/owner.ts @@ -55,7 +55,7 @@ export function ownerNamespace(this: N8nApp): void { ); } - let owner = await Db.collections.User!.findOne(userId, { + let owner = await Db.collections.User.findOne(userId, { relations: ['globalRole'], }); @@ -78,11 +78,11 @@ export function ownerNamespace(this: N8nApp): void { await validateEntity(owner); - owner = await Db.collections.User!.save(owner); + owner = await Db.collections.User.save(owner); Logger.info('Owner was set up successfully', { userId: req.user.id }); - await Db.collections.Settings!.update( + await Db.collections.Settings.update( { key: 'userManagement.isInstanceOwnerSetUp' }, { value: JSON.stringify(true) }, ); @@ -108,7 +108,7 @@ export function ownerNamespace(this: N8nApp): void { `/${this.restEndpoint}/owner/skip-setup`, // eslint-disable-next-line @typescript-eslint/naming-convention ResponseHelper.send(async (_req: AuthenticatedRequest, _res: express.Response) => { - await Db.collections.Settings!.update( + await Db.collections.Settings.update( { key: 'userManagement.skipInstanceOwnerSetup' }, { value: JSON.stringify(true) }, ); diff --git a/packages/cli/src/UserManagement/routes/passwordReset.ts b/packages/cli/src/UserManagement/routes/passwordReset.ts index 1217786079..1e1b19f51c 100644 --- a/packages/cli/src/UserManagement/routes/passwordReset.ts +++ b/packages/cli/src/UserManagement/routes/passwordReset.ts @@ -53,7 +53,7 @@ export function passwordResetNamespace(this: N8nApp): void { } // User should just be able to reset password if one is already present - const user = await Db.collections.User!.findOne({ email, password: Not(IsNull()) }); + const user = await Db.collections.User.findOne({ email, password: Not(IsNull()) }); if (!user || !user.password) { Logger.debug( @@ -69,7 +69,7 @@ export function passwordResetNamespace(this: N8nApp): void { const resetPasswordTokenExpiration = Math.floor(Date.now() / 1000) + 7200; - await Db.collections.User!.update(id, { resetPasswordToken, resetPasswordTokenExpiration }); + await Db.collections.User.update(id, { resetPasswordToken, resetPasswordTokenExpiration }); const baseUrl = getInstanceBaseUrl(); const url = new URL(`${baseUrl}/change-password`); @@ -134,7 +134,7 @@ export function passwordResetNamespace(this: N8nApp): void { // Timestamp is saved in seconds const currentTimestamp = Math.floor(Date.now() / 1000); - const user = await Db.collections.User!.findOne({ + const user = await Db.collections.User.findOne({ id, resetPasswordToken, resetPasswordTokenExpiration: MoreThanOrEqual(currentTimestamp), @@ -187,7 +187,7 @@ export function passwordResetNamespace(this: N8nApp): void { // Timestamp is saved in seconds const currentTimestamp = Math.floor(Date.now() / 1000); - const user = await Db.collections.User!.findOne({ + const user = await Db.collections.User.findOne({ id: userId, resetPasswordToken, resetPasswordTokenExpiration: MoreThanOrEqual(currentTimestamp), @@ -204,7 +204,7 @@ export function passwordResetNamespace(this: N8nApp): void { throw new ResponseHelper.ResponseError('', undefined, 404); } - await Db.collections.User!.update(userId, { + await Db.collections.User.update(userId, { password: await hashPassword(validPassword), resetPasswordToken: null, resetPasswordTokenExpiration: null, diff --git a/packages/cli/src/UserManagement/routes/users.ts b/packages/cli/src/UserManagement/routes/users.ts index 8f3a794d8f..3b19697036 100644 --- a/packages/cli/src/UserManagement/routes/users.ts +++ b/packages/cli/src/UserManagement/routes/users.ts @@ -1,6 +1,5 @@ /* eslint-disable no-restricted-syntax */ /* eslint-disable import/no-cycle */ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ import { Response } from 'express'; import { In } from 'typeorm'; import validator from 'validator'; @@ -108,7 +107,7 @@ export function usersNamespace(this: N8nApp): void { createUsers[invite.email] = null; }); - const role = await Db.collections.Role!.findOne({ scope: 'global', name: 'member' }); + const role = await Db.collections.Role.findOne({ scope: 'global', name: 'member' }); if (!role) { Logger.error( @@ -122,7 +121,7 @@ export function usersNamespace(this: N8nApp): void { } // remove/exclude existing users from creation - const existingUsers = await Db.collections.User!.find({ + const existingUsers = await Db.collections.User.find({ where: { email: In(Object.keys(createUsers)) }, }); existingUsers.forEach((user) => { @@ -190,6 +189,7 @@ export function usersNamespace(this: N8nApp): void { }; if (result?.success) { void InternalHooksManager.getInstance().onUserTransactionalEmail({ + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion user_id: id!, message_type: 'New user invite', }); @@ -249,7 +249,7 @@ export function usersNamespace(this: N8nApp): void { } } - const users = await Db.collections.User!.find({ where: { id: In([inviterId, inviteeId]) } }); + const users = await Db.collections.User.find({ where: { id: In([inviterId, inviteeId]) } }); if (users.length !== 2) { Logger.debug( @@ -317,7 +317,7 @@ export function usersNamespace(this: N8nApp): void { const validPassword = validatePassword(password); - const users = await Db.collections.User!.find({ + const users = await Db.collections.User.find({ where: { id: In([inviterId, inviteeId]) }, relations: ['globalRole'], }); @@ -351,7 +351,7 @@ export function usersNamespace(this: N8nApp): void { invitee.lastName = lastName; invitee.password = await hashPassword(validPassword); - const updatedUser = await Db.collections.User!.save(invitee); + const updatedUser = await Db.collections.User.save(invitee); await issueCookie(res, updatedUser); @@ -366,7 +366,7 @@ export function usersNamespace(this: N8nApp): void { this.app.get( `/${this.restEndpoint}/users`, ResponseHelper.send(async () => { - const users = await Db.collections.User!.find({ relations: ['globalRole'] }); + const users = await Db.collections.User.find({ relations: ['globalRole'] }); return users.map((user): PublicUser => sanitizeUser(user, ['personalizationAnswers'])); }), @@ -398,7 +398,7 @@ export function usersNamespace(this: N8nApp): void { ); } - const users = await Db.collections.User!.find({ + const users = await Db.collections.User.find({ where: { id: In([transferId, idToDelete]) }, }); @@ -432,11 +432,11 @@ export function usersNamespace(this: N8nApp): void { } const [ownedSharedWorkflows, ownedSharedCredentials] = await Promise.all([ - Db.collections.SharedWorkflow!.find({ + Db.collections.SharedWorkflow.find({ relations: ['workflow'], where: { user: userToDelete }, }), - Db.collections.SharedCredentials!.find({ + Db.collections.SharedCredentials.find({ relations: ['credentials'], where: { user: userToDelete }, }), @@ -494,7 +494,7 @@ export function usersNamespace(this: N8nApp): void { ); } - const reinvitee = await Db.collections.User!.findOne({ id: idToReinvite }); + const reinvitee = await Db.collections.User.findOne({ id: idToReinvite }); if (!reinvitee) { Logger.debug( diff --git a/packages/cli/src/WaitTracker.ts b/packages/cli/src/WaitTracker.ts index 1534ac325b..327af008f2 100644 --- a/packages/cli/src/WaitTracker.ts +++ b/packages/cli/src/WaitTracker.ts @@ -71,7 +71,7 @@ export class WaitTrackerClass { ); } - const executions = await Db.collections.Execution!.find(findQuery); + const executions = await Db.collections.Execution.find(findQuery); if (executions.length === 0) { return; @@ -107,7 +107,7 @@ export class WaitTrackerClass { } // Also check in database - const execution = await Db.collections.Execution!.findOne(executionId); + const execution = await Db.collections.Execution.findOne(executionId); if (execution === undefined || !execution.waitTill) { throw new Error(`The execution ID "${executionId}" could not be found.`); @@ -127,7 +127,7 @@ export class WaitTrackerClass { fullExecutionData.stoppedAt = new Date(); fullExecutionData.waitTill = undefined; - await Db.collections.Execution!.update( + await Db.collections.Execution.update( executionId, ResponseHelper.flattenExecutionData(fullExecutionData), ); @@ -146,7 +146,7 @@ export class WaitTrackerClass { (async () => { // Get the data to execute - const fullExecutionDataFlatted = await Db.collections.Execution!.findOne(executionId); + const fullExecutionDataFlatted = await Db.collections.Execution.findOne(executionId); if (fullExecutionDataFlatted === undefined) { throw new Error(`The execution with the id "${executionId}" does not exist.`); diff --git a/packages/cli/src/WorkflowCredentials.ts b/packages/cli/src/WorkflowCredentials.ts index a52232866f..f266b9bbc2 100644 --- a/packages/cli/src/WorkflowCredentials.ts +++ b/packages/cli/src/WorkflowCredentials.ts @@ -33,8 +33,8 @@ export async function WorkflowCredentials(nodes: INode[]): Promise setTimeout(() => { throttling = false; @@ -371,8 +369,7 @@ export function hookFunctionsPreExecute(parentProcessMode?: string): IWorkflowEx { executionId: this.executionId, nodeName }, ); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const execution = await Db.collections.Execution!.findOne(this.executionId); + const execution = await Db.collections.Execution.findOne(this.executionId); if (execution === undefined) { // Something went badly wrong if this happens. @@ -418,8 +415,7 @@ export function hookFunctionsPreExecute(parentProcessMode?: string): IWorkflowEx const flattenedExecutionData = ResponseHelper.flattenExecutionData(fullExecutionData); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - await Db.collections.Execution!.update( + await Db.collections.Execution.update( this.executionId, flattenedExecutionData as IExecutionFlattedDb, ); @@ -503,7 +499,7 @@ function hookFunctionsSave(parentProcessMode?: string): IWorkflowExecuteHooks { if (isManualMode && !saveManualExecutions && !fullRunData.waitTill) { // Data is always saved, so we remove from database - await Db.collections.Execution!.delete(this.executionId); + await Db.collections.Execution.delete(this.executionId); await BinaryDataManager.getInstance().markDataForDeletionByExecutionId( this.executionId, ); @@ -539,7 +535,7 @@ function hookFunctionsSave(parentProcessMode?: string): IWorkflowExecuteHooks { ); } // Data is always saved, so we remove from database - await Db.collections.Execution!.delete(this.executionId); + await Db.collections.Execution.delete(this.executionId); await BinaryDataManager.getInstance().markDataForDeletionByExecutionId( this.executionId, ); @@ -580,7 +576,7 @@ function hookFunctionsSave(parentProcessMode?: string): IWorkflowExecuteHooks { const executionData = ResponseHelper.flattenExecutionData(fullExecutionData); // Save the Execution in DB - await Db.collections.Execution!.update( + await Db.collections.Execution.update( this.executionId, executionData as IExecutionFlattedDb, ); @@ -588,7 +584,7 @@ function hookFunctionsSave(parentProcessMode?: string): IWorkflowExecuteHooks { if (fullRunData.finished === true && this.retryOf !== undefined) { // If the retry was successful save the reference it on the original execution // await Db.collections.Execution!.save(executionData as IExecutionFlattedDb); - await Db.collections.Execution!.update(this.retryOf, { + await Db.collections.Execution.update(this.retryOf, { retrySuccessId: this.executionId, }); } @@ -693,14 +689,14 @@ function hookFunctionsSaveWorker(): IWorkflowExecuteHooks { const executionData = ResponseHelper.flattenExecutionData(fullExecutionData); // Save the Execution in DB - await Db.collections.Execution!.update( + await Db.collections.Execution.update( this.executionId, executionData as IExecutionFlattedDb, ); if (fullRunData.finished === true && this.retryOf !== undefined) { // If the retry was successful save the reference it on the original execution - await Db.collections.Execution!.update(this.retryOf, { + await Db.collections.Execution.update(this.retryOf, { retrySuccessId: this.executionId, }); } @@ -804,7 +800,7 @@ export async function getWorkflowData( relations = relations.filter((relation) => relation !== 'workflow.tags'); } - const shared = await Db.collections.SharedWorkflow!.findOne({ + const shared = await Db.collections.SharedWorkflow.findOne({ relations, where: whereClause({ user, @@ -959,7 +955,7 @@ export async function executeWorkflow( const executionData = ResponseHelper.flattenExecutionData(fullExecutionData); - await Db.collections.Execution!.update(executionId, executionData as IExecutionFlattedDb); + await Db.collections.Execution.update(executionId, executionData as IExecutionFlattedDb); throw { ...error, stack: error.stack, diff --git a/packages/cli/src/WorkflowHelpers.ts b/packages/cli/src/WorkflowHelpers.ts index 72f7cf2eb5..8ac6cc2284 100644 --- a/packages/cli/src/WorkflowHelpers.ts +++ b/packages/cli/src/WorkflowHelpers.ts @@ -107,9 +107,9 @@ export async function executeErrorWorkflow( const user = await getWorkflowOwner(workflowErrorData.workflow.id!); if (user.globalRole.name === 'owner') { - workflowData = await Db.collections.Workflow!.findOne({ id: Number(workflowId) }); + workflowData = await Db.collections.Workflow.findOne({ id: Number(workflowId) }); } else { - const sharedWorkflowData = await Db.collections.SharedWorkflow!.findOne({ + const sharedWorkflowData = await Db.collections.SharedWorkflow.findOne({ where: { workflow: { id: workflowId }, user, @@ -121,7 +121,7 @@ export async function executeErrorWorkflow( } } } else { - workflowData = await Db.collections.Workflow!.findOne({ id: Number(workflowId) }); + workflowData = await Db.collections.Workflow.findOne({ id: Number(workflowId) }); } if (workflowData === undefined) { @@ -426,7 +426,7 @@ export async function saveStaticDataById( workflowId: string | number, newStaticData: IDataObject, ): Promise { - await Db.collections.Workflow!.update(workflowId, { + await Db.collections.Workflow.update(workflowId, { staticData: newStaticData, }); } @@ -440,7 +440,7 @@ export async function saveStaticDataById( */ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types export async function getStaticDataById(workflowId: string | number) { - const workflowData = await Db.collections.Workflow!.findOne(workflowId, { + const workflowData = await Db.collections.Workflow.findOne(workflowId, { select: ['staticData'], }); @@ -586,7 +586,7 @@ export function whereClause({ * Get the IDs of the workflows that have been shared with the user. */ export async function getSharedWorkflowIds(user: User): Promise { - const sharedWorkflows = await Db.collections.SharedWorkflow!.find({ + const sharedWorkflows = await Db.collections.SharedWorkflow.find({ relations: ['workflow'], where: whereClause({ user, diff --git a/packages/cli/src/WorkflowRunner.ts b/packages/cli/src/WorkflowRunner.ts index b88ee57a53..495a37c6f7 100644 --- a/packages/cli/src/WorkflowRunner.ts +++ b/packages/cli/src/WorkflowRunner.ts @@ -513,7 +513,7 @@ export class WorkflowRunner { reject(error); } - const executionDb = (await Db.collections.Execution!.findOne( + const executionDb = (await Db.collections.Execution.findOne( executionId, )) as IExecutionFlattedDb; const fullExecutionData = ResponseHelper.unflattenExecutionData(executionDb); @@ -548,7 +548,7 @@ export class WorkflowRunner { (workflowDidSucceed && saveDataSuccessExecution === 'none') || (!workflowDidSucceed && saveDataErrorExecution === 'none') ) { - await Db.collections.Execution!.delete(executionId); + await Db.collections.Execution.delete(executionId); await BinaryDataManager.getInstance().markDataForDeletionByExecutionId(executionId); } // eslint-disable-next-line id-denylist diff --git a/packages/cli/src/api/credentials.api.ts b/packages/cli/src/api/credentials.api.ts index f6d054782d..6880017aa8 100644 --- a/packages/cli/src/api/credentials.api.ts +++ b/packages/cli/src/api/credentials.api.ts @@ -53,12 +53,12 @@ credentialsController.get( try { if (req.user.globalRole.name === 'owner') { - credentials = await Db.collections.Credentials!.find({ + credentials = await Db.collections.Credentials.find({ select: ['id', 'name', 'type', 'nodesAccess', 'createdAt', 'updatedAt'], where: filter, }); } else { - const shared = await Db.collections.SharedCredentials!.find({ + const shared = await Db.collections.SharedCredentials.find({ where: whereClause({ user: req.user, entityType: 'credentials', @@ -67,7 +67,7 @@ credentialsController.get( if (!shared.length) return []; - credentials = await Db.collections.Credentials!.find({ + credentials = await Db.collections.Credentials.find({ select: ['id', 'name', 'type', 'nodesAccess', 'createdAt', 'updatedAt'], where: { id: In(shared.map(({ credentialId }) => credentialId)), @@ -175,7 +175,7 @@ credentialsController.post( await externalHooks.run('credentials.create', [encryptedData]); - const role = await Db.collections.Role!.findOneOrFail({ + const role = await Db.collections.Role.findOneOrFail({ name: 'owner', scope: 'credential', }); @@ -213,7 +213,7 @@ credentialsController.delete( ResponseHelper.send(async (req: CredentialRequest.Delete) => { const { id: credentialId } = req.params; - const shared = await Db.collections.SharedCredentials!.findOne({ + const shared = await Db.collections.SharedCredentials.findOne({ relations: ['credentials'], where: whereClause({ user: req.user, @@ -236,7 +236,7 @@ credentialsController.delete( await externalHooks.run('credentials.delete', [credentialId]); - await Db.collections.Credentials!.remove(shared.credentials); + await Db.collections.Credentials.remove(shared.credentials); return true; }), @@ -255,7 +255,7 @@ credentialsController.patch( await validateEntity(updateData); - const shared = await Db.collections.SharedCredentials!.findOne({ + const shared = await Db.collections.SharedCredentials.findOne({ relations: ['credentials'], where: whereClause({ user: req.user, @@ -329,11 +329,11 @@ credentialsController.patch( await externalHooks.run('credentials.update', [newCredentialData]); // Update the credentials in DB - await Db.collections.Credentials!.update(credentialId, newCredentialData); + await Db.collections.Credentials.update(credentialId, newCredentialData); // We sadly get nothing back from "update". Neither if it updated a record // nor the new value. So query now the updated entry. - const responseData = await Db.collections.Credentials!.findOne(credentialId); + const responseData = await Db.collections.Credentials.findOne(credentialId); if (responseData === undefined) { throw new ResponseHelper.ResponseError( @@ -363,7 +363,7 @@ credentialsController.get( ResponseHelper.send(async (req: CredentialRequest.Get) => { const { id: credentialId } = req.params; - const shared = await Db.collections.SharedCredentials!.findOne({ + const shared = await Db.collections.SharedCredentials.findOne({ relations: ['credentials'], where: whereClause({ user: req.user, From 176538e5f21f14ea3e5964dbe905fe4af89faaef Mon Sep 17 00:00:00 2001 From: Michael Kret <88898367+michael-radency@users.noreply.github.com> Date: Thu, 14 Apr 2022 10:19:45 +0300 Subject: [PATCH 20/85] feat(Google Cloud Realtime Database Node): Make it possible to select region (#3096) * upstream merge * :hammer: fixed bug, replaced icon with svg, added ability to get whole db object * :hammer: optimization * :hammer: option for region in credentials * :bug: Fix region default * :zap: Remove dot Co-authored-by: ricardo Co-authored-by: Jan Oberhauser --- ...seRealtimeDatabaseOAuth2Api.credentials.ts | 20 ++++++++ .../RealtimeDatabase/GenericFunctions.ts | 9 ++-- .../RealtimeDatabase/RealtimeDatabase.node.ts | 47 +++++++++++++++--- .../googleFirebaseRealtimeDatabase.png | Bin 2103 -> 0 bytes .../googleFirebaseRealtimeDatabase.svg | 36 ++++++++++++++ 5 files changed, 101 insertions(+), 11 deletions(-) delete mode 100644 packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/googleFirebaseRealtimeDatabase.png create mode 100644 packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/googleFirebaseRealtimeDatabase.svg diff --git a/packages/nodes-base/credentials/GoogleFirebaseRealtimeDatabaseOAuth2Api.credentials.ts b/packages/nodes-base/credentials/GoogleFirebaseRealtimeDatabaseOAuth2Api.credentials.ts index 2e6017b296..52413c0b7e 100644 --- a/packages/nodes-base/credentials/GoogleFirebaseRealtimeDatabaseOAuth2Api.credentials.ts +++ b/packages/nodes-base/credentials/GoogleFirebaseRealtimeDatabaseOAuth2Api.credentials.ts @@ -23,5 +23,25 @@ export class GoogleFirebaseRealtimeDatabaseOAuth2Api implements ICredentialType type: 'hidden', default: scopes.join(' '), }, + { + displayName: 'Region', + name: 'region', + type: 'options', + default: 'firebaseio.com', + options: [ + { + name: 'us-central1', + value: 'firebaseio.com', + }, + { + name: 'europe-west1', + value: 'europe-west1.firebasedatabase.app', + }, + { + name: 'asia-southeast1', + value: 'asia-southeast1.firebasedatabase.app', + }, + ], + }, ]; } diff --git a/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/GenericFunctions.ts index acb50b22f4..3a70524f24 100644 --- a/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/GenericFunctions.ts @@ -9,11 +9,13 @@ import { } from 'n8n-core'; import { - IDataObject, NodeApiError, + IDataObject, JsonObject, NodeApiError, } from 'n8n-workflow'; export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, projectId: string, method: string, resource: string, body: any = {}, qs: IDataObject = {}, headers: IDataObject = {}, uri: string | null = null): Promise { // tslint:disable-line:no-any + const { region } = await this.getCredentials('googleFirebaseRealtimeDatabaseOAuth2Api') as IDataObject; + const options: OptionsWithUrl = { headers: { 'Content-Type': 'application/json', @@ -21,9 +23,10 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF method, body, qs, - url: uri || `https://${projectId}.firebaseio.com/${resource}.json`, + url: uri || `https://${projectId}.${region}/${resource}.json`, json: true, }; + try { if (Object.keys(headers).length !== 0) { options.headers = Object.assign({}, options.headers, headers); @@ -34,7 +37,7 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF return await this.helpers.requestOAuth2!.call(this, 'googleFirebaseRealtimeDatabaseOAuth2Api', options); } catch (error) { - throw new NodeApiError(this.getNode(), error); + throw new NodeApiError(this.getNode(), error as JsonObject); } } diff --git a/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/RealtimeDatabase.node.ts b/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/RealtimeDatabase.node.ts index 023d2b1a80..cd7cd66ded 100644 --- a/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/RealtimeDatabase.node.ts +++ b/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/RealtimeDatabase.node.ts @@ -9,6 +9,7 @@ import { INodePropertyOptions, INodeType, INodeTypeDescription, + JsonObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; @@ -22,7 +23,7 @@ export class RealtimeDatabase implements INodeType { description: INodeTypeDescription = { displayName: 'Google Cloud Realtime Database', name: 'googleFirebaseRealtimeDatabase', - icon: 'file:googleFirebaseRealtimeDatabase.png', + icon: 'file:googleFirebaseRealtimeDatabase.svg', group: ['input'], version: 1, subtitle: '={{$parameter["operation"]}}', @@ -53,6 +54,7 @@ export class RealtimeDatabase implements INodeType { displayName: 'Operation', name: 'operation', type: 'options', + noDataExpression: true, options: [ { name: 'Create', @@ -81,7 +83,6 @@ export class RealtimeDatabase implements INodeType { }, ], default: 'create', - description: 'The operation to perform.', required: true, }, { @@ -89,9 +90,28 @@ export class RealtimeDatabase implements INodeType { name: 'path', type: 'string', default: '', - placeholder: '/app/users', - description: 'Object path on database. With leading slash. Do not append .json.', + placeholder: 'e.g. /app/users', + description: 'Object path on database. Do not append .json.', required: true, + displayOptions: { + hide: { + 'operation': [ 'get' ], + }, + }, + }, + { + displayName: 'Object Path', + name: 'path', + type: 'string', + default: '', + placeholder: 'e.g. /app/users', + description: 'Object path on database. Do not append .json.', + hint: 'Leave blank to get a whole database object', + displayOptions: { + show: { + 'operation': [ 'get' ], + }, + }, }, { displayName: 'Columns / Attributes', @@ -121,7 +141,7 @@ export class RealtimeDatabase implements INodeType { ): Promise { const projects = await googleApiRequestAllItems.call( this, - 'projects', + '', 'GET', 'results', {}, @@ -129,14 +149,23 @@ export class RealtimeDatabase implements INodeType { {}, 'https://firebase.googleapis.com/v1beta1/projects', ); - const returnData = projects.map((o: IDataObject) => ({ name: o.projectId, value: o.projectId })) as INodePropertyOptions[]; + + const returnData = projects + // select only realtime database projects + .filter((project: IDataObject) => (project.resources as IDataObject).realtimeDatabaseInstance ) + .map((project: IDataObject) => ( + { + name: project.projectId, + value: (project.resources as IDataObject).realtimeDatabaseInstance, + } + )) as INodePropertyOptions[]; + return returnData; }, }, }; async execute(this: IExecuteFunctions): Promise { - const items = this.getInputData(); const returnData: IDataObject[] = []; const length = (items.length as unknown) as number; @@ -144,6 +173,7 @@ export class RealtimeDatabase implements INodeType { const operation = this.getNodeParameter('operation', 0) as string; //https://firebase.google.com/docs/reference/rest/database + if (['push', 'create', 'update'].includes(operation) && items.length === 1 && Object.keys(items[0].json).length === 0) { throw new NodeOperationError(this.getNode(), `The ${operation} operation needs input data`); } @@ -151,6 +181,7 @@ export class RealtimeDatabase implements INodeType { for (let i = 0; i < length; i++) { try { const projectId = this.getNodeParameter('projectId', i) as string; + let method = 'GET', attributes = ''; const document: IDataObject = {}; if (operation === 'create') { @@ -194,7 +225,7 @@ export class RealtimeDatabase implements INodeType { } } catch (error) { if (this.continueOnFail()) { - returnData.push({ error: error.message }); + returnData.push({ error: (error as JsonObject).message }); continue; } throw error; diff --git a/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/googleFirebaseRealtimeDatabase.png b/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/googleFirebaseRealtimeDatabase.png deleted file mode 100644 index a95667610749659b31f1395f467b1a41d59ad878..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2103 zcmX9;3pmql8=tdyajDSZqa4bqdR0gc898iDTO%RfR3;jq(`J%6Ha-+lFU=_>Qc6h9 zWDPTmJT+eeo_w&2&`*$Cn=Xx^H9?nV%`xIa>m=Y4~QPKy`$ufIcrV3oYt&gjAa?a8a8B1cG!Fw*v|Ed0)C77ZVdB z?r`KM|M4%+X3v=z0s$CwSWpla>~&8}xG8*cQdng0I0pyP-GL!Hs03lf2_6wP)8rK&M_BI)0^Xm6 zCPWJ*BcRy|XlH~>_vZyTLAMRSLI59JL8=R+1>d>KlZJ7;q2-uU@^nHDpI561N7ndq^UYgzeV+Bq?yvl24KV2i!r9 zqnLSypQ6f7RRsIo__tKo*4BoHhx7CEaX1{<;|flk<))I|6-u{lF14IOqXFH%mo=-AHb)qmW_GPm$**$;{5qGMUVto}S#?+*_$h z$w^7^H{xPr30N!^{D1<7;NW|!t@lePc;_jzMl->>l>DRa|{-2t?MNG^>D_Yp^0nR$`%I!sMmZBO9L7~1N zUz<-><=ueI&(C*ub~ZINg-6AL?5NJixTpD{y_J^+pZky2`d~c0mODJeweG7>=r%hZ z#ah^C#>>zIbN2Je>h%O?edyiC<1rqdFiB~7X&HboB@}G!kP~eRWJCfnAR1>}R8tU% zHnKOabm3gRqe}{FKTL@J2oy8z!5C;Dz*px!GQVY&*^O+Dt8(Mq-JT#%Oj>{W=fL)WjRd)HuWoN z?YsZd9I0%L)aCi};aeHn3X#&?XsfY8S1m&MUSB(u@Q8@;@wCD!jGenS?ljCdv$4Ie zHPL^JqVS-w9)mEm-lzHT0Dt^(v_ZDkbg~Kfe$l?d1!KuvCf{V@1h5};3v7PpxJ%ms z<4_s6>+JdvT$^*EAOQ8;sbOqa+M&JHe}VSJJNA${z13*;az-FI&NEJSXq*hEWhWP% z_mlj)F|4}4!TChMx2e-f}rk#!Kizf7F5%X{DA?tMyQpLc#ktf8^AL1R{Va(TN! zA>7C3)M#u&GbS@Q@gUM}wNL5$ruvi@85a|BTb5_PH54?b_&uEy zXm}wk?cxo8%9fkl8ODwoKyoU*D6+FM4}bY9rkp}$<;Y&L*iV2xlbdkTZRI{Xp4{77 zG4-~e<*?&x+k@&si=~`u2ZO0B4lUr`%Dm2zrWKX{3Z>77am`DX*EPI!RH6bR(=k5| zzm~2FGQT8vUH8-Y<@~IcCEAp`NO)R;uc1<>ReT;kXH@;ZtrO6#l0Z5_m?@~H7e^{< zVQwr}rK*`6lU44l!kLEgS)Fa1fulD3dG!(>aH96t#41X9RHOUpUvl>-pO5K1rav4* z?b+$ZDXXoGdeg0LssJCYRl_nue%Nalhqu*gs2Dq!XTMr?``sJ;MAFpnVBz1_O!fr( zW@s5(^<@*p;vMsGlWieK>Xe)$I!?cK)2;dVMy9*FY@FR5-?-+}eEeYH?kZhB_^aom z>Shw%C3zz+q822iQX(0TM((br5tCEabB~uY7k8>#9+#k}zy_3^Do=d21@Er~N-3K< TolD#P31LV_4~JU&z|?;LSnq0; diff --git a/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/googleFirebaseRealtimeDatabase.svg b/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/googleFirebaseRealtimeDatabase.svg new file mode 100644 index 0000000000..feec452fc2 --- /dev/null +++ b/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/googleFirebaseRealtimeDatabase.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 29fdd77d7b4ac3bbb9faae73b0932183d48ae9a6 Mon Sep 17 00:00:00 2001 From: Alex Grozav Date: Thu, 14 Apr 2022 10:30:31 +0300 Subject: [PATCH 21/85] fix(ui): Reset text-edit input value when pressing esc key to have matching input values (#3098) --- packages/editor-ui/src/components/TextEdit.vue | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/editor-ui/src/components/TextEdit.vue b/packages/editor-ui/src/components/TextEdit.vue index 6a4de8a450..7ee367556d 100644 --- a/packages/editor-ui/src/components/TextEdit.vue +++ b/packages/editor-ui/src/components/TextEdit.vue @@ -4,7 +4,7 @@
-
+
@@ -35,6 +35,13 @@ export default Vue.extend({ this.$emit('valueChanged', value); }, + onKeyDownEsc () { + // Resetting input value when closing the dialog, required when closing it using the `Esc` key + this.tempValue = this.value; + + this.closeDialog(); + }, + closeDialog () { // Handle the close externally as the visible parameter is an external prop // and is so not allowed to be changed here. From 5e54249c414346f3f1c4bf7c720f9d2a0182096f Mon Sep 17 00:00:00 2001 From: Francesco Pongiluppi Date: Thu, 14 Apr 2022 09:36:46 +0200 Subject: [PATCH 22/85] :zap: Make event on Eventbrite Trigger Node optional (#2829) * Set `event` property as optional * Add some parameter descriptions To please nodelinter, mostly. * Fix UI complaining about missing parameter. * :rotating_light: Fixed lint isssues * :zap: Improvements Co-authored-by: Jonathan Bennetts Co-authored-by: ricardo --- .../nodes/Eventbrite/EventbriteTrigger.node.ts | 17 +++++++++-------- .../nodes/Eventbrite/GenericFunctions.ts | 5 ++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/nodes-base/nodes/Eventbrite/EventbriteTrigger.node.ts b/packages/nodes-base/nodes/Eventbrite/EventbriteTrigger.node.ts index 4685c98e61..f3a4cc9a7b 100644 --- a/packages/nodes-base/nodes/Eventbrite/EventbriteTrigger.node.ts +++ b/packages/nodes-base/nodes/Eventbrite/EventbriteTrigger.node.ts @@ -26,6 +26,7 @@ export class EventbriteTrigger implements INodeType { group: ['trigger'], version: 1, description: 'Handle Eventbrite events via webhooks', + subtitle: '={{$parameter["event"]}}', defaults: { name: 'Eventbrite Trigger', }, @@ -79,7 +80,6 @@ export class EventbriteTrigger implements INodeType { }, ], default: 'privateKey', - description: 'The resource to operate on.', }, { displayName: 'Organization', @@ -90,7 +90,7 @@ export class EventbriteTrigger implements INodeType { loadOptionsMethod: 'getOrganizations', }, default: '', - description: '', + description: 'The Eventbrite Organization to work on', }, { displayName: 'Event', @@ -104,7 +104,7 @@ export class EventbriteTrigger implements INodeType { loadOptionsMethod: 'getEvents', }, default: '', - description: '', + description: 'Limit the triggers to this event', }, { displayName: 'Actions', @@ -174,14 +174,14 @@ export class EventbriteTrigger implements INodeType { ], required: true, default: [], - description: '', + description: 'One or more action to subscribe to.', }, { displayName: 'Resolve Data', name: 'resolveData', type: 'boolean', default: true, - description: 'By default does the webhook-data only contain the URL to receive the object data manually. If this option gets activated, it will resolve the data automatically.', + description: 'By default does the webhook-data only contain the URL to receive the object data manually. If this option gets activated, it will resolve the data automatically', }, ], }; @@ -206,7 +206,7 @@ export class EventbriteTrigger implements INodeType { // Get all the available events to display them to user so that he can // select them easily async getEvents(this: ILoadOptionsFunctions): Promise { - const returnData: INodePropertyOptions[] = []; + const returnData: INodePropertyOptions[] = [{ name: 'All', value: 'all' }]; const organization = this.getCurrentNodeParameter('organization'); const events = await eventbriteApiRequestAllItems.call(this, 'events', 'GET', `/organizations/${organization}/events`); for (const event of events) { @@ -264,9 +264,10 @@ export class EventbriteTrigger implements INodeType { actions: actions.join(','), event_id: event, }; - + if (event === 'all' || event === '') { + delete body.event_id; + } const responseData = await eventbriteApiRequest.call(this, 'POST', endpoint, body); - webhookData.webhookId = responseData.id; return true; }, diff --git a/packages/nodes-base/nodes/Eventbrite/GenericFunctions.ts b/packages/nodes-base/nodes/Eventbrite/GenericFunctions.ts index ef1f623b93..b2102824af 100644 --- a/packages/nodes-base/nodes/Eventbrite/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Eventbrite/GenericFunctions.ts @@ -11,7 +11,7 @@ import { } from 'n8n-core'; import { - IDataObject, NodeApiError, NodeOperationError, + IDataObject, JsonObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function eventbriteApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any @@ -38,13 +38,12 @@ export async function eventbriteApiRequest(this: IHookFunctions | IExecuteFuncti } options.headers!['Authorization'] = `Bearer ${credentials.apiKey}`; - return await this.helpers.request!(options); } else { return await this.helpers.requestOAuth2!.call(this, 'eventbriteOAuth2Api', options); } } catch (error) { - throw new NodeApiError(this.getNode(), error); + throw new NodeApiError(this.getNode(), error as JsonObject); } } From 47bbe9857b5f3321c9402595041afcb6b96411c4 Mon Sep 17 00:00:00 2001 From: Jonathan Bennetts Date: Thu, 14 Apr 2022 08:41:14 +0100 Subject: [PATCH 23/85] fix(Zoho Node): Fix pagination issue (#3129) --- packages/nodes-base/nodes/Zoho/GenericFunctions.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/nodes-base/nodes/Zoho/GenericFunctions.ts b/packages/nodes-base/nodes/Zoho/GenericFunctions.ts index 5b4ae69755..cd691a6d3c 100644 --- a/packages/nodes-base/nodes/Zoho/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Zoho/GenericFunctions.ts @@ -91,15 +91,13 @@ export async function zohoApiRequestAllItems( const returnData: IDataObject[] = []; let responseData; - let uri: string | undefined; qs.per_page = 200; - qs.page = 0; + qs.page = 1; do { - responseData = await zohoApiRequest.call(this, method, endpoint, body, qs, uri); + responseData = await zohoApiRequest.call(this, method, endpoint, body, qs); if (Array.isArray(responseData) && !responseData.length) return returnData; returnData.push(...responseData.data); - uri = responseData.info.more_records; qs.page++; } while ( responseData.info.more_records !== undefined && From 17b0cd8f765ce262241c827a635e64c189acc0f8 Mon Sep 17 00:00:00 2001 From: Alex Grozav Date: Fri, 15 Apr 2022 08:35:51 +0300 Subject: [PATCH 24/85] fix(editor): Fix breaking Drop-downs after removing expressions (#3094) * :bug: Fixed multiOption parameter input dropdown values after removing expression. * :recycle: Moved array value normalization to removeExpression action. * :bug: Handled scenario where expression contained invalid value. --- .../editor-ui/src/components/ParameterInput.vue | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/editor-ui/src/components/ParameterInput.vue b/packages/editor-ui/src/components/ParameterInput.vue index e3fecf8da6..b93fe66589 100644 --- a/packages/editor-ui/src/components/ParameterInput.vue +++ b/packages/editor-ui/src/components/ParameterInput.vue @@ -421,7 +421,7 @@ export default mixins( return false; }, - expressionValueComputed (): NodeParameterValue | null { + expressionValueComputed (): NodeParameterValue | string[] | null { if (this.areExpressionsDisabled) { return this.value; } @@ -733,7 +733,7 @@ export default mixins( this.$emit('textInput', parameterData); }, - valueChanged (value: string | number | boolean | Date | null) { + valueChanged (value: string[] | string | number | boolean | Date | null) { if (value instanceof Date) { value = value.toISOString(); } @@ -768,7 +768,14 @@ export default mixins( this.expressionEditDialogVisible = true; this.trackExpressionEditOpen(); } else if (command === 'removeExpression') { - this.valueChanged(this.expressionValueComputed !== undefined ? this.expressionValueComputed : null); + let value = this.expressionValueComputed; + + if (this.parameter.type === 'multiOptions' && typeof value === 'string') { + value = (value || '').split(',') + .filter((value) => (this.parameterOptions || []).find((option) => option.value === value)); + } + + this.valueChanged(typeof value !== 'undefined' ? value : null); } else if (command === 'refreshOptions') { this.loadRemoteParameterOptions(); } From d3fecb9f6d2a3c75052b17055f6ef2852e988713 Mon Sep 17 00:00:00 2001 From: Omar Ajoue Date: Fri, 15 Apr 2022 08:00:47 +0200 Subject: [PATCH 25/85] :art: Centralize error throwing for encryption keys and credentials (#3105) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Centralized error throwing for encryption key * Unifying the error message used by cli and core packages * Improvements to error messages to make it more DRY * Removed unnecessary throw * Throwing error when credential does not exist to simplify node behavior (#3112) Co-authored-by: Iván Ovejero --- packages/cli/commands/export/credentials.ts | 3 -- packages/cli/commands/import/credentials.ts | 3 -- packages/cli/commands/start.ts | 10 +--- packages/cli/src/Server.ts | 52 +++++++------------ .../cli/src/WorkflowExecuteAdditionalData.ts | 4 +- packages/cli/src/api/credentials.api.ts | 37 +++++++------ packages/cli/src/constants.ts | 6 ++- .../test/integration/credentials.api.test.ts | 9 ++-- .../cli/test/integration/shared/testDb.ts | 4 -- packages/core/src/Constants.ts | 5 ++ packages/core/src/NodeExecuteFunctions.ts | 38 ++++++-------- packages/core/src/UserSettings.ts | 13 ++--- .../nodes/ActiveCampaign/GenericFunctions.ts | 3 -- .../AcuityScheduling/GenericFunctions.ts | 3 -- .../nodes/Affinity/GenericFunctions.ts | 4 -- .../nodes/AgileCrm/GenericFunctions.ts | 14 ++--- .../nodes/Airtable/GenericFunctions.ts | 4 -- packages/nodes-base/nodes/Amqp/Amqp.node.ts | 3 -- .../nodes-base/nodes/Amqp/AmqpTrigger.node.ts | 3 -- .../nodes/Aws/Comprehend/GenericFunctions.ts | 3 -- .../nodes/Aws/DynamoDB/GenericFunctions.ts | 3 -- .../nodes-base/nodes/Aws/GenericFunctions.ts | 3 -- .../nodes/Aws/Rekognition/GenericFunctions.ts | 3 -- .../nodes-base/nodes/Aws/S3/AwsS3.node.ts | 2 +- .../nodes/Aws/S3/GenericFunctions.ts | 3 -- .../nodes/Aws/SES/GenericFunctions.ts | 3 -- .../nodes/Aws/Textract/GenericFunctions.ts | 5 +- .../nodes/Aws/Transcribe/GenericFunctions.ts | 3 -- .../nodes/BambooHr/v1/transport/index.ts | 4 -- .../nodes/Bannerbear/GenericFunctions.ts | 4 -- .../nodes/Baserow/GenericFunctions.ts | 4 -- .../Beeminder/Beeminder.node.functions.ts | 16 ------ .../nodes/Beeminder/Beeminder.node.ts | 4 -- .../nodes/Bitbucket/GenericFunctions.ts | 3 -- .../nodes/Bitly/GenericFunctions.ts | 3 -- .../nodes/Bitwarden/GenericFunctions.ts | 6 +-- .../nodes/Brandfetch/GenericFunctions.ts | 3 -- .../nodes/Calendly/GenericFunctions.ts | 4 -- .../nodes/Chargebee/Chargebee.node.ts | 4 -- .../nodes/CircleCi/GenericFunctions.ts | 3 -- .../Cisco/Webex/CiscoWebexTrigger.node.ts | 3 -- .../nodes/Clearbit/GenericFunctions.ts | 3 -- .../nodes/ClickUp/GenericFunctions.ts | 2 +- .../nodes/Clockify/GenericFunctions.ts | 5 -- .../nodes/Cockpit/GenericFunctions.ts | 5 -- .../nodes-base/nodes/Coda/GenericFunctions.ts | 3 -- .../nodes/Contentful/GenericFunctions.ts | 4 -- .../nodes/ConvertKit/GenericFunctions.ts | 4 -- .../nodes/Copper/CopperTrigger.node.ts | 4 +- .../nodes/Cortex/GenericFunctions.ts | 4 -- .../nodes-base/nodes/CrateDb/CrateDb.node.ts | 4 -- .../nodes/CustomerIo/GenericFunctions.ts | 4 -- .../nodes/DeepL/GenericFunctions.ts | 8 --- .../nodes/Demio/GenericFunctions.ts | 3 -- .../nodes/Discourse/GenericFunctions.ts | 2 +- .../nodes/Disqus/GenericFunctions.ts | 3 -- .../nodes/Drift/GenericFunctions.ts | 4 -- .../nodes/ERPNext/GenericFunctions.ts | 4 -- .../nodes-base/nodes/Egoi/GenericFunctions.ts | 2 +- .../nodes/EmailReadImap/EmailReadImap.node.ts | 4 -- .../nodes/EmailSend/EmailSend.node.ts | 4 -- .../nodes/Eventbrite/GenericFunctions.ts | 3 -- .../nodes/Facebook/FacebookTrigger.node.ts | 2 +- .../nodes/Facebook/GenericFunctions.ts | 6 +-- .../nodes/Figma/GenericFunctions.ts | 2 +- .../nodes/FileMaker/FileMaker.node.ts | 4 -- .../nodes/FileMaker/GenericFunctions.ts | 18 ------- packages/nodes-base/nodes/Flow/Flow.node.ts | 4 -- .../nodes-base/nodes/Flow/FlowTrigger.node.ts | 12 ----- .../nodes-base/nodes/Flow/GenericFunctions.ts | 3 -- .../nodes/Formstack/GenericFunctions.ts | 4 -- .../nodes/Freshdesk/GenericFunctions.ts | 4 -- packages/nodes-base/nodes/Ftp/Ftp.node.ts | 4 -- .../nodes/GetResponse/GenericFunctions.ts | 2 +- .../nodes/Ghost/GenericFunctions.ts | 4 +- packages/nodes-base/nodes/Git/Git.node.ts | 2 +- .../nodes/Github/GenericFunctions.ts | 5 +- .../nodes/Gitlab/GenericFunctions.ts | 6 --- .../nodes-base/nodes/Gitlab/Gitlab.node.ts | 8 --- .../nodes/Google/Books/GenericFunctions.ts | 4 -- .../nodes/Google/Chat/GenericFunctions.ts | 4 -- .../nodes/Google/Docs/GenericFunctions.ts | 4 -- .../nodes/Google/Drive/GenericFunctions.ts | 4 -- .../nodes/Google/Gmail/GenericFunctions.ts | 4 -- .../nodes/Google/Sheet/GenericFunctions.ts | 4 -- .../nodes/Google/Slides/GenericFunctions.ts | 4 -- .../Google/Translate/GenericFunctions.ts | 4 -- .../nodes/Gotify/GenericFunctions.ts | 2 +- .../nodes-base/nodes/GraphQL/GraphQL.node.ts | 44 +++++++++++++--- .../nodes/Gumroad/GenericFunctions.ts | 3 -- .../nodes/HaloPSA/GenericFunctions.ts | 4 +- .../nodes/Harvest/GenericFunctions.ts | 6 +-- .../nodes/HomeAssistant/GenericFunctions.ts | 4 -- .../nodes/HttpRequest/HttpRequest.node.ts | 43 ++++++++++++--- .../nodes/Hubspot/GenericFunctions.ts | 6 +-- .../nodes/Hubspot/HubspotTrigger.node.ts | 8 +-- .../nodes/HumanticAI/GenericFunctions.ts | 3 -- .../nodes/Hunter/GenericFunctions.ts | 3 -- .../nodes/Intercom/GenericFunctions.ts | 3 -- .../nodes/InvoiceNinja/GenericFunctions.ts | 3 -- .../nodes/Iterable/GenericFunctions.ts | 2 +- .../nodes/Jenkins/GenericFunctions.ts | 2 +- .../nodes-base/nodes/Jira/GenericFunctions.ts | 8 +-- .../nodes/JotForm/GenericFunctions.ts | 3 -- packages/nodes-base/nodes/Kafka/Kafka.node.ts | 2 +- .../nodes/Kafka/KafkaTrigger.node.ts | 2 +- .../nodes/KoBoToolbox/GenericFunctions.ts | 4 +- .../nodes/Linear/GenericFunctions.ts | 2 +- .../nodes/LingvaNex/GenericFunctions.ts | 3 -- packages/nodes-base/nodes/MQTT/Mqtt.node.ts | 2 +- .../nodes-base/nodes/MQTT/MqttTrigger.node.ts | 4 -- .../nodes/Magento/GenericFunctions.ts | 2 +- .../nodes/Mailcheck/GenericFunctions.ts | 4 +- .../nodes/Mailchimp/GenericFunctions.ts | 8 +-- .../nodes/MailerLite/GenericFunctions.ts | 2 +- .../nodes-base/nodes/Mailgun/Mailgun.node.ts | 4 -- .../nodes/Mailjet/GenericFunctions.ts | 2 +- .../nodes/Mandrill/GenericFunctions.ts | 4 -- .../nodes/Marketstack/GenericFunctions.ts | 2 +- .../nodes/Matrix/GenericFunctions.ts | 3 -- .../nodes/Mattermost/v1/transport/index.ts | 4 -- .../nodes/Mautic/GenericFunctions.ts | 8 +-- .../nodes/Medium/GenericFunctions.ts | 4 -- .../nodes/MessageBird/GenericFunctions.ts | 3 -- .../Microsoft/Outlook/GenericFunctions.ts | 4 +- .../nodes/Microsoft/Sql/MicrosoftSql.node.ts | 4 -- .../nodes/Mindee/GenericFunctions.ts | 4 +- .../nodes/Mocean/GenericFunctions.ts | 3 -- .../nodes/MondayCom/GenericFunctions.ts | 2 +- .../nodes/Msg91/GenericFunctions.ts | 3 -- packages/nodes-base/nodes/MySql/MySql.node.ts | 4 -- .../nodes-base/nodes/Nasa/GenericFunctions.ts | 2 +- .../nodes/Netlify/GenericFunctions.ts | 4 -- .../nodes/NextCloud/GenericFunctions.ts | 6 --- .../nodes/NextCloud/NextCloud.node.ts | 4 -- .../nodes/NocoDB/GenericFunctions.ts | 5 -- .../nodes/Notion/GenericFunctions.ts | 2 +- packages/nodes-base/nodes/Odoo/Odoo.node.ts | 40 +++++++------- .../nodes/OneSimpleApi/GenericFunctions.ts | 3 -- .../nodes/Onfleet/GenericFunctions.ts | 2 +- .../OpenWeatherMap/OpenWeatherMap.node.ts | 4 -- .../nodes/Orbit/GenericFunctions.ts | 3 -- .../nodes-base/nodes/Oura/GenericFunctions.ts | 3 -- .../nodes/Paddle/GenericFunctions.ts | 4 -- .../nodes/PagerDuty/GenericFunctions.ts | 4 -- .../nodes/PayPal/GenericFunctions.ts | 5 +- .../nodes/Peekalink/GenericFunctions.ts | 3 -- .../nodes/Phantombuster/GenericFunctions.ts | 2 +- .../nodes/Pipedrive/PipedriveTrigger.node.ts | 17 +++++- .../nodes/Plivo/GenericFunctions.ts | 4 -- .../nodes/PostHog/GenericFunctions.ts | 2 +- .../nodes/Postgres/Postgres.node.ts | 4 -- .../nodes/Postmark/GenericFunctions.ts | 4 -- .../nodes/ProfitWell/GenericFunctions.ts | 3 -- .../nodes/Pushcut/GenericFunctions.ts | 2 +- .../nodes/Pushover/GenericFunctions.ts | 2 +- .../nodes-base/nodes/QuestDb/QuestDb.node.ts | 4 -- .../nodes/QuickBase/GenericFunctions.ts | 6 +-- .../nodes/RabbitMQ/GenericFunctions.ts | 2 +- packages/nodes-base/nodes/Redis/Redis.node.ts | 4 -- .../nodes/Redis/RedisTrigger.node.ts | 4 -- .../nodes/Rocketchat/GenericFunctions.ts | 4 -- .../nodes-base/nodes/S3/GenericFunctions.ts | 4 -- .../nodes/Salesforce/GenericFunctions.ts | 2 +- .../nodes/Salesmate/GenericFunctions.ts | 3 -- .../nodes/SeaTable/SeaTableTrigger.node.ts | 2 +- .../SecurityScorecard/GenericFunctions.ts | 4 -- .../nodes/Segment/GenericFunctions.ts | 3 -- .../nodes/SendGrid/GenericFunctions.ts | 2 +- .../nodes/Sendy/GenericFunctions.ts | 2 +- .../nodes/SentryIo/GenericFunctions.ts | 2 +- .../nodes/ServiceNow/GenericFunctions.ts | 2 +- .../nodes/Shopify/GenericFunctions.ts | 3 -- .../nodes/Shopify/ShopifyTrigger.node.ts | 2 +- .../nodes/Slack/GenericFunctions.ts | 3 -- .../nodes/Sms77/GenericFunctions.ts | 3 -- .../nodes/Spontit/GenericFunctions.ts | 2 +- packages/nodes-base/nodes/Ssh/Ssh.node.ts | 4 +- .../nodes/Stackby/GenericFunction.ts | 2 +- .../nodes/Storyblok/GenericFunctions.ts | 4 +- .../nodes/Strapi/GenericFunctions.ts | 6 +-- .../nodes-base/nodes/Strapi/Strapi.node.ts | 2 +- .../nodes/Strava/GenericFunctions.ts | 2 +- packages/nodes-base/nodes/Stripe/helpers.ts | 3 -- .../nodes/SurveyMonkey/GenericFunctions.ts | 4 -- .../SurveyMonkey/SurveyMonkeyTrigger.node.ts | 4 +- .../nodes/SyncroMSP/v1/transport/index.ts | 4 -- .../nodes/Taiga/GenericFunctions.ts | 2 +- .../nodes/Taiga/TaigaTrigger.node.ts | 2 +- .../nodes/Tapfiliate/GenericFunctions.ts | 2 +- .../nodes/Telegram/GenericFunctions.ts | 4 -- .../nodes/Telegram/Telegram.node.ts | 4 -- .../nodes/Telegram/TelegramTrigger.node.ts | 2 +- .../nodes/TheHive/GenericFunctions.ts | 7 --- .../nodes-base/nodes/TheHive/TheHive.node.ts | 38 +++++--------- .../nodes/TimescaleDb/TimescaleDb.node.ts | 4 -- .../nodes/Todoist/GenericFunctions.ts | 2 +- .../nodes/Toggl/GenericFunctions.ts | 3 -- .../nodes/TravisCi/GenericFunctions.ts | 3 -- .../nodes/Trello/GenericFunctions.ts | 4 -- .../nodes/Trello/TrelloTrigger.node.ts | 14 ----- .../nodes/Twake/GenericFunctions.ts | 2 +- .../nodes/Twilio/GenericFunctions.ts | 4 -- .../nodes/Typeform/GenericFunctions.ts | 4 -- .../nodes/UProc/GenericFunctions.ts | 3 -- .../UnleashedSoftware/GenericFunctions.ts | 4 -- .../nodes/Uplead/GenericFunctions.ts | 3 -- .../nodes/UptimeRobot/GenericFunctions.ts | 3 -- .../nodes-base/nodes/Vero/GenericFunctions.ts | 3 -- .../nodes/Vonage/GenericFunctions.ts | 2 +- packages/nodes-base/nodes/Wait/Wait.node.ts | 17 +++++- .../nodes/Webflow/GenericFunctions.ts | 3 -- .../nodes-base/nodes/Webhook/Webhook.node.ts | 16 +++++- .../nodes/Wekan/GenericFunctions.ts | 4 -- packages/nodes-base/nodes/Wise/Wise.node.ts | 2 +- .../nodes-base/nodes/Wise/WiseTrigger.node.ts | 4 +- .../nodes/WooCommerce/GenericFunctions.ts | 3 -- .../WooCommerce/WooCommerceTrigger.node.ts | 2 +- .../nodes/Wordpress/GenericFunctions.ts | 3 -- .../nodes/Wufoo/GenericFunctions.ts | 3 -- .../nodes/Yourls/GenericFunctions.ts | 2 +- .../nodes/Zendesk/GenericFunctions.ts | 8 --- .../nodes-base/nodes/Zoom/GenericFunctions.ts | 3 -- .../nodes/Zulip/GenericFunctions.ts | 4 -- packages/nodes-base/nodes/Zulip/Zulip.node.ts | 2 +- packages/workflow/src/Interfaces.ts | 17 +++--- packages/workflow/test/Helpers.ts | 4 +- 227 files changed, 348 insertions(+), 848 deletions(-) diff --git a/packages/cli/commands/export/credentials.ts b/packages/cli/commands/export/credentials.ts index ab34c9d968..5048efe68b 100644 --- a/packages/cli/commands/export/credentials.ts +++ b/packages/cli/commands/export/credentials.ts @@ -123,9 +123,6 @@ export class ExportCredentialsCommand extends Command { if (flags.decrypted) { const encryptionKey = await UserSettings.getEncryptionKey(); - if (encryptionKey === undefined) { - throw new Error('No encryption key got found to decrypt the credentials!'); - } for (let i = 0; i < credentials.length; i++) { const { name, type, nodesAccess, data } = credentials[i]; diff --git a/packages/cli/commands/import/credentials.ts b/packages/cli/commands/import/credentials.ts index eb08f1a0de..8405379c49 100644 --- a/packages/cli/commands/import/credentials.ts +++ b/packages/cli/commands/import/credentials.ts @@ -85,9 +85,6 @@ export class ImportCredentialsCommand extends Command { await UserSettings.prepareUserSettings(); const encryptionKey = await UserSettings.getEncryptionKey(); - if (encryptionKey === undefined) { - throw new Error('No encryption key found to encrypt the credentials!'); - } if (flags.separate) { const files = await glob( diff --git a/packages/cli/commands/start.ts b/packages/cli/commands/start.ts index dc9045d830..ab96543346 100644 --- a/packages/cli/commands/start.ts +++ b/packages/cli/commands/start.ts @@ -33,7 +33,6 @@ import { } from '../src'; import { getLogger } from '../src/Logger'; -import { RESPONSE_ERROR_MESSAGES } from '../src/constants'; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires const open = require('open'); @@ -173,9 +172,6 @@ export class Start extends Command { // If we don't have a JWT secret set, generate // one based and save to config. const encryptionKey = await UserSettings.getEncryptionKey(); - if (!encryptionKey) { - throw new Error('Fatal error setting up user management: no encryption key set.'); - } // For a key off every other letter from encryption key // CAREFUL: do not change this or it breaks all existing tokens. @@ -210,11 +206,7 @@ export class Start extends Command { // Wait till the database is ready await startDbInitPromise; - const encryptionKey = await UserSettings.getEncryptionKey(); - - if (!encryptionKey) { - throw new Error(RESPONSE_ERROR_MESSAGES.NO_ENCRYPTION_KEY); - } + await UserSettings.getEncryptionKey(); // Load settings from database and set them to config. const databaseSettings = await Db.collections.Settings.find({ loadOnStartup: true }); diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index 68155d0fd7..4233340a8e 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -1703,13 +1703,11 @@ class App { ); } - const encryptionKey = await UserSettings.getEncryptionKey(); - if (!encryptionKey) { - throw new ResponseHelper.ResponseError( - RESPONSE_ERROR_MESSAGES.NO_ENCRYPTION_KEY, - undefined, - 500, - ); + let encryptionKey: string; + try { + encryptionKey = await UserSettings.getEncryptionKey(); + } catch (error) { + throw new ResponseHelper.ResponseError(error.message, undefined, 500); } const mode: WorkflowExecuteMode = 'internal'; @@ -1842,15 +1840,11 @@ class App { return ResponseHelper.sendErrorResponse(res, errorResponse); } - const encryptionKey = await UserSettings.getEncryptionKey(); - - if (!encryptionKey) { - const errorResponse = new ResponseHelper.ResponseError( - RESPONSE_ERROR_MESSAGES.NO_ENCRYPTION_KEY, - undefined, - 503, - ); - return ResponseHelper.sendErrorResponse(res, errorResponse); + let encryptionKey: string; + try { + encryptionKey = await UserSettings.getEncryptionKey(); + } catch (error) { + throw new ResponseHelper.ResponseError(error.message, undefined, 500); } const mode: WorkflowExecuteMode = 'internal'; @@ -1962,13 +1956,11 @@ class App { ); } - const encryptionKey = await UserSettings.getEncryptionKey(); - if (!encryptionKey) { - throw new ResponseHelper.ResponseError( - RESPONSE_ERROR_MESSAGES.NO_ENCRYPTION_KEY, - undefined, - 500, - ); + let encryptionKey: string; + try { + encryptionKey = await UserSettings.getEncryptionKey(); + } catch (error) { + throw new ResponseHelper.ResponseError(error.message, undefined, 500); } const mode: WorkflowExecuteMode = 'internal'; @@ -2103,15 +2095,11 @@ class App { return ResponseHelper.sendErrorResponse(res, errorResponse); } - const encryptionKey = await UserSettings.getEncryptionKey(); - - if (!encryptionKey) { - const errorResponse = new ResponseHelper.ResponseError( - RESPONSE_ERROR_MESSAGES.NO_ENCRYPTION_KEY, - undefined, - 503, - ); - return ResponseHelper.sendErrorResponse(res, errorResponse); + let encryptionKey: string; + try { + encryptionKey = await UserSettings.getEncryptionKey(); + } catch (error) { + throw new ResponseHelper.ResponseError(error.message, undefined, 500); } const mode: WorkflowExecuteMode = 'internal'; diff --git a/packages/cli/src/WorkflowExecuteAdditionalData.ts b/packages/cli/src/WorkflowExecuteAdditionalData.ts index 156b324b92..55f52b583b 100644 --- a/packages/cli/src/WorkflowExecuteAdditionalData.ts +++ b/packages/cli/src/WorkflowExecuteAdditionalData.ts @@ -66,6 +66,7 @@ import { getWorkflowOwner, } from './UserManagement/UserManagementHelper'; import { whereClause } from './WorkflowHelpers'; +import { RESPONSE_ERROR_MESSAGES } from './constants'; const ERROR_TRIGGER_TYPE = config.getEnv('nodes.errorTriggerType'); @@ -1030,9 +1031,6 @@ export async function getBase( const webhookTestBaseUrl = urlBaseWebhook + config.getEnv('endpoints.webhookTest'); const encryptionKey = await UserSettings.getEncryptionKey(); - if (encryptionKey === undefined) { - throw new Error('No encryption key got found to decrypt the credentials!'); - } return { credentialsHelper: new CredentialsHelper(encryptionKey), diff --git a/packages/cli/src/api/credentials.api.ts b/packages/cli/src/api/credentials.api.ts index 6880017aa8..e69ed08cd4 100644 --- a/packages/cli/src/api/credentials.api.ts +++ b/packages/cli/src/api/credentials.api.ts @@ -115,13 +115,15 @@ credentialsController.post( ResponseHelper.send(async (req: CredentialRequest.Test): Promise => { const { credentials, nodeToTestWith } = req.body; - const encryptionKey = await UserSettings.getEncryptionKey(); - - if (!encryptionKey) { - return { - status: 'Error', - message: RESPONSE_ERROR_MESSAGES.NO_ENCRYPTION_KEY, - }; + let encryptionKey: string; + try { + encryptionKey = await UserSettings.getEncryptionKey(); + } catch (error) { + throw new ResponseHelper.ResponseError( + RESPONSE_ERROR_MESSAGES.NO_ENCRYPTION_KEY, + undefined, + 500, + ); } const helper = new CredentialsHelper(encryptionKey); @@ -149,9 +151,10 @@ credentialsController.post( nodeAccess.date = new Date(); } - const encryptionKey = await UserSettings.getEncryptionKey(); - - if (!encryptionKey) { + let encryptionKey: string; + try { + encryptionKey = await UserSettings.getEncryptionKey(); + } catch (error) { throw new ResponseHelper.ResponseError( RESPONSE_ERROR_MESSAGES.NO_ENCRYPTION_KEY, undefined, @@ -285,9 +288,10 @@ credentialsController.patch( } } - const encryptionKey = await UserSettings.getEncryptionKey(); - - if (!encryptionKey) { + let encryptionKey: string; + try { + encryptionKey = await UserSettings.getEncryptionKey(); + } catch (error) { throw new ResponseHelper.ResponseError( RESPONSE_ERROR_MESSAGES.NO_ENCRYPTION_KEY, undefined, @@ -393,9 +397,10 @@ credentialsController.get( const { data, id, ...rest } = credential; - const encryptionKey = await UserSettings.getEncryptionKey(); - - if (!encryptionKey) { + let encryptionKey: string; + try { + encryptionKey = await UserSettings.getEncryptionKey(); + } catch (error) { throw new ResponseHelper.ResponseError( RESPONSE_ERROR_MESSAGES.NO_ENCRYPTION_KEY, undefined, diff --git a/packages/cli/src/constants.ts b/packages/cli/src/constants.ts index 3cdfbb00c7..59062c4644 100644 --- a/packages/cli/src/constants.ts +++ b/packages/cli/src/constants.ts @@ -1,8 +1,12 @@ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/naming-convention */ +import { RESPONSE_ERROR_MESSAGES as CORE_RESPONSE_ERROR_MESSAGES } from 'n8n-core'; + export const RESPONSE_ERROR_MESSAGES = { NO_CREDENTIAL: 'Credential not found', - NO_ENCRYPTION_KEY: 'Encryption key missing to decrypt credentials', + NO_ENCRYPTION_KEY: CORE_RESPONSE_ERROR_MESSAGES.NO_ENCRYPTION_KEY, }; export const AUTH_COOKIE_NAME = 'n8n-auth'; diff --git a/packages/cli/test/integration/credentials.api.test.ts b/packages/cli/test/integration/credentials.api.test.ts index f5fa438cd0..e5a502eccd 100644 --- a/packages/cli/test/integration/credentials.api.test.ts +++ b/packages/cli/test/integration/credentials.api.test.ts @@ -7,6 +7,7 @@ import type { CredentialPayload, SaveCredentialFunction } from './shared/types'; import type { Role } from '../../src/databases/entities/Role'; import type { User } from '../../src/databases/entities/User'; import * as testDb from './shared/testDb'; +import { RESPONSE_ERROR_MESSAGES } from '../../src/constants'; import { CredentialsEntity } from '../../src/databases/entities/CredentialsEntity'; jest.mock('../../src/telemetry'); @@ -91,7 +92,7 @@ test('POST /credentials should fail with invalid inputs', async () => { test('POST /credentials should fail with missing encryption key', async () => { const mock = jest.spyOn(UserSettings, 'getEncryptionKey'); - mock.mockResolvedValue(undefined); + mock.mockRejectedValue(new Error(RESPONSE_ERROR_MESSAGES.NO_ENCRYPTION_KEY)); const ownerShell = await testDb.createUserShell(globalOwnerRole); const authOwnerAgent = utils.createAgent(app, { auth: true, user: ownerShell }); @@ -354,7 +355,8 @@ test('PATCH /credentials/:id should fail if cred not found', async () => { test('PATCH /credentials/:id should fail with missing encryption key', async () => { const mock = jest.spyOn(UserSettings, 'getEncryptionKey'); - mock.mockResolvedValue(undefined); + mock.mockRejectedValue(new Error(RESPONSE_ERROR_MESSAGES.NO_ENCRYPTION_KEY)); + const ownerShell = await testDb.createUserShell(globalOwnerRole); const authOwnerAgent = utils.createAgent(app, { auth: true, user: ownerShell }); @@ -504,7 +506,8 @@ test('GET /credentials/:id should fail with missing encryption key', async () => const savedCredential = await saveCredential(credentialPayload(), { user: ownerShell }); const mock = jest.spyOn(UserSettings, 'getEncryptionKey'); - mock.mockResolvedValue(undefined); + mock.mockRejectedValue(new Error(RESPONSE_ERROR_MESSAGES.NO_ENCRYPTION_KEY)); + const response = await authOwnerAgent .get(`/credentials/${savedCredential.id}`) diff --git a/packages/cli/test/integration/shared/testDb.ts b/packages/cli/test/integration/shared/testDb.ts index 3ad2dcfc56..c15ba056a0 100644 --- a/packages/cli/test/integration/shared/testDb.ts +++ b/packages/cli/test/integration/shared/testDb.ts @@ -392,10 +392,6 @@ export const getMySqlOptions = ({ name }: { name: string }): ConnectionOptions = async function encryptCredentialData(credential: CredentialsEntity) { const encryptionKey = await UserSettings.getEncryptionKey(); - if (!encryptionKey) { - throw new Error(RESPONSE_ERROR_MESSAGES.NO_ENCRYPTION_KEY); - } - const coreCredential = new Credentials( { id: null, name: credential.name }, credential.type, diff --git a/packages/core/src/Constants.ts b/packages/core/src/Constants.ts index 43103df5ac..fc1103a493 100644 --- a/packages/core/src/Constants.ts +++ b/packages/core/src/Constants.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/naming-convention */ export const BINARY_ENCODING = 'base64'; export const CUSTOM_EXTENSION_ENV = 'N8N_CUSTOM_EXTENSIONS'; export const ENCRYPTION_KEY_ENV_OVERWRITE = 'N8N_ENCRYPTION_KEY'; @@ -9,3 +10,7 @@ export const PLACEHOLDER_EMPTY_EXECUTION_ID = '__UNKOWN__'; export const PLACEHOLDER_EMPTY_WORKFLOW_ID = '__EMPTY__'; export const TUNNEL_SUBDOMAIN_ENV = 'N8N_TUNNEL_SUBDOMAIN'; export const WAIT_TIME_UNLIMITED = '3000-01-01T00:00:00.000Z'; + +export const RESPONSE_ERROR_MESSAGES = { + NO_ENCRYPTION_KEY: 'Encryption key is missing or was not set', +}; diff --git a/packages/core/src/NodeExecuteFunctions.ts b/packages/core/src/NodeExecuteFunctions.ts index c742cd08e4..6dc23ed38e 100644 --- a/packages/core/src/NodeExecuteFunctions.ts +++ b/packages/core/src/NodeExecuteFunctions.ts @@ -874,13 +874,7 @@ export async function requestOAuth2( oAuth2Options?: IOAuth2Options, isN8nRequest = false, ) { - const credentials = (await this.getCredentials( - credentialsType, - )) as ICredentialDataDecryptedObject; - - if (credentials === undefined) { - throw new Error('No credentials were returned!'); - } + const credentials = await this.getCredentials(credentialsType); if (credentials.oauthTokenData === undefined) { throw new Error('OAuth credentials not connected!'); @@ -997,9 +991,7 @@ export async function requestOAuth1( | IHttpRequestOptions, isN8nRequest = false, ) { - const credentials = (await this.getCredentials( - credentialsType, - )) as ICredentialDataDecryptedObject; + const credentials = await this.getCredentials(credentialsType); if (credentials === undefined) { throw new Error('No credentials were returned!'); @@ -1269,7 +1261,7 @@ export async function getCredentials( runIndex?: number, connectionInputData?: INodeExecutionData[], itemIndex?: number, -): Promise { +): Promise { // Get the NodeType as it has the information if the credentials are required const nodeType = workflow.nodeTypes.getByNameAndVersion(node.type, node.typeVersion); if (nodeType === undefined) { @@ -1309,8 +1301,8 @@ export async function getCredentials( node.parameters, ) ) { - // Credentials should not be displayed so return undefined even if they would be defined - return undefined; + // Credentials should not be displayed even if they would be defined + throw new NodeOperationError(node, 'Credentials not found'); } } @@ -1327,15 +1319,15 @@ export async function getCredentials( throw new NodeOperationError(node, `Node does not have any credentials set for "${type}"!`); } } else { - // Credentials are not required so resolve with undefined - return undefined; + // Credentials are not required + throw new NodeOperationError(node, 'Node does not require credentials'); } } if (fullAccess && (!node.credentials || !node.credentials[type])) { // Make sure that fullAccess nodes still behave like before that if they // request access to credentials that are currently not set it returns undefined - return undefined; + throw new NodeOperationError(node, 'Credentials not found'); } let expressionResolveValues: ICredentialsExpressionResolveValues | undefined; @@ -1605,7 +1597,7 @@ export function getExecutePollFunctions( __emit: (data: INodeExecutionData[][]): void => { throw new Error('Overwrite NodeExecuteFunctions.getExecutePullFunctions.__emit function!'); }, - async getCredentials(type: string): Promise { + async getCredentials(type: string): Promise { return getCredentials(workflow, node, type, additionalData, mode); }, getMode: (): WorkflowExecuteMode => { @@ -1759,7 +1751,7 @@ export function getExecuteTriggerFunctions( emitError: (error: Error): void => { throw new Error('Overwrite NodeExecuteFunctions.getExecuteTriggerFunctions.emit function!'); }, - async getCredentials(type: string): Promise { + async getCredentials(type: string): Promise { return getCredentials(workflow, node, type, additionalData, mode); }, getNode: () => { @@ -1949,7 +1941,7 @@ export function getExecuteFunctions( async getCredentials( type: string, itemIndex?: number, - ): Promise { + ): Promise { return getCredentials( workflow, node, @@ -2193,7 +2185,7 @@ export function getExecuteSingleFunctions( getContext(type: string): IContextObject { return NodeHelpers.getContext(runExecutionData, type, node); }, - async getCredentials(type: string): Promise { + async getCredentials(type: string): Promise { return getCredentials( workflow, node, @@ -2389,7 +2381,7 @@ export function getLoadOptionsFunctions( ): ILoadOptionsFunctions { return ((workflow: Workflow, node: INode, path: string) => { const that = { - async getCredentials(type: string): Promise { + async getCredentials(type: string): Promise { return getCredentials(workflow, node, type, additionalData, 'internal'); }, getCurrentNodeParameter: ( @@ -2533,7 +2525,7 @@ export function getExecuteHookFunctions( ): IHookFunctions { return ((workflow: Workflow, node: INode) => { const that = { - async getCredentials(type: string): Promise { + async getCredentials(type: string): Promise { return getCredentials(workflow, node, type, additionalData, mode); }, getMode: (): WorkflowExecuteMode => { @@ -2692,7 +2684,7 @@ export function getExecuteWebhookFunctions( } return additionalData.httpRequest.body; }, - async getCredentials(type: string): Promise { + async getCredentials(type: string): Promise { return getCredentials(workflow, node, type, additionalData, mode); }, getHeaderData(): object { diff --git a/packages/core/src/UserSettings.ts b/packages/core/src/UserSettings.ts index ca6406b66e..ff3a8d4140 100644 --- a/packages/core/src/UserSettings.ts +++ b/packages/core/src/UserSettings.ts @@ -10,6 +10,7 @@ import { ENCRYPTION_KEY_ENV_OVERWRITE, EXTENSIONS_SUBDIRECTORY, IUserSettings, + RESPONSE_ERROR_MESSAGES, USER_FOLDER_ENV_OVERWRITE, USER_SETTINGS_FILE_NAME, USER_SETTINGS_SUBFOLDER, @@ -73,19 +74,15 @@ export async function prepareUserSettings(): Promise { * @returns */ -export async function getEncryptionKey(): Promise { +export async function getEncryptionKey(): Promise { if (process.env[ENCRYPTION_KEY_ENV_OVERWRITE] !== undefined) { - return process.env[ENCRYPTION_KEY_ENV_OVERWRITE]; + return process.env[ENCRYPTION_KEY_ENV_OVERWRITE] as string; } const userSettings = await getUserSettings(); - if (userSettings === undefined) { - return undefined; - } - - if (userSettings.encryptionKey === undefined) { - return undefined; + if (userSettings === undefined || userSettings.encryptionKey === undefined) { + throw new Error(RESPONSE_ERROR_MESSAGES.NO_ENCRYPTION_KEY); } return userSettings.encryptionKey; diff --git a/packages/nodes-base/nodes/ActiveCampaign/GenericFunctions.ts b/packages/nodes-base/nodes/ActiveCampaign/GenericFunctions.ts index 0fc30fed51..19cf0f65dd 100644 --- a/packages/nodes-base/nodes/ActiveCampaign/GenericFunctions.ts +++ b/packages/nodes-base/nodes/ActiveCampaign/GenericFunctions.ts @@ -27,9 +27,6 @@ export interface IProduct { */ export async function activeCampaignApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: IDataObject, query?: IDataObject, dataKey?: string): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('activeCampaignApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } if (query === undefined) { query = {}; diff --git a/packages/nodes-base/nodes/AcuityScheduling/GenericFunctions.ts b/packages/nodes-base/nodes/AcuityScheduling/GenericFunctions.ts index 687871a814..59bce6d4ef 100644 --- a/packages/nodes-base/nodes/AcuityScheduling/GenericFunctions.ts +++ b/packages/nodes-base/nodes/AcuityScheduling/GenericFunctions.ts @@ -26,9 +26,6 @@ export async function acuitySchedulingApiRequest(this: IHookFunctions | IExecute try { if (authenticationMethod === 'apiKey') { const credentials = await this.getCredentials('acuitySchedulingApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } options.auth = { user: credentials.userId as string, diff --git a/packages/nodes-base/nodes/Affinity/GenericFunctions.ts b/packages/nodes-base/nodes/Affinity/GenericFunctions.ts index f16c861b1d..da80ce7718 100644 --- a/packages/nodes-base/nodes/Affinity/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Affinity/GenericFunctions.ts @@ -20,10 +20,6 @@ export async function affinityApiRequest(this: IExecuteFunctions | IWebhookFunct const credentials = await this.getCredentials('affinityApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const apiKey = `:${credentials.apiKey}`; const endpoint = 'https://api.affinity.co'; diff --git a/packages/nodes-base/nodes/AgileCrm/GenericFunctions.ts b/packages/nodes-base/nodes/AgileCrm/GenericFunctions.ts index 6c01d3c0b8..07464bd983 100644 --- a/packages/nodes-base/nodes/AgileCrm/GenericFunctions.ts +++ b/packages/nodes-base/nodes/AgileCrm/GenericFunctions.ts @@ -12,7 +12,7 @@ import { NodeApiError, } from 'n8n-workflow'; -import { +import { IContactUpdate, } from './ContactInterface'; @@ -31,11 +31,11 @@ export async function agileCrmApiRequest(this: IHookFunctions | IExecuteFunction 'Accept': 'application/json', }, auth: { - username: credentials!.email as string, - password: credentials!.apiKey as string, + username: credentials.email as string, + password: credentials.apiKey as string, }, qs: query, - uri: uri || `https://${credentials!.subdomain}.agilecrm.com/dev/${endpoint}`, + uri: uri || `https://${credentials.subdomain}.agilecrm.com/dev/${endpoint}`, json: true, }; @@ -83,7 +83,7 @@ export async function agileCrmApiRequestAllItems(this: IHookFunctions | ILoadOpt export async function agileCrmApiRequestUpdate(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method = 'PUT', endpoint?: string, body: any = {}, query: IDataObject = {}, uri?: string): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('agileCrmApi'); - const baseUri = `https://${credentials!.subdomain}.agilecrm.com/dev/`; + const baseUri = `https://${credentials.subdomain}.agilecrm.com/dev/`; const options: OptionsWithUri = { method, headers: { @@ -91,8 +91,8 @@ export async function agileCrmApiRequestUpdate(this: IHookFunctions | IExecuteFu }, body: { id: body.id }, auth: { - username: credentials!.email as string, - password: credentials!.apiKey as string, + username: credentials.email as string, + password: credentials.apiKey as string, }, uri: uri || baseUri, json: true, diff --git a/packages/nodes-base/nodes/Airtable/GenericFunctions.ts b/packages/nodes-base/nodes/Airtable/GenericFunctions.ts index 970e9323c7..1f6b5b2ffb 100644 --- a/packages/nodes-base/nodes/Airtable/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Airtable/GenericFunctions.ts @@ -42,10 +42,6 @@ export interface IRecord { export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IPollFunctions, method: string, endpoint: string, body: object, query?: IDataObject, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('airtableApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - query = query || {}; // For some reason for some endpoints the bearer auth does not work diff --git a/packages/nodes-base/nodes/Amqp/Amqp.node.ts b/packages/nodes-base/nodes/Amqp/Amqp.node.ts index 7714ab7e24..54a17e59fd 100644 --- a/packages/nodes-base/nodes/Amqp/Amqp.node.ts +++ b/packages/nodes-base/nodes/Amqp/Amqp.node.ts @@ -98,9 +98,6 @@ export class Amqp implements INodeType { async execute(this: IExecuteFunctions): Promise { try { const credentials = await this.getCredentials('amqp'); - if (!credentials) { - throw new NodeOperationError(this.getNode(), 'Credentials are mandatory!'); - } const sink = this.getNodeParameter('sink', 0, '') as string; const applicationProperties = this.getNodeParameter('headerParametersJson', 0, {}) as string | object; diff --git a/packages/nodes-base/nodes/Amqp/AmqpTrigger.node.ts b/packages/nodes-base/nodes/Amqp/AmqpTrigger.node.ts index cc11ba6c66..1c30b441fb 100644 --- a/packages/nodes-base/nodes/Amqp/AmqpTrigger.node.ts +++ b/packages/nodes-base/nodes/Amqp/AmqpTrigger.node.ts @@ -132,9 +132,6 @@ export class AmqpTrigger implements INodeType { async trigger(this: ITriggerFunctions): Promise { const credentials = await this.getCredentials('amqp'); - if (!credentials) { - throw new NodeOperationError(this.getNode(), 'Credentials are mandatory!'); - } const sink = this.getNodeParameter('sink', '') as string; const clientname = this.getNodeParameter('clientname', '') as string; diff --git a/packages/nodes-base/nodes/Aws/Comprehend/GenericFunctions.ts b/packages/nodes-base/nodes/Aws/Comprehend/GenericFunctions.ts index 399c9ea89c..40d4c73b90 100644 --- a/packages/nodes-base/nodes/Aws/Comprehend/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Aws/Comprehend/GenericFunctions.ts @@ -40,9 +40,6 @@ function getEndpointForService(service: string, credentials: ICredentialDataDecr export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('aws'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } // Concatenate path and instantiate URL object so it parses correctly query strings const endpoint = new URL(getEndpointForService(service, credentials) + path); diff --git a/packages/nodes-base/nodes/Aws/DynamoDB/GenericFunctions.ts b/packages/nodes-base/nodes/Aws/DynamoDB/GenericFunctions.ts index 9e71992875..8b25dd39b0 100644 --- a/packages/nodes-base/nodes/Aws/DynamoDB/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Aws/DynamoDB/GenericFunctions.ts @@ -37,9 +37,6 @@ function getEndpointForService(service: string, credentials: ICredentialDataDecr export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: object | IRequestBody, headers?: object): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('aws'); - if (credentials === undefined) { - throw new Error('No credentials got returned!'); - } // Concatenate path and instantiate URL object so it parses correctly query strings const endpoint = new URL(getEndpointForService(service, credentials) + path); diff --git a/packages/nodes-base/nodes/Aws/GenericFunctions.ts b/packages/nodes-base/nodes/Aws/GenericFunctions.ts index 49fa4c3208..1c89db14f5 100644 --- a/packages/nodes-base/nodes/Aws/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Aws/GenericFunctions.ts @@ -30,9 +30,6 @@ function getEndpointForService(service: string, credentials: ICredentialDataDecr export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('aws'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } // Concatenate path and instantiate URL object so it parses correctly query strings const endpoint = new URL(getEndpointForService(service, credentials) + path); diff --git a/packages/nodes-base/nodes/Aws/Rekognition/GenericFunctions.ts b/packages/nodes-base/nodes/Aws/Rekognition/GenericFunctions.ts index dc2b1b820c..27ba23e4e3 100644 --- a/packages/nodes-base/nodes/Aws/Rekognition/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Aws/Rekognition/GenericFunctions.ts @@ -38,9 +38,6 @@ import { export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string | Buffer | IDataObject, query: IDataObject = {}, headers?: object, option: IDataObject = {}, region?: string): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('aws'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const endpoint = new URL(((credentials.rekognitionEndpoint as string || '').replace('{region}', credentials.region as string) || `https://${service}.${credentials.region}.amazonaws.com`) + path); diff --git a/packages/nodes-base/nodes/Aws/S3/AwsS3.node.ts b/packages/nodes-base/nodes/Aws/S3/AwsS3.node.ts index fd13eb1781..c77fa6d3c6 100644 --- a/packages/nodes-base/nodes/Aws/S3/AwsS3.node.ts +++ b/packages/nodes-base/nodes/Aws/S3/AwsS3.node.ts @@ -137,7 +137,7 @@ export class AwsS3 implements INodeType { if (additionalFields.grantWriteAcp) { headers['x-amz-grant-write-acp'] = ''; } - let region = credentials!.region as string; + let region = credentials.region as string; if (additionalFields.region) { region = additionalFields.region as string; diff --git a/packages/nodes-base/nodes/Aws/S3/GenericFunctions.ts b/packages/nodes-base/nodes/Aws/S3/GenericFunctions.ts index 1aa593e5c3..0838622d01 100644 --- a/packages/nodes-base/nodes/Aws/S3/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Aws/S3/GenericFunctions.ts @@ -32,9 +32,6 @@ import { export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string | Buffer, query: IDataObject = {}, headers?: object, option: IDataObject = {}, region?: string): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('aws'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const endpoint = new URL(((credentials.s3Endpoint as string || '').replace('{region}', credentials.region as string) || `https://${service}.${credentials.region}.amazonaws.com`) + path); diff --git a/packages/nodes-base/nodes/Aws/SES/GenericFunctions.ts b/packages/nodes-base/nodes/Aws/SES/GenericFunctions.ts index 09b28b7aa1..201b03ce51 100644 --- a/packages/nodes-base/nodes/Aws/SES/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Aws/SES/GenericFunctions.ts @@ -32,9 +32,6 @@ import { export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('aws'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const endpoint = new URL(((credentials.sesEndpoint as string || '').replace('{region}', credentials.region as string) || `https://${service}.${credentials.region}.amazonaws.com`) + path); diff --git a/packages/nodes-base/nodes/Aws/Textract/GenericFunctions.ts b/packages/nodes-base/nodes/Aws/Textract/GenericFunctions.ts index 9758552cf4..f0ba1e8dc6 100644 --- a/packages/nodes-base/nodes/Aws/Textract/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Aws/Textract/GenericFunctions.ts @@ -43,9 +43,6 @@ function getEndpointForService(service: string, credentials: ICredentialDataDecr export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('aws'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } // Concatenate path and instantiate URL object so it parses correctly query strings const endpoint = new URL(getEndpointForService(service, credentials) + path); @@ -69,7 +66,7 @@ export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | I const errorMessage = error?.response?.data || error?.response?.body; if (errorMessage.includes('AccessDeniedException')) { const user = JSON.parse(errorMessage).Message.split(' ')[1]; - throw new NodeApiError(this.getNode(), error, { + throw new NodeApiError(this.getNode(), error, { message: 'Unauthorized — please check your AWS policy configuration', description: `Make sure an identity-based policy allows user ${user} to perform textract:AnalyzeExpense` }); } diff --git a/packages/nodes-base/nodes/Aws/Transcribe/GenericFunctions.ts b/packages/nodes-base/nodes/Aws/Transcribe/GenericFunctions.ts index ea2abe4dd1..4e7b8886cb 100644 --- a/packages/nodes-base/nodes/Aws/Transcribe/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Aws/Transcribe/GenericFunctions.ts @@ -43,9 +43,6 @@ function getEndpointForService(service: string, credentials: ICredentialDataDecr export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('aws'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } // Concatenate path and instantiate URL object so it parses correctly query strings const endpoint = new URL(getEndpointForService(service, credentials) + path); diff --git a/packages/nodes-base/nodes/BambooHr/v1/transport/index.ts b/packages/nodes-base/nodes/BambooHr/v1/transport/index.ts index ad51110a01..66a0a7859b 100644 --- a/packages/nodes-base/nodes/BambooHr/v1/transport/index.ts +++ b/packages/nodes-base/nodes/BambooHr/v1/transport/index.ts @@ -27,10 +27,6 @@ export async function apiRequest( ) { const credentials = await this.getCredentials('bambooHrApi'); - if (!credentials) { - throw new NodeOperationError(this.getNode(), 'No credentials returned!'); - } - //set-up credentials const apiKey = credentials.apiKey; const subdomain = credentials.subdomain; diff --git a/packages/nodes-base/nodes/Bannerbear/GenericFunctions.ts b/packages/nodes-base/nodes/Bannerbear/GenericFunctions.ts index 32a750a2d0..dc5373cb35 100644 --- a/packages/nodes-base/nodes/Bannerbear/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Bannerbear/GenericFunctions.ts @@ -23,10 +23,6 @@ export async function bannerbearApiRequest(this: IExecuteFunctions | IWebhookFun const credentials = await this.getCredentials('bannerbearApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const options: OptionsWithUri = { headers: { Accept: 'application/json', diff --git a/packages/nodes-base/nodes/Baserow/GenericFunctions.ts b/packages/nodes-base/nodes/Baserow/GenericFunctions.ts index e081825177..119474ddd6 100644 --- a/packages/nodes-base/nodes/Baserow/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Baserow/GenericFunctions.ts @@ -32,10 +32,6 @@ export async function baserowApiRequest( ) { const credentials = await this.getCredentials('baserowApi') as BaserowCredentials; - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const options: OptionsWithUri = { headers: { Authorization: `JWT ${jwtToken}`, diff --git a/packages/nodes-base/nodes/Beeminder/Beeminder.node.functions.ts b/packages/nodes-base/nodes/Beeminder/Beeminder.node.functions.ts index eee387d7e0..3984b4cf4a 100644 --- a/packages/nodes-base/nodes/Beeminder/Beeminder.node.functions.ts +++ b/packages/nodes-base/nodes/Beeminder/Beeminder.node.functions.ts @@ -18,10 +18,6 @@ import { export async function createDatapoint(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, data: IDataObject) { const credentials = await this.getCredentials('beeminderApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const endpoint = `/users/${credentials.user}/goals/${data.goalName}/datapoints.json`; return await beeminderApiRequest.call(this, 'POST', endpoint, data); @@ -30,10 +26,6 @@ export async function createDatapoint(this: IExecuteFunctions | IWebhookFunction export async function getAllDatapoints(this: IExecuteFunctions | IHookFunctions | ILoadOptionsFunctions, data: IDataObject) { const credentials = await this.getCredentials('beeminderApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const endpoint = `/users/${credentials.user}/goals/${data.goalName}/datapoints.json`; if (data.count !== undefined) { @@ -46,10 +38,6 @@ export async function getAllDatapoints(this: IExecuteFunctions | IHookFunctions export async function updateDatapoint(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, data: IDataObject) { const credentials = await this.getCredentials('beeminderApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const endpoint = `/users/${credentials.user}/goals/${data.goalName}/datapoints/${data.datapointId}.json`; return await beeminderApiRequest.call(this, 'PUT', endpoint, data); @@ -58,10 +46,6 @@ export async function updateDatapoint(this: IExecuteFunctions | IWebhookFunction export async function deleteDatapoint(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, data: IDataObject) { const credentials = await this.getCredentials('beeminderApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const endpoint = `/users/${credentials.user}/goals/${data.goalName}/datapoints/${data.datapointId}.json`; return await beeminderApiRequest.call(this, 'DELETE', endpoint); diff --git a/packages/nodes-base/nodes/Beeminder/Beeminder.node.ts b/packages/nodes-base/nodes/Beeminder/Beeminder.node.ts index 7aa9f9e3ce..11f7093be4 100644 --- a/packages/nodes-base/nodes/Beeminder/Beeminder.node.ts +++ b/packages/nodes-base/nodes/Beeminder/Beeminder.node.ts @@ -307,10 +307,6 @@ export class Beeminder implements INodeType { const credentials = await this.getCredentials('beeminderApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const endpoint = `/users/${credentials.user}/goals.json`; const returnData: INodePropertyOptions[] = []; diff --git a/packages/nodes-base/nodes/Bitbucket/GenericFunctions.ts b/packages/nodes-base/nodes/Bitbucket/GenericFunctions.ts index 8ac1050ebe..af6d52d9b1 100644 --- a/packages/nodes-base/nodes/Bitbucket/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Bitbucket/GenericFunctions.ts @@ -9,9 +9,6 @@ import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function bitbucketApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('bitbucketApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } let options: OptionsWithUri = { method, auth: { diff --git a/packages/nodes-base/nodes/Bitly/GenericFunctions.ts b/packages/nodes-base/nodes/Bitly/GenericFunctions.ts index 2edb001f1c..ec7fd9242f 100644 --- a/packages/nodes-base/nodes/Bitly/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Bitly/GenericFunctions.ts @@ -31,9 +31,6 @@ export async function bitlyApiRequest(this: IHookFunctions | IExecuteFunctions | try{ if (authenticationMethod === 'accessToken') { const credentials = await this.getCredentials('bitlyApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } options.headers = { Authorization: `Bearer ${credentials.accessToken}`}; return await this.helpers.request!(options); diff --git a/packages/nodes-base/nodes/Bitwarden/GenericFunctions.ts b/packages/nodes-base/nodes/Bitwarden/GenericFunctions.ts index e952d8df9d..dd9891c721 100644 --- a/packages/nodes-base/nodes/Bitwarden/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Bitwarden/GenericFunctions.ts @@ -61,7 +61,7 @@ export async function getAccessToken( this: IExecuteFunctions | ILoadOptionsFunctions, ): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('bitwardenApi') as IDataObject; + const credentials = await this.getCredentials('bitwardenApi'); const options: OptionsWithUri = { headers: { @@ -116,7 +116,7 @@ export async function handleGetAll( * Return the access token URL based on the user's environment. */ async function getTokenUrl(this: IExecuteFunctions | ILoadOptionsFunctions) { - const { environment, domain } = await this.getCredentials('bitwardenApi') as IDataObject; + const { environment, domain } = await this.getCredentials('bitwardenApi'); return environment === 'cloudHosted' ? 'https://identity.bitwarden.com/connect/token' @@ -128,7 +128,7 @@ export async function handleGetAll( * Return the base API URL based on the user's environment. */ async function getBaseUrl(this: IExecuteFunctions | ILoadOptionsFunctions) { - const { environment, domain } = await this.getCredentials('bitwardenApi') as IDataObject; + const { environment, domain } = await this.getCredentials('bitwardenApi'); return environment === 'cloudHosted' ? 'https://api.bitwarden.com' diff --git a/packages/nodes-base/nodes/Brandfetch/GenericFunctions.ts b/packages/nodes-base/nodes/Brandfetch/GenericFunctions.ts index 4400f52e3f..3423c79cb5 100644 --- a/packages/nodes-base/nodes/Brandfetch/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Brandfetch/GenericFunctions.ts @@ -16,9 +16,6 @@ import { export async function brandfetchApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any try { const credentials = await this.getCredentials('brandfetchApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } let options: OptionsWithUri = { headers: { 'x-api-key': credentials.apiKey, diff --git a/packages/nodes-base/nodes/Calendly/GenericFunctions.ts b/packages/nodes-base/nodes/Calendly/GenericFunctions.ts index 1557e1cd84..02f11ad0d0 100644 --- a/packages/nodes-base/nodes/Calendly/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Calendly/GenericFunctions.ts @@ -17,10 +17,6 @@ export async function calendlyApiRequest(this: IExecuteFunctions | IWebhookFunct const credentials = await this.getCredentials('calendlyApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const endpoint = 'https://calendly.com/api/v1'; let options: OptionsWithUri = { diff --git a/packages/nodes-base/nodes/Chargebee/Chargebee.node.ts b/packages/nodes-base/nodes/Chargebee/Chargebee.node.ts index cf896518c7..117f8807b9 100644 --- a/packages/nodes-base/nodes/Chargebee/Chargebee.node.ts +++ b/packages/nodes-base/nodes/Chargebee/Chargebee.node.ts @@ -489,10 +489,6 @@ export class Chargebee implements INodeType { const credentials = await this.getCredentials('chargebeeApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const baseUrl = `https://${credentials.accountName}.chargebee.com/api/v2`; // For Post diff --git a/packages/nodes-base/nodes/CircleCi/GenericFunctions.ts b/packages/nodes-base/nodes/CircleCi/GenericFunctions.ts index 171dff05b2..88afcefed5 100644 --- a/packages/nodes-base/nodes/CircleCi/GenericFunctions.ts +++ b/packages/nodes-base/nodes/CircleCi/GenericFunctions.ts @@ -15,9 +15,6 @@ import { export async function circleciApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('circleCiApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } let options: OptionsWithUri = { headers: { 'Circle-Token': credentials.apiKey, diff --git a/packages/nodes-base/nodes/Cisco/Webex/CiscoWebexTrigger.node.ts b/packages/nodes-base/nodes/Cisco/Webex/CiscoWebexTrigger.node.ts index 6694213261..8cbffc0c9a 100644 --- a/packages/nodes-base/nodes/Cisco/Webex/CiscoWebexTrigger.node.ts +++ b/packages/nodes-base/nodes/Cisco/Webex/CiscoWebexTrigger.node.ts @@ -601,9 +601,6 @@ export class CiscoWebexTrigger implements INodeType { const resource = this.getNodeParameter('resource') as string; const filters = this.getNodeParameter('filters', {}) as IDataObject; const credentials = await this.getCredentials('ciscoWebexOAuth2Api'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'Credentials could not be obtained'); - } const secret = getAutomaticSecret(credentials); const filter = []; for (const key of Object.keys(filters)) { diff --git a/packages/nodes-base/nodes/Clearbit/GenericFunctions.ts b/packages/nodes-base/nodes/Clearbit/GenericFunctions.ts index 969adc91cc..8ae14ff171 100644 --- a/packages/nodes-base/nodes/Clearbit/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Clearbit/GenericFunctions.ts @@ -13,9 +13,6 @@ import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function clearbitApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, api: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('clearbitApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } let options: OptionsWithUri = { headers: { Authorization: `Bearer ${credentials.apiKey}` }, method, diff --git a/packages/nodes-base/nodes/ClickUp/GenericFunctions.ts b/packages/nodes-base/nodes/ClickUp/GenericFunctions.ts index 50c1b1fb50..dad1618dcf 100644 --- a/packages/nodes-base/nodes/ClickUp/GenericFunctions.ts +++ b/packages/nodes-base/nodes/ClickUp/GenericFunctions.ts @@ -36,7 +36,7 @@ export async function clickupApiRequest(this: IHookFunctions | IExecuteFunctions const credentials = await this.getCredentials('clickUpApi'); - options.headers!['Authorization'] = credentials?.accessToken; + options.headers!['Authorization'] = credentials.accessToken; return await this.helpers.request!(options); } else { diff --git a/packages/nodes-base/nodes/Clockify/GenericFunctions.ts b/packages/nodes-base/nodes/Clockify/GenericFunctions.ts index 723a187a76..2809ac10cb 100644 --- a/packages/nodes-base/nodes/Clockify/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Clockify/GenericFunctions.ts @@ -15,11 +15,6 @@ import { export async function clockifyApiRequest(this: ILoadOptionsFunctions | IPollFunctions | IExecuteFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('clockifyApi'); - - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - - } const BASE_URL = 'https://api.clockify.me/api/v1'; const options: OptionsWithUri = { diff --git a/packages/nodes-base/nodes/Cockpit/GenericFunctions.ts b/packages/nodes-base/nodes/Cockpit/GenericFunctions.ts index 25ed70f399..e491a11448 100644 --- a/packages/nodes-base/nodes/Cockpit/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Cockpit/GenericFunctions.ts @@ -8,11 +8,6 @@ import { OptionsWithUri } from 'request'; export async function cockpitApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('cockpitApi'); - - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials available.'); - } - let options: OptionsWithUri = { headers: { Accept: 'application/json', diff --git a/packages/nodes-base/nodes/Coda/GenericFunctions.ts b/packages/nodes-base/nodes/Coda/GenericFunctions.ts index 92b1cf1ad9..d22a58116c 100644 --- a/packages/nodes-base/nodes/Coda/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Coda/GenericFunctions.ts @@ -8,9 +8,6 @@ import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function codaApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('codaApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } let options: OptionsWithUri = { headers: { 'Authorization': `Bearer ${credentials.accessToken}`}, diff --git a/packages/nodes-base/nodes/Contentful/GenericFunctions.ts b/packages/nodes-base/nodes/Contentful/GenericFunctions.ts index 75ca5beb65..571b566cb2 100644 --- a/packages/nodes-base/nodes/Contentful/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Contentful/GenericFunctions.ts @@ -15,10 +15,6 @@ import { export async function contentfulApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('contentfulApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const source = this.getNodeParameter('source', 0) as string; const isPreview = source === 'previewApi'; diff --git a/packages/nodes-base/nodes/ConvertKit/GenericFunctions.ts b/packages/nodes-base/nodes/ConvertKit/GenericFunctions.ts index 02aed42ecf..2eeda1b13d 100644 --- a/packages/nodes-base/nodes/ConvertKit/GenericFunctions.ts +++ b/packages/nodes-base/nodes/ConvertKit/GenericFunctions.ts @@ -20,10 +20,6 @@ export async function convertKitApiRequest(this: IExecuteFunctions | IExecuteSin const credentials = await this.getCredentials('convertKitApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - let options: OptionsWithUri = { headers: { 'Content-Type': 'application/json', diff --git a/packages/nodes-base/nodes/Copper/CopperTrigger.node.ts b/packages/nodes-base/nodes/Copper/CopperTrigger.node.ts index 6b5ed96f1c..eddc93e5ff 100644 --- a/packages/nodes-base/nodes/Copper/CopperTrigger.node.ts +++ b/packages/nodes-base/nodes/Copper/CopperTrigger.node.ts @@ -134,7 +134,7 @@ export class CopperTrigger implements INodeType { const credentials = await this.getCredentials('copperApi'); body.secret = { - secret: getAutomaticSecret(credentials!), + secret: getAutomaticSecret(credentials), }; const { id } = await copperApiRequest.call(this, 'POST', endpoint, body); @@ -160,7 +160,7 @@ export class CopperTrigger implements INodeType { const req = this.getRequestObject(); // Check if the supplied secret matches. If not ignore request. - if (req.body.secret !== getAutomaticSecret(credentials!)) { + if (req.body.secret !== getAutomaticSecret(credentials)) { return {}; } diff --git a/packages/nodes-base/nodes/Cortex/GenericFunctions.ts b/packages/nodes-base/nodes/Cortex/GenericFunctions.ts index 37e3ba1772..89509e3218 100644 --- a/packages/nodes-base/nodes/Cortex/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Cortex/GenericFunctions.ts @@ -25,10 +25,6 @@ export async function cortexApiRequest(this: IHookFunctions | IExecuteFunctions const credentials = await this.getCredentials('cortexApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const headerWithAuthentication = Object.assign({}, { Authorization: ` Bearer ${credentials.cortexApiKey}` }); let options: OptionsWithUri = { diff --git a/packages/nodes-base/nodes/CrateDb/CrateDb.node.ts b/packages/nodes-base/nodes/CrateDb/CrateDb.node.ts index 26b29a3ca2..aaf9f6fac5 100644 --- a/packages/nodes-base/nodes/CrateDb/CrateDb.node.ts +++ b/packages/nodes-base/nodes/CrateDb/CrateDb.node.ts @@ -253,10 +253,6 @@ export class CrateDb implements INodeType { async execute(this: IExecuteFunctions): Promise { const credentials = await this.getCredentials('crateDb'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const pgp = pgPromise(); const config = { diff --git a/packages/nodes-base/nodes/CustomerIo/GenericFunctions.ts b/packages/nodes-base/nodes/CustomerIo/GenericFunctions.ts index fdebdcd5fd..e3b166d637 100644 --- a/packages/nodes-base/nodes/CustomerIo/GenericFunctions.ts +++ b/packages/nodes-base/nodes/CustomerIo/GenericFunctions.ts @@ -19,10 +19,6 @@ import { export async function customerIoApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: object, baseApi?: string, query?: IDataObject): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('customerIoApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - query = query || {}; const options: OptionsWithUri = { diff --git a/packages/nodes-base/nodes/DeepL/GenericFunctions.ts b/packages/nodes-base/nodes/DeepL/GenericFunctions.ts index fa1c93e0d2..4986b5a04c 100644 --- a/packages/nodes-base/nodes/DeepL/GenericFunctions.ts +++ b/packages/nodes-base/nodes/DeepL/GenericFunctions.ts @@ -27,10 +27,6 @@ export async function deepLApiRequest( const credentials = await this.getCredentials('deepLApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const options: OptionsWithUri = { headers: { 'Content-Type': 'application/json', @@ -53,10 +49,6 @@ export async function deepLApiRequest( const credentials = await this.getCredentials('deepLApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - options.qs.auth_key = credentials.apiKey; return await this.helpers.request!(options); diff --git a/packages/nodes-base/nodes/Demio/GenericFunctions.ts b/packages/nodes-base/nodes/Demio/GenericFunctions.ts index 4ad71c5d63..f311e65ee0 100644 --- a/packages/nodes-base/nodes/Demio/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Demio/GenericFunctions.ts @@ -16,9 +16,6 @@ import { export async function demioApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any try { const credentials = await this.getCredentials('demioApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } let options: OptionsWithUri = { headers: { 'Api-Key': credentials.apiKey, diff --git a/packages/nodes-base/nodes/Discourse/GenericFunctions.ts b/packages/nodes-base/nodes/Discourse/GenericFunctions.ts index 2532280d60..81462dd288 100644 --- a/packages/nodes-base/nodes/Discourse/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Discourse/GenericFunctions.ts @@ -14,7 +14,7 @@ import { export async function discourseApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, path: string, body: any = {}, qs: IDataObject = {}, option = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('discourseApi') as IDataObject; + const credentials = await this.getCredentials('discourseApi'); const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Disqus/GenericFunctions.ts b/packages/nodes-base/nodes/Disqus/GenericFunctions.ts index eb994e07a0..e475f22d17 100644 --- a/packages/nodes-base/nodes/Disqus/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Disqus/GenericFunctions.ts @@ -18,9 +18,6 @@ export async function disqusApiRequest( const credentials = await this.getCredentials('disqusApi') as IDataObject; qs.api_key = credentials.accessToken; - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } // Convert to query string into a format the API can read const queryStringElements: string[] = []; diff --git a/packages/nodes-base/nodes/Drift/GenericFunctions.ts b/packages/nodes-base/nodes/Drift/GenericFunctions.ts index 8687a4f835..424b35ce75 100644 --- a/packages/nodes-base/nodes/Drift/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Drift/GenericFunctions.ts @@ -37,10 +37,6 @@ export async function driftApiRequest(this: IExecuteFunctions | IWebhookFunction if (authenticationMethod === 'accessToken') { const credentials = await this.getCredentials('driftApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - options.headers!['Authorization'] = `Bearer ${credentials.accessToken}`; return await this.helpers.request!(options); diff --git a/packages/nodes-base/nodes/ERPNext/GenericFunctions.ts b/packages/nodes-base/nodes/ERPNext/GenericFunctions.ts index 0f45ae5296..9afc73f5cc 100644 --- a/packages/nodes-base/nodes/ERPNext/GenericFunctions.ts +++ b/packages/nodes-base/nodes/ERPNext/GenericFunctions.ts @@ -27,10 +27,6 @@ export async function erpNextApiRequest( const credentials = await this.getCredentials('erpNextApi') as ERPNextApiCredentials; const baseUrl = getBaseUrl(credentials); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - let options: OptionsWithUri = { headers: { 'Accept': 'application/json', diff --git a/packages/nodes-base/nodes/Egoi/GenericFunctions.ts b/packages/nodes-base/nodes/Egoi/GenericFunctions.ts index 41c1cade6a..cfc79f46e9 100644 --- a/packages/nodes-base/nodes/Egoi/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Egoi/GenericFunctions.ts @@ -35,7 +35,7 @@ export async function getFields(this: IExecuteFunctions, listId: string) { export async function egoiApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: any = {}, qs: IDataObject = {}, headers?: object): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('egoiApi') as IDataObject; + const credentials = await this.getCredentials('egoiApi'); const options: OptionsWithUrl = { headers: { diff --git a/packages/nodes-base/nodes/EmailReadImap/EmailReadImap.node.ts b/packages/nodes-base/nodes/EmailReadImap/EmailReadImap.node.ts index c6f63fe64c..24842fc8f9 100644 --- a/packages/nodes-base/nodes/EmailReadImap/EmailReadImap.node.ts +++ b/packages/nodes-base/nodes/EmailReadImap/EmailReadImap.node.ts @@ -179,10 +179,6 @@ export class EmailReadImap implements INodeType { async trigger(this: ITriggerFunctions): Promise { const credentials = await this.getCredentials('imap'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const mailbox = this.getNodeParameter('mailbox') as string; const postProcessAction = this.getNodeParameter('postProcessAction') as string; const options = this.getNodeParameter('options', {}) as IDataObject; diff --git a/packages/nodes-base/nodes/EmailSend/EmailSend.node.ts b/packages/nodes-base/nodes/EmailSend/EmailSend.node.ts index 5d459b44ee..c4645559c2 100644 --- a/packages/nodes-base/nodes/EmailSend/EmailSend.node.ts +++ b/packages/nodes-base/nodes/EmailSend/EmailSend.node.ts @@ -146,10 +146,6 @@ export class EmailSend implements INodeType { const credentials = await this.getCredentials('smtp'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const connectionOptions: SMTPTransport.Options = { host: credentials.host as string, port: credentials.port as number, diff --git a/packages/nodes-base/nodes/Eventbrite/GenericFunctions.ts b/packages/nodes-base/nodes/Eventbrite/GenericFunctions.ts index b2102824af..9e3c50615e 100644 --- a/packages/nodes-base/nodes/Eventbrite/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Eventbrite/GenericFunctions.ts @@ -33,9 +33,6 @@ export async function eventbriteApiRequest(this: IHookFunctions | IExecuteFuncti try { if (authenticationMethod === 'privateKey') { const credentials = await this.getCredentials('eventbriteApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } options.headers!['Authorization'] = `Bearer ${credentials.apiKey}`; return await this.helpers.request!(options); diff --git a/packages/nodes-base/nodes/Facebook/FacebookTrigger.node.ts b/packages/nodes-base/nodes/Facebook/FacebookTrigger.node.ts index 952b18382d..5325647e0b 100644 --- a/packages/nodes-base/nodes/Facebook/FacebookTrigger.node.ts +++ b/packages/nodes-base/nodes/Facebook/FacebookTrigger.node.ts @@ -247,7 +247,7 @@ export class FacebookTrigger implements INodeType { const res = this.getResponseObject(); const req = this.getRequestObject(); const headerData = this.getHeaderData() as IDataObject; - const credentials = await this.getCredentials('facebookGraphAppApi') as IDataObject; + const credentials = await this.getCredentials('facebookGraphAppApi'); // Check if we're getting facebook's challenge request (https://developers.facebook.com/docs/graph-api/webhooks/getting-started) if (this.getWebhookName() === 'setup') { if (query['hub.challenge']) { diff --git a/packages/nodes-base/nodes/Facebook/GenericFunctions.ts b/packages/nodes-base/nodes/Facebook/GenericFunctions.ts index b25d8c1955..c2bf8108ee 100644 --- a/packages/nodes-base/nodes/Facebook/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Facebook/GenericFunctions.ts @@ -23,9 +23,9 @@ export async function facebookApiRequest(this: IHookFunctions | IExecuteFunction let credentials; if (this.getNode().name.includes('Trigger')) { - credentials = await this.getCredentials('facebookGraphAppApi') as IDataObject; + credentials = await this.getCredentials('facebookGraphAppApi'); } else { - credentials = await this.getCredentials('facebookGraphApi') as IDataObject; + credentials = await this.getCredentials('facebookGraphApi'); } qs.access_token = credentials!.accessToken; @@ -550,4 +550,4 @@ export function getFields(object: string) { export function getAllFields(object: string) { return getFields(object).filter((field: IDataObject) => field.value !== '*').map((field: IDataObject) => field.value); -} \ No newline at end of file +} diff --git a/packages/nodes-base/nodes/Figma/GenericFunctions.ts b/packages/nodes-base/nodes/Figma/GenericFunctions.ts index 48131f8c5f..aba1874620 100644 --- a/packages/nodes-base/nodes/Figma/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Figma/GenericFunctions.ts @@ -15,7 +15,7 @@ import { } from 'n8n-workflow'; export async function figmaApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('figmaApi') as { accessToken: string }; + const credentials = await this.getCredentials('figmaApi'); let options: OptionsWithUri = { headers: { 'X-FIGMA-TOKEN': credentials.accessToken }, diff --git a/packages/nodes-base/nodes/FileMaker/FileMaker.node.ts b/packages/nodes-base/nodes/FileMaker/FileMaker.node.ts index cd1ce177e3..2e0e37999c 100644 --- a/packages/nodes-base/nodes/FileMaker/FileMaker.node.ts +++ b/packages/nodes-base/nodes/FileMaker/FileMaker.node.ts @@ -774,10 +774,6 @@ export class FileMaker implements INodeType { const credentials = await this.getCredentials('fileMaker'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - let token; try { token = await getToken.call(this); diff --git a/packages/nodes-base/nodes/FileMaker/GenericFunctions.ts b/packages/nodes-base/nodes/FileMaker/GenericFunctions.ts index db2b4711ac..9cb9d4abf2 100644 --- a/packages/nodes-base/nodes/FileMaker/GenericFunctions.ts +++ b/packages/nodes-base/nodes/FileMaker/GenericFunctions.ts @@ -41,9 +41,6 @@ export async function layoutsApiRequest(this: ILoadOptionsFunctions | IExecuteFu const token = await getToken.call(this); const credentials = await this.getCredentials('fileMaker'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const host = credentials.host as string; const db = credentials.db as string; @@ -92,9 +89,6 @@ export async function getFields(this: ILoadOptionsFunctions): Promise { // const credentials = await this.getCredentials('fileMaker'); const layout = this.getCurrentNodeParameter('layout') as string; - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const host = credentials.host as string; const db = credentials.db as string; @@ -128,9 +122,6 @@ export async function getPortals(this: ILoadOptionsFunctions): Promise { // const credentials = await this.getCredentials('fileMaker'); const layout = this.getCurrentNodeParameter('layout') as string; - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const host = credentials.host as string; const db = credentials.db as string; @@ -163,9 +154,6 @@ export async function getScripts(this: ILoadOptionsFunctions): Promise { // const token = await getToken.call(this); const credentials = await this.getCredentials('fileMaker'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const host = credentials.host as string; const db = credentials.db as string; @@ -208,9 +196,6 @@ function parseScriptsList(scripts: ScriptObject[]): INodePropertyOptions[] { export async function getToken(this: ILoadOptionsFunctions | IExecuteFunctions | IExecuteSingleFunctions): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('fileMaker'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const host = credentials.host as string; const db = credentials.db as string; @@ -257,9 +242,6 @@ export async function getToken(this: ILoadOptionsFunctions | IExecuteFunctions | export async function logout(this: ILoadOptionsFunctions | IExecuteFunctions | IExecuteSingleFunctions, token: string): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('fileMaker'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const host = credentials.host as string; const db = credentials.db as string; diff --git a/packages/nodes-base/nodes/Flow/Flow.node.ts b/packages/nodes-base/nodes/Flow/Flow.node.ts index 530235ec82..931ffd67ca 100644 --- a/packages/nodes-base/nodes/Flow/Flow.node.ts +++ b/packages/nodes-base/nodes/Flow/Flow.node.ts @@ -64,10 +64,6 @@ export class Flow implements INodeType { async execute(this: IExecuteFunctions): Promise { const credentials = await this.getCredentials('flowApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const items = this.getInputData(); const returnData: IDataObject[] = []; const length = items.length as unknown as number; diff --git a/packages/nodes-base/nodes/Flow/FlowTrigger.node.ts b/packages/nodes-base/nodes/Flow/FlowTrigger.node.ts index ab54c9c4d2..3cfc1e8f86 100644 --- a/packages/nodes-base/nodes/Flow/FlowTrigger.node.ts +++ b/packages/nodes-base/nodes/Flow/FlowTrigger.node.ts @@ -110,10 +110,6 @@ export class FlowTrigger implements INodeType { async checkExists(this: IHookFunctions): Promise { const credentials = await this.getCredentials('flowApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - let webhooks; const qs: IDataObject = {}; const webhookData = this.getWorkflowStaticData('node'); @@ -144,10 +140,6 @@ export class FlowTrigger implements INodeType { async create(this: IHookFunctions): Promise { const credentials = await this.getCredentials('flowApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - let resourceIds, body, responseData; const webhookUrl = this.getNodeWebhookUrl('default'); const webhookData = this.getWorkflowStaticData('node'); @@ -188,10 +180,6 @@ export class FlowTrigger implements INodeType { async delete(this: IHookFunctions): Promise { const credentials = await this.getCredentials('flowApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const qs: IDataObject = {}; const webhookData = this.getWorkflowStaticData('node'); qs.organization_id = credentials.organizationId as number; diff --git a/packages/nodes-base/nodes/Flow/GenericFunctions.ts b/packages/nodes-base/nodes/Flow/GenericFunctions.ts index cf5b395165..b4104dfb79 100644 --- a/packages/nodes-base/nodes/Flow/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Flow/GenericFunctions.ts @@ -9,9 +9,6 @@ import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function flowApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('flowApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } let options: OptionsWithUri = { headers: { 'Authorization': `Bearer ${credentials.accessToken}`}, diff --git a/packages/nodes-base/nodes/Formstack/GenericFunctions.ts b/packages/nodes-base/nodes/Formstack/GenericFunctions.ts index 7c741741cf..5f0f880fe6 100644 --- a/packages/nodes-base/nodes/Formstack/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Formstack/GenericFunctions.ts @@ -78,10 +78,6 @@ export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoa if (authenticationMethod === 'accessToken') { const credentials = await this.getCredentials('formstackApi') as IDataObject; - if (credentials === undefined) { - throw new Error('No credentials got returned!'); - } - options.headers!['Authorization'] = `Bearer ${credentials.accessToken}`; return await this.helpers.request!(options); } else { diff --git a/packages/nodes-base/nodes/Freshdesk/GenericFunctions.ts b/packages/nodes-base/nodes/Freshdesk/GenericFunctions.ts index 4c54b6cefe..a4172e7ebe 100644 --- a/packages/nodes-base/nodes/Freshdesk/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Freshdesk/GenericFunctions.ts @@ -16,10 +16,6 @@ export async function freshdeskApiRequest(this: IExecuteFunctions | ILoadOptions const credentials = await this.getCredentials('freshdeskApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const apiKey = `${credentials.apiKey}:X`; const endpoint = 'freshdesk.com/api/v2'; diff --git a/packages/nodes-base/nodes/Ftp/Ftp.node.ts b/packages/nodes-base/nodes/Ftp/Ftp.node.ts index 9925581d13..0454a522c1 100644 --- a/packages/nodes-base/nodes/Ftp/Ftp.node.ts +++ b/packages/nodes-base/nodes/Ftp/Ftp.node.ts @@ -403,10 +403,6 @@ export class Ftp implements INodeType { } try { - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'Failed to get credentials!'); - } - let ftp: ftpClient; let sftp: sftpClient; diff --git a/packages/nodes-base/nodes/GetResponse/GenericFunctions.ts b/packages/nodes-base/nodes/GetResponse/GenericFunctions.ts index 13d38c7d04..395d696d96 100644 --- a/packages/nodes-base/nodes/GetResponse/GenericFunctions.ts +++ b/packages/nodes-base/nodes/GetResponse/GenericFunctions.ts @@ -34,7 +34,7 @@ export async function getresponseApiRequest(this: IWebhookFunctions | IHookFunct } if (authentication === 'apiKey') { - const credentials = await this.getCredentials('getResponseApi') as IDataObject; + const credentials = await this.getCredentials('getResponseApi'); options!.headers!['X-Auth-Token'] = `api-key ${credentials.apiKey}`; //@ts-ignore return await this.helpers.request.call(this, options); diff --git a/packages/nodes-base/nodes/Ghost/GenericFunctions.ts b/packages/nodes-base/nodes/Ghost/GenericFunctions.ts index 7560d8276f..9ad1932f33 100644 --- a/packages/nodes-base/nodes/Ghost/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Ghost/GenericFunctions.ts @@ -26,11 +26,11 @@ export async function ghostApiRequest(this: IHookFunctions | IExecuteFunctions | if (source === 'contentApi') { //https://ghost.org/faq/api-versioning/ version = 'v3'; - credentials = await this.getCredentials('ghostContentApi') as IDataObject; + credentials = await this.getCredentials('ghostContentApi'); query.key = credentials.apiKey as string; } else { version = 'v2'; - credentials = await this.getCredentials('ghostAdminApi') as IDataObject; + credentials = await this.getCredentials('ghostAdminApi'); // Create the token (including decoding secret) const [id, secret] = (credentials.apiKey as string).split(':'); diff --git a/packages/nodes-base/nodes/Git/Git.node.ts b/packages/nodes-base/nodes/Git/Git.node.ts index 70f951e583..e070c317ce 100644 --- a/packages/nodes-base/nodes/Git/Git.node.ts +++ b/packages/nodes-base/nodes/Git/Git.node.ts @@ -209,7 +209,7 @@ export class Git implements INodeType { const authentication = this.getNodeParameter('authentication', 0) as string; if (authentication === 'gitPassword') { - const gitCredentials = await this.getCredentials('gitPassword') as IDataObject; + const gitCredentials = await this.getCredentials('gitPassword'); const url = new URL(repositoryPath); url.username = gitCredentials.username as string; diff --git a/packages/nodes-base/nodes/Github/GenericFunctions.ts b/packages/nodes-base/nodes/Github/GenericFunctions.ts index f5bfcf0d50..12e97da9c7 100644 --- a/packages/nodes-base/nodes/Github/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Github/GenericFunctions.ts @@ -40,9 +40,6 @@ export async function githubApiRequest(this: IHookFunctions | IExecuteFunctions, if (authenticationMethod === 'accessToken') { const credentials = await this.getCredentials('githubApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const baseUrl = credentials!.server || 'https://api.github.com'; options.uri = `${baseUrl}${endpoint}`; @@ -52,7 +49,7 @@ export async function githubApiRequest(this: IHookFunctions | IExecuteFunctions, } else { const credentials = await this.getCredentials('githubOAuth2Api'); - const baseUrl = credentials!.server || 'https://api.github.com'; + const baseUrl = credentials.server || 'https://api.github.com'; options.uri = `${baseUrl}${endpoint}`; //@ts-ignore return await this.helpers.requestOAuth2.call(this, 'githubOAuth2Api', options); diff --git a/packages/nodes-base/nodes/Gitlab/GenericFunctions.ts b/packages/nodes-base/nodes/Gitlab/GenericFunctions.ts index ba73e7dfe3..5158309af4 100644 --- a/packages/nodes-base/nodes/Gitlab/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Gitlab/GenericFunctions.ts @@ -40,9 +40,6 @@ export async function gitlabApiRequest(this: IHookFunctions | IExecuteFunctions, try { if (authenticationMethod === 'accessToken') { const credentials = await this.getCredentials('gitlabApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } options.headers!['Private-Token'] = `${credentials.accessToken}`; @@ -51,9 +48,6 @@ export async function gitlabApiRequest(this: IHookFunctions | IExecuteFunctions, return await this.helpers.request(options); } else { const credentials = await this.getCredentials('gitlabOAuth2Api'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } options.uri = `${(credentials.server as string).replace(/\/$/, '')}/api/v4${endpoint}`; diff --git a/packages/nodes-base/nodes/Gitlab/Gitlab.node.ts b/packages/nodes-base/nodes/Gitlab/Gitlab.node.ts index b3270b90c6..7211ce7893 100644 --- a/packages/nodes-base/nodes/Gitlab/Gitlab.node.ts +++ b/packages/nodes-base/nodes/Gitlab/Gitlab.node.ts @@ -1101,16 +1101,8 @@ export class Gitlab implements INodeType { try { if (authenticationMethod === 'accessToken') { credentials = await this.getCredentials('gitlabApi'); - - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } } else { credentials = await this.getCredentials('gitlabOAuth2Api'); - - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } } } catch (error) { if (this.continueOnFail()) { diff --git a/packages/nodes-base/nodes/Google/Books/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Books/GenericFunctions.ts index 12ccbcd9d7..fa6335afbb 100644 --- a/packages/nodes-base/nodes/Google/Books/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Books/GenericFunctions.ts @@ -49,10 +49,6 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF privateKey: string; }; - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const { access_token } = await getAccessToken.call(this, credentials as unknown as IGoogleAuthCredentials); options.headers!.Authorization = `Bearer ${access_token}`; diff --git a/packages/nodes-base/nodes/Google/Chat/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Chat/GenericFunctions.ts index e78e93c3d5..bca871a23c 100644 --- a/packages/nodes-base/nodes/Google/Chat/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Chat/GenericFunctions.ts @@ -57,10 +57,6 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF } else{ const credentials = await this.getCredentials('googleApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const { access_token } = await getAccessToken.call(this, credentials as unknown as IGoogleAuthCredentials); options.headers!.Authorization = `Bearer ${access_token}`; //@ts-ignore diff --git a/packages/nodes-base/nodes/Google/Docs/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Docs/GenericFunctions.ts index 1a193c091c..667730fce6 100644 --- a/packages/nodes-base/nodes/Google/Docs/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Docs/GenericFunctions.ts @@ -53,10 +53,6 @@ export async function googleApiRequest( if (authenticationMethod === 'serviceAccount') { const credentials = await this.getCredentials('googleApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const { access_token } = await getAccessToken.call(this, credentials as unknown as IGoogleAuthCredentials); options.headers!.Authorization = `Bearer ${access_token}`; diff --git a/packages/nodes-base/nodes/Google/Drive/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Drive/GenericFunctions.ts index 48ef48a8c6..9f18b7436c 100644 --- a/packages/nodes-base/nodes/Google/Drive/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Drive/GenericFunctions.ts @@ -50,10 +50,6 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF if (authenticationMethod === 'serviceAccount') { const credentials = await this.getCredentials('googleApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const { access_token } = await getAccessToken.call(this, credentials as unknown as IGoogleAuthCredentials); options.headers!.Authorization = `Bearer ${access_token}`; diff --git a/packages/nodes-base/nodes/Google/Gmail/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Gmail/GenericFunctions.ts index 5ea259adb2..3a392bc73f 100644 --- a/packages/nodes-base/nodes/Google/Gmail/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Gmail/GenericFunctions.ts @@ -65,10 +65,6 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF if (authenticationMethod === 'serviceAccount') { const credentials = await this.getCredentials('googleApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const { access_token } = await getAccessToken.call(this, credentials as unknown as IGoogleAuthCredentials); options.headers!.Authorization = `Bearer ${access_token}`; diff --git a/packages/nodes-base/nodes/Google/Sheet/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Sheet/GenericFunctions.ts index 5e34987d76..93c147a548 100644 --- a/packages/nodes-base/nodes/Google/Sheet/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Sheet/GenericFunctions.ts @@ -47,10 +47,6 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF if (authenticationMethod === 'serviceAccount') { const credentials = await this.getCredentials('googleApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const { access_token } = await getAccessToken.call(this, credentials as unknown as IGoogleAuthCredentials); options.headers!.Authorization = `Bearer ${access_token}`; diff --git a/packages/nodes-base/nodes/Google/Slides/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Slides/GenericFunctions.ts index 66d7a57fa4..1baccd54e4 100644 --- a/packages/nodes-base/nodes/Google/Slides/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Slides/GenericFunctions.ts @@ -56,10 +56,6 @@ export async function googleApiRequest( if (authenticationMethod === 'serviceAccount') { const credentials = await this.getCredentials('googleApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const { access_token } = await getAccessToken.call(this, credentials as unknown as IGoogleAuthCredentials); options.headers.Authorization = `Bearer ${access_token}`; return await this.helpers.request!(options); diff --git a/packages/nodes-base/nodes/Google/Translate/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Translate/GenericFunctions.ts index 940e36c18b..504931be4e 100644 --- a/packages/nodes-base/nodes/Google/Translate/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Translate/GenericFunctions.ts @@ -46,10 +46,6 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF if (authenticationMethod === 'serviceAccount') { const credentials = await this.getCredentials('googleApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const { access_token } = await getAccessToken.call(this, credentials as unknown as IGoogleAuthCredentials); options.headers!.Authorization = `Bearer ${access_token}`; diff --git a/packages/nodes-base/nodes/Gotify/GenericFunctions.ts b/packages/nodes-base/nodes/Gotify/GenericFunctions.ts index e1d8bdca9b..e13bfcfd28 100644 --- a/packages/nodes-base/nodes/Gotify/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Gotify/GenericFunctions.ts @@ -14,7 +14,7 @@ import { export async function gotifyApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, path: string, body: any = {}, qs: IDataObject = {}, uri?: string | undefined, option = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('gotifyApi') as IDataObject; + const credentials = await this.getCredentials('gotifyApi'); const options: OptionsWithUri = { method, diff --git a/packages/nodes-base/nodes/GraphQL/GraphQL.node.ts b/packages/nodes-base/nodes/GraphQL/GraphQL.node.ts index 7048d9461f..0f50e5a628 100644 --- a/packages/nodes-base/nodes/GraphQL/GraphQL.node.ts +++ b/packages/nodes-base/nodes/GraphQL/GraphQL.node.ts @@ -305,12 +305,44 @@ export class GraphQL implements INodeType { async execute(this: IExecuteFunctions): Promise { const items = this.getInputData(); - const httpBasicAuth = await this.getCredentials('httpBasicAuth'); - const httpDigestAuth = await this.getCredentials('httpDigestAuth'); - const httpHeaderAuth = await this.getCredentials('httpHeaderAuth'); - const httpQueryAuth = await this.getCredentials('httpQueryAuth'); - const oAuth1Api = await this.getCredentials('oAuth1Api'); - const oAuth2Api = await this.getCredentials('oAuth2Api'); + let httpBasicAuth; + let httpDigestAuth; + let httpHeaderAuth; + let httpQueryAuth; + let oAuth1Api; + let oAuth2Api; + + try { + httpBasicAuth = await this.getCredentials('httpBasicAuth'); + } catch(error) { + // Do nothing + } + try { + httpDigestAuth = await this.getCredentials('httpDigestAuth'); + } catch(error) { + // Do nothing + } + try { + httpHeaderAuth = await this.getCredentials('httpHeaderAuth'); + } catch(error) { + // Do nothing + } + try { + httpQueryAuth = await this.getCredentials('httpQueryAuth'); + } catch(error) { + // Do nothing + } + try { + oAuth1Api = await this.getCredentials('oAuth1Api'); + } catch(error) { + // Do nothing + } + try { + oAuth2Api = await this.getCredentials('oAuth2Api'); + } catch(error) { + // Do nothing + } + let requestOptions: OptionsWithUri & RequestPromiseOptions; diff --git a/packages/nodes-base/nodes/Gumroad/GenericFunctions.ts b/packages/nodes-base/nodes/Gumroad/GenericFunctions.ts index 412ea18c9c..1cc6df1f64 100644 --- a/packages/nodes-base/nodes/Gumroad/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Gumroad/GenericFunctions.ts @@ -10,9 +10,6 @@ import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function gumroadApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('gumroadApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } body = Object.assign({ access_token: credentials.accessToken }, body); let options: OptionsWithUri = { diff --git a/packages/nodes-base/nodes/HaloPSA/GenericFunctions.ts b/packages/nodes-base/nodes/HaloPSA/GenericFunctions.ts index c98be4b307..6133809d6d 100644 --- a/packages/nodes-base/nodes/HaloPSA/GenericFunctions.ts +++ b/packages/nodes-base/nodes/HaloPSA/GenericFunctions.ts @@ -28,7 +28,7 @@ interface IHaloPSATokens { export async function getAccessTokens( this: IExecuteFunctions | ILoadOptionsFunctions, ): Promise { - const credentials = (await this.getCredentials('haloPSAApi')) as IDataObject; + const credentials = await this.getCredentials('haloPSAApi'); const options: OptionsWithUri = { headers: { @@ -67,7 +67,7 @@ export async function haloPSAApiRequest( qs: IDataObject = {}, option: IDataObject = {}, ): Promise { // tslint:disable-line:no-any - const resourceApiUrl = ((await this.getCredentials('haloPSAApi')) as IDataObject) + const resourceApiUrl = (await this.getCredentials('haloPSAApi')) .resourceApiUrl as string; try { diff --git a/packages/nodes-base/nodes/Harvest/GenericFunctions.ts b/packages/nodes-base/nodes/Harvest/GenericFunctions.ts index 8d074aef25..276c9dfe25 100644 --- a/packages/nodes-base/nodes/Harvest/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Harvest/GenericFunctions.ts @@ -35,11 +35,7 @@ export async function harvestApiRequest(this: IHookFunctions | IExecuteFunctions try { if (authenticationMethod === 'accessToken') { - const credentials = await this.getCredentials('harvestApi') as IDataObject; - - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } + const credentials = await this.getCredentials('harvestApi'); //@ts-ignore options.headers['Authorization'] = `Bearer ${credentials.accessToken}`; diff --git a/packages/nodes-base/nodes/HomeAssistant/GenericFunctions.ts b/packages/nodes-base/nodes/HomeAssistant/GenericFunctions.ts index 673caab7c3..6fcef17943 100644 --- a/packages/nodes-base/nodes/HomeAssistant/GenericFunctions.ts +++ b/packages/nodes-base/nodes/HomeAssistant/GenericFunctions.ts @@ -17,10 +17,6 @@ import { export async function homeAssistantApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions, method: string, resource: string, body: IDataObject = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}) { const credentials = await this.getCredentials('homeAssistantApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - let options: OptionsWithUri = { headers: { Authorization: `Bearer ${credentials.accessToken}`, diff --git a/packages/nodes-base/nodes/HttpRequest/HttpRequest.node.ts b/packages/nodes-base/nodes/HttpRequest/HttpRequest.node.ts index 2a84eb0dc8..17d0758dec 100644 --- a/packages/nodes-base/nodes/HttpRequest/HttpRequest.node.ts +++ b/packages/nodes-base/nodes/HttpRequest/HttpRequest.node.ts @@ -658,12 +658,43 @@ export class HttpRequest implements INodeType { const parametersAreJson = this.getNodeParameter('jsonParameters', 0) as boolean; const responseFormat = this.getNodeParameter('responseFormat', 0) as string; - const httpBasicAuth = await this.getCredentials('httpBasicAuth'); - const httpDigestAuth = await this.getCredentials('httpDigestAuth'); - const httpHeaderAuth = await this.getCredentials('httpHeaderAuth'); - const httpQueryAuth = await this.getCredentials('httpQueryAuth'); - const oAuth1Api = await this.getCredentials('oAuth1Api'); - const oAuth2Api = await this.getCredentials('oAuth2Api'); + let httpBasicAuth; + let httpDigestAuth; + let httpHeaderAuth; + let httpQueryAuth; + let oAuth1Api; + let oAuth2Api; + + try { + httpBasicAuth = await this.getCredentials('httpBasicAuth'); + } catch (error) { + // Do nothing + } + try { + httpDigestAuth = await this.getCredentials('httpDigestAuth'); + } catch (error) { + // Do nothing + } + try { + httpHeaderAuth = await this.getCredentials('httpHeaderAuth'); + } catch (error) { + // Do nothing + } + try { + httpQueryAuth = await this.getCredentials('httpQueryAuth'); + } catch (error) { + // Do nothing + } + try { + oAuth1Api = await this.getCredentials('oAuth1Api'); + } catch (error) { + // Do nothing + } + try { + oAuth2Api = await this.getCredentials('oAuth2Api'); + } catch (error) { + // Do nothing + } let requestOptions: OptionsWithUri; let setUiParameter: IDataObject; diff --git a/packages/nodes-base/nodes/Hubspot/GenericFunctions.ts b/packages/nodes-base/nodes/Hubspot/GenericFunctions.ts index c37d7a19fe..13711fadc9 100644 --- a/packages/nodes-base/nodes/Hubspot/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Hubspot/GenericFunctions.ts @@ -41,18 +41,18 @@ export async function hubspotApiRequest(this: IHookFunctions | IExecuteFunctions if (authenticationMethod === 'apiKey') { const credentials = await this.getCredentials('hubspotApi'); - options.qs.hapikey = credentials!.apiKey as string; + options.qs.hapikey = credentials.apiKey as string; return await this.helpers.request!(options); } else if (authenticationMethod === 'appToken') { const credentials = await this.getCredentials('hubspotAppToken'); - options.headers!['Authorization'] = `Bearer ${credentials!.appToken}`; + options.headers!['Authorization'] = `Bearer ${credentials.appToken}`; return await this.helpers.request!(options); } else if (authenticationMethod === 'developerApi') { if (endpoint.includes('webhooks')) { const credentials = await this.getCredentials('hubspotDeveloperApi'); - options.qs.hapikey = credentials!.apiKey as string; + options.qs.hapikey = credentials.apiKey as string; return await this.helpers.request!(options); } else { diff --git a/packages/nodes-base/nodes/Hubspot/HubspotTrigger.node.ts b/packages/nodes-base/nodes/Hubspot/HubspotTrigger.node.ts index 38241757f5..eae01dfa8f 100644 --- a/packages/nodes-base/nodes/Hubspot/HubspotTrigger.node.ts +++ b/packages/nodes-base/nodes/Hubspot/HubspotTrigger.node.ts @@ -282,7 +282,7 @@ export class HubspotTrigger implements INodeType { // Check all the webhooks which exist already if it is identical to the // one that is supposed to get created. const currentWebhookUrl = this.getNodeWebhookUrl('default') as string; - const { appId } = await this.getCredentials('hubspotDeveloperApi') as IDataObject; + const { appId } = await this.getCredentials('hubspotDeveloperApi'); try { const { targetUrl } = await hubspotApiRequest.call(this, 'GET', `/webhooks/v3/${appId}/settings`, {}); @@ -309,7 +309,7 @@ export class HubspotTrigger implements INodeType { }, async create(this: IHookFunctions): Promise { const webhookUrl = this.getNodeWebhookUrl('default'); - const { appId } = await this.getCredentials('hubspotDeveloperApi') as IDataObject; + const { appId } = await this.getCredentials('hubspotDeveloperApi'); const events = (this.getNodeParameter('eventsUi') as IDataObject || {}).eventValues as IDataObject[] || []; const additionalFields = this.getNodeParameter('additionalFields') as IDataObject; let endpoint = `/webhooks/v3/${appId}/settings`; @@ -341,7 +341,7 @@ export class HubspotTrigger implements INodeType { return true; }, async delete(this: IHookFunctions): Promise { - const { appId } = await this.getCredentials('hubspotDeveloperApi') as IDataObject; + const { appId } = await this.getCredentials('hubspotDeveloperApi'); const { results: subscriptions } = await hubspotApiRequest.call(this, 'GET', `/webhooks/v3/${appId}/subscriptions`, {}); @@ -361,7 +361,7 @@ export class HubspotTrigger implements INodeType { async webhook(this: IWebhookFunctions): Promise { - const credentials = await this.getCredentials('hubspotDeveloperApi') as IDataObject; + const credentials = await this.getCredentials('hubspotDeveloperApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials found!'); diff --git a/packages/nodes-base/nodes/HumanticAI/GenericFunctions.ts b/packages/nodes-base/nodes/HumanticAI/GenericFunctions.ts index 68b82cb7a0..8e0603f969 100644 --- a/packages/nodes-base/nodes/HumanticAI/GenericFunctions.ts +++ b/packages/nodes-base/nodes/HumanticAI/GenericFunctions.ts @@ -16,9 +16,6 @@ import { export async function humanticAiApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, option: IDataObject = {}): Promise { // tslint:disable-line:no-any try { const credentials = await this.getCredentials('humanticAiApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } let options: OptionsWithUri = { headers: { 'Content-Type': 'application/json', diff --git a/packages/nodes-base/nodes/Hunter/GenericFunctions.ts b/packages/nodes-base/nodes/Hunter/GenericFunctions.ts index 070b0f59e0..2dbd9c75ad 100644 --- a/packages/nodes-base/nodes/Hunter/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Hunter/GenericFunctions.ts @@ -9,9 +9,6 @@ import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function hunterApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('hunterApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } qs = Object.assign({ api_key: credentials.apiKey }, qs); let options: OptionsWithUri = { method, diff --git a/packages/nodes-base/nodes/Intercom/GenericFunctions.ts b/packages/nodes-base/nodes/Intercom/GenericFunctions.ts index 42ac234414..f0d666c367 100644 --- a/packages/nodes-base/nodes/Intercom/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Intercom/GenericFunctions.ts @@ -13,9 +13,6 @@ import { export async function intercomApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, endpoint: string, method: string, body: any = {}, query?: IDataObject, uri?: string): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('intercomApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const headerWithAuthentication = Object.assign({}, { Authorization: `Bearer ${credentials.apiKey}`, Accept: 'application/json' }); diff --git a/packages/nodes-base/nodes/InvoiceNinja/GenericFunctions.ts b/packages/nodes-base/nodes/InvoiceNinja/GenericFunctions.ts index 4f8aacd522..072ef66fb0 100644 --- a/packages/nodes-base/nodes/InvoiceNinja/GenericFunctions.ts +++ b/packages/nodes-base/nodes/InvoiceNinja/GenericFunctions.ts @@ -19,9 +19,6 @@ import { export async function invoiceNinjaApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: any = {}, query?: IDataObject, uri?: string): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('invoiceNinjaApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const baseUrl = credentials!.url || 'https://app.invoiceninja.com'; const options: OptionsWithUri = { diff --git a/packages/nodes-base/nodes/Iterable/GenericFunctions.ts b/packages/nodes-base/nodes/Iterable/GenericFunctions.ts index 688da08d8d..068598b270 100644 --- a/packages/nodes-base/nodes/Iterable/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Iterable/GenericFunctions.ts @@ -14,7 +14,7 @@ import { export async function iterableApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, headers: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('iterableApi') as IDataObject; + const credentials = await this.getCredentials('iterableApi'); const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Jenkins/GenericFunctions.ts b/packages/nodes-base/nodes/Jenkins/GenericFunctions.ts index 85ad9b8eb9..f176018d6e 100644 --- a/packages/nodes-base/nodes/Jenkins/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Jenkins/GenericFunctions.ts @@ -15,7 +15,7 @@ import { } from 'n8n-workflow'; export async function jenkinsApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, uri: string, qs: IDataObject = {}, body: any = '', option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('jenkinsApi') as IDataObject; + const credentials = await this.getCredentials('jenkinsApi'); let options: OptionsWithUri = { headers: { 'Accept': 'application/json', diff --git a/packages/nodes-base/nodes/Jira/GenericFunctions.ts b/packages/nodes-base/nodes/Jira/GenericFunctions.ts index 277b566ecd..32e485247a 100644 --- a/packages/nodes-base/nodes/Jira/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Jira/GenericFunctions.ts @@ -22,17 +22,13 @@ export async function jiraSoftwareCloudApiRequest(this: IHookFunctions | IExecut const jiraVersion = this.getNodeParameter('jiraVersion', 0) as string; - let jiraCredentials: ICredentialDataDecryptedObject | undefined; + let jiraCredentials: ICredentialDataDecryptedObject; if (jiraVersion === 'server') { jiraCredentials = await this.getCredentials('jiraSoftwareServerApi'); } else { jiraCredentials = await this.getCredentials('jiraSoftwareCloudApi'); } - if (jiraCredentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - if (jiraVersion === 'server') { domain = jiraCredentials!.domain; data = Buffer.from(`${jiraCredentials!.email}:${jiraCredentials!.password}`).toString('base64'); @@ -120,7 +116,7 @@ export function getId(url: string) { return url.split('/').pop(); } -export function simplifyIssueOutput(responseData: { +export function simplifyIssueOutput(responseData: { names: { [key: string]: string }, fields: IDataObject, id: string, diff --git a/packages/nodes-base/nodes/JotForm/GenericFunctions.ts b/packages/nodes-base/nodes/JotForm/GenericFunctions.ts index 0aff20da1e..6a5fd10580 100644 --- a/packages/nodes-base/nodes/JotForm/GenericFunctions.ts +++ b/packages/nodes-base/nodes/JotForm/GenericFunctions.ts @@ -10,9 +10,6 @@ import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function jotformApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('jotFormApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } let options: OptionsWithUri = { headers: { 'APIKEY': credentials.apiKey, diff --git a/packages/nodes-base/nodes/Kafka/Kafka.node.ts b/packages/nodes-base/nodes/Kafka/Kafka.node.ts index c936735d32..e5eb9a7bc3 100644 --- a/packages/nodes-base/nodes/Kafka/Kafka.node.ts +++ b/packages/nodes-base/nodes/Kafka/Kafka.node.ts @@ -222,7 +222,7 @@ export class Kafka implements INodeType { compression = CompressionTypes.GZIP; } - const credentials = await this.getCredentials('kafka') as IDataObject; + const credentials = await this.getCredentials('kafka'); const brokers = (credentials.brokers as string || '').split(',').map(item => item.trim()) as string[]; diff --git a/packages/nodes-base/nodes/Kafka/KafkaTrigger.node.ts b/packages/nodes-base/nodes/Kafka/KafkaTrigger.node.ts index 4a882bdcbe..5a0260e9e2 100644 --- a/packages/nodes-base/nodes/Kafka/KafkaTrigger.node.ts +++ b/packages/nodes-base/nodes/Kafka/KafkaTrigger.node.ts @@ -147,7 +147,7 @@ export class KafkaTrigger implements INodeType { const groupId = this.getNodeParameter('groupId') as string; - const credentials = await this.getCredentials('kafka') as IDataObject; + const credentials = await this.getCredentials('kafka'); const brokers = (credentials.brokers as string || '').split(',').map(item => item.trim()) as string[]; diff --git a/packages/nodes-base/nodes/KoBoToolbox/GenericFunctions.ts b/packages/nodes-base/nodes/KoBoToolbox/GenericFunctions.ts index 0fbf61e697..07afbadbdb 100644 --- a/packages/nodes-base/nodes/KoBoToolbox/GenericFunctions.ts +++ b/packages/nodes-base/nodes/KoBoToolbox/GenericFunctions.ts @@ -15,7 +15,7 @@ import { import _ from 'lodash'; export async function koBoToolboxApiRequest(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('koBoToolboxApi') as IDataObject; + const credentials = await this.getCredentials('koBoToolboxApi'); // Set up pagination / scrolling const returnAll = !!option.returnAll; @@ -165,7 +165,7 @@ export async function downloadAttachments(this: IExecuteFunctions | IWebhookFunc binary: {}, }; - const credentials = await this.getCredentials('koBoToolboxApi') as IDataObject; + const credentials = await this.getCredentials('koBoToolboxApi'); // Look for attachment links - there can be more than one const attachmentList = (submission['_attachments'] || submission['attachments']) as any[]; // tslint:disable-line:no-any diff --git a/packages/nodes-base/nodes/Linear/GenericFunctions.ts b/packages/nodes-base/nodes/Linear/GenericFunctions.ts index 666299260f..8b8ae6c11c 100644 --- a/packages/nodes-base/nodes/Linear/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Linear/GenericFunctions.ts @@ -24,7 +24,7 @@ import { } from './Queries'; export async function linearApiRequest(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, body: any = {}, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('linearApi') as IDataObject; + const credentials = await this.getCredentials('linearApi'); const endpoint = 'https://api.linear.app/graphql'; diff --git a/packages/nodes-base/nodes/LingvaNex/GenericFunctions.ts b/packages/nodes-base/nodes/LingvaNex/GenericFunctions.ts index cf7341e4d5..f08c43bf69 100644 --- a/packages/nodes-base/nodes/LingvaNex/GenericFunctions.ts +++ b/packages/nodes-base/nodes/LingvaNex/GenericFunctions.ts @@ -16,9 +16,6 @@ import { export async function lingvaNexApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any try { const credentials = await this.getCredentials('lingvaNexApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } let options: OptionsWithUri = { headers: { Authorization: `Bearer ${credentials.apiKey}`, diff --git a/packages/nodes-base/nodes/MQTT/Mqtt.node.ts b/packages/nodes-base/nodes/MQTT/Mqtt.node.ts index a090532cd0..712b712b75 100644 --- a/packages/nodes-base/nodes/MQTT/Mqtt.node.ts +++ b/packages/nodes-base/nodes/MQTT/Mqtt.node.ts @@ -108,7 +108,7 @@ export class Mqtt implements INodeType { async execute(this: IExecuteFunctions): Promise { const items = this.getInputData(); const length = (items.length as unknown) as number; - const credentials = await this.getCredentials('mqtt') as IDataObject; + const credentials = await this.getCredentials('mqtt'); const protocol = credentials.protocol as string || 'mqtt'; const host = credentials.host as string; diff --git a/packages/nodes-base/nodes/MQTT/MqttTrigger.node.ts b/packages/nodes-base/nodes/MQTT/MqttTrigger.node.ts index 104f82437e..5e2f8e1a70 100644 --- a/packages/nodes-base/nodes/MQTT/MqttTrigger.node.ts +++ b/packages/nodes-base/nodes/MQTT/MqttTrigger.node.ts @@ -73,10 +73,6 @@ export class MqttTrigger implements INodeType { const credentials = await this.getCredentials('mqtt'); - if (!credentials) { - throw new NodeOperationError(this.getNode(), 'Credentials are mandatory!'); - } - const topics = (this.getNodeParameter('topics') as string).split(','); const topicsQoS: IDataObject = {}; diff --git a/packages/nodes-base/nodes/Magento/GenericFunctions.ts b/packages/nodes-base/nodes/Magento/GenericFunctions.ts index 4a7353a507..baede8153a 100644 --- a/packages/nodes-base/nodes/Magento/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Magento/GenericFunctions.ts @@ -25,7 +25,7 @@ import { } from './Types'; export async function magentoApiRequest(this: IWebhookFunctions | IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, headers: IDataObject = {}, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('magento2Api') as IDataObject; + const credentials = await this.getCredentials('magento2Api'); let options: OptionsWithUri = { method, diff --git a/packages/nodes-base/nodes/Mailcheck/GenericFunctions.ts b/packages/nodes-base/nodes/Mailcheck/GenericFunctions.ts index 504a1d3606..62e24f6c7e 100644 --- a/packages/nodes-base/nodes/Mailcheck/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Mailcheck/GenericFunctions.ts @@ -14,7 +14,7 @@ import { } from 'n8n-workflow'; export async function mailCheckApiRequest(this: IWebhookFunctions | IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, headers: IDataObject = {}, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('mailcheckApi') as IDataObject; + const credentials = await this.getCredentials('mailcheckApi'); let options: OptionsWithUri = { headers: { @@ -44,4 +44,4 @@ export async function mailCheckApiRequest(this: IWebhookFunctions | IHookFunctio } throw error; } -} \ No newline at end of file +} diff --git a/packages/nodes-base/nodes/Mailchimp/GenericFunctions.ts b/packages/nodes-base/nodes/Mailchimp/GenericFunctions.ts index d1df3eb360..d86cab10e0 100644 --- a/packages/nodes-base/nodes/Mailchimp/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Mailchimp/GenericFunctions.ts @@ -37,10 +37,6 @@ export async function mailchimpApiRequest(this: IHookFunctions | IExecuteFunctio if (authenticationMethod === 'apiKey') { const credentials = await this.getCredentials('mailchimpApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - options.headers = Object.assign({}, headers, { Authorization: `apikey ${credentials.apiKey}` }); if (!(credentials.apiKey as string).includes('-')) { @@ -52,7 +48,7 @@ export async function mailchimpApiRequest(this: IHookFunctions | IExecuteFunctio return await this.helpers.request!(options); } else { - const credentials = await this.getCredentials('mailchimpOAuth2Api') as IDataObject; + const credentials = await this.getCredentials('mailchimpOAuth2Api'); const { api_endpoint } = await getMetadata.call(this, credentials.oauthTokenData as IDataObject); @@ -96,7 +92,7 @@ export function validateJSON(json: string | undefined): any { // tslint:disable- } async function getMetadata(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, oauthTokenData: IDataObject) { - const credentials = await this.getCredentials('mailchimpOAuth2Api') as IDataObject; + const credentials = await this.getCredentials('mailchimpOAuth2Api'); const options: OptionsWithUrl = { headers: { 'Accept': 'application/json', diff --git a/packages/nodes-base/nodes/MailerLite/GenericFunctions.ts b/packages/nodes-base/nodes/MailerLite/GenericFunctions.ts index 2f98f8b949..a9ef546ab5 100644 --- a/packages/nodes-base/nodes/MailerLite/GenericFunctions.ts +++ b/packages/nodes-base/nodes/MailerLite/GenericFunctions.ts @@ -15,7 +15,7 @@ import { export async function mailerliteApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IHookFunctions, method: string, path: string, body: any = {}, qs: IDataObject = {}, option = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('mailerLiteApi') as IDataObject; + const credentials = await this.getCredentials('mailerLiteApi'); const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Mailgun/Mailgun.node.ts b/packages/nodes-base/nodes/Mailgun/Mailgun.node.ts index f2ce0d753d..3bd11cd850 100644 --- a/packages/nodes-base/nodes/Mailgun/Mailgun.node.ts +++ b/packages/nodes-base/nodes/Mailgun/Mailgun.node.ts @@ -125,10 +125,6 @@ export class Mailgun implements INodeType { const credentials = await this.getCredentials('mailgunApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const formData: IDataObject = { from: fromEmail, to: toEmail, diff --git a/packages/nodes-base/nodes/Mailjet/GenericFunctions.ts b/packages/nodes-base/nodes/Mailjet/GenericFunctions.ts index 49c2b72eca..7807eda359 100644 --- a/packages/nodes-base/nodes/Mailjet/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Mailjet/GenericFunctions.ts @@ -43,7 +43,7 @@ export async function mailjetApiRequest(this: IExecuteFunctions | IExecuteSingle }; } else { const smsApiCredentials = await this.getCredentials('mailjetSmsApi'); - options.headers!['Authorization'] = `Bearer ${smsApiCredentials!.token}`; + options.headers!['Authorization'] = `Bearer ${smsApiCredentials.token}`; } try { return await this.helpers.request!(options); diff --git a/packages/nodes-base/nodes/Mandrill/GenericFunctions.ts b/packages/nodes-base/nodes/Mandrill/GenericFunctions.ts index fe7899e517..c7555b99b4 100644 --- a/packages/nodes-base/nodes/Mandrill/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Mandrill/GenericFunctions.ts @@ -14,10 +14,6 @@ import { NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function mandrillApiRequest(this: IExecuteFunctions | IHookFunctions | ILoadOptionsFunctions, resource: string, method: string, action: string, body: any = {}, headers?: object): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('mandrillApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const data = Object.assign({}, body, { key: credentials.apiKey }); const endpoint = 'mandrillapp.com/api/1.0'; diff --git a/packages/nodes-base/nodes/Marketstack/GenericFunctions.ts b/packages/nodes-base/nodes/Marketstack/GenericFunctions.ts index 76097aefb3..325637134f 100644 --- a/packages/nodes-base/nodes/Marketstack/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Marketstack/GenericFunctions.ts @@ -19,7 +19,7 @@ export async function marketstackApiRequest( body: IDataObject = {}, qs: IDataObject = {}, ) { - const credentials = await this.getCredentials('marketstackApi') as IDataObject; + const credentials = await this.getCredentials('marketstackApi'); const protocol = credentials.useHttps ? 'https' : 'http'; // Free API does not support HTTPS const options: OptionsWithUri = { diff --git a/packages/nodes-base/nodes/Matrix/GenericFunctions.ts b/packages/nodes-base/nodes/Matrix/GenericFunctions.ts index 25a0d22a88..230ae6c3f5 100644 --- a/packages/nodes-base/nodes/Matrix/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Matrix/GenericFunctions.ts @@ -50,9 +50,6 @@ export async function matrixApiRequest(this: IExecuteFunctions | IExecuteSingleF let response: any; // tslint:disable-line:no-any const credentials = await this.getCredentials('matrixApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } //@ts-ignore options.uri = `${credentials.homeserverUrl}/_matrix/${option.overridePrefix || 'client'}/r0${resource}`; options.headers!.Authorization = `Bearer ${credentials.accessToken}`; diff --git a/packages/nodes-base/nodes/Mattermost/v1/transport/index.ts b/packages/nodes-base/nodes/Mattermost/v1/transport/index.ts index c76440e626..96fd780369 100644 --- a/packages/nodes-base/nodes/Mattermost/v1/transport/index.ts +++ b/packages/nodes-base/nodes/Mattermost/v1/transport/index.ts @@ -24,10 +24,6 @@ export async function apiRequest( ) { const credentials = await this.getCredentials('mattermostApi'); - if (!credentials) { - throw new NodeOperationError(this.getNode(), 'No credentials returned!'); - } - const options: IHttpRequestOptions = { method, body, diff --git a/packages/nodes-base/nodes/Mautic/GenericFunctions.ts b/packages/nodes-base/nodes/Mautic/GenericFunctions.ts index 6b68c00ff9..bbb26a00c7 100644 --- a/packages/nodes-base/nodes/Mautic/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Mautic/GenericFunctions.ts @@ -34,8 +34,8 @@ export async function mauticApiRequest(this: IHookFunctions | IExecuteFunctions let returnData; if (authenticationMethod === 'credentials') { - const credentials = await this.getCredentials('mauticApi') as IDataObject; - const baseUrl = credentials!.url as string; + const credentials = await this.getCredentials('mauticApi'); + const baseUrl = credentials.url as string; const base64Key = Buffer.from(`${credentials.username}:${credentials.password}`).toString('base64'); @@ -46,8 +46,8 @@ export async function mauticApiRequest(this: IHookFunctions | IExecuteFunctions //@ts-ignore returnData = await this.helpers.request(options); } else { - const credentials = await this.getCredentials('mauticOAuth2Api') as IDataObject; - const baseUrl = credentials!.url as string; + const credentials = await this.getCredentials('mauticOAuth2Api'); + const baseUrl = credentials.url as string; options.uri = `${baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl}${options.uri}`; //@ts-ignore diff --git a/packages/nodes-base/nodes/Medium/GenericFunctions.ts b/packages/nodes-base/nodes/Medium/GenericFunctions.ts index c6d4daa06c..1d3fbcd14a 100644 --- a/packages/nodes-base/nodes/Medium/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Medium/GenericFunctions.ts @@ -34,10 +34,6 @@ export async function mediumApiRequest(this: IHookFunctions | IExecuteFunctions if (authenticationMethod === 'accessToken') { const credentials = await this.getCredentials('mediumApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - options.headers!['Authorization'] = `Bearer ${credentials.accessToken}`; return await this.helpers.request!(options); diff --git a/packages/nodes-base/nodes/MessageBird/GenericFunctions.ts b/packages/nodes-base/nodes/MessageBird/GenericFunctions.ts index 95a9206bb1..9566789759 100644 --- a/packages/nodes-base/nodes/MessageBird/GenericFunctions.ts +++ b/packages/nodes-base/nodes/MessageBird/GenericFunctions.ts @@ -28,9 +28,6 @@ export async function messageBirdApiRequest( query: IDataObject = {}, ): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('messageBirdApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials returned!'); - } const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Microsoft/Outlook/GenericFunctions.ts b/packages/nodes-base/nodes/Microsoft/Outlook/GenericFunctions.ts index 243df33da1..7fa84ef473 100644 --- a/packages/nodes-base/nodes/Microsoft/Outlook/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Microsoft/Outlook/GenericFunctions.ts @@ -19,8 +19,8 @@ export async function microsoftApiRequest(this: IExecuteFunctions | IExecuteSing let apiUrl = `https://graph.microsoft.com/v1.0/me${resource}`; // If accessing shared mailbox - if (credentials!.useShared && credentials!.userPrincipalName) { - apiUrl = `https://graph.microsoft.com/v1.0/users/${credentials!.userPrincipalName}${resource}`; + if (credentials.useShared && credentials.userPrincipalName) { + apiUrl = `https://graph.microsoft.com/v1.0/users/${credentials.userPrincipalName}${resource}`; } const options: OptionsWithUri = { diff --git a/packages/nodes-base/nodes/Microsoft/Sql/MicrosoftSql.node.ts b/packages/nodes-base/nodes/Microsoft/Sql/MicrosoftSql.node.ts index 738e24bc16..b3e27a4983 100644 --- a/packages/nodes-base/nodes/Microsoft/Sql/MicrosoftSql.node.ts +++ b/packages/nodes-base/nodes/Microsoft/Sql/MicrosoftSql.node.ts @@ -215,10 +215,6 @@ export class MicrosoftSql implements INodeType { async execute(this: IExecuteFunctions): Promise { const credentials = await this.getCredentials('microsoftSql'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const config = { server: credentials.server as string, port: credentials.port as number, diff --git a/packages/nodes-base/nodes/Mindee/GenericFunctions.ts b/packages/nodes-base/nodes/Mindee/GenericFunctions.ts index 4d0d01f7d9..3b61635a1d 100644 --- a/packages/nodes-base/nodes/Mindee/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Mindee/GenericFunctions.ts @@ -19,9 +19,9 @@ export async function mindeeApiRequest(this: IExecuteFunctions | IExecuteSingleF let credentials; if (resource === 'receipt') { - credentials = await this.getCredentials('mindeeReceiptApi') as IDataObject; + credentials = await this.getCredentials('mindeeReceiptApi'); } else { - credentials = await this.getCredentials('mindeeInvoiceApi') as IDataObject; + credentials = await this.getCredentials('mindeeInvoiceApi'); } const options: OptionsWithUri = { diff --git a/packages/nodes-base/nodes/Mocean/GenericFunctions.ts b/packages/nodes-base/nodes/Mocean/GenericFunctions.ts index 52849300ae..e0dd2a6d7d 100644 --- a/packages/nodes-base/nodes/Mocean/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Mocean/GenericFunctions.ts @@ -18,9 +18,6 @@ import { */ export async function moceanApiRequest(this: IHookFunctions | IExecuteFunctions, method: string, endpoint: string, body: IDataObject, query?: IDataObject): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('moceanApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } if (query === undefined) { query = {}; diff --git a/packages/nodes-base/nodes/MondayCom/GenericFunctions.ts b/packages/nodes-base/nodes/MondayCom/GenericFunctions.ts index 70caedaf51..1cf694df8d 100644 --- a/packages/nodes-base/nodes/MondayCom/GenericFunctions.ts +++ b/packages/nodes-base/nodes/MondayCom/GenericFunctions.ts @@ -37,7 +37,7 @@ export async function mondayComApiRequest(this: IExecuteFunctions | IWebhookFunc options = Object.assign({}, options, option); try { if (authenticationMethod === 'accessToken') { - const credentials = await this.getCredentials('mondayComApi') as IDataObject; + const credentials = await this.getCredentials('mondayComApi'); options.headers = { Authorization: `Bearer ${credentials.apiToken}` }; diff --git a/packages/nodes-base/nodes/Msg91/GenericFunctions.ts b/packages/nodes-base/nodes/Msg91/GenericFunctions.ts index 3abe1e39e0..4bc6d1fd0b 100644 --- a/packages/nodes-base/nodes/Msg91/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Msg91/GenericFunctions.ts @@ -18,9 +18,6 @@ import { */ export async function msg91ApiRequest(this: IHookFunctions | IExecuteFunctions, method: string, endpoint: string, body: IDataObject, query?: IDataObject): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('msg91Api'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } if (query === undefined) { query = {}; diff --git a/packages/nodes-base/nodes/MySql/MySql.node.ts b/packages/nodes-base/nodes/MySql/MySql.node.ts index 37abc7f63a..e71036ef6d 100644 --- a/packages/nodes-base/nodes/MySql/MySql.node.ts +++ b/packages/nodes-base/nodes/MySql/MySql.node.ts @@ -214,10 +214,6 @@ export class MySql implements INodeType { async execute(this: IExecuteFunctions): Promise { const credentials = await this.getCredentials('mySql'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - // Destructuring SSL configuration const { ssl, diff --git a/packages/nodes-base/nodes/Nasa/GenericFunctions.ts b/packages/nodes-base/nodes/Nasa/GenericFunctions.ts index 8f4e4c0852..8a1b9ef6d6 100644 --- a/packages/nodes-base/nodes/Nasa/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Nasa/GenericFunctions.ts @@ -13,7 +13,7 @@ import { export async function nasaApiRequest(this: IHookFunctions | IExecuteFunctions, method: string, endpoint: string, qs: IDataObject, option: IDataObject = {}, uri?: string | undefined): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('nasaApi') as IDataObject; + const credentials = await this.getCredentials('nasaApi'); qs.api_key = credentials['api_key'] as string; diff --git a/packages/nodes-base/nodes/Netlify/GenericFunctions.ts b/packages/nodes-base/nodes/Netlify/GenericFunctions.ts index 6aefb1fbb9..dfa6bb831e 100644 --- a/packages/nodes-base/nodes/Netlify/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Netlify/GenericFunctions.ts @@ -37,10 +37,6 @@ export async function netlifyApiRequest(this: IHookFunctions | IExecuteFunctions try { const credentials = await this.getCredentials('netlifyApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - options.headers!['Authorization'] = `Bearer ${credentials.accessToken}`; return await this.helpers.request!(options); diff --git a/packages/nodes-base/nodes/NextCloud/GenericFunctions.ts b/packages/nodes-base/nodes/NextCloud/GenericFunctions.ts index 586dc75546..dcf91887a1 100644 --- a/packages/nodes-base/nodes/NextCloud/GenericFunctions.ts +++ b/packages/nodes-base/nodes/NextCloud/GenericFunctions.ts @@ -39,9 +39,6 @@ export async function nextCloudApiRequest(this: IHookFunctions | IExecuteFunctio try { if (authenticationMethod === 'accessToken') { const credentials = await this.getCredentials('nextCloudApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } options.auth = { user: credentials.user as string, @@ -56,9 +53,6 @@ export async function nextCloudApiRequest(this: IHookFunctions | IExecuteFunctio return await this.helpers.request(options); } else { const credentials = await this.getCredentials('nextCloudOAuth2Api'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } options.uri = `${credentials.webDavUrl}/${encodeURI(endpoint)}`; diff --git a/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts b/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts index c916c99213..186695d4f7 100644 --- a/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts +++ b/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts @@ -1014,10 +1014,6 @@ export class NextCloud implements INodeType { credentials = await this.getCredentials('nextCloudOAuth2Api'); } - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const resource = this.getNodeParameter('resource', 0) as string; const operation = this.getNodeParameter('operation', 0) as string; diff --git a/packages/nodes-base/nodes/NocoDB/GenericFunctions.ts b/packages/nodes-base/nodes/NocoDB/GenericFunctions.ts index f1215e2fdd..8000c444e3 100644 --- a/packages/nodes-base/nodes/NocoDB/GenericFunctions.ts +++ b/packages/nodes-base/nodes/NocoDB/GenericFunctions.ts @@ -36,11 +36,6 @@ interface IAttachment { */ export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IPollFunctions, method: string, endpoint: string, body: object, query?: IDataObject, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('nocoDb'); - - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - query = query || {}; const options: OptionsWithUri = { diff --git a/packages/nodes-base/nodes/Notion/GenericFunctions.ts b/packages/nodes-base/nodes/Notion/GenericFunctions.ts index d6a1f568f9..5c8c2a3543 100644 --- a/packages/nodes-base/nodes/Notion/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Notion/GenericFunctions.ts @@ -55,7 +55,7 @@ export async function notionApiRequest(this: IHookFunctions | IExecuteFunctions json: true, }; options = Object.assign({}, options, option); - const credentials = await this.getCredentials('notionApi') as IDataObject; + const credentials = await this.getCredentials('notionApi'); if (!uri) { //do not include the API Key when downloading files, else the request fails options!.headers!['Authorization'] = `Bearer ${credentials.apiKey}`; diff --git a/packages/nodes-base/nodes/Odoo/Odoo.node.ts b/packages/nodes-base/nodes/Odoo/Odoo.node.ts index bc72e3d8c6..6ae832a6d7 100644 --- a/packages/nodes-base/nodes/Odoo/Odoo.node.ts +++ b/packages/nodes-base/nodes/Odoo/Odoo.node.ts @@ -112,10 +112,10 @@ export class Odoo implements INodeType { } const credentials = await this.getCredentials('odooApi'); - const url = credentials?.url as string; - const username = credentials?.username as string; - const password = credentials?.password as string; - const db = odooGetDBName(credentials?.db as string, url); + const url = credentials.url as string; + const username = credentials.username as string; + const password = credentials.password as string; + const db = odooGetDBName(credentials.db as string, url); const userID = await odooGetUserID.call(this, db, username, password, url); const responce = await odooGetModelFields.call(this, db, userID, password, resource, url); @@ -134,10 +134,10 @@ export class Odoo implements INodeType { }, async getModels(this: ILoadOptionsFunctions): Promise { const credentials = await this.getCredentials('odooApi'); - const url = credentials?.url as string; - const username = credentials?.username as string; - const password = credentials?.password as string; - const db = odooGetDBName(credentials?.db as string, url); + const url = credentials.url as string; + const username = credentials.username as string; + const password = credentials.password as string; + const db = odooGetDBName(credentials.db as string, url); const userID = await odooGetUserID.call(this, db, username, password, url); const body = { @@ -172,10 +172,10 @@ export class Odoo implements INodeType { }, async getStates(this: ILoadOptionsFunctions): Promise { const credentials = await this.getCredentials('odooApi'); - const url = credentials?.url as string; - const username = credentials?.username as string; - const password = credentials?.password as string; - const db = odooGetDBName(credentials?.db as string, url); + const url = credentials.url as string; + const username = credentials.username as string; + const password = credentials.password as string; + const db = odooGetDBName(credentials.db as string, url); const userID = await odooGetUserID.call(this, db, username, password, url); const body = { @@ -201,10 +201,10 @@ export class Odoo implements INodeType { }, async getCountries(this: ILoadOptionsFunctions): Promise { const credentials = await this.getCredentials('odooApi'); - const url = credentials?.url as string; - const username = credentials?.username as string; - const password = credentials?.password as string; - const db = odooGetDBName(credentials?.db as string, url); + const url = credentials.url as string; + const username = credentials.username as string; + const password = credentials.password as string; + const db = odooGetDBName(credentials.db as string, url); const userID = await odooGetUserID.call(this, db, username, password, url); const body = { @@ -297,10 +297,10 @@ export class Odoo implements INodeType { const operation = this.getNodeParameter('operation', 0) as string; const credentials = await this.getCredentials('odooApi'); - const url = (credentials?.url as string).replace(/\/$/, ''); - const username = credentials?.username as string; - const password = credentials?.password as string; - const db = odooGetDBName(credentials?.db as string, url); + const url = (credentials.url as string).replace(/\/$/, ''); + const username = credentials.username as string; + const password = credentials.password as string; + const db = odooGetDBName(credentials.db as string, url); const userID = await odooGetUserID.call(this, db, username, password, url); //---------------------------------------------------------------------- diff --git a/packages/nodes-base/nodes/OneSimpleApi/GenericFunctions.ts b/packages/nodes-base/nodes/OneSimpleApi/GenericFunctions.ts index 5e89c03156..e816a28881 100644 --- a/packages/nodes-base/nodes/OneSimpleApi/GenericFunctions.ts +++ b/packages/nodes-base/nodes/OneSimpleApi/GenericFunctions.ts @@ -14,9 +14,6 @@ import { export async function oneSimpleApiRequest(this: IExecuteFunctions, method: string, resource: string, body: IDataObject = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}) { const credentials = await this.getCredentials('oneSimpleApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const outputFormat = 'json'; let options: OptionsWithUri = { diff --git a/packages/nodes-base/nodes/Onfleet/GenericFunctions.ts b/packages/nodes-base/nodes/Onfleet/GenericFunctions.ts index de4ec2fde0..cd9bc02379 100644 --- a/packages/nodes-base/nodes/Onfleet/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Onfleet/GenericFunctions.ts @@ -24,7 +24,7 @@ export async function onfleetApiRequest( qs?: any, // tslint:disable-line:no-any uri?: string): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('onfleetApi') as ICredentialDataDecryptedObject; + const credentials = await this.getCredentials('onfleetApi'); const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/OpenWeatherMap/OpenWeatherMap.node.ts b/packages/nodes-base/nodes/OpenWeatherMap/OpenWeatherMap.node.ts index 5c594fb5e4..3671dc3a60 100644 --- a/packages/nodes-base/nodes/OpenWeatherMap/OpenWeatherMap.node.ts +++ b/packages/nodes-base/nodes/OpenWeatherMap/OpenWeatherMap.node.ts @@ -210,10 +210,6 @@ export class OpenWeatherMap implements INodeType { const credentials = await this.getCredentials('openWeatherMapApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const operation = this.getNodeParameter('operation', 0) as string; let endpoint = ''; diff --git a/packages/nodes-base/nodes/Orbit/GenericFunctions.ts b/packages/nodes-base/nodes/Orbit/GenericFunctions.ts index d98fece239..8e63d753a2 100644 --- a/packages/nodes-base/nodes/Orbit/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Orbit/GenericFunctions.ts @@ -20,9 +20,6 @@ import { export async function orbitApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any try { const credentials = await this.getCredentials('orbitApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } let options: OptionsWithUri = { headers: { Authorization: `Bearer ${credentials.accessToken}`, diff --git a/packages/nodes-base/nodes/Oura/GenericFunctions.ts b/packages/nodes-base/nodes/Oura/GenericFunctions.ts index 18a46a075b..655dd273cc 100644 --- a/packages/nodes-base/nodes/Oura/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Oura/GenericFunctions.ts @@ -26,9 +26,6 @@ export async function ouraApiRequest( ) { const credentials = await this.getCredentials('ouraApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } let options: OptionsWithUri = { headers: { Authorization: `Bearer ${credentials.accessToken}`, diff --git a/packages/nodes-base/nodes/Paddle/GenericFunctions.ts b/packages/nodes-base/nodes/Paddle/GenericFunctions.ts index d24c66c2dc..114ee978cb 100644 --- a/packages/nodes-base/nodes/Paddle/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Paddle/GenericFunctions.ts @@ -19,10 +19,6 @@ export async function paddleApiRequest(this: IHookFunctions | IExecuteFunctions const productionUrl = 'https://vendors.paddle.com/api'; const sandboxUrl = 'https://sandbox-vendors.paddle.com/api'; - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'Could not retrieve credentials!'); - } - const isSandbox = credentials.sandbox; const options: OptionsWithUri = { diff --git a/packages/nodes-base/nodes/PagerDuty/GenericFunctions.ts b/packages/nodes-base/nodes/PagerDuty/GenericFunctions.ts index 23e3bb7238..629c6d83a7 100644 --- a/packages/nodes-base/nodes/PagerDuty/GenericFunctions.ts +++ b/packages/nodes-base/nodes/PagerDuty/GenericFunctions.ts @@ -50,10 +50,6 @@ export async function pagerDutyApiRequest(this: IExecuteFunctions | IWebhookFunc if (authenticationMethod === 'apiToken') { const credentials = await this.getCredentials('pagerDutyApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - options.headers!['Authorization'] = `Token token=${credentials.apiToken}`; return await this.helpers.request!(options); diff --git a/packages/nodes-base/nodes/PayPal/GenericFunctions.ts b/packages/nodes-base/nodes/PayPal/GenericFunctions.ts index 1e8b84b4eb..ce9b7b0e23 100644 --- a/packages/nodes-base/nodes/PayPal/GenericFunctions.ts +++ b/packages/nodes-base/nodes/PayPal/GenericFunctions.ts @@ -16,7 +16,7 @@ import { export async function payPalApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, endpoint: string, method: string, body: any = {}, query?: IDataObject, uri?: string): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('payPalApi'); - const env = getEnvironment(credentials!.env as string); + const env = getEnvironment(credentials.env as string); const tokenInfo = await getAccessToken.call(this); const headerWithAuthentication = Object.assign({ }, { Authorization: `Bearer ${tokenInfo.access_token}`, 'Content-Type': 'application/json' }); @@ -45,9 +45,6 @@ function getEnvironment(env: string): string { async function getAccessToken(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('payPalApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const env = getEnvironment(credentials!.env as string); const data = Buffer.from(`${credentials!.clientId}:${credentials!.secret}`).toString(BINARY_ENCODING); const headerWithAuthentication = Object.assign({}, diff --git a/packages/nodes-base/nodes/Peekalink/GenericFunctions.ts b/packages/nodes-base/nodes/Peekalink/GenericFunctions.ts index c153522377..136568e034 100644 --- a/packages/nodes-base/nodes/Peekalink/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Peekalink/GenericFunctions.ts @@ -16,9 +16,6 @@ import { export async function peekalinkApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any try { const credentials = await this.getCredentials('peekalinkApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } let options: OptionsWithUri = { headers: { 'X-API-Key': credentials.apiKey, diff --git a/packages/nodes-base/nodes/Phantombuster/GenericFunctions.ts b/packages/nodes-base/nodes/Phantombuster/GenericFunctions.ts index c044f85a30..26e186e295 100644 --- a/packages/nodes-base/nodes/Phantombuster/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Phantombuster/GenericFunctions.ts @@ -14,7 +14,7 @@ import { export async function phantombusterApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, path: string, body: any = {}, qs: IDataObject = {}, option = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('phantombusterApi') as IDataObject; + const credentials = await this.getCredentials('phantombusterApi'); const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Pipedrive/PipedriveTrigger.node.ts b/packages/nodes-base/nodes/Pipedrive/PipedriveTrigger.node.ts index 7a2eb0bad7..a43ebfbe8f 100644 --- a/packages/nodes-base/nodes/Pipedrive/PipedriveTrigger.node.ts +++ b/packages/nodes-base/nodes/Pipedrive/PipedriveTrigger.node.ts @@ -4,6 +4,7 @@ import { } from 'n8n-core'; import { + ICredentialDataDecryptedObject, INodeType, INodeTypeDescription, IWebhookResponseData, @@ -267,7 +268,13 @@ export class PipedriveTrigger implements INodeType { }; if (incomingAuthentication === 'basicAuth') { - const httpBasicAuth = await this.getCredentials('httpBasicAuth'); + let httpBasicAuth; + + try { + httpBasicAuth = await this.getCredentials('httpBasicAuth'); + } catch (error) { + // Do nothing + } if (httpBasicAuth === undefined || !httpBasicAuth.user || !httpBasicAuth.password) { // Data is not defined on node so can not authenticate @@ -323,7 +330,13 @@ export class PipedriveTrigger implements INodeType { if (incomingAuthentication === 'basicAuth') { // Basic authorization is needed to call webhook - const httpBasicAuth = await this.getCredentials('httpBasicAuth'); + let httpBasicAuth: ICredentialDataDecryptedObject | undefined; + + try { + httpBasicAuth = await this.getCredentials('httpBasicAuth'); + } catch (error) { + // Do nothing + } if (httpBasicAuth === undefined || !httpBasicAuth.user || !httpBasicAuth.password) { // Data is not defined on node so can not authenticate diff --git a/packages/nodes-base/nodes/Plivo/GenericFunctions.ts b/packages/nodes-base/nodes/Plivo/GenericFunctions.ts index f33f7deaeb..00433769a5 100644 --- a/packages/nodes-base/nodes/Plivo/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Plivo/GenericFunctions.ts @@ -32,10 +32,6 @@ export async function plivoApiRequest( const credentials = await this.getCredentials('plivoApi') as { authId: string, authToken: string }; - if (!credentials) { - throw new NodeOperationError(this.getNode(), 'No credentials returned!'); - } - const options: OptionsWithUri = { headers: { 'user-agent': 'plivo-n8n', diff --git a/packages/nodes-base/nodes/PostHog/GenericFunctions.ts b/packages/nodes-base/nodes/PostHog/GenericFunctions.ts index 11a03c992f..352c4fc0c2 100644 --- a/packages/nodes-base/nodes/PostHog/GenericFunctions.ts +++ b/packages/nodes-base/nodes/PostHog/GenericFunctions.ts @@ -13,7 +13,7 @@ import { export async function posthogApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions, method: string, path: string, body: any = {}, qs: IDataObject = {}, option = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('postHogApi') as IDataObject; + const credentials = await this.getCredentials('postHogApi'); const base = credentials.url as string; diff --git a/packages/nodes-base/nodes/Postgres/Postgres.node.ts b/packages/nodes-base/nodes/Postgres/Postgres.node.ts index e10d354382..982c27bb07 100644 --- a/packages/nodes-base/nodes/Postgres/Postgres.node.ts +++ b/packages/nodes-base/nodes/Postgres/Postgres.node.ts @@ -250,10 +250,6 @@ export class Postgres implements INodeType { async execute(this: IExecuteFunctions): Promise { const credentials = await this.getCredentials('postgres'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const pgp = pgPromise(); const config: IDataObject = { diff --git a/packages/nodes-base/nodes/Postmark/GenericFunctions.ts b/packages/nodes-base/nodes/Postmark/GenericFunctions.ts index cf37eb28e1..8d68a891d1 100644 --- a/packages/nodes-base/nodes/Postmark/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Postmark/GenericFunctions.ts @@ -19,10 +19,6 @@ import { export async function postmarkApiRequest(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, method : string, endpoint : string, body: any = {}, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('postmarkApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - let options: OptionsWithUri = { headers: { 'Content-Type': 'application/json', diff --git a/packages/nodes-base/nodes/ProfitWell/GenericFunctions.ts b/packages/nodes-base/nodes/ProfitWell/GenericFunctions.ts index b286963ecc..ce21b545ba 100644 --- a/packages/nodes-base/nodes/ProfitWell/GenericFunctions.ts +++ b/packages/nodes-base/nodes/ProfitWell/GenericFunctions.ts @@ -16,9 +16,6 @@ import { export async function profitWellApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any try { const credentials = await this.getCredentials('profitWellApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } let options: OptionsWithUri = { headers: { 'Authorization': credentials.accessToken, diff --git a/packages/nodes-base/nodes/Pushcut/GenericFunctions.ts b/packages/nodes-base/nodes/Pushcut/GenericFunctions.ts index 9c53ca6296..ee2c2937c0 100644 --- a/packages/nodes-base/nodes/Pushcut/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Pushcut/GenericFunctions.ts @@ -15,7 +15,7 @@ import { export async function pushcutApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions, method: string, path: string, body: any = {}, qs: IDataObject = {}, uri?: string | undefined, option = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('pushcutApi') as IDataObject; + const credentials = await this.getCredentials('pushcutApi'); const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Pushover/GenericFunctions.ts b/packages/nodes-base/nodes/Pushover/GenericFunctions.ts index a840ac9f1c..5b08c58397 100644 --- a/packages/nodes-base/nodes/Pushover/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Pushover/GenericFunctions.ts @@ -14,7 +14,7 @@ import { export async function pushoverApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, path: string, body: any = {}, qs: IDataObject = {}, option = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('pushoverApi') as IDataObject; + const credentials = await this.getCredentials('pushoverApi'); if (method === 'GET') { qs.token = credentials.apiKey; diff --git a/packages/nodes-base/nodes/QuestDb/QuestDb.node.ts b/packages/nodes-base/nodes/QuestDb/QuestDb.node.ts index e625d2e9a0..6c11d33728 100644 --- a/packages/nodes-base/nodes/QuestDb/QuestDb.node.ts +++ b/packages/nodes-base/nodes/QuestDb/QuestDb.node.ts @@ -207,10 +207,6 @@ export class QuestDb implements INodeType { async execute(this: IExecuteFunctions): Promise { const credentials = await this.getCredentials('questDb'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const pgp = pgPromise(); const config = { diff --git a/packages/nodes-base/nodes/QuickBase/GenericFunctions.ts b/packages/nodes-base/nodes/QuickBase/GenericFunctions.ts index ec93b066b7..f8b6abdf39 100644 --- a/packages/nodes-base/nodes/QuickBase/GenericFunctions.ts +++ b/packages/nodes-base/nodes/QuickBase/GenericFunctions.ts @@ -15,11 +15,7 @@ import { export async function quickbaseApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('quickbaseApi') as IDataObject; - - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } + const credentials = await this.getCredentials('quickbaseApi'); if (!credentials.hostname) { throw new NodeOperationError(this.getNode(), 'Hostname must be defined'); diff --git a/packages/nodes-base/nodes/RabbitMQ/GenericFunctions.ts b/packages/nodes-base/nodes/RabbitMQ/GenericFunctions.ts index 22700746b7..6257f367fe 100644 --- a/packages/nodes-base/nodes/RabbitMQ/GenericFunctions.ts +++ b/packages/nodes-base/nodes/RabbitMQ/GenericFunctions.ts @@ -7,7 +7,7 @@ import { const amqplib = require('amqplib'); export async function rabbitmqConnect(this: IExecuteFunctions | ITriggerFunctions, options: IDataObject): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('rabbitmq') as IDataObject; + const credentials = await this.getCredentials('rabbitmq'); const credentialKeys = [ 'hostname', diff --git a/packages/nodes-base/nodes/Redis/Redis.node.ts b/packages/nodes-base/nodes/Redis/Redis.node.ts index 4978f90b96..ba6f259398 100644 --- a/packages/nodes-base/nodes/Redis/Redis.node.ts +++ b/packages/nodes-base/nodes/Redis/Redis.node.ts @@ -525,10 +525,6 @@ export class Redis implements INodeType { // Should maybe have a parameter which is JSON. const credentials = await this.getCredentials('redis'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const redisOptions: redis.ClientOpts = { host: credentials.host as string, port: credentials.port as number, diff --git a/packages/nodes-base/nodes/Redis/RedisTrigger.node.ts b/packages/nodes-base/nodes/Redis/RedisTrigger.node.ts index c6105b3b8f..037b399432 100644 --- a/packages/nodes-base/nodes/Redis/RedisTrigger.node.ts +++ b/packages/nodes-base/nodes/Redis/RedisTrigger.node.ts @@ -70,10 +70,6 @@ export class RedisTrigger implements INodeType { const credentials = await this.getCredentials('redis'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const redisOptions: redis.ClientOpts = { host: credentials.host as string, port: credentials.port as number, diff --git a/packages/nodes-base/nodes/Rocketchat/GenericFunctions.ts b/packages/nodes-base/nodes/Rocketchat/GenericFunctions.ts index 3453675579..671084a848 100644 --- a/packages/nodes-base/nodes/Rocketchat/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Rocketchat/GenericFunctions.ts @@ -12,10 +12,6 @@ import { NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function rocketchatApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions, resource: string, method: string, operation: string, body: any = {}, headers?: object): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('rocketchatApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const headerWithAuthentication = Object.assign({}, headers, { 'X-Auth-Token': credentials.authKey, diff --git a/packages/nodes-base/nodes/S3/GenericFunctions.ts b/packages/nodes-base/nodes/S3/GenericFunctions.ts index bfdafe0583..e59fdea25b 100644 --- a/packages/nodes-base/nodes/S3/GenericFunctions.ts +++ b/packages/nodes-base/nodes/S3/GenericFunctions.ts @@ -34,10 +34,6 @@ export async function s3ApiRequest(this: IHookFunctions | IExecuteFunctions | IL credentials = await this.getCredentials('s3'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - if (!(credentials.endpoint as string).startsWith('http')) { throw new NodeOperationError(this.getNode(), 'HTTP(S) Scheme is required in endpoint definition'); } diff --git a/packages/nodes-base/nodes/Salesforce/GenericFunctions.ts b/packages/nodes-base/nodes/Salesforce/GenericFunctions.ts index 911fb377a5..a01355e336 100644 --- a/packages/nodes-base/nodes/Salesforce/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Salesforce/GenericFunctions.ts @@ -29,7 +29,7 @@ export async function salesforceApiRequest(this: IExecuteFunctions | IExecuteSin // https://help.salesforce.com/articleView?id=remoteaccess_oauth_jwt_flow.htm&type=5 const credentialsType = 'salesforceJwtApi'; const credentials = await this.getCredentials(credentialsType); - const response = await getAccessToken.call(this, credentials as IDataObject); + const response = await getAccessToken.call(this, credentials); const { instance_url, access_token } = response; const options = getOptions.call(this, method, (uri || endpoint), body, qs, instance_url as string); Logger.debug(`Authentication for "Salesforce" node is using "jwt". Invoking URI ${options.uri}`); diff --git a/packages/nodes-base/nodes/Salesmate/GenericFunctions.ts b/packages/nodes-base/nodes/Salesmate/GenericFunctions.ts index 9a419e3b82..359390211c 100644 --- a/packages/nodes-base/nodes/Salesmate/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Salesmate/GenericFunctions.ts @@ -10,9 +10,6 @@ import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function salesmateApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('salesmateApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/SeaTable/SeaTableTrigger.node.ts b/packages/nodes-base/nodes/SeaTable/SeaTableTrigger.node.ts index 1b8d7c8491..b5209a8e1b 100644 --- a/packages/nodes-base/nodes/SeaTable/SeaTableTrigger.node.ts +++ b/packages/nodes-base/nodes/SeaTable/SeaTableTrigger.node.ts @@ -109,7 +109,7 @@ export class SeaTableTrigger implements INodeType { const simple = this.getNodeParameter('simple') as boolean; const event = this.getNodeParameter('event') as string; const ctx: ICtx = {}; - const credentials = await this.getCredentials('seaTableApi') as IDataObject; + const credentials = await this.getCredentials('seaTableApi'); const timezone = credentials.timezone as string || 'Europe/Berlin'; const now = moment().utc().format(); diff --git a/packages/nodes-base/nodes/SecurityScorecard/GenericFunctions.ts b/packages/nodes-base/nodes/SecurityScorecard/GenericFunctions.ts index 319d774b99..74e1471aed 100644 --- a/packages/nodes-base/nodes/SecurityScorecard/GenericFunctions.ts +++ b/packages/nodes-base/nodes/SecurityScorecard/GenericFunctions.ts @@ -15,10 +15,6 @@ import { export async function scorecardApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, query: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('securityScorecardApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const headerWithAuthentication = { Authorization: `Token ${credentials.apiKey}` }; let options: OptionsWithUri = { diff --git a/packages/nodes-base/nodes/Segment/GenericFunctions.ts b/packages/nodes-base/nodes/Segment/GenericFunctions.ts index e692e1d4a2..645175728d 100644 --- a/packages/nodes-base/nodes/Segment/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Segment/GenericFunctions.ts @@ -10,9 +10,6 @@ import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function segmentApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('segmentApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const base64Key = Buffer.from(`${credentials.writekey}:`).toString('base64'); const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/SendGrid/GenericFunctions.ts b/packages/nodes-base/nodes/SendGrid/GenericFunctions.ts index 4615f95b50..4787312b6b 100644 --- a/packages/nodes-base/nodes/SendGrid/GenericFunctions.ts +++ b/packages/nodes-base/nodes/SendGrid/GenericFunctions.ts @@ -14,7 +14,7 @@ import { } from 'n8n-workflow'; export async function sendGridApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, endpoint: string, method: string, body: any = {}, qs: IDataObject = {}, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('sendGridApi') as IDataObject; + const credentials = await this.getCredentials('sendGridApi'); const host = 'api.sendgrid.com/v3'; diff --git a/packages/nodes-base/nodes/Sendy/GenericFunctions.ts b/packages/nodes-base/nodes/Sendy/GenericFunctions.ts index 0c58e3d59e..1d70932fef 100644 --- a/packages/nodes-base/nodes/Sendy/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Sendy/GenericFunctions.ts @@ -13,7 +13,7 @@ import { export async function sendyApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions, method: string, path: string, body: any = {}, qs: IDataObject = {}, option = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('sendyApi') as IDataObject; + const credentials = await this.getCredentials('sendyApi'); body.api_key = credentials.apiKey; diff --git a/packages/nodes-base/nodes/SentryIo/GenericFunctions.ts b/packages/nodes-base/nodes/SentryIo/GenericFunctions.ts index 667593e70e..ae9b2243ae 100644 --- a/packages/nodes-base/nodes/SentryIo/GenericFunctions.ts +++ b/packages/nodes-base/nodes/SentryIo/GenericFunctions.ts @@ -52,7 +52,7 @@ export async function sentryIoApiRequest(this: IHookFunctions | IExecuteFunction const credentials = await this.getCredentials(credentialName); - if (credentials?.url) { + if (credentials.url) { options.uri = `${credentials?.url}${resource}`; } diff --git a/packages/nodes-base/nodes/ServiceNow/GenericFunctions.ts b/packages/nodes-base/nodes/ServiceNow/GenericFunctions.ts index 5d121933f0..074d8e7e0d 100644 --- a/packages/nodes-base/nodes/ServiceNow/GenericFunctions.ts +++ b/packages/nodes-base/nodes/ServiceNow/GenericFunctions.ts @@ -32,7 +32,7 @@ export async function serviceNowApiRequest(this: IExecuteFunctions | ILoadOption method, qs, body, - uri: uri || `https://${credentials?.subdomain}.service-now.com/api${resource}`, + uri: uri || `https://${credentials.subdomain}.service-now.com/api${resource}`, json: true, }; if (!Object.keys(body).length) { diff --git a/packages/nodes-base/nodes/Shopify/GenericFunctions.ts b/packages/nodes-base/nodes/Shopify/GenericFunctions.ts index ca728e4213..4648a9e9c9 100644 --- a/packages/nodes-base/nodes/Shopify/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Shopify/GenericFunctions.ts @@ -20,9 +20,6 @@ import { export async function shopifyApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, query: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('shopifyApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const headerWithAuthentication = Object.assign({}, { Authorization: `Basic ${Buffer.from(`${credentials.apiKey}:${credentials.password}`).toString(BINARY_ENCODING)}` }); diff --git a/packages/nodes-base/nodes/Shopify/ShopifyTrigger.node.ts b/packages/nodes-base/nodes/Shopify/ShopifyTrigger.node.ts index d88626118d..a990d435a2 100644 --- a/packages/nodes-base/nodes/Shopify/ShopifyTrigger.node.ts +++ b/packages/nodes-base/nodes/Shopify/ShopifyTrigger.node.ts @@ -357,7 +357,7 @@ export class ShopifyTrigger implements INodeType { async webhook(this: IWebhookFunctions): Promise { const headerData = this.getHeaderData() as IDataObject; const req = this.getRequestObject(); - const credentials = await this.getCredentials('shopifyApi') as IDataObject; + const credentials = await this.getCredentials('shopifyApi'); const topic = this.getNodeParameter('topic') as string; if (headerData['x-shopify-topic'] !== undefined && headerData['x-shopify-hmac-sha256'] !== undefined diff --git a/packages/nodes-base/nodes/Slack/GenericFunctions.ts b/packages/nodes-base/nodes/Slack/GenericFunctions.ts index c8b9e0f5c6..6e6bdf799a 100644 --- a/packages/nodes-base/nodes/Slack/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Slack/GenericFunctions.ts @@ -41,9 +41,6 @@ export async function slackApiRequest(this: IExecuteFunctions | IExecuteSingleFu if (authenticationMethod === 'accessToken') { const credentials = await this.getCredentials('slackApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } options.headers!.Authorization = `Bearer ${credentials.accessToken}`; //@ts-ignore response = await this.helpers.request(options); diff --git a/packages/nodes-base/nodes/Sms77/GenericFunctions.ts b/packages/nodes-base/nodes/Sms77/GenericFunctions.ts index 000b8f6805..3b7b4e7b06 100644 --- a/packages/nodes-base/nodes/Sms77/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Sms77/GenericFunctions.ts @@ -24,9 +24,6 @@ import { */ export async function sms77ApiRequest(this: IHookFunctions | IExecuteFunctions, method: string, endpoint: string, body: IDataObject, qs: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('sms77Api'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Spontit/GenericFunctions.ts b/packages/nodes-base/nodes/Spontit/GenericFunctions.ts index 9697c79544..2469ae7de8 100644 --- a/packages/nodes-base/nodes/Spontit/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Spontit/GenericFunctions.ts @@ -15,7 +15,7 @@ import { export async function spontitApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('spontitApi') as IDataObject; + const credentials = await this.getCredentials('spontitApi'); try { const options: OptionsWithUri = { diff --git a/packages/nodes-base/nodes/Ssh/Ssh.node.ts b/packages/nodes-base/nodes/Ssh/Ssh.node.ts index 7e10f96d62..7a238c275e 100644 --- a/packages/nodes-base/nodes/Ssh/Ssh.node.ts +++ b/packages/nodes-base/nodes/Ssh/Ssh.node.ts @@ -293,7 +293,7 @@ export class Ssh implements INodeType { try { if (authentication === 'password') { - const credentials = await this.getCredentials('sshPassword') as IDataObject; + const credentials = await this.getCredentials('sshPassword'); await ssh.connect({ host: credentials.host as string, @@ -304,7 +304,7 @@ export class Ssh implements INodeType { } else if (authentication === 'privateKey') { - const credentials = await this.getCredentials('sshPrivateKey') as IDataObject; + const credentials = await this.getCredentials('sshPrivateKey'); const { path, } = await file({ prefix: 'n8n-ssh-' }); temporaryFiles.push(path); diff --git a/packages/nodes-base/nodes/Stackby/GenericFunction.ts b/packages/nodes-base/nodes/Stackby/GenericFunction.ts index 53ffaca132..10611d6b2b 100644 --- a/packages/nodes-base/nodes/Stackby/GenericFunction.ts +++ b/packages/nodes-base/nodes/Stackby/GenericFunction.ts @@ -24,7 +24,7 @@ import { * @returns {Promise} */ export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IPollFunctions, method: string, endpoint: string, body: IDataObject, query?: IDataObject, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('stackbyApi') as IDataObject; + const credentials = await this.getCredentials('stackbyApi'); const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Storyblok/GenericFunctions.ts b/packages/nodes-base/nodes/Storyblok/GenericFunctions.ts index 74c4946495..ed3ff7ff63 100644 --- a/packages/nodes-base/nodes/Storyblok/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Storyblok/GenericFunctions.ts @@ -34,13 +34,13 @@ export async function storyblokApiRequest(this: IHookFunctions | IExecuteFunctio } if (authenticationMethod === 'contentApi') { - const credentials = await this.getCredentials('storyblokContentApi') as IDataObject; + const credentials = await this.getCredentials('storyblokContentApi'); options.uri = `https://api.storyblok.com${resource}`; Object.assign(options.qs, { token: credentials.apiKey }); } else { - const credentials = await this.getCredentials('storyblokManagementApi') as IDataObject; + const credentials = await this.getCredentials('storyblokManagementApi'); options.uri = `https://mapi.storyblok.com${resource}`; diff --git a/packages/nodes-base/nodes/Strapi/GenericFunctions.ts b/packages/nodes-base/nodes/Strapi/GenericFunctions.ts index e64f012d9a..e52e46f6c0 100644 --- a/packages/nodes-base/nodes/Strapi/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Strapi/GenericFunctions.ts @@ -15,7 +15,7 @@ import { export async function strapiApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, headers: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('strapiApi') as IDataObject; + const credentials = await this.getCredentials('strapiApi'); try { const options: OptionsWithUri = { @@ -44,7 +44,7 @@ export async function strapiApiRequest(this: IExecuteFunctions | ILoadOptionsFun } export async function getToken(this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions | IWebhookFunctions): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('strapiApi') as IDataObject; + const credentials = await this.getCredentials('strapiApi'); let options = {} as OptionsWithUri; options = { headers: { @@ -64,7 +64,7 @@ export async function getToken(this: IExecuteFunctions | ILoadOptionsFunctions | export async function strapiApiRequestAllItems(this: IHookFunctions | ILoadOptionsFunctions | IExecuteFunctions, method: string, resource: string, body: any = {}, query: IDataObject = {}, headers: IDataObject = {}): Promise { // tslint:disable-line:no-any const returnData: IDataObject[] = []; - const {apiVersion} = await this.getCredentials('strapiApi') as IDataObject; + const {apiVersion} = await this.getCredentials('strapiApi'); let responseData; if (apiVersion === 'v4') { diff --git a/packages/nodes-base/nodes/Strapi/Strapi.node.ts b/packages/nodes-base/nodes/Strapi/Strapi.node.ts index 019278cdff..9400e6a6d9 100644 --- a/packages/nodes-base/nodes/Strapi/Strapi.node.ts +++ b/packages/nodes-base/nodes/Strapi/Strapi.node.ts @@ -114,7 +114,7 @@ export class Strapi implements INodeType { const resource = this.getNodeParameter('resource', 0) as string; const operation = this.getNodeParameter('operation', 0) as string; - const { apiVersion } = await this.getCredentials('strapiApi') as IDataObject; + const { apiVersion } = await this.getCredentials('strapiApi'); const { jwt } = await getToken.call(this); headers.Authorization = `Bearer ${jwt}`; diff --git a/packages/nodes-base/nodes/Strava/GenericFunctions.ts b/packages/nodes-base/nodes/Strava/GenericFunctions.ts index 531fbcf4da..4915d0c877 100644 --- a/packages/nodes-base/nodes/Strava/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Strava/GenericFunctions.ts @@ -32,7 +32,7 @@ export async function stravaApiRequest(this: IExecuteFunctions | IExecuteSingleF } if (this.getNode().type.includes('Trigger') && resource.includes('/push_subscriptions')) { - const credentials = await this.getCredentials('stravaOAuth2Api') as IDataObject; + const credentials = await this.getCredentials('stravaOAuth2Api'); if (method === 'GET') { qs.client_id = credentials.clientId; qs.client_secret = credentials.clientSecret; diff --git a/packages/nodes-base/nodes/Stripe/helpers.ts b/packages/nodes-base/nodes/Stripe/helpers.ts index 38823eb12b..581e3916c6 100644 --- a/packages/nodes-base/nodes/Stripe/helpers.ts +++ b/packages/nodes-base/nodes/Stripe/helpers.ts @@ -37,9 +37,6 @@ export async function stripeApiRequest( query?: object, ) { const credentials = await this.getCredentials('stripeApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const options = { method, diff --git a/packages/nodes-base/nodes/SurveyMonkey/GenericFunctions.ts b/packages/nodes-base/nodes/SurveyMonkey/GenericFunctions.ts index 292fc3c74b..85134811db 100644 --- a/packages/nodes-base/nodes/SurveyMonkey/GenericFunctions.ts +++ b/packages/nodes-base/nodes/SurveyMonkey/GenericFunctions.ts @@ -42,10 +42,6 @@ export async function surveyMonkeyApiRequest(this: IExecuteFunctions | IWebhookF try { if ( authenticationMethod === 'accessToken') { const credentials = await this.getCredentials('surveyMonkeyApi'); - - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } // @ts-ignore options.headers['Authorization'] = `bearer ${credentials.accessToken}`; diff --git a/packages/nodes-base/nodes/SurveyMonkey/SurveyMonkeyTrigger.node.ts b/packages/nodes-base/nodes/SurveyMonkey/SurveyMonkeyTrigger.node.ts index 8a274ea2b2..812b47f807 100644 --- a/packages/nodes-base/nodes/SurveyMonkey/SurveyMonkeyTrigger.node.ts +++ b/packages/nodes-base/nodes/SurveyMonkey/SurveyMonkeyTrigger.node.ts @@ -496,9 +496,9 @@ export class SurveyMonkeyTrigger implements INodeType { const webhookName = this.getWebhookName(); if (authenticationMethod === 'accessToken') { - credentials = await this.getCredentials('surveyMonkeyApi') as IDataObject; + credentials = await this.getCredentials('surveyMonkeyApi'); } else { - credentials = await this.getCredentials('surveyMonkeyOAuth2Api') as IDataObject; + credentials = await this.getCredentials('surveyMonkeyOAuth2Api'); } if (webhookName === 'setup') { diff --git a/packages/nodes-base/nodes/SyncroMSP/v1/transport/index.ts b/packages/nodes-base/nodes/SyncroMSP/v1/transport/index.ts index 228f5033a7..890e56ec54 100644 --- a/packages/nodes-base/nodes/SyncroMSP/v1/transport/index.ts +++ b/packages/nodes-base/nodes/SyncroMSP/v1/transport/index.ts @@ -26,10 +26,6 @@ export async function apiRequest( ) { const credentials = await this.getCredentials('syncroMspApi'); - if (!credentials) { - throw new NodeOperationError(this.getNode(), 'No credentials returned!'); - } - query['api_key'] = credentials.apiKey; const options: IHttpRequestOptions = { diff --git a/packages/nodes-base/nodes/Taiga/GenericFunctions.ts b/packages/nodes-base/nodes/Taiga/GenericFunctions.ts index 9bf79988f7..0b9996e198 100644 --- a/packages/nodes-base/nodes/Taiga/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Taiga/GenericFunctions.ts @@ -60,7 +60,7 @@ export async function taigaApiRequest( uri?: string | undefined, option = {}, ): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('taigaApi') as ICredentialDataDecryptedObject; + const credentials = await this.getCredentials('taigaApi'); const authToken = await getAuthorization.call(this, credentials); diff --git a/packages/nodes-base/nodes/Taiga/TaigaTrigger.node.ts b/packages/nodes-base/nodes/Taiga/TaigaTrigger.node.ts index 6abf04e551..107fc948b3 100644 --- a/packages/nodes-base/nodes/Taiga/TaigaTrigger.node.ts +++ b/packages/nodes-base/nodes/Taiga/TaigaTrigger.node.ts @@ -175,7 +175,7 @@ export class TaigaTrigger implements INodeType { return false; }, async create(this: IHookFunctions): Promise { - const credentials = await this.getCredentials('taigaApi') as ICredentialDataDecryptedObject; + const credentials = await this.getCredentials('taigaApi'); const webhookUrl = this.getNodeWebhookUrl('default') as string; diff --git a/packages/nodes-base/nodes/Tapfiliate/GenericFunctions.ts b/packages/nodes-base/nodes/Tapfiliate/GenericFunctions.ts index 7114b3052c..686ec4de20 100644 --- a/packages/nodes-base/nodes/Tapfiliate/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Tapfiliate/GenericFunctions.ts @@ -14,7 +14,7 @@ import { } from 'n8n-workflow'; export async function tapfiliateApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: any = {}, qs: IDataObject = {}, uri?: string | undefined, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('tapfiliateApi') as IDataObject; + const credentials = await this.getCredentials('tapfiliateApi'); const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Telegram/GenericFunctions.ts b/packages/nodes-base/nodes/Telegram/GenericFunctions.ts index 08f88c0c43..363bcc0048 100644 --- a/packages/nodes-base/nodes/Telegram/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Telegram/GenericFunctions.ts @@ -147,10 +147,6 @@ export function addAdditionalFields(this: IExecuteFunctions, body: IDataObject, export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, method: string, endpoint: string, body: IDataObject, query?: IDataObject, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('telegramApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - query = query || {}; const options: OptionsWithUri = { diff --git a/packages/nodes-base/nodes/Telegram/Telegram.node.ts b/packages/nodes-base/nodes/Telegram/Telegram.node.ts index 4eec2fa0da..5904dff36c 100644 --- a/packages/nodes-base/nodes/Telegram/Telegram.node.ts +++ b/packages/nodes-base/nodes/Telegram/Telegram.node.ts @@ -2194,10 +2194,6 @@ export class Telegram implements INodeType { const filePath = responseData.result.file_path; const credentials = await this.getCredentials('telegramApi'); - - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const file = await apiRequest.call(this, 'GET', '', {}, {}, { json: false, encoding: null, uri: `https://api.telegram.org/file/bot${credentials.accessToken}/${filePath}`, resolveWithFullResponse: true }); const fileName = filePath.split('/').pop(); diff --git a/packages/nodes-base/nodes/Telegram/TelegramTrigger.node.ts b/packages/nodes-base/nodes/Telegram/TelegramTrigger.node.ts index 2234a81dfc..b45426e02f 100644 --- a/packages/nodes-base/nodes/Telegram/TelegramTrigger.node.ts +++ b/packages/nodes-base/nodes/Telegram/TelegramTrigger.node.ts @@ -211,7 +211,7 @@ export class TelegramTrigger implements INodeType { async webhook(this: IWebhookFunctions): Promise { - const credentials = await this.getCredentials('telegramApi') as IDataObject; + const credentials = await this.getCredentials('telegramApi'); const bodyData = this.getBodyData() as IEvent; diff --git a/packages/nodes-base/nodes/TheHive/GenericFunctions.ts b/packages/nodes-base/nodes/TheHive/GenericFunctions.ts index b9ed363f12..a6ee58cec6 100644 --- a/packages/nodes-base/nodes/TheHive/GenericFunctions.ts +++ b/packages/nodes-base/nodes/TheHive/GenericFunctions.ts @@ -18,10 +18,6 @@ import { Eq } from './QueryFunctions'; export async function theHiveApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, query: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('theHiveApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const headerWithAuthentication = Object.assign({}, { Authorization: `Bearer ${credentials.ApiKey}` }); let options: OptionsWithUri = { @@ -113,9 +109,6 @@ export async function prepareCustomFields(this: IHookFunctions | IExecuteFunctio } else if (additionalFields.customFieldsUi) { // Get Custom Field Types from TheHive const credentials = await this.getCredentials('theHiveApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'Credentials could not be obtained'); - } const version = credentials.apiVersion; const endpoint = version === 'v1' ? '/customField' : '/list/custom_fields'; diff --git a/packages/nodes-base/nodes/TheHive/TheHive.node.ts b/packages/nodes-base/nodes/TheHive/TheHive.node.ts index ac6a7d1f20..526ca7f0d3 100644 --- a/packages/nodes-base/nodes/TheHive/TheHive.node.ts +++ b/packages/nodes-base/nodes/TheHive/TheHive.node.ts @@ -182,9 +182,6 @@ export class TheHive implements INodeType { }, async loadCustomFields(this: ILoadOptionsFunctions): Promise { const credentials = await this.getCredentials('theHiveApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'Credentials could not be obtained'); - } const version = credentials.apiVersion; const endpoint = version === 'v1' ? '/customField' : '/list/custom_fields'; @@ -211,7 +208,7 @@ export class TheHive implements INodeType { }, async loadObservableOptions(this: ILoadOptionsFunctions): Promise { // if v1 is not used we remove 'count' option - const version = (await this.getCredentials('theHiveApi'))?.apiVersion; + const version = (await this.getCredentials('theHiveApi')).apiVersion; const options = [ ...(version === 'v1') ? [{ name: 'Count', value: 'count', description: 'Count observables' }] : [], @@ -226,7 +223,7 @@ export class TheHive implements INodeType { return options; }, async loadObservableTypes(this: ILoadOptionsFunctions): Promise { - const version = (await this.getCredentials('theHiveApi'))?.apiVersion; + const version = (await this.getCredentials('theHiveApi')).apiVersion; const endpoint = version === 'v1' ? '/observable/type?range=all' : '/list/list_artifactDataType'; const dataTypes = await theHiveApiRequest.call( @@ -271,9 +268,6 @@ export class TheHive implements INodeType { }, async loadTaskOptions(this: ILoadOptionsFunctions): Promise { const credentials = await this.getCredentials('theHiveApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'Credentials could not be obtained'); - } const version = credentials.apiVersion; const options = [ ...(version === 'v1') ? [{ name: 'Count', value: 'count', description: 'Count tasks' }] : [], @@ -288,9 +282,6 @@ export class TheHive implements INodeType { }, async loadAlertOptions(this: ILoadOptionsFunctions): Promise { const credentials = await this.getCredentials('theHiveApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'Credentials could not be obtained'); - } const version = credentials.apiVersion; const options = [ ...(version === 'v1') ? [{ name: 'Count', value: 'count', description: 'Count alerts' }] : [], @@ -308,9 +299,6 @@ export class TheHive implements INodeType { }, async loadCaseOptions(this: ILoadOptionsFunctions): Promise { const credentials = await this.getCredentials('theHiveApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'Credentials could not be obtained'); - } const version = credentials.apiVersion; const options = [ ...(version === 'v1') ? [{ name: 'Count', value: 'count', description: 'Count a case' }] : [], @@ -544,7 +532,7 @@ export class TheHive implements INodeType { ); } if (operation === 'getAll') { - const credentials = await this.getCredentials('theHiveApi') as IDataObject; + const credentials = await this.getCredentials('theHiveApi'); const returnAll = this.getNodeParameter('returnAll', i) as boolean; @@ -975,7 +963,7 @@ export class TheHive implements INodeType { if (operation === 'get') { const observableId = this.getNodeParameter('id', i) as string; - const credentials = await this.getCredentials('theHiveApi') as IDataObject; + const credentials = await this.getCredentials('theHiveApi'); const version = credentials.apiVersion; @@ -1020,7 +1008,7 @@ export class TheHive implements INodeType { } if (operation === 'getAll') { - const credentials = await this.getCredentials('theHiveApi') as IDataObject; + const credentials = await this.getCredentials('theHiveApi'); const returnAll = this.getNodeParameter('returnAll', i) as boolean; @@ -1093,7 +1081,7 @@ export class TheHive implements INodeType { } if (operation === 'search') { - const credentials = await this.getCredentials('theHiveApi') as IDataObject; + const credentials = await this.getCredentials('theHiveApi'); const returnAll = this.getNodeParameter('returnAll', i) as boolean; @@ -1357,7 +1345,7 @@ export class TheHive implements INodeType { if (operation === 'get') { const caseId = this.getNodeParameter('id', i) as string; - const credentials = await this.getCredentials('theHiveApi') as IDataObject; + const credentials = await this.getCredentials('theHiveApi'); const version = credentials.apiVersion; @@ -1402,7 +1390,7 @@ export class TheHive implements INodeType { } if (operation === 'getAll') { - const credentials = await this.getCredentials('theHiveApi') as IDataObject; + const credentials = await this.getCredentials('theHiveApi'); const returnAll = this.getNodeParameter('returnAll', i) as boolean; @@ -1646,7 +1634,7 @@ export class TheHive implements INodeType { if (operation === 'get') { const taskId = this.getNodeParameter('id', i) as string; - const credentials = await this.getCredentials('theHiveApi') as IDataObject; + const credentials = await this.getCredentials('theHiveApi'); const version = credentials.apiVersion; @@ -1690,7 +1678,7 @@ export class TheHive implements INodeType { if (operation === 'getAll') { // get all require a case id (it retursn all tasks for a specific case) - const credentials = await this.getCredentials('theHiveApi') as IDataObject; + const credentials = await this.getCredentials('theHiveApi'); const returnAll = this.getNodeParameter('returnAll', i) as boolean; @@ -1765,7 +1753,7 @@ export class TheHive implements INodeType { } if (operation === 'search') { - const credentials = await this.getCredentials('theHiveApi') as IDataObject; + const credentials = await this.getCredentials('theHiveApi'); const returnAll = this.getNodeParameter('returnAll', i) as boolean; @@ -1988,7 +1976,7 @@ export class TheHive implements INodeType { if (operation === 'get') { const logId = this.getNodeParameter('id', i) as string; - const credentials = await this.getCredentials('theHiveApi') as IDataObject; + const credentials = await this.getCredentials('theHiveApi'); const version = credentials.apiVersion; @@ -2032,7 +2020,7 @@ export class TheHive implements INodeType { } if (operation === 'getAll') { - const credentials = await this.getCredentials('theHiveApi') as IDataObject; + const credentials = await this.getCredentials('theHiveApi'); const returnAll = this.getNodeParameter('returnAll', i) as boolean; diff --git a/packages/nodes-base/nodes/TimescaleDb/TimescaleDb.node.ts b/packages/nodes-base/nodes/TimescaleDb/TimescaleDb.node.ts index 4d9bec9739..58398d289b 100644 --- a/packages/nodes-base/nodes/TimescaleDb/TimescaleDb.node.ts +++ b/packages/nodes-base/nodes/TimescaleDb/TimescaleDb.node.ts @@ -271,10 +271,6 @@ export class TimescaleDb implements INodeType { async execute(this: IExecuteFunctions): Promise { const credentials = await this.getCredentials('timescaleDb'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const pgp = pgPromise(); const config = { diff --git a/packages/nodes-base/nodes/Todoist/GenericFunctions.ts b/packages/nodes-base/nodes/Todoist/GenericFunctions.ts index f7324daef9..aba3afa25d 100644 --- a/packages/nodes-base/nodes/Todoist/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Todoist/GenericFunctions.ts @@ -46,7 +46,7 @@ export async function todoistApiRequest( try { if (authentication === 'apiKey') { - const credentials = await this.getCredentials('todoistApi') as IDataObject; + const credentials = await this.getCredentials('todoistApi'); //@ts-ignore options.headers['Authorization'] = `Bearer ${credentials.apiKey}`; diff --git a/packages/nodes-base/nodes/Toggl/GenericFunctions.ts b/packages/nodes-base/nodes/Toggl/GenericFunctions.ts index b8386abb94..56bdeeb181 100644 --- a/packages/nodes-base/nodes/Toggl/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Toggl/GenericFunctions.ts @@ -15,9 +15,6 @@ import { export async function togglApiRequest(this: ITriggerFunctions | IPollFunctions | IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, query?: IDataObject, uri?: string): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('togglApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const headerWithAuthentication = Object.assign({}, { Authorization: ` Basic ${Buffer.from(`${credentials.username}:${credentials.password}`).toString('base64')}` }); diff --git a/packages/nodes-base/nodes/TravisCi/GenericFunctions.ts b/packages/nodes-base/nodes/TravisCi/GenericFunctions.ts index 00c224bb37..dbc4146bfb 100644 --- a/packages/nodes-base/nodes/TravisCi/GenericFunctions.ts +++ b/packages/nodes-base/nodes/TravisCi/GenericFunctions.ts @@ -21,9 +21,6 @@ import querystring from 'querystring'; export async function travisciApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('travisCiApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } let options: OptionsWithUri = { headers: { 'Travis-API-Version': '3', diff --git a/packages/nodes-base/nodes/Trello/GenericFunctions.ts b/packages/nodes-base/nodes/Trello/GenericFunctions.ts index df29f882d8..4556cba88b 100644 --- a/packages/nodes-base/nodes/Trello/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Trello/GenericFunctions.ts @@ -24,10 +24,6 @@ import { export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: object, query?: IDataObject): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('trelloApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - query = query || {}; query.key = credentials.apiKey; diff --git a/packages/nodes-base/nodes/Trello/TrelloTrigger.node.ts b/packages/nodes-base/nodes/Trello/TrelloTrigger.node.ts index 34a5f78fd5..04e1423543 100644 --- a/packages/nodes-base/nodes/Trello/TrelloTrigger.node.ts +++ b/packages/nodes-base/nodes/Trello/TrelloTrigger.node.ts @@ -70,10 +70,6 @@ export class TrelloTrigger implements INodeType { async checkExists(this: IHookFunctions): Promise { const credentials = await this.getCredentials('trelloApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - // Check all the webhooks which exist already if it is identical to the // one that is supposed to get created. const endpoint = `tokens/${credentials.apiToken}/webhooks`; @@ -98,9 +94,6 @@ export class TrelloTrigger implements INodeType { const webhookUrl = this.getNodeWebhookUrl('default'); const credentials = await this.getCredentials('trelloApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const idModel = this.getNodeParameter('id') as string; @@ -129,9 +122,6 @@ export class TrelloTrigger implements INodeType { if (webhookData.webhookId !== undefined) { const credentials = await this.getCredentials('trelloApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const endpoint = `tokens/${credentials.apiToken}/webhooks/${webhookData.webhookId}`; @@ -171,10 +161,6 @@ export class TrelloTrigger implements INodeType { const credentials = await this.getCredentials('trelloApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - // TODO: Check why that does not work as expected even though it gets done as described // https://developers.trello.com/page/webhooks // // Check if the request is valid diff --git a/packages/nodes-base/nodes/Twake/GenericFunctions.ts b/packages/nodes-base/nodes/Twake/GenericFunctions.ts index dd4360702c..c02f3f0a05 100644 --- a/packages/nodes-base/nodes/Twake/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Twake/GenericFunctions.ts @@ -35,7 +35,7 @@ export async function twakeApiRequest(this: IHookFunctions | IExecuteFunctions | // if (authenticationMethod === 'cloud') { const credentials = await this.getCredentials('twakeCloudApi'); - options.headers!.Authorization = `Bearer ${credentials!.workspaceKey}`; + options.headers!.Authorization = `Bearer ${credentials.workspaceKey}`; // } else { // const credentials = await this.getCredentials('twakeServerApi'); diff --git a/packages/nodes-base/nodes/Twilio/GenericFunctions.ts b/packages/nodes-base/nodes/Twilio/GenericFunctions.ts index 086e930064..a2d9cab967 100644 --- a/packages/nodes-base/nodes/Twilio/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Twilio/GenericFunctions.ts @@ -29,10 +29,6 @@ export async function twilioApiRequest(this: IHookFunctions | IExecuteFunctions, apiKeySecret: string; }; - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - if (query === undefined) { query = {}; } diff --git a/packages/nodes-base/nodes/Typeform/GenericFunctions.ts b/packages/nodes-base/nodes/Typeform/GenericFunctions.ts index 688a0d715c..e628d1d915 100644 --- a/packages/nodes-base/nodes/Typeform/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Typeform/GenericFunctions.ts @@ -67,10 +67,6 @@ export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoa const credentials = await this.getCredentials('typeformApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - options.headers!['Authorization'] = `bearer ${credentials.accessToken}`; return await this.helpers.request!(options); diff --git a/packages/nodes-base/nodes/UProc/GenericFunctions.ts b/packages/nodes-base/nodes/UProc/GenericFunctions.ts index b3c94d31b2..13d169289c 100644 --- a/packages/nodes-base/nodes/UProc/GenericFunctions.ts +++ b/packages/nodes-base/nodes/UProc/GenericFunctions.ts @@ -15,9 +15,6 @@ import { export async function uprocApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('uprocApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } const token = Buffer.from(`${credentials.email}:${credentials.apiKey}`).toString('base64'); const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/UnleashedSoftware/GenericFunctions.ts b/packages/nodes-base/nodes/UnleashedSoftware/GenericFunctions.ts index d33a386a64..8627445e13 100644 --- a/packages/nodes-base/nodes/UnleashedSoftware/GenericFunctions.ts +++ b/packages/nodes-base/nodes/UnleashedSoftware/GenericFunctions.ts @@ -42,10 +42,6 @@ export async function unleashedApiRequest(this: IHookFunctions | IExecuteFunctio const credentials = await this.getCredentials('unleashedSoftwareApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const signature = createHmac('sha256', (credentials.apiKey as string)) .update(qs.stringify(query)) .digest('base64'); diff --git a/packages/nodes-base/nodes/Uplead/GenericFunctions.ts b/packages/nodes-base/nodes/Uplead/GenericFunctions.ts index 74b1a74050..b684265981 100644 --- a/packages/nodes-base/nodes/Uplead/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Uplead/GenericFunctions.ts @@ -9,9 +9,6 @@ import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function upleadApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('upleadApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } let options: OptionsWithUri = { headers: { Authorization: credentials.apiKey }, method, diff --git a/packages/nodes-base/nodes/UptimeRobot/GenericFunctions.ts b/packages/nodes-base/nodes/UptimeRobot/GenericFunctions.ts index 240051abf2..12a08fe687 100644 --- a/packages/nodes-base/nodes/UptimeRobot/GenericFunctions.ts +++ b/packages/nodes-base/nodes/UptimeRobot/GenericFunctions.ts @@ -14,9 +14,6 @@ import { export async function uptimeRobotApiRequest(this: IExecuteFunctions, method: string, resource: string, body: IDataObject = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}) { const credentials = await this.getCredentials('uptimeRobotApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } let options: OptionsWithUri = { method, diff --git a/packages/nodes-base/nodes/Vero/GenericFunctions.ts b/packages/nodes-base/nodes/Vero/GenericFunctions.ts index 1775f4f914..ceca8ed940 100644 --- a/packages/nodes-base/nodes/Vero/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Vero/GenericFunctions.ts @@ -8,9 +8,6 @@ import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function veroApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('veroApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } let options: OptionsWithUri = { method, diff --git a/packages/nodes-base/nodes/Vonage/GenericFunctions.ts b/packages/nodes-base/nodes/Vonage/GenericFunctions.ts index 9b010b9903..e462d8c02d 100644 --- a/packages/nodes-base/nodes/Vonage/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Vonage/GenericFunctions.ts @@ -14,7 +14,7 @@ import { export async function vonageApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, path: string, body: any = {}, qs: IDataObject = {}, option = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('vonageApi') as IDataObject; + const credentials = await this.getCredentials('vonageApi'); body.api_key = credentials.apiKey as string; diff --git a/packages/nodes-base/nodes/Wait/Wait.node.ts b/packages/nodes-base/nodes/Wait/Wait.node.ts index 7f79064dfa..ba447c3df6 100644 --- a/packages/nodes-base/nodes/Wait/Wait.node.ts +++ b/packages/nodes-base/nodes/Wait/Wait.node.ts @@ -5,6 +5,7 @@ import { } from 'n8n-core'; import { + ICredentialDataDecryptedObject, IDataObject, INodeExecutionData, INodeType, @@ -686,7 +687,13 @@ export class Wait implements INodeType { if (incomingAuthentication === 'basicAuth') { // Basic authorization is needed to call webhook - const httpBasicAuth = await this.getCredentials('httpBasicAuth'); + let httpBasicAuth: ICredentialDataDecryptedObject | undefined; + + try { + httpBasicAuth = await this.getCredentials('httpBasicAuth'); + } catch (error) { + // Do nothing + } if (httpBasicAuth === undefined || !httpBasicAuth.user || !httpBasicAuth.password) { // Data is not defined on node so can not authenticate @@ -706,7 +713,13 @@ export class Wait implements INodeType { } } else if (incomingAuthentication === 'headerAuth') { // Special header with value is needed to call webhook - const httpHeaderAuth = await this.getCredentials('httpHeaderAuth'); + let httpHeaderAuth: ICredentialDataDecryptedObject | undefined; + + try { + httpHeaderAuth = await this.getCredentials('httpHeaderAuth'); + } catch (error) { + // Do nothing + } if (httpHeaderAuth === undefined || !httpHeaderAuth.name || !httpHeaderAuth.value) { // Data is not defined on node so can not authenticate diff --git a/packages/nodes-base/nodes/Webflow/GenericFunctions.ts b/packages/nodes-base/nodes/Webflow/GenericFunctions.ts index 5629d918f9..ec0b338683 100644 --- a/packages/nodes-base/nodes/Webflow/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Webflow/GenericFunctions.ts @@ -48,9 +48,6 @@ export async function webflowApiRequest( try { if (authenticationMethod === 'accessToken') { const credentials = await this.getCredentials('webflowApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } options.headers!['authorization'] = `Bearer ${credentials.accessToken}`; diff --git a/packages/nodes-base/nodes/Webhook/Webhook.node.ts b/packages/nodes-base/nodes/Webhook/Webhook.node.ts index b2e96f7153..3ce2e0138e 100644 --- a/packages/nodes-base/nodes/Webhook/Webhook.node.ts +++ b/packages/nodes-base/nodes/Webhook/Webhook.node.ts @@ -4,6 +4,7 @@ import { } from 'n8n-core'; import { + ICredentialDataDecryptedObject, IDataObject, INodeExecutionData, INodeType, @@ -454,7 +455,12 @@ export class Webhook implements INodeType { if (authentication === 'basicAuth') { // Basic authorization is needed to call webhook - const httpBasicAuth = await this.getCredentials('httpBasicAuth'); + let httpBasicAuth: ICredentialDataDecryptedObject | undefined; + try { + httpBasicAuth = await this.getCredentials('httpBasicAuth'); + } catch (error) { + // Do nothing + } if (httpBasicAuth === undefined || !httpBasicAuth.user || !httpBasicAuth.password) { // Data is not defined on node so can not authenticate @@ -474,7 +480,13 @@ export class Webhook implements INodeType { } } else if (authentication === 'headerAuth') { // Special header with value is needed to call webhook - const httpHeaderAuth = await this.getCredentials('httpHeaderAuth'); + let httpHeaderAuth: ICredentialDataDecryptedObject | undefined; + try { + httpHeaderAuth = await this.getCredentials('httpHeaderAuth'); + } catch (error) { + // Do nothing + } + if (httpHeaderAuth === undefined || !httpHeaderAuth.name || !httpHeaderAuth.value) { // Data is not defined on node so can not authenticate diff --git a/packages/nodes-base/nodes/Wekan/GenericFunctions.ts b/packages/nodes-base/nodes/Wekan/GenericFunctions.ts index 50810f263b..598ed8f7c3 100644 --- a/packages/nodes-base/nodes/Wekan/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Wekan/GenericFunctions.ts @@ -48,10 +48,6 @@ export async function getAuthorization( export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: object, query?: IDataObject): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('wekanApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - query = query || {}; const { token } = await getAuthorization.call(this, credentials); diff --git a/packages/nodes-base/nodes/Wise/Wise.node.ts b/packages/nodes-base/nodes/Wise/Wise.node.ts index cf10a5d149..c995c52676 100644 --- a/packages/nodes-base/nodes/Wise/Wise.node.ts +++ b/packages/nodes-base/nodes/Wise/Wise.node.ts @@ -439,7 +439,7 @@ export class Wise implements INodeType { // in sandbox, simulate transfer completion so that PDF receipt can be downloaded - const { environment } = await this.getCredentials('wiseApi') as IDataObject; + const { environment } = await this.getCredentials('wiseApi'); if (environment === 'test') { for (const endpoint of ['processing', 'funds_converted', 'outgoing_payment_sent']) { diff --git a/packages/nodes-base/nodes/Wise/WiseTrigger.node.ts b/packages/nodes-base/nodes/Wise/WiseTrigger.node.ts index 47914a7462..cded9a2b54 100644 --- a/packages/nodes-base/nodes/Wise/WiseTrigger.node.ts +++ b/packages/nodes-base/nodes/Wise/WiseTrigger.node.ts @@ -153,7 +153,7 @@ export class WiseTrigger implements INodeType { async webhook(this: IWebhookFunctions): Promise { const req = this.getRequestObject(); const headers = this.getHeaderData() as IDataObject; - const credentials = await this.getCredentials('wiseApi') as IDataObject; + const credentials = await this.getCredentials('wiseApi'); if (headers['x-test-notification'] === 'true') { const res = this.getResponseObject(); @@ -185,4 +185,4 @@ export class WiseTrigger implements INodeType { ], }; } -} \ No newline at end of file +} diff --git a/packages/nodes-base/nodes/WooCommerce/GenericFunctions.ts b/packages/nodes-base/nodes/WooCommerce/GenericFunctions.ts index 74f59a9aa6..28a88fca7d 100644 --- a/packages/nodes-base/nodes/WooCommerce/GenericFunctions.ts +++ b/packages/nodes-base/nodes/WooCommerce/GenericFunctions.ts @@ -38,9 +38,6 @@ import { export async function woocommerceApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('wooCommerceApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } let options: OptionsWithUri = { auth: { diff --git a/packages/nodes-base/nodes/WooCommerce/WooCommerceTrigger.node.ts b/packages/nodes-base/nodes/WooCommerce/WooCommerceTrigger.node.ts index 2e322c658b..f10b1e3c87 100644 --- a/packages/nodes-base/nodes/WooCommerce/WooCommerceTrigger.node.ts +++ b/packages/nodes-base/nodes/WooCommerce/WooCommerceTrigger.node.ts @@ -135,7 +135,7 @@ export class WooCommerceTrigger implements INodeType { const webhookUrl = this.getNodeWebhookUrl('default'); const webhookData = this.getWorkflowStaticData('node'); const event = this.getNodeParameter('event') as string; - const secret = getAutomaticSecret(credentials!); + const secret = getAutomaticSecret(credentials); const endpoint = '/webhooks'; const body: IDataObject = { delivery_url: webhookUrl, diff --git a/packages/nodes-base/nodes/Wordpress/GenericFunctions.ts b/packages/nodes-base/nodes/Wordpress/GenericFunctions.ts index 8f72caca42..ad74683126 100644 --- a/packages/nodes-base/nodes/Wordpress/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Wordpress/GenericFunctions.ts @@ -14,9 +14,6 @@ import { export async function wordpressApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('wordpressApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } let options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Wufoo/GenericFunctions.ts b/packages/nodes-base/nodes/Wufoo/GenericFunctions.ts index 0963ee65b3..c9a930f4a1 100644 --- a/packages/nodes-base/nodes/Wufoo/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Wufoo/GenericFunctions.ts @@ -15,9 +15,6 @@ import { export async function wufooApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('wufooApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } let options: OptionsWithUri = { auth: { diff --git a/packages/nodes-base/nodes/Yourls/GenericFunctions.ts b/packages/nodes-base/nodes/Yourls/GenericFunctions.ts index 2f10e8b81e..4bed81295c 100644 --- a/packages/nodes-base/nodes/Yourls/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Yourls/GenericFunctions.ts @@ -14,7 +14,7 @@ import { export async function yourlsApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, body: any = {}, qs: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('yourlsApi') as IDataObject; + const credentials = await this.getCredentials('yourlsApi'); qs.signature = credentials.signature as string; qs.format = 'json'; diff --git a/packages/nodes-base/nodes/Zendesk/GenericFunctions.ts b/packages/nodes-base/nodes/Zendesk/GenericFunctions.ts index 379a99fe28..2bedc684d9 100644 --- a/packages/nodes-base/nodes/Zendesk/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Zendesk/GenericFunctions.ts @@ -37,10 +37,6 @@ export async function zendeskApiRequest(this: IHookFunctions | IExecuteFunctions if (authenticationMethod === 'apiToken') { const credentials = await this.getCredentials('zendeskApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const base64Key = Buffer.from(`${credentials.email}/token:${credentials.apiToken}`).toString('base64'); options.uri = uri || `https://${credentials.subdomain}.zendesk.com/api/v2${resource}.json`; options.headers!['Authorization'] = `Basic ${base64Key}`; @@ -48,10 +44,6 @@ export async function zendeskApiRequest(this: IHookFunctions | IExecuteFunctions } else { const credentials = await this.getCredentials('zendeskOAuth2Api'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - options.uri = uri || `https://${credentials.subdomain}.zendesk.com/api/v2${resource}.json`; return await this.helpers.requestOAuth2!.call(this, 'zendeskOAuth2Api', options); diff --git a/packages/nodes-base/nodes/Zoom/GenericFunctions.ts b/packages/nodes-base/nodes/Zoom/GenericFunctions.ts index 306a9848e7..fc6f7f5c7b 100644 --- a/packages/nodes-base/nodes/Zoom/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Zoom/GenericFunctions.ts @@ -37,9 +37,6 @@ export async function zoomApiRequest(this: IExecuteFunctions | IExecuteSingleFun try { if (authenticationMethod === 'accessToken') { const credentials = await this.getCredentials('zoomApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } options.headers!.Authorization = `Bearer ${credentials.accessToken}`; //@ts-ignore diff --git a/packages/nodes-base/nodes/Zulip/GenericFunctions.ts b/packages/nodes-base/nodes/Zulip/GenericFunctions.ts index 4ee0d1e787..6f5b5640a1 100644 --- a/packages/nodes-base/nodes/Zulip/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Zulip/GenericFunctions.ts @@ -17,10 +17,6 @@ export async function zulipApiRequest(this: IExecuteFunctions | IWebhookFunction const credentials = await this.getCredentials('zulipApi'); - if (credentials === undefined) { - throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); - } - const endpoint = `${credentials.url}/api/v1`; let options: OptionsWithUri = { diff --git a/packages/nodes-base/nodes/Zulip/Zulip.node.ts b/packages/nodes-base/nodes/Zulip/Zulip.node.ts index 6f5d945c94..cde0ac8310 100644 --- a/packages/nodes-base/nodes/Zulip/Zulip.node.ts +++ b/packages/nodes-base/nodes/Zulip/Zulip.node.ts @@ -231,7 +231,7 @@ export class Zulip implements INodeType { }, }; responseData = await zulipApiRequest.call(this, 'POST', '/user_uploads', {}, {}, undefined, { formData }); - responseData.uri = `${credentials!.url}${responseData.uri}`; + responseData.uri = `${credentials.url}${responseData.uri}`; } } diff --git a/packages/workflow/src/Interfaces.ts b/packages/workflow/src/Interfaces.ts index 240a912b71..c9b58b5795 100644 --- a/packages/workflow/src/Interfaces.ts +++ b/packages/workflow/src/Interfaces.ts @@ -483,10 +483,7 @@ export interface IExecuteFunctions { inputData?: INodeExecutionData[], ): Promise; getContext(type: string): IContextObject; - getCredentials( - type: string, - itemIndex?: number, - ): Promise; + getCredentials(type: string, itemIndex?: number): Promise; getInputData(inputIndex?: number, inputName?: string): INodeExecutionData[]; getMode(): WorkflowExecuteMode; getNode(): INode; @@ -533,7 +530,7 @@ export interface IExecuteSingleFunctions { itemIndex: number | undefined, ): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[]; getContext(type: string): IContextObject; - getCredentials(type: string): Promise; + getCredentials(type: string): Promise; getInputData(inputIndex?: number, inputName?: string): INodeExecutionData; getMode(): WorkflowExecuteMode; getNode(): INode; @@ -583,7 +580,7 @@ export interface ICredentialTestFunctions { } export interface ILoadOptionsFunctions { - getCredentials(type: string): Promise; + getCredentials(type: string): Promise; getNode(): INode; getNodeParameter( parameterName: string, @@ -624,7 +621,7 @@ export interface ILoadOptionsFunctions { } export interface IHookFunctions { - getCredentials(type: string): Promise; + getCredentials(type: string): Promise; getMode(): WorkflowExecuteMode; getActivationMode(): WorkflowActivateMode; getNode(): INode; @@ -654,7 +651,7 @@ export interface IHookFunctions { export interface IPollFunctions { __emit(data: INodeExecutionData[][]): void; - getCredentials(type: string): Promise; + getCredentials(type: string): Promise; getMode(): WorkflowExecuteMode; getActivationMode(): WorkflowActivateMode; getNode(): INode; @@ -686,7 +683,7 @@ export interface ITriggerFunctions { responsePromise?: IDeferredPromise, ): void; emitError(error: Error, responsePromise?: IDeferredPromise): void; - getCredentials(type: string): Promise; + getCredentials(type: string): Promise; getMode(): WorkflowExecuteMode; getActivationMode(): WorkflowActivateMode; getNode(): INode; @@ -714,7 +711,7 @@ export interface ITriggerFunctions { export interface IWebhookFunctions { getBodyData(): IDataObject; - getCredentials(type: string): Promise; + getCredentials(type: string): Promise; getHeaderData(): object; getMode(): WorkflowExecuteMode; getNode(): INode; diff --git a/packages/workflow/test/Helpers.ts b/packages/workflow/test/Helpers.ts index 8e66d737d1..a94be10c98 100644 --- a/packages/workflow/test/Helpers.ts +++ b/packages/workflow/test/Helpers.ts @@ -211,7 +211,7 @@ export function getExecuteFunctions( async getCredentials( type: string, itemIndex?: number, - ): Promise { + ): Promise { return { apiKey: '12345', }; @@ -388,7 +388,7 @@ export function getExecuteSingleFunctions( getContext(type: string): IContextObject { return NodeHelpers.getContext(runExecutionData, type, node); }, - async getCredentials(type: string): Promise { + async getCredentials(type: string): Promise { return { apiKey: '12345', }; From 8532b0030dbdeb85b2f74ce078adb44f43a7c4d3 Mon Sep 17 00:00:00 2001 From: Ben Hesseldieck <1849459+BHesseldieck@users.noreply.github.com> Date: Fri, 15 Apr 2022 08:11:35 +0200 Subject: [PATCH 26/85] fix(core): Make email for UM case insensitive (#3078) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🚧 lowercasing email * ✅ add tests for case insensitive email * 🐘 add migration to lowercase email * 🚚 rename migration * 🐛 fix package.lock * :bug: fix double import * 📋 add todo --- .../email/UserManagementMailer.ts | 1 + .../cli/src/UserManagement/routes/users.ts | 2 +- packages/cli/src/databases/entities/User.ts | 13 +++- .../1648740597343-LowerCaseUserEmail.ts | 17 +++++ .../src/databases/mysqldb/migrations/index.ts | 2 + .../1648740597343-LowerCaseUserEmail.ts | 21 ++++++ .../databases/postgresdb/migrations/index.ts | 2 + .../1648740597343-LowerCaseUserEmail.ts | 22 +++++++ .../src/databases/sqlite/migrations/index.ts | 2 + .../cli/src/databases/utils/transformers.ts | 9 ++- .../test/integration/auth.endpoints.test.ts | 66 +++++++++++-------- packages/cli/test/integration/me.api.test.ts | 20 ++---- .../cli/test/integration/owner.api.test.ts | 29 ++++++++ .../integration/passwordReset.api.test.ts | 19 ++++-- .../cli/test/integration/users.api.test.ts | 46 +++++++------ 15 files changed, 197 insertions(+), 74 deletions(-) create mode 100644 packages/cli/src/databases/mysqldb/migrations/1648740597343-LowerCaseUserEmail.ts create mode 100644 packages/cli/src/databases/postgresdb/migrations/1648740597343-LowerCaseUserEmail.ts create mode 100644 packages/cli/src/databases/sqlite/migrations/1648740597343-LowerCaseUserEmail.ts diff --git a/packages/cli/src/UserManagement/email/UserManagementMailer.ts b/packages/cli/src/UserManagement/email/UserManagementMailer.ts index cda715a7c7..5fa51319b6 100644 --- a/packages/cli/src/UserManagement/email/UserManagementMailer.ts +++ b/packages/cli/src/UserManagement/email/UserManagementMailer.ts @@ -12,6 +12,7 @@ import { } from './Interfaces'; import { NodeMailer } from './NodeMailer'; +// TODO: make function fully async (remove sync functions) async function getTemplate(configKeyName: string, defaultFilename: string) { const templateOverride = (await GenericHelpers.getConfigValue( `userManagement.emails.templates.${configKeyName}`, diff --git a/packages/cli/src/UserManagement/routes/users.ts b/packages/cli/src/UserManagement/routes/users.ts index 3b19697036..d6f1caac7d 100644 --- a/packages/cli/src/UserManagement/routes/users.ts +++ b/packages/cli/src/UserManagement/routes/users.ts @@ -104,7 +104,7 @@ export function usersNamespace(this: N8nApp): void { 400, ); } - createUsers[invite.email] = null; + createUsers[invite.email.toLowerCase()] = null; }); const role = await Db.collections.Role.findOne({ scope: 'global', name: 'member' }); diff --git a/packages/cli/src/databases/entities/User.ts b/packages/cli/src/databases/entities/User.ts index ee539c4f65..12f4ec64c1 100644 --- a/packages/cli/src/databases/entities/User.ts +++ b/packages/cli/src/databases/entities/User.ts @@ -12,6 +12,7 @@ import { ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn, + BeforeInsert, } from 'typeorm'; import { IsEmail, IsString, Length } from 'class-validator'; import * as config from '../../../config'; @@ -20,7 +21,7 @@ import { Role } from './Role'; import { SharedWorkflow } from './SharedWorkflow'; import { SharedCredentials } from './SharedCredentials'; import { NoXss } from '../utils/customValidators'; -import { answersFormatter } from '../utils/transformers'; +import { answersFormatter, lowerCaser } from '../utils/transformers'; export const MIN_PASSWORD_LENGTH = 8; @@ -62,7 +63,11 @@ export class User { @PrimaryGeneratedColumn('uuid') id: string; - @Column({ length: 254, nullable: true }) + @Column({ + length: 254, + nullable: true, + transformer: lowerCaser, + }) @Index({ unique: true }) @IsEmail() email: string; @@ -119,8 +124,10 @@ export class User { }) updatedAt: Date; + @BeforeInsert() @BeforeUpdate() - setUpdateDate(): void { + preUpsertHook(): void { + this.email = this.email?.toLowerCase(); this.updatedAt = new Date(); } diff --git a/packages/cli/src/databases/mysqldb/migrations/1648740597343-LowerCaseUserEmail.ts b/packages/cli/src/databases/mysqldb/migrations/1648740597343-LowerCaseUserEmail.ts new file mode 100644 index 0000000000..a627ed830a --- /dev/null +++ b/packages/cli/src/databases/mysqldb/migrations/1648740597343-LowerCaseUserEmail.ts @@ -0,0 +1,17 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; +import config = require('../../../../config'); + +export class LowerCaseUserEmail1648740597343 implements MigrationInterface { + name = 'LowerCaseUserEmail1648740597343'; + + public async up(queryRunner: QueryRunner): Promise { + const tablePrefix = config.get('database.tablePrefix'); + + await queryRunner.query(` + UPDATE ${tablePrefix}user + SET email = LOWER(email); + `); + } + + public async down(queryRunner: QueryRunner): Promise {} +} diff --git a/packages/cli/src/databases/mysqldb/migrations/index.ts b/packages/cli/src/databases/mysqldb/migrations/index.ts index 16ee37da46..6c859556d0 100644 --- a/packages/cli/src/databases/mysqldb/migrations/index.ts +++ b/packages/cli/src/databases/mysqldb/migrations/index.ts @@ -12,6 +12,7 @@ import { AddWaitColumnId1626183952959 } from './1626183952959-AddWaitColumn'; import { UpdateWorkflowCredentials1630451444017 } from './1630451444017-UpdateWorkflowCredentials'; import { AddExecutionEntityIndexes1644424784709 } from './1644424784709-AddExecutionEntityIndexes'; import { CreateUserManagement1646992772331 } from './1646992772331-CreateUserManagement'; +import { LowerCaseUserEmail1648740597343 } from './1648740597343-LowerCaseUserEmail'; export const mysqlMigrations = [ InitialMigration1588157391238, @@ -28,4 +29,5 @@ export const mysqlMigrations = [ UpdateWorkflowCredentials1630451444017, AddExecutionEntityIndexes1644424784709, CreateUserManagement1646992772331, + LowerCaseUserEmail1648740597343, ]; diff --git a/packages/cli/src/databases/postgresdb/migrations/1648740597343-LowerCaseUserEmail.ts b/packages/cli/src/databases/postgresdb/migrations/1648740597343-LowerCaseUserEmail.ts new file mode 100644 index 0000000000..02a12d047f --- /dev/null +++ b/packages/cli/src/databases/postgresdb/migrations/1648740597343-LowerCaseUserEmail.ts @@ -0,0 +1,21 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; +import config = require('../../../../config'); + +export class LowerCaseUserEmail1648740597343 implements MigrationInterface { + name = 'LowerCaseUserEmail1648740597343'; + + public async up(queryRunner: QueryRunner): Promise { + let tablePrefix = config.get('database.tablePrefix'); + const schema = config.get('database.postgresdb.schema'); + if (schema) { + tablePrefix = schema + '.' + tablePrefix; + } + + await queryRunner.query(` + UPDATE ${tablePrefix}user + SET email = LOWER(email); + `); + } + + public async down(queryRunner: QueryRunner): Promise {} +} diff --git a/packages/cli/src/databases/postgresdb/migrations/index.ts b/packages/cli/src/databases/postgresdb/migrations/index.ts index 903b6a7e72..3c1fb23d4f 100644 --- a/packages/cli/src/databases/postgresdb/migrations/index.ts +++ b/packages/cli/src/databases/postgresdb/migrations/index.ts @@ -10,6 +10,7 @@ import { UpdateWorkflowCredentials1630419189837 } from './1630419189837-UpdateWo import { AddExecutionEntityIndexes1644422880309 } from './1644422880309-AddExecutionEntityIndexes'; import { IncreaseTypeVarcharLimit1646834195327 } from './1646834195327-IncreaseTypeVarcharLimit'; import { CreateUserManagement1646992772331 } from './1646992772331-CreateUserManagement'; +import { LowerCaseUserEmail1648740597343 } from './1648740597343-LowerCaseUserEmail'; export const postgresMigrations = [ InitialMigration1587669153312, @@ -24,4 +25,5 @@ export const postgresMigrations = [ AddExecutionEntityIndexes1644422880309, IncreaseTypeVarcharLimit1646834195327, CreateUserManagement1646992772331, + LowerCaseUserEmail1648740597343, ]; diff --git a/packages/cli/src/databases/sqlite/migrations/1648740597343-LowerCaseUserEmail.ts b/packages/cli/src/databases/sqlite/migrations/1648740597343-LowerCaseUserEmail.ts new file mode 100644 index 0000000000..2eb7898750 --- /dev/null +++ b/packages/cli/src/databases/sqlite/migrations/1648740597343-LowerCaseUserEmail.ts @@ -0,0 +1,22 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; +import config = require('../../../../config'); +import { logMigrationEnd, logMigrationStart } from '../../utils/migrationHelpers'; + +export class LowerCaseUserEmail1648740597343 implements MigrationInterface { + name = 'LowerCaseUserEmail1648740597343'; + + public async up(queryRunner: QueryRunner): Promise { + logMigrationStart(this.name); + + const tablePrefix = config.get('database.tablePrefix'); + + await queryRunner.query(` + UPDATE "${tablePrefix}user" + SET email = LOWER(email); + `); + + logMigrationEnd(this.name); + } + + public async down(queryRunner: QueryRunner): Promise {} +} diff --git a/packages/cli/src/databases/sqlite/migrations/index.ts b/packages/cli/src/databases/sqlite/migrations/index.ts index 2f938fe0d1..347c403aea 100644 --- a/packages/cli/src/databases/sqlite/migrations/index.ts +++ b/packages/cli/src/databases/sqlite/migrations/index.ts @@ -11,6 +11,7 @@ import { AddWaitColumn1621707690587 } from './1621707690587-AddWaitColumn'; import { UpdateWorkflowCredentials1630330987096 } from './1630330987096-UpdateWorkflowCredentials'; import { AddExecutionEntityIndexes1644421939510 } from './1644421939510-AddExecutionEntityIndexes'; import { CreateUserManagement1646992772331 } from './1646992772331-CreateUserManagement'; +import { LowerCaseUserEmail1648740597343 } from './1648740597343-LowerCaseUserEmail'; const sqliteMigrations = [ InitialMigration1588102412422, @@ -24,6 +25,7 @@ const sqliteMigrations = [ UpdateWorkflowCredentials1630330987096, AddExecutionEntityIndexes1644421939510, CreateUserManagement1646992772331, + LowerCaseUserEmail1648740597343, ]; export { sqliteMigrations }; diff --git a/packages/cli/src/databases/utils/transformers.ts b/packages/cli/src/databases/utils/transformers.ts index f843c1c2f7..c2a9d3e0d2 100644 --- a/packages/cli/src/databases/utils/transformers.ts +++ b/packages/cli/src/databases/utils/transformers.ts @@ -2,8 +2,13 @@ import { IPersonalizationSurveyAnswers } from '../../Interfaces'; export const idStringifier = { - from: (value: number): string | number => (value ? value.toString() : value), - to: (value: string): number | string => (value ? Number(value) : value), + from: (value: number): string | number => (typeof value === 'number' ? value.toString() : value), + to: (value: string): number | string => (typeof value === 'string' ? Number(value) : value), +}; + +export const lowerCaser = { + from: (value: string): string => value, + to: (value: string): string => (typeof value === 'string' ? value.toLowerCase() : value), }; /** diff --git a/packages/cli/test/integration/auth.endpoints.test.ts b/packages/cli/test/integration/auth.endpoints.test.ts index fd24d49c0e..0bbb5b7e58 100644 --- a/packages/cli/test/integration/auth.endpoints.test.ts +++ b/packages/cli/test/integration/auth.endpoints.test.ts @@ -1,4 +1,3 @@ -import { hashSync, genSaltSync } from 'bcryptjs'; import express from 'express'; import validator from 'validator'; import { v4 as uuid } from 'uuid'; @@ -60,38 +59,47 @@ afterAll(async () => { test('POST /login should log user in', async () => { const authlessAgent = utils.createAgent(app); - const response = await authlessAgent.post('/login').send({ - email: TEST_USER.email, - password: TEST_USER.password, - }); + await Promise.all( + [ + { + email: TEST_USER.email, + password: TEST_USER.password, + }, + { + email: TEST_USER.email.toUpperCase(), + password: TEST_USER.password, + }, + ].map(async (payload) => { + const response = await authlessAgent.post('/login').send(payload); - expect(response.statusCode).toBe(200); + expect(response.statusCode).toBe(200); - const { - id, - email, - firstName, - lastName, - password, - personalizationAnswers, - globalRole, - resetPasswordToken, - } = response.body.data; + const { + id, + email, + firstName, + lastName, + password, + personalizationAnswers, + globalRole, + resetPasswordToken, + } = response.body.data; - expect(validator.isUUID(id)).toBe(true); - expect(email).toBe(TEST_USER.email); - expect(firstName).toBe(TEST_USER.firstName); - expect(lastName).toBe(TEST_USER.lastName); - expect(password).toBeUndefined(); - expect(personalizationAnswers).toBeNull(); - expect(password).toBeUndefined(); - expect(resetPasswordToken).toBeUndefined(); - expect(globalRole).toBeDefined(); - expect(globalRole.name).toBe('owner'); - expect(globalRole.scope).toBe('global'); + expect(validator.isUUID(id)).toBe(true); + expect(email).toBe(TEST_USER.email); + expect(firstName).toBe(TEST_USER.firstName); + expect(lastName).toBe(TEST_USER.lastName); + expect(password).toBeUndefined(); + expect(personalizationAnswers).toBeNull(); + expect(resetPasswordToken).toBeUndefined(); + expect(globalRole).toBeDefined(); + expect(globalRole.name).toBe('owner'); + expect(globalRole.scope).toBe('global'); - const authToken = utils.getAuthToken(response); - expect(authToken).toBeDefined(); + const authToken = utils.getAuthToken(response); + expect(authToken).toBeDefined(); + }), + ); }); test('GET /login should receive logged in user', async () => { diff --git a/packages/cli/test/integration/me.api.test.ts b/packages/cli/test/integration/me.api.test.ts index 85c435a5b8..186f09ddea 100644 --- a/packages/cli/test/integration/me.api.test.ts +++ b/packages/cli/test/integration/me.api.test.ts @@ -91,7 +91,7 @@ describe('Owner shell', () => { } = response.body.data; expect(validator.isUUID(id)).toBe(true); - expect(email).toBe(validPayload.email); + expect(email).toBe(validPayload.email.toLowerCase()); expect(firstName).toBe(validPayload.firstName); expect(lastName).toBe(validPayload.lastName); expect(personalizationAnswers).toBeNull(); @@ -103,7 +103,7 @@ describe('Owner shell', () => { const storedOwnerShell = await Db.collections.User!.findOneOrFail(id); - expect(storedOwnerShell.email).toBe(validPayload.email); + expect(storedOwnerShell.email).toBe(validPayload.email.toLowerCase()); expect(storedOwnerShell.firstName).toBe(validPayload.firstName); expect(storedOwnerShell.lastName).toBe(validPayload.lastName); } @@ -245,7 +245,7 @@ describe('Member', () => { } = response.body.data; expect(validator.isUUID(id)).toBe(true); - expect(email).toBe(validPayload.email); + expect(email).toBe(validPayload.email.toLowerCase()); expect(firstName).toBe(validPayload.firstName); expect(lastName).toBe(validPayload.lastName); expect(personalizationAnswers).toBeNull(); @@ -257,7 +257,7 @@ describe('Member', () => { const storedMember = await Db.collections.User!.findOneOrFail(id); - expect(storedMember.email).toBe(validPayload.email); + expect(storedMember.email).toBe(validPayload.email.toLowerCase()); expect(storedMember.firstName).toBe(validPayload.firstName); expect(storedMember.lastName).toBe(validPayload.lastName); } @@ -400,7 +400,7 @@ describe('Owner', () => { } = response.body.data; expect(validator.isUUID(id)).toBe(true); - expect(email).toBe(validPayload.email); + expect(email).toBe(validPayload.email.toLowerCase()); expect(firstName).toBe(validPayload.firstName); expect(lastName).toBe(validPayload.lastName); expect(personalizationAnswers).toBeNull(); @@ -412,19 +412,13 @@ describe('Owner', () => { const storedOwner = await Db.collections.User!.findOneOrFail(id); - expect(storedOwner.email).toBe(validPayload.email); + expect(storedOwner.email).toBe(validPayload.email.toLowerCase()); expect(storedOwner.firstName).toBe(validPayload.firstName); expect(storedOwner.lastName).toBe(validPayload.lastName); } }); }); -const TEST_USER = { - email: randomEmail(), - firstName: randomName(), - lastName: randomName(), -}; - const SURVEY = [ 'codingSkill', 'companyIndustry', @@ -444,7 +438,7 @@ const VALID_PATCH_ME_PAYLOADS = [ password: randomValidPassword(), }, { - email: randomEmail(), + email: randomEmail().toUpperCase(), firstName: randomName(), lastName: randomName(), password: randomValidPassword(), diff --git a/packages/cli/test/integration/owner.api.test.ts b/packages/cli/test/integration/owner.api.test.ts index 3f97f298b3..e479196999 100644 --- a/packages/cli/test/integration/owner.api.test.ts +++ b/packages/cli/test/integration/owner.api.test.ts @@ -30,6 +30,12 @@ beforeAll(async () => { }); beforeEach(async () => { + jest.mock('../../config'); + + config.set('userManagement.isInstanceOwnerSetUp', false); +}); + +afterEach(async () => { await testDb.truncate(['User'], testDbName); }); @@ -88,6 +94,29 @@ test('POST /owner should create owner and enable isInstanceOwnerSetUp', async () expect(isInstanceOwnerSetUpSetting).toBe(true); }); +test('POST /owner should create owner with lowercased email', async () => { + const ownerShell = await testDb.createUserShell(globalOwnerRole); + const authOwnerAgent = utils.createAgent(app, { auth: true, user: ownerShell }); + + const newOwnerData = { + email: randomEmail().toUpperCase(), + firstName: randomName(), + lastName: randomName(), + password: randomValidPassword(), + }; + + const response = await authOwnerAgent.post('/owner').send(newOwnerData); + + expect(response.statusCode).toBe(200); + + const { id, email } = response.body.data; + + expect(email).toBe(newOwnerData.email.toLowerCase()); + + const storedOwner = await Db.collections.User!.findOneOrFail(id); + expect(storedOwner.email).toBe(newOwnerData.email.toLowerCase()); +}); + test('POST /owner should fail with invalid inputs', async () => { const ownerShell = await testDb.createUserShell(globalOwnerRole); const authOwnerAgent = utils.createAgent(app, { auth: true, user: ownerShell }); diff --git a/packages/cli/test/integration/passwordReset.api.test.ts b/packages/cli/test/integration/passwordReset.api.test.ts index 8b41428862..ef1ffdbf2f 100644 --- a/packages/cli/test/integration/passwordReset.api.test.ts +++ b/packages/cli/test/integration/passwordReset.api.test.ts @@ -19,6 +19,7 @@ jest.mock('../../src/telemetry'); let app: express.Application; let testDbName = ''; let globalOwnerRole: Role; +let globalMemberRole: Role; beforeAll(async () => { app = utils.initTestServer({ endpointGroups: ['passwordReset'], applyAuth: true }); @@ -26,6 +27,7 @@ beforeAll(async () => { testDbName = initResult.testDbName; globalOwnerRole = await testDb.getGlobalOwnerRole(); + globalMemberRole = await testDb.getGlobalMemberRole(); utils.initTestTelemetry(); utils.initTestLogger(); @@ -50,17 +52,22 @@ test('POST /forgot-password should send password reset email', async () => { const owner = await testDb.createUser({ globalRole: globalOwnerRole }); const authlessAgent = utils.createAgent(app); + const member = await testDb.createUser({ email: 'test@test.com', globalRole: globalMemberRole }); await utils.configureSmtp(); - const response = await authlessAgent.post('/forgot-password').send({ email: owner.email }); + await Promise.all( + [{ email: owner.email }, { email: member.email.toUpperCase() }].map(async (payload) => { + const response = await authlessAgent.post('/forgot-password').send(payload); - expect(response.statusCode).toBe(200); - expect(response.body).toEqual({}); + expect(response.statusCode).toBe(200); + expect(response.body).toEqual({}); - const storedOwner = await Db.collections.User!.findOneOrFail({ email: owner.email }); - expect(storedOwner.resetPasswordToken).toBeDefined(); - expect(storedOwner.resetPasswordTokenExpiration).toBeGreaterThan(Math.ceil(Date.now() / 1000)); + const user = await Db.collections.User!.findOneOrFail({ email: payload.email }); + expect(user.resetPasswordToken).toBeDefined(); + expect(user.resetPasswordTokenExpiration).toBeGreaterThan(Math.ceil(Date.now() / 1000)); + }), + ); }); test('POST /forgot-password should fail if emailing is not set up', async () => { diff --git a/packages/cli/test/integration/users.api.test.ts b/packages/cli/test/integration/users.api.test.ts index eaee6d4db8..f139cd4351 100644 --- a/packages/cli/test/integration/users.api.test.ts +++ b/packages/cli/test/integration/users.api.test.ts @@ -481,13 +481,15 @@ test('POST /users should fail if user management is disabled', async () => { expect(response.statusCode).toBe(500); }); -test('POST /users should email invites and create user shells', async () => { +test('POST /users should email invites and create user shells but ignore existing', async () => { const owner = await testDb.createUser({ globalRole: globalOwnerRole }); + const member = await testDb.createUser({ globalRole: globalMemberRole }); + const memberShell = await testDb.createUserShell(globalMemberRole); const authOwnerAgent = utils.createAgent(app, { auth: true, user: owner }); await utils.configureSmtp(); - const testEmails = [randomEmail(), randomEmail(), randomEmail()]; + const testEmails = [randomEmail(), randomEmail().toUpperCase(), memberShell.email, member.email]; const payload = testEmails.map((e) => ({ email: e })); @@ -495,27 +497,31 @@ test('POST /users should email invites and create user shells', async () => { expect(response.statusCode).toBe(200); - await Promise.all( - response.body.data.map(async ({ user, error }: { user: User; error: Error }) => { - const { id, email: receivedEmail } = user; + for (const { + user: { id, email: receivedEmail }, + error, + } of response.body.data) { + expect(validator.isUUID(id)).toBe(true); + expect(id).not.toBe(member.id); - expect(validator.isUUID(id)).toBe(true); - expect(testEmails.some((e) => e === receivedEmail)).toBe(true); - if (error) { - expect(error).toBe('Email could not be sent'); - } + const lowerCasedEmail = receivedEmail.toLowerCase(); + expect(receivedEmail).toBe(lowerCasedEmail); + expect(payload.some(({ email }) => email.toLowerCase() === lowerCasedEmail)).toBe(true); - const storedUser = await Db.collections.User!.findOneOrFail(id); - const { firstName, lastName, personalizationAnswers, password, resetPasswordToken } = - storedUser; + if (error) { + expect(error).toBe('Email could not be sent'); + } - expect(firstName).toBeNull(); - expect(lastName).toBeNull(); - expect(personalizationAnswers).toBeNull(); - expect(password).toBeNull(); - expect(resetPasswordToken).toBeNull(); - }), - ); + const storedUser = await Db.collections.User!.findOneOrFail(id); + const { firstName, lastName, personalizationAnswers, password, resetPasswordToken } = + storedUser; + + expect(firstName).toBeNull(); + expect(lastName).toBeNull(); + expect(personalizationAnswers).toBeNull(); + expect(password).toBeNull(); + expect(resetPasswordToken).toBeNull(); + } }); test('POST /users should fail with invalid inputs', async () => { From 18dee373d5ebf337e33d1c38e057ed0c24a74f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Fri, 15 Apr 2022 08:22:58 +0200 Subject: [PATCH 27/85] :zap: Add autocompletion for i18n keys in script sections of Vue files (#3133) * :blue_book: Type `baseText()` to i18n keys * :blue_book: Adjust `baseText()` signature * :shirt: Except JSON files from Vue ESLint * :bug: Fix errors surfaced by `baseText()` typing * :zap: Pluralize keys * :blue_book: Add typing for category names * :zap: Mark internal keys * :pencil2: Update docs references * :art: Prettify syntax * :bug: Fix leftover internal key references --- .../src/components/DeleteUserModal.vue | 12 +++-- .../src/components/InviteUsersModal.vue | 5 +- packages/editor-ui/src/components/Node.vue | 7 ++- .../components/NodeCreator/CategoryItem.vue | 7 +-- .../src/components/WorkflowSettings.vue | 2 +- .../src/plugins/i18n/docs/ADDENDUM.md | 12 ++--- packages/editor-ui/src/plugins/i18n/index.ts | 28 +++++++++-- .../src/plugins/i18n/locales/en.json | 46 +++++++++---------- .../editor-ui/src/plugins/i18n/types.d.ts | 7 --- .../editor-ui/src/views/SettingsUsersView.vue | 5 +- packages/editor-ui/src/views/SetupView.vue | 15 +++++- packages/editor-ui/tsconfig.json | 1 + packages/editor-ui/tslint.json | 3 +- 13 files changed, 95 insertions(+), 55 deletions(-) delete mode 100644 packages/editor-ui/src/plugins/i18n/types.d.ts diff --git a/packages/editor-ui/src/components/DeleteUserModal.vue b/packages/editor-ui/src/components/DeleteUserModal.vue index de21bcb4bb..1871288aed 100644 --- a/packages/editor-ui/src/components/DeleteUserModal.vue +++ b/packages/editor-ui/src/components/DeleteUserModal.vue @@ -90,8 +90,11 @@ export default mixins(showMessage).extend({ return this.userToDelete && !this.userToDelete.firstName; }, title(): string { - const user = this.userToDelete && (this.userToDelete.fullName || this.userToDelete.email); - return this.$locale.baseText('settings.users.deleteUser', { interpolate: { user }}); + const user = this.userToDelete && (this.userToDelete.fullName || this.userToDelete.email) || ''; + return this.$locale.baseText( + 'settings.users.deleteUser', + { interpolate: { user }}, + ); }, enabled(): boolean { if (this.isPending) { @@ -138,7 +141,10 @@ export default mixins(showMessage).extend({ if (this.transferId) { const getUserById = this.$store.getters['users/getUserById']; const transferUser: IUser = getUserById(this.transferId); - message = this.$locale.baseText('settings.users.transferredToUser', { interpolate: { user: transferUser.fullName }}); + message = this.$locale.baseText( + 'settings.users.transferredToUser', + { interpolate: { user: transferUser.fullName || '' }}, + ); } this.$showMessage({ diff --git a/packages/editor-ui/src/components/InviteUsersModal.vue b/packages/editor-ui/src/components/InviteUsersModal.vue index 18730fe580..d52ebd1ae5 100644 --- a/packages/editor-ui/src/components/InviteUsersModal.vue +++ b/packages/editor-ui/src/components/InviteUsersModal.vue @@ -106,7 +106,10 @@ export default mixins(showMessage).extend({ }, buttonLabel(): string { if (this.emailsCount > 1) { - return this.$locale.baseText('settings.users.inviteXUser', { interpolate: { count: this.emailsCount }}); + return this.$locale.baseText( + 'settings.users.inviteXUser', + { interpolate: { count: this.emailsCount.toString() }}, + ); } return this.$locale.baseText('settings.users.inviteUser'); diff --git a/packages/editor-ui/src/components/Node.vue b/packages/editor-ui/src/components/Node.vue index 2c7e9abfe7..1120a05e35 100644 --- a/packages/editor-ui/src/components/Node.vue +++ b/packages/editor-ui/src/components/Node.vue @@ -125,13 +125,16 @@ export default mixins(externalHooks, nodeBase, nodeHelpers, workflowHelpers).ext if (this.nodeType !== null && this.nodeType.hasOwnProperty('eventTriggerDescription')) { const nodeName = this.$locale.shortNodeType(this.nodeType.name); const { eventTriggerDescription } = this.nodeType; - return this.$locale.nodeText().eventTriggerDescription(nodeName, eventTriggerDescription); + return this.$locale.nodeText().eventTriggerDescription( + nodeName, + eventTriggerDescription || '', + ); } else { return this.$locale.baseText( 'node.waitingForYouToCreateAnEventIn', { interpolate: { - nodeType: this.nodeType && getTriggerNodeServiceName(this.nodeType.displayName), + nodeType: this.nodeType ? getTriggerNodeServiceName(this.nodeType.displayName) : '', }, }, ); diff --git a/packages/editor-ui/src/components/NodeCreator/CategoryItem.vue b/packages/editor-ui/src/components/NodeCreator/CategoryItem.vue index dcf9bafe1b..a35b4729e6 100644 --- a/packages/editor-ui/src/components/NodeCreator/CategoryItem.vue +++ b/packages/editor-ui/src/components/NodeCreator/CategoryItem.vue @@ -15,6 +15,7 @@ @@ -100,4 +176,39 @@ export default Vue.extend({ display: flex; } +.draggable { + width: 100px; + height: 100px; + position: fixed; + z-index: 1; + opacity: 0.66; + border: 2px solid var(--color-foreground-xdark); + border-radius: var(--border-radius-large); + background-color: var(--color-background-xlight); + display: flex; + justify-content: center; + align-items: center; +} + +.draggable-data-transfer { + width: 1px; + height: 1px; +} + + + diff --git a/packages/editor-ui/src/components/NodeCreator/SubcategoryPanel.vue b/packages/editor-ui/src/components/NodeCreator/SubcategoryPanel.vue index f7d16d5255..75b737b790 100644 --- a/packages/editor-ui/src/components/NodeCreator/SubcategoryPanel.vue +++ b/packages/editor-ui/src/components/NodeCreator/SubcategoryPanel.vue @@ -13,7 +13,9 @@
@@ -38,9 +40,6 @@ export default Vue.extend({ }, }, methods: { - selected(element: INodeCreateElement) { - this.$emit('selected', element); - }, onBackArrowClick() { this.$emit('close'); }, @@ -101,4 +100,4 @@ export default Vue.extend({ } } - \ No newline at end of file + diff --git a/packages/editor-ui/src/views/NodeView.vue b/packages/editor-ui/src/views/NodeView.vue index 18c4b83c73..41a5cc7966 100644 --- a/packages/editor-ui/src/views/NodeView.vue +++ b/packages/editor-ui/src/views/NodeView.vue @@ -1,5 +1,9 @@