Skip to content

Commit

Permalink
Merge branch 'master' into ADO-1546-lead-enrichment-components
Browse files Browse the repository at this point in the history
* master:
  refactor(core): Warn on sqlite DB detected during init on queue mode (#8034)
  docs: Two small UI copy fixes in sub-nodes (#8032)
  fix(core): Restore workflow ID during execution creation (#8031)
  fix(core): Initialize queue once in queue mode (#8025)
  fix(editor): Add back credential `use` permission (#8023)
  fix(editor): Disable auto scroll and list size check when clicking on executions (#7983)
  fix(editor): Fix dialogVisibleChanged hooks event when meta.value is undefined (no-changelog) (#7986)
  perf(editor): Improve canvas rendering performance (#8022)
  • Loading branch information
MiloradFilipovic committed Dec 15, 2023
2 parents 17b5170 + f18bc5f commit 68b5993
Show file tree
Hide file tree
Showing 21 changed files with 165 additions and 90 deletions.
20 changes: 20 additions & 0 deletions cypress/e2e/17-sharing.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,26 @@ describe('Sharing', { disableAutoLogin: true }, () => {
ndv.actions.close();
});

it('should open W1, add node using C2 as U2', () => {
cy.signin(INSTANCE_MEMBERS[0]);

cy.visit(workflowsPage.url);
workflowsPage.getters.workflowCards().should('have.length', 2);
workflowsPage.getters.workflowCard('Workflow W1').click();
workflowPage.actions.addNodeToCanvas('Airtable', true, true);
ndv.getters.credentialInput().find('input').should('have.value', 'Credential C2');
ndv.actions.close();
workflowPage.actions.saveWorkflowOnButtonClick();

workflowPage.actions.openNode('Notion');
ndv.getters
.credentialInput()
.find('input')
.should('have.value', 'Credential C1')
.should('be.enabled');
ndv.actions.close();
});

it('should not have access to W2, as U3', () => {
cy.signin(INSTANCE_MEMBERS[1]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export class OutputParserItemList implements INodeType {
type: 'number',
default: -1,
description:
'Defines many many items should be returned maximally. If set to -1, there is no limit.',
'Defines how many items should be returned maximally. If set to -1, there is no limit.',
},
// For that to be easily possible the metadata would have to be returned and be able to be read.
// Would also be possible with a wrapper but that would be even more hacky and the output types
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export class ToolSerpApi implements INodeType {
type: 'string',
default: 'google.com',
description:
'Defines the country to use for search. Head to <a href="https://serpapi.com/google-countries">Google countries page</a> for a full list of supported countries.',
'Defines the domain to use for search. Head to <a href="https://serpapi.com/google-domains">Google domains page</a> for a full list of supported domains.',
},
{
displayName: 'Language',
Expand Down
6 changes: 6 additions & 0 deletions packages/cli/src/commands/BaseCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ export abstract class BaseCommand extends Command {
);
}

if (config.getEnv('executions.mode') === 'queue' && dbType === 'sqlite') {
this.logger.warn(
'Queue mode is not officially supported with sqlite. Please switch to PostgreSQL.',
);
}

if (
process.env.N8N_BINARY_DATA_TTL ??
process.env.N8N_PERSISTED_BINARY_DATA_TTL ??
Expand Down
19 changes: 16 additions & 3 deletions packages/cli/src/commands/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ import type {
INodeTypes,
IRun,
} from 'n8n-workflow';
import { Workflow, NodeOperationError, sleep, ApplicationError } from 'n8n-workflow';
import {
Workflow,
NodeOperationError,
sleep,
ApplicationError,
ErrorReporterProxy as EventReporter,
} from 'n8n-workflow';

import * as Db from '@/Db';
import * as ResponseHelper from '@/ResponseHelper';
Expand Down Expand Up @@ -130,7 +136,15 @@ export class Worker extends BaseCommand {
{ extra: { executionId } },
);
}
const workflowId = fullExecutionData.workflowData.id!;
const workflowId = fullExecutionData.workflowData.id!; // @tech_debt Ensure this is not optional

if (!workflowId) {
EventReporter.report('Detected ID-less workflow', {
level: 'info',
extra: { execution: fullExecutionData },
});
}

this.logger.info(
`Start job: ${job.id} (Workflow ID: ${workflowId} | Execution: ${executionId})`,
);
Expand Down Expand Up @@ -292,7 +306,6 @@ export class Worker extends BaseCommand {
this.logger.debug('Queue init complete');
await this.initOrchestration();
this.logger.debug('Orchestration init complete');
await this.initQueue();

await Container.get(OrchestrationWorkerService).publishToEventLog(
new EventMessageGeneric({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ export class ExecutionRepository extends Repository<ExecutionEntity> {
const { connections, nodes, name } = workflowData ?? {};
await this.executionDataRepository.insert({
executionId,
workflowData: { connections, nodes, name },
workflowData: { connections, nodes, name, id: workflowData?.id },
data: stringify(data),
});
return String(executionId);
Expand Down
18 changes: 9 additions & 9 deletions packages/cli/test/integration/commands/worker.cmd.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,15 @@ test('worker initializes all its components', async () => {
expect(worker.queueModeId).toBeDefined();
expect(worker.queueModeId).toContain('worker');
expect(worker.queueModeId.length).toBeGreaterThan(15);
expect(worker.initLicense).toHaveBeenCalled();
expect(worker.initBinaryDataService).toHaveBeenCalled();
expect(worker.initExternalHooks).toHaveBeenCalled();
expect(worker.initExternalSecrets).toHaveBeenCalled();
expect(worker.initEventBus).toHaveBeenCalled();
expect(worker.initOrchestration).toHaveBeenCalled();
expect(OrchestrationHandlerWorkerService.prototype.initSubscriber).toHaveBeenCalled();
expect(OrchestrationWorkerService.prototype.publishToEventLog).toHaveBeenCalled();
expect(worker.initQueue).toHaveBeenCalled();
expect(worker.initLicense).toHaveBeenCalledTimes(1);
expect(worker.initBinaryDataService).toHaveBeenCalledTimes(1);
expect(worker.initExternalHooks).toHaveBeenCalledTimes(1);
expect(worker.initExternalSecrets).toHaveBeenCalledTimes(1);
expect(worker.initEventBus).toHaveBeenCalledTimes(1);
expect(worker.initOrchestration).toHaveBeenCalledTimes(1);
expect(OrchestrationHandlerWorkerService.prototype.initSubscriber).toHaveBeenCalledTimes(1);
expect(OrchestrationWorkerService.prototype.publishToEventLog).toHaveBeenCalledTimes(1);
expect(worker.initQueue).toHaveBeenCalledTimes(1);

jest.restoreAllMocks();
});
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ describe('ExecutionRepository', () => {
const executionDataRepo = Container.get(ExecutionDataRepository);
const executionData = await executionDataRepo.findOneBy({ executionId });
expect(executionData?.workflowData).toEqual({
id: workflow.id,
connections: workflow.connections,
nodes: workflow.nodes,
name: workflow.name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,6 @@ export default defineComponent({
this.$router.go(-1);
}
},
'workflowsStore.activeWorkflowExecution'() {
this.checkListSize();
this.scrollToActiveCard();
},
},
mounted() {
// On larger screens, we need to load more then first page of executions
Expand Down
3 changes: 1 addition & 2 deletions packages/editor-ui/src/components/Node.vue
Original file line number Diff line number Diff line change
Expand Up @@ -637,8 +637,7 @@ export default defineComponent({
// so we only update it when necessary (when node is mounted and when it's opened and closed (isActive))
try {
const nodeSubtitle =
this.nodeHelpers.getNodeSubtitle(this.data, this.nodeType, this.getCurrentWorkflow()) ||
'';
this.nodeHelpers.getNodeSubtitle(this.data, this.nodeType, this.workflow) || '';
this.nodeSubtitle = nodeSubtitle.includes(CUSTOM_API_CALL_KEY) ? '' : nodeSubtitle;
} catch (e) {
Expand Down
2 changes: 1 addition & 1 deletion packages/editor-ui/src/composables/useNodeHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ export function useNodeHelpers() {
.getCredentialsByType(credentialTypeDescription.name)
.filter((credential: ICredentialsResponse) => {
const permissions = getCredentialPermissions(currentUser, credential);
return permissions.read;
return permissions.use;
});

if (userCredentials === null) {
Expand Down
2 changes: 1 addition & 1 deletion packages/editor-ui/src/hooks/cloud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ export const n8nCloudHooks: PartialDeep<ExternalHooks> = {
dialogVisibleChanged: [
(_, meta) => {
const segmentStore = useSegment();
const currentValue = meta.value.slice(1);
const currentValue = meta.value?.slice(1) ?? '';
let isValueDefault = false;

switch (typeof meta.parameter.default) {
Expand Down
4 changes: 4 additions & 0 deletions packages/editor-ui/src/permissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ export const getCredentialPermissions = (user: IUser | null, credential: ICreden
test: (permissions) =>
hasPermission(['rbac'], { rbac: { scope: 'credential:delete' } }) || !!permissions.isOwner,
},
{
name: 'use',
test: (permissions) => !!permissions.isOwner || !!permissions.isSharee,
},
];

return parsePermissionsTable(user, table);
Expand Down
20 changes: 18 additions & 2 deletions packages/editor-ui/src/plugins/i18n/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export const i18nInstance = createI18n({
});

export class I18nClass {
private baseTextCache = new Map<string, string>();

private get i18n() {
return i18nInstance.global;
}
Expand Down Expand Up @@ -50,11 +52,25 @@ export class I18nClass {
key: BaseTextKey,
options?: { adjustToNumber?: number; interpolate?: { [key: string]: string } },
): string {
// Create a unique cache key
const cacheKey = `${key}-${JSON.stringify(options)}`;

// Check if the result is already cached
if (this.baseTextCache.has(cacheKey)) {
return this.baseTextCache.get(cacheKey) ?? key;
}

let result: string;
if (options?.adjustToNumber !== undefined) {
return this.i18n.tc(key, options.adjustToNumber, options?.interpolate).toString();
result = this.i18n.tc(key, options.adjustToNumber, options?.interpolate ?? {}).toString();
} else {
result = this.i18n.t(key, options?.interpolate ?? {}).toString();
}

return this.i18n.t(key, options?.interpolate).toString();
// Store the result in the cache
this.baseTextCache.set(cacheKey, result);

return result;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ export const register = () => {
container.appendChild(unconnectedGroup);
container.appendChild(defaultGroup);

endpointInstance.setupOverlays();
endpointInstance.setVisible(false);

return container;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,6 @@ export class N8nAddInputEndpoint extends EndpointRepresentation<ComputedN8nAddIn

type = N8nAddInputEndpoint.type;

setupOverlays() {
this.endpoint.instance.setSuspendDrawing(true);
this.endpoint.instance.setSuspendDrawing(false);
}

bindEvents() {
this.instance.bind(EVENT_ENDPOINT_CLICK, this.fireClickEvent);
}
Expand Down
6 changes: 0 additions & 6 deletions packages/editor-ui/src/plugins/jsplumb/N8nPlusEndpointType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ export class N8nPlusEndpoint extends EndpointRepresentation<ComputedN8nPlusEndpo

setupOverlays() {
this.clearOverlays();
this.endpoint.instance.setSuspendDrawing(true);
this.stalkOverlay = this.endpoint.addOverlay({
type: 'Custom',
options: {
Expand Down Expand Up @@ -78,7 +77,6 @@ export class N8nPlusEndpoint extends EndpointRepresentation<ComputedN8nPlusEndpo
},
},
});
this.endpoint.instance.setSuspendDrawing(false);
}

bindEvents() {
Expand Down Expand Up @@ -151,18 +149,14 @@ export class N8nPlusEndpoint extends EndpointRepresentation<ComputedN8nPlusEndpo
}

setIsVisible(visible: boolean) {
this.instance.setSuspendDrawing(true);
Object.keys(this.endpoint.getOverlays()).forEach((overlay) => {
this.endpoint.getOverlays()[overlay].setVisible(visible);
});

this.setVisible(visible);

// Re-trigger the success state if label is set
if (visible && this.label) {
this.setSuccessOutput(this.label);
}
this.instance.setSuspendDrawing(false);
}

setSuccessOutput(label: string) {
Expand Down
2 changes: 1 addition & 1 deletion packages/editor-ui/src/stores/users.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export const useUsersStore = defineStore(STORES.USERS, {
return (resource: ICredentialsResponse): boolean => {
const permissions = getCredentialPermissions(this.currentUser, resource);

return permissions.read;
return permissions.use;
};
},
},
Expand Down
3 changes: 0 additions & 3 deletions packages/editor-ui/src/stores/workflows.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -894,8 +894,6 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
},
};
}

this.workflowExecutionPairedItemMappings = getPairedItemsMapping(this.workflowExecutionData);
},

resetAllNodesIssues(): boolean {
Expand Down Expand Up @@ -1130,7 +1128,6 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
};
}
this.workflowExecutionData.data!.resultData.runData[pushData.nodeName].push(pushData.data);
this.workflowExecutionPairedItemMappings = getPairedItemsMapping(this.workflowExecutionData);
},
clearNodeExecutionData(nodeName: string): void {
if (!this.workflowExecutionData?.data) {
Expand Down
Loading

0 comments on commit 68b5993

Please sign in to comment.