Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filter bar #840

Merged
merged 2 commits into from
Aug 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading