@cellaware/utils 8.0.3 → 8.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/dist/azure/cosmos.d.ts +98 -0
- package/dist/azure/cosmos.js +276 -0
- package/dist/azure/email.d.ts +3 -0
- package/dist/azure/email.js +20 -0
- package/dist/azure/function.d.ts +14 -0
- package/dist/azure/function.js +124 -0
- package/dist/azure/slot.d.ts +1 -0
- package/dist/azure/slot.js +4 -0
- package/dist/azure/storage.d.ts +4 -0
- package/dist/azure/storage.js +67 -0
- package/dist/chatwms/alert.d.ts +86 -0
- package/dist/chatwms/alert.js +62 -0
- package/dist/chatwms/azure/cosmos.d.ts +21 -0
- package/dist/chatwms/azure/cosmos.js +34 -0
- package/dist/chatwms/azure/function.d.ts +21 -0
- package/dist/chatwms/azure/function.js +29 -0
- package/dist/chatwms/azure/storage.d.ts +5 -0
- package/dist/chatwms/azure/storage.js +17 -0
- package/dist/chatwms/client.d.ts +18 -0
- package/dist/chatwms/client.js +48 -0
- package/dist/chatwms/dashboard.d.ts +82 -0
- package/dist/chatwms/dashboard.js +17 -0
- package/dist/chatwms/datagrid.d.ts +120 -0
- package/dist/chatwms/datagrid.js +781 -0
- package/dist/chatwms/developer.d.ts +27 -0
- package/dist/chatwms/developer.js +12 -0
- package/dist/chatwms/github/issue.d.ts +1 -0
- package/dist/chatwms/github/issue.js +4 -0
- package/dist/chatwms/instance.d.ts +16 -0
- package/dist/chatwms/instance.js +18 -0
- package/dist/chatwms/report.d.ts +66 -0
- package/dist/chatwms/report.js +24 -0
- package/dist/chatwms/response.d.ts +12 -0
- package/dist/chatwms/response.js +13 -0
- package/dist/chatwms/search.d.ts +12 -0
- package/dist/chatwms/search.js +9 -0
- package/dist/chatwms/user.d.ts +27 -0
- package/dist/chatwms/user.js +40 -0
- package/dist/github/issue.d.ts +1 -0
- package/dist/github/issue.js +23 -0
- package/dist/llm/chain-store.d.ts +49 -0
- package/dist/llm/chain-store.js +284 -0
- package/dist/llm/cost.d.ts +3 -0
- package/dist/llm/cost.js +78 -0
- package/dist/llm/model.d.ts +12 -0
- package/dist/llm/model.js +1 -0
- package/dist/stopwatch.d.ts +8 -0
- package/dist/stopwatch.js +36 -0
- package/dist/util.d.ts +36 -0
- package/dist/util.js +257 -0
- package/dist/version.d.ts +4 -0
- package/dist/version.js +12 -0
- package/package.json +1 -1
|
@@ -0,0 +1,781 @@
|
|
|
1
|
+
import { isDateString } from "../util.js";
|
|
2
|
+
import { CHATWMS_DEFAULT_LANGUAGE } from "./user.js";
|
|
3
|
+
export function initDatagridState() {
|
|
4
|
+
return {
|
|
5
|
+
adjRowData: [],
|
|
6
|
+
chartRowData: []
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export const DEFAULT_VALUE_FORMAT_VALUE = 'none';
|
|
10
|
+
export function evaluateValueFormat(colFmt, value, locale) {
|
|
11
|
+
if (value == null)
|
|
12
|
+
return value;
|
|
13
|
+
const fmt = colFmt.valueFormat;
|
|
14
|
+
if (!fmt)
|
|
15
|
+
return value;
|
|
16
|
+
try {
|
|
17
|
+
switch (colFmt.type) {
|
|
18
|
+
case 'text':
|
|
19
|
+
return formatText(value, fmt);
|
|
20
|
+
case 'number':
|
|
21
|
+
return formatNumber(value, fmt);
|
|
22
|
+
case 'date':
|
|
23
|
+
return formatDate(value, fmt, locale);
|
|
24
|
+
default:
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function formatTextEnabled(fmt) {
|
|
33
|
+
return fmt.txtCaseVal !== DEFAULT_VALUE_FORMAT_VALUE;
|
|
34
|
+
}
|
|
35
|
+
function formatText(value, fmt) {
|
|
36
|
+
if (!formatTextEnabled(fmt))
|
|
37
|
+
return value;
|
|
38
|
+
const str = String(value);
|
|
39
|
+
switch (fmt.txtCaseVal) {
|
|
40
|
+
case 'lower': return str.toLowerCase();
|
|
41
|
+
case 'upper': return str.toUpperCase();
|
|
42
|
+
case 'title':
|
|
43
|
+
return str
|
|
44
|
+
.toLowerCase()
|
|
45
|
+
.split(' ')
|
|
46
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
47
|
+
.join(' ');
|
|
48
|
+
default:
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export function formatNumberEnabled(fmt) {
|
|
53
|
+
return fmt.numCommaVal !== DEFAULT_VALUE_FORMAT_VALUE ||
|
|
54
|
+
fmt.numCurrencyVal !== DEFAULT_VALUE_FORMAT_VALUE ||
|
|
55
|
+
fmt.numPercentVal !== DEFAULT_VALUE_FORMAT_VALUE ||
|
|
56
|
+
fmt.numRoundVal !== DEFAULT_VALUE_FORMAT_VALUE;
|
|
57
|
+
}
|
|
58
|
+
function formatNumber(value, fmt) {
|
|
59
|
+
if (!formatNumberEnabled(fmt))
|
|
60
|
+
return value;
|
|
61
|
+
let num = parseFloat(value);
|
|
62
|
+
if (isNaN(num))
|
|
63
|
+
return value;
|
|
64
|
+
/*
|
|
65
|
+
We need to be intentional about the order of operations for number formatting.
|
|
66
|
+
For example, some formatting operations will transform the number to a string.
|
|
67
|
+
If we need to perform some arithmetic or round it, we need to do so first before
|
|
68
|
+
number is transformed into a string.
|
|
69
|
+
*/
|
|
70
|
+
if (fmt.numPercentVal === '100') {
|
|
71
|
+
num *= 100;
|
|
72
|
+
}
|
|
73
|
+
const decimals = parseInt(fmt.numRoundVal ?? '', 10);
|
|
74
|
+
if (!isNaN(decimals)) {
|
|
75
|
+
num = parseFloat(num.toFixed(decimals));
|
|
76
|
+
}
|
|
77
|
+
let formatted = num;
|
|
78
|
+
if (fmt.numCommaVal === 'on') {
|
|
79
|
+
formatted = num.toLocaleString();
|
|
80
|
+
}
|
|
81
|
+
if (fmt.numCurrencyVal === 'dollar') {
|
|
82
|
+
formatted = `$${formatted}`;
|
|
83
|
+
}
|
|
84
|
+
if (fmt.numPercentVal === '1' || fmt.numPercentVal === '100') {
|
|
85
|
+
formatted = `${formatted}%`;
|
|
86
|
+
}
|
|
87
|
+
return formatted;
|
|
88
|
+
}
|
|
89
|
+
function formatDate(value, fmt, locale) {
|
|
90
|
+
let valueStr;
|
|
91
|
+
if (value instanceof Date) {
|
|
92
|
+
valueStr = value.toISOString();
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
valueStr = String(value);
|
|
96
|
+
}
|
|
97
|
+
// Make sure we are dealing with a valid date string before we go any further.
|
|
98
|
+
if (!isDateString(valueStr)) {
|
|
99
|
+
return value;
|
|
100
|
+
}
|
|
101
|
+
// Remove time zone and milliseconds from date string.
|
|
102
|
+
valueStr = valueStr.replace(/Z/i, '');
|
|
103
|
+
valueStr = valueStr.replace(/\.\d+$/, '');
|
|
104
|
+
// Initialize date options and functionality.
|
|
105
|
+
const options = { hourCycle: 'h23' };
|
|
106
|
+
let formatDateEnabled = false;
|
|
107
|
+
const setOpt = (k, v) => {
|
|
108
|
+
if (v !== DEFAULT_VALUE_FORMAT_VALUE) {
|
|
109
|
+
options[k] = v;
|
|
110
|
+
formatDateEnabled = true;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
setOpt('year', fmt.dteYearVal);
|
|
114
|
+
setOpt('month', fmt.dteMonthVal);
|
|
115
|
+
setOpt('day', fmt.dteDayVal);
|
|
116
|
+
setOpt('weekday', fmt.dteWeekdayVal);
|
|
117
|
+
setOpt('hour', fmt.dteHourVal);
|
|
118
|
+
setOpt('minute', fmt.dteMinuteVal);
|
|
119
|
+
setOpt('second', fmt.dteSecondVal);
|
|
120
|
+
setOpt('hourCycle', fmt.dteHourcycleVal === 'h24' ? 'h23' : fmt.dteHourcycleVal);
|
|
121
|
+
// Handle simple date edge cases.
|
|
122
|
+
if (valueStr.length === 10) {
|
|
123
|
+
// Special handling for ISO-ish short date string (YYYY-AA-BB or AA-BB-YYYY).
|
|
124
|
+
const c4 = valueStr.at(4);
|
|
125
|
+
const c5 = valueStr.at(5);
|
|
126
|
+
if (c4 === '-' || c4 === '/' || c5 === '-' || c5 === '/') {
|
|
127
|
+
valueStr += ' 00:00:00'; // Make sure time is zero'd out.
|
|
128
|
+
if (!formatDateEnabled) {
|
|
129
|
+
setOpt('day', '2-digit');
|
|
130
|
+
setOpt('month', '2-digit');
|
|
131
|
+
setOpt('year', 'numeric');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else if (valueStr.length === 8) {
|
|
136
|
+
// Special handling for ISO-ish shorter date string (YY-MM-DD in any order).
|
|
137
|
+
const c2 = valueStr.at(2);
|
|
138
|
+
const c5 = valueStr.at(5);
|
|
139
|
+
if ((c2 === '-' && c5 === '-') || (c2 === '/' && c5 === '/')) {
|
|
140
|
+
valueStr += ' 00:00:00'; // Make sure time is zero'd out.
|
|
141
|
+
if (!formatDateEnabled) {
|
|
142
|
+
setOpt('day', '2-digit');
|
|
143
|
+
setOpt('month', '2-digit');
|
|
144
|
+
setOpt('year', '2-digit');
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
let dteStr = new Date(valueStr).toLocaleString(locale, options);
|
|
149
|
+
// NOTE: by default, we should use slash as separator.
|
|
150
|
+
if (fmt.dteSeparatorVal === DEFAULT_VALUE_FORMAT_VALUE) {
|
|
151
|
+
dteStr = dteStr.replaceAll('-', '/');
|
|
152
|
+
}
|
|
153
|
+
else if (fmt.dteSeparatorVal === 'dash') {
|
|
154
|
+
dteStr = dteStr.replaceAll('/', '-');
|
|
155
|
+
}
|
|
156
|
+
else if (fmt.dteSeparatorVal === 'slash') {
|
|
157
|
+
dteStr = dteStr.replaceAll('-', '/');
|
|
158
|
+
}
|
|
159
|
+
dteStr = dteStr.replaceAll(',', '');
|
|
160
|
+
// We want to preserve simple dates.
|
|
161
|
+
// If no is formatting detected, the date's length should not be greater than the original value's.
|
|
162
|
+
if (!formatDateEnabled) {
|
|
163
|
+
dteStr = dteStr.substring(0, value.length);
|
|
164
|
+
dteStr = dteStr.trim();
|
|
165
|
+
// Trim any separator characters off.
|
|
166
|
+
if (dteStr.endsWith('-') || dteStr.endsWith('/') || dteStr.endsWith(':') || dteStr.endsWith('.') || dteStr.endsWith('T')) {
|
|
167
|
+
dteStr = dteStr.substring(0, dteStr.length - 1).trim();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return dteStr;
|
|
171
|
+
}
|
|
172
|
+
export var ConditionalFormatRule;
|
|
173
|
+
(function (ConditionalFormatRule) {
|
|
174
|
+
// TEXT:
|
|
175
|
+
ConditionalFormatRule["CONTAINS"] = "conditional-format-rule-contains";
|
|
176
|
+
ConditionalFormatRule["DOES_NOT_CONTAIN"] = "conditional-format-rule-does-not-contain";
|
|
177
|
+
ConditionalFormatRule["BEGINS_WITH"] = "conditional-format-rule-begins-with";
|
|
178
|
+
ConditionalFormatRule["ENDS_WITH"] = "conditional-format-rule-ends-with";
|
|
179
|
+
// NUMBER:
|
|
180
|
+
ConditionalFormatRule["GREATER_THAN"] = "conditional-format-rule-greater-than";
|
|
181
|
+
ConditionalFormatRule["GREATER_THAN_OR_EQUAL_TO"] = "conditional-format-rule-greater-than-or-equal-to";
|
|
182
|
+
ConditionalFormatRule["LESS_THAN"] = "conditional-format-rule-less-than";
|
|
183
|
+
ConditionalFormatRule["LESS_THAN_OR_EQUAL_TO"] = "conditional-format-rule-less-than-or-equal-to";
|
|
184
|
+
ConditionalFormatRule["BETWEEN"] = "conditional-format-rule-between";
|
|
185
|
+
// ANY:
|
|
186
|
+
ConditionalFormatRule["EQUALS"] = "conditional-format-rule-equals";
|
|
187
|
+
ConditionalFormatRule["DOES_NOT_EQUAL"] = "conditional-format-rule-does-not-equal";
|
|
188
|
+
ConditionalFormatRule["BLANK"] = "conditional-format-rule-blank";
|
|
189
|
+
ConditionalFormatRule["NOT_BLANK"] = "conditional-format-rule-not-blank";
|
|
190
|
+
})(ConditionalFormatRule || (ConditionalFormatRule = {}));
|
|
191
|
+
export const CONDITIONAL_FORMAT_RULES = [
|
|
192
|
+
ConditionalFormatRule.EQUALS,
|
|
193
|
+
ConditionalFormatRule.DOES_NOT_EQUAL,
|
|
194
|
+
ConditionalFormatRule.BLANK,
|
|
195
|
+
ConditionalFormatRule.NOT_BLANK,
|
|
196
|
+
ConditionalFormatRule.CONTAINS,
|
|
197
|
+
ConditionalFormatRule.DOES_NOT_CONTAIN,
|
|
198
|
+
ConditionalFormatRule.BEGINS_WITH,
|
|
199
|
+
ConditionalFormatRule.ENDS_WITH,
|
|
200
|
+
ConditionalFormatRule.GREATER_THAN,
|
|
201
|
+
ConditionalFormatRule.GREATER_THAN_OR_EQUAL_TO,
|
|
202
|
+
ConditionalFormatRule.LESS_THAN,
|
|
203
|
+
ConditionalFormatRule.LESS_THAN_OR_EQUAL_TO,
|
|
204
|
+
ConditionalFormatRule.BETWEEN
|
|
205
|
+
];
|
|
206
|
+
export const CONDITIONAL_FORMAT_RULES_TEXT = [
|
|
207
|
+
ConditionalFormatRule.EQUALS,
|
|
208
|
+
ConditionalFormatRule.DOES_NOT_EQUAL,
|
|
209
|
+
ConditionalFormatRule.BLANK,
|
|
210
|
+
ConditionalFormatRule.NOT_BLANK,
|
|
211
|
+
ConditionalFormatRule.CONTAINS,
|
|
212
|
+
ConditionalFormatRule.DOES_NOT_CONTAIN,
|
|
213
|
+
ConditionalFormatRule.BEGINS_WITH,
|
|
214
|
+
ConditionalFormatRule.ENDS_WITH
|
|
215
|
+
];
|
|
216
|
+
export const CONDITIONAL_FORMAT_RULES_NUMBER = [
|
|
217
|
+
ConditionalFormatRule.EQUALS,
|
|
218
|
+
ConditionalFormatRule.DOES_NOT_EQUAL,
|
|
219
|
+
ConditionalFormatRule.BLANK,
|
|
220
|
+
ConditionalFormatRule.NOT_BLANK,
|
|
221
|
+
ConditionalFormatRule.GREATER_THAN,
|
|
222
|
+
ConditionalFormatRule.GREATER_THAN_OR_EQUAL_TO,
|
|
223
|
+
ConditionalFormatRule.LESS_THAN,
|
|
224
|
+
ConditionalFormatRule.LESS_THAN_OR_EQUAL_TO,
|
|
225
|
+
ConditionalFormatRule.BETWEEN
|
|
226
|
+
];
|
|
227
|
+
export const CONDITIONAL_FORMAT_RULES_BOOLEAN = [
|
|
228
|
+
ConditionalFormatRule.EQUALS,
|
|
229
|
+
ConditionalFormatRule.DOES_NOT_EQUAL,
|
|
230
|
+
ConditionalFormatRule.BLANK,
|
|
231
|
+
ConditionalFormatRule.NOT_BLANK
|
|
232
|
+
];
|
|
233
|
+
export function initDatagridCondition() {
|
|
234
|
+
return {
|
|
235
|
+
columnName: '',
|
|
236
|
+
dataType: '',
|
|
237
|
+
rule: '',
|
|
238
|
+
value: ''
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
export async function summarizeCondition(condition, localeMessageFn) {
|
|
242
|
+
let ruleStr = '';
|
|
243
|
+
switch (condition.rule) {
|
|
244
|
+
case ConditionalFormatRule.BETWEEN:
|
|
245
|
+
ruleStr = `${await localeMessageFn(CHATWMS_DEFAULT_LANGUAGE, condition.rule)} ${condition.value} ${await localeMessageFn(CHATWMS_DEFAULT_LANGUAGE, 'conditional-format-rule-and')} ${condition.value2}`;
|
|
246
|
+
break;
|
|
247
|
+
case ConditionalFormatRule.BLANK:
|
|
248
|
+
case ConditionalFormatRule.NOT_BLANK:
|
|
249
|
+
ruleStr = `${await localeMessageFn(CHATWMS_DEFAULT_LANGUAGE, condition.rule)}`;
|
|
250
|
+
break;
|
|
251
|
+
default:
|
|
252
|
+
if (condition.dataType === 'text') {
|
|
253
|
+
ruleStr = `${await localeMessageFn(CHATWMS_DEFAULT_LANGUAGE, condition.rule)} '${condition.value}'`;
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
ruleStr = `${await localeMessageFn(CHATWMS_DEFAULT_LANGUAGE, condition.rule)} ${condition.value}`;
|
|
257
|
+
}
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
return `${condition.columnName} ${ruleStr}`;
|
|
261
|
+
}
|
|
262
|
+
export function codifyCondition(condition) {
|
|
263
|
+
// NOTE: since we check for action/unsafe SQL with every query, we do not need to check for SQL injection here.
|
|
264
|
+
if (condition.dataType === 'number') {
|
|
265
|
+
const v1 = !condition.value || condition.value == '' ? 0 : condition.value;
|
|
266
|
+
const v2 = !condition.value2 || condition.value2 == '' ? 0 : condition.value2;
|
|
267
|
+
// Need to wrap in quotes due to how ChatWMS will alias columns (ex: location_id -> Location ID).
|
|
268
|
+
const quotedColumnName = `"${condition.columnName}"`;
|
|
269
|
+
switch (condition.rule) {
|
|
270
|
+
case ConditionalFormatRule.EQUALS:
|
|
271
|
+
return `${quotedColumnName} = ${v1}`;
|
|
272
|
+
case ConditionalFormatRule.DOES_NOT_EQUAL:
|
|
273
|
+
return `${quotedColumnName} != ${v1}`;
|
|
274
|
+
case ConditionalFormatRule.GREATER_THAN:
|
|
275
|
+
return `${quotedColumnName} > ${v1}`;
|
|
276
|
+
case ConditionalFormatRule.GREATER_THAN_OR_EQUAL_TO:
|
|
277
|
+
return `${quotedColumnName} >= ${v1}`;
|
|
278
|
+
case ConditionalFormatRule.LESS_THAN:
|
|
279
|
+
return `${quotedColumnName} < ${v1}`;
|
|
280
|
+
case ConditionalFormatRule.LESS_THAN_OR_EQUAL_TO:
|
|
281
|
+
return `${quotedColumnName} <= ${v1}`;
|
|
282
|
+
case ConditionalFormatRule.BETWEEN:
|
|
283
|
+
return `${quotedColumnName} BETWEEN ${v1} AND ${v2}`;
|
|
284
|
+
case ConditionalFormatRule.BLANK:
|
|
285
|
+
return `${quotedColumnName} IS NULL`;
|
|
286
|
+
case ConditionalFormatRule.NOT_BLANK:
|
|
287
|
+
return `${quotedColumnName} IS NOT NULL`;
|
|
288
|
+
default:
|
|
289
|
+
return '1 = 2'; // Fail if we get here.
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
else if (condition.dataType === 'date') {
|
|
293
|
+
const v1 = !condition.value || condition.value == '' ? 0 : condition.value;
|
|
294
|
+
const v2 = !condition.value2 || condition.value2 == '' ? 0 : condition.value2;
|
|
295
|
+
// Need to wrap in quotes due to how ChatWMS will alias columns (ex: location_id -> Location ID).
|
|
296
|
+
const quotedColumnName = `"${condition.columnName}"`;
|
|
297
|
+
switch (condition.rule) {
|
|
298
|
+
case ConditionalFormatRule.EQUALS:
|
|
299
|
+
return `${quotedColumnName} = '${v1}'`;
|
|
300
|
+
case ConditionalFormatRule.DOES_NOT_EQUAL:
|
|
301
|
+
return `${quotedColumnName} != '${v1}'`;
|
|
302
|
+
case ConditionalFormatRule.GREATER_THAN:
|
|
303
|
+
return `${quotedColumnName} > '${v1}'`;
|
|
304
|
+
case ConditionalFormatRule.GREATER_THAN_OR_EQUAL_TO:
|
|
305
|
+
return `${quotedColumnName} >= '${v1}'`;
|
|
306
|
+
case ConditionalFormatRule.LESS_THAN:
|
|
307
|
+
return `${quotedColumnName} < '${v1}'`;
|
|
308
|
+
case ConditionalFormatRule.LESS_THAN_OR_EQUAL_TO:
|
|
309
|
+
return `${quotedColumnName} <= '${v1}'`;
|
|
310
|
+
case ConditionalFormatRule.BETWEEN:
|
|
311
|
+
return `${quotedColumnName} BETWEEN '${v1}' AND '${v2}'`;
|
|
312
|
+
case ConditionalFormatRule.BLANK:
|
|
313
|
+
return `${quotedColumnName} IS NULL`;
|
|
314
|
+
case ConditionalFormatRule.NOT_BLANK:
|
|
315
|
+
return `${quotedColumnName} IS NOT NULL`;
|
|
316
|
+
default:
|
|
317
|
+
return '1 = 2'; // Fail if we get here.
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
else {
|
|
321
|
+
// NOTE: it is a safe assumption to trim any whitespace off the value.
|
|
322
|
+
const v1 = (condition.value ?? '__DUMMY__').trim();
|
|
323
|
+
// Need to wrap in quotes due to how ChatWMS will alias columns (ex: location_id -> Location ID).
|
|
324
|
+
// NOTE: wrapping column and values in `UPPER` to support case insensitivity.
|
|
325
|
+
const quotedColumnName = `UPPER("${condition.columnName}")`;
|
|
326
|
+
switch (condition.rule) {
|
|
327
|
+
case ConditionalFormatRule.EQUALS:
|
|
328
|
+
return `${quotedColumnName} = UPPER('${v1}')`;
|
|
329
|
+
case ConditionalFormatRule.DOES_NOT_EQUAL:
|
|
330
|
+
return `${quotedColumnName} != UPPER('${v1}')`;
|
|
331
|
+
case ConditionalFormatRule.CONTAINS:
|
|
332
|
+
return `${quotedColumnName} LIKE UPPER('%${v1}%')`;
|
|
333
|
+
case ConditionalFormatRule.DOES_NOT_CONTAIN:
|
|
334
|
+
return `${quotedColumnName} NOT LIKE UPPER('%${v1}%')`;
|
|
335
|
+
case ConditionalFormatRule.BEGINS_WITH:
|
|
336
|
+
return `${quotedColumnName} LIKE UPPER('${v1}%')`;
|
|
337
|
+
case ConditionalFormatRule.ENDS_WITH:
|
|
338
|
+
return `${quotedColumnName} LIKE UPPER('%${v1}')`;
|
|
339
|
+
case ConditionalFormatRule.BLANK:
|
|
340
|
+
return `${quotedColumnName} IS NULL`;
|
|
341
|
+
case ConditionalFormatRule.NOT_BLANK:
|
|
342
|
+
return `${quotedColumnName} IS NOT NULL`;
|
|
343
|
+
default:
|
|
344
|
+
return '1 = 2'; // Fail if we get here.
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Equivalent of `parseNumeric` in front end
|
|
350
|
+
*
|
|
351
|
+
* https://github.com/cellaware/chatwms-az-swa-ng/blob/development/src/app/utils/data.ts#L126
|
|
352
|
+
*/
|
|
353
|
+
function stripNumericValueFormat(value) {
|
|
354
|
+
if (value === undefined)
|
|
355
|
+
return null;
|
|
356
|
+
if (typeof value === 'number')
|
|
357
|
+
return value;
|
|
358
|
+
// Remove commas, dollar signs, percent signs
|
|
359
|
+
const cleaned = value.replace(/[$,%]/g, '').replace(/,/g, '');
|
|
360
|
+
return cleaned;
|
|
361
|
+
}
|
|
362
|
+
function buildDatagridConditionEvaluator(condition) {
|
|
363
|
+
const v1 = condition.value;
|
|
364
|
+
const v2 = condition.value2;
|
|
365
|
+
const isBlank = (v) => v === null || v === undefined || (condition.dataType !== 'number' && condition.dataType !== 'boolean' && v === '');
|
|
366
|
+
if (condition.dataType === 'number') {
|
|
367
|
+
switch (condition.rule) {
|
|
368
|
+
case ConditionalFormatRule.EQUALS:
|
|
369
|
+
return v => stripNumericValueFormat(v) == v1;
|
|
370
|
+
case ConditionalFormatRule.DOES_NOT_EQUAL:
|
|
371
|
+
return v => stripNumericValueFormat(v) != v1;
|
|
372
|
+
case ConditionalFormatRule.GREATER_THAN:
|
|
373
|
+
return v => stripNumericValueFormat(v) > v1;
|
|
374
|
+
case ConditionalFormatRule.GREATER_THAN_OR_EQUAL_TO:
|
|
375
|
+
return v => stripNumericValueFormat(v) >= v1;
|
|
376
|
+
case ConditionalFormatRule.LESS_THAN:
|
|
377
|
+
return v => stripNumericValueFormat(v) < v1;
|
|
378
|
+
case ConditionalFormatRule.LESS_THAN_OR_EQUAL_TO:
|
|
379
|
+
return v => stripNumericValueFormat(v) <= v1;
|
|
380
|
+
case ConditionalFormatRule.BETWEEN:
|
|
381
|
+
return v => stripNumericValueFormat(v) >= v1 && stripNumericValueFormat(v) <= (v2 ?? v1); // fallback to v1 if v2 missing
|
|
382
|
+
case ConditionalFormatRule.BLANK:
|
|
383
|
+
return v => isBlank(v);
|
|
384
|
+
case ConditionalFormatRule.NOT_BLANK:
|
|
385
|
+
return v => !isBlank(v);
|
|
386
|
+
default:
|
|
387
|
+
return () => false;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
switch (condition.rule) {
|
|
392
|
+
case ConditionalFormatRule.EQUALS:
|
|
393
|
+
return v => v == v1;
|
|
394
|
+
case ConditionalFormatRule.DOES_NOT_EQUAL:
|
|
395
|
+
return v => v != v1;
|
|
396
|
+
case ConditionalFormatRule.CONTAINS:
|
|
397
|
+
return v => typeof v === 'string' && v.includes(v1);
|
|
398
|
+
case ConditionalFormatRule.DOES_NOT_CONTAIN:
|
|
399
|
+
return v => typeof v === 'string' && !v.includes(v1);
|
|
400
|
+
case ConditionalFormatRule.BEGINS_WITH:
|
|
401
|
+
return v => typeof v === 'string' && v.startsWith(v1);
|
|
402
|
+
case ConditionalFormatRule.ENDS_WITH:
|
|
403
|
+
return v => typeof v === 'string' && v.endsWith(v1);
|
|
404
|
+
case ConditionalFormatRule.BLANK:
|
|
405
|
+
return v => isBlank(v);
|
|
406
|
+
case ConditionalFormatRule.NOT_BLANK:
|
|
407
|
+
return v => !isBlank(v);
|
|
408
|
+
default:
|
|
409
|
+
return () => false;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
function buildPivotDatagridConditionEvaluator(condition, columnNames) {
|
|
414
|
+
const fn = buildDatagridConditionEvaluator(condition);
|
|
415
|
+
return row => columnNames.some(columnName => fn(row[columnName]));
|
|
416
|
+
}
|
|
417
|
+
function evaluateDatagridCondition(rows, condition) {
|
|
418
|
+
const fn = buildDatagridConditionEvaluator(condition);
|
|
419
|
+
return rows.filter(row => fn(row[condition.columnName]));
|
|
420
|
+
}
|
|
421
|
+
function evaluatePivotDatagridCondition(rows, condition, mappedColumnNames) {
|
|
422
|
+
let columnNames = [condition.columnName];
|
|
423
|
+
const mappedColumnNamesSet = mappedColumnNames.get(condition.columnName);
|
|
424
|
+
if (!!mappedColumnNamesSet) {
|
|
425
|
+
columnNames = Array.from(mappedColumnNamesSet);
|
|
426
|
+
}
|
|
427
|
+
const fn = buildPivotDatagridConditionEvaluator(condition, columnNames);
|
|
428
|
+
return rows.filter(row => fn(row));
|
|
429
|
+
}
|
|
430
|
+
function parseColumnState(columnState) {
|
|
431
|
+
const rowGroupCols = [];
|
|
432
|
+
const pivotCols = [];
|
|
433
|
+
const valueCols = [];
|
|
434
|
+
const sortModel = [];
|
|
435
|
+
for (const col of columnState) {
|
|
436
|
+
// Row Group Columns:
|
|
437
|
+
// NOTE: we only want the highest level data.
|
|
438
|
+
if (col.rowGroup && col.rowGroupIndex === 0) {
|
|
439
|
+
rowGroupCols.push({
|
|
440
|
+
field: col.colId
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
// Pivot Columns:
|
|
444
|
+
// NOTE: we only want the highest level data.
|
|
445
|
+
if (col.pivot && col.pivotIndex === 0) {
|
|
446
|
+
pivotCols.push({
|
|
447
|
+
field: col.colId
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
// Value Columns (Aggregations):
|
|
451
|
+
if (col.aggFunc) {
|
|
452
|
+
valueCols.push({
|
|
453
|
+
field: col.colId,
|
|
454
|
+
aggFunc: col.aggFunc
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
// Sorting:
|
|
458
|
+
if (col.sort) {
|
|
459
|
+
sortModel.push({
|
|
460
|
+
colId: col.colId,
|
|
461
|
+
sort: col.sort
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
// NOTE: commenting this out since we only care about the highest level data.
|
|
466
|
+
// rowGroupCols.sort((a, b) => {
|
|
467
|
+
// const iA = columnState.find(c => c.colId === a.field)?.rowGroupIndex ?? 0;
|
|
468
|
+
// const iB = columnState.find(c => c.colId === b.field)?.rowGroupIndex ?? 0;
|
|
469
|
+
// return iA - iB;
|
|
470
|
+
// });
|
|
471
|
+
// pivotCols.sort((a, b) => {
|
|
472
|
+
// const iA = columnState.find(c => c.colId === a.field)?.pivotIndex ?? 0;
|
|
473
|
+
// const iB = columnState.find(c => c.colId === b.field)?.pivotIndex ?? 0;
|
|
474
|
+
// return iA - iB;
|
|
475
|
+
// });
|
|
476
|
+
sortModel.sort((a, b) => {
|
|
477
|
+
const iA = columnState.find(c => c.colId === a.colId)?.sortIndex ?? 0;
|
|
478
|
+
const iB = columnState.find(c => c.colId === b.colId)?.sortIndex ?? 0;
|
|
479
|
+
return iA - iB;
|
|
480
|
+
});
|
|
481
|
+
return {
|
|
482
|
+
rowGroupCols,
|
|
483
|
+
pivotCols,
|
|
484
|
+
valueCols,
|
|
485
|
+
sortModel
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
function filterRows(data, filterModel) {
|
|
489
|
+
const textOps = {
|
|
490
|
+
equals: (v, f) => (v ?? '').toLowerCase() === f.toLowerCase(),
|
|
491
|
+
notEqual: (v, f) => (v ?? '').toLowerCase() !== f.toLowerCase(),
|
|
492
|
+
contains: (v, f) => (v ?? '').toLowerCase().includes(f.toLowerCase()),
|
|
493
|
+
notContains: (v, f) => !(v ?? '').toLowerCase().includes(f.toLowerCase()),
|
|
494
|
+
startsWith: (v, f) => (v ?? '').toLowerCase().startsWith(f.toLowerCase()),
|
|
495
|
+
endsWith: (v, f) => (v ?? '').toLowerCase().endsWith(f.toLowerCase()),
|
|
496
|
+
blank: (v) => v == null || v === '',
|
|
497
|
+
notBlank: (v) => !(v == null || v === '')
|
|
498
|
+
};
|
|
499
|
+
const numberOps = {
|
|
500
|
+
equals: (v, f) => v == f,
|
|
501
|
+
notEqual: (v, f) => v != f,
|
|
502
|
+
lessThan: (v, f) => v < f,
|
|
503
|
+
lessThanOrEqual: (v, f) => v <= f,
|
|
504
|
+
greaterThan: (v, f) => v > f,
|
|
505
|
+
greaterThanOrEqual: (v, f) => v >= f,
|
|
506
|
+
inRange: (v, f, t) => v >= f && v <= t,
|
|
507
|
+
blank: (v) => v == null,
|
|
508
|
+
notBlank: (v) => v != null
|
|
509
|
+
};
|
|
510
|
+
function checkCondition(value, cond) {
|
|
511
|
+
const { filterType, type, filter, filterTo, values } = cond;
|
|
512
|
+
if (filterType === 'text') {
|
|
513
|
+
const fn = textOps[type ?? 'contains'];
|
|
514
|
+
return fn?.(value, filter);
|
|
515
|
+
}
|
|
516
|
+
if (filterType === 'number') {
|
|
517
|
+
const fn = numberOps[type ?? 'equals'];
|
|
518
|
+
return type === 'inRange'
|
|
519
|
+
? fn?.(value, filter, filterTo)
|
|
520
|
+
: fn?.(value, filter);
|
|
521
|
+
}
|
|
522
|
+
if (filterType === 'set') {
|
|
523
|
+
// Only boolean types are supported by set filter -- need to represent as string for comparison.
|
|
524
|
+
return (values ?? []).includes(`${value}`);
|
|
525
|
+
}
|
|
526
|
+
return true;
|
|
527
|
+
}
|
|
528
|
+
function compilePredicate(model) {
|
|
529
|
+
return (row) => {
|
|
530
|
+
return Object.entries(model).every(([field, filter]) => {
|
|
531
|
+
const value = row[field];
|
|
532
|
+
if ('conditions' in filter && Array.isArray(filter.conditions)) {
|
|
533
|
+
const logicFn = filter.operator === 'OR' ? 'some' : 'every';
|
|
534
|
+
return filter.conditions[logicFn](cond => checkCondition(value, cond));
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
return checkCondition(value, filter);
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
const predicate = compilePredicate(filterModel);
|
|
543
|
+
return data.filter(predicate);
|
|
544
|
+
}
|
|
545
|
+
function pivotData(data, rowGroupCols, pivotCols, valueCols) {
|
|
546
|
+
const groupBy = (row) => Object.fromEntries(rowGroupCols.map(col => [col.field, row[col.field]]));
|
|
547
|
+
const pivotBy = (row) => pivotCols.map(col => row[col.field]).join('_');
|
|
548
|
+
const grouped = new Map();
|
|
549
|
+
for (const row of data) {
|
|
550
|
+
const groupKey = JSON.stringify(groupBy(row));
|
|
551
|
+
if (!grouped.has(groupKey))
|
|
552
|
+
grouped.set(groupKey, []);
|
|
553
|
+
grouped.get(groupKey).push(row);
|
|
554
|
+
}
|
|
555
|
+
const rows = [];
|
|
556
|
+
const mappedColumnNames = new Map();
|
|
557
|
+
for (const [groupKey, groupRows] of grouped.entries()) {
|
|
558
|
+
const groupObj = JSON.parse(groupKey);
|
|
559
|
+
const pivotBuckets = new Map();
|
|
560
|
+
for (const row of groupRows) {
|
|
561
|
+
const pivotKey = pivotBy(row);
|
|
562
|
+
if (!pivotBuckets.has(pivotKey))
|
|
563
|
+
pivotBuckets.set(pivotKey, []);
|
|
564
|
+
pivotBuckets.get(pivotKey).push(row);
|
|
565
|
+
}
|
|
566
|
+
for (const [pivotKey, rows] of pivotBuckets.entries()) {
|
|
567
|
+
for (const { field, aggFunc } of valueCols) {
|
|
568
|
+
const values = rows.map(r => r[field]).filter(v => v != null);
|
|
569
|
+
const key = `${pivotKey} ${field}`;
|
|
570
|
+
let columnNames = mappedColumnNames.get(field);
|
|
571
|
+
if (!!columnNames) {
|
|
572
|
+
columnNames.add(key);
|
|
573
|
+
}
|
|
574
|
+
else {
|
|
575
|
+
columnNames = new Set([key]);
|
|
576
|
+
mappedColumnNames.set(field, columnNames);
|
|
577
|
+
}
|
|
578
|
+
switch (aggFunc) {
|
|
579
|
+
case 'sum':
|
|
580
|
+
groupObj[key] = values.map(Number).reduce((a, b) => a + b, 0);
|
|
581
|
+
break;
|
|
582
|
+
case 'count':
|
|
583
|
+
groupObj[key] = values.length;
|
|
584
|
+
break;
|
|
585
|
+
case 'min':
|
|
586
|
+
groupObj[key] = values.reduce((a, b) => (a < b ? a : b), values[0]);
|
|
587
|
+
break;
|
|
588
|
+
case 'max':
|
|
589
|
+
groupObj[key] = values.reduce((a, b) => (a > b ? a : b), values[0]);
|
|
590
|
+
break;
|
|
591
|
+
case 'avg': {
|
|
592
|
+
const nums = values.map(Number).filter(n => !isNaN(n));
|
|
593
|
+
groupObj[key] = nums.length ? nums.reduce((a, b) => a + b, 0) / nums.length : null;
|
|
594
|
+
break;
|
|
595
|
+
}
|
|
596
|
+
case 'first':
|
|
597
|
+
groupObj[key] = values[0];
|
|
598
|
+
break;
|
|
599
|
+
case 'last':
|
|
600
|
+
groupObj[key] = values[values.length - 1];
|
|
601
|
+
break;
|
|
602
|
+
default:
|
|
603
|
+
groupObj[key] = null;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
rows.push(groupObj);
|
|
608
|
+
}
|
|
609
|
+
return { rows, mappedColumnNames };
|
|
610
|
+
}
|
|
611
|
+
function groupAndAggregate(data, rowGroupCols, groupKeys, valueCols) {
|
|
612
|
+
const level = groupKeys.length;
|
|
613
|
+
const groupField = rowGroupCols[level]?.field;
|
|
614
|
+
if (!groupField)
|
|
615
|
+
return data;
|
|
616
|
+
const grouped = new Map();
|
|
617
|
+
for (const row of data) {
|
|
618
|
+
const key = row[groupField];
|
|
619
|
+
if (!grouped.has(key))
|
|
620
|
+
grouped.set(key, []);
|
|
621
|
+
grouped.get(key).push(row);
|
|
622
|
+
}
|
|
623
|
+
const output = [];
|
|
624
|
+
for (const [key, rows] of grouped.entries()) {
|
|
625
|
+
if (level < rowGroupCols.length - 1) {
|
|
626
|
+
output.push({
|
|
627
|
+
group: true,
|
|
628
|
+
key,
|
|
629
|
+
children: groupAndAggregate(rows, rowGroupCols, [...groupKeys, key], valueCols)
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
633
|
+
const aggData = {};
|
|
634
|
+
for (const { field, aggFunc } of valueCols) {
|
|
635
|
+
const rawValues = rows.map(r => r[field]).filter(v => v != null);
|
|
636
|
+
switch (aggFunc) {
|
|
637
|
+
case 'sum': {
|
|
638
|
+
const nums = rawValues.map(Number).filter(v => !isNaN(v));
|
|
639
|
+
aggData[field] = nums.reduce((a, b) => a + b, 0);
|
|
640
|
+
break;
|
|
641
|
+
}
|
|
642
|
+
case 'avg': {
|
|
643
|
+
const nums = rawValues.map(Number).filter(v => !isNaN(v));
|
|
644
|
+
const total = nums.reduce((a, b) => a + b, 0);
|
|
645
|
+
aggData[field] = nums.length > 0 ? total / nums.length : null;
|
|
646
|
+
break;
|
|
647
|
+
}
|
|
648
|
+
case 'min':
|
|
649
|
+
aggData[field] = rawValues.reduce((a, b) => (a < b ? a : b), rawValues[0]);
|
|
650
|
+
break;
|
|
651
|
+
case 'max':
|
|
652
|
+
aggData[field] = rawValues.reduce((a, b) => (a > b ? a : b), rawValues[0]);
|
|
653
|
+
break;
|
|
654
|
+
case 'count':
|
|
655
|
+
aggData[field] = rawValues.length;
|
|
656
|
+
break;
|
|
657
|
+
case 'first':
|
|
658
|
+
aggData[field] = rawValues[0];
|
|
659
|
+
break;
|
|
660
|
+
case 'last':
|
|
661
|
+
aggData[field] = rawValues[rawValues.length - 1];
|
|
662
|
+
break;
|
|
663
|
+
default:
|
|
664
|
+
aggData[field] = null;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
// NOTE: we only want the highest level data -- we don't care about child rows.
|
|
668
|
+
output.push({
|
|
669
|
+
[groupField]: key,
|
|
670
|
+
...aggData,
|
|
671
|
+
// children: rows
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
return output;
|
|
676
|
+
}
|
|
677
|
+
function sortRows(data, sortModel) {
|
|
678
|
+
return [...data].sort((a, b) => {
|
|
679
|
+
for (const { colId, sort } of sortModel) {
|
|
680
|
+
const valA = a[colId];
|
|
681
|
+
const valB = b[colId];
|
|
682
|
+
if (valA === valB)
|
|
683
|
+
continue;
|
|
684
|
+
const cmp = valA > valB ? 1 : -1;
|
|
685
|
+
return sort === 'asc' ? cmp : -cmp;
|
|
686
|
+
}
|
|
687
|
+
return 0;
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
export function transformDatagrid(rows, datagridState, locale, condition) {
|
|
691
|
+
const columnState = datagridState.columnState ?? [];
|
|
692
|
+
const filterModel = datagridState.filterModel ?? {};
|
|
693
|
+
const isPivotMode = !!datagridState.isPivotMode;
|
|
694
|
+
const columnFormats = datagridState.columnFormats ?? [];
|
|
695
|
+
const { rowGroupCols, pivotCols, valueCols, sortModel } = parseColumnState(columnState);
|
|
696
|
+
rows = filterRows(rows, filterModel);
|
|
697
|
+
const chartRowData = [];
|
|
698
|
+
// IMPORTANT: we evaluate the datagrid condition AFTER we are done with all transformations.
|
|
699
|
+
if (isPivotMode && pivotCols.length > 0 && valueCols.length > 0) {
|
|
700
|
+
const pivotOutput = pivotData(rows, rowGroupCols, pivotCols, valueCols);
|
|
701
|
+
rows = pivotOutput.rows;
|
|
702
|
+
rows = sortModel.length > 0 ? sortRows(rows, sortModel) : rows;
|
|
703
|
+
let mappedDisplayColumnNames = new Map();
|
|
704
|
+
// Should not need to do hidden/visible column analysis -- pivoting creates new results with only the necessary columns.
|
|
705
|
+
rows.forEach(row => {
|
|
706
|
+
let chartRow = {};
|
|
707
|
+
columnFormats.forEach(columnFormat => {
|
|
708
|
+
if (columnFormat.name in row) {
|
|
709
|
+
const value = row[columnFormat.name];
|
|
710
|
+
const formattedValue = evaluateValueFormat(columnFormat, row[columnFormat.name], locale);
|
|
711
|
+
row[columnFormat.displayName] = formattedValue;
|
|
712
|
+
chartRow[columnFormat.displayName] = formatNumberEnabled(columnFormat.valueFormat) ? value : formattedValue;
|
|
713
|
+
// Remove name in favor of display name.
|
|
714
|
+
if (columnFormat.displayName !== columnFormat.name) {
|
|
715
|
+
delete row[columnFormat.name];
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
else {
|
|
719
|
+
const mappedColumnNamesSet = pivotOutput.mappedColumnNames.get(columnFormat.name);
|
|
720
|
+
if (!!mappedColumnNamesSet) {
|
|
721
|
+
const mappedColumnNamesArr = Array.from(mappedColumnNamesSet);
|
|
722
|
+
for (const mappedColumnName of mappedColumnNamesArr) {
|
|
723
|
+
if (mappedColumnName in row) {
|
|
724
|
+
const adjDisplayName = mappedColumnName.replace(columnFormat.name, columnFormat.displayName);
|
|
725
|
+
const value = row[mappedColumnName];
|
|
726
|
+
const formattedValue = evaluateValueFormat(columnFormat, row[mappedColumnName], locale);
|
|
727
|
+
row[adjDisplayName] = formattedValue;
|
|
728
|
+
chartRow[adjDisplayName] = formatNumberEnabled(columnFormat.valueFormat) ? value : formattedValue;
|
|
729
|
+
// Remove name in favor of display name.
|
|
730
|
+
if (adjDisplayName !== mappedColumnName) {
|
|
731
|
+
delete row[mappedColumnName];
|
|
732
|
+
}
|
|
733
|
+
let displayColumnNames = mappedDisplayColumnNames.get(columnFormat.displayName);
|
|
734
|
+
if (!!displayColumnNames) {
|
|
735
|
+
displayColumnNames.add(adjDisplayName);
|
|
736
|
+
}
|
|
737
|
+
else {
|
|
738
|
+
displayColumnNames = new Set([adjDisplayName]);
|
|
739
|
+
mappedDisplayColumnNames.set(columnFormat.displayName, displayColumnNames);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
});
|
|
746
|
+
chartRowData.push(chartRow);
|
|
747
|
+
});
|
|
748
|
+
if (!!condition) {
|
|
749
|
+
rows = evaluatePivotDatagridCondition(rows, condition, mappedDisplayColumnNames);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
else {
|
|
753
|
+
if (rowGroupCols.length > 0) {
|
|
754
|
+
rows = groupAndAggregate(rows, rowGroupCols, [], valueCols);
|
|
755
|
+
}
|
|
756
|
+
rows = sortModel.length > 0 ? sortRows(rows, sortModel) : rows;
|
|
757
|
+
const hiddenColumnNames = columnState.filter(column => !!column.hide && !column.rowGroup).map(column => column.colId) ?? [];
|
|
758
|
+
const visibleColumnFormats = columnFormats.filter(column => !hiddenColumnNames.includes(column.name)) ?? [];
|
|
759
|
+
rows.forEach(row => {
|
|
760
|
+
let chartRow = {};
|
|
761
|
+
hiddenColumnNames.forEach(columnName => {
|
|
762
|
+
delete row[columnName];
|
|
763
|
+
});
|
|
764
|
+
visibleColumnFormats.forEach(columnFormat => {
|
|
765
|
+
const value = row[columnFormat.name];
|
|
766
|
+
const formattedValue = evaluateValueFormat(columnFormat, row[columnFormat.name], locale);
|
|
767
|
+
row[columnFormat.displayName] = formattedValue;
|
|
768
|
+
chartRow[columnFormat.displayName] = formatNumberEnabled(columnFormat.valueFormat) ? value : formattedValue;
|
|
769
|
+
// Remove name in favor of display name.
|
|
770
|
+
if (columnFormat.displayName !== columnFormat.name) {
|
|
771
|
+
delete row[columnFormat.name];
|
|
772
|
+
}
|
|
773
|
+
});
|
|
774
|
+
chartRowData.push(chartRow);
|
|
775
|
+
});
|
|
776
|
+
if (!!condition) {
|
|
777
|
+
rows = evaluateDatagridCondition(rows, condition);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
return { ...datagridState, adjRowData: rows, chartRowData };
|
|
781
|
+
}
|