@sankhyalabs/core 5.20.0-dev.5 → 5.20.0-dev.50

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 (179) hide show
  1. package/.docs/README.md +3 -1
  2. package/.docs/classes/ApplicationContext.md +31 -32
  3. package/.docs/classes/ArrayUtils.md +95 -83
  4. package/.docs/classes/AuthorizedServiceCaller.md +25 -34
  5. package/.docs/classes/Change.md +59 -74
  6. package/.docs/classes/DataUnit.md +1180 -1086
  7. package/.docs/classes/DataUnitAction.md +25 -42
  8. package/.docs/classes/DataUnitStorage.md +40 -43
  9. package/.docs/classes/DateUtils.md +140 -133
  10. package/.docs/classes/ElementIDUtils.md +123 -122
  11. package/.docs/classes/ErrorException.md +67 -88
  12. package/.docs/classes/ErrorTracking.md +20 -23
  13. package/.docs/classes/FieldComparator.md +35 -39
  14. package/.docs/classes/FloatingManager.md +195 -198
  15. package/.docs/classes/HTMLBuilder.md +14 -20
  16. package/.docs/classes/HttpProvider.md +45 -41
  17. package/.docs/classes/IDBRepository.md +201 -196
  18. package/.docs/classes/JSUtils.md +65 -66
  19. package/.docs/classes/KeyboardManager.md +95 -87
  20. package/.docs/classes/{MaskFormatter-1.md → MaskFormatter.md} +93 -128
  21. package/.docs/classes/NumberUtils.md +163 -152
  22. package/.docs/classes/ObjectUtils.md +206 -70
  23. package/.docs/classes/OnboardingUtils.md +36 -51
  24. package/.docs/classes/OverflowWatcher.md +533 -0
  25. package/.docs/classes/PromiseSync.md +25 -42
  26. package/.docs/classes/ReadyUtil.md +31 -41
  27. package/.docs/classes/RequestMetadata.md +29 -30
  28. package/.docs/classes/SearchUtils.md +18 -20
  29. package/.docs/classes/SelectionInfo.md +73 -74
  30. package/.docs/classes/ServiceCanceledException.md +193 -0
  31. package/.docs/classes/SkwHttpProvider.md +33 -45
  32. package/.docs/classes/StringUtils.md +297 -322
  33. package/.docs/classes/TimeFormatter.md +43 -44
  34. package/.docs/classes/UserAgentUtils.md +17 -20
  35. package/.docs/classes/VersionUtils.md +15 -18
  36. package/.docs/classes/WaitingChangeException.md +63 -84
  37. package/.docs/classes/WarningException.md +67 -88
  38. package/.docs/enumerations/Action.md +317 -0
  39. package/.docs/enumerations/ChangeOperation.md +47 -0
  40. package/.docs/enumerations/DataType.md +57 -0
  41. package/.docs/enumerations/DependencyType.md +37 -0
  42. package/.docs/enumerations/OverflowDirection.md +29 -0
  43. package/.docs/enumerations/SelectionMode.md +27 -0
  44. package/.docs/enumerations/SortMode.md +27 -0
  45. package/.docs/enumerations/UserInterface.md +177 -0
  46. package/.docs/functions/defaultDataLoader.md +25 -0
  47. package/.docs/{modules.md → globals.md} +27 -36
  48. package/.docs/interfaces/ChildDescriptor.md +12 -16
  49. package/.docs/interfaces/ChildLink.md +9 -12
  50. package/.docs/interfaces/DUActionInterceptor.md +10 -14
  51. package/.docs/interfaces/ExecutionContext.md +17 -32
  52. package/.docs/interfaces/FieldDescriptor.md +52 -66
  53. package/.docs/interfaces/Filter.md +13 -17
  54. package/.docs/interfaces/IElementIDInfo.md +11 -14
  55. package/.docs/interfaces/ILoadResult.md +11 -16
  56. package/.docs/interfaces/IRepository.md +106 -93
  57. package/.docs/interfaces/IRepositoryIndex.md +23 -30
  58. package/.docs/interfaces/LoadDataRequest.md +36 -45
  59. package/.docs/interfaces/LoadDataResponse.md +11 -14
  60. package/.docs/interfaces/OverFlowWatcherParams.md +67 -0
  61. package/.docs/interfaces/PageRequest.md +16 -20
  62. package/.docs/interfaces/PaginationInfo.md +24 -31
  63. package/.docs/interfaces/PromiseSyncCallback.md +13 -17
  64. package/.docs/interfaces/QuickFilter.md +17 -21
  65. package/.docs/interfaces/Record.md +26 -33
  66. package/.docs/interfaces/SavedRecord.md +33 -41
  67. package/.docs/interfaces/Sort.md +12 -16
  68. package/.docs/interfaces/SortingProvider.md +10 -13
  69. package/.docs/interfaces/UnitMetadata.md +16 -21
  70. package/.docs/interfaces/WaitingChange.md +16 -20
  71. package/.docs/namespaces/MaskFormatter/README.md +17 -0
  72. package/.docs/namespaces/MaskFormatter/type-aliases/MaskCharacter.md +13 -0
  73. package/.docs/namespaces/MaskFormatter/variables/MaskCharacter.md +13 -0
  74. package/.docs/type-aliases/DataUnitEventOptions.md +17 -0
  75. package/.docs/type-aliases/OnOverflowCallBack.md +25 -0
  76. package/.docs/variables/OVERFLOWED_CLASS_NAME.md +13 -0
  77. package/dist/dataunit/DataUnit.d.ts +67 -6
  78. package/dist/dataunit/DataUnit.js +151 -32
  79. package/dist/dataunit/DataUnit.js.map +1 -1
  80. package/dist/dataunit/DataUnitHelper.js +6 -5
  81. package/dist/dataunit/DataUnitHelper.js.map +1 -1
  82. package/dist/dataunit/formatting/PrettyFormatter.js +8 -6
  83. package/dist/dataunit/formatting/PrettyFormatter.js.map +1 -1
  84. package/dist/dataunit/loading/LoadDataRequest.d.ts +1 -1
  85. package/dist/dataunit/metadata/DataType.js +13 -1
  86. package/dist/dataunit/metadata/DataType.js.map +1 -1
  87. package/dist/dataunit/state/action/DataUnitAction.d.ts +5 -1
  88. package/dist/dataunit/state/action/DataUnitAction.js +4 -0
  89. package/dist/dataunit/state/action/DataUnitAction.js.map +1 -1
  90. package/dist/dataunit/state/slice/ChangesSlice.js +12 -11
  91. package/dist/dataunit/state/slice/ChangesSlice.js.map +1 -1
  92. package/dist/dataunit/state/slice/InvalidFieldsSlice.js +2 -0
  93. package/dist/dataunit/state/slice/InvalidFieldsSlice.js.map +1 -1
  94. package/dist/dataunit/state/slice/LoadingProperties.d.ts +9 -0
  95. package/dist/dataunit/state/slice/LoadingProperties.js +31 -0
  96. package/dist/dataunit/state/slice/LoadingProperties.js.map +1 -0
  97. package/dist/dataunit/state/slice/RecordsSlice.js +1 -1
  98. package/dist/dataunit/state/slice/RecordsSlice.js.map +1 -1
  99. package/dist/dataunit/state/slice/SelectionSlice.js +4 -4
  100. package/dist/dataunit/state/slice/SelectionSlice.js.map +1 -1
  101. package/dist/exceptions/ServiceCanceledException.d.ts +14 -0
  102. package/dist/exceptions/ServiceCanceledException.js +13 -0
  103. package/dist/exceptions/ServiceCanceledException.js.map +1 -0
  104. package/dist/index.d.ts +4 -2
  105. package/dist/index.js +3 -1
  106. package/dist/index.js.map +1 -1
  107. package/dist/repository/IRepository.d.ts +6 -0
  108. package/dist/repository/indexeddb/IDBRepository.d.ts +1 -0
  109. package/dist/repository/indexeddb/IDBRepository.js +3 -0
  110. package/dist/repository/indexeddb/IDBRepository.js.map +1 -1
  111. package/dist/utils/DateUtils.js +3 -0
  112. package/dist/utils/DateUtils.js.map +1 -1
  113. package/dist/utils/ElementUtils.d.ts +2 -0
  114. package/dist/utils/ElementUtils.js +9 -0
  115. package/dist/utils/ElementUtils.js.map +1 -0
  116. package/dist/utils/MaskFormatter.d.ts +2 -1
  117. package/dist/utils/MaskFormatter.js +5 -1
  118. package/dist/utils/MaskFormatter.js.map +1 -1
  119. package/dist/utils/ObjectUtils.d.ts +38 -0
  120. package/dist/utils/ObjectUtils.js +51 -0
  121. package/dist/utils/ObjectUtils.js.map +1 -1
  122. package/dist/utils/OnboardingUtils.js +1 -1
  123. package/dist/utils/OnboardingUtils.js.map +1 -1
  124. package/dist/utils/OverflowWatcher/index.d.ts +59 -0
  125. package/dist/utils/OverflowWatcher/index.js +188 -0
  126. package/dist/utils/OverflowWatcher/index.js.map +1 -0
  127. package/dist/utils/OverflowWatcher/types/overflow-callback.d.ts +6 -0
  128. package/dist/utils/OverflowWatcher/types/overflow-callback.js +2 -0
  129. package/dist/utils/OverflowWatcher/types/overflow-callback.js.map +1 -0
  130. package/dist/utils/OverflowWatcher/types/overflow-direction.d.ts +7 -0
  131. package/dist/utils/OverflowWatcher/types/overflow-direction.js +9 -0
  132. package/dist/utils/OverflowWatcher/types/overflow-direction.js.map +1 -0
  133. package/dist/utils/SortingUtils.d.ts +9 -0
  134. package/dist/utils/SortingUtils.js +24 -0
  135. package/dist/utils/SortingUtils.js.map +1 -0
  136. package/jest.config.ts +3 -1
  137. package/package.json +12 -4
  138. package/reports/test-report.xml +175 -0
  139. package/setupTests.js +7 -0
  140. package/sonar-project.properties +10 -0
  141. package/src/dataunit/DataUnit.ts +179 -46
  142. package/src/dataunit/DataUnitHelper.ts +6 -5
  143. package/src/dataunit/formatting/PrettyFormatter.ts +7 -6
  144. package/src/dataunit/loading/LoadDataRequest.ts +1 -1
  145. package/src/dataunit/metadata/DataType.ts +13 -1
  146. package/src/dataunit/state/action/DataUnitAction.ts +5 -1
  147. package/src/dataunit/state/slice/ChangesSlice.ts +15 -14
  148. package/src/dataunit/state/slice/InvalidFieldsSlice.ts +2 -0
  149. package/src/dataunit/state/slice/LoadingProperties.ts +37 -0
  150. package/src/dataunit/state/slice/RecordsSlice.ts +1 -1
  151. package/src/dataunit/state/slice/SelectionSlice.ts +4 -4
  152. package/src/dataunit/state/slice/test/RecordsSlice.spec.ts +45 -0
  153. package/src/dataunit/test/DataUnit.spec.ts +44 -0
  154. package/src/exceptions/ServiceCanceledException.ts +25 -0
  155. package/src/index.ts +10 -1
  156. package/src/repository/IRepository.ts +7 -0
  157. package/src/repository/indexeddb/IDBRepository.ts +4 -0
  158. package/src/utils/DateUtils.ts +3 -0
  159. package/src/utils/ElementUtils.ts +10 -0
  160. package/src/utils/MaskFormatter.ts +5 -1
  161. package/src/utils/ObjectUtils.ts +56 -0
  162. package/src/utils/OnboardingUtils.ts +1 -1
  163. package/src/utils/OverflowWatcher/index.ts +243 -0
  164. package/src/utils/OverflowWatcher/types/overflow-callback.ts +6 -0
  165. package/src/utils/OverflowWatcher/types/overflow-direction.ts +7 -0
  166. package/src/utils/SortingUtils.ts +30 -0
  167. package/src/utils/test/objectUtils.spec.ts +109 -0
  168. package/test/dataunit/formatting/PrettyFormatter.spec.ts +177 -0
  169. package/test/util/ElementUtils.spec.ts +34 -0
  170. package/test/util/OverflowWatcher.spec.ts +152 -0
  171. package/.docs/.nojekyll +0 -1
  172. package/.docs/enums/Action.md +0 -305
  173. package/.docs/enums/ChangeOperation.md +0 -52
  174. package/.docs/enums/DataType.md +0 -63
  175. package/.docs/enums/DependencyType.md +0 -41
  176. package/.docs/enums/SelectionMode.md +0 -30
  177. package/.docs/enums/SortMode.md +0 -30
  178. package/.docs/enums/UserInterface.md +0 -195
  179. package/.docs/modules/MaskFormatter.md +0 -37
