Skip to content

Commit

Permalink
Merge branch 'master' into node-158-graphql-node-doesnt-throw-errors-…
Browse files Browse the repository at this point in the history
…outputs-item-with-error
  • Loading branch information
maspio committed Aug 18, 2023
2 parents bd2ad70 + 270946a commit bec4169
Show file tree
Hide file tree
Showing 46 changed files with 562 additions and 223 deletions.
1 change: 0 additions & 1 deletion .vscode/settings.default.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
"typescript.format.enable": false,
"typescript.tsdk": "node_modules/typescript/lib",
"workspace-default-settings.runOnActivation": true,
"prettier.prettierPath": "node_modules/prettier",
"eslint.probe": ["javascript", "typescript", "vue"],
"eslint.workingDirectories": [
{
Expand Down
67 changes: 67 additions & 0 deletions cypress/e2e/27-opt-in-trial-banner.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { BannerStack, MainSidebar, WorkflowPage } from '../pages';
import planData from '../fixtures/Plan_data_opt_in_trial.json';
import { INSTANCE_OWNER } from '../constants';

const mainSidebar = new MainSidebar();
const bannerStack = new BannerStack();
const workflowPage = new WorkflowPage();

describe('BannerStack', { disableAutoLogin: true }, () => {
before(() => {
const now = new Date();
const fiveDaysFromNow = new Date(now.getTime() + 5 * 24 * 60 * 60 * 1000);
planData.expirationDate = fiveDaysFromNow.toJSON();
});

it('should render trial banner for opt-in cloud user', () => {
cy.intercept('GET', '/rest/settings', (req) => {
req.on('response', (res) => {
res.send({
data: { ...res.body.data, deployment: { type: 'cloud' }, n8nMetadata: { userId: 1 } },
});
});
}).as('loadSettings');

cy.intercept('GET', '/rest/admin/cloud-plan', {
body: planData,
}).as('getPlanData');

cy.signin({ email: INSTANCE_OWNER.email, password: INSTANCE_OWNER.password });

cy.visit(workflowPage.url);

cy.wait('@getPlanData');

bannerStack.getters.banner().should('be.visible');

mainSidebar.actions.signout();

bannerStack.getters.banner().should('not.be.visible');

cy.signin({ email: INSTANCE_OWNER.email, password: INSTANCE_OWNER.password });

cy.visit(workflowPage.url);

bannerStack.getters.banner().should('be.visible');

mainSidebar.actions.signout();
});

it('should not render opt-in-trial banner for non cloud deployment', () => {
cy.intercept('GET', '/rest/settings', (req) => {
req.on('response', (res) => {
res.send({
data: { ...res.body.data, deployment: { type: 'default' } },
});
});
}).as('loadSettings');

cy.signin({ email: INSTANCE_OWNER.email, password: INSTANCE_OWNER.password });

cy.visit(workflowPage.url);

bannerStack.getters.banner().should('not.be.visible');

mainSidebar.actions.signout();
});
});
29 changes: 29 additions & 0 deletions cypress/fixtures/Plan_data_opt_in_trial.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"id": 200,
"planId": 1,
"pruneExecutionsInterval": 168,
"monthlyExecutionsLimit": 1000,
"activeWorkflowsLimit": 20,
"credentialsLimit": 100,
"supportTier": "community",
"displayName": "Trial",
"enabledFeatures": ["userManagement", "advancedExecutionFilters", "sharing"],
"licenseFeatures": {
"feat:sharing": true,
"feat:advancedExecutionFilters": true,
"quota:users": -1,
"quota:maxVariables": -1,
"feat:variables": true,
"feat:apiDisabled": true
},
"metadata": {
"version": "v1",
"group": "trial",
"slug": "trial-2",
"trial": {
"length": 14,
"gracePeriod": 3
}
},
"expirationDate": "2023-08-30T15:47:27.611Z"
}
8 changes: 8 additions & 0 deletions cypress/pages/bannerStack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { BasePage } from './base';

export class BannerStack extends BasePage {
getters = {
banner: () => cy.getByTestId('banner-stack'),
};
actions = {};
}
1 change: 1 addition & 0 deletions cypress/pages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export * from './settings-users';
export * from './settings-log-streaming';
export * from './sidebar';
export * from './ndv';
export * from './bannerStack';
13 changes: 12 additions & 1 deletion cypress/pages/sidebar/main-sidebar.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { BasePage } from '../base';
import { WorkflowsPage } from '../workflows';

export class MainSidebar extends BasePage {
getters = {
Expand All @@ -9,7 +10,7 @@ export class MainSidebar extends BasePage {
workflows: () => this.getters.menuItem('Workflows'),
credentials: () => this.getters.menuItem('Credentials'),
executions: () => this.getters.menuItem('Executions'),
userMenu: () => cy.getByTestId('main-sidebar-user-menu'),
userMenu: () => cy.get('div[class="action-dropdown-container"]'),
};
actions = {
goToSettings: () => {
Expand All @@ -26,5 +27,15 @@ export class MainSidebar extends BasePage {
openUserMenu: () => {
this.getters.userMenu().find('[role="button"]').last().click();
},
openUserMenu: () => {
this.getters.userMenu().click();
},
signout: () => {
const workflowsPage = new WorkflowsPage();
cy.visit(workflowsPage.url);
this.actions.openUserMenu();
cy.getByTestId('user-menu-item-logout').click();
cy.wrap(Cypress.session.clearAllSavedSessions());
},
};
}
17 changes: 2 additions & 15 deletions packages/cli/src/ActiveWebhooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,25 +63,13 @@ export class ActiveWebhooks {
this.webhookUrls[webhookKey].push(webhookData);

try {
const webhookExists = await workflow.runWebhookMethod(
'checkExists',
await workflow.createWebhookIfNotExists(
webhookData,
NodeExecuteFunctions,
mode,
activation,
this.testWebhooks,
);
if (webhookExists !== true) {
// If webhook does not exist yet create it
await workflow.runWebhookMethod(
'create',
webhookData,
NodeExecuteFunctions,
mode,
activation,
this.testWebhooks,
);
}
} catch (error) {
// If there was a problem unregister the webhook again
if (this.webhookUrls[webhookKey].length <= 1) {
Expand Down Expand Up @@ -183,8 +171,7 @@ export class ActiveWebhooks {
// Go through all the registered webhooks of the workflow and remove them

for (const webhookData of webhooks) {
await workflow.runWebhookMethod(
'delete',
await workflow.deleteWebhook(
webhookData,
NodeExecuteFunctions,
mode,
Expand Down
23 changes: 2 additions & 21 deletions packages/cli/src/ActiveWorkflowRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -392,25 +392,13 @@ export class ActiveWorkflowRunner implements IWebhookManager {
try {
// TODO: this should happen in a transaction, that way we don't need to manually remove this in `catch`
await this.webhookService.storeWebhook(webhook);
const webhookExists = await workflow.runWebhookMethod(
'checkExists',
await workflow.createWebhookIfNotExists(
webhookData,
NodeExecuteFunctions,
mode,
activation,
false,
);
if (webhookExists !== true) {
// If webhook does not exist yet create it
await workflow.runWebhookMethod(
'create',
webhookData,
NodeExecuteFunctions,
mode,
activation,
false,
);
}
} catch (error) {
if (
activation === 'init' &&
Expand Down Expand Up @@ -489,14 +477,7 @@ export class ActiveWorkflowRunner implements IWebhookManager {
const webhooks = WebhookHelpers.getWorkflowWebhooks(workflow, additionalData, undefined, true);

for (const webhookData of webhooks) {
await workflow.runWebhookMethod(
'delete',
webhookData,
NodeExecuteFunctions,
mode,
'update',
false,
);
await workflow.deleteWebhook(webhookData, NodeExecuteFunctions, mode, 'update', false);
}

await WorkflowHelpers.saveStaticData(workflow);
Expand Down
43 changes: 16 additions & 27 deletions packages/cli/src/InternalHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ export class InternalHooks implements IInternalHooksClass {
return this.telemetry.track(
'User responded to personalization questions',
personalizationSurveyData,
{ withPostHog: true },
);
}

Expand Down Expand Up @@ -190,21 +189,17 @@ export class InternalHooks implements IInternalHooksClass {
workflowName: workflow.name,
},
}),
this.telemetry.track(
'User saved workflow',
{
user_id: user.id,
workflow_id: workflow.id,
node_graph_string: JSON.stringify(nodeGraph),
notes_count_overlapping: overlappingCount,
notes_count_non_overlapping: notesCount - overlappingCount,
version_cli: N8N_VERSION,
num_tags: workflow.tags?.length ?? 0,
public_api: publicApi,
sharing_role: userRole,
},
{ withPostHog: true },
),
this.telemetry.track('User saved workflow', {
user_id: user.id,
workflow_id: workflow.id,
node_graph_string: JSON.stringify(nodeGraph),
notes_count_overlapping: overlappingCount,
notes_count_non_overlapping: notesCount - overlappingCount,
version_cli: N8N_VERSION,
num_tags: workflow.tags?.length ?? 0,
public_api: publicApi,
sharing_role: userRole,
}),
]);
}

Expand Down Expand Up @@ -415,11 +410,7 @@ export class InternalHooks implements IInternalHooksClass {
node_id: nodeGraphResult.nameIndices[runData.data.startData?.destinationNode],
};

promises.push(
this.telemetry.track('Manual node exec finished', telemetryPayload, {
withPostHog: true,
}),
);
promises.push(this.telemetry.track('Manual node exec finished', telemetryPayload));
} else {
nodeGraphResult.webhookNodeNames.forEach((name: string) => {
const execJson = runData.data.resultData.runData[name]?.[0]?.data?.main?.[0]?.[0]
Expand All @@ -432,9 +423,7 @@ export class InternalHooks implements IInternalHooksClass {
});

promises.push(
this.telemetry.track('Manual workflow exec finished', manualExecEventProperties, {
withPostHog: true,
}),
this.telemetry.track('Manual workflow exec finished', manualExecEventProperties),
);
}
}
Expand Down Expand Up @@ -484,7 +473,7 @@ export class InternalHooks implements IInternalHooksClass {
user_id_list: userList,
};

return this.telemetry.track('User updated workflow sharing', properties, { withPostHog: true });
return this.telemetry.track('User updated workflow sharing', properties);
}

async onN8nStop(): Promise<void> {
Expand Down Expand Up @@ -1017,7 +1006,7 @@ export class InternalHooks implements IInternalHooksClass {
user_id: string;
workflow_id: string;
}): Promise<void> {
return this.telemetry.track('Workflow first prod success', data, { withPostHog: true });
return this.telemetry.track('Workflow first prod success', data);
}

async onFirstWorkflowDataLoad(data: {
Expand All @@ -1028,7 +1017,7 @@ export class InternalHooks implements IInternalHooksClass {
credential_type?: string;
credential_id?: string;
}): Promise<void> {
return this.telemetry.track('Workflow first data fetched', data, { withPostHog: true });
return this.telemetry.track('Workflow first data fetched', data);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/Server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ export class Server extends AbstractServer {
const controllers: object[] = [
new EventBusController(),
new AuthController({ config, internalHooks, repositories, logger, postHog }),
new OwnerController({ config, internalHooks, repositories, logger }),
new OwnerController({ config, internalHooks, repositories, logger, postHog }),
new MeController({ externalHooks, internalHooks, repositories, logger }),
new NodeTypesController({ config, nodeTypes }),
new PasswordResetController({
Expand Down
Loading

0 comments on commit bec4169

Please sign in to comment.