1865 implement a tooltip with smart filters documentation (#1952)
* Added QuestionIcon * Added Info button functionality and tests * Styled component renamed * Info button testing moved to AddFilter spec * Styled paragraph renamed
This commit is contained in:
parent
7eab325ac3
commit
18eadfca28
6 changed files with 173 additions and 2 deletions
|
@ -4,8 +4,11 @@ import { MessageFilters } from 'components/Topics/Topic/Details/Messages/Filters
|
||||||
import { FilterEdit } from 'components/Topics/Topic/Details/Messages/Filters/FilterModal';
|
import { FilterEdit } from 'components/Topics/Topic/Details/Messages/Filters/FilterModal';
|
||||||
import SavedFilters from 'components/Topics/Topic/Details/Messages/Filters/SavedFilters';
|
import SavedFilters from 'components/Topics/Topic/Details/Messages/Filters/SavedFilters';
|
||||||
import SavedIcon from 'components/common/Icons/SavedIcon';
|
import SavedIcon from 'components/common/Icons/SavedIcon';
|
||||||
|
import QuestionIcon from 'components/common/Icons/QuestionIcon';
|
||||||
|
import useModal from 'lib/hooks/useModal';
|
||||||
|
|
||||||
import AddEditFilterContainer from './AddEditFilterContainer';
|
import AddEditFilterContainer from './AddEditFilterContainer';
|
||||||
|
import InfoModal from './InfoModal';
|
||||||
|
|
||||||
export interface FilterModalProps {
|
export interface FilterModalProps {
|
||||||
toggleIsOpen(): void;
|
toggleIsOpen(): void;
|
||||||
|
@ -32,6 +35,7 @@ const AddFilter: React.FC<FilterModalProps> = ({
|
||||||
}) => {
|
}) => {
|
||||||
const [savedFilterState, setSavedFilterState] =
|
const [savedFilterState, setSavedFilterState] =
|
||||||
React.useState<boolean>(false);
|
React.useState<boolean>(false);
|
||||||
|
const { isOpen, toggle } = useModal();
|
||||||
|
|
||||||
const onSubmit = React.useCallback(
|
const onSubmit = React.useCallback(
|
||||||
async (values: AddMessageFilters) => {
|
async (values: AddMessageFilters) => {
|
||||||
|
@ -52,7 +56,19 @@ const AddFilter: React.FC<FilterModalProps> = ({
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<S.FilterTitle>Add filter</S.FilterTitle>
|
<S.FilterTitle>
|
||||||
|
Add filter
|
||||||
|
<div>
|
||||||
|
<S.QuestionIconContainer
|
||||||
|
type="button"
|
||||||
|
aria-label="info"
|
||||||
|
onClick={toggle}
|
||||||
|
>
|
||||||
|
<QuestionIcon />
|
||||||
|
</S.QuestionIconContainer>
|
||||||
|
{isOpen && <InfoModal toggleIsOpen={toggle} />}
|
||||||
|
</div>
|
||||||
|
</S.FilterTitle>
|
||||||
{savedFilterState ? (
|
{savedFilterState ? (
|
||||||
<SavedFilters
|
<SavedFilters
|
||||||
deleteFilter={deleteFilter}
|
deleteFilter={deleteFilter}
|
||||||
|
|
|
@ -102,6 +102,29 @@ export const ClearAll = styled.span`
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const ButtonContainer = styled.div`
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ListItem = styled.li`
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
margin-left: 20px;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: ${({ theme }) => theme.table.td.color.normal};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const InfoParagraph = styled.p`
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.5;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: ${({ theme }) => theme.table.td.color.normal};
|
||||||
|
`;
|
||||||
|
|
||||||
export const MessageFilterModal = styled.div`
|
export const MessageFilterModal = styled.div`
|
||||||
height: auto;
|
height: auto;
|
||||||
width: 560px;
|
width: 560px;
|
||||||
|
@ -115,11 +138,34 @@ export const MessageFilterModal = styled.div`
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const InfoModal = styled.div`
|
||||||
|
height: auto;
|
||||||
|
width: 560px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: ${({ theme }) => theme.modal.backgroundColor};
|
||||||
|
position: absolute;
|
||||||
|
left: 25%;
|
||||||
|
border: 1px solid ${({ theme }) => theme.breadcrumb};
|
||||||
|
box-shadow: ${({ theme }) => theme.modal.shadow};
|
||||||
|
padding: 32px;
|
||||||
|
z-index: 1;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const QuestionIconContainer = styled.button`
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
`;
|
||||||
|
|
||||||
export const FilterTitle = styled.h3`
|
export const FilterTitle = styled.h3`
|
||||||
line-height: 32px;
|
line-height: 32px;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
margin-bottom: 40px;
|
margin-bottom: 40px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
&:after {
|
&:after {
|
||||||
content: '';
|
content: '';
|
||||||
width: calc(100% + 32px);
|
width: calc(100% + 32px);
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
import React from 'react';
|
||||||
|
import * as S from 'components/Topics/Topic/Details/Messages/Filters/Filters.styled';
|
||||||
|
import { Button } from 'components/common/Button/Button';
|
||||||
|
|
||||||
|
export interface InfoModalProps {
|
||||||
|
toggleIsOpen(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const InfoModal: React.FC<InfoModalProps> = ({ toggleIsOpen }) => {
|
||||||
|
return (
|
||||||
|
<S.InfoModal>
|
||||||
|
<S.InfoParagraph>
|
||||||
|
<b>Variables bound to groovy context:</b> partition, timestampMs,
|
||||||
|
keyAsText, valueAsText, header, key (json if possible), value (json if
|
||||||
|
possible).
|
||||||
|
</S.InfoParagraph>
|
||||||
|
<S.InfoParagraph>
|
||||||
|
<b>JSON parsing logic:</b>
|
||||||
|
</S.InfoParagraph>
|
||||||
|
<S.InfoParagraph>
|
||||||
|
Key and Value (if they can be parsed to JSON) they are bound as JSON
|
||||||
|
objects, otherwise bound as nulls.
|
||||||
|
</S.InfoParagraph>
|
||||||
|
<S.InfoParagraph>
|
||||||
|
<b>Sample filters:</b>
|
||||||
|
</S.InfoParagraph>
|
||||||
|
<ol aria-label="info-list">
|
||||||
|
<S.ListItem>
|
||||||
|
`keyAsText != null && keyAsText ~"([Gg])roovy"` - regex for
|
||||||
|
key as a string
|
||||||
|
</S.ListItem>
|
||||||
|
<S.ListItem>
|
||||||
|
`value.name == "iS.ListItemax" && value.age > 30` - in
|
||||||
|
case value is json
|
||||||
|
</S.ListItem>
|
||||||
|
<S.ListItem>
|
||||||
|
`value == null && valueAsText != null` - search for values that are
|
||||||
|
not nulls and are not json
|
||||||
|
</S.ListItem>
|
||||||
|
<S.ListItem>
|
||||||
|
`headers.sentBy == "some system" &&
|
||||||
|
headers["sentAt"] == "2020-01-01"`
|
||||||
|
</S.ListItem>
|
||||||
|
<S.ListItem>multiS.ListItemne filters are also allowed:</S.ListItem>
|
||||||
|
</ol>
|
||||||
|
<S.ButtonContainer>
|
||||||
|
<Button
|
||||||
|
buttonSize="M"
|
||||||
|
buttonType="secondary"
|
||||||
|
type="button"
|
||||||
|
onClick={toggleIsOpen}
|
||||||
|
>
|
||||||
|
Ok
|
||||||
|
</Button>
|
||||||
|
</S.ButtonContainer>
|
||||||
|
</S.InfoModal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default InfoModal;
|
|
@ -36,6 +36,18 @@ describe('AddFilter component', () => {
|
||||||
expect(screen.getAllByRole('savedFilter')).toHaveLength(2);
|
expect(screen.getAllByRole('savedFilter')).toHaveLength(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('info button to be in the document', () => {
|
||||||
|
renderComponent();
|
||||||
|
expect(screen.getByRole('button', { name: 'info' })).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders InfoModal', () => {
|
||||||
|
renderComponent();
|
||||||
|
userEvent.click(screen.getByRole('button', { name: 'info' }));
|
||||||
|
expect(screen.getByRole('button', { name: 'Ok' })).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole('list', { name: 'info-list' })).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
it('should test click on return to custom filter redirects to Add filters', async () => {
|
it('should test click on return to custom filter redirects to Add filters', async () => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
userEvent.click(screen.getByRole('savedFilterText'));
|
userEvent.click(screen.getByRole('savedFilterText'));
|
||||||
|
@ -159,7 +171,7 @@ describe('AddFilter component', () => {
|
||||||
it('OnSubmit condition with checkbox on functionality', async () => {
|
it('OnSubmit condition with checkbox on functionality', async () => {
|
||||||
await act(() => {
|
await act(() => {
|
||||||
userEvent.click(screen.getByRole('checkbox'));
|
userEvent.click(screen.getByRole('checkbox'));
|
||||||
userEvent.click(screen.getAllByRole('button')[1]);
|
userEvent.click(screen.getAllByRole('button')[2]);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(activeFilterHandlerMock).not.toHaveBeenCalled();
|
expect(activeFilterHandlerMock).not.toHaveBeenCalled();
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
import { screen } from '@testing-library/react';
|
||||||
|
import { render } from 'lib/testHelpers';
|
||||||
|
import React from 'react';
|
||||||
|
import InfoModal from 'components/Topics/Topic/Details/Messages/Filters/InfoModal';
|
||||||
|
|
||||||
|
describe('InfoModal component', () => {
|
||||||
|
it('closes InfoModal', () => {
|
||||||
|
const toggleInfoModal = jest.fn();
|
||||||
|
render(<InfoModal toggleIsOpen={toggleInfoModal} />);
|
||||||
|
userEvent.click(screen.getByRole('button', { name: 'Ok' }));
|
||||||
|
expect(toggleInfoModal).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,23 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { useTheme } from 'styled-components';
|
||||||
|
|
||||||
|
const QuestionIcon: React.FC = () => {
|
||||||
|
const theme = useTheme();
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="19"
|
||||||
|
height="19"
|
||||||
|
viewBox="0 0 19 19"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<circle cx="9.5" cy="9.5" r="8.5" stroke="#5C5CF6" strokeWidth="2" />
|
||||||
|
<path
|
||||||
|
d="M8.31818 11.2727V11.0682C8.31818 10.5994 8.35511 10.2259 8.42898 9.94744C8.50284 9.66903 8.61222 9.44602 8.7571 9.27841C8.90199 9.10795 9.07955 8.95455 9.28977 8.81818C9.47159 8.69886 9.63352 8.58381 9.77557 8.47301C9.92045 8.36222 10.0341 8.24432 10.1165 8.11932C10.2017 7.99432 10.2443 7.85227 10.2443 7.69318C10.2443 7.55114 10.2102 7.42614 10.142 7.31818C10.0739 7.21023 9.98153 7.12642 9.86506 7.06676C9.74858 7.0071 9.61932 6.97727 9.47727 6.97727C9.32386 6.97727 9.18182 7.01278 9.05114 7.08381C8.9233 7.15483 8.8196 7.25284 8.74006 7.37784C8.66335 7.50284 8.625 7.64773 8.625 7.8125H6.44318C6.44886 7.1875 6.59091 6.6804 6.86932 6.29119C7.14773 5.89915 7.51705 5.61222 7.97727 5.4304C8.4375 5.24574 8.94318 5.15341 9.49432 5.15341C10.1023 5.15341 10.6449 5.2429 11.1222 5.42188C11.5994 5.59801 11.9759 5.86506 12.2514 6.22301C12.527 6.57812 12.6648 7.02273 12.6648 7.55682C12.6648 7.90057 12.6051 8.20312 12.4858 8.46449C12.3693 8.72301 12.206 8.9517 11.9957 9.15057C11.7884 9.34659 11.5455 9.52557 11.267 9.6875C11.0625 9.80682 10.8906 9.9304 10.7514 10.0582C10.6122 10.1832 10.5071 10.3267 10.4361 10.4886C10.3651 10.6477 10.3295 10.8409 10.3295 11.0682V11.2727H8.31818ZM9.35795 14.1364C9.02841 14.1364 8.74574 14.0213 8.50994 13.7912C8.27699 13.5582 8.16193 13.2756 8.16477 12.9432C8.16193 12.6193 8.27699 12.3423 8.50994 12.1122C8.74574 11.8821 9.02841 11.767 9.35795 11.767C9.67045 11.767 9.94602 11.8821 10.1847 12.1122C10.4261 12.3423 10.5483 12.6193 10.5511 12.9432C10.5483 13.1648 10.4901 13.3665 10.3764 13.5483C10.2656 13.7273 10.1207 13.8707 9.94176 13.9787C9.76278 14.0838 9.56818 14.1364 9.35795 14.1364Z"
|
||||||
|
fill={theme.icons.savedIcon}
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default QuestionIcon;
|
Loading…
Add table
Reference in a new issue