Skip to content

Commit

Permalink
Merge pull request #890 from terrestris/create-entities-from-provider…
Browse files Browse the repository at this point in the history
…-endpoints

Introduce buttons to create users, groups and roles from the respective provider
  • Loading branch information
dnlkoch authored Nov 12, 2024
2 parents 0d0cf07 + a47407f commit be2b36a
Show file tree
Hide file tree
Showing 26 changed files with 1,427 additions and 552 deletions.
34 changes: 11 additions & 23 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"@monaco-editor/react": "4.6.0",
"@terrestris/base-util": "3.0.0",
"@terrestris/ol-util": "21.0.0",
"@terrestris/shogun-util": "9.1.1",
"@terrestris/shogun-util": "10.2.0",
"@uiw/react-md-editor": "4.0.4",
"antd": "5.21.5",
"i18next-browser-languagedetector": "8.0.0",
Expand Down
62 changes: 62 additions & 0 deletions src/Component/CreateAllGroupsButton/CreateAllGroupsButton.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from 'react';

import {
cleanup,
fireEvent,
render,
screen,
waitForElementToBeRemoved
} from '@testing-library/react';

import SHOGunAPIClient from '@terrestris/shogun-util/dist/service/SHOGunAPIClient';

import { CreateAllGroupsButton } from './CreateAllGroupsButton';
import GroupService from '@terrestris/shogun-util/dist/service/GroupService';
import Group from '@terrestris/shogun-util/dist/model/Group';

import type { PartialOmit } from '../../test-util';

const mockService: Partial<GroupService<Group>> = {
createAllFromProvider: jest.fn()
};

const mockSHOGunAPIClient: PartialOmit<SHOGunAPIClient, 'group'> = {
group: jest.fn().mockReturnValue(mockService)
};

jest.mock('../../Hooks/useSHOGunAPIClient', () => {
const originalModule = jest.requireActual('../../Hooks/useSHOGunAPIClient');
return {
__esModule: true,
...originalModule,
default: jest.fn(() => mockSHOGunAPIClient)
};
});

describe('<CreateAllGroupsButton />', () => {

afterEach(cleanup);

it('can be rendered', () => {
const {
container
} = render(
<CreateAllGroupsButton />);

expect(container).toBeVisible();
});

it('calls the appropriate service method', async () => {
render(<CreateAllGroupsButton />);

const buttonElement = screen.getByText('CreateAllGroupsButton.title');

fireEvent.click(buttonElement);

expect(mockSHOGunAPIClient.group().createAllFromProvider).toHaveBeenCalled();

await waitForElementToBeRemoved(() => screen.queryByLabelText('loading'));

expect(screen.getByText('CreateAllGroupsButton.success')).toBeVisible();
});
});
81 changes: 81 additions & 0 deletions src/Component/CreateAllGroupsButton/CreateAllGroupsButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React, {
useState
} from 'react';

import {
UsergroupAddOutlined
} from '@ant-design/icons';
import {
Button,
message,
Tooltip
} from 'antd';
import { ButtonProps } from 'antd/lib/button';

import { useTranslation } from 'react-i18next';

import useSHOGunAPIClient from '../../Hooks/useSHOGunAPIClient';

import Logger from '../../Logger';

export type CreateAllGroupsButtonProps = Omit<ButtonProps, 'onClick' | 'loading'> & {
onSuccess?: () => void;
onError?: (error: any) => void;
};

export const CreateAllGroupsButton: React.FC<CreateAllGroupsButtonProps> = ({
onSuccess,
onError,
...passThroughProps
}) => {

const [isLoading, setIsLoading] = useState<boolean>(false);

const [messageApi, contextHolder] = message.useMessage();

const client = useSHOGunAPIClient();

const {
t
} = useTranslation();

const onCreateGroupsClick = async () => {
setIsLoading(true);

try {
await client?.group().createAllFromProvider();

messageApi.success(t('CreateAllGroupsButton.success'));

onSuccess?.();
} catch (error) {
messageApi.error(t('CreateAllGroupsButton.error'));

Logger.error('Error while creating the groups: ', error);

onError?.(error);
} finally {
setIsLoading(false);
}
};

return (
<>
{contextHolder}
<Tooltip
title={t('CreateAllGroupsButton.tooltip')}
>
<Button
onClick={onCreateGroupsClick}
loading={isLoading}
icon={<UsergroupAddOutlined />}
{...passThroughProps}
>
{t('CreateAllGroupsButton.title')}
</Button>
</Tooltip>
</>
);
};

