Skip to content

Commit 81fc998

Browse files
committed
WIP
1 parent 7cb53b6 commit 81fc998

6 files changed

Lines changed: 224 additions & 9 deletions

File tree

packages/pluggableWidgets/datagrid-web/src/controllers/PaginationController.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
import { QueryController } from "@mendix/widget-plugin-grid/query/query-controller";
12
import { DerivedPropsGate } from "@mendix/widget-plugin-mobx-kit/props-gate";
23
import { ReactiveController, ReactiveControllerHost } from "@mendix/widget-plugin-mobx-kit/reactive-controller";
34
import { PaginationEnum, ShowPagingButtonsEnum } from "../../typings/DatagridProps";
4-
import { QueryController } from "./query-controller";
55

66
type Gate = DerivedPropsGate<{
77
pageSize: number;

packages/pluggableWidgets/datagrid-web/src/helpers/state/RootGridStore.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { BaseControllerHost } from "@mendix/widget-plugin-mobx-kit/BaseControlle
66
import { disposeBatch } from "@mendix/widget-plugin-mobx-kit/disposeBatch";
77
import { DerivedPropsGate } from "@mendix/widget-plugin-mobx-kit/props-gate";
88
import { generateUUID } from "@mendix/widget-plugin-platform/framework/generate-uuid";
9-
import { autorun, computed } from "mobx";
9+
import { autorun } from "mobx";
1010
import { DatagridContainerProps } from "../../../typings/DatagridProps";
1111
import { DatasourceParamsController } from "../../controllers/DatasourceParamsController";
1212
import { DerivedLoaderController } from "../../controllers/DerivedLoaderController";
@@ -67,7 +67,7 @@ export class RootGridStore extends BaseControllerHost {
6767
});
6868

6969
new RefreshController(this, {
70-
query: computed(() => query.computedCopy),
70+
query: query.derivedQuery,
7171
delay: props.refreshInterval * 1000
7272
});
7373

packages/pluggableWidgets/gallery-web/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"dependencies": {
4444
"@mendix/widget-plugin-external-events": "workspace:*",
4545
"@mendix/widget-plugin-filtering": "workspace:*",
46+
"@mendix/widget-plugin-mobx-kit": "workspace:^",
4647
"@mendix/widget-plugin-sorting": "workspace:*",
4748
"classnames": "^2.3.2",
4849
"mobx": "6.12.3",
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import { compactArray, fromCompactArray, isAnd } from "@mendix/filter-commons/condition-utils";
2+
import { createContextWithStub, FilterAPI } from "@mendix/widget-plugin-filtering/context";
3+
import { CustomFilterHost } from "@mendix/widget-plugin-filtering/stores/generic/CustomFilterHost";
4+
import { DatasourceController } from "@mendix/widget-plugin-grid/query/DatasourceController";
5+
import { PaginationController } from "@mendix/widget-plugin-grid/query/PaginationController";
6+
import { RefreshController } from "@mendix/widget-plugin-grid/query/RefreshController";
7+
import { BaseControllerHost } from "@mendix/widget-plugin-mobx-kit/BaseControllerHost";
8+
import { disposeBatch } from "@mendix/widget-plugin-mobx-kit/disposeBatch";
9+
import { DerivedPropsGate } from "@mendix/widget-plugin-mobx-kit/props-gate";
10+
import { ReactiveController, ReactiveControllerHost } from "@mendix/widget-plugin-mobx-kit/reactive-controller";
11+
import { generateUUID } from "@mendix/widget-plugin-platform/framework/generate-uuid";
12+
import { ListValue } from "mendix";
13+
import { FilterCondition } from "mendix/filters";
14+
import { makeAutoObservable, reaction } from "mobx";
15+
import { PaginationEnum } from "../../typings/GalleryProps";
16+
17+
interface DynamicProps {
18+
datasource: ListValue;
19+
}
20+
21+
interface StaticProps {
22+
pagination: PaginationEnum;
23+
showPagingButtons: "always" | "auto";
24+
showTotalCount: boolean;
25+
pageSize: number;
26+
}
27+
28+
type Gate = DerivedPropsGate<DynamicProps>;
29+
30+
type GalleryStoreSpec = StaticProps & {
31+
gate: Gate;
32+
};
33+
34+
export class GalleryStore extends BaseControllerHost {
35+
private readonly _id: string;
36+
private readonly _query: DatasourceController;
37+
readonly paging: PaginationController;
38+
readonly filterAPI: FilterAPI;
39+
40+
constructor(spec: GalleryStoreSpec) {
41+
super();
42+
43+
this._id = `GalleryStore@${generateUUID()}`;
44+
45+
this._query = new DatasourceController(this, { gate: spec.gate });
46+
47+
this.paging = new PaginationController(this, {
48+
gate: undefined,
49+
query: this._query,
50+
pageSize: spec.pageSize,
51+
pagination: spec.pagination,
52+
showPagingButtons: spec.showPagingButtons,
53+
showTotalCount: true
54+
});
55+
56+
const filterObserver = new CustomFilterHost();
57+
58+
const paramCtrl = new QueryParamsController(this, this._query, filterObserver);
59+
60+
this.filterAPI = createContextWithStub({
61+
filterObserver,
62+
parentChannelName: this._id,
63+
sharedInitFilter: paramCtrl.unzipFilter(spec.gate.props.datasource.filter)
64+
});
65+
66+
new RefreshController(this, {
67+
delay: 0,
68+
query: this._query.derivedQuery
69+
});
70+
}
71+
}
72+
73+
class QueryParamsController implements ReactiveController {
74+
private readonly _query: DatasourceController;
75+
private readonly _filters: CustomFilterHost;
76+
77+
constructor(host: ReactiveControllerHost, query: DatasourceController, filters: CustomFilterHost) {
78+
host.addController(this);
79+
80+
this._query = query;
81+
this._filters = filters;
82+
83+
makeAutoObservable(this, { setup: false });
84+
}
85+
86+
private get _derivedSortOrder(): ListValue["sortOrder"] {
87+
return [];
88+
}
89+
90+
private get _derivedFilter(): FilterCondition {
91+
return compactArray(this._filters.conditions);
92+
}
93+
94+
setup(): () => void {
95+
const [add, disposeAll] = disposeBatch();
96+
add(
97+
reaction(
98+
() => this._derivedSortOrder,
99+
sortOrder => this._query.setSortOrder(sortOrder),
100+
{ fireImmediately: true }
101+
)
102+
);
103+
add(
104+
reaction(
105+
() => this._derivedFilter,
106+
filter => this._query.setFilter(filter),
107+
{ fireImmediately: true }
108+
)
109+
);
110+
111+
return disposeAll;
112+
}
113+
114+
unzipFilter(filter?: FilterCondition): Array<FilterCondition | undefined> {
115+
if (!filter || !isAnd(filter)) {
116+
return [];
117+
}
118+
return fromCompactArray(filter);
119+
}
120+
}

packages/shared/widget-plugin-grid/src/query/DatasourceController.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { DerivedPropsGate } from "@mendix/widget-plugin-mobx-kit/props-gate";
22
import { ReactiveController, ReactiveControllerHost } from "@mendix/widget-plugin-mobx-kit/reactive-controller";
33
import { ListValue, ValueStatus } from "mendix";
4-
import { action, autorun, makeAutoObservable } from "mobx";
4+
import { action, autorun, computed, IComputedValue, makeAutoObservable } from "mobx";
55
import { QueryController } from "./query-controller";
66

77
type Gate = DerivedPropsGate<{ datasource: ListValue }>;
8+
89
type DatasourceControllerSpec = { gate: Gate };
910

1011
export class DatasourceController implements ReactiveController, QueryController {
@@ -58,7 +59,7 @@ export class DatasourceController implements ReactiveController, QueryController
5859
return this.datasource.status === "loading";
5960
}
6061

61-
private get datasource(): ListValue {
62+
get datasource(): ListValue {
6263
return this.gate.props.datasource;
6364
}
6465

@@ -90,12 +91,13 @@ export class DatasourceController implements ReactiveController, QueryController
9091
}
9192

9293
/**
93-
* Returns a new copy of the controller.
94+
* Returns computed value that holds controller copy.
9495
* Recomputes the copy every time the datasource changes.
9596
*/
96-
get computedCopy(): DatasourceController {
97-
const [copy] = [this.datasource].map(() => Object.create(this));
98-
return copy;
97+
get derivedQuery(): IComputedValue<DatasourceController> {
98+
const data = (): DatasourceController => [this.datasource].map(() => Object.create(this))[0];
99+
100+
return computed(data);
99101
}
100102

101103
setup(): () => void {
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { ReactiveController, ReactiveControllerHost } from "@mendix/widget-plugin-mobx-kit/reactive-controller";
2+
import { QueryController } from "./query-controller";
3+
4+
5+
type PaginationEnum = "buttons" | "virtualScrolling" | "loadMore";
6+
7+
type ShowPagingButtonsEnum = "always" | "auto";
8+
9+
type PaginationKind = `${PaginationEnum}.${ShowPagingButtonsEnum}`;
10+
11+
interface StaticProps {
12+
pageSize: number;
13+
pagination: PaginationEnum;
14+
showPagingButtons: ShowPagingButtonsEnum;
15+
showTotalCount: boolean;
16+
}
17+
18+
type Gate = undefined;
19+
20+
type PaginationControllerSpec = StaticProps &{
21+
gate: Gate;
22+
query: QueryController;
23+
};
24+
25+
26+
export class PaginationController implements ReactiveController {
27+
private readonly _pageSize: number;
28+
private readonly _query: QueryController;
29+
readonly pagination: PaginationEnum;
30+
readonly paginationKind: PaginationKind;
31+
readonly showPagingButtons: ShowPagingButtonsEnum;
32+
readonly showTotalCount: boolean;
33+
34+
constructor(host: ReactiveControllerHost, spec: PaginationControllerSpec) {
35+
host.addController(this);
36+
this._pageSize = spec.pageSize;
37+
this._query = spec.query;
38+
this.pagination = spec.pagination;
39+
this.showPagingButtons = spec.showPagingButtons;
40+
this.showTotalCount = spec.showTotalCount;
41+
this.paginationKind = `${this.pagination}.${this.showPagingButtons}`;
42+
this._setInitParams();
43+
}
44+
45+
get isLimitBased(): boolean {
46+
return this.pagination === "virtualScrolling" || this.pagination === "loadMore";
47+
}
48+
49+
get pageSize(): number {
50+
return this._pageSize;
51+
}
52+
53+
get currentPage(): number {
54+
const {
55+
_query: { limit, offset },
56+
pageSize
57+
} = this;
58+
return this.isLimitBased ? limit / pageSize : offset / pageSize;
59+
}
60+
61+
get showPagination(): boolean {
62+
switch (this.paginationKind) {
63+
case "buttons.always":
64+
return true;
65+
case "buttons.auto": {
66+
const { totalCount = -1 } = this._query;
67+
return totalCount > this._query.limit;
68+
}
69+
default:
70+
return this.showTotalCount;
71+
}
72+
}
73+
74+
private _setInitParams(): void {
75+
if (this.pagination === "buttons" || this.showTotalCount) {
76+
this._query.requestTotalCount(true);
77+
}
78+
79+
this._query.setPageSize(this.pageSize);
80+
}
81+
82+
setup(): void {}
83+
84+
setPage = (computePage: (prevPage: number) => number): void => {
85+
const newPage = computePage(this.currentPage);
86+
if (this.isLimitBased) {
87+
this._query.setLimit(newPage * this.pageSize);
88+
} else {
89+
this._query.setOffset(newPage * this.pageSize);
90+
}
91+
};
92+
}

0 commit comments

Comments
 (0)