mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
fix: Account for nanoid workflow ids for subworkflow execute policy (#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>
This commit is contained in:
parent
c9b79485cf
commit
67092c0a1b
|
@ -67,7 +67,7 @@
|
||||||
</n8n-select>
|
</n8n-select>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<div v-if="isSharingEnabled">
|
<div v-if="isSharingEnabled" data-test-id="workflow-caller-policy">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="10" class="setting-name">
|
<el-col :span="10" class="setting-name">
|
||||||
{{ $locale.baseText('workflowSettings.callerPolicy') + ':' }}
|
{{ $locale.baseText('workflowSettings.callerPolicy') + ':' }}
|
||||||
|
@ -114,6 +114,7 @@
|
||||||
type="text"
|
type="text"
|
||||||
v-model="workflowSettings.callerIds"
|
v-model="workflowSettings.callerIds"
|
||||||
@update:modelValue="onCallerIdsInput"
|
@update:modelValue="onCallerIdsInput"
|
||||||
|
data-test-id="workflow-caller-policy-workflow-ids"
|
||||||
/>
|
/>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
@ -374,13 +375,11 @@ import {
|
||||||
|
|
||||||
import type { WorkflowSettings } from 'n8n-workflow';
|
import type { WorkflowSettings } from 'n8n-workflow';
|
||||||
import { deepCopy } from 'n8n-workflow';
|
import { deepCopy } from 'n8n-workflow';
|
||||||
import {
|
import { useSettingsStore } from '@/stores/settings.store';
|
||||||
useWorkflowsStore,
|
import { useUsersStore } from '@/stores/users.store';
|
||||||
useSettingsStore,
|
import { useRootStore } from '@/stores/n8nRoot.store';
|
||||||
useRootStore,
|
import { useWorkflowsEEStore } from '@/stores/workflows.ee.store';
|
||||||
useWorkflowsEEStore,
|
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||||
useUsersStore,
|
|
||||||
} from '@/stores';
|
|
||||||
import { createEventBus } from 'n8n-design-system/utils';
|
import { createEventBus } from 'n8n-design-system/utils';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
@ -566,9 +565,9 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onCallerIdsInput(str: string) {
|
onCallerIdsInput(str: string) {
|
||||||
this.workflowSettings.callerIds = /^[0-9,\s]+$/.test(str)
|
this.workflowSettings.callerIds = /^[a-zA-Z0-9,\s]+$/.test(str)
|
||||||
? str
|
? str
|
||||||
: str.replace(/[^0-9,\s]/g, '');
|
: str.replace(/[^a-zA-Z0-9,\s]/g, '');
|
||||||
},
|
},
|
||||||
closeDialog() {
|
closeDialog() {
|
||||||
this.modalBus.emit('close');
|
this.modalBus.emit('close');
|
||||||
|
|
|
@ -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,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,6 +1,6 @@
|
||||||
import type { IExternalHooks } from '@/Interface';
|
import type { IExternalHooks } from '@/Interface';
|
||||||
import type { IDataObject } from 'n8n-workflow';
|
import type { IDataObject } from 'n8n-workflow';
|
||||||
import { useWebhooksStore } from '@/stores';
|
import { useWebhooksStore } from '@/stores/webhooks.store';
|
||||||
import { runExternalHook } from '@/utils';
|
import { runExternalHook } from '@/utils';
|
||||||
|
|
||||||
export function useExternalHooks(): IExternalHooks {
|
export function useExternalHooks(): IExternalHooks {
|
||||||
|
|
Loading…
Reference in a new issue