@adaptabletools/adaptable-cjs 23.0.2 → 23.0.4-canary.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adaptabletools/adaptable-cjs",
3
- "version": "23.0.2",
3
+ "version": "23.0.4-canary.0",
4
4
  "description": "Powerful AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements",
5
5
  "keywords": [
6
6
  "web-components",
@@ -49,7 +49,6 @@
49
49
  "@tanstack/react-virtual": "^3.13.22",
50
50
  "class-variance-authority": "^0.7.1",
51
51
  "clsx": "^2.1.1",
52
- "cron-parser": "^4.9.0",
53
52
  "date-fns": "^4.1.0",
54
53
  "lucide-react": "^0.563.0",
55
54
  "normalize.css": "^8.0.1",
@@ -7,7 +7,7 @@ import { CustomRenderContext } from '../agGrid/AdaptableFrameworkComponent';
7
7
  */
8
8
  export interface SettingsPanelOptions {
9
9
  /**
10
- * Title for the Settings Panel
10
+ * Title for Settings Panel
11
11
  *
12
12
  * @defaultValue 'Settings Panel'
13
13
  */
@@ -45,7 +45,7 @@ export interface SettingsPanelOptions {
45
45
  */
46
46
  navigation?: SettingsPanelNavigationConfigurer;
47
47
  /**
48
- * Initial position of Settings Panel window
48
+ * Initial position of Settings Panel — pixel offset of top-left corner from top-left of viewport (requires `popupType` to be `'window'`)
49
49
  *
50
50
  * @defaultValue Middle of Screen
51
51
  */
@@ -54,7 +54,7 @@ export interface SettingsPanelOptions {
54
54
  y: number;
55
55
  };
56
56
  /**
57
- * Initial size of Settings Panel
57
+ * Initial size (in pixels) of Settings Panel (requires `popupType` to be `'window'`)
58
58
  *
59
59
  * @defaultValue Computed based on size of screen
60
60
  */
@@ -63,7 +63,7 @@ export interface SettingsPanelOptions {
63
63
  height: number;
64
64
  };
65
65
  /**
66
- * Whether Settings Panel is 'window' (i.e. movable, resizable, no backdrop) or 'modal' (centre of screen with backdrop)
66
+ * How the Settings Panel is rendered: `'modal'` (centred and unmovable and resizable) or `'window'` (supports size, position, drag and resize)
67
67
  *
68
68
  * @defaultValue 'modal'
69
69
  */
@@ -38,6 +38,24 @@ export interface GridApi {
38
38
  * Retrieves visible data from the grid (filtered and sorted)
39
39
  */
40
40
  getVisibleData(): any[];
41
+ /**
42
+ * Retrieves all the values for a single Column.
43
+ *
44
+ * @param columnId the Column to read the values from
45
+ */
46
+ getColumnData(columnId: string): any[];
47
+ /**
48
+ * Retrieves the filtered values for a single Column.
49
+ *
50
+ * @param columnId the Column to read the values from
51
+ */
52
+ getFilteredColumnData(columnId: string): any[];
53
+ /**
54
+ * Retrieves the visible (filtered and sorted) values for a single Column.
55
+ *
56
+ * @param columnId the Column to read the values from
57
+ */
58
+ getVisibleColumnData(columnId: string): any[];
41
59
  /**
42
60
  * Loads data into grid and fire a `RowChanged.trigger='Load'` event
43
61
  * @param data data to load
@@ -27,6 +27,9 @@ export declare class GridApiImpl extends ApiBase implements GridApi {
27
27
  getGridData(): any[];
28
28
  getFilteredData(): any[];
29
29
  getVisibleData(): any[];
30
+ getColumnData(columnId: string): any[];
31
+ getFilteredColumnData(columnId: string): any[];
32
+ getVisibleColumnData(columnId: string): any[];
30
33
  updateGridData(dataRows: any[], dataUpdateConfig?: DataUpdateConfig): Promise<IRowNode[]>;
31
34
  addOrUpdateGridData(dataRows: any[], dataUpdateConfig?: DataUpdateConfig): Promise<{
32
35
  addedRows: IRowNode[];
@@ -51,6 +51,33 @@ class GridApiImpl extends ApiBase_1.ApiBase {
51
51
  });
52
52
  return data;
53
53
  }
54
+ getColumnData(columnId) {
55
+ const data = [];
56
+ this._adaptable.forAllRowNodesDo((rowNode) => {
57
+ if (!this.isGroupRowNode(rowNode)) {
58
+ data.push(this.getRawValueFromRowNode(rowNode, columnId));
59
+ }
60
+ });
61
+ return data;
62
+ }
63
+ getFilteredColumnData(columnId) {
64
+ const data = [];
65
+ this.getAgGridApi().forEachNodeAfterFilter((rowNode) => {
66
+ if (!this.isGroupRowNode(rowNode)) {
67
+ data.push(this.getRawValueFromRowNode(rowNode, columnId));
68
+ }
69
+ });
70
+ return data;
71
+ }
72
+ getVisibleColumnData(columnId) {
73
+ const data = [];
74
+ this.getAdaptableInternalApi().forAllVisibleRowNodesDo((rowNode) => {
75
+ if (!this.isGroupRowNode(rowNode)) {
76
+ data.push(this.getRawValueFromRowNode(rowNode, columnId));
77
+ }
78
+ });
79
+ return data;
80
+ }
54
81
  async updateGridData(dataRows, dataUpdateConfig) {
55
82
  const rowNodes = await this._adaptable.updateRows(dataRows, dataUpdateConfig);
56
83
  const rowDataChangedInfo = this.getAdaptableInternalApi().buildRowDataChangedInfo(dataRows, rowNodes, 'Update');
@@ -1,3 +1,4 @@
1
+ import type { AgChartInstance, AgSparklineOptions } from 'ag-charts-types';
1
2
  import { ApiBase } from './ApiBase';
2
3
  import { StyledColumnApi } from '../StyledColumnApi';
3
4
  import { StyledColumn, StyledColumnState } from '../../AdaptableState/StyledColumnState';
@@ -25,6 +26,7 @@ export declare class StyledColumnApiImpl extends ApiBase implements StyledColumn
25
26
  hasBulletChartStyle(columnId: string): boolean;
26
27
  hasRatingStyle(columnId: string): boolean;
27
28
  canDisplaySparklines(): boolean;
29
+ renderSparkline(options: AgSparklineOptions): AgChartInstance<AgSparklineOptions> | null;
28
30
  suspendStyledColumn(styledColumn: StyledColumn): void;
29
31
  unSuspendStyledColumn(styledColumn: StyledColumn): void;
30
32
  suspendAllStyledColumn(): void;
@@ -83,6 +83,9 @@ class StyledColumnApiImpl extends ApiBase_1.ApiBase {
83
83
  canDisplaySparklines() {
84
84
  return this._adaptable.canDisplaySparklines();
85
85
  }
86
+ renderSparkline(options) {
87
+ return this.internalApi.createSparkline(options);
88
+ }
86
89
  suspendStyledColumn(styledColumn) {
87
90
  this.dispatchAction(StyledColumnRedux.StyledColumnSuspend(styledColumn));
88
91
  }
@@ -4,8 +4,18 @@ import { StyledColumn } from '../../AdaptableState/StyledColumnState';
4
4
  import { CellColorRange, ColumnComparison, NumericStyledColumn } from '../../AdaptableState/StyledColumns/Common/NumericStyledColumn';
5
5
  import { BadgeStyle, BadgeStyleDefinition } from '../../AdaptableState/StyledColumns/BadgeStyle';
6
6
  import { IRowNode } from 'ag-grid-enterprise';
7
+ import type { AgChartInstance, AgSparklineOptions } from 'ag-charts-types';
7
8
  import { PredicateDefHandlerContext } from '../../types';
8
9
  export declare class StyledColumnInternalApi extends ApiBase {
10
+ /**
11
+ * Creates a sparkline described by `options` in its target container and
12
+ * returns the chart instance (used to update / destroy it).
13
+ *
14
+ * Centralises sparkline creation so view components don't import
15
+ * `ag-charts-enterprise` directly: the `createSparkline` factory is sourced
16
+ * from the AG Grid Sparklines module via the grid's registry bean.
17
+ */
18
+ createSparkline(options: AgSparklineOptions): AgChartInstance<AgSparklineOptions> | null;
9
19
  getMinValueForNumericColumn(column: AdaptableColumn | undefined): number | undefined;
10
20
  getMaxValueForNumericColumn(column: AdaptableColumn | undefined): number | undefined;
11
21
  getAvgValueForNumericColumn(column: AdaptableColumn | undefined): number | undefined;
@@ -14,6 +14,26 @@ const DYNAMIC_RANGE_ENDPOINTS = [
14
14
  const isDynamicRangeEndpoint = (value) => typeof value === 'string' &&
15
15
  DYNAMIC_RANGE_ENDPOINTS.includes(value);
16
16
  class StyledColumnInternalApi extends ApiBase_1.ApiBase {
17
+ /**
18
+ * Creates a sparkline described by `options` in its target container and
19
+ * returns the chart instance (used to update / destroy it).
20
+ *
21
+ * Centralises sparkline creation so view components don't import
22
+ * `ag-charts-enterprise` directly: the `createSparkline` factory is sourced
23
+ * from the AG Grid Sparklines module via the grid's registry bean.
24
+ */
25
+ createSparkline(options) {
26
+ if (!this.getStyledColumnApi().canDisplaySparklines()) {
27
+ this.logWarn('Cannot render Sparkline: AG Grid Sparklines are not enabled. Register the AG Grid Sparklines module (e.g. `AllEnterpriseModule.with(AgChartsEnterpriseModule)`) to use Sparklines.');
28
+ return null;
29
+ }
30
+ const createSparklineFactory = this._adaptable.agGridAdapter.DANGER_getCreateSparkline();
31
+ if (!createSparklineFactory) {
32
+ this.logWarn('Cannot render Sparkline: unable to obtain the AG Grid Sparkline rendering factory.');
33
+ return null;
34
+ }
35
+ return createSparklineFactory(options);
36
+ }
17
37
  getMinValueForNumericColumn(column) {
18
38
  if (!column || column.dataType !== 'number') {
19
39
  return undefined;
@@ -1,3 +1,4 @@
1
+ import type { AgChartInstance, AgSparklineOptions } from 'ag-charts-types';
1
2
  import { AdaptableColumn } from '../AdaptableState/Common/AdaptableColumn';
2
3
  import { StyledColumn, StyledColumnState } from '../AdaptableState/StyledColumnState';
3
4
  import { LayoutExtendedConfig } from '../types';
@@ -117,4 +118,17 @@ export interface StyledColumnApi {
117
118
  * Can this AdapTable instance display Sparklines (e.g. is AG Grid SparklinesModule installed)
118
119
  */
119
120
  canDisplaySparklines(): boolean;
121
+ /**
122
+ * Renders a standalone [Sparkline](https://www.ag-grid.com/javascript-data-grid/sparklines-overview/)
123
+ * into a DOM element you provide, using the same AG Charts engine as Sparkline Styled Columns.
124
+ *
125
+ * Provide at least `container` (where to render) and `data` (what to plot) on `options`; see
126
+ * [AgSparklineOptions](https://www.ag-grid.com/javascript-data-grid/sparklines-overview/) for the
127
+ * full set (`type`, `width`/`height`, `min`/`max`, etc.).
128
+ *
129
+ * The caller owns the returned instance and is responsible for its lifecycle: call `update()` to
130
+ * re-render it when the data or options change, and `destroy()` to dispose of it (e.g. when the
131
+ * `container` is removed) to avoid memory leaks. AdapTable does not track or clean it up for you.
132
+ */
133
+ renderSparkline(options: AgSparklineOptions): AgChartInstance<AgSparklineOptions> | null;
120
134
  }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Lightweight, dependency-free parser for standard 5-field cron expressions:
3
+ *
4
+ * minute hour day-of-month month day-of-week
5
+ *
6
+ * Each field supports:
7
+ * - `*` — every value in the field range
8
+ * - A single integer (e.g. `9`)
9
+ * - A comma-separated list (e.g. `1,3,5`)
10
+ * - A range (e.g. `1-5`)
11
+ * - A step (e.g. `* /15`, `0-30/5`)
12
+ *
13
+ * For day-of-week, both `0` and `7` represent Sunday.
14
+ *
15
+ * This module exists to keep AdapTable free of the `cron-parser` package (which
16
+ * transitively pulls in `luxon`). AdapTable only uses cron expressions in the
17
+ * Scheduling system, and only ever needs to:
18
+ * 1. validate a user-entered cron string, and
19
+ * 2. compute the next fire time from "now".
20
+ */
21
+ interface ParsedCron {
22
+ minute: Set<number>;
23
+ hour: Set<number>;
24
+ dayOfMonth: Set<number>;
25
+ month: Set<number>;
26
+ dayOfWeek: Set<number>;
27
+ /** True when the day-of-month field is `*` (i.e. unrestricted). */
28
+ dayOfMonthIsStar: boolean;
29
+ /** True when the day-of-week field is `*` (i.e. unrestricted). */
30
+ dayOfWeekIsStar: boolean;
31
+ }
32
+ /**
33
+ * Parses a 5-field cron expression. Throws when the expression is invalid.
34
+ */
35
+ export declare function parseCronExpression(expression: string): ParsedCron;
36
+ /**
37
+ * Returns true if the given expression is a valid 5-field cron expression.
38
+ */
39
+ export declare function isCronExpressionValid(expression: string): boolean;
40
+ /**
41
+ * Returns the next time the cron expression fires after `fromDate` (exclusive).
42
+ * Returns null if no match is found within a 4-year horizon.
43
+ */
44
+ export declare function getNextCronOccurrence(expression: string, fromDate?: Date): Date | null;
45
+ export {};
@@ -0,0 +1,184 @@
1
+ "use strict";
2
+ /**
3
+ * Lightweight, dependency-free parser for standard 5-field cron expressions:
4
+ *
5
+ * minute hour day-of-month month day-of-week
6
+ *
7
+ * Each field supports:
8
+ * - `*` — every value in the field range
9
+ * - A single integer (e.g. `9`)
10
+ * - A comma-separated list (e.g. `1,3,5`)
11
+ * - A range (e.g. `1-5`)
12
+ * - A step (e.g. `* /15`, `0-30/5`)
13
+ *
14
+ * For day-of-week, both `0` and `7` represent Sunday.
15
+ *
16
+ * This module exists to keep AdapTable free of the `cron-parser` package (which
17
+ * transitively pulls in `luxon`). AdapTable only uses cron expressions in the
18
+ * Scheduling system, and only ever needs to:
19
+ * 1. validate a user-entered cron string, and
20
+ * 2. compute the next fire time from "now".
21
+ */
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.parseCronExpression = parseCronExpression;
24
+ exports.isCronExpressionValid = isCronExpressionValid;
25
+ exports.getNextCronOccurrence = getNextCronOccurrence;
26
+ const MINUTE_RANGE = [0, 59];
27
+ const HOUR_RANGE = [0, 23];
28
+ const DAY_OF_MONTH_RANGE = [1, 31];
29
+ const MONTH_RANGE = [1, 12];
30
+ const FIELD_LABELS = ['minute', 'hour', 'day-of-month', 'month', 'day-of-week'];
31
+ /**
32
+ * Parses a 5-field cron expression. Throws when the expression is invalid.
33
+ */
34
+ function parseCronExpression(expression) {
35
+ if (!expression || typeof expression !== 'string') {
36
+ throw new Error('Cron expression is empty');
37
+ }
38
+ const parts = expression.trim().split(/\s+/);
39
+ if (parts.length !== 5) {
40
+ throw new Error(`Expected 5 cron fields (minute hour day-of-month month day-of-week) but got ${parts.length}`);
41
+ }
42
+ const minute = parseField(parts[0], MINUTE_RANGE, FIELD_LABELS[0]);
43
+ const hour = parseField(parts[1], HOUR_RANGE, FIELD_LABELS[1]);
44
+ const dayOfMonth = parseField(parts[2], DAY_OF_MONTH_RANGE, FIELD_LABELS[2]);
45
+ const month = parseField(parts[3], MONTH_RANGE, FIELD_LABELS[3]);
46
+ const dayOfWeek = parseDayOfWeekField(parts[4]);
47
+ return {
48
+ minute,
49
+ hour,
50
+ dayOfMonth,
51
+ month,
52
+ dayOfWeek,
53
+ dayOfMonthIsStar: parts[2] === '*',
54
+ dayOfWeekIsStar: parts[4] === '*',
55
+ };
56
+ }
57
+ /**
58
+ * Returns true if the given expression is a valid 5-field cron expression.
59
+ */
60
+ function isCronExpressionValid(expression) {
61
+ try {
62
+ parseCronExpression(expression);
63
+ return true;
64
+ }
65
+ catch {
66
+ return false;
67
+ }
68
+ }
69
+ /**
70
+ * Returns the next time the cron expression fires after `fromDate` (exclusive).
71
+ * Returns null if no match is found within a 4-year horizon.
72
+ */
73
+ function getNextCronOccurrence(expression, fromDate = new Date()) {
74
+ const cron = parseCronExpression(expression);
75
+ // Bump to the start of the next minute - cron has minute granularity and
76
+ // we never want to return `fromDate` itself.
77
+ const next = new Date(fromDate.getTime());
78
+ next.setSeconds(0, 0);
79
+ next.setMinutes(next.getMinutes() + 1);
80
+ // Safety horizon — patterns like "0 0 31 2 *" (31 Feb) can never match.
81
+ const horizon = new Date(next.getTime());
82
+ horizon.setFullYear(horizon.getFullYear() + 4);
83
+ while (next < horizon) {
84
+ if (!cron.month.has(next.getMonth() + 1)) {
85
+ // Jump to the 1st of the next month.
86
+ next.setDate(1);
87
+ next.setHours(0, 0, 0, 0);
88
+ next.setMonth(next.getMonth() + 1);
89
+ continue;
90
+ }
91
+ if (!matchesDay(cron, next)) {
92
+ next.setHours(0, 0, 0, 0);
93
+ next.setDate(next.getDate() + 1);
94
+ continue;
95
+ }
96
+ if (!cron.hour.has(next.getHours())) {
97
+ next.setMinutes(0, 0, 0);
98
+ next.setHours(next.getHours() + 1);
99
+ continue;
100
+ }
101
+ if (!cron.minute.has(next.getMinutes())) {
102
+ next.setSeconds(0, 0);
103
+ next.setMinutes(next.getMinutes() + 1);
104
+ continue;
105
+ }
106
+ return next;
107
+ }
108
+ return null;
109
+ }
110
+ /**
111
+ * Standard cron day matching:
112
+ * - if both day-of-month and day-of-week are `*`, the day always matches
113
+ * - if only one is `*`, only the other is applied
114
+ * - if neither is `*`, the day matches when **either** matches (OR semantics)
115
+ */
116
+ function matchesDay(cron, date) {
117
+ const domMatches = cron.dayOfMonth.has(date.getDate());
118
+ const dowMatches = cron.dayOfWeek.has(date.getDay());
119
+ if (cron.dayOfMonthIsStar && cron.dayOfWeekIsStar) {
120
+ return true;
121
+ }
122
+ if (cron.dayOfMonthIsStar) {
123
+ return dowMatches;
124
+ }
125
+ if (cron.dayOfWeekIsStar) {
126
+ return domMatches;
127
+ }
128
+ return domMatches || dowMatches;
129
+ }
130
+ function parseField(field, range, label) {
131
+ const [min, max] = range;
132
+ const values = new Set();
133
+ const segments = field.split(',');
134
+ for (const raw of segments) {
135
+ const segment = raw.trim();
136
+ if (segment === '') {
137
+ throw new Error(`Invalid ${label} field "${field}"`);
138
+ }
139
+ const [rangePart, stepPart] = segment.split('/');
140
+ const step = stepPart === undefined ? 1 : Number(stepPart);
141
+ if (!Number.isInteger(step) || step <= 0) {
142
+ throw new Error(`Invalid step value in ${label} field "${segment}"`);
143
+ }
144
+ let from;
145
+ let to;
146
+ if (rangePart === '*') {
147
+ from = min;
148
+ to = max;
149
+ }
150
+ else if (rangePart.includes('-')) {
151
+ const [fromStr, toStr] = rangePart.split('-');
152
+ from = Number(fromStr);
153
+ to = Number(toStr);
154
+ }
155
+ else {
156
+ from = Number(rangePart);
157
+ to = from;
158
+ }
159
+ if (!Number.isInteger(from) || !Number.isInteger(to)) {
160
+ throw new Error(`Invalid ${label} field "${segment}"`);
161
+ }
162
+ if (from < min || to > max || from > to) {
163
+ throw new Error(`Out-of-range ${label} field "${segment}" (expected ${min}-${max})`);
164
+ }
165
+ for (let v = from; v <= to; v += step) {
166
+ values.add(v);
167
+ }
168
+ }
169
+ if (values.size === 0) {
170
+ throw new Error(`Empty ${label} field`);
171
+ }
172
+ return values;
173
+ }
174
+ function parseDayOfWeekField(field) {
175
+ // Cron allows 0 or 7 to represent Sunday — parse with an extended range
176
+ // [0,7] and then collapse 7 → 0 so callers can compare against
177
+ // `Date.getDay()` which returns 0-6.
178
+ const extended = parseField(field, [0, 7], 'day-of-week');
179
+ const normalised = new Set();
180
+ for (const value of extended) {
181
+ normalised.add(value === 7 ? 0 : value);
182
+ }
183
+ return normalised;
184
+ }
@@ -10,8 +10,8 @@ exports.isScheduleValid = isScheduleValid;
10
10
  exports.getScheduleDescription = getScheduleDescription;
11
11
  exports.isValidCronExpression = isValidCronExpression;
12
12
  const tslib_1 = require("tslib");
13
- const cron_parser_1 = require("cron-parser");
14
13
  const StringExtensions_1 = tslib_1.__importDefault(require("../../Extensions/StringExtensions"));
14
+ const CronExpression_1 = require("./CronExpression");
15
15
  const WEEKDAY_TO_CRON = {
16
16
  Sunday: 0,
17
17
  Monday: 1,
@@ -135,11 +135,9 @@ function getNextRunDateFromSchedule(schedule) {
135
135
  if (!schedule.CronExpression?.trim()) {
136
136
  return null;
137
137
  }
138
- const interval = (0, cron_parser_1.parseExpression)(schedule.CronExpression.trim(), {
139
- currentDate: new Date(),
140
- });
141
- const next = interval.next().toDate();
142
- return next > new Date() ? next : null;
138
+ const now = new Date();
139
+ const next = (0, CronExpression_1.getNextCronOccurrence)(schedule.CronExpression.trim(), now);
140
+ return next && next > now ? next : null;
143
141
  }
144
142
  catch {
145
143
  return null;
@@ -166,13 +164,10 @@ function isScheduleValid(schedule) {
166
164
  if (preset === 'selectedDays' && days.length === 0) {
167
165
  return 'Select at least one day';
168
166
  }
169
- try {
170
- (0, cron_parser_1.parseExpression)(schedule.CronExpression.trim());
171
- return true;
172
- }
173
- catch {
167
+ if (!(0, CronExpression_1.isCronExpressionValid)(schedule.CronExpression.trim())) {
174
168
  return 'Cron expression is not valid';
175
169
  }
170
+ return true;
176
171
  }
177
172
  function getScheduleDescription(schedule) {
178
173
  if (!schedule) {
@@ -238,11 +233,5 @@ function isValidCronExpression(expression) {
238
233
  if (StringExtensions_1.default.IsNullOrEmpty(expression)) {
239
234
  return false;
240
235
  }
241
- try {
242
- (0, cron_parser_1.parseExpression)(expression.trim());
243
- return true;
244
- }
245
- catch {
246
- return false;
247
- }
236
+ return (0, CronExpression_1.isCronExpressionValid)(expression.trim());
248
237
  }
@@ -7,7 +7,7 @@ export declare class ThemeService implements IThemeService {
7
7
  constructor(api: AdaptableApi);
8
8
  destroy(): void;
9
9
  subscribe(): void;
10
- onThemeChanged: () => void;
10
+ onThemeSelected: () => void;
11
11
  applyNewThemeVariables(theme: AdaptableTheme): void;
12
12
  showMissingThemeFiles(theme: AdaptableTheme): void;
13
13
  getDOMPrefferedColorScheme(): 'dark' | 'light';
@@ -23,14 +23,14 @@ class ThemeService {
23
23
  document.adoptedStyleSheets = [...document.adoptedStyleSheets].filter((sheet) => sheet !== this.styleSheetObject);
24
24
  }
25
25
  subscribe() {
26
- const themeChangedUnsubscribe = this.api.eventApi.on('ThemeSelected', this.onThemeChanged);
26
+ const themeChangedUnsubscribe = this.api.eventApi.on('ThemeSelected', this.onThemeSelected);
27
27
  const prefferedColorSchemeUnsubscribe = this.attachPrefferedColorSchemeListener();
28
28
  this.unsubscribe = () => {
29
29
  themeChangedUnsubscribe();
30
30
  prefferedColorSchemeUnsubscribe();
31
31
  };
32
32
  }
33
- onThemeChanged = () => {
33
+ onThemeSelected = () => {
34
34
  let currentTheme = this.api.themeApi.getCurrentThemeObject();
35
35
  currentTheme = this.mapOsTheme(currentTheme);
36
36
  this.applyNewThemeVariables(currentTheme);
@@ -11,7 +11,7 @@ const AdaptableContext_1 = require("../../../AdaptableContext");
11
11
  const Utilities_1 = require("../Utilities");
12
12
  const utils_1 = require("../../../../lib/utils");
13
13
  const WindowDialog = (props) => {
14
- const { onChange, style, baseClassName, className, isActionModule, settingsPanelOptionsKey, onHide, ...dialogProps } = props;
14
+ const { onChange, style, baseClassName, className, isActionModule, settingsPanelOptionsKey, onHide, dataName, ...dialogProps } = props;
15
15
  const adaptable = (0, AdaptableContext_1.useAdaptable)();
16
16
  const dispatch = (0, react_redux_1.useDispatch)();
17
17
  const settingsPanelOptions = adaptable.adaptableOptions.settingsPanelOptions;
@@ -38,7 +38,7 @@ const WindowDialog = (props) => {
38
38
  position: popupSettings.position,
39
39
  onChange: handleWindowSettings,
40
40
  };
41
- return ((0, jsx_runtime_1.jsx)(Dialog_1.default, { windowModal: true, fixed: false, windowModalProps: windowModalProps, style: props.style, onDismiss: onHide, isOpen: true, showCloseButton: true, ...dialogProps, className: (0, utils_1.cn)('twa:p-0 twa:h-full', className) }));
41
+ return ((0, jsx_runtime_1.jsx)(Dialog_1.default, { "data-name": dataName, windowModal: true, fixed: false, windowModalProps: windowModalProps, style: props.style, onDismiss: onHide, isOpen: true, showCloseButton: true, ...dialogProps, className: (0, utils_1.cn)('twa:p-0 twa:h-full', className) }));
42
42
  };
43
43
  const PopupDialog = (props) => {
44
44
  const { style, className, onHide, children, ...dialogProps } = props;
@@ -5,7 +5,6 @@ exports.getSparklineCellChromeCss = getSparklineCellChromeCss;
5
5
  const tslib_1 = require("tslib");
6
6
  const jsx_runtime_1 = require("react/jsx-runtime");
7
7
  const React = tslib_1.__importStar(require("react"));
8
- const ag_charts_enterprise_1 = require("ag-charts-enterprise");
9
8
  const AdaptableHelper_1 = require("../../../../../Utilities/Helpers/AdaptableHelper");
10
9
  const SparklineStyleHelper_1 = require("../../../../../Utilities/Helpers/StyledColumns/SparklineStyleHelper");
11
10
  const StyleHelper_1 = require("../../../../../Utilities/Helpers/StyleHelper");
@@ -58,23 +57,6 @@ const buildSparklinePreviewOptions = (sparklineStyle, container, data, width, he
58
57
  }
59
58
  return options;
60
59
  };
61
- /**
62
- * AG Grid registers chart modules via `AgChartsEnterpriseModule.setup()` when
63
- * sparklines are enabled. Standalone `AgCharts.createSparkline` needs the same
64
- * setup — otherwise the settings-panel preview throws "No modules registered".
65
- */
66
- let agChartsPreviewModulesReady = false;
67
- const ensureAgChartsEnterpriseModules = () => {
68
- if (agChartsPreviewModulesReady) {
69
- return;
70
- }
71
- ag_charts_enterprise_1.AgChartsEnterpriseModule.setup();
72
- agChartsPreviewModulesReady = true;
73
- };
74
- const createSparkline = (options) => {
75
- ensureAgChartsEnterpriseModules();
76
- return ag_charts_enterprise_1.AgChartsEnterpriseModule.createSparkline(options);
77
- };
78
60
  const SparklinePreviewCanvas = ({ sparklineStyle, columnId }) => {
79
61
  const adaptable = (0, AdaptableContext_1.useAdaptable)();
80
62
  const containerRef = React.useRef(null);
@@ -98,7 +80,7 @@ const SparklinePreviewCanvas = ({ sparklineStyle, columnId }) => {
98
80
  const options = buildSparklinePreviewOptions(sparklineStyle, container, data, width, PREVIEW_HEIGHT);
99
81
  try {
100
82
  if (!instanceRef.current) {
101
- instanceRef.current = createSparkline(options);
83
+ instanceRef.current = adaptable.api.styledColumnApi.internalApi.createSparkline(options);
102
84
  }
103
85
  else {
104
86
  instanceRef.current.update(options);
@@ -1,4 +1,5 @@
1
1
  import { ColDef, ColGroupDef, Column, GridApi, GridOptions, IRowNode, ManagedGridOptionKey, ManagedGridOptions, Module } from 'ag-grid-enterprise';
2
+ import type { AgChartInstance, AgSparklineOptions } from 'ag-charts-types';
2
3
  import { AdaptableAgGrid } from './AdaptableAgGrid';
3
4
  import { AdaptableColumn, AdaptableColumnGroup } from '../AdaptableState/Common/AdaptableColumn';
4
5
  import { SelectedCellInfo } from '../AdaptableState/Selection/SelectedCellInfo';
@@ -31,6 +32,7 @@ export declare class AgGridAdapter {
31
32
  monkeyPatchingAggColumnFilters(): void;
32
33
  monkeyPatchingAggFuncLabels(): void;
33
34
  private DANGER_getPrivateAgGridBeans;
35
+ DANGER_getCreateSparkline(): ((options: AgSparklineOptions) => AgChartInstance<AgSparklineOptions>) | undefined;
34
36
  DANGER_getLiveGridOptions(): GridOptions<any>;
35
37
  getAgGridRootElement(): HTMLElement;
36
38
  /**
@@ -243,6 +243,16 @@ class AgGridAdapter {
243
243
  }
244
244
  return beans;
245
245
  }
246
+ // #sparkline_factory
247
+ // The AG Grid Sparklines module stores the `createSparkline` factory (sourced from
248
+ // `AgChartsEnterpriseModule`) in the registered `agSparklineCellRenderer` default params.
249
+ // We read it straight from the registry bean so Adaptable can render standalone sparkline
250
+ // previews without taking a direct dependency on `ag-charts-enterprise`.
251
+ DANGER_getCreateSparkline() {
252
+ const registry = this.DANGER_getPrivateAgGridBeans()?.registry;
253
+ const sparklineComponent = registry?.getUserComponent('agSparklineCellRenderer', 'agSparklineCellRenderer');
254
+ return sparklineComponent?.params?.createSparkline;
255
+ }
246
256
  DANGER_getLiveGridOptions() {
247
257
  return this.DANGER_getPrivateAgGridBeans()?.gridOptions;
248
258
  }
@@ -38,6 +38,10 @@ exports.agGridDataTypeDefinitions = {
38
38
  // boolean: is kept as is
39
39
  // object: is kept as is
40
40
  // Adaptable specific types
41
+ unknown: {
42
+ baseDataType: 'text',
43
+ extendsDataType: 'text',
44
+ },
41
45
  [exports.TEXT_ARRAY_DATA_TYPE]: {
42
46
  baseDataType: 'text',
43
47
  extendsDataType: 'text',
@@ -104,9 +104,22 @@ const WindowModal = (props) => {
104
104
  }
105
105
  }, []);
106
106
  const ResizableCmp = re_resizable_1.Resizable;
107
+ // React propagates events through the component tree, not the DOM tree. A
108
+ // nested popup (e.g. a modal wizard) rendered as a React child of this window
109
+ // is portaled elsewhere in the DOM, so a mousedown inside it would bubble here
110
+ // and incorrectly bring this window to the front (covering the popup). Guard
111
+ // against this by only reacting to mousedowns that happen inside this window's
112
+ // own DOM subtree.
113
+ const handleMouseDown = (event) => {
114
+ const node = targetRef.current;
115
+ if (node && event.target instanceof Node && !node.contains(event.target)) {
116
+ return;
117
+ }
118
+ stacking.bringInFront();
119
+ };
107
120
  return (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)("div", { style: style,
108
121
  //@ts-ignore
109
- ref: targetRef, onMouseDown: stacking.bringInFront, children: (0, jsx_runtime_1.jsx)(ResizableCmp, { minWidth: props.minWidth, minHeight: props.minHeight, onResizeStop: handleResizeStop, onResize: handleResize, bounds: "window", defaultSize: {
122
+ ref: targetRef, onMouseDown: handleMouseDown, children: (0, jsx_runtime_1.jsx)(ResizableCmp, { minWidth: props.minWidth, minHeight: props.minHeight, onResizeStop: handleResizeStop, onResize: handleResize, bounds: "window", defaultSize: {
110
123
  width: props.size.width,
111
124
  height: props.size.height,
112
125
  }, children: props.children }) }), portalElement);