@adaptabletools/adaptable 23.0.3 → 23.0.4
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 -2
- package/src/Api/GridApi.d.ts +18 -0
- package/src/Api/Implementation/GridApiImpl.d.ts +3 -0
- package/src/Api/Implementation/GridApiImpl.js +27 -0
- package/src/Api/Implementation/StyledColumnApiImpl.d.ts +2 -0
- package/src/Api/Implementation/StyledColumnApiImpl.js +3 -0
- package/src/Api/Internal/StyledColumnInternalApi.d.ts +10 -0
- package/src/Api/Internal/StyledColumnInternalApi.js +20 -0
- package/src/Api/StyledColumnApi.d.ts +14 -0
- package/src/Utilities/Helpers/Scheduling/CronExpression.d.ts +45 -0
- package/src/Utilities/Helpers/Scheduling/CronExpression.js +179 -0
- package/src/Utilities/Helpers/Scheduling/ScheduleHelper.js +7 -18
- package/src/View/StyledColumn/Wizard/StyledColumnWizardStyleSection/Components/StyledColumnSparklinePreview.js +1 -19
- package/src/agGrid/AgGridAdapter.d.ts +2 -0
- package/src/agGrid/AgGridAdapter.js +10 -0
- package/src/env.js +2 -2
- package/tsconfig.esm.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adaptabletools/adaptable",
|
|
3
|
-
"version": "23.0.
|
|
3
|
+
"version": "23.0.4",
|
|
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",
|
|
@@ -48,7 +48,6 @@
|
|
|
48
48
|
"@tanstack/react-virtual": "^3.13.22",
|
|
49
49
|
"class-variance-authority": "^0.7.1",
|
|
50
50
|
"clsx": "^2.1.1",
|
|
51
|
-
"cron-parser": "^4.9.0",
|
|
52
51
|
"date-fns": "^4.1.0",
|
|
53
52
|
"lucide-react": "^0.563.0",
|
|
54
53
|
"normalize.css": "^8.0.1",
|
package/src/Api/GridApi.d.ts
CHANGED
|
@@ -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[];
|
|
@@ -47,6 +47,33 @@ export class GridApiImpl extends ApiBase {
|
|
|
47
47
|
});
|
|
48
48
|
return data;
|
|
49
49
|
}
|
|
50
|
+
getColumnData(columnId) {
|
|
51
|
+
const data = [];
|
|
52
|
+
this._adaptable.forAllRowNodesDo((rowNode) => {
|
|
53
|
+
if (!this.isGroupRowNode(rowNode)) {
|
|
54
|
+
data.push(this.getRawValueFromRowNode(rowNode, columnId));
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
return data;
|
|
58
|
+
}
|
|
59
|
+
getFilteredColumnData(columnId) {
|
|
60
|
+
const data = [];
|
|
61
|
+
this.getAgGridApi().forEachNodeAfterFilter((rowNode) => {
|
|
62
|
+
if (!this.isGroupRowNode(rowNode)) {
|
|
63
|
+
data.push(this.getRawValueFromRowNode(rowNode, columnId));
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
return data;
|
|
67
|
+
}
|
|
68
|
+
getVisibleColumnData(columnId) {
|
|
69
|
+
const data = [];
|
|
70
|
+
this.getAdaptableInternalApi().forAllVisibleRowNodesDo((rowNode) => {
|
|
71
|
+
if (!this.isGroupRowNode(rowNode)) {
|
|
72
|
+
data.push(this.getRawValueFromRowNode(rowNode, columnId));
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
return data;
|
|
76
|
+
}
|
|
50
77
|
async updateGridData(dataRows, dataUpdateConfig) {
|
|
51
78
|
const rowNodes = await this._adaptable.updateRows(dataRows, dataUpdateConfig);
|
|
52
79
|
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;
|
|
@@ -79,6 +79,9 @@ export class StyledColumnApiImpl extends ApiBase {
|
|
|
79
79
|
canDisplaySparklines() {
|
|
80
80
|
return this._adaptable.canDisplaySparklines();
|
|
81
81
|
}
|
|
82
|
+
renderSparkline(options) {
|
|
83
|
+
return this.internalApi.createSparkline(options);
|
|
84
|
+
}
|
|
82
85
|
suspendStyledColumn(styledColumn) {
|
|
83
86
|
this.dispatchAction(StyledColumnRedux.StyledColumnSuspend(styledColumn));
|
|
84
87
|
}
|
|
@@ -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;
|
|
@@ -10,6 +10,26 @@ const DYNAMIC_RANGE_ENDPOINTS = [
|
|
|
10
10
|
const isDynamicRangeEndpoint = (value) => typeof value === 'string' &&
|
|
11
11
|
DYNAMIC_RANGE_ENDPOINTS.includes(value);
|
|
12
12
|
export class StyledColumnInternalApi extends ApiBase {
|
|
13
|
+
/**
|
|
14
|
+
* Creates a sparkline described by `options` in its target container and
|
|
15
|
+
* returns the chart instance (used to update / destroy it).
|
|
16
|
+
*
|
|
17
|
+
* Centralises sparkline creation so view components don't import
|
|
18
|
+
* `ag-charts-enterprise` directly: the `createSparkline` factory is sourced
|
|
19
|
+
* from the AG Grid Sparklines module via the grid's registry bean.
|
|
20
|
+
*/
|
|
21
|
+
createSparkline(options) {
|
|
22
|
+
if (!this.getStyledColumnApi().canDisplaySparklines()) {
|
|
23
|
+
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.');
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
const createSparklineFactory = this._adaptable.agGridAdapter.DANGER_getCreateSparkline();
|
|
27
|
+
if (!createSparklineFactory) {
|
|
28
|
+
this.logWarn('Cannot render Sparkline: unable to obtain the AG Grid Sparkline rendering factory.');
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return createSparklineFactory(options);
|
|
32
|
+
}
|
|
13
33
|
getMinValueForNumericColumn(column) {
|
|
14
34
|
if (!column || column.dataType !== 'number') {
|
|
15
35
|
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,179 @@
|
|
|
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
|
+
const MINUTE_RANGE = [0, 59];
|
|
22
|
+
const HOUR_RANGE = [0, 23];
|
|
23
|
+
const DAY_OF_MONTH_RANGE = [1, 31];
|
|
24
|
+
const MONTH_RANGE = [1, 12];
|
|
25
|
+
const FIELD_LABELS = ['minute', 'hour', 'day-of-month', 'month', 'day-of-week'];
|
|
26
|
+
/**
|
|
27
|
+
* Parses a 5-field cron expression. Throws when the expression is invalid.
|
|
28
|
+
*/
|
|
29
|
+
export function parseCronExpression(expression) {
|
|
30
|
+
if (!expression || typeof expression !== 'string') {
|
|
31
|
+
throw new Error('Cron expression is empty');
|
|
32
|
+
}
|
|
33
|
+
const parts = expression.trim().split(/\s+/);
|
|
34
|
+
if (parts.length !== 5) {
|
|
35
|
+
throw new Error(`Expected 5 cron fields (minute hour day-of-month month day-of-week) but got ${parts.length}`);
|
|
36
|
+
}
|
|
37
|
+
const minute = parseField(parts[0], MINUTE_RANGE, FIELD_LABELS[0]);
|
|
38
|
+
const hour = parseField(parts[1], HOUR_RANGE, FIELD_LABELS[1]);
|
|
39
|
+
const dayOfMonth = parseField(parts[2], DAY_OF_MONTH_RANGE, FIELD_LABELS[2]);
|
|
40
|
+
const month = parseField(parts[3], MONTH_RANGE, FIELD_LABELS[3]);
|
|
41
|
+
const dayOfWeek = parseDayOfWeekField(parts[4]);
|
|
42
|
+
return {
|
|
43
|
+
minute,
|
|
44
|
+
hour,
|
|
45
|
+
dayOfMonth,
|
|
46
|
+
month,
|
|
47
|
+
dayOfWeek,
|
|
48
|
+
dayOfMonthIsStar: parts[2] === '*',
|
|
49
|
+
dayOfWeekIsStar: parts[4] === '*',
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Returns true if the given expression is a valid 5-field cron expression.
|
|
54
|
+
*/
|
|
55
|
+
export function isCronExpressionValid(expression) {
|
|
56
|
+
try {
|
|
57
|
+
parseCronExpression(expression);
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Returns the next time the cron expression fires after `fromDate` (exclusive).
|
|
66
|
+
* Returns null if no match is found within a 4-year horizon.
|
|
67
|
+
*/
|
|
68
|
+
export function getNextCronOccurrence(expression, fromDate = new Date()) {
|
|
69
|
+
const cron = parseCronExpression(expression);
|
|
70
|
+
// Bump to the start of the next minute - cron has minute granularity and
|
|
71
|
+
// we never want to return `fromDate` itself.
|
|
72
|
+
const next = new Date(fromDate.getTime());
|
|
73
|
+
next.setSeconds(0, 0);
|
|
74
|
+
next.setMinutes(next.getMinutes() + 1);
|
|
75
|
+
// Safety horizon — patterns like "0 0 31 2 *" (31 Feb) can never match.
|
|
76
|
+
const horizon = new Date(next.getTime());
|
|
77
|
+
horizon.setFullYear(horizon.getFullYear() + 4);
|
|
78
|
+
while (next < horizon) {
|
|
79
|
+
if (!cron.month.has(next.getMonth() + 1)) {
|
|
80
|
+
// Jump to the 1st of the next month.
|
|
81
|
+
next.setDate(1);
|
|
82
|
+
next.setHours(0, 0, 0, 0);
|
|
83
|
+
next.setMonth(next.getMonth() + 1);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (!matchesDay(cron, next)) {
|
|
87
|
+
next.setHours(0, 0, 0, 0);
|
|
88
|
+
next.setDate(next.getDate() + 1);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (!cron.hour.has(next.getHours())) {
|
|
92
|
+
next.setMinutes(0, 0, 0);
|
|
93
|
+
next.setHours(next.getHours() + 1);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (!cron.minute.has(next.getMinutes())) {
|
|
97
|
+
next.setSeconds(0, 0);
|
|
98
|
+
next.setMinutes(next.getMinutes() + 1);
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
return next;
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Standard cron day matching:
|
|
107
|
+
* - if both day-of-month and day-of-week are `*`, the day always matches
|
|
108
|
+
* - if only one is `*`, only the other is applied
|
|
109
|
+
* - if neither is `*`, the day matches when **either** matches (OR semantics)
|
|
110
|
+
*/
|
|
111
|
+
function matchesDay(cron, date) {
|
|
112
|
+
const domMatches = cron.dayOfMonth.has(date.getDate());
|
|
113
|
+
const dowMatches = cron.dayOfWeek.has(date.getDay());
|
|
114
|
+
if (cron.dayOfMonthIsStar && cron.dayOfWeekIsStar) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
if (cron.dayOfMonthIsStar) {
|
|
118
|
+
return dowMatches;
|
|
119
|
+
}
|
|
120
|
+
if (cron.dayOfWeekIsStar) {
|
|
121
|
+
return domMatches;
|
|
122
|
+
}
|
|
123
|
+
return domMatches || dowMatches;
|
|
124
|
+
}
|
|
125
|
+
function parseField(field, range, label) {
|
|
126
|
+
const [min, max] = range;
|
|
127
|
+
const values = new Set();
|
|
128
|
+
const segments = field.split(',');
|
|
129
|
+
for (const raw of segments) {
|
|
130
|
+
const segment = raw.trim();
|
|
131
|
+
if (segment === '') {
|
|
132
|
+
throw new Error(`Invalid ${label} field "${field}"`);
|
|
133
|
+
}
|
|
134
|
+
const [rangePart, stepPart] = segment.split('/');
|
|
135
|
+
const step = stepPart === undefined ? 1 : Number(stepPart);
|
|
136
|
+
if (!Number.isInteger(step) || step <= 0) {
|
|
137
|
+
throw new Error(`Invalid step value in ${label} field "${segment}"`);
|
|
138
|
+
}
|
|
139
|
+
let from;
|
|
140
|
+
let to;
|
|
141
|
+
if (rangePart === '*') {
|
|
142
|
+
from = min;
|
|
143
|
+
to = max;
|
|
144
|
+
}
|
|
145
|
+
else if (rangePart.includes('-')) {
|
|
146
|
+
const [fromStr, toStr] = rangePart.split('-');
|
|
147
|
+
from = Number(fromStr);
|
|
148
|
+
to = Number(toStr);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
from = Number(rangePart);
|
|
152
|
+
to = from;
|
|
153
|
+
}
|
|
154
|
+
if (!Number.isInteger(from) || !Number.isInteger(to)) {
|
|
155
|
+
throw new Error(`Invalid ${label} field "${segment}"`);
|
|
156
|
+
}
|
|
157
|
+
if (from < min || to > max || from > to) {
|
|
158
|
+
throw new Error(`Out-of-range ${label} field "${segment}" (expected ${min}-${max})`);
|
|
159
|
+
}
|
|
160
|
+
for (let v = from; v <= to; v += step) {
|
|
161
|
+
values.add(v);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (values.size === 0) {
|
|
165
|
+
throw new Error(`Empty ${label} field`);
|
|
166
|
+
}
|
|
167
|
+
return values;
|
|
168
|
+
}
|
|
169
|
+
function parseDayOfWeekField(field) {
|
|
170
|
+
// Cron allows 0 or 7 to represent Sunday — parse with an extended range
|
|
171
|
+
// [0,7] and then collapse 7 → 0 so callers can compare against
|
|
172
|
+
// `Date.getDay()` which returns 0-6.
|
|
173
|
+
const extended = parseField(field, [0, 7], 'day-of-week');
|
|
174
|
+
const normalised = new Set();
|
|
175
|
+
for (const value of extended) {
|
|
176
|
+
normalised.add(value === 7 ? 0 : value);
|
|
177
|
+
}
|
|
178
|
+
return normalised;
|
|
179
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { parseExpression } from 'cron-parser';
|
|
2
1
|
import StringExtensions from '../../Extensions/StringExtensions';
|
|
2
|
+
import { getNextCronOccurrence, isCronExpressionValid as isCronExpressionValidInternal, } from './CronExpression';
|
|
3
3
|
const WEEKDAY_TO_CRON = {
|
|
4
4
|
Sunday: 0,
|
|
5
5
|
Monday: 1,
|
|
@@ -123,11 +123,9 @@ export function getNextRunDateFromSchedule(schedule) {
|
|
|
123
123
|
if (!schedule.CronExpression?.trim()) {
|
|
124
124
|
return null;
|
|
125
125
|
}
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const next = interval.next().toDate();
|
|
130
|
-
return next > new Date() ? next : null;
|
|
126
|
+
const now = new Date();
|
|
127
|
+
const next = getNextCronOccurrence(schedule.CronExpression.trim(), now);
|
|
128
|
+
return next && next > now ? next : null;
|
|
131
129
|
}
|
|
132
130
|
catch {
|
|
133
131
|
return null;
|
|
@@ -154,13 +152,10 @@ export function isScheduleValid(schedule) {
|
|
|
154
152
|
if (preset === 'selectedDays' && days.length === 0) {
|
|
155
153
|
return 'Select at least one day';
|
|
156
154
|
}
|
|
157
|
-
|
|
158
|
-
parseExpression(schedule.CronExpression.trim());
|
|
159
|
-
return true;
|
|
160
|
-
}
|
|
161
|
-
catch {
|
|
155
|
+
if (!isCronExpressionValidInternal(schedule.CronExpression.trim())) {
|
|
162
156
|
return 'Cron expression is not valid';
|
|
163
157
|
}
|
|
158
|
+
return true;
|
|
164
159
|
}
|
|
165
160
|
export function getScheduleDescription(schedule) {
|
|
166
161
|
if (!schedule) {
|
|
@@ -226,11 +221,5 @@ export function isValidCronExpression(expression) {
|
|
|
226
221
|
if (StringExtensions.IsNullOrEmpty(expression)) {
|
|
227
222
|
return false;
|
|
228
223
|
}
|
|
229
|
-
|
|
230
|
-
parseExpression(expression.trim());
|
|
231
|
-
return true;
|
|
232
|
-
}
|
|
233
|
-
catch {
|
|
234
|
-
return false;
|
|
235
|
-
}
|
|
224
|
+
return isCronExpressionValidInternal(expression.trim());
|
|
236
225
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import { AgChartsEnterpriseModule } from 'ag-charts-enterprise';
|
|
4
3
|
import { AdaptableHelper } from '../../../../../Utilities/Helpers/AdaptableHelper';
|
|
5
4
|
import { resolveSparklineOptionsForRender } from '../../../../../Utilities/Helpers/StyledColumns/SparklineStyleHelper';
|
|
6
5
|
import { convertAdaptableStyleToCSS, hasCellBoxStyle, } from '../../../../../Utilities/Helpers/StyleHelper';
|
|
@@ -53,23 +52,6 @@ const buildSparklinePreviewOptions = (sparklineStyle, container, data, width, he
|
|
|
53
52
|
}
|
|
54
53
|
return options;
|
|
55
54
|
};
|
|
56
|
-
/**
|
|
57
|
-
* AG Grid registers chart modules via `AgChartsEnterpriseModule.setup()` when
|
|
58
|
-
* sparklines are enabled. Standalone `AgCharts.createSparkline` needs the same
|
|
59
|
-
* setup — otherwise the settings-panel preview throws "No modules registered".
|
|
60
|
-
*/
|
|
61
|
-
let agChartsPreviewModulesReady = false;
|
|
62
|
-
const ensureAgChartsEnterpriseModules = () => {
|
|
63
|
-
if (agChartsPreviewModulesReady) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
AgChartsEnterpriseModule.setup();
|
|
67
|
-
agChartsPreviewModulesReady = true;
|
|
68
|
-
};
|
|
69
|
-
const createSparkline = (options) => {
|
|
70
|
-
ensureAgChartsEnterpriseModules();
|
|
71
|
-
return AgChartsEnterpriseModule.createSparkline(options);
|
|
72
|
-
};
|
|
73
55
|
const SparklinePreviewCanvas = ({ sparklineStyle, columnId }) => {
|
|
74
56
|
const adaptable = useAdaptable();
|
|
75
57
|
const containerRef = React.useRef(null);
|
|
@@ -93,7 +75,7 @@ const SparklinePreviewCanvas = ({ sparklineStyle, columnId }) => {
|
|
|
93
75
|
const options = buildSparklinePreviewOptions(sparklineStyle, container, data, width, PREVIEW_HEIGHT);
|
|
94
76
|
try {
|
|
95
77
|
if (!instanceRef.current) {
|
|
96
|
-
instanceRef.current = createSparkline(options);
|
|
78
|
+
instanceRef.current = adaptable.api.styledColumnApi.internalApi.createSparkline(options);
|
|
97
79
|
}
|
|
98
80
|
else {
|
|
99
81
|
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
|
/**
|
|
@@ -239,6 +239,16 @@ export class AgGridAdapter {
|
|
|
239
239
|
}
|
|
240
240
|
return beans;
|
|
241
241
|
}
|
|
242
|
+
// #sparkline_factory
|
|
243
|
+
// The AG Grid Sparklines module stores the `createSparkline` factory (sourced from
|
|
244
|
+
// `AgChartsEnterpriseModule`) in the registered `agSparklineCellRenderer` default params.
|
|
245
|
+
// We read it straight from the registry bean so Adaptable can render standalone sparkline
|
|
246
|
+
// previews without taking a direct dependency on `ag-charts-enterprise`.
|
|
247
|
+
DANGER_getCreateSparkline() {
|
|
248
|
+
const registry = this.DANGER_getPrivateAgGridBeans()?.registry;
|
|
249
|
+
const sparklineComponent = registry?.getUserComponent('agSparklineCellRenderer', 'agSparklineCellRenderer');
|
|
250
|
+
return sparklineComponent?.params?.createSparkline;
|
|
251
|
+
}
|
|
242
252
|
DANGER_getLiveGridOptions() {
|
|
243
253
|
return this.DANGER_getPrivateAgGridBeans()?.gridOptions;
|
|
244
254
|
}
|
package/src/env.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
NEXT_PUBLIC_INFINITE_TABLE_LICENSE_KEY: "StartDate=2021-06-29|EndDate=2030-01-01|Owner=Adaptable|Type=distribution|TS=1624971462479|C=137829811,1004007071,2756196225,1839832928,3994409405,636616862" || '',
|
|
3
|
-
PUBLISH_TIMESTAMP:
|
|
4
|
-
VERSION: "23.0.
|
|
3
|
+
PUBLISH_TIMESTAMP: 1782415229232 || Date.now(),
|
|
4
|
+
VERSION: "23.0.4" || '--current-version--',
|
|
5
5
|
};
|