|
1 | | -import { DerivedPropsGate, SetupComponent, SetupComponentHost } from "@mendix/widget-plugin-mobx-kit/main"; |
2 | | -import { DynamicValue, ListValue, SelectionMultiValue, SelectionSingleValue } from "mendix"; |
3 | | -import { action, makeAutoObservable, reaction } from "mobx"; |
4 | | - |
5 | | -type DynamicProps = { |
6 | | - datasource: ListValue; |
7 | | - selectAllTemplate?: DynamicValue<string>; |
8 | | - selectAllText?: DynamicValue<string>; |
9 | | - itemSelection?: SelectionSingleValue | SelectionMultiValue; |
10 | | - allSelectedText?: DynamicValue<string>; |
11 | | -}; |
12 | | - |
13 | | -interface SelectService { |
14 | | - selectAllPages(): Promise<{ success: boolean }> | { success: boolean }; |
15 | | - clearSelection(): void; |
16 | | -} |
17 | | - |
18 | | -interface CounterService { |
19 | | - selectedCount: number; |
20 | | - selectedCountText: string; |
21 | | - clearButtonLabel: string; |
22 | | -} |
| 1 | +import { SelectAllEvents } from "@mendix/widget-plugin-grid/select-all/select-all.model"; |
| 2 | +import { Emitter } from "@mendix/widget-plugin-mobx-kit/main"; |
| 3 | +import { makeAutoObservable } from "mobx"; |
23 | 4 |
|
24 | 5 | /** @injectable */ |
25 | | -export class SelectAllBarViewModel implements SetupComponent { |
26 | | - private barVisible = false; |
27 | | - private clearVisible = false; |
28 | | - |
29 | | - pending = false; |
30 | | - |
| 6 | +export class SelectAllBarViewModel { |
31 | 7 | constructor( |
32 | | - host: SetupComponentHost, |
33 | | - private readonly gate: DerivedPropsGate<DynamicProps>, |
34 | | - private readonly selectService: SelectService, |
35 | | - private readonly count: CounterService, |
36 | | - private readonly enableSelectAll: boolean |
| 8 | + private emitter: Emitter<SelectAllEvents>, |
| 9 | + private state: { pending: boolean; visible: boolean; clearBtnVisible: boolean }, |
| 10 | + private selectionTexts: { |
| 11 | + clearSelectionButtonLabel: string; |
| 12 | + selectedCountText: string; |
| 13 | + }, |
| 14 | + private selectAllTexts: { |
| 15 | + selectAllLabel: string; |
| 16 | + selectionStatus: string; |
| 17 | + }, |
| 18 | + private enableSelectAll: boolean |
37 | 19 | ) { |
38 | | - host.add(this); |
39 | | - type PrivateMembers = "setClearVisible" | "setPending" | "hideBar" | "showBar"; |
40 | | - makeAutoObservable<this, PrivateMembers>(this, { |
41 | | - setClearVisible: action, |
42 | | - setPending: action, |
43 | | - hideBar: action, |
44 | | - showBar: action |
45 | | - }); |
46 | | - } |
47 | | - |
48 | | - private get props(): DynamicProps { |
49 | | - return this.gate.props; |
50 | | - } |
51 | | - |
52 | | - private setClearVisible(value: boolean): void { |
53 | | - this.clearVisible = value; |
54 | | - } |
55 | | - |
56 | | - private setPending(value: boolean): void { |
57 | | - this.pending = value; |
58 | | - } |
59 | | - |
60 | | - private hideBar(): void { |
61 | | - this.barVisible = false; |
62 | | - this.clearVisible = false; |
63 | | - } |
64 | | - |
65 | | - private showBar(): void { |
66 | | - this.barVisible = true; |
67 | | - } |
68 | | - |
69 | | - private get total(): number { |
70 | | - return this.props.datasource.totalCount ?? 0; |
71 | | - } |
72 | | - |
73 | | - private get selectAllFormat(): string { |
74 | | - return this.props.selectAllTemplate?.value ?? "Select all %d rows in the data source"; |
75 | | - } |
76 | | - |
77 | | - private get selectAllText(): string { |
78 | | - return this.props.selectAllText?.value ?? "Select all rows in the data source"; |
79 | | - } |
80 | | - |
81 | | - private get allSelectedText(): string { |
82 | | - const str = this.props.allSelectedText?.value ?? "All %d rows selected."; |
83 | | - return str.replace("%d", `${this.count.selectedCount}`); |
84 | | - } |
85 | | - |
86 | | - private get isCurrentPageSelected(): boolean { |
87 | | - const selection = this.props.itemSelection; |
88 | | - |
89 | | - if (!selection || selection.type === "Single") return false; |
90 | | - |
91 | | - const pageIds = new Set(this.props.datasource.items?.map(item => item.id) ?? []); |
92 | | - const selectionSubArray = selection.selection.filter(item => pageIds.has(item.id)); |
93 | | - return selectionSubArray.length === pageIds.size && pageIds.size > 0; |
94 | | - } |
95 | | - |
96 | | - private get isAllItemsSelected(): boolean { |
97 | | - if (this.total > 0) return this.total === this.count.selectedCount; |
98 | | - |
99 | | - const { offset, limit, items = [], hasMoreItems } = this.gate.props.datasource; |
100 | | - const noMoreItems = typeof hasMoreItems === "boolean" && hasMoreItems === false; |
101 | | - const fullyLoaded = offset === 0 && limit >= items.length; |
102 | | - |
103 | | - return fullyLoaded && noMoreItems && items.length === this.count.selectedCount; |
| 20 | + makeAutoObservable(this); |
104 | 21 | } |
105 | 22 |
|
106 | 23 | get selectAllLabel(): string { |
107 | | - if (this.total > 0) return this.selectAllFormat.replace("%d", `${this.total}`); |
108 | | - return this.selectAllText; |
| 24 | + return this.selectAllTexts.selectAllLabel; |
109 | 25 | } |
110 | 26 |
|
111 | 27 | get clearSelectionLabel(): string { |
112 | | - return this.count.clearButtonLabel; |
| 28 | + return this.selectionTexts.clearSelectionButtonLabel; |
113 | 29 | } |
114 | 30 |
|
115 | 31 | get selectionStatus(): string { |
116 | | - if (this.isAllItemsSelected) return this.allSelectedText; |
117 | | - return this.count.selectedCountText; |
| 32 | + return this.selectAllTexts.selectionStatus; |
118 | 33 | } |
119 | 34 |
|
120 | 35 | get isBarVisible(): boolean { |
121 | | - return this.enableSelectAll && this.barVisible; |
| 36 | + return this.enableSelectAll && this.state.visible; |
122 | 37 | } |
123 | 38 |
|
124 | 39 | get isClearVisible(): boolean { |
125 | | - return this.clearVisible; |
| 40 | + return this.state.clearBtnVisible; |
126 | 41 | } |
127 | 42 |
|
128 | 43 | get isSelectAllDisabled(): boolean { |
129 | | - return this.pending; |
130 | | - } |
131 | | - |
132 | | - setup(): (() => void) | void { |
133 | | - if (!this.enableSelectAll) return; |
134 | | - |
135 | | - return reaction( |
136 | | - () => this.isCurrentPageSelected, |
137 | | - isCurrentPageSelected => { |
138 | | - if (isCurrentPageSelected === false) { |
139 | | - this.hideBar(); |
140 | | - } else if (this.isAllItemsSelected === false) { |
141 | | - this.showBar(); |
142 | | - } |
143 | | - } |
144 | | - ); |
| 44 | + return this.state.pending; |
145 | 45 | } |
146 | 46 |
|
147 | 47 | onClear(): void { |
148 | | - this.selectService.clearSelection(); |
| 48 | + this.emitter.emit("clear"); |
149 | 49 | } |
150 | 50 |
|
151 | | - async onSelectAll(): Promise<void> { |
152 | | - this.setPending(true); |
153 | | - try { |
154 | | - const { success } = await this.selectService.selectAllPages(); |
155 | | - this.setClearVisible(success); |
156 | | - } finally { |
157 | | - this.setPending(false); |
158 | | - } |
| 51 | + onSelectAll(): void { |
| 52 | + this.emitter.emit("startSelecting"); |
159 | 53 | } |
160 | 54 | } |
0 commit comments