@sankhyalabs/core 1.0.72 → 2.0.0

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