@sankhyalabs/core 5.16.4 → 5.17.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 (56) hide show
  1. package/.docs/classes/Change.md +11 -11
  2. package/.docs/classes/DataUnit.md +185 -115
  3. package/.docs/classes/ObjectUtils.md +48 -0
  4. package/.docs/classes/OverflowWatcher.md +310 -46
  5. package/.docs/classes/SelectionInfo.md +11 -11
  6. package/.docs/enumerations/Action.md +32 -22
  7. package/.docs/enumerations/ChangeOperation.md +4 -4
  8. package/.docs/enumerations/SelectionMode.md +2 -2
  9. package/.docs/globals.md +6 -0
  10. package/.docs/interfaces/DUActionInterceptor.md +1 -1
  11. package/.docs/interfaces/OverFlowWatcherParams.md +67 -0
  12. package/.docs/interfaces/PageRequest.md +3 -3
  13. package/.docs/interfaces/QuickFilter.md +3 -3
  14. package/.docs/interfaces/Record.md +4 -4
  15. package/.docs/interfaces/SavedRecord.md +5 -5
  16. package/.docs/interfaces/WaitingChange.md +3 -3
  17. package/.docs/type-aliases/DataUnitEventOptions.md +17 -0
  18. package/.docs/variables/OVERFLOWED_CLASS_NAME.md +13 -0
  19. package/dist/dataunit/DataUnit.d.ts +23 -3
  20. package/dist/dataunit/DataUnit.js +51 -17
  21. package/dist/dataunit/DataUnit.js.map +1 -1
  22. package/dist/dataunit/formatting/PrettyFormatter.js +7 -5
  23. package/dist/dataunit/formatting/PrettyFormatter.js.map +1 -1
  24. package/dist/dataunit/state/action/DataUnitAction.d.ts +1 -0
  25. package/dist/dataunit/state/action/DataUnitAction.js +1 -0
  26. package/dist/dataunit/state/action/DataUnitAction.js.map +1 -1
  27. package/dist/dataunit/state/slice/SelectionSlice.js +2 -2
  28. package/dist/dataunit/state/slice/SelectionSlice.js.map +1 -1
  29. package/dist/index.d.ts +3 -3
  30. package/dist/index.js +2 -2
  31. package/dist/index.js.map +1 -1
  32. package/dist/utils/ElementUtils.d.ts +2 -0
  33. package/dist/utils/ElementUtils.js +9 -0
  34. package/dist/utils/ElementUtils.js.map +1 -0
  35. package/dist/utils/ObjectUtils.d.ts +14 -0
  36. package/dist/utils/ObjectUtils.js +18 -0
  37. package/dist/utils/ObjectUtils.js.map +1 -1
  38. package/dist/utils/OverflowWatcher/index.d.ts +35 -7
  39. package/dist/utils/OverflowWatcher/index.js +140 -59
  40. package/dist/utils/OverflowWatcher/index.js.map +1 -1
  41. package/jest.config.ts +2 -0
  42. package/package.json +3 -2
  43. package/reports/test-report.xml +151 -0
  44. package/setupTests.js +7 -0
  45. package/sonar-project.properties +6 -3
  46. package/src/dataunit/DataUnit.ts +57 -18
  47. package/src/dataunit/formatting/PrettyFormatter.ts +6 -5
  48. package/src/dataunit/state/action/DataUnitAction.ts +1 -0
  49. package/src/dataunit/state/slice/SelectionSlice.ts +2 -2
  50. package/src/index.ts +6 -3
  51. package/src/utils/ElementUtils.ts +10 -0
  52. package/src/utils/ObjectUtils.ts +20 -0
  53. package/src/utils/OverflowWatcher/index.ts +170 -78
  54. package/test/dataunit/formatting/PrettyFormatter.spec.ts +177 -0
  55. package/test/util/ElementUtils.spec.ts +34 -0
  56. package/test/util/OverflowWatcher.spec.ts +152 -118
