fix(editor): Enable moving resources only if team projects are available by the license (#10271)

This commit is contained in:
Csaba Tuncsik 2024-08-01 17:33:10 +02:00 committed by GitHub
parent 43ae159ea4
commit 42ba8841c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 20 additions and 20 deletions

View file

@ -6,7 +6,7 @@ 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'; import { useProjectsStore } from '@/stores/projects.store';
const renderComponent = createComponentRenderer(CredentialCard); const renderComponent = createComponentRenderer(CredentialCard);
@ -22,12 +22,12 @@ const createCredential = (overrides = {}): ICredentialsResponse => ({
}); });
describe('CredentialCard', () => { describe('CredentialCard', () => {
let settingsStore: ReturnType<typeof useSettingsStore>; let projectsStore: ReturnType<typeof useProjectsStore>;
beforeEach(() => { beforeEach(() => {
const pinia = createTestingPinia(); const pinia = createTestingPinia();
setActivePinia(pinia); setActivePinia(pinia);
settingsStore = useSettingsStore(); projectsStore = useProjectsStore();
}); });
it('should render name and home project name', () => { it('should render name and home project name', () => {
@ -63,7 +63,7 @@ describe('CredentialCard', () => {
}); });
it('should show Move action only if there is resource permission and not on community plan', async () => { it('should show Move action only if there is resource permission and not on community plan', async () => {
vi.spyOn(settingsStore, 'isCommunityPlan', 'get').mockReturnValue(false); vi.spyOn(projectsStore, 'isTeamProjectFeatureEnabled', 'get').mockReturnValue(true);
const data = createCredential({ const data = createCredential({
scopes: ['credential:move'], scopes: ['credential:move'],

View file

@ -14,7 +14,6 @@ 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',
@ -46,7 +45,6 @@ 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));
@ -66,7 +64,7 @@ const actions = computed(() => {
}); });
} }
if (credentialPermissions.value.move && !settingsStore.isCommunityPlan) { if (credentialPermissions.value.move && projectsStore.isTeamProjectFeatureEnabled) {
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

@ -116,7 +116,7 @@ onMounted(async () => {
<hr <hr
v-if=" v-if="
displayProjects.length || displayProjects.length ||
(projectsStore.hasPermissionToCreateProjects && projectsStore.teamProjectsAvailable) (projectsStore.hasPermissionToCreateProjects && projectsStore.isTeamProjectFeatureEnabled)
" "
class="mt-m mb-m" class="mt-m mb-m"
/> />
@ -137,7 +137,9 @@ onMounted(async () => {
</ElMenu> </ElMenu>
<N8nTooltip placement="right" :disabled="projectsStore.canCreateProjects"> <N8nTooltip placement="right" :disabled="projectsStore.canCreateProjects">
<ElMenu <ElMenu
v-if="projectsStore.hasPermissionToCreateProjects && projectsStore.teamProjectsAvailable" v-if="
projectsStore.hasPermissionToCreateProjects && projectsStore.isTeamProjectFeatureEnabled
"
:collapse="props.collapsed" :collapse="props.collapsed"
class="pl-xs pr-xs" class="pl-xs pr-xs"
> >
@ -171,7 +173,7 @@ onMounted(async () => {
<hr <hr
v-if=" v-if="
displayProjects.length || displayProjects.length ||
(projectsStore.hasPermissionToCreateProjects && projectsStore.teamProjectsAvailable) (projectsStore.hasPermissionToCreateProjects && projectsStore.isTeamProjectFeatureEnabled)
" "
class="mt-m mb-m" class="mt-m mb-m"
/> />

View file

@ -7,7 +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'; import { useProjectsStore } from '@/stores/projects.store';
vi.mock('vue-router', () => { vi.mock('vue-router', () => {
const push = vi.fn(); const push = vi.fn();
@ -40,13 +40,13 @@ 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>; let projectsStore: ReturnType<typeof useProjectsStore>;
beforeEach(async () => { beforeEach(async () => {
pinia = createPinia(); pinia = createPinia();
setActivePinia(pinia); setActivePinia(pinia);
router = useRouter(); router = useRouter();
settingsStore = useSettingsStore(); projectsStore = useProjectsStore();
windowOpenSpy = vi.spyOn(window, 'open').mockImplementation(() => null); windowOpenSpy = vi.spyOn(window, 'open').mockImplementation(() => null);
}); });
@ -143,8 +143,8 @@ describe('WorkflowCard', () => {
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 () => { it('should show Move action only if there is resource permission and team projects available', async () => {
vi.spyOn(settingsStore, 'isCommunityPlan', 'get').mockReturnValue(false); vi.spyOn(projectsStore, 'isTeamProjectFeatureEnabled', 'get').mockReturnValue(true);
const data = createWorkflow({ const data = createWorkflow({
scopes: ['workflow:move'], scopes: ['workflow:move'],

View file

@ -95,7 +95,7 @@ const actions = computed(() => {
}); });
} }
if (workflowPermissions.value.move && !settingsStore.isCommunityPlan) { if (workflowPermissions.value.move && projectsStore.isTeamProjectFeatureEnabled) {
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

@ -49,19 +49,19 @@ export const useProjectsStore = defineStore('projects', () => {
); );
const teamProjects = computed(() => projects.value.filter((p) => p.type === ProjectTypes.Team)); const teamProjects = computed(() => projects.value.filter((p) => p.type === ProjectTypes.Team));
const teamProjectsLimit = computed(() => settingsStore.settings.enterprise.projects.team.limit); const teamProjectsLimit = computed(() => settingsStore.settings.enterprise.projects.team.limit);
const teamProjectsAvailable = computed<boolean>( const isTeamProjectFeatureEnabled = computed<boolean>(
() => settingsStore.settings.enterprise.projects.team.limit !== 0, () => settingsStore.settings.enterprise.projects.team.limit !== 0,
); );
const hasUnlimitedProjects = computed<boolean>( const hasUnlimitedProjects = computed<boolean>(
() => settingsStore.settings.enterprise.projects.team.limit === -1, () => settingsStore.settings.enterprise.projects.team.limit === -1,
); );
const teamProjectLimitExceeded = computed<boolean>( const isTeamProjectLimitExceeded = computed<boolean>(
() => projectsCount.value.team >= teamProjectsLimit.value, () => projectsCount.value.team >= teamProjectsLimit.value,
); );
const canCreateProjects = computed<boolean>( const canCreateProjects = computed<boolean>(
() => () =>
hasUnlimitedProjects.value || hasUnlimitedProjects.value ||
(teamProjectsAvailable.value && !teamProjectLimitExceeded.value), (isTeamProjectFeatureEnabled.value && !isTeamProjectLimitExceeded.value),
); );
const hasPermissionToCreateProjects = computed(() => const hasPermissionToCreateProjects = computed(() =>
hasPermission(['rbac'], { rbac: { scope: 'project:create' } }), hasPermission(['rbac'], { rbac: { scope: 'project:create' } }),
@ -199,7 +199,7 @@ export const useProjectsStore = defineStore('projects', () => {
hasUnlimitedProjects, hasUnlimitedProjects,
canCreateProjects, canCreateProjects,
hasPermissionToCreateProjects, hasPermissionToCreateProjects,
teamProjectsAvailable, isTeamProjectFeatureEnabled,
projectNavActiveId, projectNavActiveId,
setCurrentProject, setCurrentProject,
getAllProjects, getAllProjects,