n8n/packages/workflow/test/TelemetryHelpers.test.ts

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

894 lines
23 KiB
TypeScript
Raw Normal View History

feat(core): Allow credential reuse on HTTP Request node (#3228) * :sparkles: Create controller * :zap: Mount controller * :pencil2: Add error messages * :sparkles: Create scopes fetcher * :zap: Account for non-existent credential type * :blue_book: Type scopes request * :zap: Adjust error message * :test_tube: Add tests * :sparkles: Introduce simple node versioning * :zap: Add example how to read version in node-code for custom logic * :bug: Fix setting of parameters * :bug: Fix another instance where it sets the wrong parameter * :zap: Remove unnecessary TOODs * :sparkles: Re-version HTTP Request node * :shirt: Satisfy linter * :zap: Retrieve node version * :rewind: Undo Jan's changes to Set node * :test_tube: Fix CI/CD for `/oauth2-credential` tests (#3230) * :bug: Fix notice warning missing background color (#3231) * :bug: Check for generic auth in node cred types * :zap: Refactor credentials dropdown for HTTP Request node (#3222) * :zap: Discoverability flow (#3229) * :sparkles: Added node credentials type proxy. Changed node credentials input order. * :zap: Add computed property from versioning branch * :bug: Fix cred ref lost and unsaved * :zap: Make options consistent with cred type names * :zap: Use prop to set component order * :zap: Use constant and version * :zap: Fix rendering for generic auth creds * :zap: Mark as required on first selection * :zap: Implement discoverability flow * :zap: Mark as required on subsequent selections * :zap: Fix marking as required after cred deletion * :zap: Refactor to clean up * :zap: Detect position automatically * :zap: Add i18n to option label * :zap: Hide subtitle for custom action * :zap: Detect active credential type * :zap: Prop drilling to re-render select * :fire: Remove unneeded property * :pencil2: Rename arg * :fire: Remove unused import * :fire: Remove unneeded getters * :fire: Remove unused import * :zap: Generalize cred component positioning * :zap: Set up request * :bug: Fix edge case in endpoint * :zap: Display scopes alert box * :rewind: Revert "Generalize cred comp positioning" This reverts commit 75eea89273b854110fa6d1f96c7c1d78dd3b0731. * :zap: Consolidate HTTPRN check * :zap: Fix hue percentage to degree * :fire: Remove unused import * :fire: Remove unused import * :fire: Remove unused class * :fire: Remove unused import * :blue_book: Create type for HTTPRN v2 auth params * :pencil2: Rename check * :fire: Remove unused import * :pencil2: Add i18n to `reportUnsetCredential()` * :zap: Refactor Alex's spacing changes * :zap: Post-merge fixes * :zap: Add docs link * :fire: Exclude Notion OAuth cred * :pencil2: Update copy * :pencil2: Rename param * :art: Reposition notice and simplify styling * :pencil2: Update copy * :pencil2: Update copy * :zap: Hide params during custom action * :zap: Show notice if any cred type supported * :bug: Prevent scopes text overflow * :fire: Remove superfluous check * :pencil2: Break up docstring * :art: Tweak notice styling * :zap: Reorder cred param in Webhook node * :pencil2: Shorten cred name in scopes notice * :test_tube: Update Notice snapshots * :bug: Fix check when `globalRole` is `undefined` * :rewind: Revert 3f2c4a6 * :zap: Apply feedback from Product * :test_tube: Update snapshot * :zap: Adjust regex expansion pattern for singular * :fire: Remove unused import * :fire: Remove logging * :zap: Make `somethingElse` key more unique * :zap: Move something else to constants * :zap: Consolidate notice component * :zap: Apply latest feedback * :test_tube: Update tests * :test_tube: Update snapshot * :pencil2: Fix singular version * :test_tube: Finalize tests * :pencil2: Rename constant * :test_tube: Expand tests * :fire: Remove `truncate` prop * :truck: Move scopes fetching to store * :truck: Move method to component * :zap: Use constant * :zap: Refactor `Notice` component * :test_tube: Update tests * :fire: Remove unused keys * :zap: Inject custom API call option * :fire: Remove unused props * :art: Use `compact` prop * :test_tube: Update snapshots * :truck: Move scopes to store * :truck: Move `nodeCredentialTypes` to parent * :pencil2: Rename cred types per branding * :bug: Clear scopes when none * :zap: Add default * :truck: Move `newHttpRequestNodeCredentialType` to parent * :fire: Remove test data * :zap: Separate lines for readability * :zap: Change reference from node to node name * :pencil2: Rename i18n keys * :zap: Refactor OAuth check * :fire: Remove unused key * :truck: Move `OAuth1/2 API` to i18n * :zap: Refactor `skipCheck` * :zap: Add `stopPropagation` and `preventDefault` * :truck: Move active credential scopes logic to store * :art: Fix spacing for `NodeWebhooks` component * :zap: Implement feedback * :zap: Update HTTPRN default and issue copy * Refactor to use `CredentialsSelect` param (#3304) * :zap: Refactor into cred type param * :zap: Componentize scopes notice * :fire: Remove unused data * :fire: Remove unused `loadOptions` * :zap: Componentize `NodeCredentialType` * :bug: Fix param validation * :fire: Remove dup methods * :zap: Refactor all references to `isHttpRequestNodeV2` * :art: Fix styling * :fire: Remove unused import * :fire: Remove unused properties * :art: Fix spacing for Pipedrive Trigger node * :art: Undo Webhook node styling change * :fire: Remove unused style * :zap: Cover `httpHeaderAuth` edge case * :bug: Fix `this.node` reference * :truck: Rename to `credentialsSelect` * :bug: Fix mistaken renaming * :zap: Set one attribute per line * :zap: Move condition to instantiation site * :truck: Rename prop * :zap: Refactor away `prepareScopesNotice` * :pencil2: Rename i18n keys * :pencil2: Update i18n calls * :pencil2: Add more i18n keys * :fire: Remove unused props * :pencil2: Add explanatory comment * :zap: Adjust check in `hasProxyAuth` * :zap: Refactor `credentialSelected` from prop to event * :zap: Eventify `valueChanged`, `setFocus`, `onBlur` * :zap: Eventify `optionSelected` * :zap: Add `noDataExpression` * :fire: Remove logging * :fire: Remove URL from scopes * :zap: Disregard expressions for display * :art: Use CSS modules * :blue_book: Tigthen interface * :bug: Fix generic auth display * :bug: Fix generic auth validation * :blue_book: Loosen type * :truck: Move event params to end * :zap: Generalize reference * :zap: Refactor generic auth as `credentialsSelect` param * :rewind: Restore check for `httpHeaderAuth ` * :truck: Rename `existing` to `predefined` * Extend metrics for HTTP Request node (#3282) * :zap: Extend metrics * :test_tube: Add tests * :zap: Update param names Co-authored-by: Alex Grozav <alex@grozav.com> * :zap: Update check per new branch * :zap: Include generic auth check * :zap: Adjust telemetry (#3359) * :zap: Filter credential types by label Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com> Co-authored-by: Alex Grozav <alex@grozav.com>
2022-05-24 02:36:19 -07:00
import { v5 as uuidv5, v3 as uuidv3, v4 as uuidv4, v1 as uuidv1 } from 'uuid';
import {
ANONYMIZATION_CHARACTER as CHAR,
generateNodesGraph,
getDomainBase,
getDomainPath,
} from '@/TelemetryHelpers';
import { ApplicationError, STICKY_NODE_TYPE, type IWorkflowBase } from '@/index';
import { nodeTypes } from './ExpressionExtensions/Helpers';
import { mock } from 'jest-mock-extended';
import * as nodeHelpers from '@/NodeHelpers';
feat(core): Allow credential reuse on HTTP Request node (#3228) * :sparkles: Create controller * :zap: Mount controller * :pencil2: Add error messages * :sparkles: Create scopes fetcher * :zap: Account for non-existent credential type * :blue_book: Type scopes request * :zap: Adjust error message * :test_tube: Add tests * :sparkles: Introduce simple node versioning * :zap: Add example how to read version in node-code for custom logic * :bug: Fix setting of parameters * :bug: Fix another instance where it sets the wrong parameter * :zap: Remove unnecessary TOODs * :sparkles: Re-version HTTP Request node * :shirt: Satisfy linter * :zap: Retrieve node version * :rewind: Undo Jan's changes to Set node * :test_tube: Fix CI/CD for `/oauth2-credential` tests (#3230) * :bug: Fix notice warning missing background color (#3231) * :bug: Check for generic auth in node cred types * :zap: Refactor credentials dropdown for HTTP Request node (#3222) * :zap: Discoverability flow (#3229) * :sparkles: Added node credentials type proxy. Changed node credentials input order. * :zap: Add computed property from versioning branch * :bug: Fix cred ref lost and unsaved * :zap: Make options consistent with cred type names * :zap: Use prop to set component order * :zap: Use constant and version * :zap: Fix rendering for generic auth creds * :zap: Mark as required on first selection * :zap: Implement discoverability flow * :zap: Mark as required on subsequent selections * :zap: Fix marking as required after cred deletion * :zap: Refactor to clean up * :zap: Detect position automatically * :zap: Add i18n to option label * :zap: Hide subtitle for custom action * :zap: Detect active credential type * :zap: Prop drilling to re-render select * :fire: Remove unneeded property * :pencil2: Rename arg * :fire: Remove unused import * :fire: Remove unneeded getters * :fire: Remove unused import * :zap: Generalize cred component positioning * :zap: Set up request * :bug: Fix edge case in endpoint * :zap: Display scopes alert box * :rewind: Revert "Generalize cred comp positioning" This reverts commit 75eea89273b854110fa6d1f96c7c1d78dd3b0731. * :zap: Consolidate HTTPRN check * :zap: Fix hue percentage to degree * :fire: Remove unused import * :fire: Remove unused import * :fire: Remove unused class * :fire: Remove unused import * :blue_book: Create type for HTTPRN v2 auth params * :pencil2: Rename check * :fire: Remove unused import * :pencil2: Add i18n to `reportUnsetCredential()` * :zap: Refactor Alex's spacing changes * :zap: Post-merge fixes * :zap: Add docs link * :fire: Exclude Notion OAuth cred * :pencil2: Update copy * :pencil2: Rename param * :art: Reposition notice and simplify styling * :pencil2: Update copy * :pencil2: Update copy * :zap: Hide params during custom action * :zap: Show notice if any cred type supported * :bug: Prevent scopes text overflow * :fire: Remove superfluous check * :pencil2: Break up docstring * :art: Tweak notice styling * :zap: Reorder cred param in Webhook node * :pencil2: Shorten cred name in scopes notice * :test_tube: Update Notice snapshots * :bug: Fix check when `globalRole` is `undefined` * :rewind: Revert 3f2c4a6 * :zap: Apply feedback from Product * :test_tube: Update snapshot * :zap: Adjust regex expansion pattern for singular * :fire: Remove unused import * :fire: Remove logging * :zap: Make `somethingElse` key more unique * :zap: Move something else to constants * :zap: Consolidate notice component * :zap: Apply latest feedback * :test_tube: Update tests * :test_tube: Update snapshot * :pencil2: Fix singular version * :test_tube: Finalize tests * :pencil2: Rename constant * :test_tube: Expand tests * :fire: Remove `truncate` prop * :truck: Move scopes fetching to store * :truck: Move method to component * :zap: Use constant * :zap: Refactor `Notice` component * :test_tube: Update tests * :fire: Remove unused keys * :zap: Inject custom API call option * :fire: Remove unused props * :art: Use `compact` prop * :test_tube: Update snapshots * :truck: Move scopes to store * :truck: Move `nodeCredentialTypes` to parent * :pencil2: Rename cred types per branding * :bug: Clear scopes when none * :zap: Add default * :truck: Move `newHttpRequestNodeCredentialType` to parent * :fire: Remove test data * :zap: Separate lines for readability * :zap: Change reference from node to node name * :pencil2: Rename i18n keys * :zap: Refactor OAuth check * :fire: Remove unused key * :truck: Move `OAuth1/2 API` to i18n * :zap: Refactor `skipCheck` * :zap: Add `stopPropagation` and `preventDefault` * :truck: Move active credential scopes logic to store * :art: Fix spacing for `NodeWebhooks` component * :zap: Implement feedback * :zap: Update HTTPRN default and issue copy * Refactor to use `CredentialsSelect` param (#3304) * :zap: Refactor into cred type param * :zap: Componentize scopes notice * :fire: Remove unused data * :fire: Remove unused `loadOptions` * :zap: Componentize `NodeCredentialType` * :bug: Fix param validation * :fire: Remove dup methods * :zap: Refactor all references to `isHttpRequestNodeV2` * :art: Fix styling * :fire: Remove unused import * :fire: Remove unused properties * :art: Fix spacing for Pipedrive Trigger node * :art: Undo Webhook node styling change * :fire: Remove unused style * :zap: Cover `httpHeaderAuth` edge case * :bug: Fix `this.node` reference * :truck: Rename to `credentialsSelect` * :bug: Fix mistaken renaming * :zap: Set one attribute per line * :zap: Move condition to instantiation site * :truck: Rename prop * :zap: Refactor away `prepareScopesNotice` * :pencil2: Rename i18n keys * :pencil2: Update i18n calls * :pencil2: Add more i18n keys * :fire: Remove unused props * :pencil2: Add explanatory comment * :zap: Adjust check in `hasProxyAuth` * :zap: Refactor `credentialSelected` from prop to event * :zap: Eventify `valueChanged`, `setFocus`, `onBlur` * :zap: Eventify `optionSelected` * :zap: Add `noDataExpression` * :fire: Remove logging * :fire: Remove URL from scopes * :zap: Disregard expressions for display * :art: Use CSS modules * :blue_book: Tigthen interface * :bug: Fix generic auth display * :bug: Fix generic auth validation * :blue_book: Loosen type * :truck: Move event params to end * :zap: Generalize reference * :zap: Refactor generic auth as `credentialsSelect` param * :rewind: Restore check for `httpHeaderAuth ` * :truck: Rename `existing` to `predefined` * Extend metrics for HTTP Request node (#3282) * :zap: Extend metrics * :test_tube: Add tests * :zap: Update param names Co-authored-by: Alex Grozav <alex@grozav.com> * :zap: Update check per new branch * :zap: Include generic auth check * :zap: Adjust telemetry (#3359) * :zap: Filter credential types by label Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com> Co-authored-by: Alex Grozav <alex@grozav.com>
2022-05-24 02:36:19 -07:00
describe('getDomainBase should return protocol plus domain', () => {
test('in valid URLs', () => {
for (const url of validUrls(numericId)) {
const { full, protocolPlusDomain } = url;
expect(getDomainBase(full)).toBe(protocolPlusDomain);
}
});
test('in malformed URLs', () => {
for (const url of malformedUrls(numericId)) {
const { full, protocolPlusDomain } = url;
expect(getDomainBase(full)).toBe(protocolPlusDomain);
}
});
});
describe('getDomainPath should return pathname, excluding query string', () => {
describe('anonymizing strings containing at least one number', () => {
test('in valid URLs', () => {
for (const url of validUrls(alphanumericId)) {
const { full, pathname } = url;
expect(getDomainPath(full)).toBe(pathname);
}
});
test('in malformed URLs', () => {
for (const url of malformedUrls(alphanumericId)) {
const { full, pathname } = url;
expect(getDomainPath(full)).toBe(pathname);
}
});
});
describe('anonymizing UUIDs', () => {
test('in valid URLs', () => {
for (const url of uuidUrls(validUrls)) {
const { full, pathname } = url;
expect(getDomainPath(full)).toBe(pathname);
}
});
test('in malformed URLs', () => {
for (const url of uuidUrls(malformedUrls)) {
const { full, pathname } = url;
expect(getDomainPath(full)).toBe(pathname);
}
});
});
describe('anonymizing emails', () => {
test('in valid URLs', () => {
for (const url of validUrls(email)) {
const { full, pathname } = url;
expect(getDomainPath(full)).toBe(pathname);
}
});
test('in malformed URLs', () => {
for (const url of malformedUrls(email)) {
const { full, pathname } = url;
expect(getDomainPath(full)).toBe(pathname);
}
});
});
});
describe('generateNodesGraph', () => {
test('should return node graph when node type is unknown', () => {
const workflow: IWorkflowBase = {
createdAt: new Date('2024-01-05T13:49:14.244Z'),
updatedAt: new Date('2024-01-05T15:44:31.000Z'),
id: 'NfV4GV9aQTifSLc2',
name: 'My workflow 26',
active: false,
nodes: [
{
parameters: {},
id: 'fa7d5628-5a47-4c8f-98ef-fb3532e5a9f5',
name: 'When clicking "Execute Workflow"',
type: 'n8n-nodes-base.manualTrigger',
typeVersion: 1,
position: [420, 420],
},
{
parameters: {
documentId: { __rl: true, mode: 'list', value: '' },
sheetName: { __rl: true, mode: 'list', value: '' },
},
id: '266128b9-e5db-4c26-9555-185d48946afb',
name: 'Google Sheets',
type: 'test.unknown',
typeVersion: 4.2,
position: [640, 420],
},
],
connections: {
'When clicking "Execute Workflow"': {
main: [[{ node: 'Google Sheets', type: 'main', index: 0 }]],
},
},
settings: { executionOrder: 'v1' },
pinData: {},
versionId: '70b92d94-0e9a-4b41-9976-a654df420af5',
};
expect(generateNodesGraph(workflow, nodeTypes)).toEqual({
nodeGraph: {
node_types: ['n8n-nodes-base.manualTrigger', 'test.unknown'],
node_connections: [{ start: '0', end: '1' }],
nodes: {
'0': {
id: 'fa7d5628-5a47-4c8f-98ef-fb3532e5a9f5',
type: 'n8n-nodes-base.manualTrigger',
version: 1,
position: [420, 420],
},
'1': {
id: '266128b9-e5db-4c26-9555-185d48946afb',
type: 'test.unknown',
version: 4.2,
position: [640, 420],
},
},
notes: {},
is_pinned: false,
},
nameIndices: { 'When clicking "Execute Workflow"': '0', 'Google Sheets': '1' },
webhookNodeNames: [],
});
});
test('should return node graph when workflow is empty', () => {
const workflow: IWorkflowBase = {
createdAt: new Date('2024-01-05T13:49:14.244Z'),
updatedAt: new Date('2024-01-05T15:44:31.000Z'),
id: 'NfV4GV9aQTifSLc2',
name: 'My workflow 26',
active: false,
nodes: [],
connections: {},
settings: { executionOrder: 'v1' },
pinData: {},
versionId: '70b92d94-0e9a-4b41-9976-a654df420af5',
};
expect(generateNodesGraph(workflow, nodeTypes)).toEqual({
nodeGraph: {
node_types: [],
node_connections: [],
nodes: {},
notes: {},
is_pinned: false,
},
nameIndices: {},
webhookNodeNames: [],
});
});
test('should return node graph when workflow keys are not set', () => {
const workflow: Partial<IWorkflowBase> = {};
expect(generateNodesGraph(workflow, nodeTypes)).toEqual({
nodeGraph: {
node_types: [],
node_connections: [],
nodes: {},
notes: {},
is_pinned: false,
},
nameIndices: {},
webhookNodeNames: [],
});
});
test('should return node graph when node has multiple operation fields with different display options', () => {
const workflow: IWorkflowBase = {
createdAt: new Date('2024-01-05T13:49:14.244Z'),
updatedAt: new Date('2024-01-05T15:44:31.000Z'),
id: 'NfV4GV9aQTifSLc2',
name: 'My workflow 26',
active: false,
nodes: [
{
parameters: {},
id: 'fa7d5628-5a47-4c8f-98ef-fb3532e5a9f5',
name: 'When clicking "Execute Workflow"',
type: 'n8n-nodes-base.manualTrigger',
typeVersion: 1,
position: [420, 420],
},
{
parameters: {
documentId: { __rl: true, mode: 'list', value: '' },
sheetName: { __rl: true, mode: 'list', value: '' },
},
id: '266128b9-e5db-4c26-9555-185d48946afb',
name: 'Google Sheets',
type: 'test.googleSheets',
typeVersion: 4.2,
position: [640, 420],
},
],
connections: {
'When clicking "Execute Workflow"': {
main: [[{ node: 'Google Sheets', type: 'main', index: 0 }]],
},
},
settings: { executionOrder: 'v1' },
pinData: {},
versionId: '70b92d94-0e9a-4b41-9976-a654df420af5',
};
expect(generateNodesGraph(workflow, nodeTypes)).toEqual({
nodeGraph: {
node_types: ['n8n-nodes-base.manualTrigger', 'test.googleSheets'],
node_connections: [{ start: '0', end: '1' }],
nodes: {
'0': {
id: 'fa7d5628-5a47-4c8f-98ef-fb3532e5a9f5',
type: 'n8n-nodes-base.manualTrigger',
version: 1,
position: [420, 420],
},
'1': {
id: '266128b9-e5db-4c26-9555-185d48946afb',
type: 'test.googleSheets',
version: 4.2,
position: [640, 420],
operation: 'read',
resource: 'sheet',
},
},
notes: {},
is_pinned: false,
},
nameIndices: { 'When clicking "Execute Workflow"': '0', 'Google Sheets': '1' },
webhookNodeNames: [],
});
});
test('should return node graph with stickies of default size', () => {
const workflow: IWorkflowBase = {
createdAt: new Date('2024-01-05T13:49:14.244Z'),
updatedAt: new Date('2024-01-05T15:44:31.000Z'),
id: 'NfV4GV9aQTifSLc2',
name: 'My workflow 26',
active: false,
nodes: [
{
parameters: {},
id: 'fa7d5628-5a47-4c8f-98ef-fb3532e5a9f5',
name: 'When clicking "Execute Workflow"',
type: 'n8n-nodes-base.manualTrigger',
typeVersion: 1,
position: [420, 420],
},
{
parameters: {
documentId: { __rl: true, mode: 'list', value: '' },
sheetName: { __rl: true, mode: 'list', value: '' },
},
id: '266128b9-e5db-4c26-9555-185d48946afb',
name: 'Google Sheets',
type: 'test.googleSheets',
typeVersion: 4.2,
position: [640, 420],
},
{
parameters: {
content:
"test\n\n## I'm a note \n**Double click** to edit me. [Guide](https://docs.n8n.io/workflows/sticky-notes/)",
},
id: '03e85c3e-4303-4f93-8d62-e05d457e8f70',
name: 'Sticky Note',
type: 'n8n-nodes-base.stickyNote',
typeVersion: 1,
position: [240, 140],
},
],
connections: {
'When clicking "Execute Workflow"': {
main: [[{ node: 'Google Sheets', type: 'main', index: 0 }]],
},
},
settings: { executionOrder: 'v1' },
pinData: {},
versionId: '70b92d94-0e9a-4b41-9976-a654df420af5',
};
expect(generateNodesGraph(workflow, nodeTypes)).toEqual({
nodeGraph: {
node_types: ['n8n-nodes-base.manualTrigger', 'test.googleSheets'],
node_connections: [{ start: '0', end: '1' }],
nodes: {
'0': {
id: 'fa7d5628-5a47-4c8f-98ef-fb3532e5a9f5',
type: 'n8n-nodes-base.manualTrigger',
version: 1,
position: [420, 420],
},
'1': {
id: '266128b9-e5db-4c26-9555-185d48946afb',
type: 'test.googleSheets',
version: 4.2,
position: [640, 420],
operation: 'read',
resource: 'sheet',
},
},
notes: { '0': { overlapping: false, position: [240, 140], height: 160, width: 240 } },
is_pinned: false,
},
nameIndices: { 'When clicking "Execute Workflow"': '0', 'Google Sheets': '1' },
webhookNodeNames: [],
});
});
test('should return node graph with stickies indicating overlap', () => {
const workflow: IWorkflowBase = {
createdAt: new Date('2024-01-05T13:49:14.244Z'),
updatedAt: new Date('2024-01-05T15:44:31.000Z'),
id: 'NfV4GV9aQTifSLc2',
name: 'My workflow 26',
active: false,
nodes: [
{
parameters: {},
id: 'fa7d5628-5a47-4c8f-98ef-fb3532e5a9f5',
name: 'When clicking "Execute Workflow"',
type: 'n8n-nodes-base.manualTrigger',
typeVersion: 1,
position: [420, 420],
},
{
parameters: {
documentId: { __rl: true, mode: 'list', value: '' },
sheetName: { __rl: true, mode: 'list', value: '' },
},
id: '266128b9-e5db-4c26-9555-185d48946afb',
name: 'Google Sheets',
type: 'test.googleSheets',
typeVersion: 4.2,
position: [640, 420],
},
{
parameters: {
content:
"test\n\n## I'm a note \n**Double click** to edit me. [Guide](https://docs.n8n.io/workflows/sticky-notes/)",
height: 488,
width: 645,
},
id: '03e85c3e-4303-4f93-8d62-e05d457e8f70',
name: 'Sticky Note',
type: 'n8n-nodes-base.stickyNote',
typeVersion: 1,
position: [240, 140],
},
],
connections: {
'When clicking "Execute Workflow"': {
main: [[{ node: 'Google Sheets', type: 'main', index: 0 }]],
},
},
settings: { executionOrder: 'v1' },
pinData: {},
versionId: '70b92d94-0e9a-4b41-9976-a654df420af5',
};
expect(generateNodesGraph(workflow, nodeTypes)).toEqual({
nodeGraph: {
node_types: ['n8n-nodes-base.manualTrigger', 'test.googleSheets'],
node_connections: [{ start: '0', end: '1' }],
nodes: {
'0': {
id: 'fa7d5628-5a47-4c8f-98ef-fb3532e5a9f5',
type: 'n8n-nodes-base.manualTrigger',
version: 1,
position: [420, 420],
},
'1': {
id: '266128b9-e5db-4c26-9555-185d48946afb',
type: 'test.googleSheets',
version: 4.2,
position: [640, 420],
operation: 'read',
resource: 'sheet',
},
},
notes: { '0': { overlapping: true, position: [240, 140], height: 488, width: 645 } },
is_pinned: false,
},
nameIndices: { 'When clicking "Execute Workflow"': '0', 'Google Sheets': '1' },
webhookNodeNames: [],
});
});
test('should return node graph indicating pinned data', () => {
const workflow: Partial<IWorkflowBase> = {
nodes: [
{
parameters: {},
id: 'e59d3ad9-3448-4899-9f47-d2922c8727ce',
name: 'When clicking "Execute Workflow"',
type: 'n8n-nodes-base.manualTrigger',
typeVersion: 1,
position: [460, 460],
},
],
connections: {},
pinData: {
'When clicking "Execute Workflow"': [],
},
};
expect(generateNodesGraph(workflow, nodeTypes)).toEqual({
nameIndices: {
'When clicking "Execute Workflow"': '0',
},
nodeGraph: {
is_pinned: true,
node_connections: [],
node_types: ['n8n-nodes-base.manualTrigger'],
nodes: {
'0': {
id: 'e59d3ad9-3448-4899-9f47-d2922c8727ce',
position: [460, 460],
type: 'n8n-nodes-base.manualTrigger',
version: 1,
},
},
notes: {},
},
webhookNodeNames: [],
});
});
test('should return graph with webhook node', () => {
const workflow: Partial<IWorkflowBase> = {
nodes: [
{
parameters: {
path: 'bf4c0699-cff8-4440-8964-8e97fda8b4f8',
options: {},
},
id: '5e49e129-2c59-4650-95ea-14d4b94db1f3',
name: 'Webhook',
type: 'n8n-nodes-base.webhook',
typeVersion: 1.1,
position: [520, 380],
webhookId: 'bf4c0699-cff8-4440-8964-8e97fda8b4f8',
},
],
connections: {},
pinData: {},
};
expect(generateNodesGraph(workflow, nodeTypes)).toEqual({
nodeGraph: {
node_types: ['n8n-nodes-base.webhook'],
node_connections: [],
nodes: {
'0': {
id: '5e49e129-2c59-4650-95ea-14d4b94db1f3',
type: 'n8n-nodes-base.webhook',
version: 1.1,
position: [520, 380],
},
},
notes: {},
is_pinned: false,
},
nameIndices: { Webhook: '0' },
webhookNodeNames: ['Webhook'],
});
});
test('should return graph with http v4 node with generic auth', () => {
const workflow: Partial<IWorkflowBase> = {
nodes: [
{
parameters: {
url: 'google.com/path/test',
authentication: 'genericCredentialType',
genericAuthType: 'httpBasicAuth',
options: {},
},
id: '04d6e44f-09c1-454d-9225-60aeed7f022c',
name: 'HTTP Request V4 with generic auth',
type: 'n8n-nodes-base.httpRequest',
typeVersion: 4.1,
position: [780, 120],
credentials: {
httpBasicAuth: {
id: 'yuuJAO2Ang5B64wd',
name: 'Unnamed credential',
},
},
},
],
connections: {},
pinData: {},
};
expect(generateNodesGraph(workflow, nodeTypes)).toEqual({
nodeGraph: {
node_types: ['n8n-nodes-base.httpRequest'],
node_connections: [],
nodes: {
'0': {
id: '04d6e44f-09c1-454d-9225-60aeed7f022c',
type: 'n8n-nodes-base.httpRequest',
version: 4.1,
position: [780, 120],
credential_type: 'httpBasicAuth',
credential_set: true,
domain_base: 'google.com',
domain_path: '/path/test',
},
},
notes: {},
is_pinned: false,
},
nameIndices: { 'HTTP Request V4 with generic auth': '0' },
webhookNodeNames: [],
});
});
test('should return graph with HTTP V4 with predefined cred', () => {
const workflow: Partial<IWorkflowBase> = {
nodes: [
{
parameters: {
url: 'google.com/path/test',
authentication: 'predefinedCredentialType',
nodeCredentialType: 'activeCampaignApi',
options: {},
},
id: 'dcc4a9e1-c2c5-4d7e-aec0-2a23adabbb77',
name: 'HTTP Request V4 with predefined cred',
type: 'n8n-nodes-base.httpRequest',
typeVersion: 4.1,
position: [320, 220],
credentials: {
httpBasicAuth: {
id: 'yuuJAO2Ang5B64wd',
name: 'Unnamed credential',
},
activeCampaignApi: {
id: 'SFCbnfgRBuSzRu6N',
name: 'ActiveCampaign account',
},
},
},
],
connections: {},
pinData: {},
};
expect(generateNodesGraph(workflow, nodeTypes)).toEqual({
nodeGraph: {
node_types: ['n8n-nodes-base.httpRequest'],
node_connections: [],
nodes: {
'0': {
id: 'dcc4a9e1-c2c5-4d7e-aec0-2a23adabbb77',
type: 'n8n-nodes-base.httpRequest',
version: 4.1,
position: [320, 220],
credential_type: 'activeCampaignApi',
credential_set: true,
domain_base: 'google.com',
domain_path: '/path/test',
},
},
notes: {},
is_pinned: false,
},
nameIndices: { 'HTTP Request V4 with predefined cred': '0' },
webhookNodeNames: [],
});
});
test('should return graph with http v1 node', () => {
const workflow: Partial<IWorkflowBase> = {
nodes: [
{
parameters: {
url: 'https://google.com',
options: {},
},
id: 'b468b603-3e59-4515-b555-90cfebd64d47',
name: 'HTTP Request V1',
type: 'n8n-nodes-base.httpRequest',
typeVersion: 1,
position: [320, 460],
},
],
connections: {},
pinData: {},
};
expect(generateNodesGraph(workflow, nodeTypes)).toEqual({
nodeGraph: {
node_types: ['n8n-nodes-base.httpRequest'],
node_connections: [],
nodes: {
'0': {
id: 'b468b603-3e59-4515-b555-90cfebd64d47',
type: 'n8n-nodes-base.httpRequest',
version: 1,
position: [320, 460],
domain: 'google.com',
},
},
notes: {},
is_pinned: false,
},
nameIndices: { 'HTTP Request V1': '0' },
webhookNodeNames: [],
});
});
test('should return graph with http v4 node with no parameters and no credentials', () => {
const workflow: Partial<IWorkflowBase> = {
nodes: [
{
parameters: {
options: {},
},
id: 'd002e66f-deba-455c-9f8b-65239db453c3',
name: 'HTTP Request v4 with defaults',
type: 'n8n-nodes-base.httpRequest',
typeVersion: 4.1,
position: [600, 240],
},
],
connections: {},
pinData: {},
};
expect(generateNodesGraph(workflow, nodeTypes)).toEqual({
nodeGraph: {
node_types: ['n8n-nodes-base.httpRequest'],
node_connections: [],
nodes: {
'0': {
id: 'd002e66f-deba-455c-9f8b-65239db453c3',
type: 'n8n-nodes-base.httpRequest',
version: 4.1,
position: [600, 240],
credential_set: false,
domain_base: '',
domain_path: '',
},
},
notes: {},
is_pinned: false,
},
nameIndices: { 'HTTP Request v4 with defaults': '0' },
webhookNodeNames: [],
});
});
test('should support custom connections like in AI nodes', () => {
const workflow: Partial<IWorkflowBase> = {
nodes: [
{
parameters: {},
id: 'fe69383c-e418-4f98-9c0e-924deafa7f93',
name: 'When clicking "Test workflow"',
type: 'n8n-nodes-base.manualTrigger',
typeVersion: 1,
position: [540, 220],
},
{
parameters: {},
id: 'c5c374f1-6fad-46bb-8eea-ceec126b300a',
name: 'Chain',
type: '@n8n/n8n-nodes-langchain.chainLlm',
typeVersion: 1,
position: [760, 320],
},
{
parameters: {
options: {},
},
id: '198133b6-95dd-4f7e-90e5-e16c4cdbad12',
name: 'Model',
type: '@n8n/n8n-nodes-langchain.lmChatOpenAi',
typeVersion: 1,
position: [780, 500],
},
],
connections: {
'When clicking "Test workflow"': {
main: [
[
{
node: 'Chain',
type: 'main',
index: 0,
},
],
],
},
Model: {
ai_languageModel: [
[
{
node: 'Chain',
type: 'ai_languageModel',
index: 0,
},
],
],
},
},
};
expect(generateNodesGraph(workflow, nodeTypes)).toEqual({
nodeGraph: {
node_types: [
'n8n-nodes-base.manualTrigger',
'@n8n/n8n-nodes-langchain.chainLlm',
'@n8n/n8n-nodes-langchain.lmChatOpenAi',
],
node_connections: [
{
start: '0',
end: '1',
},
{
start: '2',
end: '1',
},
],
nodes: {
'0': {
id: 'fe69383c-e418-4f98-9c0e-924deafa7f93',
type: 'n8n-nodes-base.manualTrigger',
version: 1,
position: [540, 220],
},
'1': {
id: 'c5c374f1-6fad-46bb-8eea-ceec126b300a',
type: '@n8n/n8n-nodes-langchain.chainLlm',
version: 1,
position: [760, 320],
},
'2': {
id: '198133b6-95dd-4f7e-90e5-e16c4cdbad12',
type: '@n8n/n8n-nodes-langchain.lmChatOpenAi',
version: 1,
position: [780, 500],
},
},
notes: {},
is_pinned: false,
},
nameIndices: {
'When clicking "Test workflow"': '0',
Chain: '1',
Model: '2',
},
webhookNodeNames: [],
});
});
test('should not fail on error to resolve a node parameter for sticky node type', () => {
const workflow = mock<IWorkflowBase>({ nodes: [{ type: STICKY_NODE_TYPE }] });
jest.spyOn(nodeHelpers, 'getNodeParameters').mockImplementationOnce(() => {
throw new ApplicationError('Could not find property option');
});
expect(() => generateNodesGraph(workflow, nodeTypes)).not.toThrow();
});
});
feat(core): Allow credential reuse on HTTP Request node (#3228) * :sparkles: Create controller * :zap: Mount controller * :pencil2: Add error messages * :sparkles: Create scopes fetcher * :zap: Account for non-existent credential type * :blue_book: Type scopes request * :zap: Adjust error message * :test_tube: Add tests * :sparkles: Introduce simple node versioning * :zap: Add example how to read version in node-code for custom logic * :bug: Fix setting of parameters * :bug: Fix another instance where it sets the wrong parameter * :zap: Remove unnecessary TOODs * :sparkles: Re-version HTTP Request node * :shirt: Satisfy linter * :zap: Retrieve node version * :rewind: Undo Jan's changes to Set node * :test_tube: Fix CI/CD for `/oauth2-credential` tests (#3230) * :bug: Fix notice warning missing background color (#3231) * :bug: Check for generic auth in node cred types * :zap: Refactor credentials dropdown for HTTP Request node (#3222) * :zap: Discoverability flow (#3229) * :sparkles: Added node credentials type proxy. Changed node credentials input order. * :zap: Add computed property from versioning branch * :bug: Fix cred ref lost and unsaved * :zap: Make options consistent with cred type names * :zap: Use prop to set component order * :zap: Use constant and version * :zap: Fix rendering for generic auth creds * :zap: Mark as required on first selection * :zap: Implement discoverability flow * :zap: Mark as required on subsequent selections * :zap: Fix marking as required after cred deletion * :zap: Refactor to clean up * :zap: Detect position automatically * :zap: Add i18n to option label * :zap: Hide subtitle for custom action * :zap: Detect active credential type * :zap: Prop drilling to re-render select * :fire: Remove unneeded property * :pencil2: Rename arg * :fire: Remove unused import * :fire: Remove unneeded getters * :fire: Remove unused import * :zap: Generalize cred component positioning * :zap: Set up request * :bug: Fix edge case in endpoint * :zap: Display scopes alert box * :rewind: Revert "Generalize cred comp positioning" This reverts commit 75eea89273b854110fa6d1f96c7c1d78dd3b0731. * :zap: Consolidate HTTPRN check * :zap: Fix hue percentage to degree * :fire: Remove unused import * :fire: Remove unused import * :fire: Remove unused class * :fire: Remove unused import * :blue_book: Create type for HTTPRN v2 auth params * :pencil2: Rename check * :fire: Remove unused import * :pencil2: Add i18n to `reportUnsetCredential()` * :zap: Refactor Alex's spacing changes * :zap: Post-merge fixes * :zap: Add docs link * :fire: Exclude Notion OAuth cred * :pencil2: Update copy * :pencil2: Rename param * :art: Reposition notice and simplify styling * :pencil2: Update copy * :pencil2: Update copy * :zap: Hide params during custom action * :zap: Show notice if any cred type supported * :bug: Prevent scopes text overflow * :fire: Remove superfluous check * :pencil2: Break up docstring * :art: Tweak notice styling * :zap: Reorder cred param in Webhook node * :pencil2: Shorten cred name in scopes notice * :test_tube: Update Notice snapshots * :bug: Fix check when `globalRole` is `undefined` * :rewind: Revert 3f2c4a6 * :zap: Apply feedback from Product * :test_tube: Update snapshot * :zap: Adjust regex expansion pattern for singular * :fire: Remove unused import * :fire: Remove logging * :zap: Make `somethingElse` key more unique * :zap: Move something else to constants * :zap: Consolidate notice component * :zap: Apply latest feedback * :test_tube: Update tests * :test_tube: Update snapshot * :pencil2: Fix singular version * :test_tube: Finalize tests * :pencil2: Rename constant * :test_tube: Expand tests * :fire: Remove `truncate` prop * :truck: Move scopes fetching to store * :truck: Move method to component * :zap: Use constant * :zap: Refactor `Notice` component * :test_tube: Update tests * :fire: Remove unused keys * :zap: Inject custom API call option * :fire: Remove unused props * :art: Use `compact` prop * :test_tube: Update snapshots * :truck: Move scopes to store * :truck: Move `nodeCredentialTypes` to parent * :pencil2: Rename cred types per branding * :bug: Clear scopes when none * :zap: Add default * :truck: Move `newHttpRequestNodeCredentialType` to parent * :fire: Remove test data * :zap: Separate lines for readability * :zap: Change reference from node to node name * :pencil2: Rename i18n keys * :zap: Refactor OAuth check * :fire: Remove unused key * :truck: Move `OAuth1/2 API` to i18n * :zap: Refactor `skipCheck` * :zap: Add `stopPropagation` and `preventDefault` * :truck: Move active credential scopes logic to store * :art: Fix spacing for `NodeWebhooks` component * :zap: Implement feedback * :zap: Update HTTPRN default and issue copy * Refactor to use `CredentialsSelect` param (#3304) * :zap: Refactor into cred type param * :zap: Componentize scopes notice * :fire: Remove unused data * :fire: Remove unused `loadOptions` * :zap: Componentize `NodeCredentialType` * :bug: Fix param validation * :fire: Remove dup methods * :zap: Refactor all references to `isHttpRequestNodeV2` * :art: Fix styling * :fire: Remove unused import * :fire: Remove unused properties * :art: Fix spacing for Pipedrive Trigger node * :art: Undo Webhook node styling change * :fire: Remove unused style * :zap: Cover `httpHeaderAuth` edge case * :bug: Fix `this.node` reference * :truck: Rename to `credentialsSelect` * :bug: Fix mistaken renaming * :zap: Set one attribute per line * :zap: Move condition to instantiation site * :truck: Rename prop * :zap: Refactor away `prepareScopesNotice` * :pencil2: Rename i18n keys * :pencil2: Update i18n calls * :pencil2: Add more i18n keys * :fire: Remove unused props * :pencil2: Add explanatory comment * :zap: Adjust check in `hasProxyAuth` * :zap: Refactor `credentialSelected` from prop to event * :zap: Eventify `valueChanged`, `setFocus`, `onBlur` * :zap: Eventify `optionSelected` * :zap: Add `noDataExpression` * :fire: Remove logging * :fire: Remove URL from scopes * :zap: Disregard expressions for display * :art: Use CSS modules * :blue_book: Tigthen interface * :bug: Fix generic auth display * :bug: Fix generic auth validation * :blue_book: Loosen type * :truck: Move event params to end * :zap: Generalize reference * :zap: Refactor generic auth as `credentialsSelect` param * :rewind: Restore check for `httpHeaderAuth ` * :truck: Rename `existing` to `predefined` * Extend metrics for HTTP Request node (#3282) * :zap: Extend metrics * :test_tube: Add tests * :zap: Update param names Co-authored-by: Alex Grozav <alex@grozav.com> * :zap: Update check per new branch * :zap: Include generic auth check * :zap: Adjust telemetry (#3359) * :zap: Filter credential types by label Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com> Co-authored-by: Alex Grozav <alex@grozav.com>
2022-05-24 02:36:19 -07:00
function validUrls(idMaker: typeof alphanumericId | typeof email, char = CHAR) {
const firstId = idMaker();
const secondId = idMaker();
const firstIdObscured = char.repeat(firstId.length);
const secondIdObscured = char.repeat(secondId.length);
return [
{
full: `https://test.com/api/v1/users/${firstId}`,
protocolPlusDomain: 'https://test.com',
pathname: `/api/v1/users/${firstIdObscured}`,
},
{
full: `https://test.com/api/v1/users/${firstId}/`,
protocolPlusDomain: 'https://test.com',
pathname: `/api/v1/users/${firstIdObscured}/`,
},
{
full: `https://test.com/api/v1/users/${firstId}/posts/${secondId}`,
protocolPlusDomain: 'https://test.com',
pathname: `/api/v1/users/${firstIdObscured}/posts/${secondIdObscured}`,
},
{
full: `https://test.com/api/v1/users/${firstId}/posts/${secondId}/`,
protocolPlusDomain: 'https://test.com',
pathname: `/api/v1/users/${firstIdObscured}/posts/${secondIdObscured}/`,
},
{
full: `https://test.com/api/v1/users/${firstId}/posts/${secondId}/`,
protocolPlusDomain: 'https://test.com',
pathname: `/api/v1/users/${firstIdObscured}/posts/${secondIdObscured}/`,
},
{
full: `https://test.com/api/v1/users?id=${firstId}`,
protocolPlusDomain: 'https://test.com',
pathname: '/api/v1/users',
},
{
full: `https://test.com/api/v1/users?id=${firstId}&post=${secondId}`,
protocolPlusDomain: 'https://test.com',
pathname: '/api/v1/users',
},
{
full: `https://test.com/api/v1/users/${firstId}/posts/${secondId}`,
protocolPlusDomain: 'https://test.com',
pathname: `/api/v1/users/${firstIdObscured}/posts/${secondIdObscured}`,
},
];
}
function malformedUrls(idMaker: typeof numericId | typeof email, char = CHAR) {
const firstId = idMaker();
const secondId = idMaker();
const firstIdObscured = char.repeat(firstId.length);
const secondIdObscured = char.repeat(secondId.length);
return [
{
full: `test.com/api/v1/users/${firstId}/posts/${secondId}/`,
protocolPlusDomain: 'test.com',
pathname: `/api/v1/users/${firstIdObscured}/posts/${secondIdObscured}/`,
},
{
full: `htp://test.com/api/v1/users/${firstId}/posts/${secondId}/`,
protocolPlusDomain: 'htp://test.com',
pathname: `/api/v1/users/${firstIdObscured}/posts/${secondIdObscured}/`,
},
{
full: `test.com/api/v1/users?id=${firstId}`,
protocolPlusDomain: 'test.com',
pathname: '/api/v1/users',
},
{
full: `test.com/api/v1/users?id=${firstId}&post=${secondId}`,
protocolPlusDomain: 'test.com',
pathname: '/api/v1/users',
},
];
}
const email = () => encodeURIComponent('test@test.com');
function uuidUrls(
urlsMaker: typeof validUrls | typeof malformedUrls,
baseName = 'test',
namespaceUuid = uuidv4(),
) {
return [
...urlsMaker(() => uuidv5(baseName, namespaceUuid)),
...urlsMaker(uuidv4),
...urlsMaker(() => uuidv3(baseName, namespaceUuid)),
...urlsMaker(uuidv1),
];
}
function digit() {
return Math.floor(Math.random() * 10);
}
function positiveDigit(): number {
const d = digit();
return d === 0 ? positiveDigit() : d;
}
function numericId(length = positiveDigit()) {
return Array.from({ length }, digit).join('');
}
function alphanumericId() {
return chooseRandomly([`john${numericId()}`, `title${numericId(1)}`, numericId()]);
feat(core): Allow credential reuse on HTTP Request node (#3228) * :sparkles: Create controller * :zap: Mount controller * :pencil2: Add error messages * :sparkles: Create scopes fetcher * :zap: Account for non-existent credential type * :blue_book: Type scopes request * :zap: Adjust error message * :test_tube: Add tests * :sparkles: Introduce simple node versioning * :zap: Add example how to read version in node-code for custom logic * :bug: Fix setting of parameters * :bug: Fix another instance where it sets the wrong parameter * :zap: Remove unnecessary TOODs * :sparkles: Re-version HTTP Request node * :shirt: Satisfy linter * :zap: Retrieve node version * :rewind: Undo Jan's changes to Set node * :test_tube: Fix CI/CD for `/oauth2-credential` tests (#3230) * :bug: Fix notice warning missing background color (#3231) * :bug: Check for generic auth in node cred types * :zap: Refactor credentials dropdown for HTTP Request node (#3222) * :zap: Discoverability flow (#3229) * :sparkles: Added node credentials type proxy. Changed node credentials input order. * :zap: Add computed property from versioning branch * :bug: Fix cred ref lost and unsaved * :zap: Make options consistent with cred type names * :zap: Use prop to set component order * :zap: Use constant and version * :zap: Fix rendering for generic auth creds * :zap: Mark as required on first selection * :zap: Implement discoverability flow * :zap: Mark as required on subsequent selections * :zap: Fix marking as required after cred deletion * :zap: Refactor to clean up * :zap: Detect position automatically * :zap: Add i18n to option label * :zap: Hide subtitle for custom action * :zap: Detect active credential type * :zap: Prop drilling to re-render select * :fire: Remove unneeded property * :pencil2: Rename arg * :fire: Remove unused import * :fire: Remove unneeded getters * :fire: Remove unused import * :zap: Generalize cred component positioning * :zap: Set up request * :bug: Fix edge case in endpoint * :zap: Display scopes alert box * :rewind: Revert "Generalize cred comp positioning" This reverts commit 75eea89273b854110fa6d1f96c7c1d78dd3b0731. * :zap: Consolidate HTTPRN check * :zap: Fix hue percentage to degree * :fire: Remove unused import * :fire: Remove unused import * :fire: Remove unused class * :fire: Remove unused import * :blue_book: Create type for HTTPRN v2 auth params * :pencil2: Rename check * :fire: Remove unused import * :pencil2: Add i18n to `reportUnsetCredential()` * :zap: Refactor Alex's spacing changes * :zap: Post-merge fixes * :zap: Add docs link * :fire: Exclude Notion OAuth cred * :pencil2: Update copy * :pencil2: Rename param * :art: Reposition notice and simplify styling * :pencil2: Update copy * :pencil2: Update copy * :zap: Hide params during custom action * :zap: Show notice if any cred type supported * :bug: Prevent scopes text overflow * :fire: Remove superfluous check * :pencil2: Break up docstring * :art: Tweak notice styling * :zap: Reorder cred param in Webhook node * :pencil2: Shorten cred name in scopes notice * :test_tube: Update Notice snapshots * :bug: Fix check when `globalRole` is `undefined` * :rewind: Revert 3f2c4a6 * :zap: Apply feedback from Product * :test_tube: Update snapshot * :zap: Adjust regex expansion pattern for singular * :fire: Remove unused import * :fire: Remove logging * :zap: Make `somethingElse` key more unique * :zap: Move something else to constants * :zap: Consolidate notice component * :zap: Apply latest feedback * :test_tube: Update tests * :test_tube: Update snapshot * :pencil2: Fix singular version * :test_tube: Finalize tests * :pencil2: Rename constant * :test_tube: Expand tests * :fire: Remove `truncate` prop * :truck: Move scopes fetching to store * :truck: Move method to component * :zap: Use constant * :zap: Refactor `Notice` component * :test_tube: Update tests * :fire: Remove unused keys * :zap: Inject custom API call option * :fire: Remove unused props * :art: Use `compact` prop * :test_tube: Update snapshots * :truck: Move scopes to store * :truck: Move `nodeCredentialTypes` to parent * :pencil2: Rename cred types per branding * :bug: Clear scopes when none * :zap: Add default * :truck: Move `newHttpRequestNodeCredentialType` to parent * :fire: Remove test data * :zap: Separate lines for readability * :zap: Change reference from node to node name * :pencil2: Rename i18n keys * :zap: Refactor OAuth check * :fire: Remove unused key * :truck: Move `OAuth1/2 API` to i18n * :zap: Refactor `skipCheck` * :zap: Add `stopPropagation` and `preventDefault` * :truck: Move active credential scopes logic to store * :art: Fix spacing for `NodeWebhooks` component * :zap: Implement feedback * :zap: Update HTTPRN default and issue copy * Refactor to use `CredentialsSelect` param (#3304) * :zap: Refactor into cred type param * :zap: Componentize scopes notice * :fire: Remove unused data * :fire: Remove unused `loadOptions` * :zap: Componentize `NodeCredentialType` * :bug: Fix param validation * :fire: Remove dup methods * :zap: Refactor all references to `isHttpRequestNodeV2` * :art: Fix styling * :fire: Remove unused import * :fire: Remove unused properties * :art: Fix spacing for Pipedrive Trigger node * :art: Undo Webhook node styling change * :fire: Remove unused style * :zap: Cover `httpHeaderAuth` edge case * :bug: Fix `this.node` reference * :truck: Rename to `credentialsSelect` * :bug: Fix mistaken renaming * :zap: Set one attribute per line * :zap: Move condition to instantiation site * :truck: Rename prop * :zap: Refactor away `prepareScopesNotice` * :pencil2: Rename i18n keys * :pencil2: Update i18n calls * :pencil2: Add more i18n keys * :fire: Remove unused props * :pencil2: Add explanatory comment * :zap: Adjust check in `hasProxyAuth` * :zap: Refactor `credentialSelected` from prop to event * :zap: Eventify `valueChanged`, `setFocus`, `onBlur` * :zap: Eventify `optionSelected` * :zap: Add `noDataExpression` * :fire: Remove logging * :fire: Remove URL from scopes * :zap: Disregard expressions for display * :art: Use CSS modules * :blue_book: Tigthen interface * :bug: Fix generic auth display * :bug: Fix generic auth validation * :blue_book: Loosen type * :truck: Move event params to end * :zap: Generalize reference * :zap: Refactor generic auth as `credentialsSelect` param * :rewind: Restore check for `httpHeaderAuth ` * :truck: Rename `existing` to `predefined` * Extend metrics for HTTP Request node (#3282) * :zap: Extend metrics * :test_tube: Add tests * :zap: Update param names Co-authored-by: Alex Grozav <alex@grozav.com> * :zap: Update check per new branch * :zap: Include generic auth check * :zap: Adjust telemetry (#3359) * :zap: Filter credential types by label Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com> Co-authored-by: Alex Grozav <alex@grozav.com>
2022-05-24 02:36:19 -07:00
}
const chooseRandomly = <T>(array: T[]) => array[Math.floor(Math.random() * array.length)];