Feat: Add "All assignees" in Task team member dropdown (#1763)
* implemented all select option FilterDropdownEntitySearchSelect and enabled it for tasks page filter * created new filter operand IsNotNull for make a select all qraphql query, added internal state for tracking isAllEntitySelected * used filterCurrentlyEdited to track if isAllEntitySelected is selected * fixed filter button icon SelectAll Icon
This commit is contained in:
@ -3043,6 +3043,7 @@ export enum ViewFilterOperand {
|
|||||||
GreaterThan = 'GreaterThan',
|
GreaterThan = 'GreaterThan',
|
||||||
Is = 'Is',
|
Is = 'Is',
|
||||||
IsNot = 'IsNot',
|
IsNot = 'IsNot',
|
||||||
|
IsNotNull = 'IsNotNull',
|
||||||
LessThan = 'LessThan'
|
LessThan = 'LessThan'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { useTheme } from '@emotion/react';
|
||||||
|
|
||||||
|
import { IconComponent } from '@/ui/icon/types/IconComponent';
|
||||||
import { Avatar, AvatarType } from '@/users/components/Avatar';
|
import { Avatar, AvatarType } from '@/users/components/Avatar';
|
||||||
import { isNonEmptyString } from '~/utils/isNonEmptyString';
|
import { isNonEmptyString } from '~/utils/isNonEmptyString';
|
||||||
|
|
||||||
@ -13,6 +15,7 @@ type OwnProps = {
|
|||||||
pictureUrl?: string;
|
pictureUrl?: string;
|
||||||
avatarType?: AvatarType;
|
avatarType?: AvatarType;
|
||||||
variant?: EntityChipVariant;
|
variant?: EntityChipVariant;
|
||||||
|
LeftIcon?: IconComponent;
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum EntityChipVariant {
|
export enum EntityChipVariant {
|
||||||
@ -27,9 +30,12 @@ export const EntityChip = ({
|
|||||||
pictureUrl,
|
pictureUrl,
|
||||||
avatarType = 'rounded',
|
avatarType = 'rounded',
|
||||||
variant = EntityChipVariant.Regular,
|
variant = EntityChipVariant.Regular,
|
||||||
|
LeftIcon,
|
||||||
}: OwnProps) => {
|
}: OwnProps) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
const handleLinkClick = (event: React.MouseEvent<HTMLDivElement>) => {
|
const handleLinkClick = (event: React.MouseEvent<HTMLDivElement>) => {
|
||||||
if (linkToEntity) {
|
if (linkToEntity) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@ -50,13 +56,17 @@ export const EntityChip = ({
|
|||||||
: ChipVariant.Transparent
|
: ChipVariant.Transparent
|
||||||
}
|
}
|
||||||
leftComponent={
|
leftComponent={
|
||||||
<Avatar
|
LeftIcon ? (
|
||||||
avatarUrl={pictureUrl}
|
<LeftIcon size={theme.icon.size.md} stroke={theme.icon.stroke.sm} />
|
||||||
colorId={entityId}
|
) : (
|
||||||
placeholder={name}
|
<Avatar
|
||||||
size="sm"
|
avatarUrl={pictureUrl}
|
||||||
type={avatarType}
|
colorId={entityId}
|
||||||
/>
|
placeholder={name}
|
||||||
|
size="sm"
|
||||||
|
type={avatarType}
|
||||||
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -33,6 +33,11 @@ export type SingleEntitySelectBaseProps<
|
|||||||
selectedEntity?: CustomEntityForSelect;
|
selectedEntity?: CustomEntityForSelect;
|
||||||
onCreate?: () => void;
|
onCreate?: () => void;
|
||||||
showCreateButton?: boolean;
|
showCreateButton?: boolean;
|
||||||
|
SelectAllIcon?: IconComponent;
|
||||||
|
selectAllLabel?: string;
|
||||||
|
isAllEntitySelected?: boolean;
|
||||||
|
isAllEntitySelectShown?: boolean;
|
||||||
|
onAllEntitySelected?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SingleEntitySelectBase = <
|
export const SingleEntitySelectBase = <
|
||||||
@ -47,6 +52,11 @@ export const SingleEntitySelectBase = <
|
|||||||
selectedEntity,
|
selectedEntity,
|
||||||
onCreate,
|
onCreate,
|
||||||
showCreateButton,
|
showCreateButton,
|
||||||
|
SelectAllIcon,
|
||||||
|
selectAllLabel,
|
||||||
|
isAllEntitySelected,
|
||||||
|
isAllEntitySelectShown,
|
||||||
|
onAllEntitySelected,
|
||||||
}: SingleEntitySelectBaseProps<CustomEntityForSelect>) => {
|
}: SingleEntitySelectBaseProps<CustomEntityForSelect>) => {
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@ -94,6 +104,15 @@ export const SingleEntitySelectBase = <
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StyledDropdownMenuItemsContainer ref={containerRef} hasMaxHeight>
|
<StyledDropdownMenuItemsContainer ref={containerRef} hasMaxHeight>
|
||||||
|
{isAllEntitySelectShown && selectAllLabel && onAllEntitySelected && (
|
||||||
|
<MenuItemSelect
|
||||||
|
onClick={() => onAllEntitySelected()}
|
||||||
|
LeftIcon={SelectAllIcon}
|
||||||
|
text={selectAllLabel}
|
||||||
|
hovered={preselectedOptionId === EmptyButtonId}
|
||||||
|
selected={!!isAllEntitySelected}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{emptyLabel && (
|
{emptyLabel && (
|
||||||
<MenuItemSelect
|
<MenuItemSelect
|
||||||
onClick={() => onEntitySelected()}
|
onClick={() => onEntitySelected()}
|
||||||
@ -105,7 +124,7 @@ export const SingleEntitySelectBase = <
|
|||||||
)}
|
)}
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<DropdownMenuSkeletonItem />
|
<DropdownMenuSkeletonItem />
|
||||||
) : entitiesInDropdown.length === 0 ? (
|
) : entitiesInDropdown.length === 0 && !isAllEntitySelectShown ? (
|
||||||
<MenuItem text="No result" />
|
<MenuItem text="No result" />
|
||||||
) : (
|
) : (
|
||||||
entitiesInDropdown?.map((entity) => (
|
entitiesInDropdown?.map((entity) => (
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { EntitiesForMultipleEntitySelect } from '@/ui/input/relation-picker/components/MultipleEntitySelect';
|
import { EntitiesForMultipleEntitySelect } from '@/ui/input/relation-picker/components/MultipleEntitySelect';
|
||||||
import { SingleEntitySelectBase } from '@/ui/input/relation-picker/components/SingleEntitySelectBase';
|
import { SingleEntitySelectBase } from '@/ui/input/relation-picker/components/SingleEntitySelectBase';
|
||||||
@ -12,6 +12,8 @@ import { filterDropdownSelectedEntityIdScopedState } from '@/ui/view-bar/states/
|
|||||||
import { selectedOperandInDropdownScopedState } from '@/ui/view-bar/states/selectedOperandInDropdownScopedState';
|
import { selectedOperandInDropdownScopedState } from '@/ui/view-bar/states/selectedOperandInDropdownScopedState';
|
||||||
|
|
||||||
import { useViewBarContext } from '../hooks/useViewBarContext';
|
import { useViewBarContext } from '../hooks/useViewBarContext';
|
||||||
|
import { filterDropdownSearchInputScopedState } from '../states/filterDropdownSearchInputScopedState';
|
||||||
|
import { FilterOperand } from '../types/FilterOperand';
|
||||||
|
|
||||||
export const FilterDropdownEntitySearchSelect = ({
|
export const FilterDropdownEntitySearchSelect = ({
|
||||||
entitiesForSelect,
|
entitiesForSelect,
|
||||||
@ -20,6 +22,8 @@ export const FilterDropdownEntitySearchSelect = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { ViewBarRecoilScopeContext } = useViewBarContext();
|
const { ViewBarRecoilScopeContext } = useViewBarContext();
|
||||||
|
|
||||||
|
const [isAllEntitySelected, setIsAllEntitySelected] = useState(false);
|
||||||
|
|
||||||
const [filterDropdownSelectedEntityId, setFilterDropdownSelectedEntityId] =
|
const [filterDropdownSelectedEntityId, setFilterDropdownSelectedEntityId] =
|
||||||
useRecoilScopedState(
|
useRecoilScopedState(
|
||||||
filterDropdownSelectedEntityIdScopedState,
|
filterDropdownSelectedEntityIdScopedState,
|
||||||
@ -52,6 +56,10 @@ export const FilterDropdownEntitySearchSelect = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isAllEntitySelected) {
|
||||||
|
setIsAllEntitySelected(false);
|
||||||
|
}
|
||||||
|
|
||||||
const clickedOnAlreadySelectedEntity =
|
const clickedOnAlreadySelectedEntity =
|
||||||
selectedEntity.id === filterDropdownSelectedEntityId;
|
selectedEntity.id === filterDropdownSelectedEntityId;
|
||||||
|
|
||||||
@ -72,11 +80,54 @@ export const FilterDropdownEntitySearchSelect = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const [filterDropdownSearchInput] = useRecoilScopedState(
|
||||||
|
filterDropdownSearchInputScopedState,
|
||||||
|
ViewBarRecoilScopeContext,
|
||||||
|
);
|
||||||
|
|
||||||
|
const isAllEntitySelectShown =
|
||||||
|
!!filterDefinitionUsedInDropdown?.selectAllLabel &&
|
||||||
|
!!filterDefinitionUsedInDropdown?.SelectAllIcon &&
|
||||||
|
(isAllEntitySelected ||
|
||||||
|
filterDefinitionUsedInDropdown?.selectAllLabel
|
||||||
|
.toLocaleLowerCase()
|
||||||
|
.includes(filterDropdownSearchInput.toLocaleLowerCase()));
|
||||||
|
|
||||||
|
const handleAllEntitySelectClick = () => {
|
||||||
|
if (
|
||||||
|
!filterDefinitionUsedInDropdown ||
|
||||||
|
!selectedOperandInDropdown ||
|
||||||
|
!filterDefinitionUsedInDropdown.selectAllLabel
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isAllEntitySelected) {
|
||||||
|
setIsAllEntitySelected(false);
|
||||||
|
|
||||||
|
removeFilter(filterDefinitionUsedInDropdown.key);
|
||||||
|
} else {
|
||||||
|
setIsAllEntitySelected(true);
|
||||||
|
|
||||||
|
setFilterDropdownSelectedEntityId(null);
|
||||||
|
|
||||||
|
upsertFilter({
|
||||||
|
displayValue: filterDefinitionUsedInDropdown.selectAllLabel,
|
||||||
|
key: filterDefinitionUsedInDropdown.key,
|
||||||
|
operand: FilterOperand.IsNotNull,
|
||||||
|
type: filterDefinitionUsedInDropdown.type,
|
||||||
|
value: '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!filterCurrentlyEdited) {
|
if (!filterCurrentlyEdited) {
|
||||||
setFilterDropdownSelectedEntityId(null);
|
setFilterDropdownSelectedEntityId(null);
|
||||||
} else {
|
} else {
|
||||||
setFilterDropdownSelectedEntityId(filterCurrentlyEdited.value);
|
setFilterDropdownSelectedEntityId(filterCurrentlyEdited.value);
|
||||||
|
setIsAllEntitySelected(
|
||||||
|
filterCurrentlyEdited.operand === FilterOperand.IsNotNull,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
filterCurrentlyEdited,
|
filterCurrentlyEdited,
|
||||||
@ -91,6 +142,11 @@ export const FilterDropdownEntitySearchSelect = ({
|
|||||||
selectedEntity={entitiesForSelect.selectedEntities[0]}
|
selectedEntity={entitiesForSelect.selectedEntities[0]}
|
||||||
loading={entitiesForSelect.loading}
|
loading={entitiesForSelect.loading}
|
||||||
onEntitySelected={handleUserSelected}
|
onEntitySelected={handleUserSelected}
|
||||||
|
SelectAllIcon={filterDefinitionUsedInDropdown?.SelectAllIcon}
|
||||||
|
selectAllLabel={filterDefinitionUsedInDropdown?.selectAllLabel}
|
||||||
|
isAllEntitySelected={isAllEntitySelected}
|
||||||
|
isAllEntitySelectShown={isAllEntitySelectShown}
|
||||||
|
onAllEntitySelected={handleAllEntitySelectClick}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,16 +1,19 @@
|
|||||||
import { EntityChip } from '@/ui/chip/components/EntityChip';
|
import { EntityChip } from '@/ui/chip/components/EntityChip';
|
||||||
|
import { IconComponent } from '@/ui/icon/types/IconComponent';
|
||||||
|
|
||||||
import { Filter } from '../types/Filter';
|
import { Filter } from '../types/Filter';
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
filter: Filter;
|
filter: Filter;
|
||||||
|
Icon?: IconComponent;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const GenericEntityFilterChip = ({ filter }: OwnProps) => (
|
export const GenericEntityFilterChip = ({ filter, Icon }: OwnProps) => (
|
||||||
<EntityChip
|
<EntityChip
|
||||||
entityId={filter.value}
|
entityId={filter.value}
|
||||||
name={filter.displayValue}
|
name={filter.displayValue}
|
||||||
avatarType="rounded"
|
avatarType="rounded"
|
||||||
pictureUrl={filter.displayAvatarUrl}
|
pictureUrl={filter.displayAvatarUrl}
|
||||||
|
LeftIcon={Icon}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import { useViewBarContext } from '../hooks/useViewBarContext';
|
|||||||
import { availableFiltersScopedState } from '../states/availableFiltersScopedState';
|
import { availableFiltersScopedState } from '../states/availableFiltersScopedState';
|
||||||
import { filtersScopedState } from '../states/filtersScopedState';
|
import { filtersScopedState } from '../states/filtersScopedState';
|
||||||
import { isFilterDropdownUnfoldedScopedState } from '../states/isFilterDropdownUnfoldedScopedState';
|
import { isFilterDropdownUnfoldedScopedState } from '../states/isFilterDropdownUnfoldedScopedState';
|
||||||
|
import { FilterOperand } from '../types/FilterOperand';
|
||||||
import { getOperandsForFilterType } from '../utils/getOperandsForFilterType';
|
import { getOperandsForFilterType } from '../utils/getOperandsForFilterType';
|
||||||
|
|
||||||
import { FilterDropdownEntitySearchInput } from './FilterDropdownEntitySearchInput';
|
import { FilterDropdownEntitySearchInput } from './FilterDropdownEntitySearchInput';
|
||||||
@ -100,7 +101,14 @@ export const SingleEntityFilterDropdownButton = ({
|
|||||||
onClick={() => handleIsUnfoldedChange(!isFilterDropdownUnfolded)}
|
onClick={() => handleIsUnfoldedChange(!isFilterDropdownUnfolded)}
|
||||||
>
|
>
|
||||||
{filters[0] ? (
|
{filters[0] ? (
|
||||||
<GenericEntityFilterChip filter={filters[0]} />
|
<GenericEntityFilterChip
|
||||||
|
filter={filters[0]}
|
||||||
|
Icon={
|
||||||
|
filters[0].operand === FilterOperand.IsNotNull
|
||||||
|
? availableFilter.SelectAllIcon
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
'Filter'
|
'Filter'
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -8,4 +8,6 @@ export type FilterDefinition = {
|
|||||||
Icon: IconComponent;
|
Icon: IconComponent;
|
||||||
type: FilterType;
|
type: FilterType;
|
||||||
entitySelectComponent?: JSX.Element;
|
entitySelectComponent?: JSX.Element;
|
||||||
|
selectAllLabel?: string;
|
||||||
|
SelectAllIcon?: IconComponent;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -14,6 +14,8 @@ export const getOperandLabel = (operand: FilterOperand | null | undefined) => {
|
|||||||
return 'Is';
|
return 'Is';
|
||||||
case FilterOperand.IsNot:
|
case FilterOperand.IsNot:
|
||||||
return 'Is not';
|
return 'Is not';
|
||||||
|
case FilterOperand.IsNotNull:
|
||||||
|
return 'Is not null';
|
||||||
default:
|
default:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@ -29,6 +31,8 @@ export const getOperandLabelShort = (
|
|||||||
case FilterOperand.IsNot:
|
case FilterOperand.IsNot:
|
||||||
case FilterOperand.DoesNotContain:
|
case FilterOperand.DoesNotContain:
|
||||||
return ': Not';
|
return ': Not';
|
||||||
|
case FilterOperand.IsNotNull:
|
||||||
|
return ': NotNull';
|
||||||
case FilterOperand.GreaterThan:
|
case FilterOperand.GreaterThan:
|
||||||
return '\u00A0> ';
|
return '\u00A0> ';
|
||||||
case FilterOperand.LessThan:
|
case FilterOperand.LessThan:
|
||||||
|
|||||||
@ -4,88 +4,97 @@ import { Filter } from '../types/Filter';
|
|||||||
import { FilterOperand } from '../types/FilterOperand';
|
import { FilterOperand } from '../types/FilterOperand';
|
||||||
|
|
||||||
export const turnFilterIntoWhereClause = (filter: Filter) => {
|
export const turnFilterIntoWhereClause = (filter: Filter) => {
|
||||||
switch (filter.type) {
|
switch (filter.operand) {
|
||||||
case 'text':
|
case FilterOperand.IsNotNull:
|
||||||
switch (filter.operand) {
|
return {
|
||||||
case FilterOperand.Contains:
|
[filter.key]: {
|
||||||
return {
|
not: null,
|
||||||
[filter.key]: {
|
},
|
||||||
contains: filter.value,
|
};
|
||||||
mode: QueryMode.Insensitive,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
case FilterOperand.DoesNotContain:
|
|
||||||
return {
|
|
||||||
[filter.key]: {
|
|
||||||
not: {
|
|
||||||
contains: filter.value,
|
|
||||||
mode: QueryMode.Insensitive,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
default:
|
|
||||||
throw new Error(
|
|
||||||
`Unknown operand ${filter.operand} for ${filter.type} filter`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
case 'number':
|
|
||||||
switch (filter.operand) {
|
|
||||||
case FilterOperand.GreaterThan:
|
|
||||||
return {
|
|
||||||
[filter.key]: {
|
|
||||||
gte: parseFloat(filter.value),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
case FilterOperand.LessThan:
|
|
||||||
return {
|
|
||||||
[filter.key]: {
|
|
||||||
lte: parseFloat(filter.value),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
default:
|
|
||||||
throw new Error(
|
|
||||||
`Unknown operand ${filter.operand} for ${filter.type} filter`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
case 'date':
|
|
||||||
switch (filter.operand) {
|
|
||||||
case FilterOperand.GreaterThan:
|
|
||||||
return {
|
|
||||||
[filter.key]: {
|
|
||||||
gte: filter.value,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
case FilterOperand.LessThan:
|
|
||||||
return {
|
|
||||||
[filter.key]: {
|
|
||||||
lte: filter.value,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
default:
|
|
||||||
throw new Error(
|
|
||||||
`Unknown operand ${filter.operand} for ${filter.type} filter`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
case 'entity':
|
|
||||||
switch (filter.operand) {
|
|
||||||
case FilterOperand.Is:
|
|
||||||
return {
|
|
||||||
[filter.key]: {
|
|
||||||
equals: filter.value,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
case FilterOperand.IsNot:
|
|
||||||
return {
|
|
||||||
[filter.key]: {
|
|
||||||
not: { equals: filter.value },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
default:
|
|
||||||
throw new Error(
|
|
||||||
`Unknown operand ${filter.operand} for ${filter.type} filter`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
throw new Error('Unknown filter type');
|
switch (filter.type) {
|
||||||
|
case 'text':
|
||||||
|
switch (filter.operand) {
|
||||||
|
case FilterOperand.Contains:
|
||||||
|
return {
|
||||||
|
[filter.key]: {
|
||||||
|
contains: filter.value,
|
||||||
|
mode: QueryMode.Insensitive,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
case FilterOperand.DoesNotContain:
|
||||||
|
return {
|
||||||
|
[filter.key]: {
|
||||||
|
not: {
|
||||||
|
contains: filter.value,
|
||||||
|
mode: QueryMode.Insensitive,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
`Unknown operand ${filter.operand} for ${filter.type} filter`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case 'number':
|
||||||
|
switch (filter.operand) {
|
||||||
|
case FilterOperand.GreaterThan:
|
||||||
|
return {
|
||||||
|
[filter.key]: {
|
||||||
|
gte: parseFloat(filter.value),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
case FilterOperand.LessThan:
|
||||||
|
return {
|
||||||
|
[filter.key]: {
|
||||||
|
lte: parseFloat(filter.value),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
`Unknown operand ${filter.operand} for ${filter.type} filter`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case 'date':
|
||||||
|
switch (filter.operand) {
|
||||||
|
case FilterOperand.GreaterThan:
|
||||||
|
return {
|
||||||
|
[filter.key]: {
|
||||||
|
gte: filter.value,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
case FilterOperand.LessThan:
|
||||||
|
return {
|
||||||
|
[filter.key]: {
|
||||||
|
lte: filter.value,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
`Unknown operand ${filter.operand} for ${filter.type} filter`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case 'entity':
|
||||||
|
switch (filter.operand) {
|
||||||
|
case FilterOperand.Is:
|
||||||
|
return {
|
||||||
|
[filter.key]: {
|
||||||
|
equals: filter.value,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
case FilterOperand.IsNot:
|
||||||
|
return {
|
||||||
|
[filter.key]: {
|
||||||
|
not: { equals: filter.value },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
`Unknown operand ${filter.operand} for ${filter.type} filter`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new Error('Unknown filter type');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { TasksRecoilScopeContext } from '@/activities/states/recoil-scope-contexts/TasksRecoilScopeContext';
|
import { TasksRecoilScopeContext } from '@/activities/states/recoil-scope-contexts/TasksRecoilScopeContext';
|
||||||
import { IconUser } from '@/ui/icon';
|
import { IconUser, IconUserCircle } from '@/ui/icon';
|
||||||
import { FilterDefinitionByEntity } from '@/ui/view-bar/types/FilterDefinitionByEntity';
|
import { FilterDefinitionByEntity } from '@/ui/view-bar/types/FilterDefinitionByEntity';
|
||||||
import { FilterDropdownUserSearchSelect } from '@/users/components/FilterDropdownUserSearchSelect';
|
import { FilterDropdownUserSearchSelect } from '@/users/components/FilterDropdownUserSearchSelect';
|
||||||
import { Activity } from '~/generated/graphql';
|
import { Activity } from '~/generated/graphql';
|
||||||
@ -13,5 +13,7 @@ export const tasksFilters: FilterDefinitionByEntity<Activity>[] = [
|
|||||||
entitySelectComponent: (
|
entitySelectComponent: (
|
||||||
<FilterDropdownUserSearchSelect context={TasksRecoilScopeContext} />
|
<FilterDropdownUserSearchSelect context={TasksRecoilScopeContext} />
|
||||||
),
|
),
|
||||||
|
selectAllLabel: 'All assignees',
|
||||||
|
SelectAllIcon: IconUserCircle,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@ -823,6 +823,7 @@ enum ViewFilterOperand {
|
|||||||
LessThan
|
LessThan
|
||||||
Is
|
Is
|
||||||
IsNot
|
IsNot
|
||||||
|
IsNotNull
|
||||||
}
|
}
|
||||||
|
|
||||||
model ViewFilter {
|
model ViewFilter {
|
||||||
|
|||||||
Reference in New Issue
Block a user