@graphenedata/cli 0.0.15 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/README.md +138 -0
  2. package/dist/cli/bigQuery-I3F46SC6.js +75 -0
  3. package/dist/cli/bigQuery-I3F46SC6.js.map +7 -0
  4. package/dist/cli/chunk-OVWODUTJ.js +12849 -0
  5. package/dist/cli/chunk-OVWODUTJ.js.map +7 -0
  6. package/dist/cli/chunk-QAXEOZ43.js +53 -0
  7. package/dist/cli/chunk-QAXEOZ43.js.map +7 -0
  8. package/dist/cli/cli.js +234 -11197
  9. package/dist/cli/clickhouse-ZN5AN2UL.js +64 -0
  10. package/dist/cli/clickhouse-ZN5AN2UL.js.map +7 -0
  11. package/dist/cli/duckdb-IYBIO5KJ.js +87 -0
  12. package/dist/cli/duckdb-IYBIO5KJ.js.map +7 -0
  13. package/dist/cli/serve2-TNN5EROW.js +447 -0
  14. package/dist/cli/serve2-TNN5EROW.js.map +7 -0
  15. package/dist/cli/snowflake-MOQB5GA4.js +128 -0
  16. package/dist/cli/snowflake-MOQB5GA4.js.map +7 -0
  17. package/dist/index.d.ts +63 -0
  18. package/dist/lang/index.d.ts +63 -0
  19. package/dist/skills/graphene/SKILL.md +150 -96
  20. package/dist/skills/graphene/references/big-value.md +6 -41
  21. package/dist/skills/graphene/references/date-range.md +64 -0
  22. package/dist/skills/graphene/references/dropdown.md +3 -4
  23. package/dist/skills/graphene/references/echarts.md +162 -0
  24. package/dist/skills/graphene/references/gsql.md +55 -25
  25. package/dist/skills/graphene/references/model-gsql.md +72 -0
  26. package/dist/skills/graphene/references/table.md +13 -14
  27. package/dist/skills/graphene/references/text-input.md +2 -1
  28. package/dist/ui/app.css +239 -340
  29. package/dist/ui/component-utilities/dataShaping.ts +484 -0
  30. package/dist/ui/component-utilities/dataSummary.ts +57 -0
  31. package/dist/ui/component-utilities/enrich.ts +763 -0
  32. package/dist/ui/component-utilities/format.ts +177 -0
  33. package/dist/ui/component-utilities/inputUtils.ts +44 -8
  34. package/dist/ui/component-utilities/theme.ts +200 -0
  35. package/dist/ui/component-utilities/themeStores.ts +21 -8
  36. package/dist/ui/component-utilities/types.ts +70 -0
  37. package/dist/ui/components/AreaChart.svelte +57 -105
  38. package/dist/ui/components/BarChart.svelte +71 -129
  39. package/dist/ui/components/BigValue.svelte +24 -40
  40. package/dist/ui/components/Column.svelte +10 -18
  41. package/dist/ui/components/DateRange.svelte +54 -21
  42. package/dist/ui/components/Dropdown.svelte +47 -26
  43. package/dist/ui/components/DropdownOption.svelte +1 -2
  44. package/dist/ui/components/ECharts.svelte +181 -67
  45. package/dist/ui/components/InlineDelta.svelte +50 -31
  46. package/dist/ui/components/LineChart.svelte +54 -125
  47. package/dist/ui/components/PieChart.svelte +27 -37
  48. package/dist/ui/components/QueryLoad.svelte +77 -45
  49. package/dist/ui/components/Row.svelte +2 -1
  50. package/dist/ui/components/ScatterPlot.svelte +52 -0
  51. package/dist/ui/components/Skeleton.svelte +32 -0
  52. package/dist/ui/components/Table.svelte +3 -2
  53. package/dist/ui/components/TableGroupRow.svelte +28 -36
  54. package/dist/ui/components/TableHarness.svelte +32 -0
  55. package/dist/ui/components/TableHeader.svelte +34 -59
  56. package/dist/ui/components/TableRow.svelte +14 -38
  57. package/dist/ui/components/TableSubtotalRow.svelte +18 -21
  58. package/dist/ui/components/TableTotalRow.svelte +27 -37
  59. package/dist/ui/components/TextInput.svelte +13 -12
  60. package/dist/ui/components/Value.svelte +25 -0
  61. package/dist/ui/components/_Table.svelte +72 -70
  62. package/dist/ui/internal/ChartGallery.svelte +527 -0
  63. package/dist/ui/internal/ErrorDisplay.svelte +22 -97
  64. package/dist/ui/internal/LocalApp.svelte +80 -17
  65. package/dist/ui/internal/PageNavGroup.svelte +269 -0
  66. package/dist/ui/internal/Sidebar.svelte +178 -0
  67. package/dist/ui/internal/SidebarToggle.svelte +47 -0
  68. package/dist/ui/internal/StyleGallery.svelte +244 -0
  69. package/dist/ui/internal/clientCache.ts +2 -2
  70. package/dist/ui/internal/pageInputs.svelte.js +292 -0
  71. package/dist/ui/internal/queryEngine.ts +102 -117
  72. package/dist/ui/internal/runSocket.ts +32 -12
  73. package/dist/ui/internal/sidebar.svelte.js +18 -0
  74. package/dist/ui/internal/telemetry.ts +51 -16
  75. package/dist/ui/internal/types.d.ts +7 -0
  76. package/dist/ui/web.js +28 -11
  77. package/package.json +36 -38
  78. package/dist/skills/graphene/references/area-chart.md +0 -95
  79. package/dist/skills/graphene/references/bar-chart.md +0 -112
  80. package/dist/skills/graphene/references/line-chart.md +0 -108
  81. package/dist/skills/graphene/references/pie-chart.md +0 -29
  82. package/dist/skills/graphene/references/value-formats.md +0 -104
  83. package/dist/ui/component-utilities/autoFormatting.js +0 -280
  84. package/dist/ui/component-utilities/builtInFormats.js +0 -481
  85. package/dist/ui/component-utilities/chartContext.js +0 -12
  86. package/dist/ui/component-utilities/chartWindowDebug.js +0 -21
  87. package/dist/ui/component-utilities/checkInputs.js +0 -84
  88. package/dist/ui/component-utilities/convert.js +0 -15
  89. package/dist/ui/component-utilities/dateParsing.js +0 -56
  90. package/dist/ui/component-utilities/dropdownContext.ts +0 -1
  91. package/dist/ui/component-utilities/echarts.js +0 -252
  92. package/dist/ui/component-utilities/echartsThemes.js +0 -443
  93. package/dist/ui/component-utilities/formatTitle.js +0 -24
  94. package/dist/ui/component-utilities/formatting.js +0 -241
  95. package/dist/ui/component-utilities/getColumnExtents.js +0 -79
  96. package/dist/ui/component-utilities/getColumnSummary.js +0 -62
  97. package/dist/ui/component-utilities/getCompletedData.js +0 -122
  98. package/dist/ui/component-utilities/getDistinctCount.js +0 -7
  99. package/dist/ui/component-utilities/getDistinctValues.js +0 -15
  100. package/dist/ui/component-utilities/getSeriesConfig.js +0 -231
  101. package/dist/ui/component-utilities/getSortedData.js +0 -9
  102. package/dist/ui/component-utilities/getStackPercentages.js +0 -45
  103. package/dist/ui/component-utilities/getStackedData.js +0 -19
  104. package/dist/ui/component-utilities/getYAxisIndex.js +0 -15
  105. package/dist/ui/component-utilities/globalContexts.js +0 -1
  106. package/dist/ui/component-utilities/helpers/getCompletedData.helpers.js +0 -119
  107. package/dist/ui/component-utilities/replaceNulls.js +0 -16
  108. package/dist/ui/component-utilities/tableUtils.ts +0 -107
  109. package/dist/ui/component-utilities/tidyWithTypes.js +0 -9
  110. package/dist/ui/components/Area.svelte +0 -214
  111. package/dist/ui/components/Bar.svelte +0 -347
  112. package/dist/ui/components/Chart.svelte +0 -995
  113. package/dist/ui/components/Line.svelte +0 -227
  114. package/dist/ui/internal/NavSidebar.svelte +0 -396
  115. package/dist/ui/internal/theme.ts +0 -60
  116. package/dist/ui/public/inter-latin-ext.woff2 +0 -0
  117. package/dist/ui/public/inter-latin.woff2 +0 -0
