@adaptabletools/adaptable 23.0.20 → 23.0.22
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 +1 -1
- package/src/AdaptableOptions/FilterOptions.d.ts +26 -0
- package/src/AdaptableOptions/LayoutOptions.d.ts +1 -8
- package/src/AdaptableState/InitialState.d.ts +1 -1
- package/src/Api/GridApi.d.ts +5 -1
- package/src/Api/Implementation/FormatColumnApiImpl.d.ts +1 -0
- package/src/Api/Implementation/FormatColumnApiImpl.js +15 -0
- package/src/Api/Implementation/FreeTextColumnApiImpl.js +0 -3
- package/src/Api/Implementation/GridApiImpl.d.ts +1 -0
- package/src/Api/Implementation/GridApiImpl.js +22 -1
- package/src/Api/Implementation/StateApiImpl.d.ts +2 -0
- package/src/Api/Implementation/StateApiImpl.js +15 -0
- package/src/Api/Internal/ColumnFilterInternalApi.d.ts +7 -1
- package/src/Api/Internal/ColumnFilterInternalApi.js +3 -0
- package/src/Api/Internal/FormatColumnInternalApi.d.ts +5 -0
- package/src/Api/Internal/FormatColumnInternalApi.js +22 -0
- package/src/Api/Internal/StateInternalApi.d.ts +6 -1
- package/src/Api/Internal/StateInternalApi.js +44 -0
- package/src/Api/StateApi.d.ts +20 -0
- package/src/Redux/Store/AdaptableReduxMerger.js +24 -6
- package/src/Redux/Store/AdaptableStore.js +1 -1
- package/src/Utilities/Helpers/DisplayFormatHelper.js +16 -4
- package/src/Utilities/Helpers/SettingsPanelHelper.js +2 -2
- package/src/View/Components/ColumnFilter/components/FloatingFilterValues.d.ts +9 -0
- package/src/View/Components/ColumnFilter/components/FloatingFilterValues.js +21 -41
- package/src/View/Components/FilterForm/ListBoxFilterForm.js +16 -14
- package/src/View/Components/PredicateEditor/PredicateEditor.js +7 -1
- package/src/View/FormatColumn/Wizard/FormatColumnFormatWizardSection.js +6 -2
- package/src/agGrid/AdaptableAgGrid.d.ts +1 -0
- package/src/agGrid/AdaptableAgGrid.js +15 -0
- package/src/agGrid/AdaptableFilterHandler.d.ts +5 -1
- package/src/agGrid/AdaptableFilterHandler.js +44 -0
- package/src/components/Combobox/comboboxUtils.d.ts +6 -0
- package/src/components/Combobox/comboboxUtils.js +1 -1
- package/src/components/Combobox/index.d.ts +11 -0
- package/src/components/Combobox/index.js +16 -5
- package/src/components/Tree/TreeDropdown/index.d.ts +11 -0
- package/src/components/Tree/TreeDropdown/index.js +6 -3
- package/src/env.js +2 -2
- package/tsconfig.esm.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -206,6 +206,24 @@ export interface InFilterValueResult {
|
|
|
206
206
|
* Search changes reset the list and set `offset` back to 0.
|
|
207
207
|
*/
|
|
208
208
|
hasMore?: boolean;
|
|
209
|
+
/**
|
|
210
|
+
* Custom text for the collapsed IN Filter input.
|
|
211
|
+
*
|
|
212
|
+
* Receives the currently selected items (and their count) and must return a
|
|
213
|
+
* string.
|
|
214
|
+
*
|
|
215
|
+
* When omitted, the input shows the selected count (e.g. `(3)`) followed by the
|
|
216
|
+
* selected labels joined with a comma. When provided, it fully replaces that
|
|
217
|
+
* text (including the count - render one yourself if you want it).
|
|
218
|
+
*
|
|
219
|
+
* For tree-shaped filters (group columns and date columns), each selected leaf
|
|
220
|
+
* is one entry in `selectedValues`: its `value` is the full leaf path and its
|
|
221
|
+
* `label` the joined path label. `selectedCount` is the number of selected leaves.
|
|
222
|
+
*/
|
|
223
|
+
renderInputValues?: (params: {
|
|
224
|
+
selectedValues: InFilterValue[];
|
|
225
|
+
selectedCount: number;
|
|
226
|
+
}) => string;
|
|
209
227
|
}
|
|
210
228
|
/**
|
|
211
229
|
* Information about items in the IN Column Filter
|
|
@@ -276,6 +294,14 @@ export interface CustomInFilterValuesContext<TData = any> extends AdaptableColum
|
|
|
276
294
|
* Opaque pagination cursors may also be stashed on this object and read on the next call.
|
|
277
295
|
*/
|
|
278
296
|
previousFilterResult?: InFilterValueResult;
|
|
297
|
+
/**
|
|
298
|
+
* Values currently selected in the IN (or NOT IN) Column Filter.
|
|
299
|
+
*
|
|
300
|
+
* Labels are resolved from previously loaded In Filter items when available.
|
|
301
|
+
*
|
|
302
|
+
* Useful with lazy pagination or server-side search: selected items may not be in the current page.
|
|
303
|
+
*/
|
|
304
|
+
selectedValues: InFilterValue[];
|
|
279
305
|
/**
|
|
280
306
|
* Zero-based index of the first value to return.
|
|
281
307
|
* Reset to 0 when the dropdown opens or `currentSearchValue` changes.
|
|
@@ -24,14 +24,7 @@ export interface LayoutOptions<TData = any> {
|
|
|
24
24
|
*/
|
|
25
25
|
layoutCreationDefaultProperties?: LayoutCreationDefaultProperties | ((context: LayoutCreationDefaultPropertiesContext) => TableLayoutCreationDefaultProperties | PivotLayoutCreationDefaultProperties);
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* When provided, this overrides `LayoutRowSelection.Checkboxes` and any `gridOptions.rowSelection.checkboxes` value,
|
|
30
|
-
* and forces AG Grid `hideDisabledCheckboxes: true` so returning `false` hides (rather than greys out) the checkbox.
|
|
31
|
-
*
|
|
32
|
-
* Does not apply when the Layout sets `RowSelection: false` (row selection is fully disabled for that Layout).
|
|
33
|
-
*
|
|
34
|
-
* Use `context.rowNode` for group / footer / pinned / total rows (`data` may be `undefined` for those).
|
|
27
|
+
* Sets if Row Selection checkbox should be visible for a given row
|
|
35
28
|
*/
|
|
36
29
|
isRowSelectionCheckboxVisible?: (context: LayoutRowSelectionContext<TData>) => boolean;
|
|
37
30
|
}
|
|
@@ -60,7 +60,7 @@ export interface InitialState {
|
|
|
60
60
|
*/
|
|
61
61
|
FormatColumn?: FormatColumnState;
|
|
62
62
|
/**
|
|
63
|
-
* Collection of *FreeText* objects
|
|
63
|
+
* Collection of *FreeText* objects that define user-owned columns whose cell values are stored in Adaptable State (not the grid DataSource). Use for editable per-row fields such as ops notes, flags, or codes — distinct from cell-level Notes and Comments.
|
|
64
64
|
*/
|
|
65
65
|
FreeTextColumn?: FreeTextColumnState;
|
|
66
66
|
/**
|
package/src/Api/GridApi.d.ts
CHANGED
|
@@ -35,9 +35,13 @@ export interface GridApi {
|
|
|
35
35
|
*/
|
|
36
36
|
getFilteredData(): any[];
|
|
37
37
|
/**
|
|
38
|
-
* Retrieves visible data from the grid (filtered and sorted)
|
|
38
|
+
* Retrieves visible data from the grid (filtered and sorted from visible columns only)
|
|
39
39
|
*/
|
|
40
40
|
getVisibleData(): any[];
|
|
41
|
+
/**
|
|
42
|
+
* Retrieves the displayed (formatted but not styled) data from the grid (filtered and sorted and visible columns only)
|
|
43
|
+
*/
|
|
44
|
+
getDisplayedData(): any[];
|
|
41
45
|
/**
|
|
42
46
|
* Retrieves all the values for a single Column.
|
|
43
47
|
*
|
|
@@ -38,4 +38,5 @@ export declare class FormatColumnApiImpl extends ApiBase implements FormatColumn
|
|
|
38
38
|
incrementFormatColumnPrecedence(formatColumn: FormatColumn): void;
|
|
39
39
|
decrementFormatColumnPrecedence(formatColumn: FormatColumn): void;
|
|
40
40
|
findFormatColumns(criteria: AdaptableObjectLookupCriteria): FormatColumn[];
|
|
41
|
+
private refreshColumnsForFormatColumns;
|
|
41
42
|
}
|
|
@@ -39,14 +39,17 @@ export class FormatColumnApiImpl extends ApiBase {
|
|
|
39
39
|
addFormatColumn(formatColumn) {
|
|
40
40
|
this.addUidToAdaptableObject(formatColumn);
|
|
41
41
|
this.dispatchAction(FormatColumnRedux.FormatColumnAdd(formatColumn));
|
|
42
|
+
this.refreshColumnsForFormatColumns(formatColumn);
|
|
42
43
|
return this.getFormatColumnByUuId(formatColumn.Uuid);
|
|
43
44
|
}
|
|
44
45
|
addFormatColumns(formatColumns) {
|
|
45
46
|
this.dispatchAction(FormatColumnRedux.FormatColumnsAdd(formatColumns));
|
|
47
|
+
this.refreshColumnsForFormatColumns(formatColumns);
|
|
46
48
|
return formatColumns?.map((formatColumn) => this.getFormatColumnByUuId(formatColumn.Uuid));
|
|
47
49
|
}
|
|
48
50
|
editFormatColumn(formatColumn) {
|
|
49
51
|
this.dispatchAction(FormatColumnRedux.FormatColumnEdit(formatColumn));
|
|
52
|
+
this.refreshColumnsForFormatColumns(formatColumn);
|
|
50
53
|
return this.getFormatColumnByUuId(formatColumn.Uuid);
|
|
51
54
|
}
|
|
52
55
|
addFormatColumnStyle(formatColumn, style) {
|
|
@@ -56,26 +59,33 @@ export class FormatColumnApiImpl extends ApiBase {
|
|
|
56
59
|
updateFormatColumnStyle(formatColumn, style) {
|
|
57
60
|
formatColumn.Style = style;
|
|
58
61
|
this.dispatchAction(FormatColumnRedux.FormatColumnEdit(formatColumn));
|
|
62
|
+
this.refreshColumnsForFormatColumns(formatColumn);
|
|
59
63
|
}
|
|
60
64
|
deleteFormatColumn(formatColumn) {
|
|
61
65
|
this.dispatchAction(FormatColumnRedux.FormatColumnDelete(formatColumn));
|
|
66
|
+
this.refreshColumnsForFormatColumns(formatColumn);
|
|
62
67
|
}
|
|
63
68
|
deleteAllFormatColumns() {
|
|
64
69
|
this.dispatchAction(FormatColumnRedux.FormatColumnDeleteAll());
|
|
70
|
+
this.getGridApi().refreshAllCells(true);
|
|
65
71
|
}
|
|
66
72
|
suspendFormatColumn(formatColumn) {
|
|
67
73
|
this.dispatchAction(FormatColumnRedux.FormatColumnSuspend(formatColumn));
|
|
74
|
+
this.refreshColumnsForFormatColumns(formatColumn);
|
|
68
75
|
return this.getFormatColumnByUuId(formatColumn.Uuid);
|
|
69
76
|
}
|
|
70
77
|
unSuspendFormatColumn(formatColumn) {
|
|
71
78
|
this.dispatchAction(FormatColumnRedux.FormatColumnUnSuspend(formatColumn));
|
|
79
|
+
this.refreshColumnsForFormatColumns(formatColumn);
|
|
72
80
|
return this.getFormatColumnByUuId(formatColumn.Uuid);
|
|
73
81
|
}
|
|
74
82
|
suspendAllFormatColumn() {
|
|
75
83
|
this.dispatchAction(FormatColumnRedux.FormatColumnSuspendAll());
|
|
84
|
+
this.getGridApi().refreshAllCells(true);
|
|
76
85
|
}
|
|
77
86
|
unSuspendAllFormatColumn() {
|
|
78
87
|
this.dispatchAction(FormatColumnRedux.FormatColumnUnSuspendAll());
|
|
88
|
+
this.getGridApi().refreshAllCells(true);
|
|
79
89
|
}
|
|
80
90
|
getFormatColumnsForColumn(column, config) {
|
|
81
91
|
const formatColumns = this.getFormatColumns(config).filter((formatColumn) => (config?.includeSuspended || !formatColumn.IsSuspended) && (config?.includeReadOnly || !formatColumn.IsReadOnly));
|
|
@@ -114,9 +124,11 @@ export class FormatColumnApiImpl extends ApiBase {
|
|
|
114
124
|
}
|
|
115
125
|
incrementFormatColumnPrecedence(formatColumn) {
|
|
116
126
|
this.dispatchAction(FormatColumnRedux.FormatColumnMoveUp(formatColumn));
|
|
127
|
+
this.refreshColumnsForFormatColumns(formatColumn);
|
|
117
128
|
}
|
|
118
129
|
decrementFormatColumnPrecedence(formatColumn) {
|
|
119
130
|
this.dispatchAction(FormatColumnRedux.FormatColumnMoveDown(formatColumn));
|
|
131
|
+
this.refreshColumnsForFormatColumns(formatColumn);
|
|
120
132
|
}
|
|
121
133
|
findFormatColumns(criteria) {
|
|
122
134
|
const config = {
|
|
@@ -124,4 +136,7 @@ export class FormatColumnApiImpl extends ApiBase {
|
|
|
124
136
|
};
|
|
125
137
|
return this.getAdaptableInternalApi().findAdaptableObjectsByLookupCriteria(criteria, this.getFormatColumns(config));
|
|
126
138
|
}
|
|
139
|
+
refreshColumnsForFormatColumns(formatColumns) {
|
|
140
|
+
this.internalApi.refreshFormatColumnPresentation(formatColumns);
|
|
141
|
+
}
|
|
127
142
|
}
|
|
@@ -27,6 +27,7 @@ export declare class GridApiImpl extends ApiBase implements GridApi {
|
|
|
27
27
|
getGridData(): any[];
|
|
28
28
|
getFilteredData(): any[];
|
|
29
29
|
getVisibleData(): any[];
|
|
30
|
+
getDisplayedData(): any[];
|
|
30
31
|
getColumnData(columnId: string): any[];
|
|
31
32
|
getFilteredColumnData(columnId: string): any[];
|
|
32
33
|
getVisibleColumnData(columnId: string): any[];
|
|
@@ -36,9 +36,30 @@ export class GridApiImpl extends ApiBase {
|
|
|
36
36
|
}
|
|
37
37
|
getVisibleData() {
|
|
38
38
|
const data = [];
|
|
39
|
+
const visibleColumns = this.getColumnApi().getVisibleColumns();
|
|
39
40
|
this.getAdaptableInternalApi().forAllVisibleRowNodesDo((rowNode) => {
|
|
40
41
|
if (!this.isGroupRowNode(rowNode)) {
|
|
41
|
-
|
|
42
|
+
const visibleRow = {};
|
|
43
|
+
visibleColumns.forEach((column) => {
|
|
44
|
+
const key = column.field ?? column.columnId;
|
|
45
|
+
visibleRow[key] = this.getRawValueFromRowNode(rowNode, column.columnId);
|
|
46
|
+
});
|
|
47
|
+
data.push(visibleRow);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
return data;
|
|
51
|
+
}
|
|
52
|
+
getDisplayedData() {
|
|
53
|
+
const data = [];
|
|
54
|
+
const visibleColumns = this.getColumnApi().getVisibleColumns();
|
|
55
|
+
this.getAdaptableInternalApi().forAllVisibleRowNodesDo((rowNode) => {
|
|
56
|
+
if (!this.isGroupRowNode(rowNode)) {
|
|
57
|
+
const displayedRow = {};
|
|
58
|
+
visibleColumns.forEach((column) => {
|
|
59
|
+
const key = column.field ?? column.columnId;
|
|
60
|
+
displayedRow[key] = this.getDisplayValueFromRowNode(rowNode, column.columnId);
|
|
61
|
+
});
|
|
62
|
+
data.push(displayedRow);
|
|
42
63
|
}
|
|
43
64
|
});
|
|
44
65
|
return data;
|
|
@@ -30,6 +30,8 @@ export declare class StateApiImpl extends ApiBase implements StateApi {
|
|
|
30
30
|
copyUserStateToClipboard(): void;
|
|
31
31
|
getInitialState(): InitialState | any;
|
|
32
32
|
reloadInitialState(newInitialState?: InitialState): Promise<void>;
|
|
33
|
+
applyInitialState(newInitialState?: InitialState): Promise<void>;
|
|
34
|
+
remergePersistedState(): Promise<void>;
|
|
33
35
|
getAllState(): AdaptableState;
|
|
34
36
|
getPersistentState(): AdaptablePersistentState;
|
|
35
37
|
getAllUserState(): BaseState[];
|
|
@@ -66,12 +66,27 @@ export class StateApiImpl extends ApiBase {
|
|
|
66
66
|
.then(() => {
|
|
67
67
|
const newState = this.getPersistentState();
|
|
68
68
|
this.getEventApi().internalApi.fireAdaptableStateReloadedEvent(oldState, newState);
|
|
69
|
+
this.getGridApi().refreshAllCells(true);
|
|
70
|
+
this.getThemeApi().applyCurrentTheme();
|
|
69
71
|
})
|
|
70
72
|
.then(() => {
|
|
71
73
|
return this.getAdaptableStore().saveStateNow(this._adaptable, this.getAdaptableStore().TheStore.getState());
|
|
72
74
|
});
|
|
73
75
|
});
|
|
74
76
|
}
|
|
77
|
+
applyInitialState(newInitialState) {
|
|
78
|
+
if (newInitialState) {
|
|
79
|
+
this.getOptions().initialState = JSON.parse(JSON.stringify(newInitialState));
|
|
80
|
+
}
|
|
81
|
+
const initialState = (newInitialState ?? this.getInitialState());
|
|
82
|
+
return this.internalApi.applyMergedInitialAndUserState(initialState, this.getPersistentState());
|
|
83
|
+
}
|
|
84
|
+
async remergePersistedState() {
|
|
85
|
+
const config = buildAdaptableStateFunctionConfig(this._adaptable);
|
|
86
|
+
const loadState = this.getOptions().stateOptions.loadState;
|
|
87
|
+
const userState = await loadState(config);
|
|
88
|
+
return this.internalApi.applyMergedInitialAndUserState(this.getInitialState(), userState);
|
|
89
|
+
}
|
|
75
90
|
getAllState() {
|
|
76
91
|
return this.getAdaptableState();
|
|
77
92
|
}
|
|
@@ -5,7 +5,7 @@ import { AdaptablePredicateDef } from '../../AdaptableState/Common/AdaptablePred
|
|
|
5
5
|
import { ColumnFilter } from '../../AdaptableState/Common/ColumnFilter';
|
|
6
6
|
import { GridCell } from '../../AdaptableState/Selection/GridCell';
|
|
7
7
|
import { LayoutColumnFilterAction } from '../../Redux/ActionsReducers/LayoutRedux';
|
|
8
|
-
import { InFilterValueResult } from '../../types';
|
|
8
|
+
import { InFilterValue, InFilterValueResult } from '../../types';
|
|
9
9
|
import { ApiBase } from '../Implementation/ApiBase';
|
|
10
10
|
import { AdaptableFilterHandler } from '../../agGrid/AdaptableFilterHandler';
|
|
11
11
|
export declare class ColumnFilterInternalApi extends ApiBase {
|
|
@@ -58,5 +58,11 @@ export declare class ColumnFilterInternalApi extends ApiBase {
|
|
|
58
58
|
}): Promise<InFilterValueResult>;
|
|
59
59
|
shouldManuallyApplyColumnFilter(columnId: string): boolean;
|
|
60
60
|
getAdaptableFilterHandler(columnId: string): AdaptableFilterHandler | undefined;
|
|
61
|
+
/**
|
|
62
|
+
* Returns the remembered selected In-filter items for a column - used to resolve
|
|
63
|
+
* labels for selected values missing from the current page (lazy pagination).
|
|
64
|
+
* @param columnId column to get the remembered values for
|
|
65
|
+
*/
|
|
66
|
+
getRememberedLazyInFilterValues(columnId: string): InFilterValue[];
|
|
61
67
|
getAllAdaptableFilterHandlers(): AdaptableFilterHandler[];
|
|
62
68
|
}
|
|
@@ -234,6 +234,9 @@ export class ColumnFilterInternalApi extends ApiBase {
|
|
|
234
234
|
getAdaptableFilterHandler(columnId) {
|
|
235
235
|
return this.getAgGridApi().getColumnFilterHandler(columnId);
|
|
236
236
|
}
|
|
237
|
+
getRememberedLazyInFilterValues(columnId) {
|
|
238
|
+
return this.getAdaptableFilterHandler(columnId)?.getRememberedLazyInFilterValues() ?? [];
|
|
239
|
+
}
|
|
237
240
|
getAllAdaptableFilterHandlers() {
|
|
238
241
|
const allFilterableColumns = this.getColumnApi().getFilterableColumns();
|
|
239
242
|
const filterHandlers = allFilterableColumns
|
|
@@ -2,6 +2,11 @@ import { Column, HeaderValueGetterParams, IRowNode } from 'ag-grid-enterprise';
|
|
|
2
2
|
import { AdaptableColumn, AdaptableFormat, AdaptablePredicateDef, ColumnScope, FormatColumn, FormatColumnConfig, FormatColumnTarget, StringFormatterOptions } from '../../types';
|
|
3
3
|
import { ApiBase } from '../Implementation/ApiBase';
|
|
4
4
|
export declare class FormatColumnInternalApi extends ApiBase {
|
|
5
|
+
/**
|
|
6
|
+
* Re-evaluate Format Column styles on affected columns after state changes.
|
|
7
|
+
* Column-model update alone can leave visible cells stale until scroll.
|
|
8
|
+
*/
|
|
9
|
+
refreshFormatColumnPresentation(formatColumns: FormatColumn | FormatColumn[] | undefined): void;
|
|
5
10
|
/**
|
|
6
11
|
* Retrieves all Format Columns in Adaptable State with the `Style` property set
|
|
7
12
|
* @returns format columns
|
|
@@ -27,6 +27,28 @@ function getParentGroup(source) {
|
|
|
27
27
|
return undefined;
|
|
28
28
|
}
|
|
29
29
|
export class FormatColumnInternalApi extends ApiBase {
|
|
30
|
+
refreshFormatColumnPresentation(formatColumns) {
|
|
31
|
+
if (!formatColumns) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const list = Array.isArray(formatColumns) ? formatColumns : [formatColumns];
|
|
35
|
+
const columnIds = new Set();
|
|
36
|
+
for (const formatColumn of list) {
|
|
37
|
+
if (!formatColumn?.Scope) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (this.getColumnScopeApi().scopeIsAll(formatColumn.Scope)) {
|
|
41
|
+
this.getGridApi().refreshAllCells(true);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
this.getColumnScopeApi()
|
|
45
|
+
.getColumnsInScope(formatColumn.Scope)
|
|
46
|
+
.forEach((column) => columnIds.add(column.columnId));
|
|
47
|
+
}
|
|
48
|
+
if (columnIds.size > 0) {
|
|
49
|
+
this.getGridApi().refreshColumns([...columnIds]);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
30
52
|
getAllFormatColumnWithStyle(config) {
|
|
31
53
|
return this.getFormatColumnApi()
|
|
32
54
|
.getFormatColumns(config)
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import { AdaptablePersistentState, AdaptableState } from '../../types';
|
|
1
|
+
import { AdaptablePersistentState, AdaptableState, InitialState } from '../../types';
|
|
2
2
|
import { ApiBase } from '../Implementation/ApiBase';
|
|
3
3
|
export declare class StateInternalApi extends ApiBase {
|
|
4
|
+
/**
|
|
5
|
+
* Startup-equivalent merge: Initial State + user state → store, layout/theme/cells, persist.
|
|
6
|
+
* Does not clear persistence and does not call `loadState` (caller supplies user state).
|
|
7
|
+
*/
|
|
8
|
+
applyMergedInitialAndUserState(initialState: InitialState, userState: AdaptablePersistentState | Record<string, unknown> | null | undefined): Promise<void>;
|
|
4
9
|
getAllStateForDevTools(): AdaptableState;
|
|
5
10
|
/**
|
|
6
11
|
* Replaces persisted Adaptable state with the supplied snapshot (e.g. from DevTools).
|
|
@@ -1,6 +1,50 @@
|
|
|
1
1
|
import { getPersistableState, LoadState, InitState } from '../../Redux/Store/AdaptableStore';
|
|
2
|
+
import { MergeStateFunction } from '../../Redux/Store/AdaptableReduxMerger';
|
|
3
|
+
import { buildAdaptableStateFunctionConfig } from '../../Redux/Store/buildAdaptableStateFunctionConfig';
|
|
4
|
+
import { addUuidsToInitialState } from '../../Utilities/Helpers/AdaptableHelper';
|
|
2
5
|
import { ApiBase } from '../Implementation/ApiBase';
|
|
6
|
+
function deepClone(value) {
|
|
7
|
+
return JSON.parse(JSON.stringify(value ?? null));
|
|
8
|
+
}
|
|
3
9
|
export class StateInternalApi extends ApiBase {
|
|
10
|
+
applyMergedInitialAndUserState(initialState, userState) {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
this.getAdaptableInternalApi().executeWithProgressIndicator('Applying Initial State...', () => {
|
|
13
|
+
try {
|
|
14
|
+
const oldState = this.getAdaptableApi().stateApi.getPersistentState();
|
|
15
|
+
const initialForMerge = addUuidsToInitialState(deepClone(initialState));
|
|
16
|
+
const userForMerge = deepClone(userState ?? {});
|
|
17
|
+
let merged = MergeStateFunction(initialForMerge, userForMerge);
|
|
18
|
+
const stateFunctionConfig = buildAdaptableStateFunctionConfig(this._adaptable);
|
|
19
|
+
merged = this.getOptions().stateOptions.applyState(merged, stateFunctionConfig);
|
|
20
|
+
const agGridOptions = {
|
|
21
|
+
columnDefs: this._adaptable.agGridAdapter.getGridOption('columnDefs'),
|
|
22
|
+
autoGroupColumnDef: this._adaptable.agGridAdapter.getGridOption('autoGroupColumnDef'),
|
|
23
|
+
rowModelType: this._adaptable.agGridAdapter.getGridOption('rowModelType'),
|
|
24
|
+
treeData: this._adaptable.agGridAdapter.getGridOption('treeData'),
|
|
25
|
+
};
|
|
26
|
+
merged = this._adaptable.normalizeAdaptableState(merged, agGridOptions);
|
|
27
|
+
this.getAdaptableStore().TheStore.dispatch(LoadState(merged));
|
|
28
|
+
this.getAdaptableStore().TheStore.dispatch(InitState());
|
|
29
|
+
this._adaptable.refreshLayout();
|
|
30
|
+
this.getGridApi().refreshAllCells(true);
|
|
31
|
+
this.getThemeApi().applyCurrentTheme();
|
|
32
|
+
const newState = this.getAdaptableApi().stateApi.getPersistentState();
|
|
33
|
+
this.getEventApi().internalApi.fireAdaptableStateReloadedEvent(oldState, newState);
|
|
34
|
+
void this.getAdaptableStore()
|
|
35
|
+
.saveStateNow(this._adaptable)
|
|
36
|
+
.then(() => resolve())
|
|
37
|
+
.catch(reject);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
reject(error);
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
this.getUserInterfaceApi().hideProgressIndicator();
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
4
48
|
getAllStateForDevTools() {
|
|
5
49
|
let allState = this.getAdaptableApi().stateApi.getAllState();
|
|
6
50
|
if (allState.Layout && Array.isArray(allState.Layout.Layouts)) {
|
package/src/Api/StateApi.d.ts
CHANGED
|
@@ -42,6 +42,26 @@ export interface StateApi {
|
|
|
42
42
|
* @param newInitialState optional new InitialState to load
|
|
43
43
|
*/
|
|
44
44
|
reloadInitialState(newInitialState?: InitialState): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Merges Initial State into the **current** user state (Revision / Override / KeepUserDefined),
|
|
47
|
+
* without clearing persistence. Same merge as startup, applied at runtime.
|
|
48
|
+
*
|
|
49
|
+
* When `newInitialState` is provided it also updates `AdaptableOptions.initialState`.
|
|
50
|
+
* Omitting it re-applies the current Initial State onto current user state.
|
|
51
|
+
*
|
|
52
|
+
* @param newInitialState optional Initial State to merge (defaults to current Initial State)
|
|
53
|
+
*/
|
|
54
|
+
applyInitialState(newInitialState?: InitialState): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Re-runs the startup merge using **persisted** user state from `StateOptions.loadState`
|
|
57
|
+
* and the current `AdaptableOptions.initialState`. Does not clear persistence.
|
|
58
|
+
*
|
|
59
|
+
* Use when remote/local storage may have changed (or Initial State in options was updated)
|
|
60
|
+
* and you want to re-sync without a full wipe (`reloadInitialState`).
|
|
61
|
+
*
|
|
62
|
+
* Unsaved in-memory-only changes are discarded in favour of what `loadState` returns.
|
|
63
|
+
*/
|
|
64
|
+
remergePersistedState(): Promise<void>;
|
|
45
65
|
/**
|
|
46
66
|
* Copies all Adaptable state to clipboard
|
|
47
67
|
*/
|
|
@@ -2,6 +2,7 @@ import { isArray } from '../../Utilities/Extensions/ArrayExtensions';
|
|
|
2
2
|
import { isObject, merge, mergeWith, } from '../../Utilities/Extensions/ObjectExtensions';
|
|
3
3
|
import { AdaptableLogger } from '../../agGrid/AdaptableLogger';
|
|
4
4
|
import AdaptableHelper from '../../Utilities/Helpers/AdaptableHelper';
|
|
5
|
+
const mergerLogger = new AdaptableLogger('StateMerger');
|
|
5
6
|
function customizer(objValue, srcValue) {
|
|
6
7
|
if (isArray(objValue)) {
|
|
7
8
|
if (!Array.isArray(srcValue)) {
|
|
@@ -66,8 +67,10 @@ export function MergeStateFunction(oldState, newState) {
|
|
|
66
67
|
}
|
|
67
68
|
for (const initialStateModuleName in initialState) {
|
|
68
69
|
if (!state[initialStateModuleName]) {
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
state[initialStateModuleName] = initialState[initialStateModuleName];
|
|
71
|
+
if (initialState[initialStateModuleName]?.Revision != null) {
|
|
72
|
+
mergerLogger.info(`Added section '${initialStateModuleName}' from Initial State (Revision preserved)`, initialState[initialStateModuleName].Revision);
|
|
73
|
+
}
|
|
71
74
|
}
|
|
72
75
|
}
|
|
73
76
|
for (const stateModuleName in state) {
|
|
@@ -75,14 +78,29 @@ export function MergeStateFunction(oldState, newState) {
|
|
|
75
78
|
const stateRevision = state[stateModuleName].Revision ?? 0;
|
|
76
79
|
const initialStateRevision = initialState[stateModuleName].Revision ?? 0;
|
|
77
80
|
const stateRevisionKey = typeof stateRevision === 'object' ? stateRevision.Key : stateRevision;
|
|
78
|
-
|
|
81
|
+
let initialStateRevisionStrategy = 'Override';
|
|
82
|
+
if (typeof initialStateRevision === 'object') {
|
|
83
|
+
const rawStrategy = initialStateRevision.UpdateStrategy ?? initialStateRevision.Behavior;
|
|
84
|
+
if (rawStrategy === 'KeepUserDefined' || rawStrategy === 'Override') {
|
|
85
|
+
initialStateRevisionStrategy = rawStrategy;
|
|
86
|
+
}
|
|
87
|
+
else if (rawStrategy != null) {
|
|
88
|
+
mergerLogger.warn(`Unknown Revision UpdateStrategy '${rawStrategy}' on section '${stateModuleName}'; falling back to Override`, initialStateRevision);
|
|
89
|
+
}
|
|
90
|
+
if (initialStateRevision.UpdateStrategy == null &&
|
|
91
|
+
initialStateRevision.Behavior != null) {
|
|
92
|
+
mergerLogger.info(`Section '${stateModuleName}' uses legacy Revision.Behavior; prefer UpdateStrategy`, initialStateRevision);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
79
95
|
const initialStateRevisionKey = typeof initialStateRevision === 'object' ? initialStateRevision.Key : initialStateRevision;
|
|
80
96
|
if (initialStateRevisionKey > stateRevisionKey) {
|
|
81
|
-
if (
|
|
82
|
-
|
|
97
|
+
if (initialStateRevisionStrategy === 'KeepUserDefined') {
|
|
98
|
+
mergerLogger.info(`Applying Revision on '${stateModuleName}': ${stateRevisionKey} → ${initialStateRevisionKey} (KeepUserDefined)`);
|
|
99
|
+
state[stateModuleName] = ProcessKeepUserDefinedRevision(deepClone(initialState[stateModuleName]), state[stateModuleName]);
|
|
83
100
|
}
|
|
84
101
|
else {
|
|
85
|
-
|
|
102
|
+
mergerLogger.info(`Applying Revision on '${stateModuleName}': ${stateRevisionKey} → ${initialStateRevisionKey} (Override)`);
|
|
103
|
+
state[stateModuleName] = initialState[stateModuleName];
|
|
86
104
|
}
|
|
87
105
|
}
|
|
88
106
|
}
|
|
@@ -255,7 +255,7 @@ export class AdaptableStore {
|
|
|
255
255
|
this.storageEngine.setStateKey(adaptableStateKey);
|
|
256
256
|
this.loadStorageInProgress = true;
|
|
257
257
|
return (this.Load = this.storageEngine
|
|
258
|
-
.load(adaptable, initialState)
|
|
258
|
+
.load(adaptable, initialState ?? adaptable.adaptableOptions.initialState)
|
|
259
259
|
.then((storedState) => {
|
|
260
260
|
if (storedState && this.loadStateOnStartup) {
|
|
261
261
|
this.TheStore.dispatch(LoadState(postProcessState(adaptable.adaptableOptions.stateOptions.applyState(storedState, buildAdaptableStateFunctionConfig(adaptable)))));
|
|
@@ -14,9 +14,21 @@ const getFractionDigitsAfterMultiplier = (input, multiplier, explicitFractionDig
|
|
|
14
14
|
if (multiplier === 1) {
|
|
15
15
|
return getInputFractionDigitCount(input);
|
|
16
16
|
}
|
|
17
|
+
if (!Number.isFinite(multiplier) || multiplier === 0) {
|
|
18
|
+
return getInputFractionDigitCount(input);
|
|
19
|
+
}
|
|
17
20
|
const multiplierPower = Math.round(Math.log10(Math.abs(multiplier)));
|
|
21
|
+
if (!Number.isFinite(multiplierPower)) {
|
|
22
|
+
return getInputFractionDigitCount(input);
|
|
23
|
+
}
|
|
18
24
|
return Math.max(0, getInputFractionDigitCount(input) - multiplierPower);
|
|
19
25
|
};
|
|
26
|
+
const normalizeMultiplier = (multiplier) => {
|
|
27
|
+
if (multiplier == null || !Number.isFinite(multiplier) || multiplier === 0) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
return multiplier;
|
|
31
|
+
};
|
|
20
32
|
export function NumberFormatter(input, options = {}, rowNode, column, api) {
|
|
21
33
|
let preparedInput;
|
|
22
34
|
if (options.Content) {
|
|
@@ -41,11 +53,11 @@ export function NumberFormatter(input, options = {}, rowNode, column, api) {
|
|
|
41
53
|
if (isNaN(n)) {
|
|
42
54
|
return preparedInput.toString();
|
|
43
55
|
}
|
|
44
|
-
|
|
56
|
+
const effectiveMultiplier = normalizeMultiplier(options.Multiplier);
|
|
45
57
|
let multiplierFractionDigits;
|
|
46
|
-
if (
|
|
47
|
-
n *=
|
|
48
|
-
multiplierFractionDigits = getFractionDigitsAfterMultiplier(preparedInput,
|
|
58
|
+
if (effectiveMultiplier !== undefined) {
|
|
59
|
+
n *= effectiveMultiplier;
|
|
60
|
+
multiplierFractionDigits = getFractionDigitsAfterMultiplier(preparedInput, effectiveMultiplier, options.FractionDigits);
|
|
49
61
|
n = parseFloat(n.toFixed(multiplierFractionDigits));
|
|
50
62
|
}
|
|
51
63
|
if (options.IntegerDigits > 20) {
|
|
@@ -5,7 +5,7 @@ export const DEFAULT_SETTINGS_PANEL_NAVIGATION_GROUPS = [
|
|
|
5
5
|
},
|
|
6
6
|
{
|
|
7
7
|
label: 'Layout',
|
|
8
|
-
items: ['Layout', 'CalculatedColumn', 'CustomSort', 'Charting'],
|
|
8
|
+
items: ['Layout', 'CalculatedColumn', 'FreeTextColumn', 'CustomSort', 'Charting'],
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
label: 'Formatting',
|
|
@@ -17,7 +17,7 @@ export const DEFAULT_SETTINGS_PANEL_NAVIGATION_GROUPS = [
|
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
label: 'Notes & Annotations',
|
|
20
|
-
items: ['Alert', 'Note', 'Comment', '
|
|
20
|
+
items: ['Alert', 'Note', 'Comment', 'SystemStatus'],
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
label: 'Export & Import',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { ColumnValuesSelectProps } from '../../FilterForm/ListBoxFilterForm';
|
|
3
|
+
import { InFilterValue } from '../../../../types';
|
|
3
4
|
/** Suggested page size passed to `customInFilterValues` as `context.limit`. */
|
|
4
5
|
export declare const IN_FILTER_VALUES_PAGE_SIZE = 1000;
|
|
5
6
|
export interface FloatingFilterValuesProps {
|
|
@@ -31,6 +32,10 @@ export declare function useDistinctFilterColumnValues(options: {
|
|
|
31
32
|
skipDefaultSearch: boolean;
|
|
32
33
|
searchValueUsedInFilterValue: boolean;
|
|
33
34
|
hasMore: boolean;
|
|
35
|
+
renderInputValues?: (params: {
|
|
36
|
+
selectedValues: InFilterValue[];
|
|
37
|
+
selectedCount: number;
|
|
38
|
+
}) => string;
|
|
34
39
|
};
|
|
35
40
|
setQuickFilterValues: React.Dispatch<React.SetStateAction<{
|
|
36
41
|
values: {
|
|
@@ -41,6 +46,10 @@ export declare function useDistinctFilterColumnValues(options: {
|
|
|
41
46
|
skipDefaultSearch: boolean;
|
|
42
47
|
searchValueUsedInFilterValue: boolean;
|
|
43
48
|
hasMore: boolean;
|
|
49
|
+
renderInputValues?: (params: {
|
|
50
|
+
selectedValues: InFilterValue[];
|
|
51
|
+
selectedCount: number;
|
|
52
|
+
}) => string;
|
|
44
53
|
}>>;
|
|
45
54
|
triggerValuesLoad: (options?: {
|
|
46
55
|
usePrevious: boolean;
|