Skip to content

[WC-2870] filtering dropdown #1530

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

Open
wants to merge 37 commits into
base: data-widgets-v3.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
fe6f367
chore: add attributes to settings
iobuhov Feb 26, 2025
1916412
chore: change interface
iobuhov Feb 27, 2025
6e8771b
chore: rename controller
iobuhov Feb 28, 2025
a7230f5
refactor: rename interface
iobuhov Feb 28, 2025
1eaafd8
feat: add filter observer
iobuhov Feb 28, 2025
81740dd
refactor: rename type
iobuhov Feb 28, 2025
c4db83b
refactor: remove dead code
iobuhov Feb 28, 2025
7b786c3
feat: add filter observer to filter api
iobuhov Feb 28, 2025
7e1a0d1
chore: change personalization
iobuhov Mar 3, 2025
bbad47d
chore: change attr type
iobuhov Mar 3, 2025
c1230a8
feat: add custom text filter
iobuhov Mar 3, 2025
8872af4
chore: merge filters
iobuhov Mar 4, 2025
19ef689
feat: add state persistence
iobuhov Mar 4, 2025
a6d0f54
chore: change tag exp to not equal
iobuhov Mar 4, 2025
bf7ec60
chore: add condition tagging
iobuhov Mar 4, 2025
7e83125
chore: add filter initialization
iobuhov Mar 4, 2025
199ff8f
chore: remove placeholder tag
iobuhov Mar 4, 2025
2d5d0c4
test: fix unit tests
iobuhov Mar 4, 2025
dfa05af
test: fix unit tests
iobuhov Mar 4, 2025
3232bb6
chore: change label
iobuhov Mar 5, 2025
0b84c66
chore: fix types
iobuhov Mar 5, 2025
a6d38fa
fix: update types
iobuhov Mar 7, 2025
fbe641c
fix: update types
iobuhov Mar 7, 2025
7328928
fix: update types
iobuhov Mar 7, 2025
0efbfe8
fix: change types
iobuhov Mar 7, 2025
9322489
test: update settings schema
iobuhov Mar 7, 2025
db883cb
chore: update lockfile
iobuhov Apr 4, 2025
09f54f1
feat: add custom text filter
iobuhov Mar 3, 2025
eab0053
feat(datagrid-date-filter-web): add linked ds
iobuhov Apr 4, 2025
c9bd1d5
feat: add date store provider
iobuhov Apr 4, 2025
6fe71a6
feat: add store injector to date filter
iobuhov Apr 4, 2025
e84bc86
chore: show linked ds in settings
iobuhov Apr 9, 2025
4550744
feat: number filter grid wide filtering
gjulivan Mar 27, 2025
930c3d8
chore: update xml
iobuhov Apr 9, 2025
68e9b81
chore(datagrid-number-filter-web): update editor config
iobuhov Apr 9, 2025
5b7684b
chore: update formatter logic
iobuhov Apr 9, 2025
4793404
feat: add new set of properties
iobuhov Apr 11, 2025
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
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { hidePropertiesIn, hidePropertyIn, Properties } from "@mendix/pluggable-widgets-tools";
import {
betweenIcon,
betweenIconDark,
Expand All @@ -23,22 +24,23 @@ import {
import {
ContainerProps,
ImageProps,
structurePreviewPalette,
StructurePreviewProps,
text,
structurePreviewPalette
text
} from "@mendix/widget-plugin-platform/preview/structure-preview-api";
import { hidePropertiesIn, hidePropertyIn, Properties } from "@mendix/pluggable-widgets-tools";

import { DatagridDateFilterPreviewProps, DefaultFilterEnum } from "../typings/DatagridDateFilterProps";

export function getProperties(
values: DatagridDateFilterPreviewProps,
defaultProperties: Properties,
platform: "web" | "desktop"
): Properties {
export function getProperties(values: DatagridDateFilterPreviewProps, defaultProperties: Properties): Properties {
if (!values.adjustable) {
hidePropertyIn(defaultProperties, values, "screenReaderButtonCaption");
}

if (values.attrChoice === "auto") {
hidePropertyIn(defaultProperties, values, "attributes");
hidePropertyIn(defaultProperties, {} as { linkedDs: unknown }, "linkedDs");
}

if (values.defaultFilter !== "between") {
hidePropertiesIn(defaultProperties, values, [
"defaultStartDate",
Expand All @@ -49,13 +51,7 @@ export function getProperties(
} else {
hidePropertiesIn(defaultProperties, values, ["defaultValue", "valueAttribute"]);
}
if (platform === "web") {
if (!values.advanced) {
hidePropertiesIn(defaultProperties, values, ["onChange", "valueAttribute"]);
}
} else {
hidePropertyIn(defaultProperties, values, "advanced");
}

return defaultProperties;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,18 @@ import { DatagridDateFilterContainerProps } from "../typings/DatagridDateFilterP
import { Container } from "./components/DateFilterContainer";
import { withDateFilterAPI } from "./hocs/withDateFilterAPI";
import { isLoadingDefaultValues } from "./utils/widget-utils";
import { withDateLinkedAttributes } from "./hocs/withDateLinkedAttributes";

const container = withPreloader(Container, isLoadingDefaultValues);
const Widget = withDateFilterAPI(container);
const FilterAuto = withDateFilterAPI(container);
const FilterLinked = withDateLinkedAttributes(container);

export default function DatagridDateFilter(props: DatagridDateFilterContainerProps): ReactElement | null {
return <Widget {...props} />;
const isAuto = props.attrChoice === "auto";

if (isAuto) {
return <FilterAuto {...props} />;
}

return <FilterLinked {...props} />;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,32 @@
<properties>
<propertyGroup caption="General">
<propertyGroup caption="General">
<property key="advanced" type="boolean" defaultValue="false">
<caption>Enable advanced options</caption>
<property key="attrChoice" type="enumeration" defaultValue="auto">
<caption>Filter attributes</caption>
<description />
<enumerationValues>
<enumerationValue key="auto">Auto</enumerationValue>
<enumerationValue key="linked">Custom</enumerationValue>
</enumerationValues>
</property>
<property key="linkedDs" type="datasource" isLinked="true" isList="true">
<caption>Datasource to Filter</caption>
<description />
</property>
<property key="attributes" type="object" isList="true" required="false">
<caption>Attributes</caption>
<description>Select the attributes that the end-user may use for filtering.</description>
<properties>
<propertyGroup caption="General">
<property key="attribute" type="attribute" dataSource="../linkedDs" isMetaData="true" required="true">
<caption>Attribute</caption>
<description />
<attributeTypes>
<attributeType name="DateTime" />
</attributeTypes>
</property>
</propertyGroup>
</properties>
</property>
<property key="defaultValue" type="expression" required="false">
<caption>Default value</caption>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import "@testing-library/jest-dom";
import { FilterAPIv2 } from "@mendix/widget-plugin-filtering/context";
import { FilterAPI } from "@mendix/widget-plugin-filtering/context";
import {
HeaderFiltersStore,
HeaderFiltersStoreProps
HeaderFiltersStoreSpec
} from "@mendix/widget-plugin-filtering/stores/generic/HeaderFiltersStore";
import {
actionValue,
Expand All @@ -15,11 +15,7 @@ import { createContext, createElement } from "react";
import DatagridDateFilter from "../../DatagridDateFilter";
import { DatagridDateFilterContainerProps } from "../../../typings/DatagridDateFilterProps";
import { MXGlobalObject, MXSessionConfig } from "../../../typings/global";

interface StaticInfo {
name: string;
filtersChannelName: string;
}
import { FilterObserver } from "@mendix/widget-plugin-filtering/typings/FilterObserver";

function createMXObjectMock(
code: string,
Expand Down Expand Up @@ -54,13 +50,17 @@ const commonProps: DatagridDateFilterContainerProps = {
advanced: false
};

const headerFilterStoreInfo: StaticInfo = {
name: commonProps.name,
filtersChannelName: ""
};

const mxObject = createMXObjectMock("en_US", "en-US");

const mockSpec = (spec: Partial<HeaderFiltersStoreSpec>): HeaderFiltersStoreSpec => ({
filterList: [],
filterChannelName: "datagrid/1",
headerInitFilter: [],
sharedInitFilter: [],
customFilterHost: {} as FilterObserver,
...spec
});

describe("Date Filter", () => {
describe("with single instance", () => {
afterEach(() => {
Expand All @@ -69,13 +69,13 @@ describe("Date Filter", () => {

describe("with single attribute", () => {
beforeEach(() => {
const props: HeaderFiltersStoreProps = {
const spec = mockSpec({
filterList: [
{ filter: new ListAttributeValueBuilder().withType("DateTime").withFilterable(true).build() }
]
};
const headerFilterStore = new HeaderFiltersStore(props, headerFilterStoreInfo, null);
(window as any)["com.mendix.widgets.web.filterable.filterContext.v2"] = createContext<FilterAPIv2>(
});
const headerFilterStore = new HeaderFiltersStore(spec);
(window as any)["com.mendix.widgets.web.filterable.filterContext.v2"] = createContext<FilterAPI>(
headerFilterStore.context
);
(window as any).mx = mxObject;
Expand Down Expand Up @@ -144,7 +144,7 @@ describe("Date Filter", () => {

describe("with double attributes", () => {
beforeAll(() => {
const props: HeaderFiltersStoreProps = {
const spec = mockSpec({
filterList: [
{
filter: new ListAttributeValueBuilder()
Expand All @@ -161,9 +161,9 @@ describe("Date Filter", () => {
.build()
}
]
};
const headerFilterStore = new HeaderFiltersStore(props, headerFilterStoreInfo, null);
(window as any)["com.mendix.widgets.web.filterable.filterContext.v2"] = createContext<FilterAPIv2>(
});
const headerFilterStore = new HeaderFiltersStore(spec);
(window as any)["com.mendix.widgets.web.filterable.filterContext.v2"] = createContext<FilterAPI>(
headerFilterStore.context
);
(window as any).mx = mxObject;
Expand All @@ -184,13 +184,13 @@ describe("Date Filter", () => {

describe("with wrong attribute's type", () => {
beforeAll(() => {
const props: HeaderFiltersStoreProps = {
const spec = mockSpec({
filterList: [
{ filter: new ListAttributeValueBuilder().withType("Decimal").withFilterable(true).build() }
]
};
const headerFilterStore = new HeaderFiltersStore(props, headerFilterStoreInfo, null);
(window as any)["com.mendix.widgets.web.filterable.filterContext.v2"] = createContext<FilterAPIv2>(
});
const headerFilterStore = new HeaderFiltersStore(spec);
(window as any)["com.mendix.widgets.web.filterable.filterContext.v2"] = createContext<FilterAPI>(
headerFilterStore.context
);
(window as any).mx = mxObject;
Expand All @@ -211,7 +211,7 @@ describe("Date Filter", () => {

describe("with wrong multiple attributes' types", () => {
beforeAll(() => {
const props: HeaderFiltersStoreProps = {
const spec = mockSpec({
filterList: [
{
filter: new ListAttributeValueBuilder()
Expand All @@ -228,9 +228,9 @@ describe("Date Filter", () => {
.build()
}
]
};
const headerFilterStore = new HeaderFiltersStore(props, headerFilterStoreInfo, null);
(window as any)["com.mendix.widgets.web.filterable.filterContext.v2"] = createContext<FilterAPIv2>(
});
const headerFilterStore = new HeaderFiltersStore(spec);
(window as any)["com.mendix.widgets.web.filterable.filterContext.v2"] = createContext<FilterAPI>(
headerFilterStore.context
);
(window as any).mx = mxObject;
Expand Down Expand Up @@ -267,13 +267,13 @@ describe("Date Filter", () => {

describe("with multiple instances", () => {
beforeAll(() => {
const props: HeaderFiltersStoreProps = {
const spec = mockSpec({
filterList: [
{ filter: new ListAttributeValueBuilder().withType("DateTime").withFilterable(true).build() }
]
};
const headerFilterStore = new HeaderFiltersStore(props, headerFilterStoreInfo, null);
(window as any)["com.mendix.widgets.web.filterable.filterContext.v2"] = createContext<FilterAPIv2>(
});
const headerFilterStore = new HeaderFiltersStore(spec);
(window as any)["com.mendix.widgets.web.filterable.filterContext.v2"] = createContext<FilterAPI>(
headerFilterStore.context
);
(window as any).mx = mxObject;
Expand All @@ -296,13 +296,13 @@ describe("Date Filter", () => {

describe("with session config", () => {
beforeEach(() => {
const props: HeaderFiltersStoreProps = {
const spec = mockSpec({
filterList: [
{ filter: new ListAttributeValueBuilder().withType("DateTime").withFilterable(true).build() }
]
};
const headerFilterStore = new HeaderFiltersStore(props, headerFilterStoreInfo, null);
(window as any)["com.mendix.widgets.web.filterable.filterContext.v2"] = createContext<FilterAPIv2>(
});
const headerFilterStore = new HeaderFiltersStore(spec);
(window as any)["com.mendix.widgets.web.filterable.filterContext.v2"] = createContext<FilterAPI>(
headerFilterStore.context
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export function withDateFilterAPI<P extends object>(
Component: (props: P & Date_FilterAPIv2) => React.ReactElement
): (props: P) => React.ReactElement {
return function FilterAPIProvider(props) {
const api = useDateFilterAPI("");
const api = useDateFilterAPI();

if (api.hasError) {
return <Alert bootstrapStyle="danger">{api.error.message}</Alert>;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { createElement } from "react";
import { AttributeMetaData } from "mendix";
import { useFilterAPI } from "@mendix/widget-plugin-filtering/context";
import { APIError } from "@mendix/widget-plugin-filtering/errors";
import { error, value, Result } from "@mendix/widget-plugin-filtering/result-meta";
import { Date_InputFilterInterface } from "@mendix/widget-plugin-filtering/typings/InputFilterInterface";
import { Alert } from "@mendix/widget-plugin-component-kit/Alert";
import { useConst } from "@mendix/widget-plugin-mobx-kit/react/useConst";
import { useSetup } from "@mendix/widget-plugin-mobx-kit/react/useSetup";
import { DateStoreProvider } from "@mendix/widget-plugin-filtering/custom-filter-api/DateStoreProvider";
import { ISetupable } from "@mendix/widget-plugin-mobx-kit/setupable";

interface RequiredProps {
attributes: Array<{
attribute: AttributeMetaData<Date>;
}>;
name: string;
}

interface StoreProvider extends ISetupable {
store: Date_InputFilterInterface;
}

type Component<P extends object> = (props: P) => React.ReactElement;

export function withDateLinkedAttributes<P extends RequiredProps>(
component: Component<P & InjectableFilterAPI>
): Component<P> {
const StoreInjector = withInjectedStore(component);

return function FilterAPIProvider(props) {
const api = useStoreProvider(props);

if (api.hasError) {
return <Alert bootstrapStyle="danger">{api.error.message}</Alert>;
}

return <StoreInjector {...props} {...api.value} />;
};
}

function withInjectedStore<P extends object>(
Component: Component<P & InjectableFilterAPI>
): Component<P & { provider: StoreProvider; channel: string }> {
return function StoreInjector(props) {
const provider = useSetup(() => props.provider);
return <Component {...props} filterStore={provider.store} parentChannelName={props.channel} />;
};
}

interface InjectableFilterAPI {
filterStore: Date_InputFilterInterface;
parentChannelName?: string;
}

function useStoreProvider(props: RequiredProps): Result<{ provider: StoreProvider; channel: string }, APIError> {
const filterAPI = useFilterAPI();
return useConst(() => {
if (filterAPI.hasError) {
return error(filterAPI.error);
}

return value({
provider: new DateStoreProvider(filterAPI.value, {
attributes: props.attributes.map(obj => obj.attribute),
dataKey: props.name
}),
channel: filterAPI.value.parentChannelName
});
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,27 @@
* @author Mendix Widgets Framework Team
*/
import { CSSProperties } from "react";
import { ActionValue, DynamicValue, EditableValue } from "mendix";
import { ActionValue, AttributeMetaData, DynamicValue, EditableValue } from "mendix";

export type AttrChoiceEnum = "auto" | "linked";

export interface AttributesType {
attribute: AttributeMetaData<Date>;
}

export type DefaultFilterEnum = "between" | "greater" | "greaterEqual" | "equal" | "notEqual" | "smaller" | "smallerEqual" | "empty" | "notEmpty";

export interface AttributesPreviewType {
attribute: string;
}

export interface DatagridDateFilterContainerProps {
name: string;
class: string;
style?: CSSProperties;
tabIndex?: number;
advanced: boolean;
attrChoice: AttrChoiceEnum;
attributes: AttributesType[];
defaultValue?: DynamicValue<Date>;
defaultStartDate?: DynamicValue<Date>;
defaultEndDate?: DynamicValue<Date>;
Expand All @@ -40,7 +51,8 @@ export interface DatagridDateFilterPreviewProps {
readOnly: boolean;
renderMode: "design" | "xray" | "structure";
translate: (text: string) => string;
advanced: boolean;
attrChoice: AttrChoiceEnum;
attributes: AttributesPreviewType[];
defaultValue: string;
defaultStartDate: string;
defaultEndDate: string;
Expand Down
Loading