@adaptabletools/adaptable 24.0.0-canary.4 → 24.0.0-canary.6

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 (104) hide show
  1. package/aql.d.ts +104 -0
  2. package/aql.js +212 -0
  3. package/devtools.d.ts +182 -1
  4. package/index.css +271 -102
  5. package/package.json +2 -1
  6. package/src/AdaptableInterfaces/IAdaptable.d.ts +4 -4
  7. package/src/AdaptableOptions/DefaultAdaptableOptions.js +5 -5
  8. package/src/AdaptableOptions/FlashingCellOptions.d.ts +3 -3
  9. package/src/AdaptableOptions/SettingsPanelOptions.d.ts +6 -4
  10. package/src/AdaptableOptions/StateOptions.d.ts +37 -13
  11. package/src/AdaptableState/AdaptableState.d.ts +2 -0
  12. package/src/AdaptableState/Common/AdaptableAlert.d.ts +15 -0
  13. package/src/AdaptableState/Common/AdaptableAlert.js +9 -0
  14. package/src/AdaptableState/QuickSearchState.d.ts +4 -0
  15. package/src/Api/Events/LayoutChanged.d.ts +5 -3
  16. package/src/Api/Implementation/AlertApiImpl.d.ts +5 -5
  17. package/src/Api/Implementation/AlertApiImpl.js +26 -19
  18. package/src/Api/Implementation/ColumnScopeApiImpl.js +3 -3
  19. package/src/Api/Implementation/StateApiImpl.d.ts +1 -1
  20. package/src/Api/Implementation/StateApiImpl.js +4 -3
  21. package/src/Api/Internal/AlertInternalApi.js +12 -7
  22. package/src/Api/Internal/CalculatedColumnInternalApi.js +1 -1
  23. package/src/Api/Internal/StateInternalApi.d.ts +1 -1
  24. package/src/Api/Internal/StateInternalApi.js +2 -2
  25. package/src/Api/StateApi.d.ts +2 -2
  26. package/src/Redux/ActionsReducers/LayoutRedux.d.ts +3 -3
  27. package/src/Redux/ActionsReducers/QuickSearchRedux.d.ts +0 -4
  28. package/src/Redux/ActionsReducers/QuickSearchRedux.js +3 -7
  29. package/src/Redux/Store/AdaptableReduxLocalStorageEngine.d.ts +8 -0
  30. package/src/Redux/Store/AdaptableReduxLocalStorageEngine.js +12 -12
  31. package/src/Redux/Store/AdaptableStore.d.ts +8 -5
  32. package/src/Redux/Store/AdaptableStore.js +70 -38
  33. package/src/Redux/Store/Interface/IAdaptableStore.d.ts +5 -5
  34. package/src/Redux/Store/Interface/IStorageEngine.d.ts +4 -4
  35. package/src/Redux/Store/StateOptionsGuards.d.ts +58 -0
  36. package/src/Redux/Store/StateOptionsGuards.js +112 -0
  37. package/src/Redux/Store/isTransientReduxAction.d.ts +5 -0
  38. package/src/Redux/Store/isTransientReduxAction.js +19 -0
  39. package/src/Utilities/Constants/DocumentationLinkConstants.d.ts +1 -0
  40. package/src/Utilities/Constants/DocumentationLinkConstants.js +1 -0
  41. package/src/Utilities/Constants/ReduxConstants.d.ts +2 -2
  42. package/src/Utilities/Constants/ReduxConstants.js +5 -5
  43. package/src/Utilities/Helpers/AlertTypeHelper.d.ts +1 -1
  44. package/src/Utilities/Helpers/SettingsPanelHelper.d.ts +14 -0
  45. package/src/Utilities/Helpers/SettingsPanelHelper.js +37 -1
  46. package/src/Utilities/Helpers/UIHelper.d.ts +6 -3
  47. package/src/Utilities/Helpers/UIHelper.js +8 -4
  48. package/src/Utilities/ObjectFactory.js +3 -3
  49. package/src/View/Dashboard/DashboardPopupSections.js +1 -1
  50. package/src/View/GridInfo/GridInfoPopup.js +62 -25
  51. package/src/View/StyledColumn/RangesComponent.js +6 -6
  52. package/src/View/StyledColumn/Wizard/StyledColumnWizardBulletSection.js +2 -2
  53. package/src/View/StyledColumn/Wizard/StyledColumnWizardRangeBarSection.js +4 -4
  54. package/src/View/StyledColumn/Wizard/StyledColumnWizardStyleSection/StyledColumnWizardRangesSection.js +2 -2
  55. package/src/View/StyledColumn/Wizard/StyledColumnWizardStyleSection/StyledColumnWizardStyleSection.js +2 -2
  56. package/src/View/Wizard/CollapsibleWizardCard.d.ts +3 -1
  57. package/src/View/Wizard/CollapsibleWizardCard.js +17 -9
  58. package/src/agGrid/AdaptableAgGrid.d.ts +4 -4
  59. package/src/agGrid/AdaptableAgGrid.js +2 -0
  60. package/src/agGrid/AgGridColumnAdapter.d.ts +1 -1
  61. package/src/agGrid/AgGridColumnAdapter.js +7 -5
  62. package/src/components/aql/QueryBuilder/QueryBuilderInputs.js +12 -2
  63. package/src/env.js +2 -2
  64. package/src/layout-manager/src/normalizeLayoutModel.d.ts +1 -1
  65. package/src/layout-manager/src/simplifyLayoutModel.d.ts +1 -1
  66. package/src/migration/AdaptableUpgradeHelper.d.ts +7 -2
  67. package/src/migration/VersionUpgrade17.js +13 -8
  68. package/src/setupDevTools.js +442 -103
  69. package/src/types.d.ts +1 -1
  70. package/tsconfig.esm.tsbuildinfo +1 -1
  71. package/upgrade.d.ts +1 -0
  72. package/upgrade.js +1 -0
  73. package/vendor/components/Button/index.d.ts +1 -1
  74. package/vendor/components/Button/index.d.ts.map +1 -1
  75. package/vendor/components/Button/index.js.map +1 -1
  76. package/vendor/components/CheckBox/index.d.ts +1 -1
  77. package/vendor/components/CheckBox/index.d.ts.map +1 -1
  78. package/vendor/components/CheckBox/index.js.map +1 -1
  79. package/vendor/components/ColorPicker/colorPickerTab.d.ts +4 -0
  80. package/vendor/components/ColorPicker/colorPickerTab.d.ts.map +1 -0
  81. package/vendor/components/ColorPicker/colorPickerTab.js +50 -0
  82. package/vendor/components/ColorPicker/colorPickerTab.js.map +1 -0
  83. package/vendor/components/ColorPicker/index.d.ts +31 -0
  84. package/vendor/components/ColorPicker/index.d.ts.map +1 -0
  85. package/vendor/components/ColorPicker/index.js +132 -0
  86. package/vendor/components/ColorPicker/index.js.map +1 -0
  87. package/vendor/components/ColorPicker/themeColors.d.ts +24 -0
  88. package/vendor/components/ColorPicker/themeColors.d.ts.map +1 -0
  89. package/vendor/components/ColorPicker/themeColors.js +52 -0
  90. package/vendor/components/ColorPicker/themeColors.js.map +1 -0
  91. package/vendor/components/Combobox/VirtualizedList.d.ts +1 -1
  92. package/vendor/components/Combobox/VirtualizedList.d.ts.map +1 -1
  93. package/vendor/components/Combobox/VirtualizedList.js.map +1 -1
  94. package/vendor/components/Combobox/index.d.ts +1 -1
  95. package/vendor/components/Combobox/index.d.ts.map +1 -1
  96. package/vendor/components/Combobox/index.js.map +1 -1
  97. package/vendor/components/index.css +213 -0
  98. package/vendor/components/index.d.ts +2 -0
  99. package/vendor/components/index.d.ts.map +1 -1
  100. package/vendor/components/index.js +1 -0
  101. package/vendor/components/index.js.map +1 -1
  102. package/vendor/components/ui/combobox.d.ts.map +1 -1
  103. package/vendor/components/ui/combobox.js +1 -1
  104. package/vendor/components/ui/combobox.js.map +1 -1