@@ -25,34 +25,41 @@ import { getFormattedValue } from "./formatting/PrettyFormatter.js";
25
25
  import { v4 as uuid } from "uuid";
26
26
  import { DataUnitStorage } from "./DataUnitStorage.js";
27
27
  import { getInvalidFieldMessage, InvalidFieldsReducer } from "./state/slice/InvalidFieldsSlice.js";
28
+ import { getLoadingProperties, LoadingPropertiesReducer } from "./state/slice/LoadingProperties.js";
29
+ import SortingUtils from "../utils/SortingUtils.js";
30
+ import ServiceCanceledException from "../exceptions/ServiceCanceledException.js";
28
31
 
29
32
  /***
30
33
  * `DataUnit`: Atua como uma camada de abstração entre o back-end e a interface do usuário.
31
34
  */
32
35
  export default class DataUnit {
33
-
36
+
34
37
  public static CHANGING_PAGE_LOADING_SOURCE = "CHANGING_PAGE_LOADING_SOURCE";
38
+ public static ALL_RECORDS_SELECTION_SOURCE = "ALL_RECORDS_SELECTION_SOURCE";
35
39
  public static DEFAULT_DATAUNIT_NAME = "dataunit";
36
40
 
37
41
  private _uuid: string;
38
42
  private _name: string;
39
- private _observers: Array<(action: DataUnitAction) => void>;
43
+ private _observers: Array<(action: DataUnitAction, options?: DataUnitEventOptions) => void>;
40
44
  private _sortingProvider?: SortingProvider;
41
45
  private _filterProviders: Map<string, FilterProvider>;
42
46
  private _stateManager: StateManager;
43
- private _interceptors: Array<DUActionInterceptor>;
47
+ private _interceptors: Map<string, DUActionInterceptor>;
44
48
  private _pageSize: number;
45
49
  private _childByName = new Map<string, DataUnit>();
46
50
  private _parentDataUnit: DataUnit | undefined;
47
51
  private _loadingLockers: Promise<void>[];
48
52
  private _savingLockers: Promise<any>[] = [];
49
53
  private _defaultSorting: Array<Sort>;
54
+ private _allowReleaseCallbacks: boolean;
55
+ private _waitingToReload: boolean = false;
50
56
 
51
57
  public metadataLoader?: (dataUnit: DataUnit) => Promise<UnitMetadata>;
52
58
  public dataLoader?: (dataUnit: DataUnit, request: LoadDataRequest) => Promise<LoadDataResponse>;
53
59
  public saveLoader?: (dataUnit: DataUnit, changes: Array<Change>) => Promise<Array<SavedRecord>>;
54
60
  public removeLoader?: (dataUnit: DataUnit, recordIds: Array<string>) => Promise<Array<string>>;
55
61
  public recordLoader?: (dataUnit: DataUnit, recordIds: Array<string>) => Promise<Array<Record>>;
62
+ public allRecordsLoader?: (dataUnit: DataUnit) => Array<Record> | undefined;
56
63
 
57
64
  constructor(name: string = DataUnit.DEFAULT_DATAUNIT_NAME, parentDataUnit?: DataUnit) {
58
65
  this._uuid = uuid()
@@ -61,6 +68,7 @@ export default class DataUnit {
61
68
  this._stateManager = new StateManager(
62
69
  [
63
70
  HistReducer,
71
+ LoadingPropertiesReducer,
64
72
  UnitMetadataReducer,
65
73
  LoadingControlReducer,
66
74
  RecordsReducer,
@@ -77,7 +85,8 @@ export default class DataUnit {
77
85
  this._filterProviders = new Map<string, FilterProvider>();
78
86
  this._sortingProvider = undefined;
79
87
  this._defaultSorting = [];
80
- this._interceptors = [];
88
+ this._allowReleaseCallbacks = true;
89
+ this._interceptors = new Map();
81
90
  this._parentDataUnit = parentDataUnit;
82
91
  this._parentDataUnit?.subscribe(this.onDataUnitParentEvent);
83
92
  this._loadingLockers = [];
@@ -108,17 +117,55 @@ export default class DataUnit {
108
117
  * - Sorting Providers
109
118
  */
110
119
  public releaseCallbacks(){
120
+ if(!this._allowReleaseCallbacks) return;
121
+
111
122
  this._observers = [];
112
123
  this._filterProviders = new Map<string, FilterProvider>();
113
124
  this._sortingProvider = undefined;
114
- this._interceptors = [];
125
+ this._interceptors = new Map();
115
126
  }
116
127
 
128
+ /**
129
+ * Adiciona uma propriedade transacional que será envida aos
130
+ * loaders (dataLoader, saveLoader, removeLoader e recordLoader) na chamada.
131
+ * Essas propriedades serão limpas ao final da execução de cada método.
132
+ *
133
+ * @param name - Nome da propriedade
134
+ * @param value - Valor da propriedade
135
+ *
136
+ */
137
+ public addGlobalLoaderProp(name: string, value: string):void{
138
+ this.dispatchAction(Action.LOADING_PROPERTY_ADDED, {[name]: value});
139
+ }
140
+
141
+ /**
142
+ * Retorna as propriedades transacionais adicionados anteriores à chamada.
143
+ *
144
+ * @returns - Todas as propriedades desde o final do último loader.
145
+ */
146
+ public getGlobalLoaderProps(): Map<string, string>{
147
+ return getLoadingProperties(this._stateManager) || new Map();
148
+ }
117
149
 
118
150
  public get dataUnitId(): string{
119
151
  return this._uuid;
120
152
  }
121
153
 
154
+ /**
155
+ * Retorna se o dataUnit está com recarregamento pendente.
156
+ */
157
+ public isWaitingToReload(): boolean {
158
+ return this._waitingToReload;
159
+ }
160
+
161
+ /**
162
+ * Define se o dataUnit tem um recarregamento pendente.
163
+ * @param isWaiting
164
+ */
165
+ public setWaitingToReload(isWaiting: boolean){
166
+ this._waitingToReload = isWaiting;
167
+ }
168
+
122
169
  /**
123
170
  *
124
171
  * Obtém o nome de identificação do DataUnit (geralmente em formato de URI - Uniform Resource Identifier).
@@ -157,6 +204,8 @@ export default class DataUnit {
157
204
  case Action.NEXT_SELECTED:
158
205
  case Action.PREVIOUS_SELECTED:
159
206
  case Action.DATA_LOADED:
207
+ case Action.RECORDS_ADDED:
208
+ case Action.EDITION_CANCELED:
160
209
  this.clearDataUnit();
161
210
  const selectedRecord = this._parentDataUnit?.getSelectedRecord();
162
211
  if(selectedRecord != undefined && !this.isNewRecord(selectedRecord.__record__id__)){
@@ -215,22 +264,24 @@ export default class DataUnit {
215
264
  if (await this.dispatchAction(Action.LOADING_DATA, request, executionCtx)) {
216
265
  if (this.dataLoader) {
217
266
  this.dataLoader(this, request).then(
218
- response => {
219
- this.dispatchAction(
267
+ async response => {
268
+ await this.dispatchAction(
220
269
  Action.DATA_LOADED,
221
- {...response, keepSelection: request.keepSelection, filters: request.filters},
270
+ {...response, keepSelection: request.keepSelection, filters: request.filters, selectFirstRecord},
222
271
  executionCtx
223
272
  );
224
273
 
274
+ await this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
275
+
225
276
  if(selectFirstRecord){
226
277
  this.requestSelectFirst(executionCtx);
227
278
  }
228
-
229
279
  resolve(response);
230
280
  }
231
281
  ).catch(error => {
232
282
  console.error(error);
233
283
  const {errorCode} = error;
284
+ this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
234
285
  fail(new ErrorException("Erro ao carregar registros", error, errorCode))
235
286
  });
236
287
  }
@@ -292,13 +343,16 @@ export default class DataUnit {
292
343
 
293
344
  await this.processLoadingLockers();
294
345
 
295
- if (this._parentDataUnit && !this._parentDataUnit.getSelectedRecord()) {
346
+ if (this._parentDataUnit) {
347
+ const parentRecord = this._parentDataUnit.getSelectedRecord();
348
+ if(parentRecord == undefined || this._parentDataUnit.isNewRecord(parentRecord.__record__id__)){
296
349
  if(this.records){
297
350
  this.clearDataUnit();
298
351
  }
299
352
  return Promise.resolve({
300
353
  records: []
301
354
  });
355
+ }
302
356
  }
303
357
 
304
358
  const loadDataRequest = this.getLoadDataRequest(quickFilter, source);
@@ -311,7 +365,7 @@ export default class DataUnit {
311
365
  *
312
366
  * @param page - Número da página desejada.
313
367
  * @param executionCtx - Contexto de execução do carregamento dos registros do DataUnit.
314
- *
368
+ *
315
369
  * @returns - Registros da página desejada.
316
370
  *
317
371
  */
@@ -431,6 +485,7 @@ export default class DataUnit {
431
485
  const changes: Array<Change> = this.getAllChangesToSave();
432
486
 
433
487
  this.saveLoader(this, changes).then((records) => {
488
+ this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
434
489
  const recordsByDataUnit = this.getRecordsByDataUnit(records);
435
490
 
436
491
  const dispatchPromisses = [];
@@ -445,9 +500,17 @@ export default class DataUnit {
445
500
  Promise.all(dispatchPromisses).then(() => resolve());
446
501
  }).catch(cause => {
447
502
  const {errorCode} = cause;
448
- fail(new ErrorException("Erro ao salvar alterações", cause, errorCode));
503
+ this.dispatchAction(Action.SAVING_ERROR);
504
+ this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
505
+ if(cause instanceof ServiceCanceledException){
506
+ console.debug("Service canceled: " + cause.message)
507
+ resolve()
508
+ } else{
509
+ fail(new ErrorException("Erro ao salvar alterações", cause, errorCode))
510
+ }
449
511
  });
450
512
  } else {
513
+ this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
451
514
  resolve();
452
515
  }
453
516
  });
@@ -513,8 +576,8 @@ export default class DataUnit {
513
576
  if(selection.isAllRecords()){
514
577
  throw new Error("Exclusão remota não implementada.");
515
578
  }
516
- const records = selection?.records || [];
517
- const recordIds = selection?.recordIds || [];
579
+ const records = selection?.records as Array<Record> || [];
580
+ const recordIds = selection?.recordIds as Array<string> || [];
518
581
  return this.removeRecords(recordIds, records, buffered, undefined, silent);
519
582
  }
520
583
  return Promise.resolve([]);
@@ -536,6 +599,7 @@ export default class DataUnit {
536
599
  public async removeRecords(recordIds: Array<string>, cachedRecords: Array<Record>, buffered: boolean = false, executionCtx?: ExecutionContext, silent: boolean = false): Promise<Array<string>> {
537
600
  if (recordIds) {
538
601
  if (buffered || !this.removeLoader) {
602
+ this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
539
603
  this.dispatchAction(Action.RECORDS_REMOVED, { records: recordIds, cachedRecords, buffered: true }, executionCtx);
540
604
  } else {
541
605
  if (await this.dispatchAction(Action.REMOVING_RECORDS, {silent}, executionCtx)) {
@@ -547,15 +611,18 @@ export default class DataUnit {
547
611
  const currentRecordsKeys = Array.from(getCurrentRecords(this._stateManager).keys());
548
612
  const removedIndex: Array<number> = recordIds
549
613
  .map(id => currentRecordsKeys.indexOf(id))
550
- .filter(index => index > -1);
614
+ .filter(index => index > -1)
615
+ .sort((a, b) => a - b);
551
616
 
552
617
  const nextIndex = Math.min(removedIndex.slice(-1)[0] + 1, currentRecordsKeys.length);
553
- const selectionAfterRemove = [currentRecordsKeys[nextIndex]];
618
+ const selectionAfterRemove = currentRecordsKeys[nextIndex] ? [currentRecordsKeys[nextIndex]] : [];
554
619
 
555
620
  this.dispatchAction(Action.RECORDS_REMOVED, { records: removedIds, cachedRecords, removedIndex, buffered: false, selectionAfterRemove }, executionCtx);
621
+ this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
556
622
  resolve(removedIds);
557
623
  }
558
624
  ).catch(error => {
625
+ this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
559
626
  const {errorCode} = error;
560
627
  fail(new ErrorException("Erro ao remover registros", error, errorCode))
561
628
  });
@@ -612,7 +679,6 @@ export default class DataUnit {
612
679
  *
613
680
  */
614
681
  public getFormattedValue(fieldName: string, value?: any): string {
615
-
616
682
  const descriptor = this.getField(fieldName);
617
683
  if (value == undefined) {
618
684
  value = this.getFieldValue(fieldName);
@@ -635,7 +701,7 @@ export default class DataUnit {
635
701
  *
636
702
  */
637
703
  public addInterceptor(interceptor: DUActionInterceptor): void {
638
- this._interceptors.push(interceptor);
704
+ this._interceptors.set(interceptor.interceptAction.toString(), interceptor);
639
705
  }
640
706
 
641
707
  /**
@@ -646,7 +712,7 @@ export default class DataUnit {
646
712
  *
647
713
  */
648
714
  public removeInterceptor(interceptor: DUActionInterceptor) {
649
- this._interceptors = this._interceptors.filter(i => i !== interceptor);
715
+ this._interceptors.delete(interceptor.interceptAction.toString())
650
716
  }
651
717
 
652
718
  /**
@@ -848,8 +914,12 @@ export default class DataUnit {
848
914
  public copySelected(executionCtx?: ExecutionContext): void {
849
915
  const selectionInfo = this.getSelectionInfo();
850
916
  if (selectionInfo) {
851
- const selectedRecords = selectionInfo.records;
917
+ if(selectionInfo.isAllRecords()){
918
+ throw new Error("Erro interno: Impossível copiar os registros selecionados pois a seleção atual é virtual.");
919
+ }
920
+ const selectedRecords = selectionInfo.records as Array<Record>;
852
921
  if(selectedRecords){
922
+
853
923
  this.dispatchAction(Action.RECORDS_COPIED, prepareCopiedRecord(this._stateManager, selectedRecords, this.getParentRecordId()), executionCtx);
854
924
  }
855
925
  }
@@ -918,13 +988,16 @@ export default class DataUnit {
918
988
  * @returns - Promise que será resolvida quando o novo valor for persistido no state.
919
989
  *
920
990
  */
921
- public async setFieldValue(fieldName: string, newValue: any, records?: Array<string>): Promise<boolean> {
922
-
991
+ public async setFieldValue(fieldName: string, newValue: any, records?: Array<string>, options?:DataUnitEventOptions): Promise<boolean> {
923
992
  if(!this.hasNewRecord() && !this.getSelectedRecord()) await this.addRecord();
924
-
993
+
925
994
  const typedValue = this.validateAndTypeValue(fieldName, newValue);
926
995
  const currentValue = this.getFieldValue(fieldName);
927
-
996
+
997
+ if(!(newValue instanceof Promise) && ObjectUtils.hasEquivalentProps(currentValue, typedValue)){
998
+ return Promise.resolve(false);
999
+ }
1000
+
928
1001
  if(newValue instanceof Promise){
929
1002
  const promise:Promise<boolean> = new Promise(accept => {
930
1003
  newValue.then(resolvedValue => {
@@ -937,7 +1010,7 @@ export default class DataUnit {
937
1010
  }
938
1011
 
939
1012
  if (currentValue !== typedValue) {
940
- const promise = this.dispatchAction(Action.DATA_CHANGED, { [fieldName]: typedValue, records }, undefined);
1013
+ const promise = this.dispatchAction(Action.DATA_CHANGED, { [fieldName]: typedValue, records }, undefined, options);
941
1014
  this._savingLockers.push(promise);
942
1015
  return promise;
943
1016
  }
@@ -958,6 +1031,18 @@ export default class DataUnit {
958
1031
  this.dispatchAction(Action.FIELD_INVALIDATED, { fieldName, message, recordId }, undefined);
959
1032
  }
960
1033
 
1034
+ /**
1035
+ *
1036
+ * Cancela o saving exibindo os campos invalidos.
1037
+ *
1038
+ * @param filds - Lista dos campos
1039
+ * @param recordId - Indica qual registro está com os campos inválido.
1040
+ *
1041
+ */
1042
+ public savingCanceled(fields: Array<{name: string, message: string}>, recordId: string): void {
1043
+ this.dispatchAction(Action.SAVING_CANCELED, { fields, recordId }, undefined);
1044
+ }
1045
+
961
1046
  /**
962
1047
  *
963
1048
  * Limpa campos inválidos.
@@ -1065,7 +1150,7 @@ export default class DataUnit {
1065
1150
  public setSelection(selection: Array<string> | SelectionMode.ALL_RECORDS, executionCtx?: ExecutionContext): Promise<SelectionInfo> {
1066
1151
  return new Promise(resolve => {
1067
1152
  this.dispatchAction(Action.SELECTION_CHANGED, { type: "id", selection }, executionCtx)
1068
- .then(()=>resolve(getSelectionInfo(this._stateManager)));
1153
+ .then(()=>resolve(this.getSelectionInfo()));
1069
1154
  });
1070
1155
  }
1071
1156
 
@@ -1122,8 +1207,16 @@ export default class DataUnit {
1122
1207
  * @returns - Objeto com informações como registros selecionados e seleção por critério.
1123
1208
  *
1124
1209
  **/
1125
- public getSelectionInfo(): SelectionInfo | undefined {
1126
- return getSelectionInfo(this._stateManager)
1210
+ public getSelectionInfo(): SelectionInfo{
1211
+ const selectionInfo: SelectionInfo = getSelectionInfo(this._stateManager);
1212
+ selectionInfo.getAllRecords = () => this.allRecordsLoader?.(this);
1213
+
1214
+ if (selectionInfo.sort != undefined && selectionInfo.sort.length > 0) {
1215
+ const sortingFunction = SortingUtils.getSortingFunction(this, selectionInfo.sort)
1216
+ selectionInfo.records?.sort(sortingFunction)
1217
+ }
1218
+
1219
+ return selectionInfo;
1127
1220
  }
1128
1221
 
1129
1222
  /**
@@ -1137,6 +1230,15 @@ export default class DataUnit {
1137
1230
  return getSelectedRecord(this._stateManager);
1138
1231
  }
1139
1232
 
1233
+ /**
1234
+ * Retorna o DataUnit pai
1235
+ *
1236
+ * @returns DataUnit pai ou undefined
1237
+ */
1238
+ public getParentDataUnit(): DataUnit | undefined {
1239
+ return this._parentDataUnit;
1240
+ }
1241
+
1140
1242
  /**
1141
1243
  *
1142
1244
  * Limpa todos os registros do DataUnit
@@ -1224,14 +1326,28 @@ export default class DataUnit {
1224
1326
  /**
1225
1327
  *
1226
1328
  * Retorna se existe algum tipo de alteração pendente.
1227
- *
1329
+ *
1330
+ * @param ignoreChildren: Define se deverá ignorar alterações pendentes no DataUnit filho.
1228
1331
  * @returns Verdadeiro se existir alterações pendentes.
1229
1332
  *
1230
1333
  */
1231
- public isDirty(): boolean {
1334
+ public isDirty(ignoreChildren?: boolean): boolean {
1335
+ if(ignoreChildren) return isDirty(this._stateManager);
1336
+
1232
1337
  return isDirty(this._stateManager) || this.childrenIsDirty();
1233
1338
  }
1234
1339
 
1340
+ /**
1341
+ *
1342
+ * Retorna se existe alterações pendentes no DataUnit pai.
1343
+ *
1344
+ * @returns Verdadeiro se existir alterações pendentes e Falso caso não exista alterações ou não exista DataUnit pai.
1345
+ *
1346
+ */
1347
+ public isParentDirty(): boolean {
1348
+ return this._parentDataUnit ? this._parentDataUnit.isDirty(true) : false;
1349
+ }
1350
+
1235
1351
  /**
1236
1352
  *
1237
1353
  * Retorna se existe algum DataUnit detail com alterações pendentes.
@@ -1404,17 +1520,17 @@ export default class DataUnit {
1404
1520
  * @returns - Verdadeiro se ação iniciada.
1405
1521
  *
1406
1522
  */
1407
- private async dispatchAction(actionType: Action, payload?: any, executionCtx?: ExecutionContext): Promise<boolean> {
1523
+ private async dispatchAction(actionType: Action, payload?: any, executionCtx?: ExecutionContext, options?:DataUnitEventOptions): Promise<boolean> {
1408
1524
  return new Promise(async resolve => {
1409
1525
  let action = new DataUnitAction(actionType, payload);
1410
1526
  if (executionCtx && executionCtx.before) {
1411
1527
  action = executionCtx.before(action);
1412
1528
  }
1413
- if (action && this._interceptors && this._interceptors.length > 0) {
1529
+ if (action && this._interceptors && this._interceptors.size > 0) {
1414
1530
  action = await this.intercept(action, this._interceptors.values());
1415
1531
  }
1416
1532
  if (action) {
1417
- this.doDispatchAction(action);
1533
+ this.doDispatchAction(action, options);
1418
1534
  if (executionCtx && executionCtx.after) {
1419
1535
  executionCtx.after(action)
1420
1536
  }
@@ -1452,7 +1568,7 @@ export default class DataUnit {
1452
1568
  * @param action - Ações em execução no DataUnit.
1453
1569
  *
1454
1570
  */
1455
- private doDispatchAction(action: DataUnitAction): void {
1571
+ private doDispatchAction(action: DataUnitAction, options:DataUnitEventOptions = {}): void {
1456
1572
  this._stateManager.process(action);
1457
1573
  this?._parentDataUnit?.dispatchAction(Action.CHILD_CHANGED, { srcAction: action, srcDataUnit: this });
1458
1574
  this._observers.forEach(f => {
@@ -1461,7 +1577,7 @@ export default class DataUnit {
1461
1577
  should be continued
1462
1578
  */
1463
1579
  try {
1464
- f(action);
1580
+ f(action, options);
1465
1581
  } catch (e) {
1466
1582
  console.warn("[DataUnit] error while call observer", e);
1467
1583
  }
@@ -1500,7 +1616,7 @@ export default class DataUnit {
1500
1616
  * @param observer - Função que recebe como parâmetro as ações que serão monitoradas.
1501
1617
  *
1502
1618
  */
1503
- public subscribe(observer: (action: DataUnitAction) => void) {
1619
+ public subscribe(observer: (action: DataUnitAction, options?:DataUnitEventOptions) => void | Promise<void>) {
1504
1620
  this._observers.push(observer);
1505
1621
  }
1506
1622
 
@@ -1527,12 +1643,16 @@ export default class DataUnit {
1527
1643
  const selection = getSelection(this._stateManager);
1528
1644
  this.dispatchAction(Action.LOADING_RECORD, selection);
1529
1645
 
1530
- if(!this.dataLoader) return;
1531
- if(!this.recordLoader) return;
1646
+ if(!this.recordLoader || !this.dataLoader) {
1647
+ this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
1648
+ return;
1649
+ }
1532
1650
 
1533
1651
  this.recordLoader(this, selection).then(response => {
1534
1652
  this.dispatchAction(Action.RECORD_LOADED, response)
1653
+ this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
1535
1654
  }).catch(cause => {
1655
+ this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
1536
1656
  const {errorCode} = cause;
1537
1657
  fail(new ErrorException("Erro ao recarregar registro", cause, errorCode));
1538
1658
  });
@@ -1671,7 +1791,7 @@ export default class DataUnit {
1671
1791
  }
1672
1792
 
1673
1793
  if (selection) {
1674
- return selection.records;
1794
+ return selection.records as Array<Record>;
1675
1795
  }
1676
1796
  }
1677
1797
 
@@ -1689,12 +1809,15 @@ export default class DataUnit {
1689
1809
  public getSelection(): Array<string> {
1690
1810
  console.warn("DataUnit: O método `getSelection` foi descontinuado. Use o método `getSelectionInfo`.");
1691
1811
  const selection = this.getSelectionInfo();
1812
+ if(selection == undefined){
1813
+ return [];
1814
+ }
1692
1815
 
1693
- if(selection != undefined && selection.isAllRecords()){
1816
+ if(selection.isAllRecords()){
1694
1817
  throw new Error("Erro interno: Impossível retornar os registros selecionados. A seleção atual é virtual. Use o método `getSelectionInfo`.");
1695
1818
  }
1696
1819
 
1697
- return selection?.recordIds || [];
1820
+ return selection?.recordIds as Array<string>;
1698
1821
  }
1699
1822
 
1700
1823
  /**
@@ -1730,6 +1853,10 @@ export default class DataUnit {
1730
1853
  return loadingLockerResolver || Promise.resolve;
1731
1854
  }
1732
1855
 
1856
+ public set allowReleaseCallbacks(allow: boolean){
1857
+ this._allowReleaseCallbacks = allow;
1858
+ }
1859
+
1733
1860
  private async processLoadingLockers(){
1734
1861
  if(this._loadingLockers.length) {
1735
1862
  await Promise.all(this._loadingLockers);
@@ -1871,12 +1998,13 @@ export enum SelectionMode{
1871
1998
 
1872
1999
  export class SelectionInfo{
1873
2000
 
1874
- private _records: Array<Record>;
1875
2001
  public mode: SelectionMode;
1876
- private _total?: number;
1877
2002
  public filters?: Array<Filter>;
1878
2003
  public sort?: Array<Sort>;
1879
-
2004
+ public getAllRecords?: () => Array<Record> | undefined;
2005
+ private _records: Array<Record>;
2006
+ private _total?: number;
2007
+
1880
2008
  constructor(records: Array<Record>, mode: SelectionMode = SelectionMode.SOME_RECORDS, total?:number, filters?: Array<Filter>, sort?: Array<Sort>){
1881
2009
  this._records = records;
1882
2010
  this._total = total;
@@ -1887,7 +2015,10 @@ export class SelectionInfo{
1887
2015
 
1888
2016
  public get records(): Array<Record> | undefined{
1889
2017
  if(this.isAllRecords()){
1890
- throw new Error("Erro interno: [ALL_RECORDS] - Impossível retornar os registros selecionados numa seleção virtual.")
2018
+ if(this.getAllRecords != undefined){
2019
+ return this.getAllRecords();
2020
+ }
2021
+ throw new Error("Erro interno: Impossível retornar os registros selecionados numa seleção virtual.");
1891
2022
  }
1892
2023
  return this._records;
1893
2024
  }
@@ -1906,7 +2037,7 @@ export class SelectionInfo{
1906
2037
  if(this.isAllRecords()){
1907
2038
  return this._total || 0;
1908
2039
  }
1909
- return this.records == undefined ? 0: this.records.length;
2040
+ return this.records == undefined ? 0 : (this.records as Array<Record>).length;
1910
2041
  }
1911
2042
 
1912
2043
  public isAllRecords(): boolean{
@@ -1917,3 +2048,5 @@ export class SelectionInfo{
1917
2048
  return this.length === 0;
1918
2049
  }
1919
2050
  }
2051
+
2052
+ export type DataUnitEventOptions = {[key:string]: any};
@@ -31,17 +31,18 @@ export function defaultDataLoader(dataUnit: DataUnit, request: LoadDataRequest,
31
31
  }
32
32
 
33
33
  function buildPaginationInfo({ offset, limit }: LoadDataRequest, records: Array<Record>): PaginationInfo | undefined {
34
- if (offset === undefined || limit === undefined) {
34
+ if (offset === undefined || limit === undefined || records === undefined) {
35
35
  return undefined;
36
36
  }
37
37
 
38
- const lastRecord = Math.min(offset + limit, records.length);
38
+ const total = records?.length || 0;
39
+ const lastRecord = Math.min(offset + limit, total);
39
40
  return {
40
- currentPage: Math.ceil(offset / limit),
41
+ currentPage: limit === 0 ? 0 : Math.ceil(offset / limit),
41
42
  firstRecord: offset,
42
43
  lastRecord: lastRecord,
43
- total: records.length,
44
- hasMore: !!(records.length - lastRecord),
44
+ total: total,
45
+ hasMore: !!(total - lastRecord),
45
46
  };
46
47
  }
47
48
 
@@ -10,10 +10,10 @@ export const getFormattedValue = (value: any, descriptor?: FieldDescriptor) => {
10
10
  }
11
11
 
12
12
  if(descriptor?.dataType === DataType.OBJECT){
13
- if(Object.hasOwn(value, "value")){
13
+ if(value && Object.hasOwn(value, "value")){
14
14
  return getSearchFormat(value, descriptor);
15
15
  }
16
- return value == undefined ? "" : value.toString();
16
+ return !value ? "" : value.toString();
17
17
  }
18
18
 
19
19
  if(descriptor?.userInterface === UserInterface.OPTIONSELECTOR){
@@ -43,7 +43,7 @@ export const getFormattedValue = (value: any, descriptor?: FieldDescriptor) => {
43
43
  const mask = getMask(value, descriptor);
44
44
  if(mask != undefined){
45
45
  try{
46
- return new MaskFormatter(mask).format(value);
46
+ return new MaskFormatter(mask).format(value, true);
47
47
  } catch(error){
48
48
  console.warn(`Erro ao formatar valor: ${value}. Mascara: ${mask}. Erro: ${error}`);
49
49
  }
@@ -53,6 +53,7 @@ export const getFormattedValue = (value: any, descriptor?: FieldDescriptor) => {
53
53
  }
54
54
 
55
55
  const getNumberFormat = (value: any, descriptor: FieldDescriptor) => {
56
+ if(value === undefined || value === null) return "";
56
57
  if(descriptor.userInterface === UserInterface.INTEGERNUMBER){
57
58
  return value;
58
59
  }
@@ -84,7 +85,7 @@ const getOptionFormat = (value: any, descriptor: FieldDescriptor) => {
84
85
  }
85
86
  }
86
87
 
87
- if(typeof value === "object"){
88
+ if(value && typeof value === "object" ){
88
89
  value = value.value
89
90
  }
90
91
 
@@ -92,7 +93,7 @@ const getOptionFormat = (value: any, descriptor: FieldDescriptor) => {
92
93
  return options[value];
93
94
  }
94
95
 
95
- return value;
96
+ return value ?? "";
96
97
  }
97
98
 
98
99
 
@@ -103,7 +104,7 @@ const getMask = (value: string, descriptor: FieldDescriptor | undefined): string
103
104
  }
104
105
 
105
106
  const mask = descriptor.properties?.mask;
106
- if(mask == undefined){
107
+ if(mask == undefined || !value){
107
108
  return;
108
109
  }
109
110
 
@@ -4,7 +4,7 @@ import { Filter, Sort } from "../metadata/UnitMetadata.js";
4
4
  /** Atributos enviados na requisição de carregamento dos registros */
5
5
  export interface LoadDataRequest {
6
6
  /** De onde partiu o refresh. Por padrão a fonte não é identificada */
7
- source?: String;
7
+ source?: string;
8
8
 
9
9
  /** Indice inicial dos registros que será retornado */
10
10
  offset?: number;
@@ -67,7 +67,16 @@ export const getConvertedValue = (dataType: DataType, value: any): any => {
67
67
  case DataType.NUMBER:
68
68
  return value === "" || isNaN(Number(value)) ? null : Number(value);
69
69
  case DataType.OBJECT:
70
- return typeof value === "string" ? JSON.parse(value) : value;
70
+ //Caso de uso campo DataType do tipo STRING e UserInterface do tipo TEXT, que tem relacionamento (TGFPRO.GRUPOPIS)
71
+ if(typeof value === "string") {
72
+ try{
73
+ return JSON.parse(value);
74
+ }catch(e){
75
+ console.warn(`Erro ao fazer parse do valor ${value} para objeto, dataType: ${dataType}`);
76
+ }
77
+ }
78
+
79
+ return value;
71
80
  case DataType.BOOLEAN:
72
81
  if (typeof value === "string") {
73
82
  return Boolean(value === 'true');
@@ -110,6 +119,9 @@ export const toString = ( dataType: DataType|undefined, value: any): string => {
110
119
  } else if (dataType === DataType.DATE) {
111
120
  if (typeof value === "string") {
112
121
  value = DateUtils.strToDate(value);
122
+ if (value == undefined) {
123
+ return value;
124
+ }
113
125
  }
114
126
  return DateUtils.formatRfc3339(value as Date);
115
127
  } else {