@adaptabletools/adaptable 21.0.6 → 21.0.7

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adaptabletools/adaptable",
3
- "version": "21.0.6",
3
+ "version": "21.0.7",
4
4
  "description": "Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements",
5
5
  "keywords": [
6
6
  "web-components",
@@ -11,7 +11,7 @@ export interface DateInputOptions {
11
11
  /**
12
12
  * Format string for formatting date input field
13
13
  *
14
- * @defaultValue 'yyyy-MM-dd'
14
+ * @defaultValue 'yyyy-MM-dd' (ISO 8601 format)
15
15
  */
16
16
  dateFormat?: string;
17
17
  /**
@@ -123,4 +123,5 @@ export declare class AdaptableInternalApi extends ApiBase {
123
123
  findAdaptableObjectsByLookupCriteria<T extends AdaptableObjectWithScope>({ scope, tag, ids }: AdaptableObjectLookupCriteria, specificAdaptableObjects: T[]): T[];
124
124
  buildBaseContext(): BaseContext;
125
125
  setCellSummaryInfo(cellSummaryInfo: CellSummmaryInfo): void;
126
+ parseDateValue(dateValue: string | Date | number): Date | undefined;
126
127
  }
@@ -5,6 +5,7 @@ import StringExtensions from '../../Utilities/Extensions/StringExtensions';
5
5
  import { ADAPTABLE_ID } from '../../Utilities/Constants/GeneralConstants';
6
6
  import { waitForCondition } from '../../Utilities/waitForCondition';
7
7
  import { isAdaptableCustomIcon, isAdaptableSystemIcon } from '../../components/Icon';
8
+ import { parseDateValue } from '../../Utilities/Helpers/DateHelper';
8
9
  export class AdaptableInternalApi extends ApiBase {
9
10
  getInternalState() {
10
11
  return this.getAdaptableState().Internal;
@@ -439,4 +440,12 @@ export class AdaptableInternalApi extends ApiBase {
439
440
  setCellSummaryInfo(cellSummaryInfo) {
440
441
  this.dispatchAction(InternalRedux.SetCellSummaryInfo(cellSummaryInfo));
441
442
  }
443
+ parseDateValue(dateValue) {
444
+ const dateFormat = this.getUserInterfaceOptions().dateInputOptions.dateFormat;
445
+ if (dateFormat === 'yyyy-MM-dd') {
446
+ // if the format is ISO, we don't pass it so that we use the date-fns `parseISO` which is more robust
447
+ return parseDateValue(dateValue);
448
+ }
449
+ return parseDateValue(dateValue, dateFormat);
450
+ }
442
451
  }
@@ -1,7 +1,5 @@
1
1
  import { ApiBase } from '../Implementation/ApiBase';
2
- import { ColDef, Column, HeaderValueGetterParams, IRowNode } from 'ag-grid-enterprise';
3
- import { CustomSort } from '../../AdaptableState/CustomSortState';
4
- import { ColumnValuesComparer } from '../../AdaptableOptions/CustomSortOptions';
2
+ import { ColDef, Column, HeaderValueGetterParams } from 'ag-grid-enterprise';
5
3
  import { AdaptableColumn, AdaptableColumnDataType } from '../../types';
6
4
  export declare function getAutoRowGroupColumnIdFor(columnId: string): string;
7
5
  export declare class ColumnInternalApi extends ApiBase {
@@ -29,7 +27,6 @@ export declare class ColumnInternalApi extends ApiBase {
29
27
  * @param columnId columnId to look up
30
28
  */
31
29
  getAgGridColumnForAdaptableColumn(columnId: string): Column;
32
- getActiveColumnComparator(columnId: string, customSort?: CustomSort, customSortComparer?: ColumnValuesComparer): (valueA: any, valueB: any, nodeA?: IRowNode, nodeB?: IRowNode, isInverted?: boolean) => number | undefined;
33
30
  isSpecialColumn(columnId: string, column?: AdaptableColumn): boolean;
34
31
  getColumnHeaderName(params: HeaderValueGetterParams): string;
35
32
  private buildColumnHeaderContext;
@@ -64,18 +64,6 @@ export class ColumnInternalApi extends ApiBase {
64
64
  getAgGridColumnForAdaptableColumn(columnId) {
65
65
  return this._adaptable.getAgGridColumnForColumnId(columnId);
66
66
  }
67
- getActiveColumnComparator(columnId, customSort, customSortComparer) {
68
- if ((!customSort || customSort?.IsSuspended) && !customSortComparer) {
69
- // defaults to AG-Grid column definition comparator if no CustomSort is defined&active
70
- const colDefComparator = this._adaptable.agGridColumnAdapter.getUserColDefProperty(columnId, 'comparator');
71
- return colDefComparator;
72
- }
73
- // CustomSort Comparer function takes precedence over CustomSort SortedValues
74
- const comparerFunction = customSortComparer
75
- ? customSortComparer.comparer
76
- : this.getCustomSortApi().internalApi.getDefaultCustomSortComparer(customSort.ColumnId, customSort.SortedValues);
77
- return comparerFunction;
78
- }
79
67
  isSpecialColumn(columnId, column = null) {
80
68
  if (column) {
81
69
  return column.isCalculatedColumn || column.isFreeTextColumn || column.isActionColumn;
@@ -14,6 +14,7 @@ export declare class ExportInternalApi extends ApiBase {
14
14
  setExportInProgress(reportName: ReportNameType, reportFormat: ReportFormatType, exportDestination: ExportDestinationType): void;
15
15
  setExportComplete(): void;
16
16
  isVisualDataExportInProgress(): boolean;
17
+ isExcelExportInProgress(): boolean;
17
18
  createSystemReport(systemReportName: SystemReportName): Report;
18
19
  isSystemReport(reportName: ReportNameType): boolean;
19
20
  isSystemDestination(destination: ExportDestinationType): boolean;
@@ -82,6 +82,9 @@ export class ExportInternalApi extends ApiBase {
82
82
  isVisualDataExportInProgress() {
83
83
  return this.getAdaptableState().Internal.Export.inProgress?.reportFormat === 'VisualExcel';
84
84
  }
85
+ isExcelExportInProgress() {
86
+ return this.getAdaptableState().Internal.Export.inProgress?.reportFormat === 'Excel';
87
+ }
85
88
  createSystemReport(systemReportName) {
86
89
  switch (systemReportName) {
87
90
  case ALL_DATA_REPORT:
@@ -8,4 +8,3 @@ export declare const isValueValidDate: (data: any) => boolean;
8
8
  export declare const dateToISO: (date: Date | number | string) => string;
9
9
  export declare const parseToISO: (date: string | Date | number, dateFormat?: string) => string;
10
10
  export declare const parseDateValue: (dateValue: string | Date | number, dateFormat?: string) => Date | undefined;
11
- export declare const parseFilterInputDate: (stringDate: string) => Date;
@@ -23,6 +23,9 @@ export const parseToISO = (date, dateFormat) => {
23
23
  const dateInstance = parseDateValue(date, dateFormat);
24
24
  return isValidDate(dateInstance) ? dateToISO(dateInstance) : '';
25
25
  };
26
+ // !!!
27
+ // AFL: ideally we should NEVER call directly this method, but use the AdaptableInternalApi.parseDateValue() instead
28
+ // we should refactor this with the first opportunity
26
29
  export const parseDateValue = (dateValue, dateFormat) => {
27
30
  if (dateValue == undefined || (typeof dateValue === 'string' && dateValue.trim() === '')) {
28
31
  return undefined;
@@ -30,27 +33,36 @@ export const parseDateValue = (dateValue, dateFormat) => {
30
33
  if (dateValue instanceof Date) {
31
34
  return !isNaN(dateValue.getTime()) ? dateValue : undefined;
32
35
  }
33
- let dateInstance;
34
- if (typeof dateValue === 'number') {
35
- dateInstance = new Date(dateValue);
36
- }
37
- else {
38
- // typeof dateValue === 'string'
39
- if (dateFormat) {
40
- dateInstance = parse(dateValue, dateFormat, new Date());
36
+ try {
37
+ let dateInstance;
38
+ if (typeof dateValue === 'number') {
39
+ dateInstance = new Date(dateValue);
41
40
  }
42
41
  else {
43
- dateInstance = parseISO(dateValue);
42
+ // typeof dateValue === 'string'
43
+ if (dateFormat) {
44
+ dateInstance = parse(dateValue, dateFormat, new Date());
45
+ }
46
+ else {
47
+ dateInstance = parseISO(dateValue);
48
+ }
49
+ if (!isValidDate(dateInstance)) {
50
+ // last chance: try to use the native Date.parse(), https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse
51
+ dateInstance = new Date(Date.parse(dateValue));
52
+ }
44
53
  }
45
54
  if (!isValidDate(dateInstance)) {
46
- // last chance: try to use the native Date.parse(), https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse
47
- dateInstance = new Date(Date.parse(dateValue));
55
+ AdaptableLogger.consoleWarnBase(`Invalid date value "${dateValue}" - cannot be converted to a Date instance. Please make sure you specify adaptableOptions.userInterfaceOptions.dateInputOptions.dateFormat correctly.`);
56
+ dateInstance = undefined;
48
57
  }
58
+ return dateInstance;
49
59
  }
50
- if (!isValidDate(dateInstance)) {
51
- AdaptableLogger.consoleWarnBase(`Invalid date value "${dateValue}" - cannot be converted to a Date instance. Please make sure you specify adaptableOptions.userInterfaceOptions.dateInputOptions.dateFormat correctly.`);
52
- dateInstance = undefined;
60
+ catch (error) {
61
+ const errorMessage = error instanceof Error ? error.message : String(error);
62
+ const errorStack = error instanceof Error ? error.stack : undefined;
63
+ AdaptableLogger.consoleErrorBase(`Error parsing date value "${dateValue}": ${errorMessage}`, {
64
+ stack: errorStack,
65
+ originalError: error,
66
+ });
53
67
  }
54
- return dateInstance;
55
68
  };
56
- export const parseFilterInputDate = (stringDate) => new Date(stringDate);
@@ -31,7 +31,7 @@ class FilterViewPanelComponent extends React.Component {
31
31
  ArrayExtensions.IsNotNullOrEmpty(this.props.ColumnFilters) && (React.createElement(AdaptablePopover, { popupPadding: 0, className: `ab-${elementType}__Filter__info`, headerText: "", bodyText: [React.createElement(ActiveFiltersPanel, null)], useButton: true, showEvent: 'focus', hideEvent: "blur", popoverMinWidth: 400 })),
32
32
  React.createElement(ButtonClear, { "aria-label": 'Clear Filters', className: `ab-${elementType}__Filter__clear`, marginLeft: 1, marginBottom: 0, marginRight: 1, onClick: () => this.onClearFilters(), tooltip: "Clear Filters", disabled: this.props.ColumnFilters.length == 0, showText: this.props.viewType === 'ToolPanel' }, this.props.viewType === 'ToolPanel' && 'Clear'),
33
33
  React.createElement(SimpleButton, { "aria-label": isAtLeastOneFilterActive ? 'Suspend All Filters' : 'Resume All Filters', className: join(`ab-${elementType}__Filter__suspend-button`, isAtLeastOneFilterActive && `ab-${elementType}__Filter__suspend-all`, !isAtLeastOneFilterActive && `ab-${elementType}__Filter__un-suspend-all`), disabled: !isAtLeastOneFilter, onClick: handleSuspendUnsuspendAll, tone: isAtLeastOneFilterActive ? 'neutral' : 'success', variant: "text", icon: isAtLeastOneFilterActive ? 'pause' : 'play', accessLevel: this.props.accessLevel })),
34
- React.createElement(Flex, { alignItems: "center" }, this.props.api.filterApi.columnFilterApi.isQuickFilterAvailable() && (React.createElement(CheckBox, { className: `ab-${elementType}__Filter__active-check`, disabled: this.props.accessLevel === 'ReadOnly' ||
34
+ React.createElement(Flex, { alignItems: "center" }, this.props.api.filterApi.columnFilterApi.isQuickFilterAvailable() && (React.createElement(CheckBox, { "data-name": "quick-filter-toggle", className: `ab-${elementType}__Filter__active-check`, disabled: this.props.accessLevel === 'ReadOnly' ||
35
35
  this.props.api.layoutApi.isCurrentLayoutPivot(), marginTop: 0, marginBottom: 0, fontSize: 2, padding: 1, checked: this.props.IsQuickFilterVisible, onChange: (checked) => {
36
36
  checked ? this.props.onShowQuickFilterBar() : this.props.onHideQuickFilterBar();
37
37
  } }, "Filter Bar")))));
@@ -1085,6 +1085,20 @@ You need to define at least one Layout!`);
1085
1085
  color: '#aaaaaa',
1086
1086
  pattern: 'Solid',
1087
1087
  },
1088
+ },
1089
+ // see #EXCEL_EXPORT_DATA_TYPES
1090
+ {
1091
+ id: 'stringExcelType',
1092
+ dataType: 'String',
1093
+ }, {
1094
+ id: 'booleanExcelType',
1095
+ dataType: 'Boolean',
1096
+ }, {
1097
+ id: 'dateExcelType',
1098
+ dataType: 'DateTime',
1099
+ }, {
1100
+ id: 'numberExcelType',
1101
+ dataType: 'Number',
1088
1102
  });
1089
1103
  this.agGridExportAdapter.originalExcelStyles = excelStyles;
1090
1104
  this.agGridExportAdapter.DANGER_excelStyles = this.agGridExportAdapter.originalExcelStyles;
@@ -3195,11 +3209,6 @@ You need to define at least one Layout!`);
3195
3209
  return this.agGridModulesAdapter.isAgGridModuleRegistered('CsvExportModule');
3196
3210
  }
3197
3211
  isQuickFilterAvailable() {
3198
- if (this.api.layoutApi.isCurrentLayoutPivot() &&
3199
- this.adaptableOptions.filterOptions.useAdaptableFiltering) {
3200
- // hide completely the quick filter if pivot is enabled
3201
- return false;
3202
- }
3203
3212
  return this.hasFloatingFilterOnAtLeastOneColumn(this.agGridAdapter.getAgGridApi().getColumnDefs());
3204
3213
  }
3205
3214
  hasFloatingFilterOnAtLeastOneColumn(columnDefs) {
@@ -169,11 +169,27 @@ export class AgGridColumnAdapter {
169
169
  if (!gridCell.column) {
170
170
  return null;
171
171
  }
172
- // if a VisualExcel report format export is in progress, we are interested only in the Excel Style Class
173
- if (this.adaptableApi.exportApi.internalApi.isVisualDataExportInProgress()) {
172
+ const isExcelExport = this.adaptableApi.exportApi.internalApi.isExcelExportInProgress();
173
+ const isVisualDataExport = this.adaptableApi.exportApi.internalApi.isVisualDataExportInProgress();
174
+ if (isExcelExport || isVisualDataExport) {
175
+ const excelStyleClasses = [];
174
176
  const userDefinedCellClass = typeof userCellClass === 'function' ? userCellClass(params) : userCellClass;
175
- const cellClassKey = AgGridExportAdapter.getExcelClassNameForCell(colId, gridCell.primaryKeyValue, userDefinedCellClass);
176
- return this.adaptableInstance.agGridExportAdapter.getExcelStyleIdForCellClassKey(cellClassKey);
177
+ if (userDefinedCellClass) {
178
+ if (Array.isArray(userDefinedCellClass)) {
179
+ excelStyleClasses.push(...userDefinedCellClass.filter(Boolean));
180
+ }
181
+ else {
182
+ excelStyleClasses.push(userDefinedCellClass);
183
+ }
184
+ }
185
+ if (isVisualDataExport) {
186
+ const cellClassKey = AgGridExportAdapter.getExcelClassNameForCell(colId, gridCell.primaryKeyValue, userDefinedCellClass);
187
+ const customCellClass = this.adaptableInstance.agGridExportAdapter.getExcelStyleIdForCellClassKey(cellClassKey);
188
+ if (customCellClass) {
189
+ excelStyleClasses.push(customCellClass);
190
+ }
191
+ }
192
+ return excelStyleClasses.length ? excelStyleClasses : null;
177
193
  }
178
194
  const isQuickSearchActive = this.isQuickSearchActive(gridCell);
179
195
  const editableClassName = this.getEditableCellClass(gridCell, params);
@@ -612,7 +628,7 @@ export class AgGridColumnAdapter {
612
628
  const isFloatingFilterDisabled = !colDef.filter ||
613
629
  !colDef.floatingFilter ||
614
630
  !this.adaptableOptions.filterOptions.useAdaptableFiltering ||
615
- !this.adaptableOptions.filterOptions.columnFilterOptions.showQuickFilter;
631
+ !this.adaptableApi.filterApi.columnFilterApi.isQuickFilterVisible();
616
632
  if (this.adaptableApi.columnApi.isAutoRowGroupColumn(col.getColId())) {
617
633
  this.setColDefProperty(col, 'floatingFilter', (original_floatingFilter) => {
618
634
  // the floating filter for the group column is "inherited" from the base column
@@ -803,10 +819,47 @@ export class AgGridColumnAdapter {
803
819
  }
804
820
  setupColumnComparator({ col, colId, abColumn }) {
805
821
  const customSort = this.adaptableApi.customSortApi.getCustomSortForColumn(colId);
806
- const columnSortComparer = this.adaptableApi.customSortApi.internalApi.getCustomSortComparer(abColumn.columnId);
822
+ const customSortComparer = this.adaptableApi.customSortApi.internalApi.getCustomSortComparer(abColumn.columnId);
823
+ const memoizedDateValues = new Map();
824
+ const getDateValue = (rawDateValue) => {
825
+ if (memoizedDateValues.has(rawDateValue)) {
826
+ return memoizedDateValues.get(rawDateValue);
827
+ }
828
+ const dateValue = this.adaptableApi.internalApi.parseDateValue(rawDateValue);
829
+ memoizedDateValues.set(rawDateValue, dateValue);
830
+ return dateValue;
831
+ };
807
832
  const comparatorGetter = (propName) => {
808
- return () => {
809
- return this.adaptableApi.columnApi.internalApi.getActiveColumnComparator(colId, customSort, columnSortComparer);
833
+ return (userPropertyValue) => {
834
+ // CustomSort Comparer function takes precedence over CustomSort SortedValues
835
+ if (customSortComparer) {
836
+ return customSortComparer.comparer;
837
+ }
838
+ if (customSort && !customSort.IsSuspended) {
839
+ return this.adaptableApi.customSortApi.internalApi.getDefaultCustomSortComparer(customSort.ColumnId, customSort.SortedValues);
840
+ }
841
+ if (userPropertyValue) {
842
+ return userPropertyValue;
843
+ }
844
+ // for DATE columns we have to use the normalised values (Date objects) to compare
845
+ if (abColumn.dataType === 'date') {
846
+ return (valueA, valueB) => {
847
+ const dateA = getDateValue(valueA);
848
+ const dateB = getDateValue(valueB);
849
+ if (dateA && dateB) {
850
+ return dateA.getTime() - dateB.getTime();
851
+ }
852
+ else if (dateA) {
853
+ return 1; // consider non-null dates as greater than null/undefined
854
+ }
855
+ else if (dateB) {
856
+ return -1; // consider non-null dates as greater than null/undefined
857
+ }
858
+ else {
859
+ return 0; // both are null/undefined, considered equal
860
+ }
861
+ };
862
+ }
810
863
  };
811
864
  };
812
865
  this.setColDefProperty(col, 'comparator', comparatorGetter('comparator'));
@@ -602,6 +602,23 @@ export class AgGridExportAdapter {
602
602
  this.registerExcelStyle(finalCellExcelStyle, cellClassId);
603
603
  });
604
604
  }, forAllVisibleRowNodesDoConfig);
605
+ // see #EXCEL_EXPORT_DATA_TYPES
606
+ this.excelStylesCache['stringExcelType'] = {
607
+ id: 'stringExcelType',
608
+ dataType: 'String',
609
+ };
610
+ this.excelStylesCache['booleanExcelType'] = {
611
+ id: 'booleanExcelType',
612
+ dataType: 'Boolean',
613
+ };
614
+ this.excelStylesCache['dateExcelType'] = {
615
+ id: 'dateExcelType',
616
+ dataType: 'DateTime',
617
+ };
618
+ this.excelStylesCache['numberExcelType'] = {
619
+ id: 'numberExcelType',
620
+ dataType: 'Number',
621
+ };
605
622
  return Object.values(this.excelStylesCache);
606
623
  }
607
624
  registerExcelStyle(excelStyle, cellClassKey) {
package/src/env.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export default {
2
2
  NEXT_PUBLIC_INFINITE_TABLE_LICENSE_KEY: "StartDate=2021-06-29|EndDate=2030-01-01|Owner=Adaptable|Type=distribution|TS=1624971462479|C=137829811,1004007071,2756196225,1839832928,3994409405,636616862" || '',
3
- PUBLISH_TIMESTAMP: 1759506293070 || Date.now(),
4
- VERSION: "21.0.6" || '--current-version--',
3
+ PUBLISH_TIMESTAMP: 1760446037964 || Date.now(),
4
+ VERSION: "21.0.7" || '--current-version--',
5
5
  };