Skip to content
5 changes: 5 additions & 0 deletions .changeset/sharp-planets-throw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': patch
---

Fixes action buttons added by apps being rendered in the Marketplace Menu rather than the User Menu
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { UIActionButtonContext } from '@rocket.chat/apps-engine/definition/ui';
import { mockAppRoot } from '@rocket.chat/mock-providers';
import { renderHook, waitFor } from '@testing-library/react';
import { renderHook } from '@testing-library/react';

import { useMarketPlaceMenu } from './useMarketPlaceMenu';

Expand Down Expand Up @@ -67,213 +66,3 @@ it('should return `explore`, `installed` and `requested` items if the user has `
}),
);
});

it('should return one action from the server with no conditions', async () => {
const { result } = renderHook(() => useMarketPlaceMenu(), {
wrapper: mockAppRoot()
.withEndpoint('GET', '/apps/actionButtons', () => [
{
appId: 'APP_ID',
actionId: 'ACTION_ID',
labelI18n: 'LABEL_I18N',
context: UIActionButtonContext.USER_DROPDOWN_ACTION,
},
])
.withEndpoint('GET', '/apps/app-request/stats', () => ({
data: {
totalSeen: 0,
totalUnseen: 1,
},
}))
.withPermission('manage-apps')
.build(),
});

expect(result.current[0].items[0]).toEqual(
expect.objectContaining({
id: 'explore',
}),
);

expect(result.current[0].items[1]).toEqual(
expect.objectContaining({
id: 'installed',
}),
);

await waitFor(() =>
expect(result.current[0]?.items[3]).toEqual(
expect.objectContaining({
id: 'APP_ID_ACTION_ID',
}),
),
);
});

describe('Marketplace menu with role conditions', () => {
it('should return the action if the user has admin role', async () => {
const { result } = renderHook(() => useMarketPlaceMenu(), {
wrapper: mockAppRoot()
.withEndpoint('GET', '/apps/actionButtons', () => [
{
appId: 'APP_ID',
actionId: 'ACTION_ID',
labelI18n: 'LABEL_I18N',
context: UIActionButtonContext.USER_DROPDOWN_ACTION,
when: {
hasOneRole: ['admin'],
},
},
])
.withEndpoint('GET', '/apps/app-request/stats', () => ({
data: {
totalSeen: 0,
totalUnseen: 1,
},
}))
.withPermission('manage-apps')
.withJohnDoe()
.withRole('admin')
.build(),
});

expect(result.current[0].items[0]).toEqual(
expect.objectContaining({
id: 'explore',
}),
);

expect(result.current[0].items[1]).toEqual(
expect.objectContaining({
id: 'installed',
}),
);

await waitFor(() =>
expect(result.current[0]?.items[3]).toEqual(
expect.objectContaining({
id: 'APP_ID_ACTION_ID',
}),
),
);
});

it('should return filter the action if the user doesn`t have admin role', async () => {
const { result } = renderHook(() => useMarketPlaceMenu(), {
wrapper: mockAppRoot()
.withEndpoint('GET', '/apps/actionButtons', () => [
{
appId: 'APP_ID',
actionId: 'ACTION_ID',
labelI18n: 'LABEL_I18N',
context: UIActionButtonContext.USER_DROPDOWN_ACTION,
when: {
hasOneRole: ['admin'],
},
},
])
.withEndpoint('GET', '/apps/app-request/stats', () => ({
data: {
totalSeen: 0,
totalUnseen: 1,
},
}))
.withPermission('manage-apps')
.build(),
});

expect(result.current[0].items[0]).toEqual(
expect.objectContaining({
id: 'explore',
}),
);

expect(result.current[0].items[1]).toEqual(
expect.objectContaining({
id: 'installed',
}),
);

expect(result.current[0].items[2]).toEqual(
expect.objectContaining({
id: 'requested-apps',
}),
);

expect(result.current[0].items[3]).toEqual(undefined);
});
});

describe('Marketplace menu with permission conditions', () => {
it('should return the action if the user has manage-apps permission', async () => {
const { result } = renderHook(() => useMarketPlaceMenu(), {
wrapper: mockAppRoot()
.withEndpoint('GET', '/apps/actionButtons', () => [
{
appId: 'APP_ID',
actionId: 'ACTION_ID',
labelI18n: 'LABEL_I18N',
context: UIActionButtonContext.USER_DROPDOWN_ACTION,
when: {
hasOnePermission: ['manage-apps'],
},
},
])
.withEndpoint('GET', '/apps/app-request/stats', () => ({
data: {
totalSeen: 0,
totalUnseen: 1,
},
}))
.withPermission('manage-apps')
.build(),
});

expect(result.current[0].items[0]).toEqual(
expect.objectContaining({
id: 'explore',
}),
);

expect(result.current[0].items[1]).toEqual(
expect.objectContaining({
id: 'installed',
}),
);

await waitFor(() =>
expect(result.current[0].items[3]).toEqual(
expect.objectContaining({
id: 'APP_ID_ACTION_ID',
}),
),
);
});

it('should return filter the action if the user doesn`t have `any` permission', async () => {
const { result } = renderHook(() => useMarketPlaceMenu(), {
wrapper: mockAppRoot()
.withEndpoint('GET', '/apps/actionButtons', () => [
{
appId: 'APP_ID',
actionId: 'ACTION_ID',
labelI18n: 'LABEL_I18N',
context: UIActionButtonContext.USER_DROPDOWN_ACTION,
when: {
hasOnePermission: ['any'],
},
},
])
.withEndpoint('GET', '/apps/app-request/stats', () => ({
data: {
totalSeen: 0,
totalUnseen: 1,
},
}))
.withPermission('manage-apps')
.build(),
});

expect(result.current[0].items[3]).toEqual(undefined);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@ import { Badge, Skeleton } from '@rocket.chat/fuselage';
import type { GenericMenuItemProps } from '@rocket.chat/ui-client';
import { useTranslation, usePermission, useRouter } from '@rocket.chat/ui-contexts';

import { useUserDropdownAppsActionButtons } from '../../../hooks/useUserDropdownAppsActionButtons';
import { useAppRequestStats } from '../../../views/marketplace/hooks/useAppRequestStats';

export const useMarketPlaceMenu = () => {
const t = useTranslation();

const appBoxItems = useUserDropdownAppsActionButtons();

const hasManageAppsPermission = usePermission('manage-apps');
const hasAccessMarketplacePermission = usePermission('access-marketplace');

Expand Down Expand Up @@ -54,11 +51,7 @@ export const useMarketPlaceMenu = () => {
return [
{
title: t('Marketplace'),
items: [
...(showMarketplace ? marketPlaceItems : []),
...(hasManageAppsPermission ? [appsManagementItem] : []),
...(appBoxItems.isSuccess ? appBoxItems.data : []),
],
items: [...(showMarketplace ? marketPlaceItems : []), ...(hasManageAppsPermission ? [appsManagementItem] : [])],
},
];
};
Loading
Loading