@graphenedata/cli 0.0.5 → 0.0.7
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/cli.ts +56 -19
- package/dist/cli/cli.js +1197 -484
- package/dist/docs/graphene.md +184 -171
- package/dist/ui/component-utilities/inputUtils.ts +11 -0
- package/dist/ui/components/Area.svelte +6 -3
- package/dist/ui/components/AreaChart.svelte +2 -1
- package/dist/ui/components/Bar.svelte +14 -8
- package/dist/ui/components/BarChart.svelte +3 -2
- package/dist/ui/components/Chart.svelte +48 -101
- package/dist/ui/components/Column.svelte +2 -0
- package/dist/ui/components/Line.svelte +8 -5
- package/dist/ui/components/LineChart.svelte +3 -3
- package/dist/ui/components/QueryLoad.svelte +1 -1
- package/dist/ui/internal/queryEngine.ts +29 -8
- package/dist/ui/web.js +3 -2
- package/package.json +3 -2
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
getFormatObjectFromString,
|
|
17
17
|
} from '../component-utilities/formatting.js'
|
|
18
18
|
import {getThemeStores} from '../component-utilities/themeStores'
|
|
19
|
+
import {parseCommaList} from '../component-utilities/inputUtils.ts'
|
|
19
20
|
|
|
20
21
|
const {resolveColor} = getThemeStores()
|
|
21
22
|
|
|
@@ -77,8 +78,8 @@
|
|
|
77
78
|
// Prop check. If local props supplied, use those. Otherwise fall back to global props.
|
|
78
79
|
$: data = $props.data
|
|
79
80
|
$: x = $props.x
|
|
80
|
-
$: y = ySet ? y : $props.y
|
|
81
|
-
$: y2 = y2Set ? y2 : $props.y2
|
|
81
|
+
$: y = ySet ? parseCommaList(y) : $props.y
|
|
82
|
+
$: y2 = y2Set ? parseCommaList(y2) : $props.y2
|
|
82
83
|
$: yFormat = $props.yFormat
|
|
83
84
|
$: y2Format = $props.y2Format
|
|
84
85
|
$: yCount = $props.yCount
|
|
@@ -89,14 +90,18 @@
|
|
|
89
90
|
$: columnSummary = $props.columnSummary
|
|
90
91
|
$: sort = $props.sort
|
|
91
92
|
$: series = seriesSet ? series : $props.series
|
|
93
|
+
$: seriesOrder = parseCommaList(seriesOrder)
|
|
92
94
|
|
|
93
95
|
let stackedData
|
|
94
96
|
let sortOrder
|
|
95
97
|
let defaultLabelPosition
|
|
96
98
|
|
|
97
|
-
$: if (!series &&
|
|
99
|
+
$: if (!series && (!Array.isArray(y) || y.length === 1)) {
|
|
98
100
|
// Single Series
|
|
99
|
-
|
|
101
|
+
{
|
|
102
|
+
let col = Array.isArray(y) ? y[0] : y
|
|
103
|
+
name = name ?? formatTitle(col, columnSummary[col].title)
|
|
104
|
+
}
|
|
100
105
|
|
|
101
106
|
if (swapXY && xType !== 'category') {
|
|
102
107
|
data = getCompletedData(data, x, y, series, true, xType !== 'time')
|
|
@@ -112,10 +117,11 @@
|
|
|
112
117
|
if (sort === true && xType === 'category') {
|
|
113
118
|
stackedData = getStackedData(data, x, y)
|
|
114
119
|
|
|
115
|
-
if (
|
|
120
|
+
if (Array.isArray(y) && y.length > 1) {
|
|
116
121
|
stackedData = getSortedData(stackedData, 'stackTotal', false)
|
|
117
122
|
} else {
|
|
118
|
-
|
|
123
|
+
let col = Array.isArray(y) ? y[0] : y
|
|
124
|
+
stackedData = getSortedData(stackedData, col, false)
|
|
119
125
|
}
|
|
120
126
|
|
|
121
127
|
sortOrder = stackedData.map((d) => d[x])
|
|
@@ -233,7 +239,7 @@
|
|
|
233
239
|
if (
|
|
234
240
|
labels === true &&
|
|
235
241
|
type === 'stacked' &&
|
|
236
|
-
(
|
|
242
|
+
((Array.isArray(y) && y.length > 1) || (series !== undefined)) &&
|
|
237
243
|
stackTotalLabel === true &&
|
|
238
244
|
series !== x
|
|
239
245
|
) {
|
|
@@ -309,7 +315,7 @@
|
|
|
309
315
|
} else {
|
|
310
316
|
d.yAxis[0] = {...d.yAxis[0], ...chartOverrides.yAxis}
|
|
311
317
|
d.xAxis = {...d.xAxis, ...chartOverrides.xAxis}
|
|
312
|
-
if (
|
|
318
|
+
if (y2Count > 0) {
|
|
313
319
|
d.yAxis[1] = {...d.yAxis[1], show: true}
|
|
314
320
|
if (['line', 'bar', 'scatter'].includes(y2SeriesType)) {
|
|
315
321
|
for (let i = 0; i < y2Count; i++) {
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import Bar from './Bar.svelte'
|
|
4
4
|
import QueryLoad from './QueryLoad.svelte'
|
|
5
5
|
import {getThemeStores} from '../component-utilities/themeStores'
|
|
6
|
+
import {parseCommaList} from '../component-utilities/inputUtils.ts'
|
|
6
7
|
|
|
7
8
|
const {resolveColor, resolveColorsObject, resolveColorPalette} = getThemeStores()
|
|
8
9
|
|
|
@@ -114,10 +115,10 @@
|
|
|
114
115
|
export let xLabelWrap = undefined
|
|
115
116
|
</script>
|
|
116
117
|
|
|
117
|
-
<QueryLoad data={data} fields={{x, y, y2, series}} let:loaded>
|
|
118
|
+
<QueryLoad data={data} fields={{x, y: parseCommaList(y), y2: parseCommaList(y2), series}} let:loaded>
|
|
118
119
|
<Chart
|
|
119
120
|
data={loaded}
|
|
120
|
-
chartContext={{data, x, y,
|
|
121
|
+
chartContext={{data, x, y, series}}
|
|
121
122
|
{x}
|
|
122
123
|
{y}
|
|
123
124
|
{y2}
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
import checkInputs from '../component-utilities/checkInputs.js'
|
|
24
24
|
import {getThemeStores} from '../component-utilities/themeStores'
|
|
25
25
|
import {toBoolean} from '../component-utilities/convert'
|
|
26
|
+
import {parseCommaList} from '../component-utilities/inputUtils.ts'
|
|
26
27
|
import {logError} from '../internal/telemetry.ts'
|
|
27
28
|
|
|
28
29
|
const {theme, resolveColor, resolveColorsObject, resolveColorPalette} = getThemeStores()
|
|
@@ -250,7 +251,10 @@
|
|
|
250
251
|
inputCols = []
|
|
251
252
|
optCols = []
|
|
252
253
|
uColName = []
|
|
253
|
-
|
|
254
|
+
// Normalize list-like inputs first
|
|
255
|
+
y = parseCommaList(y)
|
|
256
|
+
y2 = parseCommaList(y2)
|
|
257
|
+
ySet = y.length > 0
|
|
254
258
|
xSet = x ? true : false
|
|
255
259
|
|
|
256
260
|
checkInputs(data) // check that dataset exists
|
|
@@ -286,7 +290,7 @@
|
|
|
286
290
|
}
|
|
287
291
|
}
|
|
288
292
|
|
|
289
|
-
y = unusedColumns
|
|
293
|
+
y = unusedColumns // always array; empty handled by required prop checks
|
|
290
294
|
}
|
|
291
295
|
// Establish required columns based on chart type:
|
|
292
296
|
if (bubble) {
|
|
@@ -322,40 +326,17 @@
|
|
|
322
326
|
}
|
|
323
327
|
|
|
324
328
|
// Fix for stacked100 overwriting y variable. Bandaid fix - not a long-term solution:
|
|
325
|
-
if (stacked100 === true && y.includes('_pct') && originalRun === false) {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
y[i] = y[i].replace('_pct', '')
|
|
329
|
-
}
|
|
330
|
-
originalRun = false
|
|
331
|
-
} else {
|
|
332
|
-
y = y.replace('_pct', '')
|
|
333
|
-
originalRun = false
|
|
334
|
-
}
|
|
329
|
+
if (stacked100 === true && Array.isArray(y) && y.some(col => col.includes('_pct')) && originalRun === false) {
|
|
330
|
+
for (let i = 0; i < y.length; i++) y[i] = y[i].replace('_pct', '')
|
|
331
|
+
originalRun = false
|
|
335
332
|
}
|
|
336
333
|
|
|
337
334
|
// Check the inputs supplied to the chart:
|
|
338
335
|
if (x) {
|
|
339
336
|
inputCols.push(x)
|
|
340
337
|
}
|
|
341
|
-
if (y)
|
|
342
|
-
|
|
343
|
-
for (i = 0; i < y.length; i++) {
|
|
344
|
-
inputCols.push(y[i])
|
|
345
|
-
}
|
|
346
|
-
} else {
|
|
347
|
-
inputCols.push(y)
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
if (y2) {
|
|
351
|
-
if (typeof y2 === 'object') {
|
|
352
|
-
for (i = 0; i < y2.length; i++) {
|
|
353
|
-
inputCols.push(y2[i])
|
|
354
|
-
}
|
|
355
|
-
} else {
|
|
356
|
-
inputCols.push(y2)
|
|
357
|
-
}
|
|
358
|
-
}
|
|
338
|
+
if (Array.isArray(y)) for (i = 0; i < y.length; i++) inputCols.push(y[i])
|
|
339
|
+
if (Array.isArray(y2)) for (i = 0; i < y2.length; i++) inputCols.push(y2[i])
|
|
359
340
|
if (size) {
|
|
360
341
|
inputCols.push(size)
|
|
361
342
|
}
|
|
@@ -374,18 +355,8 @@
|
|
|
374
355
|
|
|
375
356
|
if (stacked100 === true) {
|
|
376
357
|
data = getStackPercentages(data, x, y)
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
for (let i = 0; i < y.length; i++) {
|
|
380
|
-
y[i] = y[i] + '_pct'
|
|
381
|
-
}
|
|
382
|
-
originalRun = false
|
|
383
|
-
} else {
|
|
384
|
-
y = y + '_pct'
|
|
385
|
-
originalRun = false
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
// Re-run column summary for new columns (not ideal):
|
|
358
|
+
for (let i = 0; i < y.length; i++) y[i] = y[i] + '_pct'
|
|
359
|
+
originalRun = false
|
|
389
360
|
columnSummary = getColumnSummary(data)
|
|
390
361
|
}
|
|
391
362
|
|
|
@@ -428,7 +399,7 @@
|
|
|
428
399
|
}
|
|
429
400
|
|
|
430
401
|
// Throw error if attempting to plot secondary y-axis on horizontal chart:
|
|
431
|
-
if (swapXY && y2) {
|
|
402
|
+
if (swapXY && y2.length) {
|
|
432
403
|
throw Error(
|
|
433
404
|
'Horizontal charts do not support a secondary y-axis. You can either set swapXY=false or remove the y2 prop from your chart.',
|
|
434
405
|
)
|
|
@@ -446,7 +417,10 @@
|
|
|
446
417
|
// Sort data based on xType
|
|
447
418
|
// ---------------------------------------------------------------------------------------
|
|
448
419
|
if (sort) {
|
|
449
|
-
let sortColumn =
|
|
420
|
+
let sortColumn = x
|
|
421
|
+
if (xDataType === 'category') {
|
|
422
|
+
sortColumn = Array.isArray(y) ? (y[0] ?? x) : x
|
|
423
|
+
}
|
|
450
424
|
let sortAscending = xDataType !== 'category'
|
|
451
425
|
data = getSortedData(data, sortColumn, sortAscending)
|
|
452
426
|
}
|
|
@@ -479,38 +453,16 @@
|
|
|
479
453
|
xFormat = columnSummary[x].format
|
|
480
454
|
}
|
|
481
455
|
|
|
482
|
-
if (
|
|
456
|
+
if (y.length === 0) {
|
|
483
457
|
yFormat = 'str'
|
|
484
458
|
} else {
|
|
485
|
-
if (yFmt)
|
|
486
|
-
|
|
487
|
-
yFormat = getFormatObjectFromString(yFmt, columnSummary[y[0]].format?.valueType)
|
|
488
|
-
} else {
|
|
489
|
-
yFormat = getFormatObjectFromString(yFmt, columnSummary[y].format?.valueType)
|
|
490
|
-
}
|
|
491
|
-
} else {
|
|
492
|
-
if (typeof y === 'object') {
|
|
493
|
-
yFormat = columnSummary[y[0]].format
|
|
494
|
-
} else {
|
|
495
|
-
yFormat = columnSummary[y].format
|
|
496
|
-
}
|
|
497
|
-
}
|
|
459
|
+
if (yFmt) yFormat = getFormatObjectFromString(yFmt, columnSummary[y[0]].format?.valueType)
|
|
460
|
+
else yFormat = columnSummary[y[0]].format
|
|
498
461
|
}
|
|
499
462
|
|
|
500
|
-
if (y2) {
|
|
501
|
-
if (y2Fmt)
|
|
502
|
-
|
|
503
|
-
y2Format = getFormatObjectFromString(y2Fmt, columnSummary[y2[0]].format?.valueType)
|
|
504
|
-
} else {
|
|
505
|
-
y2Format = getFormatObjectFromString(y2Fmt, columnSummary[y2].format?.valueType)
|
|
506
|
-
}
|
|
507
|
-
} else {
|
|
508
|
-
if (typeof y2 === 'object') {
|
|
509
|
-
y2Format = columnSummary[y2[0]].format
|
|
510
|
-
} else {
|
|
511
|
-
y2Format = columnSummary[y2].format
|
|
512
|
-
}
|
|
513
|
-
}
|
|
463
|
+
if (y2.length) {
|
|
464
|
+
if (y2Fmt) y2Format = getFormatObjectFromString(y2Fmt, columnSummary[y2[0]].format?.valueType)
|
|
465
|
+
else y2Format = columnSummary[y2[0]].format
|
|
514
466
|
}
|
|
515
467
|
|
|
516
468
|
if (size) {
|
|
@@ -523,21 +475,9 @@
|
|
|
523
475
|
|
|
524
476
|
xUnitSummary = columnSummary[x].columnUnitSummary
|
|
525
477
|
|
|
526
|
-
if (y)
|
|
527
|
-
if (typeof y === 'object') {
|
|
528
|
-
yUnitSummary = columnSummary[y[0]].columnUnitSummary
|
|
529
|
-
} else {
|
|
530
|
-
yUnitSummary = columnSummary[y].columnUnitSummary
|
|
531
|
-
}
|
|
532
|
-
}
|
|
478
|
+
if (y.length) yUnitSummary = columnSummary[y[0]].columnUnitSummary
|
|
533
479
|
|
|
534
|
-
if (y2)
|
|
535
|
-
if (typeof y2 === 'object') {
|
|
536
|
-
y2UnitSummary = columnSummary[y2[0]].columnUnitSummary
|
|
537
|
-
} else {
|
|
538
|
-
y2UnitSummary = columnSummary[y2].columnUnitSummary
|
|
539
|
-
}
|
|
540
|
-
}
|
|
480
|
+
if (y2.length) y2UnitSummary = columnSummary[y2[0]].columnUnitSummary
|
|
541
481
|
|
|
542
482
|
if (xAxisTitle === 'true') {
|
|
543
483
|
xAxisTitle = formatTitle(x, xFormat)
|
|
@@ -546,13 +486,21 @@
|
|
|
546
486
|
}
|
|
547
487
|
|
|
548
488
|
if (yAxisTitle === 'true') {
|
|
549
|
-
|
|
489
|
+
if (y.length === 1) {
|
|
490
|
+
yAxisTitle = formatTitle(y[0], yFormat)
|
|
491
|
+
} else {
|
|
492
|
+
yAxisTitle = ''
|
|
493
|
+
}
|
|
550
494
|
} else if (yAxisTitle === 'false') {
|
|
551
495
|
yAxisTitle = ''
|
|
552
496
|
}
|
|
553
497
|
|
|
554
498
|
if (y2AxisTitle === 'true') {
|
|
555
|
-
|
|
499
|
+
if (y2.length === 1) {
|
|
500
|
+
y2AxisTitle = formatTitle(y2[0], y2Format)
|
|
501
|
+
} else {
|
|
502
|
+
y2AxisTitle = ''
|
|
503
|
+
}
|
|
556
504
|
} else if (y2AxisTitle === 'false') {
|
|
557
505
|
y2AxisTitle = ''
|
|
558
506
|
}
|
|
@@ -560,18 +508,13 @@
|
|
|
560
508
|
// ---------------------------------------------------------------------------------------
|
|
561
509
|
// Get total series count
|
|
562
510
|
// ---------------------------------------------------------------------------------------
|
|
563
|
-
let yCount =
|
|
511
|
+
let yCount = y.length
|
|
564
512
|
let seriesCount = series ? getDistinctCount(data, series) : 1
|
|
565
513
|
let ySeriesCount = yCount * seriesCount
|
|
566
514
|
|
|
567
515
|
// y2Count may need to be adjusted to also factor in the series column. For now, we really
|
|
568
516
|
// only need to know that it's multi-series, so > 1 is sufficient
|
|
569
|
-
let y2Count =
|
|
570
|
-
if (typeof y2 === 'object') {
|
|
571
|
-
y2Count = y2.length
|
|
572
|
-
} else if (y2) {
|
|
573
|
-
y2Count = 1
|
|
574
|
-
}
|
|
517
|
+
let y2Count = y2.length
|
|
575
518
|
let totalSeriesCount = ySeriesCount + y2Count
|
|
576
519
|
|
|
577
520
|
// ---------------------------------------------------------------------------------------
|
|
@@ -594,15 +537,13 @@
|
|
|
594
537
|
}
|
|
595
538
|
|
|
596
539
|
let minYValue
|
|
597
|
-
if (
|
|
540
|
+
if (y.length) {
|
|
598
541
|
minYValue = columnSummary[y[0]].columnUnitSummary.min
|
|
599
542
|
for (let i = 0; i < y.length; i++) {
|
|
600
543
|
if (columnSummary[y[i]].columnUnitSummary.min < minYValue) {
|
|
601
544
|
minYValue = columnSummary[y[i]].columnUnitSummary.min
|
|
602
545
|
}
|
|
603
546
|
}
|
|
604
|
-
} else if (y) {
|
|
605
|
-
minYValue = columnSummary[y].columnUnitSummary.min
|
|
606
547
|
}
|
|
607
548
|
|
|
608
549
|
if (yLog === true && minYValue <= 0 && minYValue !== null) {
|
|
@@ -747,7 +688,7 @@
|
|
|
747
688
|
}
|
|
748
689
|
} else {
|
|
749
690
|
let primaryAxisColor = (() => {
|
|
750
|
-
if (!y2) return undefined
|
|
691
|
+
if (!(Array.isArray(y2) && y2.length)) return undefined
|
|
751
692
|
if ($yAxisColorStore === 'true') return $colorPaletteStore[0]
|
|
752
693
|
if ($yAxisColorStore === 'false') return undefined
|
|
753
694
|
return $yAxisColorStore
|
|
@@ -857,7 +798,7 @@
|
|
|
857
798
|
|
|
858
799
|
hasTitle = title ? true : false
|
|
859
800
|
hasSubtitle = subtitle ? true : false
|
|
860
|
-
hasLegend = legend * (series !== null || (
|
|
801
|
+
hasLegend = legend * (series !== null || (y.length > 1))
|
|
861
802
|
hasTopAxisTitle = yAxisTitle !== '' && swapXY
|
|
862
803
|
hasBottomAxisTitle = xAxisTitle !== '' && !swapXY
|
|
863
804
|
|
|
@@ -1048,7 +989,13 @@
|
|
|
1048
989
|
console.error(setTextRed, `Error in ${chartType}: ${e.message}`)
|
|
1049
990
|
|
|
1050
991
|
// Make an "id" for the chart so its clear to users/agents exactly which caused an error.
|
|
1051
|
-
let fieldStr = Object.entries(chartContext || {})
|
|
992
|
+
let fieldStr = Object.entries(chartContext || {})
|
|
993
|
+
.filter(([_, val]) => {
|
|
994
|
+
if (Array.isArray(val)) return val.length > 0
|
|
995
|
+
if (typeof val === 'string') return val.trim().length > 0
|
|
996
|
+
return Boolean(val)
|
|
997
|
+
})
|
|
998
|
+
.map(([name, val]) => `${name}="${Array.isArray(val) ? val.join(', ') : val}"`)
|
|
1052
999
|
let id = `${title || chartType} (${fieldStr.join(' ')})`
|
|
1053
1000
|
logError(e, {id})
|
|
1054
1001
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import {propKey, strictBuild} from '../component-utilities/chartContext.js'
|
|
8
8
|
import {getThemeStores} from '../component-utilities/themeStores'
|
|
9
9
|
import {toBoolean} from '../component-utilities/convert'
|
|
10
|
+
import {parseCommaList} from '../component-utilities/inputUtils.ts'
|
|
10
11
|
|
|
11
12
|
export let id: string
|
|
12
13
|
export let description: string | undefined = undefined
|
|
@@ -64,6 +65,7 @@
|
|
|
64
65
|
$: colorScaleStore = resolveColorPalette(colorScale)
|
|
65
66
|
|
|
66
67
|
const props = getContext(propKey)
|
|
68
|
+
$: colorBreakpoints = parseCommaList(colorBreakpoints)
|
|
67
69
|
|
|
68
70
|
const identifier = Symbol('GrapheneColumn')
|
|
69
71
|
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import {formatValue, getFormatObjectFromString} from '../component-utilities/formatting.js'
|
|
9
9
|
import {getThemeStores} from '../component-utilities/themeStores'
|
|
10
10
|
import {toBoolean} from '../component-utilities/convert'
|
|
11
|
+
import {parseCommaList} from '../component-utilities/inputUtils.ts'
|
|
11
12
|
|
|
12
13
|
const {resolveColor} = getThemeStores()
|
|
13
14
|
const props = getContext(propKey)
|
|
@@ -90,12 +91,14 @@
|
|
|
90
91
|
$: xMismatch = $props.xMismatch
|
|
91
92
|
$: columnSummary = $props.columnSummary
|
|
92
93
|
$: series = seriesSet ? series : $props.series
|
|
93
|
-
$: resolvedY = ySet ? y : $props.y
|
|
94
|
-
$: resolvedY2 = y2Set ? y2 : $props.y2
|
|
94
|
+
$: resolvedY = ySet ? parseCommaList(y) : $props.y
|
|
95
|
+
$: resolvedY2 = y2Set ? parseCommaList(y2) : $props.y2
|
|
96
|
+
$: seriesOrder = parseCommaList(seriesOrder)
|
|
95
97
|
|
|
96
98
|
$: {
|
|
97
|
-
if (!series &&
|
|
98
|
-
|
|
99
|
+
if (!series && (!Array.isArray(resolvedY) || resolvedY.length === 1)) {
|
|
100
|
+
let col = Array.isArray(resolvedY) ? resolvedY[0] : resolvedY
|
|
101
|
+
if (columnSummary?.[col]) name = name ?? formatTitle(col, columnSummary[col].title)
|
|
99
102
|
} else {
|
|
100
103
|
try {
|
|
101
104
|
data = getCompletedData(data, x, resolvedY, series)
|
|
@@ -194,7 +197,7 @@
|
|
|
194
197
|
} else {
|
|
195
198
|
value.yAxis[0] = {...value.yAxis[0], ...chartOverrides.yAxis}
|
|
196
199
|
value.xAxis = {...value.xAxis, ...chartOverrides.xAxis}
|
|
197
|
-
if (
|
|
200
|
+
if (y2Count > 0) {
|
|
198
201
|
value.yAxis[1] = {...value.yAxis[1], show: true}
|
|
199
202
|
if (['line', 'bar', 'scatter'].includes(y2SeriesType)) {
|
|
200
203
|
for (let index = 0; index < y2Count; index++) {
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import Line from './Line.svelte'
|
|
4
4
|
import QueryLoad from './QueryLoad.svelte'
|
|
5
5
|
import {getThemeStores} from '../component-utilities/themeStores'
|
|
6
|
+
import {parseCommaList} from '../component-utilities/inputUtils.ts'
|
|
6
7
|
|
|
7
8
|
const {resolveColor, resolveColorsObject, resolveColorPalette} = getThemeStores()
|
|
8
9
|
|
|
@@ -98,11 +99,10 @@
|
|
|
98
99
|
export let xLabelWrap = undefined
|
|
99
100
|
</script>
|
|
100
101
|
|
|
101
|
-
|
|
102
|
-
<QueryLoad data={data} fields={{x, y, y2, series}} let:loaded>
|
|
102
|
+
<QueryLoad data={data} fields={{x, y: parseCommaList(y), y2: parseCommaList(y2), series}} let:loaded>
|
|
103
103
|
<Chart
|
|
104
104
|
data={loaded}
|
|
105
|
-
chartContext={{data, x, y,
|
|
105
|
+
chartContext={{data, x, y, series}}
|
|
106
106
|
{x}
|
|
107
107
|
{y}
|
|
108
108
|
{y2}
|
|
@@ -23,7 +23,7 @@ interface QueryNode {
|
|
|
23
23
|
contents: string
|
|
24
24
|
callback?: ResultHandler
|
|
25
25
|
loading: boolean
|
|
26
|
-
fields: Map<string, string>
|
|
26
|
+
fields: Map<string, string | string[]>
|
|
27
27
|
errors: Error[]
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -41,10 +41,18 @@ function updateParam (name: string, value: any) {
|
|
|
41
41
|
runAll() // for now, do the easy thing and reload it all
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
function query (source: string, fields: Record<string, string>, callback: ResultHandler) {
|
|
44
|
+
function query (source: string, fields: Record<string, string | string[]>, callback: ResultHandler) {
|
|
45
45
|
// using Map here because it preserves the order in which we add fields to the select, which we use when we get the result.
|
|
46
46
|
let map = new Map(Object.entries(fields))
|
|
47
|
-
let exprs =
|
|
47
|
+
let exprs: string[] = []
|
|
48
|
+
if (map.size > 0) {
|
|
49
|
+
map.forEach((value) => {
|
|
50
|
+
if (Array.isArray(value)) exprs.push(...value)
|
|
51
|
+
else exprs.push(value)
|
|
52
|
+
})
|
|
53
|
+
} else {
|
|
54
|
+
exprs = ['*']
|
|
55
|
+
}
|
|
48
56
|
let contents = `from ${source} select ${exprs.join(', ')}`
|
|
49
57
|
queries.push({contents, callback, loading: false, fields: map, errors: [], source})
|
|
50
58
|
runAll()
|
|
@@ -87,13 +95,22 @@ async function runNode (n: QueryNode) {
|
|
|
87
95
|
let body = isJson ? await response.json() : await response.text()
|
|
88
96
|
n.errors = Array.isArray(body) ? body : [{message: body}]
|
|
89
97
|
|
|
90
|
-
let fieldIds = Array.from(n.fields.entries()).
|
|
98
|
+
let fieldIds = Array.from(n.fields.entries()).flatMap(([name, val]) => {
|
|
99
|
+
if (Array.isArray(val)) {
|
|
100
|
+
if (val.length === 0) return [] as string[]
|
|
101
|
+
if (val.length === 1) return [`${name}="${val[0]}"`]
|
|
102
|
+
return [`${name}="${val.join(', ')}"`]
|
|
103
|
+
}
|
|
104
|
+
if (typeof val === 'string' && val.trim().length === 0) return [] as string[]
|
|
105
|
+
if (val == null) return [] as string[]
|
|
106
|
+
return [`${name}="${val}"`]
|
|
107
|
+
})
|
|
91
108
|
let idStr = `Query (data="${n.source}" ` + fieldIds.join(' ') + ')'
|
|
92
|
-
n.errors.forEach(e => e.id = idStr)
|
|
109
|
+
n.errors.forEach(e => (e as any).id = idStr)
|
|
93
110
|
n.callback({errors: n.errors})
|
|
94
111
|
}
|
|
95
112
|
} catch (e) {
|
|
96
|
-
n.errors = [e]
|
|
113
|
+
n.errors = [e as Error]
|
|
97
114
|
} finally {
|
|
98
115
|
n.loading = false
|
|
99
116
|
}
|
|
@@ -115,7 +132,11 @@ function translateData (data: any, node: QueryNode) {
|
|
|
115
132
|
let rows = data.rows || []
|
|
116
133
|
rows.dataLoaded = true // evidence components need this to be set
|
|
117
134
|
rows._evidenceColumnTypes = []
|
|
118
|
-
let requestFields =
|
|
135
|
+
let requestFields: string[] = []
|
|
136
|
+
node.fields.forEach((value) => {
|
|
137
|
+
if (Array.isArray(value)) requestFields.push(...value)
|
|
138
|
+
else requestFields.push(value)
|
|
139
|
+
})
|
|
119
140
|
|
|
120
141
|
data.fields.forEach((field, index) => {
|
|
121
142
|
let name = field.name
|
|
@@ -143,7 +164,7 @@ errorProvider('queryEngine', () => {
|
|
|
143
164
|
queries.flatMap(q => q.errors).filter(q => !!q).forEach(e => {
|
|
144
165
|
unique[e.message + String((e as any).from?.lineText)] = e
|
|
145
166
|
})
|
|
146
|
-
return Object.values(unique)
|
|
167
|
+
return Object.values(unique) as Error[]
|
|
147
168
|
})
|
|
148
169
|
|
|
149
170
|
async function waitForQueries (timeout = 20_000) {
|
package/dist/ui/web.js
CHANGED
|
@@ -86,10 +86,11 @@ async function captureChart (chartTitle) {
|
|
|
86
86
|
async function takeScreenshot () {
|
|
87
87
|
await waitForQueriesToFinish()
|
|
88
88
|
if (!window.html2canvas) {
|
|
89
|
-
let html2canvas = await import('html2canvas')
|
|
89
|
+
let html2canvas = await import('@graphenedata/html2canvas')
|
|
90
90
|
window.html2canvas = html2canvas.default
|
|
91
91
|
}
|
|
92
|
-
|
|
92
|
+
|
|
93
|
+
let canvas = await window.html2canvas(document.body, {useCORS: true, allowTaint: true, scale: 1, liveDOM: true})
|
|
93
94
|
let errors = getErrors().map(e => ({message: e.message, id: e.id}))
|
|
94
95
|
return {stillLoading: isLoading(), screenshot: canvas?.toDataURL('image/png'), errors}
|
|
95
96
|
}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"main": "cli.ts",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": "Graphene Systems Inc",
|
|
6
|
-
"version": "0.0.
|
|
6
|
+
"version": "0.0.7",
|
|
7
7
|
"license": "Elastic-2.0",
|
|
8
8
|
"engines": {
|
|
9
9
|
"node": ">=16"
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@duckdb/node-api": "1.3.2-alpha.26",
|
|
27
27
|
"@google-cloud/bigquery": "^8.1.1",
|
|
28
|
+
"@graphenedata/html2canvas": "^1.4.1",
|
|
28
29
|
"@graphenedata/malloy": "0.0.304",
|
|
29
30
|
"@lezer/common": "^1.2.3",
|
|
30
31
|
"@lezer/lr": "^1.4.2",
|
|
@@ -36,10 +37,10 @@
|
|
|
36
37
|
"cli-table3": "^0.6.3",
|
|
37
38
|
"commander": "^11.0.0",
|
|
38
39
|
"debounce": "^1.2.1",
|
|
40
|
+
"dotenv": "^17.2.3",
|
|
39
41
|
"echarts": "^5.5.0",
|
|
40
42
|
"fs-extra": "11.2.0",
|
|
41
43
|
"glob": "^11.0.3",
|
|
42
|
-
"html2canvas": "^1.4.1",
|
|
43
44
|
"marked": "^16.3.0",
|
|
44
45
|
"mdsvex": "^0.12.6",
|
|
45
46
|
"nanoid": "3.3.8",
|