@@ -0,0 +1,527 @@
1
+ <script lang="ts">
2
+ import ECharts from '../components/ECharts.svelte'
3
+
4
+ let monthRows = [
5
+ {month: '2024-01-01', value: 0.082},
6
+ {month: '2024-02-01', value: 0.0932},
7
+ {month: '2024-03-01', value: 0.0901},
8
+ {month: '2024-04-01', value: 0.129},
9
+ {month: '2024-05-01', value: 0.133},
10
+ {month: '2024-06-01', value: 0.152},
11
+ ]
12
+
13
+ let weekdaySeriesRows = [
14
+ {day_of_week: 1, metric: 'Downloads', value: 150},
15
+ {day_of_week: 2, metric: 'Downloads', value: 230},
16
+ {day_of_week: 3, metric: 'Downloads', value: 224},
17
+ {day_of_week: 4, metric: 'Downloads', value: 218},
18
+ {day_of_week: 5, metric: 'Downloads', value: 335},
19
+ {day_of_week: 6, metric: 'Downloads', value: 410},
20
+ {day_of_week: 7, metric: 'Downloads', value: 360},
21
+ {day_of_week: 1, metric: 'Installs', value: 80},
22
+ {day_of_week: 2, metric: 'Installs', value: 120},
23
+ {day_of_week: 3, metric: 'Installs', value: 150},
24
+ {day_of_week: 4, metric: 'Installs', value: 130},
25
+ {day_of_week: 5, metric: 'Installs', value: 210},
26
+ {day_of_week: 6, metric: 'Installs', value: 280},
27
+ {day_of_week: 7, metric: 'Installs', value: 220},
28
+ ]
29
+
30
+ let quarterMetricRows = [
31
+ {quarter_of_year: 1, metric: 'Revenue', value: 42},
32
+ {quarter_of_year: 2, metric: 'Revenue', value: 51},
33
+ {quarter_of_year: 3, metric: 'Revenue', value: 48},
34
+ {quarter_of_year: 4, metric: 'Revenue', value: 67},
35
+ {quarter_of_year: 1, metric: 'Cost', value: 28},
36
+ {quarter_of_year: 2, metric: 'Cost', value: 32},
37
+ {quarter_of_year: 3, metric: 'Cost', value: 30},
38
+ {quarter_of_year: 4, metric: 'Cost', value: 38},
39
+ ]
40
+
41
+ let hourOrdinalRows = [
42
+ {hour_of_day: 22, volume: 120},
43
+ {hour_of_day: 7, volume: 95},
44
+ {hour_of_day: 14, volume: 143},
45
+ {hour_of_day: 3, volume: 60},
46
+ {hour_of_day: 19, volume: 158},
47
+ {hour_of_day: 10, volume: 112},
48
+ ]
49
+
50
+
51
+ let scatterRows = [
52
+ {group: 'Group A', x: 10, y: 8},
53
+ {group: 'Group A', x: 20, y: 35},
54
+ {group: 'Group A', x: 30, y: 22},
55
+ {group: 'Group A', x: 40, y: 60},
56
+ {group: 'Group A', x: 50, y: 55},
57
+ {group: 'Group A', x: 60, y: 80},
58
+ {group: 'Group A', x: 70, y: 75},
59
+ {group: 'Group B', x: 15, y: 5},
60
+ {group: 'Group B', x: 25, y: 18},
61
+ {group: 'Group B', x: 35, y: 30},
62
+ {group: 'Group B', x: 45, y: 40},
63
+ {group: 'Group B', x: 55, y: 35},
64
+ {group: 'Group B', x: 65, y: 50},
65
+ {group: 'Group B', x: 75, y: 60},
66
+ ]
67
+
68
+
69
+ let pieRows = [
70
+ {channel: 'Organic', value: 335},
71
+ {channel: 'Paid', value: 310},
72
+ {channel: 'Referral', value: 234},
73
+ {channel: 'Social', value: 135},
74
+ ]
75
+
76
+ let heatmapRows = [
77
+ {day: 'Mon', period: 'Morning', value: 28},
78
+ {day: 'Tue', period: 'Morning', value: 33},
79
+ {day: 'Wed', period: 'Morning', value: 47},
80
+ {day: 'Thu', period: 'Morning', value: 40},
81
+ {day: 'Fri', period: 'Morning', value: 38},
82
+ {day: 'Sat', period: 'Morning', value: 25},
83
+ {day: 'Sun', period: 'Morning', value: 18},
84
+ {day: 'Mon', period: 'Evening', value: 66},
85
+ {day: 'Tue', period: 'Evening', value: 72},
86
+ {day: 'Wed', period: 'Evening', value: 81},
87
+ {day: 'Thu', period: 'Evening', value: 75},
88
+ {day: 'Fri', period: 'Evening', value: 69},
89
+ {day: 'Sat', period: 'Evening', value: 55},
90
+ {day: 'Sun', period: 'Evening', value: 44},
91
+ ]
92
+
93
+ let candleRows = [
94
+ {month: 'Jan', open: 20, close: 34, low: 10, high: 38},
95
+ {month: 'Feb', open: 40, close: 35, low: 30, high: 50},
96
+ {month: 'Mar', open: 31, close: 38, low: 33, high: 44},
97
+ {month: 'Apr', open: 38, close: 15, low: 5, high: 42},
98
+ {month: 'May', open: 12, close: 36, low: 10, high: 40},
99
+ {month: 'Jun', open: 27, close: 45, low: 25, high: 48},
100
+ {month: 'Jul', open: 38, close: 52, low: 35, high: 56},
101
+ {month: 'Aug', open: 49, close: 60, low: 45, high: 65},
102
+ ]
103
+
104
+ let funnelRows = [
105
+ {stage: 'Visited', value: 100},
106
+ {stage: 'Inquiry', value: 80},
107
+ {stage: 'Order', value: 60},
108
+ {stage: 'Payment', value: 40},
109
+ {stage: 'Complete', value: 20},
110
+ ]
111
+
112
+ let treemapRows = [
113
+ {name: 'Storage', value: 40},
114
+ {name: 'Compute', value: 30},
115
+ {name: 'Network', value: 20},
116
+ {name: 'Database', value: 15},
117
+ {name: 'Security', value: 10},
118
+ {name: 'CDN', value: 8},
119
+ ]
120
+
121
+ let themeRiverRows = [
122
+ {month: '2024-01-01', topic: 'JS', value: 10},
123
+ {month: '2024-02-01', topic: 'JS', value: 15},
124
+ {month: '2024-03-01', topic: 'JS', value: 20},
125
+ {month: '2024-04-01', topic: 'JS', value: 18},
126
+ {month: '2024-05-01', topic: 'JS', value: 25},
127
+ {month: '2024-06-01', topic: 'JS', value: 30},
128
+ {month: '2024-01-01', topic: 'Python', value: 8},
129
+ {month: '2024-02-01', topic: 'Python', value: 12},
130
+ {month: '2024-03-01', topic: 'Python', value: 18},
131
+ {month: '2024-04-01', topic: 'Python', value: 22},
132
+ {month: '2024-05-01', topic: 'Python', value: 20},
133
+ {month: '2024-06-01', topic: 'Python', value: 25},
134
+ ]
135
+
136
+ let groupedStackedRows = [
137
+ {quarter: 'Q1', region: 'North', channel: 'Online', value: 160},
138
+ {quarter: 'Q1', region: 'North', channel: 'Retail', value: 110},
139
+ {quarter: 'Q1', region: 'South', channel: 'Online', value: 130},
140
+ {quarter: 'Q1', region: 'South', channel: 'Retail', value: 95},
141
+ {quarter: 'Q2', region: 'North', channel: 'Online', value: 175},
142
+ {quarter: 'Q2', region: 'North', channel: 'Retail', value: 120},
143
+ {quarter: 'Q2', region: 'South', channel: 'Online', value: 145},
144
+ {quarter: 'Q2', region: 'South', channel: 'Retail', value: 105},
145
+ {quarter: 'Q3', region: 'North', channel: 'Online', value: 190},
146
+ {quarter: 'Q3', region: 'North', channel: 'Retail', value: 125},
147
+ {quarter: 'Q3', region: 'South', channel: 'Online', value: 155},
148
+ {quarter: 'Q3', region: 'South', channel: 'Retail', value: 115},
149
+ ]
150
+ let groupedStackedSlots = Array.from(new Set(groupedStackedRows.map(row => `${row.quarter}|${row.region}`)))
151
+ let groupedStackedRegionLabels = groupedStackedSlots.map(slot => slot.split('|')[1])
152
+ let groupedStackedQuarterLabels = groupedStackedSlots.map((slot, index, slots) => {
153
+ let quarter = slot.split('|')[0]
154
+ let previousQuarter = slots[index - 1]?.split('|')[0]
155
+ return quarter === previousQuarter ? '' : quarter
156
+ })
157
+ let groupedStackedSlotRows = groupedStackedRows.map(row => ({
158
+ ...row,
159
+ slot: groupedStackedSlots.indexOf(`${row.quarter}|${row.region}`),
160
+ }))
161
+
162
+ let dualAxisRows = [
163
+ {month: '2024-01-01', revenue: 120, conversion_rate: 3.2},
164
+ {month: '2024-02-01', revenue: 138, conversion_rate: 3.5},
165
+ {month: '2024-03-01', revenue: 150, conversion_rate: 3.9},
166
+ {month: '2024-04-01', revenue: 166, conversion_rate: 4.1},
167
+ {month: '2024-05-01', revenue: 184, conversion_rate: 4.4},
168
+ {month: '2024-06-01', revenue: 205, conversion_rate: 4.8},
169
+ ]
170
+
171
+ let bubbleRows = [
172
+ {segment: 'SMB', efficiency: 42, growth: 28, pipeline: 120, quality: 55},
173
+ {segment: 'Mid Market', efficiency: 58, growth: 35, pipeline: 180, quality: 62},
174
+ {segment: 'Enterprise', efficiency: 66, growth: 48, pipeline: 260, quality: 70},
175
+ {segment: 'Public Sector', efficiency: 51, growth: 31, pipeline: 150, quality: 58},
176
+ {segment: 'Healthcare', efficiency: 63, growth: 44, pipeline: 220, quality: 68},
177
+ {segment: 'Retail', efficiency: 47, growth: 30, pipeline: 140, quality: 53},
178
+ ]
179
+
180
+ let sankeyRows = [
181
+ {source: 'Leads', target: 'Qualified', value: 420},
182
+ {source: 'Leads', target: 'Disqualified', value: 180},
183
+ {source: 'Qualified', target: 'Demo', value: 260},
184
+ {source: 'Qualified', target: 'No Decision', value: 160},
185
+ {source: 'Demo', target: 'Proposal', value: 190},
186
+ {source: 'Proposal', target: 'Won', value: 130},
187
+ {source: 'Proposal', target: 'Lost', value: 60},
188
+ ]
189
+
190
+ let chordRows = [
191
+ {source: 'Design', target: 'Engineering', value: 30},
192
+ {source: 'Design', target: 'Marketing', value: 12},
193
+ {source: 'Engineering', target: 'Support', value: 18},
194
+ {source: 'Engineering', target: 'Marketing', value: 8},
195
+ {source: 'Marketing', target: 'Sales', value: 24},
196
+ {source: 'Sales', target: 'Support', value: 16},
197
+ {source: 'Support', target: 'Design', value: 6},
198
+ ]
199
+
200
+ let beeswarmRows: {group: string; value: number}[] = []
201
+ for (let group of ['SMB', 'Mid Market', 'Enterprise', 'Public Sector']) {
202
+ for (let i = 0; i < 30; i++) beeswarmRows.push({group, value: Math.round(50 + (Math.random() - 0.5) * 40)})
203
+ }
204
+
205
+ let dayPeriods = ['Morning', 'Evening']
206
+ let weekDays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
207
+ </script>
208
+
209
+ <div class="chart-grid">
210
+ <ECharts
211
+ data={{
212
+ rows: monthRows,
213
+ fields: [
214
+ {name: 'month', type: 'date', metadata: {timeGrain: 'month'}},
215
+ {name: 'value', type: 'number', metadata: {ratio: true}},
216
+ ],
217
+ }}
218
+ config={{
219
+ title: {text: 'Line (Percentage Metadata)'},
220
+ series: [{type: 'line', encode: {x: 'month', y: 'value'}}],
221
+ }}
222
+ />
223
+
224
+ <ECharts
225
+ data={{
226
+ rows: weekdaySeriesRows,
227
+ fields: [
228
+ {name: 'day_of_week', type: 'number', metadata: {timeOrdinal: 'dow_1m'}},
229
+ {name: 'metric', type: 'string'},
230
+ {name: 'value', type: 'number'},
231
+ ],
232
+ }}
233
+ config={{
234
+ title: {text: 'Stacked Area'},
235
+ series: [{type: 'line', stack: 'total', areaStyle: {}, encode: {x: 'day_of_week', y: 'value', splitBy: 'metric'}}],
236
+ }}
237
+ />
238
+
239
+ <ECharts
240
+ data={{
241
+ rows: quarterMetricRows,
242
+ fields: [
243
+ {name: 'quarter_of_year', type: 'number', metadata: {timeOrdinal: 'quarter_of_year'}},
244
+ {name: 'metric', type: 'string'},
245
+ {name: 'value', type: 'number'},
246
+ ],
247
+ }}
248
+ config={{
249
+ title: {text: 'Bar (Quarter Ordinal)'},
250
+ series: [{type: 'bar', encode: {x: 'quarter_of_year', y: 'value', splitBy: 'metric'}}],
251
+ }}
252
+ />
253
+
254
+ <ECharts
255
+ data={{
256
+ rows: hourOrdinalRows,
257
+ fields: [
258
+ {name: 'hour_of_day', type: 'number', metadata: {timeOrdinal: 'hour_of_day'}},
259
+ {name: 'volume', type: 'number'},
260
+ ],
261
+ }}
262
+ config={{
263
+ title: {text: 'Line (Hour Ordinal)'},
264
+ series: [{type: 'line', encode: {x: 'hour_of_day', y: 'volume'}}],
265
+ }}
266
+ />
267
+
268
+
269
+ <ECharts
270
+ data={{
271
+ rows: scatterRows,
272
+ fields: [
273
+ {name: 'group', type: 'string'},
274
+ {name: 'x', type: 'number'},
275
+ {name: 'y', type: 'number'},
276
+ ],
277
+ }}
278
+ config={{
279
+ title: {text: 'Scatter'},
280
+ series: [{type: 'scatter', encode: {x: 'x', y: 'y', splitBy: 'group'}}],
281
+ }}
282
+ />
283
+
284
+ <ECharts
285
+ data={{
286
+ rows: groupedStackedSlotRows,
287
+ fields: [
288
+ {name: 'quarter', type: 'string'},
289
+ {name: 'region', type: 'string'},
290
+ {name: 'channel', type: 'string'},
291
+ {name: 'value', type: 'number'},
292
+ {name: 'slot', type: 'number'},
293
+ ],
294
+ }}
295
+ config={{
296
+ title: {text: 'Grouped + Stacked Bar (Two X-Axes)'},
297
+ tooltip: {trigger: 'axis'},
298
+ legend: {show: true},
299
+ grid: {bottom: 56},
300
+ xAxis: [
301
+ {type: 'category', data: groupedStackedRegionLabels, axisTick: {alignWithLabel: true}},
302
+ {type: 'category', data: groupedStackedQuarterLabels, position: 'bottom', offset: 24, axisTick: {show: false}},
303
+ ],
304
+ yAxis: {type: 'value'},
305
+ series: [{type: 'bar', stack: 'channels', encode: {x: 'slot', y: 'value', splitBy: 'channel'}}],
306
+ }}
307
+ />
308
+
309
+ <ECharts
310
+ data={{
311
+ rows: pieRows,
312
+ fields: [
313
+ {name: 'channel', type: 'string'},
314
+ {name: 'value', type: 'number'},
315
+ ],
316
+ }}
317
+ config={{
318
+ title: {text: 'Pie'},
319
+ tooltip: {trigger: 'item'},
320
+ series: [{type: 'pie', encode: {itemName: 'channel', value: 'value'}}],
321
+ }}
322
+ />
323
+
324
+ <ECharts
325
+ data={{
326
+ rows: heatmapRows,
327
+ fields: [
328
+ {name: 'day', type: 'string'},
329
+ {name: 'period', type: 'string'},
330
+ {name: 'value', type: 'number'},
331
+ ],
332
+ }}
333
+ config={{
334
+ title: {text: 'Heatmap'},
335
+ tooltip: {trigger: 'item'},
336
+ xAxis: {type: 'category', data: weekDays},
337
+ yAxis: {type: 'category', data: dayPeriods},
338
+ visualMap: {min: 0, max: 100, show: false},
339
+ series: [{type: 'heatmap', encode: {x: 'day', y: 'period', value: 'value'}}],
340
+ }}
341
+ />
342
+
343
+ <ECharts
344
+ data={{
345
+ rows: candleRows,
346
+ fields: [
347
+ {name: 'month', type: 'string'},
348
+ {name: 'open', type: 'number'},
349
+ {name: 'close', type: 'number'},
350
+ {name: 'low', type: 'number'},
351
+ {name: 'high', type: 'number'},
352
+ ],
353
+ }}
354
+ config={{
355
+ title: {text: 'Candlestick'},
356
+ tooltip: {trigger: 'axis'},
357
+ xAxis: {type: 'category'},
358
+ yAxis: {type: 'value', scale: true},
359
+ series: [{type: 'candlestick', encode: {x: 'month', y: ['open', 'close', 'low', 'high']}}],
360
+ }}
361
+ />
362
+
363
+ <ECharts
364
+ data={{
365
+ rows: funnelRows,
366
+ fields: [
367
+ {name: 'stage', type: 'string'},
368
+ {name: 'value', type: 'number'},
369
+ ],
370
+ }}
371
+ config={{
372
+ title: {text: 'Funnel'},
373
+ tooltip: {trigger: 'item'},
374
+ series: [{type: 'funnel', encode: {itemName: 'stage', value: 'value'}}],
375
+ }}
376
+ />
377
+
378
+ <ECharts
379
+ data={{
380
+ rows: treemapRows,
381
+ fields: [
382
+ {name: 'name', type: 'string'},
383
+ {name: 'value', type: 'number'},
384
+ ],
385
+ }}
386
+ config={{
387
+ title: {text: 'Treemap'},
388
+ tooltip: {trigger: 'item'},
389
+ series: [{type: 'treemap', encode: {itemName: 'name', value: 'value'}}],
390
+ }}
391
+ />
392
+
393
+ <ECharts
394
+ data={{
395
+ rows: themeRiverRows,
396
+ fields: [
397
+ {name: 'month', type: 'date'},
398
+ {name: 'topic', type: 'string'},
399
+ {name: 'value', type: 'number'},
400
+ ],
401
+ }}
402
+ config={{
403
+ title: {text: 'Theme River'},
404
+ tooltip: {trigger: 'axis'},
405
+ singleAxis: {type: 'time'},
406
+ series: [{type: 'themeRiver', encode: {single: 'month', value: 'value', seriesName: 'topic', splitBy: 'topic'}}],
407
+ }}
408
+ />
409
+
410
+ <ECharts
411
+ data={{
412
+ rows: dualAxisRows,
413
+ fields: [
414
+ {name: 'month', type: 'date'},
415
+ {name: 'revenue', type: 'number'},
416
+ {name: 'conversion_rate', type: 'number'},
417
+ ],
418
+ }}
419
+ config={{
420
+ title: {text: 'Bar + Line (Dual Axis)'},
421
+ tooltip: {trigger: 'axis'},
422
+ legend: {},
423
+ xAxis: {type: 'time'},
424
+ yAxis: [
425
+ {type: 'value', name: 'Revenue'},
426
+ {type: 'value', name: 'Conversion %'},
427
+ ],
428
+ series: [
429
+ {name: 'Revenue', type: 'bar', encode: {x: 'month', y: 'revenue'}},
430
+ {name: 'Conversion %', type: 'line', yAxisIndex: 1, smooth: true, encode: {x: 'month', y: 'conversion_rate'}},
431
+ ],
432
+ }}
433
+ />
434
+
435
+ <ECharts
436
+ data={{
437
+ rows: bubbleRows,
438
+ fields: [
439
+ {name: 'segment', type: 'string'},
440
+ {name: 'efficiency', type: 'number'},
441
+ {name: 'growth', type: 'number'},
442
+ {name: 'pipeline', type: 'number'},
443
+ {name: 'quality', type: 'number'},
444
+ ],
445
+ }}
446
+ config={{
447
+ title: {text: 'Bubble (x/y/size/color)'},
448
+ tooltip: {trigger: 'item'},
449
+ xAxis: {type: 'value', name: 'Efficiency'},
450
+ yAxis: {type: 'value', name: 'Growth'},
451
+ visualMap: [
452
+ {dimension: 'quality', min: 50, max: 72, inRange: {color: ['#60a5fa', '#2563eb', '#1e3a8a']}, show: false},
453
+ {dimension: 'pipeline', min: 100, max: 280, inRange: {symbolSize: [10, 28]}, show: false},
454
+ ],
455
+ series: [{type: 'scatter', encode: {x: 'efficiency', y: 'growth', tooltip: ['segment', 'pipeline', 'quality']}}],
456
+ }}
457
+ />
458
+
459
+ <ECharts
460
+ data={{
461
+ rows: beeswarmRows,
462
+ fields: [
463
+ {name: 'group', type: 'string'},
464
+ {name: 'value', type: 'number'},
465
+ ],
466
+ }}
467
+ config={{
468
+ title: {text: 'Beeswarm'},
469
+ tooltip: {trigger: 'item'},
470
+ xAxis: {type: 'category', jitter: 40, jitterOverlap: false},
471
+ yAxis: {type: 'value'},
472
+ series: [{type: 'scatter', symbolSize: 8, encode: {x: 'group', y: 'value'}}],
473
+ }}
474
+ />
475
+
476
+ <ECharts
477
+ data={{
478
+ rows: chordRows,
479
+ fields: [
480
+ {name: 'source', type: 'string'},
481
+ {name: 'target', type: 'string'},
482
+ {name: 'value', type: 'number'},
483
+ ],
484
+ }}
485
+ config={{
486
+ title: {text: 'Chord'},
487
+ tooltip: {trigger: 'item'},
488
+ series: [{type: 'chord', encode: {source: 'source', target: 'target', value: 'value'}}],
489
+ }}
490
+ />
491
+
492
+ <ECharts
493
+ data={{
494
+ rows: sankeyRows,
495
+ fields: [
496
+ {name: 'source', type: 'string'},
497
+ {name: 'target', type: 'string'},
498
+ {name: 'value', type: 'number'},
499
+ ],
500
+ }}
501
+ config={{
502
+ title: {text: 'Sankey'},
503
+ tooltip: {trigger: 'item'},
504
+ series: [{
505
+ type: 'sankey',
506
+ layout: 'none',
507
+ emphasis: {focus: 'adjacency'},
508
+ encode: {source: 'source', target: 'target', value: 'value'},
509
+ lineStyle: {curveness: 0.5},
510
+ }],
511
+ }}
512
+ />
513
+ </div>
514
+
515
+ <style>
516
+ .chart-grid {
517
+ display: grid;
518
+ grid-template-columns: repeat(auto-fill, 420px);
519
+ justify-content: center;
520
+ gap: 8px;
521
+ padding: 16px;
522
+ }
523
+
524
+ :global(.chart-grid .echarts-container) {
525
+ margin: 0;
526
+ }
527
+ </style>
@@ -1,123 +1,48 @@
1
1
  <script lang="ts">
