Skip to content

Commit

Permalink
fix: Account for nanoid workflow ids for subworkflow execute policy (n…
Browse files Browse the repository at this point in the history
…8n-io#7094)

Github issue / Community forum post (link here to close automatically):

Since the change to allow workflow IDs to become strings in Nano ID
formats, this input broke.

This PR allows all characters that comprise workflow IDs.

---------

Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
  • Loading branch information
krynble and ivov authored Sep 13, 2023
1 parent c9b7948 commit 67092c0
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 11 deletions.
19 changes: 9 additions & 10 deletions packages/editor-ui/src/components/WorkflowSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
</n8n-select>
</el-col>
</el-row>
<div v-if="isSharingEnabled">
<div v-if="isSharingEnabled" data-test-id="workflow-caller-policy">
<el-row>
<el-col :span="10" class="setting-name">
{{ $locale.baseText('workflowSettings.callerPolicy') + ':' }}
Expand Down Expand Up @@ -114,6 +114,7 @@
type="text"
v-model="workflowSettings.callerIds"
@update:modelValue="onCallerIdsInput"
data-test-id="workflow-caller-policy-workflow-ids"
/>
</el-col>
</el-row>
Expand Down Expand Up @@ -374,13 +375,11 @@ import {
import type { WorkflowSettings } from 'n8n-workflow';
import { deepCopy } from 'n8n-workflow';
import {
useWorkflowsStore,
useSettingsStore,
useRootStore,
useWorkflowsEEStore,
useUsersStore,
} from '@/stores';
import { useSettingsStore } from '@/stores/settings.store';
import { useUsersStore } from '@/stores/users.store';
import { useRootStore } from '@/stores/n8nRoot.store';
import { useWorkflowsEEStore } from '@/stores/workflows.ee.store';
import { useWorkflowsStore } from '@/stores/workflows.store';
import { createEventBus } from 'n8n-design-system/utils';
export default defineComponent({
Expand Down Expand Up @@ -566,9 +565,9 @@ export default defineComponent({
},
methods: {
onCallerIdsInput(str: string) {
this.workflowSettings.callerIds = /^[0-9,\s]+$/.test(str)
this.workflowSettings.callerIds = /^[a-zA-Z0-9,\s]+$/.test(str)
? str
: str.replace(/[^0-9,\s]/g, '');
: str.replace(/[^a-zA-Z0-9,\s]/g, '');
},
closeDialog() {
this.modalBus.emit('close');
Expand Down
152 changes: 152 additions & 0 deletions packages/editor-ui/src/components/__tests__/WorkflowSettings.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import { createPinia, setActivePinia } from 'pinia';
import WorkflowSettingsVue from '../WorkflowSettings.vue';

import { setupServer } from '@/__tests__/server';
import { afterAll, beforeAll } from 'vitest';
import { within, fireEvent } from '@testing-library/vue';

import { useWorkflowsStore } from '@/stores/workflows.store';
import { useSettingsStore } from '@/stores/settings.store';
import { useUIStore } from '@/stores/ui.store';

import { createComponentRenderer } from '@/__tests__/render';
import { EnterpriseEditionFeature, WORKFLOW_SETTINGS_MODAL_KEY } from '@/constants';

import { nextTick } from 'vue';

let pinia: ReturnType<typeof createPinia>;
let workflowsStore: ReturnType<typeof useWorkflowsStore>;
let settingsStore: ReturnType<typeof useSettingsStore>;
let uiStore: ReturnType<typeof useUIStore>;

const createComponent = createComponentRenderer(WorkflowSettingsVue, {
global: {
stubs: ['n8n-tooltip'],
},
});

describe('WorkflowSettingsVue', () => {
let server: ReturnType<typeof setupServer>;
beforeAll(() => {
server = setupServer();
});

beforeEach(async () => {
pinia = createPinia();
setActivePinia(pinia);

workflowsStore = useWorkflowsStore();
settingsStore = useSettingsStore();
uiStore = useUIStore();

await settingsStore.getSettings();

vi.spyOn(workflowsStore, 'workflowName', 'get').mockReturnValue('Test Workflow');
vi.spyOn(workflowsStore, 'workflowId', 'get').mockReturnValue('1');
vi.spyOn(workflowsStore, 'workflow', 'get').mockReturnValue({
id: '1',
name: 'Test Workflow',
active: true,
nodes: [],
connections: {},
createdAt: 1,
updatedAt: 1,
versionId: '123',
} as IWorkflowDb);

uiStore.modals[WORKFLOW_SETTINGS_MODAL_KEY] = {
open: true,
};
});

afterAll(() => {
server.shutdown();
});

it('should render correctly', async () => {
settingsStore.settings.enterprise[EnterpriseEditionFeature.Sharing] = false;
const wrapper = createComponent({ pinia });
await nextTick();
expect(wrapper.getByTestId('workflow-settings-dialog')).toBeVisible();
});

it('should not render workflow caller policy when sharing is not enabled', async () => {
settingsStore.settings.enterprise[EnterpriseEditionFeature.Sharing] = false;
const wrapper = createComponent({ pinia });

await nextTick();

expect(
within(wrapper.getByTestId('workflow-settings-dialog')).queryByTestId(
'workflow-caller-policy',
),
).not.toBeInTheDocument();
});

it('should render workflow caller policy when sharing is enabled', async () => {
settingsStore.settings.enterprise[EnterpriseEditionFeature.Sharing] = true;
const wrapper = createComponent({ pinia });

await nextTick();

expect(wrapper.getByTestId('workflow-caller-policy')).toBeVisible();
});

it('should render list of workflows field when policy is set to workflowsFromAList', async () => {
settingsStore.settings.enterprise[EnterpriseEditionFeature.Sharing] = true;
const wrapper = createComponent({ pinia });

await nextTick();

await fireEvent.click(wrapper.getByTestId('workflow-caller-policy'));
console.log(window.document.querySelectorAll('.el-select-dropdown__item')[4].innerHTML);
await fireEvent.click(window.document.querySelectorAll('.el-select-dropdown__item')[4]);

expect(wrapper.getByTestId('workflow-caller-policy-workflow-ids')).toBeVisible();
});

it('should not remove valid workflow ID characters', async () => {
const validWorkflowList = '1234567890, abcde, efgh, 1234';

settingsStore.settings.enterprise[EnterpriseEditionFeature.Sharing] = true;
const wrapper = createComponent({ pinia });

await nextTick();

await fireEvent.click(wrapper.getByTestId('workflow-caller-policy'));
console.log(window.document.querySelectorAll('.el-select-dropdown__item')[4].innerHTML);
await fireEvent.click(window.document.querySelectorAll('.el-select-dropdown__item')[4]);

await fireEvent.update(
wrapper.getByTestId('workflow-caller-policy-workflow-ids'),
validWorkflowList,
);

expect(wrapper.getByTestId('workflow-caller-policy-workflow-ids')).toHaveValue(
validWorkflowList,
);
});

it('should remove invalid workflow ID characters', async () => {
const invalidWorkflowList = '1234567890@, abc/de, ef*gh, 12%34';
const cleanedUpWorkflowList = '1234567890, abcde, efgh, 1234';

settingsStore.settings.enterprise[EnterpriseEditionFeature.Sharing] = true;
const wrapper = createComponent({ pinia });

await nextTick();

await fireEvent.click(wrapper.getByTestId('workflow-caller-policy'));
console.log(window.document.querySelectorAll('.el-select-dropdown__item')[4].innerHTML);
await fireEvent.click(window.document.querySelectorAll('.el-select-dropdown__item')[4]);

await fireEvent.update(
wrapper.getByTestId('workflow-caller-policy-workflow-ids'),
invalidWorkflowList,
);

expect(wrapper.getByTestId('workflow-caller-policy-workflow-ids')).toHaveValue(
cleanedUpWorkflowList,
);
});
});
2 changes: 1 addition & 1 deletion packages/editor-ui/src/composables/useExternalHooks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { IExternalHooks } from '@/Interface';
import type { IDataObject } from 'n8n-workflow';
import { useWebhooksStore } from '@/stores';
import { useWebhooksStore } from '@/stores/webhooks.store';
import { runExternalHook } from '@/utils';

export function useExternalHooks(): IExternalHooks {
Expand Down

0 comments on commit 67092c0

Please sign in to comment.