export default CreateAllGroupsButton;
62 changes: 62 additions & 0 deletions src/Component/CreateAllRolesButton/CreateAllRolesButton.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from 'react';

import {
cleanup,
fireEvent,
render,
screen,
waitForElementToBeRemoved
} from '@testing-library/react';

import SHOGunAPIClient from '@terrestris/shogun-util/dist/service/SHOGunAPIClient';

import { CreateAllRolesButton } from './CreateAllRolesButton';
import RoleService from '@terrestris/shogun-util/dist/service/RoleService';
import Role from '@terrestris/shogun-util/dist/model/Role';

import type { PartialOmit } from '../../test-util';

const mockService: Partial<RoleService<Role>> = {
createAllFromProvider: jest.fn()
};

const mockSHOGunAPIClient: PartialOmit<SHOGunAPIClient, 'role'> = {
role: jest.fn().mockReturnValue(mockService)
};

jest.mock('../../Hooks/useSHOGunAPIClient', () => {
const originalModule = jest.requireActual('../../Hooks/useSHOGunAPIClient');
return {
__esModule: true,
...originalModule,
default: jest.fn(() => mockSHOGunAPIClient)
};
});

describe('<CreateAllRolesButton />', () => {

afterEach(cleanup);

it('can be rendered', () => {
const {
container
} = render(
<CreateAllRolesButton />);

expect(container).toBeVisible();
});

it('calls the appropriate service method', async () => {
render(<CreateAllRolesButton />);

const buttonElement = screen.getByText('CreateAllRolesButton.title');

fireEvent.click(buttonElement);

expect(mockSHOGunAPIClient.role().createAllFromProvider).toHaveBeenCalled();

await waitForElementToBeRemoved(() => screen.queryByLabelText('loading'));

expect(screen.getByText('CreateAllRolesButton.success')).toBeVisible();
});
});
81 changes: 81 additions & 0 deletions src/Component/CreateAllRolesButton/CreateAllRolesButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React, {
useState
} from 'react';

import {
TagOutlined
} from '@ant-design/icons';
import {
Button,
message,
Tooltip
} from 'antd';
import { ButtonProps } from 'antd/lib/button';

import { useTranslation } from 'react-i18next';

import useSHOGunAPIClient from '../../Hooks/useSHOGunAPIClient';

import Logger from '../../Logger';

export type CreateAllRolesButtonProps = Omit<ButtonProps, 'onClick' | 'loading'> & {
onSuccess?: () => void;
onError?: (error: any) => void;
};

export const CreateAllRolesButton: React.FC<CreateAllRolesButtonProps> = ({
onSuccess,
onError,
...passThroughProps
}) => {

const [isLoading, setIsLoading] = useState<boolean>(false);

const [messageApi, contextHolder] = message.useMessage();

const client = useSHOGunAPIClient();

const {
t
} = useTranslation();

const onCreateRolesClick = async () => {
setIsLoading(true);

try {
await client?.role().createAllFromProvider();

messageApi.success(t('CreateAllRolesButton.success'));

onSuccess?.();
} catch (error) {
messageApi.error(t('CreateAllRolesButton.error'));

Logger.error('Error while creating the roles: ', error);

onError?.(error);
} finally {
setIsLoading(false);
}
};

return (
<>
{contextHolder}
<Tooltip
title={t('CreateAllRolesButton.tooltip')}
>
<Button
onClick={onCreateRolesClick}
loading={isLoading}
icon={<TagOutlined />}
{...passThroughProps}
>
{t('CreateAllRolesButton.title')}
</Button>
</Tooltip>
</>
);
};

export default CreateAllRolesButton;
Loading

0 comments on commit be2b36a

Please sign in to comment.