Skip to content

Commit

Permalink
feat(TDOPS-4789/facetedSearch): callback support for BadgeMenu (#5022)
Browse files Browse the repository at this point in the history
* feat(TDOPS-4789/facetedSearch): callback support for BadgeMenu

* fix: isEmpty import

* feat(TDOPS-4789/facetedSearch): callback support for BadgeMenu

* feat(TDOPS-4789/facetedSearch): callback support for BadgeMenu

---------

Co-authored-by: Inna Ivashchuk <[email protected]>
  • Loading branch information
ybaskaran and inna-i authored Dec 5, 2023
1 parent 38dad22 commit fc7d4e2
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 26 deletions.
5 changes: 5 additions & 0 deletions .changeset/purple-trains-hug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@talend/react-faceted-search': minor
---

feat(TDOPS-4789/facetedSearch): callback support for BadgeMenu
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import { useMemo } from 'react';
import { isEmpty } from 'lodash';
import { useEffect, useMemo, useState } from 'react';

import isEmpty from 'lodash/isEmpty';
import isObject from 'lodash/isObject';
import PropTypes from 'prop-types';

import Badge from '@talend/react-components/lib/Badge';

import {
callbacksPropTypes,
operatorPropTypes,
operatorsPropTypes,
} from '../../facetedSearch.propTypes';
import { BadgeFaceted } from '../BadgeFaceted';
import { BadgeMenuForm } from './BadgeMenuForm.component';
import { operatorPropTypes, operatorsPropTypes } from '../../facetedSearch.propTypes';

const getSelectBadgeLabel = (value, t) => {
const labelAll = t('FACETED_SEARCH_VALUE_ALL', { defaultValue: 'All' });
Expand All @@ -31,10 +38,37 @@ export const BadgeMenu = ({
displayType,
filterBarPlaceholder,
t,
callbacks,
...rest
}) => {
const [options, setOptions] = useState(values);
const currentOperators = useMemo(() => operators, [operators]);
const currentOperator = operator || (currentOperators && currentOperators[0]);
const [isLoading, setIsLoading] = useState(true);
const callback = callbacks && callbacks[rest.attribute];
useEffect(() => {
if (!callback || !callback.getOptions) {
setIsLoading(false);
return;
}

setIsLoading(true);
callback
.getOptions()
.then(data => {
setOptions(
data.map(item => {
if (isObject(item)) {
return { id: item.id, label: item.label };
}
return { id: item, label: item };
}),
);
})
.finally(() => {
setIsLoading(false);
});
}, [callback]);
const badgeMenuId = `${id}-badge-menu`;
const badgeLabel = useMemo(() => getSelectBadgeLabel(value, t), [value, t]);
return (
Expand All @@ -60,8 +94,9 @@ export const BadgeMenu = ({
onChange={onChangeValue}
onSubmit={onSubmitBadge}
value={badgeValue}
values={values}
values={options}
filterBarPlaceholder={filterBarPlaceholder}
isLoading={isLoading}
t={t}
{...rest}
/>
Expand Down Expand Up @@ -89,6 +124,7 @@ BadgeMenu.propTypes = {
readOnly: PropTypes.bool,
removable: PropTypes.bool,
values: PropTypes.array,
callbacks: callbacksPropTypes,
t: PropTypes.func.isRequired,
displayType: PropTypes.oneOf(Object.values(Badge.TYPES)),
filterBarPlaceholder: PropTypes.string,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { render } from '@testing-library/react';
import { BadgeFacetedProvider } from '../../context/badgeFaceted.context';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import { BadgeMenu } from './BadgeMenu.component';
import getDefaultT from '../../../translate';
import { BadgeFacetedProvider } from '../../context/badgeFaceted.context';
import { BadgeMenu } from './BadgeMenu.component';

const t = getDefaultT();

Expand All @@ -15,6 +16,7 @@ const badgeFacetedContextValue = {
onDeleteBadge: jest.fn(),
onHideOperator: jest.fn(),
onSubmitBadge: jest.fn(),
dispatch: jest.fn(),
};

const BadgeWithContext = props => (
Expand Down Expand Up @@ -53,4 +55,56 @@ describe('BadgeMenu', () => {
// Then
expect(document.querySelectorAll('span')[2]).toHaveTextContent('All');
});
it('should mount a badge with object data from callback', async () => {
// Given
const callbacks = {
id: {
getOptions: () => new Promise(resolve => resolve([{ id: '1234', label: 'production' }])),
},
};

const props = {
id: 'myId',
label: 'myLabel',
initialOperatorOpened: false,
initialValueOpened: true,
operators: ['in'],
callbacks,
values: [],
t: getDefaultT(),
attribute: 'id',
};

// When
render(
<BadgeFacetedProvider value={badgeFacetedContextValue}>
<BadgeMenu {...props} />
</BadgeFacetedProvider>,
);

// Then there is a checkbox with data taken from callback
await waitFor(() => {
expect(screen.getByRole('menuitem')).toBeVisible();
});
// Then selecting an item should dispatch proper payload
await userEvent.click(screen.getByRole('menuitem', { name: 'production' }));
await userEvent.click(
screen.getByRole('button', {
name: /apply/i,
}),
);
expect(badgeFacetedContextValue.dispatch).toHaveBeenCalledWith({
payload: {
badgeId: 'myId',
metadata: { isInCreation: false },
properties: {
initialOperatorOpened: false,
initialValueOpened: false,
operator: 'in',
value: { checked: false, id: '1234', label: 'production' },
},
},
type: 'UPDATE_BADGE',
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,8 @@ $popover-screen-width: tokens.$coral-sizing-maximal;
width: $popover-screen-width;
padding-left: 0;
}

:global(.tc-circular-progress) {
height: 100%;
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
/* eslint-disable jsx-a11y/no-autofocus */
import { useMemo, useState } from 'react';

import get from 'lodash/get';
import isEmpty from 'lodash/isEmpty';
import PropTypes from 'prop-types';

import { DropdownButton } from '@talend/design-system';
import { Action } from '@talend/react-components/lib/Actions';
import FilterBar from '@talend/react-components/lib/FilterBar';
import Rich from '@talend/react-components/lib/Rich';
import { getTheme } from '@talend/react-components/lib/theme';
import CircularProgress from '@talend/react-components/src/CircularProgress';

import cssModule from './BadgeMenu.module.scss';
import { getDataAttributesFrom } from '../../../helpers/usage.helpers';

import cssModule from './BadgeMenu.module.scss';

const theme = getTheme(cssModule);

const createRowItemEntity = value => option => {
Expand Down Expand Up @@ -84,21 +88,25 @@ const BadgeMenuForm = ({
onSubmit={onSubmit}
>
<Rich.Layout.Body id={badgeMenuFormId} className={theme('fs-badge-menu-form-body')}>
{visibleItems.map(rowItem => {
return (
<DropdownButton
key={rowItem.id}
onClick={event => {
onChange(event, rowItem);
}}
checked={rowItem.checked}
data-testid={`badge-menu-form-item-${rowItem.id}`}
data-test={`badge-menu-form-item-${rowItem.id}`}
>
<span>{rowItem.label}</span>
</DropdownButton>
);
})}
{!rest.isLoading ? (
visibleItems.map(rowItem => {
return (
<DropdownButton
key={rowItem.id}
onClick={event => {
onChange(event, rowItem);
}}
checked={rowItem.checked}
data-testid={`badge-menu-form-item-${rowItem.id}`}
data-test={`badge-menu-form-item-${rowItem.id}`}
>
<span>{rowItem.label}</span>
</DropdownButton>
);
})
) : (
<CircularProgress />
)}
</Rich.Layout.Body>
<Rich.Layout.Footer id={id} className={theme('fs-badge-menu-form-footer')}>
<div>
Expand All @@ -119,6 +127,7 @@ const BadgeMenuForm = ({
type="submit"
label={t('APPLY', { defaultValue: 'Apply' })}
bsStyle="info"
disabled={rest.isLoading}
{...getDataAttributesFrom(rest)}
/>
</Rich.Layout.Footer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,22 @@ describe('BadgeMenuForm', () => {
label: 'Item One',
});
});
it('should show loader icon if items are loading', () => {
// Given
const props = {
id: 'myId',
values: menuItems,
isLoading: true,
value: {},
t,
};
// When
render(<BadgeMenuForm {...props} />);
// Then
expect(screen.getByTestId('circular-progress')).toBeVisible();
expect(screen.getByRole('button')).toHaveAttribute('type', 'submit');
expect(screen.getByRole('button')).toBeDisabled();
});
it('should display menuitem checked', () => {
// Given
const props = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { useEffect, useMemo, useState } from 'react';

import isObject from 'lodash/isObject';
import PropTypes from 'prop-types';

import Badge from '@talend/react-components/lib/Badge';
import { BadgeTagsForm } from './BadgeTagsForm.component';
import { BadgeFaceted } from '../BadgeFaceted';

import {
callbacksPropTypes,
operatorPropTypes,
operatorsPropTypes,
} from '../../facetedSearch.propTypes';
import { BadgeFaceted } from '../BadgeFaceted';
import { BadgeTagsForm } from './BadgeTagsForm.component';

const getSelectBadgeLabel = (value, t) => {
const labelAll = t('FACETED_SEARCH_VALUE_ALL', { defaultValue: 'All' });
Expand Down Expand Up @@ -46,7 +49,7 @@ export const BadgeTags = ({
...rest
}) => {
const [tagsValues, setTagsValues] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
if (!callbacks || !callbacks.getTags) {
setIsLoading(false);
Expand Down

0 comments on commit fc7d4e2

Please sign in to comment.