Skip to content

Commit

Permalink
Filter bar (#840)
Browse files Browse the repository at this point in the history
* allow suggestionprovider to be injected to FilterClauseEditor

* fix type issues
  • Loading branch information
heswell authored Aug 8, 2023
1 parent 098b186 commit 7c8d658
Show file tree
Hide file tree
Showing 24 changed files with 182 additions and 118 deletions.
8 changes: 8 additions & 0 deletions vuu-ui/packages/vuu-filter-types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
export declare type NumericFilterClauseOp =
| "="
| "!="
| ">"
| ">="
| "<="
| "<";

export declare type SingleValueFilterClauseOp =
| "="
| "!="
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { getColumnByName, TableSchema } from "@finos/vuu-data";
import { ColumnDescriptor } from "@finos/vuu-datagrid-types";
import { FilterClause } from "@finos/vuu-filter-types";
import { FilterClause, FilterClauseOp } from "@finos/vuu-filter-types";
import {
isMultiValueFilter,
isSingleValueFilter,
isValidFilterClauseOp,
} from "@finos/vuu-utils";
import cx from "classnames";
import {
HTMLAttributes,
Expand All @@ -17,21 +22,45 @@ import { textOperators } from "./operator-utils";
import { TextInput } from "./TextInput";

import "./FilterClauseEditor.css";
import { SuggestionFetcher } from "packages/vuu-data-react/src";

export interface FilterClauseEditorProps
extends Omit<HTMLAttributes<HTMLDivElement>, "onChange"> {
filterClause: Partial<FilterClause>;
onChange: (filterClause: Partial<FilterClause>) => void;
onClose: () => void;
suggestionProvider?: () => SuggestionFetcher;
tableSchema: TableSchema;
}

const classBase = "vuuFilterClause";

// TODO boolean[] makes no sense
type FilterClauseValue =
| boolean
| boolean[]
| string
| string[]
| number
| number[];

const getFilterClauseValue = (
filterClause: Partial<FilterClause>
): FilterClauseValue | undefined => {
if (isMultiValueFilter(filterClause)) {
return filterClause.values;
} else if (isSingleValueFilter(filterClause)) {
return filterClause.value;
} else {
return undefined;
}
};

export const FilterClauseEditor = ({
onChange,
onClose,
filterClause,
suggestionProvider,
tableSchema,
...htmlAttributes
}: FilterClauseEditorProps) => {
Expand All @@ -42,8 +71,12 @@ export const FilterClauseEditor = ({
const [selectedColumn, setSelectedColumn] = useState<
ColumnDescriptor | undefined
>(getColumnByName(tableSchema, filterClause.column));
const [operator, setOperator] = useState<string | undefined>(filterClause.op);
const [value, setValue] = useState<unknown | undefined>(filterClause.value);
const [operator, setOperator] = useState<FilterClauseOp | undefined>(
filterClause.op
);
const [value, setValue] = useState<FilterClauseValue | undefined>(
getFilterClauseValue(filterClause)
);

const handleColumnSelectionChange = useCallback(
(evt: SyntheticEvent, column: ColumnDescriptor | null) => {
Expand All @@ -53,13 +86,20 @@ export const FilterClauseEditor = ({
);
const handleOperatorSelectionChange = useCallback(
(evt: SyntheticEvent, operator: string | null) => {
setOperator(operator ?? undefined);
const op = operator ?? undefined;
if (op === undefined || isValidFilterClauseOp(op)) {
setOperator(op);
} else {
throw Error(
`FilterClauseEditor, invalid value ${op} for filter clause`
);
}
},
[]
);

const handleValueChange = useCallback(
(value: string) => {
(value: string | number) => {
console.log(`handleValueChange ${value}`);
setValue(value);
onChange({
Expand Down Expand Up @@ -105,6 +145,7 @@ export const FilterClauseEditor = ({
onValueChange={handleValueChange}
operator={operator}
ref={valueRef}
suggestionProvider={suggestionProvider}
table={table}
value={value as string}
/>
Expand All @@ -118,6 +159,7 @@ export const FilterClauseEditor = ({
className={classBase}
column={selectedColumn}
filterClause={filterClause}
onValueChange={handleValueChange}
operator={operator}
ref={valueRef}
/>
Expand All @@ -129,7 +171,15 @@ export const FilterClauseEditor = ({
console.log("returning unsupported");
return null;
}
}, [selectedColumn, operator, filterClause, handleValueChange, table, value]);
}, [
selectedColumn,
operator,
filterClause,
handleValueChange,
suggestionProvider,
table,
value,
]);

return (
<div className={classBase} {...htmlAttributes} tabIndex={0}>
Expand Down
29 changes: 8 additions & 21 deletions vuu-ui/packages/vuu-filters/src/filter-clause/NumericInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,30 @@ import {
useRef,
useState,
} from "react";
import { Filter } from "@finos/vuu-filter-types";
import { Input } from "@salt-ds/core";
import { getNumericFilter } from "../filter-utils";
import { isValidNumber } from "@finos/vuu-utils";
import { FilterClauseValueEditor } from "./filterClauseTypes";

export interface NumericInputProps
extends FilterClauseValueEditor,
HTMLAttributes<HTMLDivElement> {
operatorInputRef?: RefObject<HTMLInputElement>;
onFilterChange?: (filter?: Filter) => void;
onValueChange: (value: number) => void;
operator: string;
ref: RefObject<HTMLDivElement>;
value?: number;
}

export const NumericInput = ({
className,
column,
filterClause,
onFilterChange,
operator,
// filterClause,
onValueChange,
// operator,
value,
}: NumericInputProps) => {
const defaultValue =
filterClause?.op !== "in" && isValidNumber(filterClause?.value)
? filterClause?.value
: undefined;
// const defaultOp = isNumericOperator(defaultFilter?.op)
// ? defaultFilter?.op
// : undefined;

const [valueInputValue, setValueInputValue] = useState<string>(
defaultValue?.toString() || ""
isValidNumber(value) ? value.toString() : ""
);
const valueInputRef = useRef<HTMLInputElement>(null);

Expand All @@ -54,12 +46,7 @@ export const NumericInput = ({
// type="text"
onChange={(event: ChangeEvent<HTMLInputElement>) => {
setValueInputValue(event.target.value);
const filter = getNumericFilter(
column,
operator,
Number.parseFloat(event.target.value)
);
onFilterChange(filter);
onValueChange(Number.parseFloat(event.target.value));
}}
/>
);
Expand Down
9 changes: 7 additions & 2 deletions vuu-ui/packages/vuu-filters/src/filter-clause/TextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ import { TypeaheadParams } from "@finos/vuu-protocol-types";
import { ComboBoxDeprecated } from "@salt-ds/lab";
import { ListChangeHandler } from "@salt-ds/lab/dist-types/list-deprecated";
import { getTypeaheadFilter } from "../column-filter/utils";
import { useTypeaheadSuggestions } from "@finos/vuu-data-react";
import {
SuggestionFetcher,
useTypeaheadSuggestions,
} from "@finos/vuu-data-react";
import { ExpandoCombobox } from "./ExpandoCombobox";
import { FilterClauseValueEditor } from "./filterClauseTypes";

Expand All @@ -24,6 +27,7 @@ export interface TextInputProps
ref: RefObject<HTMLDivElement>;
operator: string;
onValueChange: (value: string) => void;
suggestionProvider?: () => SuggestionFetcher;
value: string;
}

Expand All @@ -34,6 +38,7 @@ export const TextInput = forwardRef(function TextInput(
filterClause,
onValueChange,
operator,
suggestionProvider = useTypeaheadSuggestions,
table,
value,
}: TextInputProps,
Expand All @@ -45,7 +50,7 @@ export const TextInput = forwardRef(function TextInput(
// const [typeaheadValues, setTypeaheadValues] =
// useState<string[]>([defaultValues]);
const [typeaheadValues, setTypeaheadValues] = useState<string[]>([]);
const getSuggestions = useTypeaheadSuggestions();
const getSuggestions = suggestionProvider();
const valueInputRef = useRef<HTMLInputElement>(null);

const handleValueSelectionChange = useCallback(
Expand Down
12 changes: 10 additions & 2 deletions vuu-ui/packages/vuu-filters/src/filter-pill/FilterPill.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import { NamedFilter } from "packages/vuu-filter-types";
import { HTMLAttributes } from "react";
import { HTMLAttributes, useCallback } from "react";
import cx from "classnames";
import { EditableLabel, EditableLabelProps } from "@finos/vuu-ui-controls";
import { FilterPillMenu } from "../filter-pill-menu";

import "./FilterPill.css";
import { MenuActionHandler } from "packages/vuu-data-types";

const classBase = "vuuFilterPill";

export interface FilterPillProps extends HTMLAttributes<HTMLDivElement> {
filter: NamedFilter;
index?: number;
}

export const FilterPill = ({
filter,
className: classNameProp,
index = 0,
...htmlAttributes
}: FilterPillProps) => {
// const handleExitEditMode: EditableLabelProps["onExitEditMode"] = (
Expand All @@ -39,14 +42,19 @@ export const FilterPill = ({
});
};

const handleMenuAction = useCallback<MenuActionHandler>((action) => {
console.log(`handle action ${action.menuId}`);
return true;
}, []);

return (
<div {...htmlAttributes} className={cx(classBase, classNameProp)}>
<EditableLabel
defaultValue={filter.name}
onEnterEditMode={handleEnterEditMode}
onExitEditMode={handleExitEditMode}
/>
<FilterPillMenu />
<FilterPillMenu index={index} onMenuAction={handleMenuAction} />
</div>
);
};
10 changes: 5 additions & 5 deletions vuu-ui/packages/vuu-filters/src/filter-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
Filter,
FilterClause,
FilterCombinatorOp,
NumericFilterClauseOp,
} from "@finos/vuu-filter-types";
import {
extractFilterForColumn,
Expand All @@ -15,7 +16,6 @@ import {
isSingleValueFilter,
partition,
} from "@finos/vuu-utils";
import { NumericOperator } from "./filter-clause/operator-utils";

export const AND = "and";
export const EQUALS = "=";
Expand Down Expand Up @@ -399,10 +399,10 @@ export const getTypeaheadFilter = (

export const getNumericFilter = (
column: string,
operator?: NumericOperator,
op?: NumericFilterClauseOp,
value?: number
): Filter | undefined => {
if (operator === undefined) return undefined;
): FilterClause | undefined => {
if (op === undefined) return undefined;
if (value === undefined || isNaN(value)) return undefined;
return { column, op: operator, value };
return { column, op, value };
};
2 changes: 1 addition & 1 deletion vuu-ui/packages/vuu-popups/src/menu/useContextMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ const NO_OPTIONS = {};

const showContextMenuComponent = (
e: MouseEvent<HTMLElement>,
contextMenu: JSX.Elementfinos
contextMenu: JSX.Element
) => {
const position = {
x: e.clientX,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ export const ColumnSettingsPanel = ({
<Text as="h4">Column Settings</Text>
<Stack
active={activeTab}
showTabs
className={cx(`${classBase}-columnTabs`)}
onTabSelectionChanged={setActiveTab}
TabstripProps={tabstripProps}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ export const DatagridSettingsPanel = ({
getTabLabel={getTabLabel}
active={selectedTabIndex === 2 ? 1 : selectedTabIndex}
onTabSelectionChanged={handleTabSelectionChanged}
showTabs
>
<GridSettingsPanel
config={gridSettings}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ export const ColumnSettingsPanel = ({
<Text as="h4">Column Settings</Text>
<Stack
active={activeTab}
showTabs
className={cx(`${classBase}-columnTabs`)}
onTabSelectionChanged={setActiveTab}
TabstripProps={tabstripProps}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ export const DatagridSettingsPanel = ({
getTabLabel={getTabLabel}
active={selectedTabIndex === 2 ? 1 : selectedTabIndex}
onTabSelectionChanged={handleTabSelectionChanged}
showTabs
>
<GridSettingsPanel
config={gridSettings}
Expand Down
Loading

0 comments on commit 7c8d658

Please sign in to comment.