2
- // Unified error display component.
3
- // Accepts any error-like object with at least a `message` property.
4
- // Optionally shows file location, line details, and query identification.
5
- type ErrorLike = {
6
- message: string
7
- type?: string // error classification: 'analysis', 'database', 'server', 'compile'
8
- queryId?: string
9
- id?: string // legacy name for queryId, set by queryEngine/Chart
10
- file?: string
11
- line?: number
12
- column?: number
13
- from?: {line?: number, col?: number, lineText?: string}
14
- loc?: {line?: number, column?: number}
15
- codeFrame?: string
16
- frame?: string
17
- }
2
+ import type {GrapheneError} from '../../lang/index.d.ts'
18
3
 
19
4
  interface Props {
20
- error: unknown
5
+ error: GrapheneError | string
21
6
  }
22
7
 
23
8
  let {error: raw}: Props = $props()
24
9
 
25
- function normalize(raw: unknown): ErrorLike {
26
- if (typeof raw === 'string') return {message: raw}
27
- if (raw instanceof globalThis.Error) return {message: raw.message}
28
- if (raw && typeof raw === 'object') return raw as ErrorLike
29
- return {message: String(raw)}
30
- }
31
-
32
- function normalizePath(path: string) {
33
- return path.replace(/\\/g, '/').replace(/^file:\/\//, '')
34
- }
35
-
36
- function looksAbsolutePath(path: string) {
37
- return path.startsWith('/') || /^[A-Za-z]:\//.test(path)
38
- }
39
-
40
- // "/foo/bar/baz.md" → "baz.md"
41
- function basename(path: string) { return normalizePath(path).split('/').pop() || path }
42
-
43
- // Classify query errors by type for a more descriptive message prefix.
44
- function classifyError(e: ErrorLike) {
45
- if (e.type === 'analysis' || e.from || e.loc || e.codeFrame || e.frame) return `GSQL error - ${e.message || 'Unknown query error'}`
46
- if (e.type === 'database') return e.message ? `Database query failed: ${e.message}` : 'Database query failed'
47
- if (e.type === 'server') return e.message ? `Server error while running query: ${e.message}` : 'Server error while running query'
48
- return ''
49
- }
50
-
51
10
  let parsed = $derived.by(() => {
52
- let e = normalize(raw)
53
- let message = classifyError(e) || e.message || 'An unknown error occurred'
54
- let queryId = e.queryId || (e.id && !e.id.startsWith('/') ? e.id : undefined)
55
- let line = e.from?.line ?? e.loc?.line ?? e.line
56
- let column = e.from?.col ?? e.loc?.column ?? e.column
57
- let lineText = e.from?.lineText
58
- let pointer = Number.isFinite(column) ? `${' '.repeat(Math.max(0, (column || 1) - 1))}^` : ''
59
- let file = e.file && e.file !== 'input' ? basename(e.file) : undefined
60
- let fileLine = file ? `${file}${line ? `:${line}` : ''}` : undefined
61
- let absoluteFilePath = e.file ? normalizePath(e.file) : undefined
11
+ let error = typeof raw === 'string' ? {message: raw} : raw
12
+ let details: string[] = []
13
+ let file = error.file
62
14
 
63
- // Svelte/Vite embeds the absolute file path in the message ("file:line:col message")
64
- // and at the start of the frame. Strip absolute paths so screenshots stay stable.
65
- if (absoluteFilePath && looksAbsolutePath(absoluteFilePath)) {
66
- let escapedPath = absoluteFilePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
67
- message = message.replace(new RegExp(escapedPath, 'g'), file || basename(absoluteFilePath))
68
- if (message.startsWith(file || '')) message = message.replace(/^([^\s]+):\d+:\d+\s+/, '')
15
+ // Vite compile errors can include machine-specific absolute paths.
16
+ // In browser tests, pin this one known message to a stable fake path for screenshots.
17
+ if (import.meta.env.VITE_TEST && error.message?.match(/Unexpected block closing tag/) && typeof file === 'string') {
18
+ file = '/myproject/index.md'
69
19
  }
70
20
 
71
- let frame = e.frame
72
- if (frame && absoluteFilePath && looksAbsolutePath(absoluteFilePath)) {
73
- let escapedPath = absoluteFilePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
74
- frame = frame.replace(new RegExp(escapedPath, 'g'), file || basename(absoluteFilePath))
75
-
76
- // Strip leading lines that are just file paths (with optional :line suffix)
77
- let lines = frame.split('\n')
78
- while (lines.length) {
79
- let candidate = normalizePath(lines[0].trim())
80
- if (candidate === absoluteFilePath || candidate.startsWith(absoluteFilePath + ':')) {
81
- lines.shift()
82
- continue
83
- }
84
- if (looksAbsolutePath(candidate)) {
85
- lines.shift()
86
- continue
87
- }
88
- break
89
- }
90
-
91
- // Strip leftover column pointer line (just spaces and ^)
92
- if (lines.length && /^ +\^$/.test(lines[0])) lines.shift()
93
- frame = lines.join('\n')
21
+ if (error.componentId) details.push(error.componentId)
22
+ if (file && file != 'input') {
23
+ let line = error.from?.line != null ? error.from.line + 1 : undefined
24
+ details.push(line ? `${file}:${line}` : file)
94
25
  }
95
- let details: string[] = []
96
- if (queryId) details.push(queryId)
97
- if (fileLine) details.push(fileLine)
98
- else if (line) details.push(`Line ${line}`)
99
- if (lineText) { details.push(lineText); if (pointer) details.push(pointer) }
100
- if (e.codeFrame) details.push(e.codeFrame)
101
- if (frame) details.push(frame)
102
- return {message, details}
26
+ if (error.frame) details.push(error.frame)
27
+
28
+ return {message: error.message || 'Unknown error', details}
103
29
  })
104
30
  </script>
105
31
 
106
32
  <div class="g-error" role="alert">
107
33
  <p class="g-error__message">{parsed.message}</p>
108
34
  {#if parsed.details.length}
109
- <pre class="g-error__details">{parsed.details.join('\n')}</pre>
35
+ <div class="g-error__details">{parsed.details.join('\n')}</div>
110
36
  {/if}
111
37
  </div>
112
38
 
113
39
  <style>
114
40
  .g-error {
115
41
  padding: 16px 20px;
116
- margin: 12px 0;
117
42
  border-radius: 6px;
118
- border-left: 3px solid var(--red-500);
119
- background: var(--red-50);
120
- color: var(--red-800);
43
+ border-left: 3px solid var(--graphene-error-border, #ef4444);
44
+ background: var(--graphene-error-background, #fef2f2);
45
+ color: var(--graphene-error-content, #991b1b);
121
46
  }
122
47
  .g-error__message {
123
48
  margin: 0;
@@ -125,11 +50,11 @@
125
50
  }
126
51
  .g-error__details {
127
52
  margin: 12px 0 0;
128
- font-family: 'SFMono-Regular', Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
53
+ font-family: var(--font-mono);
129
54
  font-size: 0.875rem;
130
55
  line-height: 1.6;
131
56
  white-space: pre-wrap;
132
57
  word-break: break-word;
133
- color: var(--red-700);
58
+ color: var(--graphene-error-content-strong, #b91c1c);
134
59
  }
135
60
  </style>