@@ -1,12 +1,21 @@
1
1
  import { AG_GRID_VERSION } from './agGrid/AgGridModulesAdapter';
2
2
  import { ADAPTABLE_VERSION } from './EnvVars';
3
- import Emitter from './Utilities/Emitter';
3
+ import { resolveVisibleSettingsPanelNavigationGroups } from './Utilities/Helpers/SettingsPanelHelper';
4
+ import { isTransientReduxAction } from './Redux/Store/isTransientReduxAction';
5
+ import { isPivotLayout } from './Utilities/Helpers/Layouts/LayoutHelper';
4
6
  import { debug } from '@infinite-table/infinite-react';
5
7
  import { warnOnce } from './agGrid/AdaptableLogger';
6
8
  let DEV_TOOLS_LISTENING_STARTED = false;
7
9
  let DEV_TOOLS_READY = false;
8
- const __ADAPTABLE_DEVTOOLS_EMITTER = new Emitter();
9
10
  const LOG_LEVELS = ['info', 'success', 'warn', 'error', 'perf'];
11
+ const LOG_CHANNEL_BASES = ['Adaptable', 'LayoutManager'];
12
+ const MAX_LOG_ENTRIES_PER_INSTANCE = 500;
13
+ const MAX_ACTION_ENTRIES_PER_INSTANCE = 200;
14
+ const DEFAULT_LOG_LIMIT = 100;
15
+ const DEFAULT_ACTION_LIMIT = 50;
16
+ const DEVTOOLS_GLOBAL_NAME = '__ADAPTABLE_DEVTOOLS__';
17
+ const PROFILE_TRACKS_STORAGE_KEY = 'adaptableProfileTracks';
18
+ const DEBUG_STORAGE_KEY = 'debug';
10
19
  function serializeForPostMessage(value) {
11
20
  try {
12
21
  const json = JSON.stringify(value);
@@ -17,8 +26,9 @@ function serializeForPostMessage(value) {
17
26
  const seen = new WeakSet();
18
27
  const json = JSON.stringify(value, (_key, val) => {
19
28
  if (typeof val === 'object' && val !== null) {
20
- if (seen.has(val))
29
+ if (seen.has(val)) {
21
30
  return undefined;
31
+ }
22
32
  seen.add(val);
23
33
  }
24
34
  return val;
@@ -34,7 +44,9 @@ function serializeAdaptableStateForPostMessage(state, parentKey) {
34
44
  }
35
45
  try {
36
46
  const json = JSON.stringify(value);
37
- acc[key] = json === undefined ? String(value) : JSON.parse(json);
47
+ if (json !== undefined) {
48
+ acc[key] = JSON.parse(json);
49
+ }
38
50
  }
39
51
  catch (_error) {
40
52
  warnOnce(`Adaptable DevTools: skipping serializing state key "${parentKey ? `${parentKey}.` : ''}${key}"`);
@@ -66,23 +78,88 @@ function isMessageFromDevToolsContentScript(data) {
66
78
  data.target === 'adaptable-page' &&
67
79
  data.source.startsWith('adaptable-devtools-contentscript'));
68
80
  }
69
- function ensureDevToolsReady() {
70
- if (DEV_TOOLS_READY) {
71
- return Promise.resolve();
81
+ const INSTANCE_REGISTRATIONS = new Map();
82
+ const LOG_BUFFERS = new Map();
83
+ const pendingGridRuntimeUpdates = new Map();
84
+ const GRID_RUNTIME_FALLBACK_DELAY_MS = 100;
85
+ function getRegistration(adaptableId) {
86
+ const registration = INSTANCE_REGISTRATIONS.get(adaptableId);
87
+ if (!registration || registration.instance?.isDestroyed) {
88
+ return undefined;
72
89
  }
73
- DEV_TOOLS_READY = true;
74
- console.log('Adaptable DevTools is listening for messages!');
90
+ return registration;
91
+ }
92
+ function getRegisteredApi(adaptableId) {
93
+ return getRegistration(adaptableId)?.api;
94
+ }
95
+ function describeMountedInstances() {
96
+ const ids = [...INSTANCE_REGISTRATIONS.keys()];
97
+ return ids.length ? `Mounted instances: ${ids.map((id) => `"${id}"`).join(', ')}.` : 'No AdapTable instance is mounted.';
98
+ }
99
+ function resolveRegistration(adaptableId) {
100
+ if (adaptableId != null) {
101
+ const registration = getRegistration(adaptableId);
102
+ if (!registration) {
103
+ throw new Error(`Adaptable DevTools: no mounted AdapTable instance with adaptableId "${adaptableId}". ${describeMountedInstances()}`);
104
+ }
105
+ return registration;
106
+ }
107
+ const ids = [...INSTANCE_REGISTRATIONS.keys()];
108
+ if (ids.length === 1) {
109
+ return INSTANCE_REGISTRATIONS.get(ids[0]);
110
+ }
111
+ if (!ids.length) {
112
+ throw new Error('Adaptable DevTools: no AdapTable instance is mounted yet (wait for the grid to be ready, then retry).');
113
+ }
114
+ throw new Error(`Adaptable DevTools: ${ids.length} AdapTable instances are mounted; pass an adaptableId. ${describeMountedInstances()}`);
115
+ }
116
+ let LOG_INTENT_LISTENING_STARTED = false;
117
+ function parseLogChannel(channel) {
118
+ const channelParts = channel.split(':');
119
+ const [channelBase, adaptableId] = channelParts;
120
+ if (!LOG_CHANNEL_BASES.includes(channelBase)) {
121
+ return null;
122
+ }
123
+ if (channelBase === 'LayoutManager' && adaptableId === 'Diffing') {
124
+ return null;
125
+ }
126
+ if (!adaptableId) {
127
+ return null;
128
+ }
129
+ const level = channelParts.find((part) => LOG_LEVELS.includes(part));
130
+ return { adaptableId, level: level ?? 'info' };
131
+ }
132
+ function bufferLogEntry(entry) {
133
+ let buffer = LOG_BUFFERS.get(entry.adaptableId);
134
+ if (!buffer) {
135
+ buffer = [];
136
+ LOG_BUFFERS.set(entry.adaptableId, buffer);
137
+ }
138
+ buffer.push(entry);
139
+ if (buffer.length > MAX_LOG_ENTRIES_PER_INSTANCE) {
140
+ buffer.splice(0, buffer.length - MAX_LOG_ENTRIES_PER_INSTANCE);
141
+ }
142
+ }
143
+ function ensureLogIntentListening() {
144
+ if (LOG_INTENT_LISTENING_STARTED) {
145
+ return;
146
+ }
147
+ LOG_INTENT_LISTENING_STARTED = true;
75
148
  debug.onLogIntent('*', (logOptions) => {
76
149
  const { channel, color, timestamp, args } = logOptions;
77
- const channelParts = channel.split(':');
78
- const [channelBase, adaptableId] = channelParts;
79
- if (!['Adaptable', 'LayoutManager'].includes(channelBase)) {
150
+ const parsed = parseLogChannel(channel);
151
+ if (!parsed) {
80
152
  return;
81
153
  }
82
- if (channelBase === 'LayoutManager' && adaptableId === 'Diffing') {
83
- return;
84
- }
85
- if (!adaptableId) {
154
+ const formattedArgs = args.map((arg) => formatLogArgForPostMessage(arg));
155
+ bufferLogEntry({
156
+ timestamp,
157
+ adaptableId: parsed.adaptableId,
158
+ channel,
159
+ level: parsed.level,
160
+ args: formattedArgs,
161
+ });
162
+ if (!DEV_TOOLS_READY) {
86
163
  return;
87
164
  }
88
165
  window.postMessage({
@@ -90,16 +167,29 @@ function ensureDevToolsReady() {
90
167
  url: getPageUrlOfWindow(),
91
168
  type: 'log',
92
169
  payload: {
93
- adaptableId,
170
+ adaptableId: parsed.adaptableId,
94
171
  channel,
95
172
  color,
96
- level: channelParts.find((part) => LOG_LEVELS.includes(part)) ?? 'info',
173
+ level: parsed.level,
97
174
  timestamp,
98
- args: args.map((arg) => serializeForPostMessage(formatLogArgForPostMessage(arg))),
175
+ args: formattedArgs.map((arg) => serializeForPostMessage(arg)),
99
176
  },
100
177
  });
101
178
  });
102
- return __ADAPTABLE_DEVTOOLS_EMITTER.emit('ready');
179
+ }
180
+ function ensureDevToolsReady() {
181
+ if (DEV_TOOLS_READY) {
182
+ return;
183
+ }
184
+ DEV_TOOLS_READY = true;
185
+ console.log('Adaptable DevTools is listening for messages!');
186
+ for (const [adaptableId, registration] of INSTANCE_REGISTRATIONS) {
187
+ if (registration.instance?.isDestroyed) {
188
+ continue;
189
+ }
190
+ postMountMessage(adaptableId, registration.api);
191
+ postStateChangeMessage(adaptableId, { api: registration.api });
192
+ }
103
193
  }
104
194
  function handleOpenSettingsPanelMessage(payload) {
105
195
  const { adaptableId, moduleName } = payload ?? {};
@@ -107,18 +197,12 @@ function handleOpenSettingsPanelMessage(payload) {
107
197
  console.warn('Adaptable DevTools: open-settings-panel message missing adaptableId');
108
198
  return;
109
199
  }
110
- const instance = REGISTERED_ADAPTABLE_INSTANCES.get(adaptableId);
111
- if (instance?.isDestroyed) {
112
- console.warn(`Adaptable DevTools: instance "${adaptableId}" is destroyed; cannot open settings panel`);
113
- return;
200
+ try {
201
+ openSettingsPanel(adaptableId, moduleName);
114
202
  }
115
- const api = instance?.api ?? REGISTERED_ADAPTABLE_APIS.get(adaptableId);
116
- const settingsPanelApi = api?.settingsPanelApi;
117
- if (!settingsPanelApi) {
118
- console.warn(`Adaptable DevTools: settings panel is not available for "${adaptableId}" (instance not ready or destroyed)`);
119
- return;
203
+ catch (error) {
204
+ console.warn(error.message);
120
205
  }
121
- settingsPanelApi.openSettingsPanel(moduleName);
122
206
  }
123
207
  function applyThemeToDocumentElement(payload) {
124
208
  const style = document.documentElement.style;
@@ -160,7 +244,7 @@ function handleLoadVariantMessage(payload) {
160
244
  console.warn('Adaptable DevTools: load-variant message missing adaptableId or variant');
161
245
  return;
162
246
  }
163
- const api = REGISTERED_ADAPTABLE_APIS.get(adaptableId);
247
+ const api = getRegisteredApi(adaptableId);
164
248
  if (!api) {
165
249
  console.warn(`Adaptable DevTools: no registered instance for "${adaptableId}"`);
166
250
  return;
@@ -179,23 +263,279 @@ function handleRestoreStateMessage(payload) {
179
263
  console.warn('Adaptable DevTools: restore-state message missing adaptableId or state');
180
264
  return;
181
265
  }
182
- const api = REGISTERED_ADAPTABLE_APIS.get(adaptableId);
183
- if (!api) {
184
- console.warn(`Adaptable DevTools: no registered instance for "${adaptableId}"`);
185
- return;
186
- }
187
- void api.stateApi.internalApi.restoreState(state).catch((error) => {
266
+ void restoreState(adaptableId, state).catch((error) => {
188
267
  console.error(`Adaptable DevTools: failed to restore state for "${adaptableId}"`, error);
189
268
  });
190
269
  }
270
+ function openSettingsPanel(adaptableId, moduleName) {
271
+ const { api } = resolveRegistration(adaptableId);
272
+ const settingsPanelApi = api?.settingsPanelApi;
273
+ if (!settingsPanelApi) {
274
+ throw new Error(`Adaptable DevTools: settings panel is not available for "${adaptableId}" (instance not ready or destroyed)`);
275
+ }
276
+ settingsPanelApi.openSettingsPanel(moduleName);
277
+ }
278
+ function restoreState(adaptableId, state) {
279
+ if (!state || typeof state !== 'object') {
280
+ return Promise.reject(new Error('Adaptable DevTools: restoreState needs a state object'));
281
+ }
282
+ const { api } = resolveRegistration(adaptableId);
283
+ return api.stateApi.internalApi.restoreState(state);
284
+ }
285
+ function buildGridRuntime(api) {
286
+ const selectedRowInfo = api.gridApi.getSelectedRowInfo();
287
+ return {
288
+ allRowsCount: api.gridApi.getRowCount(),
289
+ visibleRowsCount: api.gridApi.getVisibleRowCount(),
290
+ selectedRowsCount: selectedRowInfo?.gridRows?.length ?? 0,
291
+ };
292
+ }
293
+ function buildInstanceSummary(api) {
294
+ const options = api.optionsApi.getAdaptableOptions();
295
+ const globalObject = typeof globalThis !== 'undefined' ? globalThis : window;
296
+ const licenseKey = globalObject.ADAPTABLE_LICENSE_KEY ||
297
+ options.licenseKey;
298
+ return {
299
+ licenseKey: licenseKey || undefined,
300
+ userName: api.optionsApi.getUserName(),
301
+ primaryKey: api.optionsApi.getPrimaryKey(),
302
+ };
303
+ }
304
+ function buildInstanceInfo(adaptableId, api) {
305
+ const { userName, primaryKey } = buildInstanceSummary(api);
306
+ return {
307
+ adaptableId,
308
+ adaptableVersion: ADAPTABLE_VERSION,
309
+ agGridVersion: AG_GRID_VERSION,
310
+ adaptableStateKey: api.optionsApi.getAdaptableStateKey(),
311
+ primaryKey,
312
+ userName,
313
+ gridRuntime: buildGridRuntime(api),
314
+ };
315
+ }
316
+ function getStateSnapshot(api) {
317
+ return api.stateApi.internalApi.getAllStateForDevTools
318
+ ? api.stateApi.internalApi.getAllStateForDevTools()
319
+ : api.stateApi.getAllState();
320
+ }
321
+ function buildColumns(api) {
322
+ const calculated = new Set(api.calculatedColumnApi.getCalculatedColumns().map((c) => c.ColumnId));
323
+ const freeText = new Set(api.freeTextColumnApi.getFreeTextColumns().map((c) => c.ColumnId));
324
+ const action = new Set(api.actionColumnApi.getActionColumns().map((c) => c.columnId));
325
+ const visible = new Set(api.columnApi.getVisibleColumns().map((c) => c.columnId));
326
+ return api.columnApi.getColumns().map((column) => ({
327
+ id: column.columnId,
328
+ friendlyName: column.friendlyName,
329
+ dataType: column.dataType,
330
+ field: column.field,
331
+ columnTypes: column.columnTypes,
332
+ visible: visible.has(column.columnId),
333
+ readOnly: column.readOnly,
334
+ isPrimaryKey: column.isPrimaryKey,
335
+ isGrouped: column.isGrouped,
336
+ pinned: column.pinned,
337
+ isGeneratedRowGroupColumn: column.isGeneratedRowGroupColumn,
338
+ isGeneratedPivotResultColumn: column.isGeneratedPivotResultColumn,
339
+ isCalculatedColumn: calculated.has(column.columnId),
340
+ isFreeTextColumn: freeText.has(column.columnId),
341
+ isActionColumn: action.has(column.columnId),
342
+ }));
343
+ }
344
+ function buildGridInfo(adaptableId, api) {
345
+ const { licenseKey, userName, primaryKey } = buildInstanceSummary(api);
346
+ const currentLayout = api.layoutApi.getCurrentLayout();
347
+ const isPivot = isPivotLayout(currentLayout);
348
+ const selectedRowInfo = api.gridApi.getSelectedRowInfo();
349
+ const available = [];
350
+ const unavailable = [];
351
+ api.internalApi.getModules().forEach((module, moduleName) => {
352
+ (module.isModuleAvailable() ? available : unavailable).push(moduleName);
353
+ });
354
+ return {
355
+ adaptableId,
356
+ adaptableVersion: ADAPTABLE_VERSION,
357
+ agGridVersion: AG_GRID_VERSION,
358
+ adaptableStateKey: api.optionsApi.getAdaptableStateKey(),
359
+ userName,
360
+ primaryKey,
361
+ isAutogeneratedPrimaryKey: api.optionsApi.isAutogeneratePrimaryKey(),
362
+ licenseKey,
363
+ layout: {
364
+ name: api.layoutApi.getCurrentLayoutName(),
365
+ type: isPivot ? 'Pivot' : 'Table',
366
+ rowGroups: api.layoutApi.getCurrentRowGroupsColumnIds() ?? [],
367
+ pivotColumns: isPivot ? (currentLayout.PivotColumns ?? []) : [],
368
+ sorts: (api.gridApi.getColumnSorts() ?? []).map((sort) => ({
369
+ columnId: sort.ColumnId,
370
+ sortOrder: sort.SortOrder,
371
+ })),
372
+ },
373
+ columnFilters: api.filterApi.columnFilterApi.columnFiltersToString(api.filterApi.columnFilterApi.getColumnFilters()),
374
+ gridFilter: api.filterApi.gridFilterApi.getCurrentGridFilterExpression() || undefined,
375
+ rows: {
376
+ all: api.gridApi.getRowCount(),
377
+ visible: api.gridApi.getVisibleRowCount(),
378
+ selected: selectedRowInfo?.gridRows?.length ?? 0,
379
+ },
380
+ columns: {
381
+ all: api.gridApi.getColumnCount(),
382
+ visible: api.gridApi.getVisibleColumnCount(),
383
+ calculated: api.calculatedColumnApi.getCalculatedColumns().map((c) => c.ColumnId),
384
+ freeText: api.freeTextColumnApi.getFreeTextColumns().map((c) => c.ColumnId),
385
+ action: api.actionColumnApi.getActionColumns().map((c) => c.columnId),
386
+ },
387
+ modules: { available, unavailable },
388
+ };
389
+ }
390
+ function getLocalStorage() {
391
+ try {
392
+ return typeof localStorage !== 'undefined' ? localStorage : undefined;
393
+ }
394
+ catch {
395
+ return undefined;
396
+ }
397
+ }
398
+ const DEVTOOLS_HELP = `AdapTable DevTools in-page API (window.${DEVTOOLS_GLOBAL_NAME}). Every method returns plain JSON unless noted.
399
+ Omit adaptableId when one instance is mounted.
400
+
401
+ listInstances() -> [{ adaptableId, adaptableVersion, agGridVersion, primaryKey, userName, gridRuntime }]
402
+ getGridInfo(id?) -> versions, layout, filters, row/column counts, modules (the Settings Panel "Grid Info" facts)
403
+ getState(id?, section?) -> full AdapTable State, or one section such as 'Layout' or 'FormatColumn'
404
+ getPersistentState(id?) -> the user state AdapTable persists; pass it to the MCP check_state / migrate_state tools
405
+ getColumns(id?) -> [{ id, friendlyName, dataType, visible, ... }]; { id, dataType } is the MCP "columns" input
406
+ getLogs(id?, { level?, channel?, limit? }) -> recent AdapTable log messages, buffered without localStorage.debug
407
+ getRecentActions(id?, limit?) -> recent state-changing actions
408
+ restoreState(id, state) -> Promise; restores a snapshot from getState()/getPersistentState()
409
+ openSettingsPanel(id?, moduleName?) -> opens the Settings Panel (e.g. 'Layout', 'FormatColumn')
410
+ setLogging(pattern | null) -> sets localStorage.debug (e.g. 'Adaptable:<id>:*'); returns the previous value
411
+ enableProfiling(enabled?) -> toggles localStorage.adaptableProfileTracks
412
+ getApi(id?) -> the live AdaptableApi (not serializable)
413
+
414
+ Docs: https://www.adaptabletools.com/docs/dev-guide-support-devtools`;
415
+ function createDevToolsGlobal() {
416
+ return {
417
+ help() {
418
+ return DEVTOOLS_HELP;
419
+ },
420
+ listInstances() {
421
+ const result = [];
422
+ for (const [adaptableId, registration] of INSTANCE_REGISTRATIONS) {
423
+ if (registration.instance?.isDestroyed) {
424
+ continue;
425
+ }
426
+ result.push(buildInstanceInfo(adaptableId, registration.api));
427
+ }
428
+ return result;
429
+ },
430
+ getState(adaptableId, section) {
431
+ const { api } = resolveRegistration(adaptableId);
432
+ const state = serializeAdaptableStateForPostMessage(getStateSnapshot(api));
433
+ if (section == null) {
434
+ return state;
435
+ }
436
+ if (!(section in state)) {
437
+ throw new Error(`Adaptable DevTools: unknown state section "${String(section)}". Sections: ${Object.keys(state).join(', ')}`);
438
+ }
439
+ return state[section];
440
+ },
441
+ getPersistentState(adaptableId) {
442
+ const { api } = resolveRegistration(adaptableId);
443
+ return serializeForPostMessage(api.stateApi.getPersistentState());
444
+ },
445
+ getColumns(adaptableId) {
446
+ const { api } = resolveRegistration(adaptableId);
447
+ return serializeForPostMessage(buildColumns(api));
448
+ },
449
+ getGridInfo(adaptableId) {
450
+ const registration = resolveRegistration(adaptableId);
451
+ const id = adaptableId ?? registration.api.optionsApi.getAdaptableId();
452
+ return serializeForPostMessage(buildGridInfo(id, registration.api));
453
+ },
454
+ getLogs(adaptableId, options) {
455
+ const registration = resolveRegistration(adaptableId);
456
+ const id = adaptableId ?? registration.api.optionsApi.getAdaptableId();
457
+ const { level, channel, limit = DEFAULT_LOG_LIMIT } = options ?? {};
458
+ const levels = level == null ? null : new Set(Array.isArray(level) ? level : [level]);
459
+ const entries = (LOG_BUFFERS.get(id) ?? []).filter((entry) => (!levels || levels.has(entry.level)) && (!channel || entry.channel.includes(channel)));
460
+ return entries.slice(Math.max(0, entries.length - limit)).map((entry) => ({ ...entry }));
461
+ },
462
+ getRecentActions(adaptableId, limit = DEFAULT_ACTION_LIMIT) {
463
+ const { actions } = resolveRegistration(adaptableId);
464
+ return actions.slice(Math.max(0, actions.length - limit)).map((entry) => ({ ...entry }));
465
+ },
466
+ restoreState(adaptableId, state) {
467
+ return restoreState(adaptableId, state);
468
+ },
469
+ openSettingsPanel(adaptableId, moduleName) {
470
+ openSettingsPanel(adaptableId, moduleName);
471
+ },
472
+ setLogging(pattern) {
473
+ const storage = getLocalStorage();
474
+ if (!storage) {
475
+ throw new Error('Adaptable DevTools: localStorage is not available');
476
+ }
477
+ const previous = storage.getItem(DEBUG_STORAGE_KEY);
478
+ if (pattern == null || pattern === '') {
479
+ storage.removeItem(DEBUG_STORAGE_KEY);
480
+ }
481
+ else {
482
+ storage.setItem(DEBUG_STORAGE_KEY, pattern);
483
+ }
484
+ return previous;
485
+ },
486
+ enableProfiling(enabled = true) {
487
+ const storage = getLocalStorage();
488
+ if (!storage) {
489
+ throw new Error('Adaptable DevTools: localStorage is not available');
490
+ }
491
+ if (enabled) {
492
+ storage.setItem(PROFILE_TRACKS_STORAGE_KEY, 'true');
493
+ }
494
+ else {
495
+ storage.removeItem(PROFILE_TRACKS_STORAGE_KEY);
496
+ }
497
+ },
498
+ getApi(adaptableId) {
499
+ return resolveRegistration(adaptableId).api;
500
+ },
501
+ };
502
+ }
503
+ function ensureDevToolsGlobal() {
504
+ if (typeof window === 'undefined') {
505
+ return;
506
+ }
507
+ if (!window[DEVTOOLS_GLOBAL_NAME]) {
508
+ Object.defineProperty(window, DEVTOOLS_GLOBAL_NAME, {
509
+ value: createDevToolsGlobal(),
510
+ writable: false,
511
+ configurable: true,
512
+ enumerable: false,
513
+ });
514
+ }
515
+ }
516
+ function setupDevToolsOnLoad() {
517
+ if (typeof window === 'undefined') {
518
+ return;
519
+ }
520
+ ensureDevToolsGlobal();
521
+ ensureLogIntentListening();
522
+ }
523
+ setupDevToolsOnLoad();
191
524
  export function listenForDevTools(adaptableInstance) {
192
- if (typeof window !== 'undefined' && !DEV_TOOLS_LISTENING_STARTED) {
525
+ if (typeof window === 'undefined') {
526
+ return;
527
+ }
528
+ setupDevToolsOnLoad();
529
+ if (!DEV_TOOLS_LISTENING_STARTED) {
193
530
  DEV_TOOLS_LISTENING_STARTED = true;
194
531
  window.addEventListener('message', (event) => {
532
+ if (event.source !== window) {
533
+ return;
534
+ }
195
535
  if (!isMessageFromDevToolsContentScript(event.data)) {
196
536
  return;
197
537
  }
198
- void ensureDevToolsReady();
538
+ ensureDevToolsReady();
199
539
  const handlers = {
200
540
  'restore-state': handleRestoreStateMessage,
201
541
  'open-settings-panel': handleOpenSettingsPanelMessage,
@@ -206,28 +546,12 @@ export function listenForDevTools(adaptableInstance) {
206
546
  handlers[event.data.type]?.(event.data.payload);
207
547
  });
208
548
  }
209
- __ADAPTABLE_DEVTOOLS_EMITTER.onIncludeFiredOnce('ready').then(() => {
210
- const { api, adaptableOptions } = adaptableInstance;
211
- if (!api || !adaptableOptions) {
212
- console.error('Cannot register Adaptable instance in DevTools because it is not ready', adaptableInstance);
213
- return;
214
- }
215
- registerAdaptableInstanceInDevTools(adaptableOptions.adaptableId, { api }, adaptableInstance);
216
- });
217
- }
218
- const REGISTERED_ADAPTABLE_IDS = new Set();
219
- const REGISTERED_ADAPTABLE_APIS = new Map();
220
- const REGISTERED_ADAPTABLE_INSTANCES = new Map();
221
- const pendingGridRuntimeUpdates = new Map();
222
- const GRID_RUNTIME_FALLBACK_DELAY_MS = 100;
223
- const INSTANCE_REGISTRATIONS = new Map();
224
- function buildGridRuntime(api) {
225
- const selectedRowInfo = api.gridApi.getSelectedRowInfo();
226
- return {
227
- allRowsCount: api.gridApi.getRowCount(),
228
- visibleRowsCount: api.gridApi.getVisibleRowCount(),
229
- selectedRowsCount: selectedRowInfo?.gridRows?.length ?? 0,
230
- };
549
+ const { api, adaptableOptions } = adaptableInstance;
550
+ if (!api || !adaptableOptions) {
551
+ console.error('Cannot register Adaptable instance in DevTools because it is not ready', adaptableInstance);
552
+ return;
553
+ }
554
+ registerAdaptableInstanceInDevTools(adaptableOptions.adaptableId, api, adaptableInstance);
231
555
  }
232
556
  function postMountMessage(adaptableId, api) {
233
557
  window.postMessage(buildMessageForExtension({
@@ -235,7 +559,8 @@ function postMountMessage(adaptableId, api) {
235
559
  adaptableId,
236
560
  adaptableVersion: ADAPTABLE_VERSION,
237
561
  agGridVersion: AG_GRID_VERSION,
238
- licenseKey: api.optionsApi.getAdaptableOptions().licenseKey,
562
+ ...buildInstanceSummary(api),
563
+ settingsPanelNavigation: resolveVisibleSettingsPanelNavigationGroups(api),
239
564
  }));
240
565
  }
241
566
  function cancelScheduledGridRuntimeUpdate(adaptableId) {
@@ -253,28 +578,31 @@ function scheduleGridRuntimeUpdate(adaptableId, api, delayMs = GRID_RUNTIME_FALL
253
578
  }, delayMs));
254
579
  }
255
580
  function postStateChangeMessage(adaptableId, options) {
256
- const api = options?.api ?? REGISTERED_ADAPTABLE_APIS.get(adaptableId);
581
+ const api = options?.api ?? getRegisteredApi(adaptableId);
257
582
  if (!api) {
258
583
  return;
259
584
  }
260
- const state = api.stateApi.internalApi.getAllStateForDevTools
261
- ? api.stateApi.internalApi.getAllStateForDevTools()
262
- : api.stateApi.getAllState();
263
585
  window.postMessage(buildMessageForExtension({
264
586
  type: 'state-change',
265
587
  adaptableId,
266
- state: serializeAdaptableStateForPostMessage(state),
588
+ state: serializeAdaptableStateForPostMessage(getStateSnapshot(api)),
267
589
  actionName: options?.actionName,
590
+ ...buildInstanceSummary(api),
591
+ settingsPanelNavigation: resolveVisibleSettingsPanelNavigationGroups(api),
268
592
  }));
269
593
  if (options?.api) {
270
594
  scheduleGridRuntimeUpdate(adaptableId, options.api);
271
595
  }
272
596
  }
273
597
  function postGridRuntimeUpdate(adaptableId, api) {
598
+ if (!DEV_TOOLS_READY) {
599
+ return;
600
+ }
274
601
  window.postMessage(buildMessageForExtension({
275
602
  type: 'state-change',
276
603
  adaptableId,
277
604
  gridRuntime: buildGridRuntime(api),
605
+ ...buildInstanceSummary(api),
278
606
  }));
279
607
  }
280
608
  function detachAdaptableInstanceListeners(adaptableId) {
@@ -284,13 +612,13 @@ function detachAdaptableInstanceListeners(adaptableId) {
284
612
  registration.unsubscribe();
285
613
  INSTANCE_REGISTRATIONS.delete(adaptableId);
286
614
  }
287
- REGISTERED_ADAPTABLE_IDS.delete(adaptableId);
288
- REGISTERED_ADAPTABLE_APIS.delete(adaptableId);
289
- REGISTERED_ADAPTABLE_INSTANCES.delete(adaptableId);
290
615
  }
291
616
  function unregisterAdaptableInstanceFromDevTools(adaptableId) {
292
617
  detachAdaptableInstanceListeners(adaptableId);
293
- window.postMessage(buildMessageForExtension({ type: 'unmount', adaptableId }));
618
+ LOG_BUFFERS.delete(adaptableId);
619
+ if (DEV_TOOLS_READY) {
620
+ window.postMessage(buildMessageForExtension({ type: 'unmount', adaptableId }));
621
+ }
294
622
  }
295
623
  const messageBase = {
296
624
  source: 'adaptable-page',
@@ -324,6 +652,9 @@ function buildMessageForExtension(params) {
324
652
  adaptableVersion: payload?.adaptableVersion,
325
653
  agGridVersion: payload?.agGridVersion,
326
654
  licenseKey: payload?.licenseKey,
655
+ userName: payload?.userName,
656
+ primaryKey: payload?.primaryKey,
657
+ settingsPanelNavigation: payload?.settingsPanelNavigation,
327
658
  },
328
659
  };
329
660
  }
@@ -337,6 +668,10 @@ function buildMessageForExtension(params) {
337
668
  state: payload?.state,
338
669
  actionName: payload?.actionName,
339
670
  gridRuntime: payload?.gridRuntime,
671
+ licenseKey: payload?.licenseKey,
672
+ userName: payload?.userName,
673
+ primaryKey: payload?.primaryKey,
674
+ settingsPanelNavigation: payload?.settingsPanelNavigation,
340
675
  },
341
676
  };
342
677
  }
@@ -351,30 +686,34 @@ function buildMessageForExtension(params) {
351
686
  };
352
687
  return message;
353
688
  }
354
- function publishStateSnapshot(adaptableId) {
355
- const api = REGISTERED_ADAPTABLE_APIS.get(adaptableId);
356
- if (!api) {
357
- return;
689
+ function recordAction(registration, actionName) {
690
+ registration.actions.push({ timestamp: Date.now(), actionName });
691
+ if (registration.actions.length > MAX_ACTION_ENTRIES_PER_INSTANCE) {
692
+ registration.actions.splice(0, registration.actions.length - MAX_ACTION_ENTRIES_PER_INSTANCE);
358
693
  }
359
- postStateChangeMessage(adaptableId, { api });
360
694
  }
361
- function registerAdaptableInstanceInDevTools(adaptableId, options, adaptableInstance) {
362
- const { api } = options;
695
+ function registerAdaptableInstanceInDevTools(adaptableId, api, adaptableInstance) {
363
696
  detachAdaptableInstanceListeners(adaptableId);
364
- console.log(`Registering instance "${adaptableId}" into Adaptable DevTools`);
365
- REGISTERED_ADAPTABLE_IDS.add(adaptableId);
366
- REGISTERED_ADAPTABLE_APIS.set(adaptableId, api);
367
- if (adaptableInstance) {
368
- REGISTERED_ADAPTABLE_INSTANCES.set(adaptableId, adaptableInstance);
369
- }
697
+ const registration = {
698
+ api,
699
+ instance: adaptableInstance,
700
+ actions: [],
701
+ unsubscribe: () => { },
702
+ };
370
703
  const onStateChange = (info) => {
371
- postStateChangeMessage(adaptableId, { actionName: info.actionName, api });
704
+ if (isTransientReduxAction(info.actionName)) {
705
+ return;
706
+ }
707
+ recordAction(registration, info.actionName);
708
+ if (DEV_TOOLS_READY) {
709
+ postStateChangeMessage(adaptableId, { actionName: info.actionName, api });
710
+ }
372
711
  };
373
712
  const onStateReloaded = () => {
374
- postStateChangeMessage(adaptableId, {
375
- actionName: 'AdaptableStateReloaded',
376
- api,
377
- });
713
+ recordAction(registration, 'AdaptableStateReloaded');
714
+ if (DEV_TOOLS_READY) {
715
+ postStateChangeMessage(adaptableId, { actionName: 'AdaptableStateReloaded', api });
716
+ }
378
717
  };
379
718
  const unsubscribeStateChanged = api.eventApi.on('AdaptableStateChanged', onStateChange);
380
719
  const unsubscribeStateReloaded = api.eventApi.on('AdaptableStateReloaded', onStateReloaded);
@@ -384,21 +723,21 @@ function registerAdaptableInstanceInDevTools(adaptableId, options, adaptableInst
384
723
  const unsubscribeDestroy = api.eventApi.on('AdaptableDestroy', () => {
385
724
  unregisterAdaptableInstanceFromDevTools(adaptableId);
386
725
  });
387
- const adaptableGrid = adaptableInstance ?? REGISTERED_ADAPTABLE_INSTANCES.get(adaptableId);
388
- const unsubscribeFiltersApplied = adaptableGrid?._on('AdapTableFiltersApplied', () => {
726
+ const unsubscribeFiltersApplied = adaptableInstance._on('AdapTableFiltersApplied', () => {
389
727
  cancelScheduledGridRuntimeUpdate(adaptableId);
390
728
  postGridRuntimeUpdate(adaptableId, api);
391
729
  });
392
- INSTANCE_REGISTRATIONS.set(adaptableId, {
393
- api,
394
- unsubscribe: () => {
395
- unsubscribeStateChanged();
396
- unsubscribeStateReloaded();
397
- unsubscribeRowSelectionChanged();
398
- unsubscribeFiltersApplied?.();
399
- unsubscribeDestroy();
400
- },
401
- });
402
- postMountMessage(adaptableId, api);
403
- publishStateSnapshot(adaptableId);
730
+ registration.unsubscribe = () => {
731
+ unsubscribeStateChanged();
732
+ unsubscribeStateReloaded();
733
+ unsubscribeRowSelectionChanged();
734
+ unsubscribeFiltersApplied?.();
735
+ unsubscribeDestroy();
736
+ };
737
+ INSTANCE_REGISTRATIONS.set(adaptableId, registration);
738
+ if (DEV_TOOLS_READY) {
739
+ console.log(`Registering instance "${adaptableId}" into Adaptable DevTools`);
740
+ postMountMessage(adaptableId, api);
741
+ postStateChangeMessage(adaptableId, { api });
742
+ }
404
743
  }