@sankhyalabs/core 1.0.70 → 1.0.71-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/.eslintrc.cjs +2 -1
  2. package/.releaserc +1 -1
  3. package/dist/dataunit/DataUnit.d.ts +33 -18
  4. package/dist/dataunit/DataUnit.js +220 -93
  5. package/dist/dataunit/DataUnit.js.map +1 -1
  6. package/dist/dataunit/loading/LoadDataRequest.d.ts +9 -0
  7. package/dist/dataunit/loading/LoadDataRequest.js +2 -0
  8. package/dist/dataunit/loading/LoadDataRequest.js.map +1 -0
  9. package/dist/dataunit/loading/LoadDataResponse.d.ts +6 -0
  10. package/dist/dataunit/loading/LoadDataResponse.js +2 -0
  11. package/dist/dataunit/loading/LoadDataResponse.js.map +1 -0
  12. package/dist/dataunit/loading/PaginationInfo.d.ts +7 -0
  13. package/dist/dataunit/loading/PaginationInfo.js +2 -0
  14. package/dist/dataunit/loading/PaginationInfo.js.map +1 -0
  15. package/dist/dataunit/state/action/DataUnitAction.d.ts +4 -0
  16. package/dist/dataunit/state/action/DataUnitAction.js.map +1 -1
  17. package/dist/dataunit/state/slice/ChangesSlice.d.ts +1 -0
  18. package/dist/dataunit/state/slice/ChangesSlice.js +3 -0
  19. package/dist/dataunit/state/slice/ChangesSlice.js.map +1 -1
  20. package/dist/dataunit/state/slice/LoadingControlSlice.d.ts +19 -0
  21. package/dist/dataunit/state/slice/LoadingControlSlice.js +45 -0
  22. package/dist/dataunit/state/slice/LoadingControlSlice.js.map +1 -0
  23. package/dist/dataunit/state/slice/RecordsSlice.js +2 -2
  24. package/dist/dataunit/state/slice/RecordsSlice.js.map +1 -1
  25. package/dist/dataunit/state/slice/SelectionSlice.js +0 -4
  26. package/dist/dataunit/state/slice/SelectionSlice.js.map +1 -1
  27. package/dist/dataunit/state/slice/WaitingChangesSlice.js.map +1 -1
  28. package/dist/exceptions/ErrorException.d.ts +2 -1
  29. package/dist/exceptions/ErrorException.js +2 -1
  30. package/dist/exceptions/ErrorException.js.map +1 -1
  31. package/dist/exceptions/WarningException.d.ts +2 -1
  32. package/dist/exceptions/WarningException.js +2 -1
  33. package/dist/exceptions/WarningException.js.map +1 -1
  34. package/dist/index.d.ts +7 -3
  35. package/dist/index.js +3 -2
  36. package/dist/index.js.map +1 -1
  37. package/dist/ui/FloatingManager.d.ts +1 -0
  38. package/dist/ui/FloatingManager.js +1 -1
  39. package/dist/ui/FloatingManager.js.map +1 -1
  40. package/dist/utils/ArrayUtils.d.ts +13 -0
  41. package/dist/utils/ArrayUtils.js +27 -0
  42. package/dist/utils/ArrayUtils.js.map +1 -0
  43. package/dist/utils/NumberUtils.d.ts +8 -0
  44. package/dist/utils/NumberUtils.js +10 -0
  45. package/dist/utils/NumberUtils.js.map +1 -1
  46. package/dist/utils/StringUtils.d.ts +16 -2
  47. package/dist/utils/StringUtils.js +45 -3
  48. package/dist/utils/StringUtils.js.map +1 -1
  49. package/jest.config.ts +5 -5
  50. package/package.json +1 -1
  51. package/src/dataunit/DataUnit.ts +240 -102
  52. package/src/dataunit/loading/LoadDataRequest.ts +10 -0
  53. package/src/dataunit/loading/LoadDataResponse.ts +7 -0
  54. package/src/dataunit/loading/PaginationInfo.ts +8 -0
  55. package/src/dataunit/state/action/DataUnitAction.ts +4 -0
  56. package/src/dataunit/state/slice/ChangesSlice.ts +4 -0
  57. package/src/dataunit/state/slice/LoadingControlSlice.ts +60 -0
  58. package/src/dataunit/state/slice/RecordsSlice.ts +3 -5
  59. package/src/dataunit/state/slice/SelectionSlice.ts +0 -5
  60. package/src/dataunit/state/slice/WaitingChangesSlice.ts +0 -1
  61. package/src/exceptions/ErrorException.ts +3 -1
  62. package/src/exceptions/WarningException.ts +4 -1
  63. package/src/index.ts +15 -3
  64. package/src/ui/FloatingManager.ts +2 -1
  65. package/src/utils/ArrayUtils.ts +28 -0
  66. package/src/utils/NumberUtils.ts +10 -0
  67. package/src/utils/StringUtils.ts +53 -3
