fix(editor): Remove "move" action from workflow and credential on community plan (#10057)

This commit is contained in:
Csaba Tuncsik 2024-07-18 15:34:39 +02:00 committed by GitHub
parent f876f9ec8b
commit 5a9a2713b4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 79 additions and 15 deletions

View file

@ -114,6 +114,8 @@ export class E2EController {
// eslint-disable-next-line @typescript-eslint/unbound-method // eslint-disable-next-line @typescript-eslint/unbound-method
license.getFeatureValue<NumericLicenseFeature> = (feature: NumericLicenseFeature) => license.getFeatureValue<NumericLicenseFeature> = (feature: NumericLicenseFeature) =>
this.numericFeatures[feature] ?? UNLIMITED_LICENSE_QUOTA; this.numericFeatures[feature] ?? UNLIMITED_LICENSE_QUOTA;
license.getPlanName = () => 'Enterprise';
} }
@Post('/reset', { skipAuth: true }) @Post('/reset', { skipAuth: true })

View file

@ -1,9 +1,12 @@
import { setActivePinia } from 'pinia'; import { setActivePinia } from 'pinia';
import { within } from '@testing-library/vue';
import userEvent from '@testing-library/user-event';
import { createTestingPinia } from '@pinia/testing'; import { createTestingPinia } from '@pinia/testing';
import { createComponentRenderer } from '@/__tests__/render'; import { createComponentRenderer } from '@/__tests__/render';
import CredentialCard from '@/components/CredentialCard.vue'; import CredentialCard from '@/components/CredentialCard.vue';
import type { ICredentialsResponse } from '@/Interface'; import type { ICredentialsResponse } from '@/Interface';
import type { ProjectSharingData } from '@/types/projects.types'; import type { ProjectSharingData } from '@/types/projects.types';
import { useSettingsStore } from '@/stores/settings.store';
const renderComponent = createComponentRenderer(CredentialCard); const renderComponent = createComponentRenderer(CredentialCard);
@ -19,9 +22,12 @@ const createCredential = (overrides = {}): ICredentialsResponse => ({
}); });
describe('CredentialCard', () => { describe('CredentialCard', () => {
let settingsStore: ReturnType<typeof useSettingsStore>;
beforeEach(() => { beforeEach(() => {
const pinia = createTestingPinia(); const pinia = createTestingPinia();
setActivePinia(pinia); setActivePinia(pinia);
settingsStore = useSettingsStore();
}); });
it('should render name and home project name', () => { it('should render name and home project name', () => {
@ -55,4 +61,28 @@ describe('CredentialCard', () => {
expect(heading).toHaveTextContent(data.name); expect(heading).toHaveTextContent(data.name);
expect(badge).toHaveTextContent('John Doe'); 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');
});
}); });

View file

@ -14,6 +14,7 @@ import { useProjectsStore } from '@/stores/projects.store';
import ProjectCardBadge from '@/components/Projects/ProjectCardBadge.vue'; import ProjectCardBadge from '@/components/Projects/ProjectCardBadge.vue';
import { useI18n } from '@/composables/useI18n'; import { useI18n } from '@/composables/useI18n';
import { ResourceType } from '@/utils/projects.utils'; import { ResourceType } from '@/utils/projects.utils';
import { useSettingsStore } from '@/stores/settings.store';
const CREDENTIAL_LIST_ITEM_ACTIONS = { const CREDENTIAL_LIST_ITEM_ACTIONS = {
OPEN: 'open', OPEN: 'open',
@ -45,6 +46,7 @@ const message = useMessage();
const uiStore = useUIStore(); const uiStore = useUIStore();
const credentialsStore = useCredentialsStore(); const credentialsStore = useCredentialsStore();
const projectsStore = useProjectsStore(); const projectsStore = useProjectsStore();
const settingsStore = useSettingsStore();
const resourceTypeLabel = computed(() => locale.baseText('generic.credential').toLowerCase()); const resourceTypeLabel = computed(() => locale.baseText('generic.credential').toLowerCase());
const credentialType = computed(() => credentialsStore.getCredentialTypeByName(props.data.type)); 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({ items.push({
label: locale.baseText('credentials.item.move'), label: locale.baseText('credentials.item.move'),
value: CREDENTIAL_LIST_ITEM_ACTIONS.MOVE, value: CREDENTIAL_LIST_ITEM_ACTIONS.MOVE,

View file

@ -7,6 +7,7 @@ import { VIEWS } from '@/constants';
import WorkflowCard from '@/components/WorkflowCard.vue'; import WorkflowCard from '@/components/WorkflowCard.vue';
import type { IWorkflowDb } from '@/Interface'; import type { IWorkflowDb } from '@/Interface';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { useSettingsStore } from '@/stores/settings.store';
vi.mock('vue-router', () => { vi.mock('vue-router', () => {
const push = vi.fn(); const push = vi.fn();
@ -39,12 +40,14 @@ describe('WorkflowCard', () => {
let pinia: ReturnType<typeof createPinia>; let pinia: ReturnType<typeof createPinia>;
let windowOpenSpy: MockInstance; let windowOpenSpy: MockInstance;
let router: ReturnType<typeof useRouter>; let router: ReturnType<typeof useRouter>;
let settingsStore: ReturnType<typeof useSettingsStore>;
beforeEach(async () => { beforeEach(async () => {
pinia = createPinia(); pinia = createPinia();
setActivePinia(pinia); setActivePinia(pinia);
router = useRouter(); router = useRouter();
windowOpenSpy = vi.spyOn(window, 'open'); settingsStore = useSettingsStore();
windowOpenSpy = vi.spyOn(window, 'open').mockImplementation(() => null);
}); });
afterEach(() => { afterEach(() => {
@ -95,10 +98,11 @@ describe('WorkflowCard', () => {
}); });
const actions = document.querySelector(`#${controllingId}`); const actions = document.querySelector(`#${controllingId}`);
await waitFor(() => { if (!actions) {
expect(actions).toBeInTheDocument(); throw new Error('Actions menu not found');
}); }
await userEvent.click(actions!.querySelectorAll('li')[0]); await userEvent.click(actions.querySelectorAll('li')[0]);
expect(actions).not.toHaveTextContent('Move');
await waitFor(() => { await waitFor(() => {
expect(router.push).toHaveBeenCalledWith({ expect(router.push).toHaveBeenCalledWith({
name: VIEWS.WORKFLOW, name: VIEWS.WORKFLOW,
@ -138,4 +142,28 @@ describe('WorkflowCard', () => {
expect(heading).toHaveTextContent(data.name); expect(heading).toHaveTextContent(data.name);
expect(badge).toHaveTextContent('John Doe'); 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');
});
}); });

View file

@ -95,7 +95,7 @@ const actions = computed(() => {
}); });
} }
if (workflowPermissions.value.move) { if (workflowPermissions.value.move && !settingsStore.isCommunityPlan) {
items.push({ items.push({
label: locale.baseText('workflows.item.move'), label: locale.baseText('workflows.item.move'),
value: WORKFLOW_LIST_ITEM_ACTIONS.MOVE, value: WORKFLOW_LIST_ITEM_ACTIONS.MOVE,

View file

@ -58,9 +58,8 @@ export function useDebugInfo() {
: store.databaseType, : store.databaseType,
executionMode: store.isQueueModeEnabled ? 'scaling' : 'regular', executionMode: store.isQueueModeEnabled ? 'scaling' : 'regular',
concurrency: store.settings.concurrency, concurrency: store.settings.concurrency,
license: license: store.isCommunityPlan
store.planName === 'Community' ? 'community'
? (store.planName.toLowerCase() as 'community')
: store.settings.license.environment === 'production' : store.settings.license.environment === 'production'
? 'enterprise (production)' ? 'enterprise (production)'
: 'enterprise (sandbox)', : 'enterprise (sandbox)',

View file

@ -77,10 +77,13 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, {
return this.settings.databaseType; return this.settings.databaseType;
}, },
planName(): string { planName(): string {
return this.settings.license.planName ?? 'Community'; return this.settings.license?.planName ?? 'Community';
},
isCommunityPlan(): boolean {
return this.planName.toLowerCase() === 'community';
}, },
consumerId(): string { consumerId(): string {
return this.settings.license.consumerId; return this.settings.license?.consumerId ?? 'unknown';
}, },
binaryDataMode(): 'default' | 'filesystem' | 's3' { binaryDataMode(): 'default' | 'filesystem' | 's3' {
return this.settings.binaryDataMode; return this.settings.binaryDataMode;