* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { Spinner } from '@sonarsource/echoes-react';
import { MultiSelector, SubHeading, Tags } from 'design-system';
import { difference, without } from 'lodash';
-import React, { useState } from 'react';
+import React, { useEffect, useState } from 'react';
import { searchProjectTags, setApplicationTags, setProjectTags } from '../../../../api/components';
import Tooltip from '../../../../components/controls/Tooltip';
import { PopupPlacement } from '../../../../components/ui/popups';
}
export default function MetaTags(props: Props) {
- const [open, setOpen] = React.useState(false);
+ const [loading, setLoading] = useState(false);
+
+ useEffect(() => {
+ setLoading(false);
+ }, [props.component.tags]);
const canUpdateTags = () => {
const { configuration } = props.component;
};
const handleSetProjectTags = (values: string[]) => {
+ setLoading(true);
setTags(values).then(
() => props.onComponentChange({ tags: values }),
() => {},
ariaTagsListLabel={translate('tags')}
className="project-info-tags"
emptyText={translate('no_tags')}
- overlay={<MetaTagsSelector selectedTags={tags} setProjectTags={handleSetProjectTags} />}
+ overlay={
+ <Spinner isLoading={loading}>
+ <MetaTagsSelector selectedTags={tags} setProjectTags={handleSetProjectTags} />
+ </Spinner>
+ }
popupPlacement={PopupPlacement.Bottom}
tags={tags}
tagsToDisplay={2}
tooltip={Tooltip}
- open={open}
- onClose={() => setOpen(false)}
/>
</>
);
import { mockComponent } from '../../../../../helpers/mocks/component';
import { renderComponent } from '../../../../../helpers/testReactTestingUtils';
import { ComponentQualifier } from '../../../../../types/component';
+import { Component } from '../../../../../types/types';
import MetaTags from '../MetaTags';
jest.mock('../../../../../api/components', () => ({
it('should allow to edit tags for a project', async () => {
const user = userEvent.setup();
-
- const onComponentChange = jest.fn();
const component = mockComponent({
key: 'my-second-project',
tags: ['foo', 'bar'],
name: 'MySecondProject',
});
- renderMetaTags({ component, onComponentChange });
+ renderMetaTags(component);
expect(await screen.findByText('foo, bar')).toBeInTheDocument();
expect(screen.getByRole('button')).toBeInTheDocument();
expect(await screen.findByRole('checkbox', { name: 'best' })).toBeInTheDocument();
await user.click(screen.getByRole('checkbox', { name: 'best' }));
- expect(onComponentChange).toHaveBeenCalledWith({ tags: ['foo', 'bar', 'best'] });
-
- onComponentChange.mockClear();
+ expect(await screen.findByRole('button', { name: 'foo bar ... +' })).toBeInTheDocument();
- /*
- * Since we're not actually updating the tags, we're back to having the foo, bar only
- */
await user.click(screen.getByRole('checkbox', { name: 'bar' }));
- expect(onComponentChange).toHaveBeenCalledWith({ tags: ['foo'] });
+
+ expect(await screen.findByRole('button', { name: 'foo best +' })).toBeInTheDocument();
expect(setProjectTags).toHaveBeenCalled();
expect(setApplicationTags).not.toHaveBeenCalled();
it('should set tags for an app', async () => {
const user = userEvent.setup();
- renderMetaTags({
- component: mockComponent({
+ renderMetaTags(
+ mockComponent({
configuration: {
showSettings: true,
},
qualifier: ComponentQualifier.Application,
}),
- });
+ );
await user.click(screen.getByRole('button', { name: 'no_tags +' }));
expect(setApplicationTags).toHaveBeenCalled();
});
-function renderMetaTags(overrides: Partial<Parameters<typeof MetaTags>[0]> = {}) {
- const component = mockComponent({
- configuration: {
- showSettings: false,
- },
- });
-
- return renderComponent(
- <MetaTags component={component} onComponentChange={jest.fn()} {...overrides} />,
- );
+function renderMetaTags(componentOverride: Partial<Component> = {}) {
+ function Component(componentOverride: Partial<Parameters<typeof MetaTags>[0]>) {
+ const [component, setComponent] = React.useState(
+ mockComponent({
+ configuration: {
+ showSettings: false,
+ },
+ ...componentOverride,
+ }),
+ );
+
+ const handleComponentChange = ({ tags }: { tags: string[] }) => {
+ setComponent((c) => {
+ return { ...c, tags };
+ });
+ };
+
+ return <MetaTags component={component} onComponentChange={handleComponentChange} />;
+ }
+
+ return renderComponent(<Component {...componentOverride} />);
}