WIP Advanced filter.

This commit is contained in:
Ahmed Bouhuolia
2020-03-23 23:00:37 +02:00
parent 52f94c30f5
commit 2ab714127a
7 changed files with 180 additions and 17 deletions

View File

@@ -1,4 +1,4 @@
import React, { useMemo } from 'react';
import React, { useMemo, useState } from 'react';
import Icon from 'components/Icon';
import {
Button,
@@ -19,23 +19,32 @@ import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
import DialogConnect from 'connectors/Dialog.connector';
import AccountsConnect from 'connectors/Accounts.connector';
import {compose} from 'utils';
import FilterDropdown from 'components/FilterDropdown';
import ResourceConnect from 'connectors/Resource.connector';
function AccountsActionsBar({
openDialog,
views,
bulkActions,
getResourceFields,
onFilterChange,
}) {
const {path} = useRouteMatch();
const onClickNewAccount = () => { openDialog('account-form', {}); };
const accountsFields = getResourceFields('accounts');
const viewsMenuItems = views.map((view) => {
return (<MenuItem href={`${path}/${view.id}/custom_view`} text={view.name} />);
});
const hasBulkActionsSelected = useMemo(() => {
return Object.keys(bulkActions).length > 0;
}, [bulkActions]);
const filterDropdown = FilterDropdown({
fields: accountsFields,
onFilterChange,
});
return (
<DashboardActionsBar>
<NavbarGroup>
@@ -60,6 +69,18 @@ function AccountsActionsBar({
text="New Account"
onClick={onClickNewAccount} />
<Popover
content={filterDropdown}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}>
<Button
className={classNames(Classes.MINIMAL, 'button--filter')}
text="Filter"
icon={ <Icon icon="filter" /> } />
</Popover>
{hasBulkActionsSelected && (
<Button
className={Classes.MINIMAL}
@@ -95,5 +116,6 @@ const mapStateToProps = (state) => {
export default compose(
DialogConnect,
AccountsConnect,
ResourceConnect,
connect(mapStateToProps),
)(AccountsActionsBar);

View File

@@ -26,6 +26,7 @@ import ViewConnect from 'connectors/View.connector';
import LoadingIndicator from 'components/LoadingIndicator';
function AccountsDataTable({
filterConditions,
accounts,
onDeleteAccount,
onInactiveAccount,
@@ -43,9 +44,17 @@ function AccountsDataTable({
// Fetch accounts list according to the given custom view id.
const fetchHook = useAsync(async () => {
await Promise.all([
fetchAccounts({ custom_view_id: customViewId }),
fetchAccounts({
custom_view_id: customViewId,
stringified_filter_roles: JSON.stringify(filterConditions) || '',
}),
]);
});
useEffect(() => {
fetchHook.execute();
}, [filterConditions]);
// Refetch accounts list after custom view id change.
useEffect(() => {
const viewMeta = getViewItem(customViewId);

View File

@@ -0,0 +1,127 @@
import React, {useEffect, useMemo} from 'react';
import {
FormGroup,
InputGroup,
Classes,
HTMLSelect,
Button,
Intent,
} from "@blueprintjs/core"
import { useFormik } from 'formik';
import { isEqual } from 'lodash';
import { usePrevious } from 'react-use';
import Icon from 'components/Icon';
export default function FilterDropdown({
fields,
onFilterChange,
}) {
const conditionalsItems = [
{ value: 'and', label: 'AND' },
{ value: 'or', label: 'OR' },
];
const resourceFields = [
...fields.map((field) => ({ value: field.key, label: field.label_name, })),
];
const compatatorsItems = [
{value: '', label: 'Select a compatator'},
{value: 'equals', label: 'Equals'},
{value: 'not_equal', label: 'Not Equal'},
{value: 'contain', label: 'Contain'},
{value: 'not_contain', label: 'Not Contain'},
];
const defaultFilterCondition = {
condition: 'and',
field_key: fields.length > 0 ? fields[0].key : '',
compatator: 'equals',
value: '',
};
const formik = useFormik({
initialValues: {
conditions: [ defaultFilterCondition ],
},
});
const onClickNewFilter = () => {
formik.setFieldValue('conditions', [
...formik.values.conditions, defaultFilterCondition,
]);
};
const filteredFilterConditions = useMemo(() => {
return formik.values.conditions.filter(condition => !!condition.value);
}, [formik.values.conditions]);
const prevConditions = usePrevious(filteredFilterConditions);
const onClickRemoveCondition = (index) => () => {
if (formik.values.conditions.length === 1) { return; }
const conditions = [ ...formik.values.conditions ];
conditions.splice(index, 1);
formik.setFieldValue('conditions', [ ...conditions ]);
}
useEffect(() => {
if (!isEqual(filteredFilterConditions, prevConditions)) {
onFilterChange(filteredFilterConditions);
}
}, [filteredFilterConditions])
return (
<div class="filter-dropdown">
<div class="filter-dropdown__body">
{formik.values.conditions.map((condition, index) => (
<div class="filter-dropdown__condition">
<FormGroup
className={'form-group--condition'}>
<HTMLSelect
options={conditionalsItems}
className={Classes.FILL}
disabled={index > 1}
{...formik.getFieldProps(`conditions[${index}].condition`)} />
</FormGroup>
<FormGroup
className={'form-group--field'}>
<HTMLSelect
options={resourceFields}
value={1}
className={Classes.FILL}
{...formik.getFieldProps(`conditions[${index}].field_key`)} />
</FormGroup>
<FormGroup
className={'form-group--compatator'}>
<HTMLSelect
options={compatatorsItems}
className={Classes.FILL}
{...formik.getFieldProps(`conditions[${index}].compatator`)} />
</FormGroup>
<FormGroup
className={'form-group--value'}>
<InputGroup
placeholder="Value"
{...formik.getFieldProps(`conditions[${index}].value`)} />
</FormGroup>
<Button
icon={<Icon icon="times" />}
iconSize={14}
minimal={true}
onClick={onClickRemoveCondition(index)} />
</div>
))}
</div>
<div class="filter-dropdown__footer">
<Button
minimal={true}
intent={Intent.PRIMARY}
onClick={onClickNewFilter}>
+ New Conditional
</Button>
</div>
</div>
)
}