@@ -1,21 +1,25 @@
1
- import { UnitMetadata, FieldDescriptor, SortingProvider, FilterProvider, Sort, Filter } from "./metadata/UnitMetadata.js";
2
1
  import { convertType, toString } from "./metadata/DataType.js";
2
+ import { FieldDescriptor, Filter, FilterProvider, Sort, SortingProvider, UnitMetadata } from "./metadata/UnitMetadata.js";
3
3
 
4
- import { DataUnitAction, Action } from "./state/action/DataUnitAction.js";
4
+ import { Action, DataUnitAction, ExecutionContext } from "./state/action/DataUnitAction.js";
5
5
  import StateManager from "./state/StateManager.js";
6
6
 
7
- import { HistReducer, canRedo, canUndo } from "./state/HistReducer.js";
8
- import { UnitMetadataReducer, getField, getMetadata } from "./state/slice/UnitMetadataSlice.js";
9
- import { RecordsReducer } from "./state/slice/RecordsSlice.js";
10
- import { SelectionReducer, getSelection, hasNext, hasPrevious } from "./state/slice/SelectionSlice.js";
11
- import { ChangesReducer, isDirty, getChangesToSave } from "./state/slice/ChangesSlice.js";
12
- import { RemovedRecordsReducer } from "./state/slice/RemovedRecordsSlice.js";
13
- import { AddedRecordsReducer, prepareAddedRecordId, prepareCopiedRecord } from "./state/slice/AddedRecordsSlice.js";
14
- import { CurrentRecordsReducer, getCurrentRecords, getFieldValue, getModifiedRecords } from "./state/slice/CurrentRecordsSlice.js";
15
- import { getBlockingWaitingChanges, getWaitingChangePromisses, getWaitingChanges, isWaiting, WaitingChangesReducer } from "./state/slice/WaitingChangesSlice.js";
16
- import WaitingChangeException from "../exceptions/WaitingChangeException.js";
17
7
  import ErrorException from "../exceptions/ErrorException.js";
8
+ import WaitingChangeException from "../exceptions/WaitingChangeException.js";
18
9
  import { StringUtils } from "../utils/StringUtils.js";
10
+ import { LoadDataRequest } from "./loading/LoadDataRequest.js";
11
+ import { LoadDataResponse } from "./loading/LoadDataResponse.js";
12
+ import { PaginationInfo } from "./loading/PaginationInfo.js";
13
+ import { AddedRecordsReducer, prepareAddedRecordId, prepareCopiedRecord } from "./state/slice/AddedRecordsSlice.js";
14
+ import { ChangesReducer, getChangesToSave, isDirty, hasDirtyRecords } from "./state/slice/ChangesSlice.js";
15
+ import { CurrentRecordsReducer, getCurrentRecords, getFieldValue, getModifiedRecords } from "./state/slice/CurrentRecordsSlice.js";
16
+ import { getCurrentPage, getLastPage, getPaginationInfo, getCurrentRequest, LoadingControlReducer, hasMorePages, hasPreviousPages } from "./state/slice/LoadingControlSlice.js";
17
+ import { RecordsReducer } from "./state/slice/RecordsSlice.js";
18
+ import { RemovedRecordsReducer } from "./state/slice/RemovedRecordsSlice.js";
19
+ import { getSelection, hasNext, hasPrevious, SelectionReducer } from "./state/slice/SelectionSlice.js";
20
+ import { getField, getMetadata, UnitMetadataReducer } from "./state/slice/UnitMetadataSlice.js";
21
+ import { getBlockingWaitingChanges, getWaitingChangePromisses, isWaiting, WaitingChangesReducer } from "./state/slice/WaitingChangesSlice.js";
22
+ import { canRedo, canUndo, HistReducer } from "./state/HistReducer.js";
19
23
 