@@ -37,7 +37,7 @@ export default class DataUnit {
37
37
 
38
38
  private _uuid: string;
39
39
  private _name: string;
40
- private _observers: Array<(action: DataUnitAction) => void>;
40
+ private _observers: Array<(action: DataUnitAction, options?:DataUnitEventOptions) => void>;
41
41
  private _sortingProvider?: SortingProvider;
42
42
  private _filterProviders: Map<string, FilterProvider>;
43
43
  private _stateManager: StateManager;
@@ -48,6 +48,7 @@ export default class DataUnit {
48
48
  private _loadingLockers: Promise<void>[];
49
49
  private _savingLockers: Promise<any>[] = [];
50
50
  private _defaultSorting: Array<Sort>;
51
+ private _allowReleaseCallbacks: boolean;
51
52
 
52
53
  public metadataLoader?: (dataUnit: DataUnit) => Promise<UnitMetadata>;
53
54
  public dataLoader?: (dataUnit: DataUnit, request: LoadDataRequest) => Promise<LoadDataResponse>;
@@ -79,6 +80,7 @@ export default class DataUnit {
79
80
  this._filterProviders = new Map<string, FilterProvider>();
80
81
  this._sortingProvider = undefined;
81
82
  this._defaultSorting = [];
83
+ this._allowReleaseCallbacks = true;
82
84
  this._interceptors = new Map();
83
85
  this._parentDataUnit = parentDataUnit;
84
86
  this._parentDataUnit?.subscribe(this.onDataUnitParentEvent);
@@ -110,6 +112,8 @@ export default class DataUnit {
110
112
  * - Sorting Providers
111
113
  */
112
114
  public releaseCallbacks(){
115
+ if(!this._allowReleaseCallbacks) return;
116
+
113
117
  this._observers = [];
114
118
  this._filterProviders = new Map<string, FilterProvider>();
115
119
  this._sortingProvider = undefined;
@@ -180,6 +184,8 @@ export default class DataUnit {
180
184
  case Action.NEXT_SELECTED:
181
185
  case Action.PREVIOUS_SELECTED:
182
186
  case Action.DATA_LOADED:
187
+ case Action.RECORDS_ADDED:
188
+ case Action.EDITION_CANCELED:
183
189
  this.clearDataUnit();
184
190
  const selectedRecord = this._parentDataUnit?.getSelectedRecord();
185
191
  if(selectedRecord != undefined && !this.isNewRecord(selectedRecord.__record__id__)){
@@ -241,10 +247,10 @@ export default class DataUnit {
241
247
  async response => {
242
248
  await this.dispatchAction(
243
249
  Action.DATA_LOADED,
244
- {...response, keepSelection: request.keepSelection, filters: request.filters},
250
+ {...response, keepSelection: request.keepSelection, filters: request.filters, selectFirstRecord},
245
251
  executionCtx
246
252
  );
247
-
253
+
248
254
  await this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
249
255
 
250
256
  if(selectFirstRecord){
@@ -317,13 +323,16 @@ export default class DataUnit {
317
323
 
318
324
  await this.processLoadingLockers();
319
325
 
320
- if (this._parentDataUnit && !this._parentDataUnit.getSelectedRecord()) {
326
+ if (this._parentDataUnit) {
327
+ const parentRecord = this._parentDataUnit.getSelectedRecord();
328
+ if(parentRecord == undefined || this._parentDataUnit.isNewRecord(parentRecord.__record__id__)){
321
329
  if(this.records){
322
330
  this.clearDataUnit();
323
331
  }
324
332
  return Promise.resolve({
325
333
  records: []
326
334
  });
335
+ }
327
336
  }
328
337
 
329
338
  const loadDataRequest = this.getLoadDataRequest(quickFilter, source);
@@ -336,7 +345,7 @@ export default class DataUnit {
336
345
  *
337
346
  * @param page - Número da página desejada.
338
347
  * @param executionCtx - Contexto de execução do carregamento dos registros do DataUnit.
339
- *
348
+ *
340
349
  * @returns - Registros da página desejada.
341
350
  *
342
351
  */
@@ -471,6 +480,7 @@ export default class DataUnit {
471
480
  Promise.all(dispatchPromisses).then(() => resolve());
472
481
  }).catch(cause => {
473
482
  const {errorCode} = cause;
483
+ this.dispatchAction(Action.SAVING_ERROR);
474
484
  this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
475
485
  fail(new ErrorException("Erro ao salvar alterações", cause, errorCode));
476
486
  });
@@ -576,7 +586,8 @@ export default class DataUnit {
576
586
  const currentRecordsKeys = Array.from(getCurrentRecords(this._stateManager).keys());
577
587
  const removedIndex: Array<number> = recordIds
578
588
  .map(id => currentRecordsKeys.indexOf(id))
579
- .filter(index => index > -1);
589
+ .filter(index => index > -1)
590
+ .sort();
580
591
 
581
592
  const nextIndex = Math.min(removedIndex.slice(-1)[0] + 1, currentRecordsKeys.length);
582
593
  const selectionAfterRemove = currentRecordsKeys[nextIndex] ? [currentRecordsKeys[nextIndex]] : [];
@@ -643,15 +654,14 @@ export default class DataUnit {
643
654
  *
644
655
  */
645
656
  public getFormattedValue(fieldName: string, value?: any): string {
646
-
647
657
  const descriptor = this.getField(fieldName);
648
- if (value == undefined) {
658
+ if (value === undefined) {
649
659
  value = this.getFieldValue(fieldName);
650
660
  } else if (typeof value === "string" && descriptor?.dataType != DataType.TEXT){
651
661
  value = this.valueFromString(fieldName, value);
652
662
  }
653
663
 
654
- if(value == undefined){
664
+ if(value === undefined){
655
665
  return "";
656
666
  }
657
667
 
@@ -949,7 +959,7 @@ export default class DataUnit {
949
959
  * @returns - Promise que será resolvida quando o novo valor for persistido no state.
950
960
  *
951
961
  */
952
- public async setFieldValue(fieldName: string, newValue: any, records?: Array<string>): Promise<boolean> {
962
+ public async setFieldValue(fieldName: string, newValue: any, records?: Array<string>, options?:DataUnitEventOptions): Promise<boolean> {
953
963
 
954
964
  if(!this.hasNewRecord() && !this.getSelectedRecord()) await this.addRecord();
955
965
 
@@ -968,7 +978,7 @@ export default class DataUnit {
968
978
  }
969
979
 
970
980
  if (currentValue !== typedValue) {
971
- const promise = this.dispatchAction(Action.DATA_CHANGED, { [fieldName]: typedValue, records }, undefined);
981
+ const promise = this.dispatchAction(Action.DATA_CHANGED, { [fieldName]: typedValue, records }, undefined, options);
972
982
  this._savingLockers.push(promise);
973
983
  return promise;
974
984
  }
@@ -1168,6 +1178,15 @@ export default class DataUnit {
1168
1178
  return getSelectedRecord(this._stateManager);
1169
1179
  }
1170
1180
 
1181
+ /**
1182
+ * Retorna o DataUnit pai
1183
+ *
1184
+ * @returns DataUnit pai ou undefined
1185
+ */
1186
+ public getParentDataUnit(): DataUnit | undefined {
1187
+ return this._parentDataUnit;
1188
+ }
1189
+
1171
1190
  /**
1172
1191
  *
1173
1192
  * Limpa todos os registros do DataUnit
@@ -1255,14 +1274,28 @@ export default class DataUnit {
1255
1274
  /**
1256
1275
  *
1257
1276
  * Retorna se existe algum tipo de alteração pendente.
1258
- *
1277
+ *
1278
+ * @param ignoreChildren: Define se deverá ignorar alterações pendentes no DataUnit filho.
1259
1279
  * @returns Verdadeiro se existir alterações pendentes.
1260
1280
  *
1261
1281
  */
1262
- public isDirty(): boolean {
1282
+ public isDirty(ignoreChildren?: boolean): boolean {
1283
+ if(ignoreChildren) return isDirty(this._stateManager);
1284
+
1263
1285
  return isDirty(this._stateManager) || this.childrenIsDirty();
1264
1286
  }
1265
1287
 
1288
+ /**
1289
+ *
1290
+ * Retorna se existe alterações pendentes no DataUnit pai.
1291
+ *
1292
+ * @returns Verdadeiro se existir alterações pendentes e Falso caso não exista alterações ou não exista DataUnit pai.
1293
+ *
1294
+ */
1295
+ public isParentDirty(): boolean {
1296
+ return this._parentDataUnit ? this._parentDataUnit.isDirty(true) : false;
1297
+ }
1298
+
1266
1299
  /**
1267
1300
  *
1268
1301
  * Retorna se existe algum DataUnit detail com alterações pendentes.
@@ -1435,7 +1468,7 @@ export default class DataUnit {
1435
1468
  * @returns - Verdadeiro se ação iniciada.
1436
1469
  *
1437
1470
  */
1438
- private async dispatchAction(actionType: Action, payload?: any, executionCtx?: ExecutionContext): Promise<boolean> {
1471
+ private async dispatchAction(actionType: Action, payload?: any, executionCtx?: ExecutionContext, options?:DataUnitEventOptions): Promise<boolean> {
1439
1472
  return new Promise(async resolve => {
1440
1473
  let action = new DataUnitAction(actionType, payload);
1441
1474
  if (executionCtx && executionCtx.before) {
@@ -1445,7 +1478,7 @@ export default class DataUnit {
1445
1478
  action = await this.intercept(action, this._interceptors.values());
1446
1479
  }
1447
1480
  if (action) {
1448
- this.doDispatchAction(action);
1481
+ this.doDispatchAction(action, options);
1449
1482
  if (executionCtx && executionCtx.after) {
1450
1483
  executionCtx.after(action)
1451
1484
  }
@@ -1483,7 +1516,7 @@ export default class DataUnit {
1483
1516
  * @param action - Ações em execução no DataUnit.
1484
1517
  *
1485
1518
  */
1486
- private doDispatchAction(action: DataUnitAction): void {
1519
+ private doDispatchAction(action: DataUnitAction, options:DataUnitEventOptions = {}): void {
1487
1520
  this._stateManager.process(action);
1488
1521
  this?._parentDataUnit?.dispatchAction(Action.CHILD_CHANGED, { srcAction: action, srcDataUnit: this });
1489
1522
  this._observers.forEach(f => {
@@ -1492,7 +1525,7 @@ export default class DataUnit {
1492
1525
  should be continued
1493
1526
  */
1494
1527
  try {
1495
- f(action);
1528
+ f(action, options);
1496
1529
  } catch (e) {
1497
1530
  console.warn("[DataUnit] error while call observer", e);
1498
1531
  }
@@ -1531,7 +1564,7 @@ export default class DataUnit {
1531
1564
  * @param observer - Função que recebe como parâmetro as ações que serão monitoradas.
1532
1565
  *
1533
1566
  */
1534
- public subscribe(observer: (action: DataUnitAction) => void) {
1567
+ public subscribe(observer: (action: DataUnitAction, options?:DataUnitEventOptions) => void | Promise<void>) {
1535
1568
  this._observers.push(observer);
1536
1569
  }
1537
1570
 
@@ -1765,6 +1798,10 @@ export default class DataUnit {
1765
1798
  return loadingLockerResolver || Promise.resolve;
1766
1799
  }
1767
1800
 
1801
+ public set allowReleaseCallbacks(allow: boolean){
1802
+ this._allowReleaseCallbacks = allow;
1803
+ }
1804
+
1768
1805
  private async processLoadingLockers(){
1769
1806
  if(this._loadingLockers.length) {
1770
1807
  await Promise.all(this._loadingLockers);
@@ -1952,3 +1989,5 @@ export class SelectionInfo{
1952
1989
  return this.length === 0;
1953
1990
  }
1954
1991
  }
1992
+
1993
+ export type DataUnitEventOptions = {[key:string]: any};
@@ -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){
@@ -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
 
@@ -35,6 +35,7 @@ export enum Action{
35
35
 
36
36
  SAVING_DATA = "savingData",
37
37
  DATA_SAVED = "dataSaved",
38
+ SAVING_ERROR = "savingError",
38
39
 
39
40
  REMOVING_RECORDS = "removingRecords",
40
41
  RECORDS_REMOVED = "recordsRemoved",
@@ -31,7 +31,7 @@ class SelectionReducerImpl implements ActionReducer {
31
31
  if (currentRecords && currentRecords.size > 0) {
32
32
  let index: number;
33
33
  if (!currentState || currentSelection.length === 0) {
34
- index = action.type === Action.PREVIOUS_SELECTED ? 0 : Math.min(1, currentRecords.size);
34
+ index = action.type === Action.PREVIOUS_SELECTED ? 0 : Math.min(0, currentRecords.size);
35
35
  } else {
36
36
  index = getItemIndex(currentSelection[0], currentRecords) + (action.type === Action.PREVIOUS_SELECTED ? -1 : 1);
37
37
  }
@@ -68,7 +68,7 @@ class SelectionReducerImpl implements ActionReducer {
68
68
  if(currentState?.lastSelection){
69
69
  return { currentSelection: currentState.lastSelection };
70
70
  }
71
- return { currentSelection: [] }
71
+ return { currentSelection: currentState?.currentSelection || [] }
72
72
  }
73
73
 
74
74
  return currentState;
package/src/index.ts CHANGED
@@ -9,7 +9,7 @@ import { HttpProvider } from "./http/HttpProvider.js";
9
9
  import { SkwHttpProvider } from "./http/SkwHttpProvider.js";
10
10
  import { RequestMetadata } from "./http/RequestMetadata.js";
11
11
  import { AuthorizedServiceCaller } from "./http/AuthorizedServiceCaller.js";
12
- import DataUnit, {SavedRecord, Record, Change, ChangeOperation, DUActionInterceptor, WaitingChange, PageRequest, QuickFilter, SelectionMode, SelectionInfo} from "./dataunit/DataUnit.js";
12
+ import DataUnit, {SavedRecord, Record, Change, ChangeOperation, DUActionInterceptor, WaitingChange, PageRequest, QuickFilter, SelectionMode, SelectionInfo, DataUnitEventOptions} from "./dataunit/DataUnit.js";
13
13
  import { DataType } from "./dataunit/metadata/DataType.js";
14
14
  import { UnitMetadata, FieldDescriptor, UserInterface, Sort, SortMode, SortingProvider, Filter, DependencyType, ChildDescriptor, ChildLink } from "./dataunit/metadata/UnitMetadata.js";
15
15
  import { DataUnitAction, Action, ExecutionContext } from "./dataunit/state/action/DataUnitAction.js";
@@ -39,7 +39,7 @@ import { IRepositoryIndex } from "./repository/indexeddb/IRepositoryIndex.js"
39
39
  import { FieldComparator } from "./dataunit/sorting/FieldComparator.js";
40
40
  import { KeyboardManager } from "./utils/KeyboardManager/index.js";
41
41
  import { SearchUtils } from "./utils/SearchUtils.js";
42
- import OverflowWatcher, { OnOverflowCallBack, OverflowDirection } from "./utils/OverflowWatcher/index.js";
42
+ import OverflowWatcher, { OnOverflowCallBack, OverflowDirection, OverFlowWatcherParams, OVERFLOWED_CLASS_NAME } from "./utils/OverflowWatcher/index.js";
43
43
 
44
44
  /*Classes públicas no pacote*/
45
45
  export {
@@ -109,5 +109,8 @@ export {
109
109
  SearchUtils,
110
110
  OverflowWatcher,
111
111
  OnOverflowCallBack,
112
- OverflowDirection
112
+ OverflowDirection,
113
+ OverFlowWatcherParams,
114
+ OVERFLOWED_CLASS_NAME,
115
+ DataUnitEventOptions
113
116
  };
@@ -0,0 +1,10 @@
1
+ import { OverflowDirection } from './OverflowWatcher/types/overflow-direction.js';
2
+
3
+ export function calcMarginSize(el:Element, scrollDirection: OverflowDirection){
4
+ const computedStyle = getComputedStyle(el);
5
+ if(OverflowDirection.HORIZONTAL === scrollDirection){
6
+ return (parseInt(computedStyle.marginLeft || '0') + parseInt(computedStyle.marginRight || '0'));
7
+ }
8
+
9
+ return (parseInt(computedStyle.marginTop || '0') + parseInt(computedStyle.marginBottom || '0'));
10
+ }
@@ -84,4 +84,24 @@ export default class ObjectUtils{
84
84
  public static equals(obj1: any, obj2: any): any {
85
85
  return ObjectUtils.objectToString(obj1) === ObjectUtils.objectToString(obj2);
86
86
  }
87
+
88
+ /**
89
+ * Verifica se o objeto está vazio (sem atributos).
90
+ *
91
+ * @param obj - Objeto a ser verificado.
92
+ * @returns - True caso o objeto esteja vazio.
93
+ */
94
+ public static isEmpty(obj: object): boolean{
95
+ return Object.keys(obj).length === 0 && obj.constructor === Object;
96
+ }
97
+
98
+ /**
99
+ * Verifica se o objeto NÃO está vazio (sem atributos).
100
+ *
101
+ * @param obj - Objeto a ser verificado.
102
+ * @returns - True caso o objeto NÃO esteja vazio
103
+ */
104
+ public static isNotEmpty(obj: object): boolean{
105
+ return !this.isEmpty(obj);
106
+ }
87
107
  }