mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 20:24:05 -08:00
fix(editor): Remove "move" action from workflow and credential on community plan (#10057)
This commit is contained in:
parent
f876f9ec8b
commit
5a9a2713b4
|
@ -114,6 +114,8 @@ export class E2EController {
|
|||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
license.getFeatureValue<NumericLicenseFeature> = (feature: NumericLicenseFeature) =>
|
||||
this.numericFeatures[feature] ?? UNLIMITED_LICENSE_QUOTA;
|
||||
|
||||
license.getPlanName = () => 'Enterprise';
|
||||
}
|
||||
|
||||
@Post('/reset', { skipAuth: true })
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import { setActivePinia } from 'pinia';
|
||||
import { within } from '@testing-library/vue';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import { createComponentRenderer } from '@/__tests__/render';
|
||||
import CredentialCard from '@/components/CredentialCard.vue';
|
||||
import type { ICredentialsResponse } from '@/Interface';
|
||||
import type { ProjectSharingData } from '@/types/projects.types';
|
||||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
|
||||
const renderComponent = createComponentRenderer(CredentialCard);
|
||||
|
||||
|
@ -19,9 +22,12 @@ const createCredential = (overrides = {}): ICredentialsResponse => ({
|
|||
});
|
||||
|
||||
describe('CredentialCard', () => {
|
||||
let settingsStore: ReturnType<typeof useSettingsStore>;
|
||||
|
||||
beforeEach(() => {
|
||||
const pinia = createTestingPinia();
|
||||
setActivePinia(pinia);
|
||||
settingsStore = useSettingsStore();
|
||||
});
|
||||
|
||||
it('should render name and home project name', () => {
|
||||
|
@ -55,4 +61,28 @@ describe('CredentialCard', () => {
|
|||
expect(heading).toHaveTextContent(data.name);
|
||||
expect(badge).toHaveTextContent('John Doe');
|
||||
});
|
||||
|
||||
it('should show Move action only if there is resource permission and not on community plan', async () => {
|
||||
vi.spyOn(settingsStore, 'isCommunityPlan', 'get').mockReturnValue(false);
|
||||
|
||||
const data = createCredential({
|
||||
scopes: ['credential:move'],
|
||||
});
|
||||
const { getByTestId } = renderComponent({ props: { data } });
|
||||
const cardActions = getByTestId('credential-card-actions');
|
||||
|
||||
expect(cardActions).toBeInTheDocument();
|
||||
|
||||
const cardActionsOpener = within(cardActions).getByRole('button');
|
||||
expect(cardActionsOpener).toBeInTheDocument();
|
||||
|
||||
const controllingId = cardActionsOpener.getAttribute('aria-controls');
|
||||
|
||||
await userEvent.click(cardActions);
|
||||
const actions = document.querySelector(`#${controllingId}`);
|
||||
if (!actions) {
|
||||
throw new Error('Actions menu not found');
|
||||
}
|
||||
expect(actions).toHaveTextContent('Move');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,6 +14,7 @@ import { useProjectsStore } from '@/stores/projects.store';
|
|||
import ProjectCardBadge from '@/components/Projects/ProjectCardBadge.vue';
|
||||
import { useI18n } from '@/composables/useI18n';
|
||||
import { ResourceType } from '@/utils/projects.utils';
|
||||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
|
||||
const CREDENTIAL_LIST_ITEM_ACTIONS = {
|
||||
OPEN: 'open',
|
||||
|
@ -45,6 +46,7 @@ const message = useMessage();
|
|||
const uiStore = useUIStore();
|
||||
const credentialsStore = useCredentialsStore();
|
||||
const projectsStore = useProjectsStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
const resourceTypeLabel = computed(() => locale.baseText('generic.credential').toLowerCase());
|
||||
const credentialType = computed(() => credentialsStore.getCredentialTypeByName(props.data.type));
|
||||
|
@ -64,7 +66,7 @@ const actions = computed(() => {
|
|||
});
|
||||
}
|
||||
|
||||
if (credentialPermissions.value.move) {
|
||||
if (credentialPermissions.value.move && !settingsStore.isCommunityPlan) {
|
||||
items.push({
|
||||
label: locale.baseText('credentials.item.move'),
|
||||
value: CREDENTIAL_LIST_ITEM_ACTIONS.MOVE,
|
||||
|
|
|
@ -7,6 +7,7 @@ import { VIEWS } from '@/constants';
|
|||
import WorkflowCard from '@/components/WorkflowCard.vue';
|
||||
import type { IWorkflowDb } from '@/Interface';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
|
||||
vi.mock('vue-router', () => {
|
||||
const push = vi.fn();
|
||||
|
@ -39,12 +40,14 @@ describe('WorkflowCard', () => {
|
|||
let pinia: ReturnType<typeof createPinia>;
|
||||
let windowOpenSpy: MockInstance;
|
||||
let router: ReturnType<typeof useRouter>;
|
||||
let settingsStore: ReturnType<typeof useSettingsStore>;
|
||||
|
||||
beforeEach(async () => {
|
||||
pinia = createPinia();
|
||||
setActivePinia(pinia);
|
||||
router = useRouter();
|
||||
windowOpenSpy = vi.spyOn(window, 'open');
|
||||
settingsStore = useSettingsStore();
|
||||
windowOpenSpy = vi.spyOn(window, 'open').mockImplementation(() => null);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -95,10 +98,11 @@ describe('WorkflowCard', () => {
|
|||
});
|
||||
|
||||
const actions = document.querySelector(`#${controllingId}`);
|
||||
await waitFor(() => {
|
||||
expect(actions).toBeInTheDocument();
|
||||
});
|
||||
await userEvent.click(actions!.querySelectorAll('li')[0]);
|
||||
if (!actions) {
|
||||
throw new Error('Actions menu not found');
|
||||
}
|
||||
await userEvent.click(actions.querySelectorAll('li')[0]);
|
||||
expect(actions).not.toHaveTextContent('Move');
|
||||
await waitFor(() => {
|
||||
expect(router.push).toHaveBeenCalledWith({
|
||||
name: VIEWS.WORKFLOW,
|
||||
|
@ -138,4 +142,28 @@ describe('WorkflowCard', () => {
|
|||
expect(heading).toHaveTextContent(data.name);
|
||||
expect(badge).toHaveTextContent('John Doe');
|
||||
});
|
||||
|
||||
it('should show Move action only if there is resource permission and not on community plan', async () => {
|
||||
vi.spyOn(settingsStore, 'isCommunityPlan', 'get').mockReturnValue(false);
|
||||
|
||||
const data = createWorkflow({
|
||||
scopes: ['workflow:move'],
|
||||
});
|
||||
const { getByTestId } = renderComponent({ props: { data } });
|
||||
const cardActions = getByTestId('workflow-card-actions');
|
||||
|
||||
expect(cardActions).toBeInTheDocument();
|
||||
|
||||
const cardActionsOpener = within(cardActions).getByRole('button');
|
||||
expect(cardActionsOpener).toBeInTheDocument();
|
||||
|
||||
const controllingId = cardActionsOpener.getAttribute('aria-controls');
|
||||
|
||||
await userEvent.click(cardActions);
|
||||
const actions = document.querySelector(`#${controllingId}`);
|
||||
if (!actions) {
|
||||
throw new Error('Actions menu not found');
|
||||
}
|
||||
expect(actions).toHaveTextContent('Move');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -95,7 +95,7 @@ const actions = computed(() => {
|
|||
});
|
||||
}
|
||||
|
||||
if (workflowPermissions.value.move) {
|
||||
if (workflowPermissions.value.move && !settingsStore.isCommunityPlan) {
|
||||
items.push({
|
||||
label: locale.baseText('workflows.item.move'),
|
||||
value: WORKFLOW_LIST_ITEM_ACTIONS.MOVE,
|
||||
|
|
|
@ -58,12 +58,11 @@ export function useDebugInfo() {
|
|||
: store.databaseType,
|
||||
executionMode: store.isQueueModeEnabled ? 'scaling' : 'regular',
|
||||
concurrency: store.settings.concurrency,
|
||||
license:
|
||||
store.planName === 'Community'
|
||||
? (store.planName.toLowerCase() as 'community')
|
||||
: store.settings.license.environment === 'production'
|
||||
? 'enterprise (production)'
|
||||
: 'enterprise (sandbox)',
|
||||
license: store.isCommunityPlan
|
||||
? 'community'
|
||||
: store.settings.license.environment === 'production'
|
||||
? 'enterprise (production)'
|
||||
: 'enterprise (sandbox)',
|
||||
consumerId: store.consumerId,
|
||||
} as const;
|
||||
};
|
||||
|
|
|
@ -77,10 +77,13 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, {
|
|||
return this.settings.databaseType;
|
||||
},
|
||||
planName(): string {
|
||||
return this.settings.license.planName ?? 'Community';
|
||||
return this.settings.license?.planName ?? 'Community';
|
||||
},
|
||||
isCommunityPlan(): boolean {
|
||||
return this.planName.toLowerCase() === 'community';
|
||||
},
|
||||
consumerId(): string {
|
||||
return this.settings.license.consumerId;
|
||||
return this.settings.license?.consumerId ?? 'unknown';
|
||||
},
|
||||
binaryDataMode(): 'default' | 'filesystem' | 's3' {
|
||||
return this.settings.binaryDataMode;
|
||||
|
|
Loading…
Reference in a new issue