20
24
  export default class DataUnit {
21
25
 
@@ -25,18 +29,21 @@ export default class DataUnit {
25
29
  private _filterProviders: Map<string, FilterProvider>;
26
30
  private _stateManager: StateManager;
27
31
  private _interceptors: Array<DUActionInterceptor>;
32
+ private _pageSize: number;
28
33
 
29
34
  public metadataLoader?: (dataUnit: DataUnit) => Promise<UnitMetadata>;
30
- public dataLoader?: (dataUnit: DataUnit, page?: PageRequest, sort?: Array<Sort>, filters?: Array<Filter>) => Promise<PageResponse>;
35
+ public dataLoader?: (dataUnit: DataUnit, request: LoadDataRequest) => Promise<LoadDataResponse>;
31
36
  public saveLoader?: (dataUnit: DataUnit, changes: Array<Change>) => Promise<Array<SavedRecord>>;
32
37
  public removeLoader?: (dataUnit: DataUnit, recordIds: Array<string>) => Promise<Array<string>>;
33
38
 
34
39
  constructor(name: string) {
35
40
  this._name = name;
41
+ this._pageSize = 0;
36
42
  this._stateManager = new StateManager(
37
43
  [
38
44
  HistReducer,
39
45
  UnitMetadataReducer,
46
+ LoadingControlReducer,
40
47
  RecordsReducer,
41
48
  RemovedRecordsReducer,
42
49
  AddedRecordsReducer,
@@ -58,7 +65,6 @@ export default class DataUnit {
58
65
 
59
66
  // Métodos privados
60
67
  private validateAndTypeValue(fieldName: string, newValue: any): any {
61
- //FIXME: Validações devem ser feitas aqui
62
68
  const descriptor: FieldDescriptor | undefined = this.getField(fieldName);
63
69
  return descriptor ? convertType(descriptor.dataType, newValue) : newValue;
64
70
  }
@@ -78,16 +84,34 @@ export default class DataUnit {
78
84
  return this._sortingProvider ? this._sortingProvider.getSort(this._name) : undefined;
79
85
  }
80
86
 
81
- private getFielterProviderKey(provider:FilterProvider):string{
82
- if(provider.getKey){
87
+ private getFielterProviderKey(provider: FilterProvider): string {
88
+ if (provider.getKey) {
83
89
  return provider.getKey();
84
90
  }
85
91
  return StringUtils.hashCode(provider.getFilter.toString());
86
92
  }
87
93
 
94
+ private executeLoadData(request: LoadDataRequest, executionCtx?: ExecutionContext): Promise<LoadDataResponse> {
95
+ return new Promise(async (resolve, fail) => {
96
+ if (await this.dispatchAction(Action.LOADING_DATA, request, executionCtx)) {
97
+ if (this.dataLoader) {
98
+ this.dataLoader(this, request).then(
99
+ response => {
100
+ this.dispatchAction(Action.DATA_LOADED, response, executionCtx);
101
+ resolve(response);
102
+ }
103
+ ).catch(error => {
104
+ const {errorCode} = error;
105
+ fail(new ErrorException("Problema carregando registros", error, errorCode))
106
+ });
107
+ }
108
+ }
109
+ });
110
+ }
111
+
88
112
  // Loaders
89
- public async loadMetadata(): Promise<UnitMetadata|void> {
90
- if(this.dispatchAction(Action.LOADING_METADATA)){
113
+ public async loadMetadata(executionCtx?: ExecutionContext): Promise<UnitMetadata | void> {
114
+ if (await this.dispatchAction(Action.LOADING_METADATA, undefined, executionCtx)) {
91
115
  return new Promise((resolve, fail) => {
92
116
  if (this.metadataLoader) {
93
117
  this.metadataLoader(this).then(
@@ -95,30 +119,60 @@ export default class DataUnit {
95
119
  this.metadata = metadata
96
120
  resolve(this.metadata);
97
121
  }
98
- ).catch(error => fail(new ErrorException("Problema carregando metadados", error)));
122
+ ).catch(error => {
123
+ const {errorCode} = error;
124
+ fail(new ErrorException("Problema carregando metadados", error, errorCode))
125
+ });
99
126
  }
100
127
  });
101
128
  }
102
129
  }
103
130
 
104
- public async loadData(page?: PageRequest): Promise<PageResponse|void> {
105
- if(this.dispatchAction(Action.LOADING_DATA)){
106
- return new Promise((resolve, fail) => {
107
- if (this.dataLoader) {
108
- const sort = this.getSort();
109
- const filters = this.getFilters();
110
- this.dataLoader(this, page, sort, filters).then(
111
- pageRes => {
112
- this.records = pageRes.records;
113
- resolve(pageRes);
114
- }
115
- ).catch(error => fail(new ErrorException("Problema carregando registros", error)));
116
- }
117
- });
131
+ public async loadData(quickFilter?: QuickFilter, executionCtx?: ExecutionContext): Promise<LoadDataResponse> {
132
+
133
+ const loadDataRequest: LoadDataRequest = {
134
+ quickFilter,
135
+ filters: this.getFilters(),
136
+ sort: this.getSort()
137
+ };
138
+
139
+ if (this._pageSize > 0) {
140
+ loadDataRequest.limit = this._pageSize
141
+ loadDataRequest.offset = 0;
118
142
  }
143
+
144
+ return this.executeLoadData(loadDataRequest, executionCtx);
119
145
  }
120
146
 
121
- public async saveData(): Promise<void> {
147
+ public async gotoPage(page: number, executionCtx?: ExecutionContext): Promise<LoadDataResponse | void> {
148
+
149
+ let request = getCurrentRequest(this._stateManager);
150
+
151
+ if (!request) {
152
+ request = {
153
+ filters: this.getFilters(),
154
+ sort: this.getSort()
155
+ }
156
+ }
157
+
158
+ if (page >= 0 && page <= getLastPage(this._stateManager, this._pageSize)) {
159
+ return this.executeLoadData({
160
+ ...request,
161
+ limit: this._pageSize,
162
+ offset: page * this._pageSize
163
+ }, executionCtx);
164
+ }
165
+ }
166
+
167
+ public async nextPage(executionCtx?: ExecutionContext): Promise<LoadDataResponse | void> {
168
+ return this.gotoPage(getCurrentPage(this._stateManager) + 1, executionCtx);
169
+ }
170
+
171
+ public async previousPage(executionCtx?: ExecutionContext): Promise<LoadDataResponse | void> {
172
+ return this.gotoPage(getCurrentPage(this._stateManager) - 1, executionCtx);
173
+ }
174
+
175
+ public async saveData(executionCtx?: ExecutionContext): Promise<void> {
122
176
  const blockingWaitingChanges = getBlockingWaitingChanges(this._stateManager);
123
177
 
124
178
  if (blockingWaitingChanges && blockingWaitingChanges.size > 0) {
@@ -126,8 +180,8 @@ export default class DataUnit {
126
180
  return Promise.reject(new WaitingChangeException("Aguardando alteração de campo", (waitingChange as WaitingChange).waitmessage));
127
181
  } else {
128
182
  if (isDirty(this._stateManager)) {
129
-
130
- if (this.dispatchAction(Action.SAVING_DATA)) {
183
+
184
+ if (await this.dispatchAction(Action.SAVING_DATA, undefined, executionCtx)) {
131
185
  const promisses = getWaitingChangePromisses(this._stateManager);
132
186
  return new Promise((resolve, fail) => {
133
187
  Promise.all(promisses || []).then(() => {
@@ -135,10 +189,13 @@ export default class DataUnit {
135
189
  const changes: Array<Change> = getChangesToSave(this._name, this._stateManager);
136
190
  this.saveLoader(this, changes).then(
137
191
  records => {
138
- this.dispatchAction(Action.DATA_SAVED, { changes, records });
192
+ this.dispatchAction(Action.DATA_SAVED, { changes, records }, executionCtx);
139
193
  resolve();
140
194
  }
141
- ).catch(cause => fail(new ErrorException("Erro salvando alterações", cause)));
195
+ ).catch(cause => {
196
+ const {errorCode} = cause;
197
+ fail(new ErrorException("Erro salvando alterações", cause, errorCode));
198
+ });
142
199
  } else {
143
200
  resolve();
144
201
  }
@@ -154,44 +211,48 @@ export default class DataUnit {
154
211
  public async removeSelectedRecords(buffered: boolean = false): Promise<Array<string>> {
155
212
  const selection = getSelection(this._stateManager);
156
213
  if (selection) {
157
- return this.removeRecords(selection, buffered);
214
+ const records = this.getSelectedRecords() || [];
215
+ return this.removeRecords(selection, records, buffered);
158
216
  }
159
217
  return Promise.resolve(selection);
160
218
  }
161
219
 
162
- public async removeRecords(records: Array<string>, buffered: boolean = false): Promise<Array<string>> {
163
- if (records) {
220
+ public async removeRecords(recordIds: Array<string>, cachedRecords: Array<Record>, buffered: boolean = false, executionCtx?: ExecutionContext): Promise<Array<string>> {
221
+ if (recordIds) {
164
222
  if (buffered || !this.removeLoader) {
165
- this.dispatchAction(Action.RECORDS_REMOVED, { records, buffered: true });
223
+ this.dispatchAction(Action.RECORDS_REMOVED, { records: recordIds, cachedRecords, buffered: true }, executionCtx);
166
224
  } else {
167
- if (this.dispatchAction(Action.REMOVING_RECORDS)) {
225
+ if (await this.dispatchAction(Action.REMOVING_RECORDS, undefined, executionCtx)) {
168
226
 
169
227
  return new Promise((resolve, fail) => {
170
228
  if (this.removeLoader) {
171
- this.removeLoader(this, records).then(
172
- records => {
229
+ this.removeLoader(this, recordIds).then(
230
+ removedIds => {
173
231
  let currentIndex = 0;
174
232
  const removedIndex: Array<number> = [];
175
233
  const currentRecords = getCurrentRecords(this._stateManager);
176
234
 
177
235
  currentRecords.forEach((value, key) => {
178
- if (records.includes(key)) {
236
+ if (removedIds.includes(key)) {
179
237
  removedIndex.push(currentIndex);
180
238
  }
181
239
 
182
240
  currentIndex++
183
241
  });
184
242
 
185
- this.dispatchAction(Action.RECORDS_REMOVED, { records, removedIndex, buffered: false });
186
- resolve(records);
243
+ this.dispatchAction(Action.RECORDS_REMOVED, { records: removedIds, cachedRecords, removedIndex, buffered: false }, executionCtx);
244
+ resolve(removedIds);
187
245
  }
188
- ).catch(error => fail(new ErrorException("Problema removendo registros", error)));
246
+ ).catch(error => {
247
+ const {errorCode} = error;
248
+ fail(new ErrorException("Problema removendo registros", error, errorCode))
249
+ });
189
250
  }
190
251
  });
191
252
  }
192
253
  }
193
254
  }
194
- return Promise.resolve(records);
255
+ return Promise.resolve(recordIds);
195
256
  }
196
257
 
197
258
  // API
@@ -217,12 +278,16 @@ export default class DataUnit {
217
278
  this._filterProviders.set(this.getFielterProviderKey(provider), provider);
218
279
  }
219
280
 
281
+ public getPaginationInfo(): PaginationInfo | void {
282
+ return getPaginationInfo(this._stateManager);
283
+ }
284
+
220
285
  public set sortingProvider(provider: SortingProvider) {
221
286
  this._sortingProvider = provider;
222
287
  }
223
288
 
224
289
  public set metadata(md: UnitMetadata) {
225
- this.dispatchAction(Action.METADATA_LOADED, md);
290
+ this.dispatchAction(Action.METADATA_LOADED, md, undefined);
226
291
  }
227
292
 
228
293
  public get metadata(): UnitMetadata {
@@ -230,7 +295,7 @@ export default class DataUnit {
230
295
  }
231
296
 
232
297
  public set records(r: Array<Record>) {
233
- this.dispatchAction(Action.DATA_LOADED, r);
298
+ this.dispatchAction(Action.DATA_LOADED, { records: this.records }, undefined);
234
299
  }
235
300
 
236
301
  public get records(): Array<Record> {
@@ -238,6 +303,14 @@ export default class DataUnit {
238
303
  return records ? Array.from(records.values()) : [];
239
304
  }
240
305
 
306
+ public set pageSize(size: number) {
307
+ this._pageSize = size;
308
+ }
309
+
310
+ public get pageSize(): number {
311
+ return this._pageSize;
312
+ }
313
+
241
314
  public getModifiedRecords(): Array<Record> {
242
315
  const modified = getModifiedRecords(this._stateManager);
243
316
  return modified || [];
@@ -247,14 +320,14 @@ export default class DataUnit {
247
320
  return getField(this._stateManager, fieldName);
248
321
  }
249
322
 
250
- public addRecord(): void {
251
- this.dispatchAction(Action.RECORDS_ADDED, prepareAddedRecordId(this._stateManager, [{}]));
323
+ public addRecord(executionCtx?: ExecutionContext): void {
324
+ this.dispatchAction(Action.RECORDS_ADDED, prepareAddedRecordId(this._stateManager, [{}]), executionCtx);
252
325
  }
253
326
 
254
- public copySelected(): void {
327
+ public copySelected(executionCtx?: ExecutionContext): void {
255
328
  const selectedRecords = this.getSelectedRecords();
256
329
  if (selectedRecords) {
257
- this.dispatchAction(Action.RECORDS_COPIED, prepareCopiedRecord(this._stateManager, selectedRecords));
330
+ this.dispatchAction(Action.RECORDS_COPIED, prepareCopiedRecord(this._stateManager, selectedRecords), executionCtx);
258
331
  }
259
332
  }
260
333
 
@@ -272,38 +345,42 @@ export default class DataUnit {
272
345
  const currentValue = this.getFieldValue(fieldName);
273
346
 
274
347
  if (currentValue !== typedValue) {
275
- this.dispatchAction(Action.DATA_CHANGED, { [fieldName]: typedValue, records });
348
+ this.dispatchAction(Action.DATA_CHANGED, { [fieldName]: typedValue, records }, undefined);
276
349
  }
277
350
  }
278
351
 
279
352
  public startChange(fieldName: string, waitingChange: WaitingChange): void {
280
- this.dispatchAction(Action.CHANGING_DATA, { [fieldName]: waitingChange });
353
+ this.dispatchAction(Action.CHANGING_DATA, { [fieldName]: waitingChange }, undefined);
281
354
  }
282
355
 
283
356
  public cancelWaitingChange(fieldName: string): void {
284
- this.dispatchAction(Action.WAITING_CHANGE_CANCELED, { fieldName });
357
+ this.dispatchAction(Action.WAITING_CHANGE_CANCELED, { fieldName }, undefined);
285
358
  }
286
359
 
287
360
  public getSelection(): Array<string> {
288
361
  return getSelection(this._stateManager);
289
362
  }
290
363
 
291
- public setSelection(selection: Array<string>): void {
292
- this.dispatchAction(Action.SELECTION_CHANGED, { type: "id", selection });
364
+ public setSelection(selection: Array<string>, executionCtx?: ExecutionContext): void {
365
+ this.dispatchAction(Action.SELECTION_CHANGED, { type: "id", selection }, executionCtx);
293
366
  }
294
367
 
295
- public selectFirst(): void {
296
- if(this.records.length > 0){
297
- this.dispatchAction(Action.SELECTION_CHANGED, { type: "index", selection: [0] });
368
+ public selectFirst(executionCtx?: ExecutionContext): void {
369
+ if (this.records.length > 0) {
370
+ this.setSelectionByIndex([0], executionCtx);
298
371
  }
299
372
  }
300
373
 
301
- public selectLast(): void {
302
- if(this.records.length > 0){
303
- this.dispatchAction(Action.SELECTION_CHANGED, { type: "index", selection: [this.records.length - 1] });
374
+ public selectLast(executionCtx?: ExecutionContext): void {
375
+ if (this.records.length > 0) {
376
+ this.setSelectionByIndex([this.records.length - 1], executionCtx);
304
377
  }
305
378
  }
306
379
 
380
+ public setSelectionByIndex(selection: Array<number>, executionCtx?: ExecutionContext): void {
381
+ this.dispatchAction(Action.SELECTION_CHANGED, { type: "index", selection }, executionCtx);
382
+ }
383
+
307
384
  public getSelectedRecords(): Array<Record> | undefined {
308
385
  const selection: Array<string> = this.getSelection();
309
386
  if (selection) {
@@ -312,28 +389,72 @@ export default class DataUnit {
312
389
  }
313
390
  }
314
391
 
315
- public nextRecord(): void {
316
- this.dispatchAction(Action.NEXT_SELECTED);
392
+ public nextRecord(executionCtx?: ExecutionContext): void {
393
+ if(!hasNext(this._stateManager)){
394
+ if(hasMorePages(this._stateManager)){
395
+ this.nextPage({
396
+ before: act =>{
397
+ if(executionCtx && executionCtx.before){
398
+ act = executionCtx.before(act);
399
+ }
400
+ return act;
401
+ },
402
+ after: act => {
403
+ this.selectFirst(executionCtx);
404
+ }
405
+ });
406
+ }
407
+ } else {
408
+ this.dispatchAction(Action.NEXT_SELECTED, undefined, executionCtx);
409
+ }
317
410
  }
318
411
 
319
- public previousRecord(): void {
320
- this.dispatchAction(Action.PREVIOUS_SELECTED);
412
+ public previousRecord(executionCtx?: ExecutionContext): void {
413
+ if(!hasPrevious(this._stateManager)){
414
+ if(hasPreviousPages(this._stateManager)){
415
+ this.previousPage({
416
+ before: act =>{
417
+ if(executionCtx && executionCtx.before){
418
+ act = executionCtx.before(act);
419
+ }
420
+ return act;
421
+ },
422
+ after: act => {
423
+ this.selectLast(executionCtx);
424
+ }
425
+ });
426
+ }
427
+ } else {
428
+ this.dispatchAction(Action.PREVIOUS_SELECTED, undefined, executionCtx);
429
+ }
321
430
  }
322
431
 
323
- public cancelEdition(): void {
324
- this.dispatchAction(Action.EDITION_CANCELED);
432
+ public cancelEdition(executionCtx?: ExecutionContext): void {
433
+ this.dispatchAction(Action.EDITION_CANCELED, undefined, executionCtx);
325
434
  }
326
435
 
327
436
  public isDirty(): boolean {
328
437
  return isDirty(this._stateManager);
329
438
  }
330
439
 
440
+ public hasDirtyRecords(): boolean {
441
+ return hasDirtyRecords(this._stateManager);
442
+ }
443
+
331
444
  public hasNext(): boolean {
332
- return hasNext(this._stateManager);
445
+ let result = hasNext(this._stateManager);
446
+ if(!result){
447
+ result = hasMorePages(this._stateManager);
448
+ }
449
+ return result;
333
450
  }
334
451
 
335
452
  public hasPrevious(): boolean {
336
- return hasPrevious(this._stateManager);
453
+ let result = hasPrevious(this._stateManager);
454
+ if(!result){
455
+ result = hasPreviousPages(this._stateManager);
456
+ }
457
+ return result;
337
458
  }
338
459
 
339
460
  public canUndo(): boolean {
@@ -344,12 +465,12 @@ export default class DataUnit {
344
465
  return canRedo(this._stateManager);
345
466
  }
346
467
 
347
- public undo() {
348
- this.dispatchAction(Action.CHANGE_UNDONE);
468
+ public undo(executionCtx?: ExecutionContext) {
469
+ this.dispatchAction(Action.CHANGE_UNDONE, undefined, executionCtx);
349
470
  }
350
471
 
351
- public redo() {
352
- this.dispatchAction(Action.CHANGE_REDONE);
472
+ public redo(executionCtx?: ExecutionContext) {
473
+ this.dispatchAction(Action.CHANGE_REDONE, undefined, executionCtx);
353
474
  }
354
475
 
355
476
  public toString() {
@@ -357,33 +478,50 @@ export default class DataUnit {
357
478
  }
358
479
 
359
480
  // Actions / State manager
360
- private dispatchAction(actionType: Action, payload?: any): boolean {
361
- let action = new DataUnitAction(actionType, payload);
362
-
363
- this._interceptors?.forEach(interceptor => {
481
+ private async dispatchAction(actionType: Action, payload?: any, executionCtx?: ExecutionContext): Promise<boolean> {
482
+ return new Promise(async resolve => {
483
+ let action = new DataUnitAction(actionType, payload);
484
+ if (executionCtx && executionCtx.before) {
485
+ action = executionCtx.before(action);
486
+ }
487
+ if (action && this._interceptors && this._interceptors.length > 0) {
488
+ action = await this.intercept(action, this._interceptors.values());
489
+ }
364
490
  if (action) {
365
- action = interceptor.interceptAction(action);
491
+ this.doDispatchAction(action);
492
+ if (executionCtx && executionCtx.after) {
493
+ executionCtx.after(action)
494
+ }
495
+ resolve(true);
496
+ } else {
497
+ resolve(false);
366
498
  }
367
499
  });
500
+ }
368
501
 
369
- if (!action) {
370
- return false;
371
- } else {
502
+ private async intercept(action: DataUnitAction, interceptors: IterableIterator<DUActionInterceptor>): Promise<DataUnitAction> {
503
+ return new Promise(async resolve => {
504
+ let ite;
505
+ while (action && !(ite = interceptors.next()).done) {
506
+ action = await ite.value.interceptAction(action);
507
+ }
508
+ resolve(action);
509
+ });
510
+ }
372
511
 
373
- this._stateManager.process(action);
374
- this._observers.forEach(f => {
375
- /*
376
- if some observer throws exceptions,
377
- should be continued
378
- */
379
- try {
380
- f(action);
381
- } catch (e) {
382
- console.warn("[DataUnit] error while call observer", e);
383
- }
384
- });
385
- }
386
- return true;
512
+ private doDispatchAction(action: DataUnitAction) {
513
+ this._stateManager.process(action);
514
+ this._observers.forEach(f => {
515
+ /*
516
+ if some observer throws exceptions,
517
+ should be continued
518
+ */
519
+ try {
520
+ f(action);
521
+ } catch (e) {
522
+ console.warn("[DataUnit] error while call observer", e);
523
+ }
524
+ });
387
525
  }
388
526
 
389
527
  public subscribe(observer: (action: DataUnitAction) => void) {
@@ -396,7 +534,7 @@ export default class DataUnit {
396
534
  }
397
535
 
398
536
  export interface DUActionInterceptor {
399
- interceptAction(action: DataUnitAction): DataUnitAction;
537
+ interceptAction(action: DataUnitAction): DataUnitAction | Promise<DataUnitAction>;
400
538
  }
401
539
 
402
540
  export interface Record {
@@ -0,0 +1,10 @@
1
+ import { QuickFilter } from "../DataUnit.js";
2
+ import { Filter, Sort } from "../metadata/UnitMetadata.js";
3
+
4
+ export interface LoadDataRequest {
5
+ offset?: number;
6
+ limit?: number;
7
+ quickFilter?: QuickFilter;
8
+ filters?: Array<Filter>;
9
+ sort?: Array<Sort>;
10
+ }
@@ -0,0 +1,7 @@
1
+ import { Record } from "../DataUnit.js";
2
+ import { PaginationInfo } from "./PaginationInfo.js";
3
+
4
+ export interface LoadDataResponse {
5
+ records: Array<Record>;
6
+ paginationInfo?: PaginationInfo;
7
+ }
@@ -0,0 +1,8 @@
1
+
2
+ export interface PaginationInfo {
3
+ currentPage: number;
4
+ firstRecord: number;
5
+ lastRecord: number;
6
+ total: number;
7
+ hasMore: boolean;
8
+ }
@@ -19,6 +19,10 @@ export class DataUnitAction implements StateAction{
19
19
  return this._payload;
20
20
  }
21
21
  }
22
+ export interface ExecutionContext{
23
+ before?: (action: DataUnitAction) => DataUnitAction;
24
+ after?: (action: DataUnitAction) => void;
25
+ }
22
26
 
23
27
  export enum Action{
24
28
 
@@ -68,6 +68,10 @@ export const isDirty = (stateManager: StateManager): boolean => {
68
68
  return true;
69
69
  }
70
70
 
71
+ return hasDirtyRecords(stateManager);
72
+ }
73
+
74
+ export const hasDirtyRecords = (stateManager: StateManager): boolean => {
71
75
  if(getWaitingChanges(stateManager) !== undefined){
72
76
  return true;
73
77
  }