Skip to content

[WC-2868] add number filter linked datasource #1511

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

Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<description />
<enumerationValues>
<enumerationValue key="auto">Auto</enumerationValue>
<enumerationValue key="linked">Manual</enumerationValue>
<enumerationValue key="linked">Custom</enumerationValue>
</enumerationValues>
</property>
<property key="linkedDs" type="datasource" isLinked="true" isList="true">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
import {
ContainerProps,
ImageProps,
structurePreviewPalette,
StructurePreviewProps,
text
} from "@mendix/widget-plugin-platform/preview/structure-preview-api";
import { hidePropertyIn, Properties } from "@mendix/pluggable-widgets-tools";
import {
emptyIcon,
emptyIconDark,
Expand All @@ -23,25 +17,26 @@ import {
smallerThanIcon,
smallerThanIconDark
} from "@mendix/widget-plugin-filtering/preview/editor-preview-icons";
import { hidePropertiesIn, hidePropertyIn, Properties } from "@mendix/pluggable-widgets-tools";
import {
ContainerProps,
ImageProps,
structurePreviewPalette,
StructurePreviewProps,
text
} from "@mendix/widget-plugin-platform/preview/structure-preview-api";

import { DatagridNumberFilterPreviewProps, DefaultFilterEnum } from "../typings/DatagridNumberFilterProps";

export function getProperties(
values: DatagridNumberFilterPreviewProps,
defaultProperties: Properties,
platform: "web" | "desktop"
): Properties {
export function getProperties(values: DatagridNumberFilterPreviewProps, defaultProperties: Properties): Properties {
if (!values.adjustable) {
hidePropertyIn(defaultProperties, values, "screenReaderButtonCaption");
}
if (platform === "web") {
if (!values.advanced) {
hidePropertiesIn(defaultProperties, values, ["onChange", "valueAttribute"]);
}
} else {
hidePropertyIn(defaultProperties, values, "advanced");

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

return defaultProperties;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,18 @@ import { DatagridNumberFilterContainerProps } from "../typings/DatagridNumberFil
import { NumberFilterContainer } from "./components/NumberFilterContainer";
import { isLoadingDefaultValues } from "./utils/widget-utils";
import { withNumberFilterAPI } from "./hocs/withNumberFilterAPI";
import { withLinkedAttributes } from "./hocs/withLinkedAttributes";

const container = withPreloader<DatagridNumberFilterContainerProps>(NumberFilterContainer, isLoadingDefaultValues);
const Widget = withNumberFilterAPI(container);
const FilterAuto = withNumberFilterAPI(container);
const FilterLinked = withLinkedAttributes(container);

export default function DatagridNumberFilter(props: DatagridNumberFilterContainerProps): ReactElement {
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,35 @@
<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="AutoNumber" />
<attributeType name="Decimal" />
<attributeType name="Integer" />
<attributeType name="Long" />
</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
@@ -0,0 +1,72 @@
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 { Number_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 { NumberStoreProvider } from "@mendix/widget-plugin-filtering/custom-filter-api/NumberStoreProvider";
import { ISetupable } from "@mendix/widget-plugin-mobx-kit/setupable";
import { Big } from "big.js";

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

interface StoreProvider extends ISetupable {
store: Number_InputFilterInterface;
}

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

export function withLinkedAttributes<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: Number_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 NumberStoreProvider(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,17 +4,28 @@
* @author Mendix Widgets Framework Team
*/
import { CSSProperties } from "react";
import { ActionValue, DynamicValue, EditableValue } from "mendix";
import { ActionValue, AttributeMetaData, DynamicValue, EditableValue } from "mendix";
import { Big } from "big.js";

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

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

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

export interface AttributesPreviewType {
attribute: string;
}

export interface DatagridNumberFilterContainerProps {
name: string;
class: string;
style?: CSSProperties;
tabIndex?: number;
advanced: boolean;
attrChoice: AttrChoiceEnum;
attributes: AttributesType[];
defaultValue?: DynamicValue<Big>;
defaultFilter: DefaultFilterEnum;
placeholder?: DynamicValue<string>;
Expand All @@ -37,7 +48,8 @@ export interface DatagridNumberFilterPreviewProps {
readOnly: boolean;
renderMode: "design" | "xray" | "structure";
translate: (text: string) => string;
advanced: boolean;
attrChoice: AttrChoiceEnum;
attributes: AttributesPreviewType[];
defaultValue: string;
defaultFilter: DefaultFilterEnum;
placeholder: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ export interface DatagridTextFilterPreviewProps {
readOnly: boolean;
renderMode: "design" | "xray" | "structure";
translate: (text: string) => string;
advanced: boolean;
customAttrs: CustomAttrsEnum;
attrChoice: AttrChoiceEnum;
attributes: AttributesPreviewType[];
defaultValue: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { FilterAPI } from "../context";
import { NumberInputFilterStore } from "../stores/input/NumberInputFilterStore";
import { Number_InputFilterInterface } from "../typings/InputFilterInterface";
import { BaseStoreProvider } from "./BaseStoreProvider";
import { FilterSpec } from "./typings";

export class NumberStoreProvider extends BaseStoreProvider<NumberInputFilterStore> {
protected _store: NumberInputFilterStore;
protected filterAPI: FilterAPI;
readonly dataKey: string;

constructor(filterAPI: FilterAPI, spec: FilterSpec<Big>) {
super();
this.filterAPI = filterAPI;
this.dataKey = spec.dataKey;
this._store = new NumberInputFilterStore(
spec.attributes,
this.findInitFilter(filterAPI.sharedInitFilter, this.dataKey)
);
}

get store(): Number_InputFilterInterface {
return this._store;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Big } from "big.js";
import { ListAttributeValue } from "mendix";
import { AttributeMetaData, ListAttributeValue, SimpleFormatter } from "mendix";
import { FilterCondition } from "mendix/filters";
import { action, comparer, makeObservable } from "mobx";
import { inputStateFromCond } from "../../condition-utils";
Expand All @@ -11,7 +11,8 @@ import { BaseInputFilterStore } from "./BaseInputFilterStore";
import { baseNames } from "./fn-mappers";

type NumFns = FilterFunctionGeneric | FilterFunctionNonValue | FilterFunctionBinary;
type Formatter = ListAttributeValue<Big>["formatter"];
type Formatter = SimpleFormatter<Big>;
type AttrMeta = AttributeMetaData<Big> & { formatter?: SimpleFormatter<Big> };

export class NumberInputFilterStore
extends BaseInputFilterStore<NumberArgument, NumFns>
Expand All @@ -20,9 +21,8 @@ export class NumberInputFilterStore
readonly storeType = "input";
readonly type = "number";

constructor(attributes: Array<ListAttributeValue<Big>>, initCond: FilterCondition | null) {
let { formatter } = attributes[0];
formatter = formatterFix(formatter);
constructor(attributes: AttrMeta[], initCond: FilterCondition | null) {
const formatter = formatterFix(attributes[0].formatter);
super(new NumberArgument(formatter), new NumberArgument(formatter), "equal", attributes);
makeObservable(this, {
updateProps: action,
Expand Down Expand Up @@ -79,11 +79,12 @@ export class NumberInputFilterStore
}
}

function formatterFix(formatter: Formatter): Formatter {
function formatterFix(formatter: Formatter | undefined): Formatter {
// Check formatter.parse to see if it is a valid formatter.
if (formatter.parse("none")?.valid === false) {
if (formatter && formatter.parse("none")?.valid === false) {
return formatter;
}

// Create a new formatter that will handle the autonumber values.
return {
format: (value: Big) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class StringInputFilterStore
readonly type = "string";

constructor(attributes: AttrMeta[], initCond: FilterCondition | null) {
const formatter = getFormatter(attributes[0]);
const formatter = getFormatter<string>(attributes[0]);
super(new StringArgument(formatter), new StringArgument(formatter), "equal", attributes);
makeObservable(this, {
updateProps: action,
Expand Down Expand Up @@ -94,11 +94,12 @@ export class StringInputFilterStore
}
}

function getFormatter(attr: AttrMeta): SimpleFormatter<string> {
function getFormatter<T>(attr: { formatter?: SimpleFormatter<T> }): SimpleFormatter<T> {
return (
attr.formatter ?? {
attr.formatter ??
({
format: v => v ?? "",
parse: v => ({ valid: true, value: v ?? "" })
}
} as SimpleFormatter<T>)
);
}