@devtable/dashboard 1.24.0 → 1.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -36,7 +36,7 @@ var __publicField = (obj, key, value) => {
36
36
  import React from "react";
37
37
  import _ from "lodash";
38
38
  import RGL, { WidthProvider } from "react-grid-layout";
39
- import { Popover, Tooltip, Group, Text, ActionIcon, Box, Button, TextInput, LoadingOverlay, Table, Select, useMantineTheme, ColorSwatch, Switch, Slider, SegmentedControl, NumberInput, Accordion, ColorInput, Divider, JsonInput, Modal, AppShell, Tabs, Menu, Container, Textarea } from "@mantine/core";
39
+ import { Popover, Tooltip, Group, Text, ActionIcon, Box, Button, TextInput, LoadingOverlay, Table, Select, useMantineTheme, ColorSwatch, Switch, Slider, SegmentedControl, NumberInput, ColorInput, Divider, Accordion, JsonInput, Modal, AppShell, Tabs, Menu, Container, Textarea } from "@mantine/core";
40
40
  import { useRequest } from "ahooks";
41
41
  import axios from "axios";
42
42
  import { InfoCircle, DeviceFloppy, Refresh, Trash, PlaylistAdd, Settings, Resize, Paint, PlayerPlay, Database, Recycle, Share } from "tabler-icons-react";
@@ -2008,7 +2008,7 @@ const defaultOption$1 = {
2008
2008
  }
2009
2009
  },
2010
2010
  grid: {
2011
- top: 30,
2011
+ top: 0,
2012
2012
  left: 15,
2013
2013
  right: 15,
2014
2014
  bottom: 30,
@@ -2102,364 +2102,6 @@ function getOption(conf, data) {
2102
2102
  };
2103
2103
  return _.merge({}, defaultOption$1, customOptions);
2104
2104
  }
2105
- echarts.use([BarChart, LineChart, ScatterChart, GridComponent, LegendComponent, TooltipComponent, CanvasRenderer]);
2106
- echarts.registerTransform(echartsStat.transform.regression);
2107
- function VizCartesianChart({
2108
- conf,
2109
- data,
2110
- width,
2111
- height
2112
- }) {
2113
- const option = React.useMemo(() => {
2114
- return getOption(conf, data);
2115
- }, [conf, data]);
2116
- if (!width || !height) {
2117
- return null;
2118
- }
2119
- return /* @__PURE__ */ jsx(ReactEChartsCore, {
2120
- echarts,
2121
- option,
2122
- style: {
2123
- width,
2124
- height
2125
- }
2126
- });
2127
- }
2128
- var ValueType = /* @__PURE__ */ ((ValueType2) => {
2129
- ValueType2["string"] = "string";
2130
- ValueType2["number"] = "number";
2131
- ValueType2["eloc"] = "eloc";
2132
- ValueType2["percentage"] = "percentage";
2133
- return ValueType2;
2134
- })(ValueType || {});
2135
- function StringCell({
2136
- value
2137
- }) {
2138
- return /* @__PURE__ */ jsx(Text, {
2139
- component: "span",
2140
- children: value
2141
- });
2142
- }
2143
- function ELOCCell({
2144
- value
2145
- }) {
2146
- return /* @__PURE__ */ jsx(Text, {
2147
- component: "span",
2148
- children: value
2149
- });
2150
- }
2151
- function NumberCell({
2152
- value
2153
- }) {
2154
- const num = numbro(value).format({
2155
- thousandSeparated: true
2156
- });
2157
- return /* @__PURE__ */ jsx(Text, {
2158
- component: "span",
2159
- children: num
2160
- });
2161
- }
2162
- function PercentageCell({
2163
- value
2164
- }) {
2165
- const num = numbro(value).format({
2166
- output: "percent",
2167
- mantissa: 3
2168
- });
2169
- return /* @__PURE__ */ jsx(Text, {
2170
- component: "span",
2171
- children: num
2172
- });
2173
- }
2174
- function CellValue({
2175
- value,
2176
- type
2177
- }) {
2178
- switch (type) {
2179
- case ValueType.string:
2180
- return /* @__PURE__ */ jsx(StringCell, {
2181
- value
2182
- });
2183
- case ValueType.eloc:
2184
- return /* @__PURE__ */ jsx(ELOCCell, {
2185
- value
2186
- });
2187
- case ValueType.number:
2188
- return /* @__PURE__ */ jsx(NumberCell, {
2189
- value
2190
- });
2191
- case ValueType.percentage:
2192
- return /* @__PURE__ */ jsx(PercentageCell, {
2193
- value
2194
- });
2195
- }
2196
- }
2197
- function VizTable({
2198
- conf,
2199
- data = [],
2200
- width,
2201
- height
2202
- }) {
2203
- const _a = conf, {
2204
- id_field,
2205
- use_raw_columns,
2206
- columns
2207
- } = _a, rest = __objRest(_a, [
2208
- "id_field",
2209
- "use_raw_columns",
2210
- "columns"
2211
- ]);
2212
- const labels = React.useMemo(() => {
2213
- if (use_raw_columns) {
2214
- return Object.keys(data == null ? void 0 : data[0]);
2215
- }
2216
- return columns.map((c) => c.label);
2217
- }, [use_raw_columns, columns, data]);
2218
- const finalColumns = React.useMemo(() => {
2219
- if (use_raw_columns) {
2220
- return Object.keys(data == null ? void 0 : data[0]).map((k2) => ({
2221
- label: k2,
2222
- value_field: k2,
2223
- value_type: ValueType.string
2224
- }));
2225
- }
2226
- return columns;
2227
- }, [use_raw_columns, columns, data]);
2228
- return /* @__PURE__ */ jsxs(Table, __spreadProps(__spreadValues({
2229
- sx: {
2230
- maxHeight: height
2231
- }
2232
- }, rest), {
2233
- children: [/* @__PURE__ */ jsx("thead", {
2234
- children: /* @__PURE__ */ jsx("tr", {
2235
- children: labels.map((label) => /* @__PURE__ */ jsx("th", {
2236
- children: label
2237
- }, label))
2238
- })
2239
- }), /* @__PURE__ */ jsx("tbody", {
2240
- children: data.slice(0, 30).map((row, index2) => /* @__PURE__ */ jsx("tr", {
2241
- children: finalColumns.map(({
2242
- value_field,
2243
- value_type
2244
- }) => /* @__PURE__ */ jsx("td", {
2245
- children: /* @__PURE__ */ jsx(Group, {
2246
- sx: {
2247
- "&, .mantine-Text-root": {
2248
- fontFamily: "monospace",
2249
- fontSize: rest.fontSize
2250
- }
2251
- },
2252
- children: /* @__PURE__ */ jsx(CellValue, {
2253
- value: row[value_field],
2254
- type: value_type
2255
- })
2256
- })
2257
- }, `${value_field}--${row[value_field]}`))
2258
- }, id_field ? row[id_field] : `row-${index2}`))
2259
- }), data.length > 100 && /* @__PURE__ */ jsx("tfoot", {
2260
- children: /* @__PURE__ */ jsx("tr", {
2261
- children: /* @__PURE__ */ jsx("td", {
2262
- colSpan: labels.length,
2263
- children: /* @__PURE__ */ jsx(Text, {
2264
- color: "red",
2265
- size: "sm",
2266
- children: "Showing only the first 30 rows to avoid causing slow performance"
2267
- })
2268
- })
2269
- })
2270
- })]
2271
- }));
2272
- }
2273
- function interpolateString(template, params = {}) {
2274
- const extendedParams = __spreadProps(__spreadValues({}, params), {
2275
- numbro
2276
- });
2277
- const names = Object.keys(extendedParams);
2278
- const vals = Object.values(extendedParams);
2279
- try {
2280
- return new Function(...names, `return \`${template}\`;`)(...vals);
2281
- } catch (error) {
2282
- return error.message;
2283
- }
2284
- }
2285
- function VizText({
2286
- conf: {
2287
- paragraphs
2288
- },
2289
- data
2290
- }) {
2291
- return /* @__PURE__ */ jsx(Fragment, {
2292
- children: paragraphs.map((_a, index2) => {
2293
- var _b = _a, {
2294
- template,
2295
- size
2296
- } = _b, rest = __objRest(_b, [
2297
- "template",
2298
- "size"
2299
- ]);
2300
- return /* @__PURE__ */ jsx(Text, __spreadProps(__spreadValues({}, rest), {
2301
- sx: {
2302
- fontSize: size
2303
- },
2304
- children: interpolateString(template, data[0])
2305
- }), `${template}---${index2}`);
2306
- })
2307
- });
2308
- }
2309
- echarts.use([GridComponent, VisualMapComponent, LegendComponent, TooltipComponent, CanvasRenderer]);
2310
- function VizBar3D({
2311
- conf,
2312
- data,
2313
- width,
2314
- height
2315
- }) {
2316
- const _a = conf, {
2317
- x_axis_data_key,
2318
- y_axis_data_key,
2319
- z_axis_data_key
2320
- } = _a, restConf = __objRest(_a, [
2321
- "x_axis_data_key",
2322
- "y_axis_data_key",
2323
- "z_axis_data_key"
2324
- ]);
2325
- const min = React.useMemo(() => {
2326
- return _.minBy(data, (d) => d[z_axis_data_key])[z_axis_data_key];
2327
- }, [data, z_axis_data_key]);
2328
- const max = React.useMemo(() => {
2329
- return _.maxBy(data, (d) => d[z_axis_data_key])[z_axis_data_key];
2330
- }, [data, z_axis_data_key]);
2331
- const option = __spreadProps(__spreadValues({
2332
- tooltip: {},
2333
- backgroundColor: "#fff",
2334
- visualMap: {
2335
- show: true,
2336
- dimension: 2,
2337
- min,
2338
- max,
2339
- inRange: {
2340
- color: ["#313695", "#4575b4", "#74add1", "#abd9e9", "#e0f3f8", "#ffffbf", "#fee090", "#fdae61", "#f46d43", "#d73027", "#a50026"]
2341
- }
2342
- },
2343
- xAxis3D: {
2344
- type: "value"
2345
- },
2346
- yAxis3D: {
2347
- type: "value"
2348
- },
2349
- zAxis3D: {
2350
- type: "value"
2351
- },
2352
- grid3D: {
2353
- viewControl: {
2354
- projection: "orthographic",
2355
- autoRotate: false
2356
- },
2357
- light: {
2358
- main: {
2359
- shadow: true,
2360
- quality: "ultra",
2361
- intensity: 1.5
2362
- }
2363
- }
2364
- }
2365
- }, restConf), {
2366
- series: [{
2367
- type: "bar3D",
2368
- wireframe: {},
2369
- data: data.map((d) => [d[x_axis_data_key], d[y_axis_data_key], d[z_axis_data_key]])
2370
- }]
2371
- });
2372
- return /* @__PURE__ */ jsx(ReactEChartsCore, {
2373
- echarts,
2374
- option,
2375
- style: {
2376
- width,
2377
- height
2378
- }
2379
- });
2380
- }
2381
- var index$2 = "";
2382
- echarts.use([PieChart, CanvasRenderer]);
2383
- const defaultOption = {
2384
- tooltip: {
2385
- show: true
2386
- },
2387
- series: {
2388
- type: "pie",
2389
- radius: ["50%", "80%"],
2390
- label: {
2391
- position: "outer",
2392
- alignTo: "edge",
2393
- formatter: "{name|{b}}\n{percentage|{d}%}",
2394
- minMargin: 5,
2395
- edgeDistance: 10,
2396
- lineHeight: 15,
2397
- rich: {
2398
- percentage: {
2399
- color: "#999"
2400
- }
2401
- },
2402
- margin: 20
2403
- },
2404
- labelLine: {
2405
- length: 15,
2406
- length2: 0,
2407
- maxSurfaceAngle: 80,
2408
- showAbove: true
2409
- },
2410
- top: 10,
2411
- bottom: 10,
2412
- left: 10,
2413
- right: 10
2414
- }
2415
- };
2416
- function VizPie({
2417
- conf,
2418
- data,
2419
- width,
2420
- height
2421
- }) {
2422
- const _a = conf, {
2423
- label_field = "name",
2424
- value_field = "value"
2425
- } = _a, restConf = __objRest(_a, [
2426
- "label_field",
2427
- "value_field"
2428
- ]);
2429
- const chartData = React.useMemo(() => {
2430
- return data.map((d) => ({
2431
- name: d[label_field],
2432
- value: Number(d[value_field])
2433
- }));
2434
- }, [data, label_field, value_field]);
2435
- const labelOptions = React.useMemo(() => {
2436
- return {
2437
- series: {
2438
- labelLayout: function(params) {
2439
- const isLeft = params.labelRect.x < width / 2;
2440
- const points = params.labelLinePoints;
2441
- points[2][0] = isLeft ? params.labelRect.x : params.labelRect.x + params.labelRect.width;
2442
- return {
2443
- labelLinePoints: points
2444
- };
2445
- }
2446
- }
2447
- };
2448
- }, [width]);
2449
- const option = _.merge({}, defaultOption, labelOptions, restConf, {
2450
- series: {
2451
- data: chartData
2452
- }
2453
- });
2454
- return /* @__PURE__ */ jsx(ReactEChartsCore, {
2455
- echarts,
2456
- option,
2457
- style: {
2458
- width,
2459
- height
2460
- }
2461
- });
2462
- }
2463
2105
  function median(numbers) {
2464
2106
  const sorted = Array.from(numbers).sort((a, b) => a - b);
2465
2107
  const middle = Math.floor(sorted.length / 2);
@@ -2852,94 +2494,503 @@ class InterpolateColor {
2852
2494
  return this.mapper(value);
2853
2495
  }
2854
2496
  }
2855
- function getColorByColorConf(conf, value) {
2856
- if (conf.type === "static") {
2857
- return conf.staticColor;
2858
- }
2859
- if (conf.type === "continuous") {
2860
- return new InterpolateColor(conf).getColor(value);
2861
- }
2862
- return "black";
2497
+ function getColorByColorConf(conf, value) {
2498
+ if (conf.type === "static") {
2499
+ return conf.staticColor;
2500
+ }
2501
+ if (conf.type === "continuous") {
2502
+ return new InterpolateColor(conf).getColor(value);
2503
+ }
2504
+ return "black";
2505
+ }
2506
+ function getNonStatsDataText(data) {
2507
+ if (data === null) {
2508
+ return "null";
2509
+ }
2510
+ if (data === void 0) {
2511
+ return "undefined";
2512
+ }
2513
+ if (Array.isArray(data)) {
2514
+ return `Array(${data.length})`;
2515
+ }
2516
+ return data.toString();
2517
+ }
2518
+ function variablesToElements(variables, data) {
2519
+ const ret = {};
2520
+ variables.forEach(({
2521
+ name,
2522
+ color: color2,
2523
+ data_field,
2524
+ aggregation,
2525
+ size,
2526
+ weight,
2527
+ formatter
2528
+ }) => {
2529
+ const value = aggregateValue(data, data_field, aggregation);
2530
+ let valueContent = "";
2531
+ if (!["string", "number"].includes(typeof value)) {
2532
+ valueContent = getNonStatsDataText(value);
2533
+ } else {
2534
+ valueContent = numbro(value).format(formatter);
2535
+ }
2536
+ ret[name] = /* @__PURE__ */ jsx(Text, {
2537
+ sx: {
2538
+ fontSize: size,
2539
+ display: "inline"
2540
+ },
2541
+ color: getColorByColorConf(color2, value),
2542
+ weight,
2543
+ children: valueContent
2544
+ });
2545
+ });
2546
+ return ret;
2547
+ }
2548
+ function preserveWhiteSpaces(text) {
2549
+ return text.split(" ").map((s) => /* @__PURE__ */ jsxs(Fragment, {
2550
+ children: [s, "\xA0"]
2551
+ }));
2552
+ }
2553
+ function withLineBreaks(text) {
2554
+ const normalized = text.replaceAll("<br />", "<br/>").replaceAll("\n", "<br/>");
2555
+ const splitted = normalized.split("<br/>");
2556
+ const ret = splitted.map((t, i) => {
2557
+ const arr = [preserveWhiteSpaces(t)];
2558
+ if (i !== splitted.length - 1) {
2559
+ arr.push(/* @__PURE__ */ jsx("br", {}));
2560
+ }
2561
+ return arr;
2562
+ }).flat().filter((t) => t !== void 0);
2563
+ return ret;
2564
+ }
2565
+ function textToJSX(text) {
2566
+ return withLineBreaks(text);
2567
+ }
2568
+ function templateToJSX(template, variables, data) {
2569
+ const variableElements = variablesToElements(variables, data);
2570
+ const regx = /^\{(.+)\}(.*)$/;
2571
+ return template.split("$").map((text) => {
2572
+ var _a;
2573
+ const match = regx.exec(text);
2574
+ if (!match) {
2575
+ return textToJSX(text);
2576
+ }
2577
+ const element = variableElements[match[1]];
2578
+ if (!element) {
2579
+ return textToJSX(text);
2580
+ }
2581
+ const rest = (_a = match[2]) != null ? _a : "";
2582
+ return /* @__PURE__ */ jsxs(Fragment, {
2583
+ children: [element, textToJSX(rest)]
2584
+ });
2585
+ });
2586
+ }
2587
+ echarts.use([BarChart, LineChart, ScatterChart, GridComponent, LegendComponent, TooltipComponent, CanvasRenderer]);
2588
+ echarts.registerTransform(echartsStat.transform.regression);
2589
+ function templateNotEmpty(str) {
2590
+ return str.trim().length > 0;
2591
+ }
2592
+ function Chart({
2593
+ conf,
2594
+ data,
2595
+ width,
2596
+ height
2597
+ }) {
2598
+ const option = React.useMemo(() => {
2599
+ return getOption(conf, data);
2600
+ }, [conf, data]);
2601
+ if (!width || !height) {
2602
+ return null;
2603
+ }
2604
+ return /* @__PURE__ */ jsx(ReactEChartsCore, {
2605
+ echarts,
2606
+ option,
2607
+ style: {
2608
+ width,
2609
+ height
2610
+ }
2611
+ });
2612
+ }
2613
+ function VizCartesianChart({
2614
+ conf,
2615
+ data,
2616
+ width,
2617
+ height
2618
+ }) {
2619
+ const {
2620
+ ref: topStatsRef,
2621
+ height: topStatsHeight
2622
+ } = useElementSize();
2623
+ const {
2624
+ ref: bottomStatsRef,
2625
+ height: bottomStatsHeight
2626
+ } = useElementSize();
2627
+ const templates = React.useMemo(() => {
2628
+ const {
2629
+ stats: {
2630
+ templates: templates2,
2631
+ variables
2632
+ }
2633
+ } = conf;
2634
+ return {
2635
+ top: templateToJSX(templates2.top, variables, data),
2636
+ bottom: templateToJSX(templates2.bottom, variables, data)
2637
+ };
2638
+ }, [conf, data]);
2639
+ const finalHeight = Math.max(0, height - topStatsHeight - bottomStatsHeight);
2640
+ return /* @__PURE__ */ jsxs(Box, {
2641
+ children: [templateNotEmpty(conf.stats.templates.top) && /* @__PURE__ */ jsx(Text, {
2642
+ ref: topStatsRef,
2643
+ align: "left",
2644
+ size: "xs",
2645
+ pl: "sm",
2646
+ children: Object.values(templates.top).map((c) => c)
2647
+ }), /* @__PURE__ */ jsx(Chart, {
2648
+ width,
2649
+ height: finalHeight,
2650
+ data,
2651
+ conf
2652
+ }), templateNotEmpty(conf.stats.templates.bottom) && /* @__PURE__ */ jsx(Text, {
2653
+ ref: bottomStatsRef,
2654
+ align: "left",
2655
+ size: "xs",
2656
+ pl: "sm",
2657
+ children: Object.values(templates.bottom).map((c) => c)
2658
+ })]
2659
+ });
2660
+ }
2661
+ var ValueType = /* @__PURE__ */ ((ValueType2) => {
2662
+ ValueType2["string"] = "string";
2663
+ ValueType2["number"] = "number";
2664
+ ValueType2["eloc"] = "eloc";
2665
+ ValueType2["percentage"] = "percentage";
2666
+ return ValueType2;
2667
+ })(ValueType || {});
2668
+ function StringCell({
2669
+ value
2670
+ }) {
2671
+ return /* @__PURE__ */ jsx(Text, {
2672
+ component: "span",
2673
+ children: value
2674
+ });
2675
+ }
2676
+ function ELOCCell({
2677
+ value
2678
+ }) {
2679
+ return /* @__PURE__ */ jsx(Text, {
2680
+ component: "span",
2681
+ children: value
2682
+ });
2683
+ }
2684
+ function NumberCell({
2685
+ value
2686
+ }) {
2687
+ const num = numbro(value).format({
2688
+ thousandSeparated: true
2689
+ });
2690
+ return /* @__PURE__ */ jsx(Text, {
2691
+ component: "span",
2692
+ children: num
2693
+ });
2694
+ }
2695
+ function PercentageCell({
2696
+ value
2697
+ }) {
2698
+ const num = numbro(value).format({
2699
+ output: "percent",
2700
+ mantissa: 3
2701
+ });
2702
+ return /* @__PURE__ */ jsx(Text, {
2703
+ component: "span",
2704
+ children: num
2705
+ });
2863
2706
  }
2864
- function getNonStatsDataText(data) {
2865
- if (data === null) {
2866
- return "null";
2867
- }
2868
- if (data === void 0) {
2869
- return "undefined";
2870
- }
2871
- if (Array.isArray(data)) {
2872
- return `Array(${data.length})`;
2707
+ function CellValue({
2708
+ value,
2709
+ type
2710
+ }) {
2711
+ switch (type) {
2712
+ case ValueType.string:
2713
+ return /* @__PURE__ */ jsx(StringCell, {
2714
+ value
2715
+ });
2716
+ case ValueType.eloc:
2717
+ return /* @__PURE__ */ jsx(ELOCCell, {
2718
+ value
2719
+ });
2720
+ case ValueType.number:
2721
+ return /* @__PURE__ */ jsx(NumberCell, {
2722
+ value
2723
+ });
2724
+ case ValueType.percentage:
2725
+ return /* @__PURE__ */ jsx(PercentageCell, {
2726
+ value
2727
+ });
2873
2728
  }
2874
- return data.toString();
2875
2729
  }
2876
- function variablesToElements(variables, data) {
2877
- const ret = {};
2878
- variables.forEach(({
2879
- name,
2880
- color: color2,
2881
- data_field,
2882
- aggregation,
2883
- size,
2884
- weight,
2885
- formatter
2886
- }) => {
2887
- const value = aggregateValue(data, data_field, aggregation);
2888
- let valueContent = "";
2889
- if (!["string", "number"].includes(typeof value)) {
2890
- valueContent = getNonStatsDataText(value);
2891
- } else {
2892
- valueContent = numbro(value).format(formatter);
2730
+ function VizTable({
2731
+ conf,
2732
+ data = [],
2733
+ width,
2734
+ height
2735
+ }) {
2736
+ const _a = conf, {
2737
+ id_field,
2738
+ use_raw_columns,
2739
+ columns
2740
+ } = _a, rest = __objRest(_a, [
2741
+ "id_field",
2742
+ "use_raw_columns",
2743
+ "columns"
2744
+ ]);
2745
+ const labels = React.useMemo(() => {
2746
+ if (use_raw_columns) {
2747
+ return Object.keys(data == null ? void 0 : data[0]);
2893
2748
  }
2894
- ret[name] = /* @__PURE__ */ jsx(Text, {
2895
- sx: {
2896
- fontSize: size,
2897
- display: "inline"
2898
- },
2899
- color: getColorByColorConf(color2, value),
2900
- weight,
2901
- children: valueContent
2902
- });
2749
+ return columns.map((c) => c.label);
2750
+ }, [use_raw_columns, columns, data]);
2751
+ const finalColumns = React.useMemo(() => {
2752
+ if (use_raw_columns) {
2753
+ return Object.keys(data == null ? void 0 : data[0]).map((k2) => ({
2754
+ label: k2,
2755
+ value_field: k2,
2756
+ value_type: ValueType.string
2757
+ }));
2758
+ }
2759
+ return columns;
2760
+ }, [use_raw_columns, columns, data]);
2761
+ return /* @__PURE__ */ jsxs(Table, __spreadProps(__spreadValues({
2762
+ sx: {
2763
+ maxHeight: height
2764
+ }
2765
+ }, rest), {
2766
+ children: [/* @__PURE__ */ jsx("thead", {
2767
+ children: /* @__PURE__ */ jsx("tr", {
2768
+ children: labels.map((label) => /* @__PURE__ */ jsx("th", {
2769
+ children: label
2770
+ }, label))
2771
+ })
2772
+ }), /* @__PURE__ */ jsx("tbody", {
2773
+ children: data.slice(0, 30).map((row, index2) => /* @__PURE__ */ jsx("tr", {
2774
+ children: finalColumns.map(({
2775
+ value_field,
2776
+ value_type
2777
+ }) => /* @__PURE__ */ jsx("td", {
2778
+ children: /* @__PURE__ */ jsx(Group, {
2779
+ sx: {
2780
+ "&, .mantine-Text-root": {
2781
+ fontFamily: "monospace",
2782
+ fontSize: rest.fontSize
2783
+ }
2784
+ },
2785
+ children: /* @__PURE__ */ jsx(CellValue, {
2786
+ value: row[value_field],
2787
+ type: value_type
2788
+ })
2789
+ })
2790
+ }, `${value_field}--${row[value_field]}`))
2791
+ }, id_field ? row[id_field] : `row-${index2}`))
2792
+ }), data.length > 100 && /* @__PURE__ */ jsx("tfoot", {
2793
+ children: /* @__PURE__ */ jsx("tr", {
2794
+ children: /* @__PURE__ */ jsx("td", {
2795
+ colSpan: labels.length,
2796
+ children: /* @__PURE__ */ jsx(Text, {
2797
+ color: "red",
2798
+ size: "sm",
2799
+ children: "Showing only the first 30 rows to avoid causing slow performance"
2800
+ })
2801
+ })
2802
+ })
2803
+ })]
2804
+ }));
2805
+ }
2806
+ function interpolateString(template, params = {}) {
2807
+ const extendedParams = __spreadProps(__spreadValues({}, params), {
2808
+ numbro
2903
2809
  });
2904
- return ret;
2810
+ const names = Object.keys(extendedParams);
2811
+ const vals = Object.values(extendedParams);
2812
+ try {
2813
+ return new Function(...names, `return \`${template}\`;`)(...vals);
2814
+ } catch (error) {
2815
+ return error.message;
2816
+ }
2905
2817
  }
2906
- function preserveWhiteSpaces(text) {
2907
- return text.split(" ").map((s) => /* @__PURE__ */ jsxs(Fragment, {
2908
- children: [s, "\xA0"]
2909
- }));
2818
+ function VizText({
2819
+ conf: {
2820
+ paragraphs
2821
+ },
2822
+ data
2823
+ }) {
2824
+ return /* @__PURE__ */ jsx(Fragment, {
2825
+ children: paragraphs.map((_a, index2) => {
2826
+ var _b = _a, {
2827
+ template,
2828
+ size
2829
+ } = _b, rest = __objRest(_b, [
2830
+ "template",
2831
+ "size"
2832
+ ]);
2833
+ return /* @__PURE__ */ jsx(Text, __spreadProps(__spreadValues({}, rest), {
2834
+ sx: {
2835
+ fontSize: size
2836
+ },
2837
+ children: interpolateString(template, data[0])
2838
+ }), `${template}---${index2}`);
2839
+ })
2840
+ });
2910
2841
  }
2911
- function withLineBreaks(text) {
2912
- const normalized = text.replaceAll("<br />", "<br/>").replaceAll("\n", "<br/>");
2913
- const splitted = normalized.split("<br/>");
2914
- const ret = splitted.map((t, i) => {
2915
- const arr = [preserveWhiteSpaces(t)];
2916
- if (i !== splitted.length - 1) {
2917
- arr.push(/* @__PURE__ */ jsx("br", {}));
2842
+ echarts.use([GridComponent, VisualMapComponent, LegendComponent, TooltipComponent, CanvasRenderer]);
2843
+ function VizBar3D({
2844
+ conf,
2845
+ data,
2846
+ width,
2847
+ height
2848
+ }) {
2849
+ const _a = conf, {
2850
+ x_axis_data_key,
2851
+ y_axis_data_key,
2852
+ z_axis_data_key
2853
+ } = _a, restConf = __objRest(_a, [
2854
+ "x_axis_data_key",
2855
+ "y_axis_data_key",
2856
+ "z_axis_data_key"
2857
+ ]);
2858
+ const min = React.useMemo(() => {
2859
+ return _.minBy(data, (d) => d[z_axis_data_key])[z_axis_data_key];
2860
+ }, [data, z_axis_data_key]);
2861
+ const max = React.useMemo(() => {
2862
+ return _.maxBy(data, (d) => d[z_axis_data_key])[z_axis_data_key];
2863
+ }, [data, z_axis_data_key]);
2864
+ const option = __spreadProps(__spreadValues({
2865
+ tooltip: {},
2866
+ backgroundColor: "#fff",
2867
+ visualMap: {
2868
+ show: true,
2869
+ dimension: 2,
2870
+ min,
2871
+ max,
2872
+ inRange: {
2873
+ color: ["#313695", "#4575b4", "#74add1", "#abd9e9", "#e0f3f8", "#ffffbf", "#fee090", "#fdae61", "#f46d43", "#d73027", "#a50026"]
2874
+ }
2875
+ },
2876
+ xAxis3D: {
2877
+ type: "value"
2878
+ },
2879
+ yAxis3D: {
2880
+ type: "value"
2881
+ },
2882
+ zAxis3D: {
2883
+ type: "value"
2884
+ },
2885
+ grid3D: {
2886
+ viewControl: {
2887
+ projection: "orthographic",
2888
+ autoRotate: false
2889
+ },
2890
+ light: {
2891
+ main: {
2892
+ shadow: true,
2893
+ quality: "ultra",
2894
+ intensity: 1.5
2895
+ }
2896
+ }
2897
+ }
2898
+ }, restConf), {
2899
+ series: [{
2900
+ type: "bar3D",
2901
+ wireframe: {},
2902
+ data: data.map((d) => [d[x_axis_data_key], d[y_axis_data_key], d[z_axis_data_key]])
2903
+ }]
2904
+ });
2905
+ return /* @__PURE__ */ jsx(ReactEChartsCore, {
2906
+ echarts,
2907
+ option,
2908
+ style: {
2909
+ width,
2910
+ height
2918
2911
  }
2919
- return arr;
2920
- }).flat().filter((t) => t !== void 0);
2921
- return ret;
2922
- }
2923
- function textToJSX(text) {
2924
- return withLineBreaks(text);
2912
+ });
2925
2913
  }
2926
- function templateToJSX(template, variables, data) {
2927
- const variableElements = variablesToElements(variables, data);
2928
- const regx = /^\{(.+)\}(.*)$/;
2929
- return template.split("$").map((text) => {
2930
- var _a;
2931
- const match = regx.exec(text);
2932
- if (!match) {
2933
- return textToJSX(text);
2914
+ var index$2 = "";
2915
+ echarts.use([PieChart, CanvasRenderer]);
2916
+ const defaultOption = {
2917
+ tooltip: {
2918
+ show: true
2919
+ },
2920
+ series: {
2921
+ type: "pie",
2922
+ radius: ["50%", "80%"],
2923
+ label: {
2924
+ position: "outer",
2925
+ alignTo: "edge",
2926
+ formatter: "{name|{b}}\n{percentage|{d}%}",
2927
+ minMargin: 5,
2928
+ edgeDistance: 10,
2929
+ lineHeight: 15,
2930
+ rich: {
2931
+ percentage: {
2932
+ color: "#999"
2933
+ }
2934
+ },
2935
+ margin: 20
2936
+ },
2937
+ labelLine: {
2938
+ length: 15,
2939
+ length2: 0,
2940
+ maxSurfaceAngle: 80,
2941
+ showAbove: true
2942
+ },
2943
+ top: 10,
2944
+ bottom: 10,
2945
+ left: 10,
2946
+ right: 10
2947
+ }
2948
+ };
2949
+ function VizPie({
2950
+ conf,
2951
+ data,
2952
+ width,
2953
+ height
2954
+ }) {
2955
+ const _a = conf, {
2956
+ label_field = "name",
2957
+ value_field = "value"
2958
+ } = _a, restConf = __objRest(_a, [
2959
+ "label_field",
2960
+ "value_field"
2961
+ ]);
2962
+ const chartData = React.useMemo(() => {
2963
+ return data.map((d) => ({
2964
+ name: d[label_field],
2965
+ value: Number(d[value_field])
2966
+ }));
2967
+ }, [data, label_field, value_field]);
2968
+ const labelOptions = React.useMemo(() => {
2969
+ return {
2970
+ series: {
2971
+ labelLayout: function(params) {
2972
+ const isLeft = params.labelRect.x < width / 2;
2973
+ const points = params.labelLinePoints;
2974
+ points[2][0] = isLeft ? params.labelRect.x : params.labelRect.x + params.labelRect.width;
2975
+ return {
2976
+ labelLinePoints: points
2977
+ };
2978
+ }
2979
+ }
2980
+ };
2981
+ }, [width]);
2982
+ const option = _.merge({}, defaultOption, labelOptions, restConf, {
2983
+ series: {
2984
+ data: chartData
2934
2985
  }
2935
- const element = variableElements[match[1]];
2936
- if (!element) {
2937
- return textToJSX(text);
2986
+ });
2987
+ return /* @__PURE__ */ jsx(ReactEChartsCore, {
2988
+ echarts,
2989
+ option,
2990
+ style: {
2991
+ width,
2992
+ height
2938
2993
  }
2939
- const rest = (_a = match[2]) != null ? _a : "";
2940
- return /* @__PURE__ */ jsxs(Fragment, {
2941
- children: [element, textToJSX(rest)]
2942
- });
2943
2994
  });
2944
2995
  }
2945
2996
  function VizStats({
@@ -4040,272 +4091,574 @@ function RegressionsField({
4040
4091
  yAxisIndex: 0,
4041
4092
  color: "#666666"
4042
4093
  }
4043
- });
4094
+ });
4095
+ return /* @__PURE__ */ jsxs(Group, {
4096
+ direction: "column",
4097
+ grow: true,
4098
+ children: [controlledFields.map((regressionItem, index2) => /* @__PURE__ */ jsx(RegressionField, {
4099
+ regressionItem,
4100
+ control,
4101
+ index: index2,
4102
+ remove,
4103
+ yAxisOptions,
4104
+ data
4105
+ })), /* @__PURE__ */ jsx(Group, {
4106
+ position: "center",
4107
+ mt: "xs",
4108
+ children: /* @__PURE__ */ jsx(Button, {
4109
+ onClick: add,
4110
+ children: "Add a Regression Line"
4111
+ })
4112
+ })]
4113
+ });
4114
+ }
4115
+ const options = [{
4116
+ label: "None",
4117
+ value: "none"
4118
+ }, {
4119
+ label: "Sum",
4120
+ value: "sum"
4121
+ }, {
4122
+ label: "Mean",
4123
+ value: "mean"
4124
+ }, {
4125
+ label: "Median",
4126
+ value: "median"
4127
+ }, {
4128
+ label: "Max",
4129
+ value: "max"
4130
+ }, {
4131
+ label: "Min",
4132
+ value: "min"
4133
+ }];
4134
+ function _AggregationSelector({
4135
+ label,
4136
+ value,
4137
+ onChange
4138
+ }, ref) {
4139
+ return /* @__PURE__ */ jsx(Select, {
4140
+ ref,
4141
+ label,
4142
+ data: options,
4143
+ value,
4144
+ onChange
4145
+ });
4146
+ }
4147
+ const AggregationSelector = React.forwardRef(_AggregationSelector);
4148
+ function _ColorArrayInput({
4149
+ label,
4150
+ value,
4151
+ onChange
4152
+ }, ref) {
4153
+ const [values, setValues] = React.useState(Array.isArray(value) ? [...value] : []);
4154
+ const add = React.useCallback(() => {
4155
+ setValues((s) => [...s, ""]);
4156
+ }, [setValues]);
4157
+ const del = React.useCallback((index2) => {
4158
+ setValues((s) => {
4159
+ s.splice(index2, 1);
4160
+ return [...s];
4161
+ });
4162
+ }, [setValues]);
4163
+ const changed = React.useMemo(() => {
4164
+ return !_.isEqual(values, value);
4165
+ }, [values, value]);
4166
+ const submit = () => {
4167
+ onChange(values.map((s) => s.toString()));
4168
+ };
4169
+ const theme = useMantineTheme();
4170
+ const swatches = React.useMemo(() => {
4171
+ return Object.entries(theme.colors).map(([_color, profile]) => profile[6]);
4172
+ }, [theme]);
4173
+ return /* @__PURE__ */ jsxs(Fragment, {
4174
+ children: [/* @__PURE__ */ jsxs(Group, {
4175
+ position: "left",
4176
+ ref,
4177
+ children: [/* @__PURE__ */ jsx(Text, {
4178
+ children: label
4179
+ }), /* @__PURE__ */ jsx(ActionIcon, {
4180
+ mr: 5,
4181
+ variant: "filled",
4182
+ color: "blue",
4183
+ disabled: !changed,
4184
+ onClick: submit,
4185
+ children: /* @__PURE__ */ jsx(DeviceFloppy, {
4186
+ size: 20
4187
+ })
4188
+ })]
4189
+ }), /* @__PURE__ */ jsxs(Group, {
4190
+ children: [values.map((v, i) => /* @__PURE__ */ jsx(ColorInput, {
4191
+ value: v,
4192
+ onChange: (color2) => {
4193
+ setValues((s) => {
4194
+ s.splice(i, 1, color2);
4195
+ return [...s];
4196
+ });
4197
+ },
4198
+ swatches,
4199
+ rightSection: /* @__PURE__ */ jsx(ActionIcon, {
4200
+ onClick: () => del(i),
4201
+ color: "red",
4202
+ children: /* @__PURE__ */ jsx(Trash, {
4203
+ size: 14
4204
+ })
4205
+ }),
4206
+ sx: {
4207
+ width: "45%"
4208
+ }
4209
+ })), /* @__PURE__ */ jsx(ActionIcon, {
4210
+ onClick: add,
4211
+ color: "blue",
4212
+ variant: "outline",
4213
+ children: /* @__PURE__ */ jsx(PlaylistAdd, {
4214
+ size: 20
4215
+ })
4216
+ })]
4217
+ })]
4218
+ });
4219
+ }
4220
+ const ColorArrayInput = React.forwardRef(_ColorArrayInput);
4221
+ const marks = [{
4222
+ label: "initial",
4223
+ value: 0
4224
+ }, {
4225
+ label: "500",
4226
+ value: 25
4227
+ }, {
4228
+ label: "700",
4229
+ value: 50
4230
+ }, {
4231
+ label: "semibold",
4232
+ value: 75
4233
+ }, {
4234
+ label: "bold",
4235
+ value: 100
4236
+ }];
4237
+ function _MantineFontWeightSlider({
4238
+ label,
4239
+ value,
4240
+ onChange
4241
+ }, ref) {
4242
+ var _a, _b;
4243
+ const [mark, setMark] = React.useState((_b = (_a = marks.find((m2) => m2.label === value)) == null ? void 0 : _a.value) != null ? _b : marks[0].value);
4244
+ React.useEffect(() => {
4245
+ const match = marks.find((s) => s.value === mark);
4246
+ if (match) {
4247
+ onChange(match.label);
4248
+ }
4249
+ }, [mark]);
4044
4250
  return /* @__PURE__ */ jsxs(Group, {
4045
4251
  direction: "column",
4046
4252
  grow: true,
4047
- children: [controlledFields.map((regressionItem, index2) => /* @__PURE__ */ jsx(RegressionField, {
4048
- regressionItem,
4049
- control,
4050
- index: index2,
4051
- remove,
4052
- yAxisOptions,
4053
- data
4054
- })), /* @__PURE__ */ jsx(Group, {
4055
- position: "center",
4056
- mt: "xs",
4057
- children: /* @__PURE__ */ jsx(Button, {
4253
+ spacing: 0,
4254
+ mt: "sm",
4255
+ mb: "lg",
4256
+ children: [/* @__PURE__ */ jsx(Text, {
4257
+ size: "sm",
4258
+ children: label
4259
+ }), /* @__PURE__ */ jsx(Slider, {
4260
+ label: null,
4261
+ marks,
4262
+ value: mark,
4263
+ onChange: setMark,
4264
+ step: 25,
4265
+ placeholder: "Pick a font size",
4266
+ ref
4267
+ })]
4268
+ });
4269
+ }
4270
+ const MantineFontWeightSlider = React.forwardRef(_MantineFontWeightSlider);
4271
+ function _TextArrayInput({
4272
+ label,
4273
+ value,
4274
+ onChange
4275
+ }, ref) {
4276
+ const [values, setValues] = React.useState(Array.isArray(value) ? [...value] : []);
4277
+ const add = React.useCallback(() => {
4278
+ setValues((s) => [...s, ""]);
4279
+ }, [setValues]);
4280
+ const del = React.useCallback((index2) => {
4281
+ setValues((s) => {
4282
+ s.splice(index2, 1);
4283
+ return [...s];
4284
+ });
4285
+ }, [setValues]);
4286
+ const changed = React.useMemo(() => {
4287
+ return !_.isEqual(values, value);
4288
+ }, [values, value]);
4289
+ const submit = () => {
4290
+ onChange(values.map((s) => s.toString()));
4291
+ };
4292
+ return /* @__PURE__ */ jsxs(Fragment, {
4293
+ children: [/* @__PURE__ */ jsxs(Group, {
4294
+ position: "left",
4295
+ ref,
4296
+ children: [/* @__PURE__ */ jsx(Text, {
4297
+ children: label
4298
+ }), /* @__PURE__ */ jsx(ActionIcon, {
4299
+ mr: 5,
4300
+ variant: "filled",
4301
+ color: "blue",
4302
+ disabled: !changed,
4303
+ onClick: submit,
4304
+ children: /* @__PURE__ */ jsx(DeviceFloppy, {
4305
+ size: 20
4306
+ })
4307
+ })]
4308
+ }), /* @__PURE__ */ jsxs(Group, {
4309
+ children: [values.map((v, i) => /* @__PURE__ */ jsx(TextInput, {
4310
+ value: v,
4311
+ onChange: (event) => {
4312
+ const newValue = event.currentTarget.value;
4313
+ setValues((s) => {
4314
+ s.splice(i, 1, newValue);
4315
+ return [...s];
4316
+ });
4317
+ },
4318
+ rightSection: /* @__PURE__ */ jsx(ActionIcon, {
4319
+ onClick: () => del(i),
4320
+ color: "red",
4321
+ children: /* @__PURE__ */ jsx(Trash, {
4322
+ size: 14
4323
+ })
4324
+ }),
4325
+ sx: {
4326
+ width: "45%"
4327
+ }
4328
+ })), /* @__PURE__ */ jsx(ActionIcon, {
4058
4329
  onClick: add,
4059
- children: "Add a Regression Line"
4060
- })
4330
+ color: "blue",
4331
+ variant: "outline",
4332
+ children: /* @__PURE__ */ jsx(PlaylistAdd, {
4333
+ size: 20
4334
+ })
4335
+ })]
4061
4336
  })]
4062
4337
  });
4063
4338
  }
4064
- function withDefaults(series) {
4065
- function setDefaults({
4066
- type,
4067
- name,
4068
- showSymbol,
4069
- symbolSize = 5,
4070
- y_axis_data_key = "value",
4071
- yAxisIndex = 0,
4072
- label_position = "top",
4073
- stack = "1",
4074
- color: color2 = "black",
4075
- barWidth = "30",
4076
- smooth = false,
4077
- step = false
4078
- }) {
4079
- return {
4080
- type,
4081
- name,
4082
- showSymbol,
4083
- symbolSize,
4084
- y_axis_data_key,
4085
- yAxisIndex,
4086
- label_position,
4087
- stack,
4088
- color: color2,
4089
- barWidth,
4090
- smooth,
4091
- step
4092
- };
4093
- }
4094
- return series.map(setDefaults);
4339
+ const TextArrayInput = React.forwardRef(_TextArrayInput);
4340
+ function getANewVariable() {
4341
+ return {
4342
+ name: randomId(),
4343
+ size: "20px",
4344
+ weight: "bold",
4345
+ color: {
4346
+ type: "static",
4347
+ staticColor: "blue"
4348
+ },
4349
+ data_field: "",
4350
+ aggregation: "none",
4351
+ formatter: {
4352
+ output: "number",
4353
+ mantissa: 0
4354
+ }
4355
+ };
4095
4356
  }
4096
- function VizCartesianChartPanel({
4097
- conf,
4098
- setConf,
4357
+ const TemplateInput = React.forwardRef(function TemplateInput2(_a, ref) {
4358
+ var _b = _a, {
4359
+ value,
4360
+ onChange
4361
+ } = _b, rest = __objRest(_b, [
4362
+ "value",
4363
+ "onChange"
4364
+ ]);
4365
+ return /* @__PURE__ */ jsx(TextInput, __spreadValues({
4366
+ ref,
4367
+ value,
4368
+ onChange
4369
+ }, rest));
4370
+ });
4371
+ function TemplateVariableField({
4372
+ value,
4373
+ onChange,
4099
4374
  data
4100
4375
  }) {
4101
- const _a = conf, {
4102
- series,
4103
- y_axes
4104
- } = _a, restConf = __objRest(_a, [
4105
- "series",
4106
- "y_axes"
4107
- ]);
4108
- const defaultValues = React.useMemo(() => {
4109
- const _a2 = restConf, {
4110
- x_axis_name = ""
4111
- } = _a2, rest = __objRest(_a2, [
4112
- "x_axis_name"
4113
- ]);
4114
- return __spreadValues({
4115
- series: withDefaults(series != null ? series : []),
4116
- x_axis_name,
4117
- y_axes: y_axes != null ? y_axes : [{
4118
- name: "Y Axis",
4119
- label_formatter: defaultNumbroFormat
4120
- }]
4121
- }, rest);
4122
- }, [series, restConf]);
4123
- React.useEffect(() => {
4124
- const configMalformed = !_.isEqual(conf, defaultValues);
4125
- if (configMalformed) {
4126
- setConf(defaultValues);
4127
- }
4128
- }, [conf, defaultValues]);
4129
- const {
4130
- control,
4131
- handleSubmit,
4132
- watch,
4133
- getValues
4134
- } = useForm({
4135
- defaultValues
4136
- });
4137
- watch(["x_axis_data_key", "x_axis_name"]);
4138
- const values = getValues();
4139
- const changed = React.useMemo(() => {
4140
- return !_.isEqual(values, conf);
4141
- }, [values, conf]);
4142
- return /* @__PURE__ */ jsx(Group, {
4143
- direction: "column",
4144
- mt: "md",
4145
- spacing: "xs",
4146
- grow: true,
4147
- children: /* @__PURE__ */ jsxs("form", {
4148
- onSubmit: handleSubmit(setConf),
4149
- children: [/* @__PURE__ */ jsxs(Group, {
4150
- position: "left",
4151
- py: "md",
4152
- pl: "md",
4376
+ const colorType = value.color.type;
4377
+ const handleChange = (path, newValue) => {
4378
+ const v = _.cloneDeep(value);
4379
+ _.set(v, path, newValue);
4380
+ onChange(v);
4381
+ };
4382
+ return /* @__PURE__ */ jsxs(Box, {
4383
+ px: "sm",
4384
+ py: "md",
4385
+ children: [/* @__PURE__ */ jsx(Text, {
4386
+ weight: "bold",
4387
+ pb: 0,
4388
+ children: value.name
4389
+ }), /* @__PURE__ */ jsx(Divider, {
4390
+ my: "xs",
4391
+ label: "Data",
4392
+ labelPosition: "center"
4393
+ }), /* @__PURE__ */ jsxs(Group, {
4394
+ direction: "row",
4395
+ grow: true,
4396
+ noWrap: true,
4397
+ children: [/* @__PURE__ */ jsx(TextInput, {
4398
+ label: "Name",
4399
+ required: true,
4400
+ value: value.name,
4401
+ onChange: (e) => handleChange("name", e.currentTarget.value)
4402
+ }), /* @__PURE__ */ jsx(DataFieldSelector, {
4403
+ label: "Data Field",
4404
+ required: true,
4405
+ data,
4406
+ value: value.data_field,
4407
+ onChange: (v) => handleChange("data_field", v)
4408
+ }), /* @__PURE__ */ jsx(AggregationSelector, {
4409
+ label: "Aggregation",
4410
+ value: value.aggregation,
4411
+ onChange: (v) => handleChange("aggregation", v)
4412
+ })]
4413
+ }), /* @__PURE__ */ jsx(NumbroFormatSelector, {
4414
+ value: value.formatter,
4415
+ onChange: (v) => handleChange("formatter", v)
4416
+ }), /* @__PURE__ */ jsx(Divider, {
4417
+ my: "xs",
4418
+ label: "Typography",
4419
+ labelPosition: "center"
4420
+ }), /* @__PURE__ */ jsx(Group, {
4421
+ direction: "column",
4422
+ grow: true,
4423
+ children: /* @__PURE__ */ jsx(TextInput, {
4424
+ label: "Font Size",
4425
+ placeholder: "10px, 1em, 1rem, 100%...",
4153
4426
  sx: {
4154
- borderBottom: "1px solid #eee",
4155
- background: "#efefef"
4156
- },
4157
- children: [/* @__PURE__ */ jsx(Text, {
4158
- children: "Chart Config"
4159
- }), /* @__PURE__ */ jsx(ActionIcon, {
4160
- type: "submit",
4161
- mr: 5,
4162
- variant: "filled",
4163
- color: "blue",
4164
- disabled: !changed,
4165
- children: /* @__PURE__ */ jsx(DeviceFloppy, {
4166
- size: 20
4167
- })
4168
- })]
4169
- }), /* @__PURE__ */ jsxs(Accordion, {
4170
- offsetIcon: false,
4171
- multiple: true,
4172
- initialState: {
4173
- 0: true,
4174
- 1: true
4427
+ flex: 1
4175
4428
  },
4176
- children: [/* @__PURE__ */ jsx(Accordion.Item, {
4177
- label: "X Axis",
4178
- children: /* @__PURE__ */ jsxs(Group, {
4179
- direction: "row",
4180
- grow: true,
4181
- noWrap: true,
4182
- children: [/* @__PURE__ */ jsx(Controller, {
4183
- name: "x_axis_data_key",
4184
- control,
4185
- render: ({
4186
- field
4187
- }) => /* @__PURE__ */ jsx(DataFieldSelector, __spreadValues({
4188
- label: "X Axis Data Field",
4189
- required: true,
4190
- data,
4191
- sx: {
4192
- flex: 1
4193
- }
4194
- }, field))
4195
- }), /* @__PURE__ */ jsx(Controller, {
4196
- name: "x_axis_name",
4197
- control,
4198
- render: ({
4199
- field
4200
- }) => /* @__PURE__ */ jsx(TextInput, __spreadValues({
4201
- label: "X Axis Name",
4202
- sx: {
4203
- flex: 1
4204
- }
4205
- }, field))
4206
- })]
4207
- })
4208
- }), /* @__PURE__ */ jsx(Accordion.Item, {
4209
- label: "Y Axes",
4210
- children: /* @__PURE__ */ jsx(YAxesField, {
4211
- control,
4212
- watch
4213
- })
4214
- }), /* @__PURE__ */ jsx(Accordion.Item, {
4215
- label: "Series",
4216
- children: /* @__PURE__ */ jsx(SeriesField, {
4217
- control,
4218
- watch,
4219
- getValues,
4220
- data
4221
- })
4222
- }), /* @__PURE__ */ jsx(Accordion.Item, {
4223
- label: "Regression Lines",
4224
- children: /* @__PURE__ */ jsx(RegressionsField, {
4225
- control,
4226
- watch,
4227
- getValues,
4228
- data
4229
- })
4429
+ value: value.size,
4430
+ onChange: (e) => handleChange("size", e.currentTarget.value)
4431
+ })
4432
+ }), /* @__PURE__ */ jsx(Group, {
4433
+ position: "apart",
4434
+ grow: true,
4435
+ sx: {
4436
+ "> *": {
4437
+ flexGrow: 1,
4438
+ maxWidth: "100%"
4439
+ }
4440
+ },
4441
+ children: /* @__PURE__ */ jsx(MantineFontWeightSlider, {
4442
+ label: "Font Weight",
4443
+ value: value.weight,
4444
+ onChange: (v) => handleChange("weight", v)
4445
+ })
4446
+ }), /* @__PURE__ */ jsx(Divider, {
4447
+ my: "xs",
4448
+ label: "Style",
4449
+ labelPosition: "center"
4450
+ }), /* @__PURE__ */ jsxs(Group, {
4451
+ direction: "column",
4452
+ grow: true,
4453
+ children: [/* @__PURE__ */ jsx(Select, {
4454
+ label: "Color Type",
4455
+ data: [{
4456
+ label: "Static Color",
4457
+ value: "static"
4458
+ }, {
4459
+ label: "Continuous Color",
4460
+ value: "continuous"
4461
+ }],
4462
+ value: value.color.type,
4463
+ onChange: (v) => handleChange("color.type", v)
4464
+ }), colorType === "static" && /* @__PURE__ */ jsx(MantineColorSelector, {
4465
+ value: value.color.staticColor,
4466
+ onChange: (v) => handleChange("color.staticColor", v)
4467
+ }), colorType === "continuous" && /* @__PURE__ */ jsxs(Fragment, {
4468
+ children: [/* @__PURE__ */ jsx(TextArrayInput, {
4469
+ label: "Value Range",
4470
+ value: value.color.valueRange,
4471
+ onChange: (v) => handleChange("color.valueRange", v)
4472
+ }), /* @__PURE__ */ jsx(ColorArrayInput, {
4473
+ label: "Color Range",
4474
+ value: value.color.colorRange,
4475
+ onChange: (v) => handleChange("color.colorRange", v)
4230
4476
  })]
4231
4477
  })]
4232
- })
4478
+ })]
4233
4479
  });
4234
4480
  }
4235
- function VizPiePanel({
4236
- conf: {
4237
- label_field,
4238
- value_field
4239
- },
4240
- setConf,
4481
+ function VariableField$1({
4482
+ control,
4483
+ index: index2,
4484
+ remove,
4241
4485
  data
4242
4486
  }) {
4243
- const form = useForm$1({
4244
- initialValues: {
4245
- label_field,
4246
- value_field
4247
- }
4487
+ return /* @__PURE__ */ jsxs(Group, {
4488
+ direction: "column",
4489
+ grow: true,
4490
+ my: "sm",
4491
+ p: 0,
4492
+ sx: {
4493
+ border: "1px solid #eee",
4494
+ borderTopColor: "#333",
4495
+ borderTopWidth: 2,
4496
+ position: "relative"
4497
+ },
4498
+ children: [/* @__PURE__ */ jsx(Controller, {
4499
+ name: `stats.variables.${index2}`,
4500
+ control,
4501
+ render: ({
4502
+ field
4503
+ }) => /* @__PURE__ */ jsx(TemplateVariableField, __spreadValues({
4504
+ data
4505
+ }, field))
4506
+ }), /* @__PURE__ */ jsx(ActionIcon, {
4507
+ color: "red",
4508
+ variant: "hover",
4509
+ onClick: () => remove(index2),
4510
+ sx: {
4511
+ position: "absolute",
4512
+ top: 15,
4513
+ right: 5
4514
+ },
4515
+ children: /* @__PURE__ */ jsx(Trash, {
4516
+ size: 16
4517
+ })
4518
+ })]
4519
+ }, index2);
4520
+ }
4521
+ function StatsField({
4522
+ control,
4523
+ watch,
4524
+ data
4525
+ }) {
4526
+ const {
4527
+ fields,
4528
+ append,
4529
+ remove
4530
+ } = useFieldArray({
4531
+ control,
4532
+ name: "stats.variables"
4248
4533
  });
4249
- return /* @__PURE__ */ jsx(Group, {
4534
+ watch("stats.templates");
4535
+ const watchFieldArray = watch("stats.variables");
4536
+ const controlledFields = fields.map((field, index2) => {
4537
+ return __spreadValues(__spreadValues({}, field), watchFieldArray[index2]);
4538
+ });
4539
+ const add = () => append(getANewVariable());
4540
+ return /* @__PURE__ */ jsxs(Group, {
4250
4541
  direction: "column",
4251
- mt: "md",
4252
- spacing: "xs",
4253
4542
  grow: true,
4254
- children: /* @__PURE__ */ jsxs("form", {
4255
- onSubmit: form.onSubmit(setConf),
4256
- children: [/* @__PURE__ */ jsxs(Group, {
4257
- position: "apart",
4258
- mb: "lg",
4259
- sx: {
4260
- position: "relative"
4261
- },
4262
- children: [/* @__PURE__ */ jsx(Text, {
4263
- children: "Pie Config"
4264
- }), /* @__PURE__ */ jsx(ActionIcon, {
4265
- type: "submit",
4266
- mr: 5,
4267
- variant: "filled",
4268
- color: "blue",
4269
- children: /* @__PURE__ */ jsx(DeviceFloppy, {
4270
- size: 20
4271
- })
4272
- })]
4273
- }), /* @__PURE__ */ jsxs(Group, {
4274
- direction: "column",
4275
- mt: "md",
4276
- spacing: "xs",
4277
- grow: true,
4278
- p: "md",
4279
- mb: "sm",
4280
- sx: {
4281
- border: "1px solid #eee",
4282
- borderRadius: "5px"
4283
- },
4284
- children: [/* @__PURE__ */ jsx(DataFieldSelector, __spreadValues({
4285
- label: "Label Field",
4286
- required: true,
4287
- data
4288
- }, form.getInputProps("label_field"))), /* @__PURE__ */ jsx(DataFieldSelector, __spreadValues({
4289
- label: "Value Field",
4290
- required: true,
4291
- data
4292
- }, form.getInputProps("value_field")))]
4543
+ children: [/* @__PURE__ */ jsxs(Group, {
4544
+ direction: "column",
4545
+ grow: true,
4546
+ noWrap: true,
4547
+ spacing: 0,
4548
+ children: [/* @__PURE__ */ jsx(Controller, {
4549
+ name: "stats.templates.top",
4550
+ control,
4551
+ render: ({
4552
+ field
4553
+ }) => /* @__PURE__ */ jsx(TemplateInput, __spreadValues({
4554
+ label: "Template for stats above the chart",
4555
+ py: "md",
4556
+ sx: {
4557
+ flexGrow: 1
4558
+ }
4559
+ }, field))
4560
+ }), /* @__PURE__ */ jsx(Controller, {
4561
+ name: "stats.templates.bottom",
4562
+ control,
4563
+ render: ({
4564
+ field
4565
+ }) => /* @__PURE__ */ jsx(TemplateInput, __spreadValues({
4566
+ label: "Template for stats under the chart",
4567
+ py: "md",
4568
+ sx: {
4569
+ flexGrow: 1
4570
+ }
4571
+ }, field))
4293
4572
  })]
4294
- })
4573
+ }), controlledFields.map((_variableItem, index2) => /* @__PURE__ */ jsx(VariableField$1, {
4574
+ control,
4575
+ index: index2,
4576
+ remove,
4577
+ data
4578
+ })), /* @__PURE__ */ jsx(Group, {
4579
+ position: "center",
4580
+ mt: "xs",
4581
+ children: /* @__PURE__ */ jsx(Button, {
4582
+ onClick: add,
4583
+ children: "Add a Variable"
4584
+ })
4585
+ })]
4295
4586
  });
4296
4587
  }
4297
- function VizRichTextPanel({
4588
+ function withDefaults(series) {
4589
+ function setDefaults({
4590
+ type,
4591
+ name,
4592
+ showSymbol,
4593
+ symbolSize = 5,
4594
+ y_axis_data_key = "value",
4595
+ yAxisIndex = 0,
4596
+ label_position = "top",
4597
+ stack = "1",
4598
+ color: color2 = "black",
4599
+ barWidth = "30",
4600
+ smooth = false,
4601
+ step = false
4602
+ }) {
4603
+ return {
4604
+ type,
4605
+ name,
4606
+ showSymbol,
4607
+ symbolSize,
4608
+ y_axis_data_key,
4609
+ yAxisIndex,
4610
+ label_position,
4611
+ stack,
4612
+ color: color2,
4613
+ barWidth,
4614
+ smooth,
4615
+ step
4616
+ };
4617
+ }
4618
+ return series.map(setDefaults);
4619
+ }
4620
+ function normalizeStats(stats) {
4621
+ if (!stats) {
4622
+ return {
4623
+ templates: {
4624
+ top: "",
4625
+ bottom: ""
4626
+ },
4627
+ variables: []
4628
+ };
4629
+ }
4630
+ return stats;
4631
+ }
4632
+ function VizCartesianChartPanel({
4298
4633
  conf,
4299
- setConf
4634
+ setConf,
4635
+ data
4300
4636
  }) {
4637
+ const _a = conf, {
4638
+ series,
4639
+ y_axes
4640
+ } = _a, restConf = __objRest(_a, [
4641
+ "series",
4642
+ "y_axes"
4643
+ ]);
4301
4644
  const defaultValues = React.useMemo(() => {
4302
- const {
4303
- content = ""
4304
- } = conf;
4305
- return {
4306
- content
4307
- };
4308
- }, [conf]);
4645
+ const _a2 = restConf, {
4646
+ x_axis_name = "",
4647
+ stats
4648
+ } = _a2, rest = __objRest(_a2, [
4649
+ "x_axis_name",
4650
+ "stats"
4651
+ ]);
4652
+ return __spreadValues({
4653
+ series: withDefaults(series != null ? series : []),
4654
+ x_axis_name,
4655
+ y_axes: y_axes != null ? y_axes : [{
4656
+ name: "Y Axis",
4657
+ label_formatter: defaultNumbroFormat
4658
+ }],
4659
+ stats: normalizeStats(stats)
4660
+ }, rest);
4661
+ }, [series, restConf]);
4309
4662
  React.useEffect(() => {
4310
4663
  const configMalformed = !_.isEqual(conf, defaultValues);
4311
4664
  if (configMalformed) {
@@ -4320,436 +4673,280 @@ function VizRichTextPanel({
4320
4673
  } = useForm({
4321
4674
  defaultValues
4322
4675
  });
4323
- watch("content");
4324
- const values = getValues();
4325
- const changed = React.useMemo(() => {
4326
- return !_.isEqual(values, conf);
4327
- }, [values, conf]);
4328
- return /* @__PURE__ */ jsx(Group, {
4329
- direction: "column",
4330
- mt: "md",
4331
- spacing: "xs",
4332
- grow: true,
4333
- children: /* @__PURE__ */ jsxs("form", {
4334
- onSubmit: handleSubmit(setConf),
4335
- children: [/* @__PURE__ */ jsxs(Group, {
4336
- position: "left",
4337
- py: "md",
4338
- pl: "md",
4339
- sx: {
4340
- borderBottom: "1px solid #eee",
4341
- background: "#efefef"
4342
- },
4343
- children: [/* @__PURE__ */ jsx(Text, {
4344
- children: "Content"
4345
- }), /* @__PURE__ */ jsx(ActionIcon, {
4346
- type: "submit",
4347
- mr: 5,
4348
- variant: "filled",
4349
- color: "blue",
4350
- disabled: !changed,
4351
- children: /* @__PURE__ */ jsx(DeviceFloppy, {
4352
- size: 20
4353
- })
4354
- })]
4355
- }), /* @__PURE__ */ jsx(Controller, {
4356
- name: "content",
4357
- control,
4358
- render: ({
4359
- field
4360
- }) => /* @__PURE__ */ jsx(RichTextEditor, __spreadValues({
4361
- sx: {
4362
- flex: 1
4363
- }
4364
- }, field))
4365
- })]
4366
- })
4367
- });
4368
- }
4369
- function updateSchema(legacyConf) {
4370
- if ("variables" in legacyConf) {
4371
- return legacyConf;
4372
- }
4373
- const {
4374
- align,
4375
- size,
4376
- weight,
4377
- color: color2,
4378
- content: {
4379
- prefix = "",
4380
- data_field = "value",
4381
- formatter = {
4382
- output: "number",
4383
- mantissa: 0
4384
- },
4385
- postfix = ""
4386
- } = {}
4387
- } = legacyConf;
4388
- return {
4389
- align,
4390
- template: `${prefix} \${value} ${postfix}`,
4391
- variables: [
4392
- {
4393
- name: "value",
4394
- data_field,
4395
- aggregation: "none",
4396
- formatter,
4397
- color: color2,
4398
- weight,
4399
- size
4400
- }
4401
- ]
4402
- };
4403
- }
4404
- const options = [{
4405
- label: "None",
4406
- value: "none"
4407
- }, {
4408
- label: "Sum",
4409
- value: "sum"
4410
- }, {
4411
- label: "Mean",
4412
- value: "mean"
4413
- }, {
4414
- label: "Median",
4415
- value: "median"
4416
- }, {
4417
- label: "Max",
4418
- value: "max"
4419
- }, {
4420
- label: "Min",
4421
- value: "min"
4422
- }];
4423
- function _AggregationSelector({
4424
- label,
4425
- value,
4426
- onChange
4427
- }, ref) {
4428
- return /* @__PURE__ */ jsx(Select, {
4429
- ref,
4430
- label,
4431
- data: options,
4432
- value,
4433
- onChange
4434
- });
4435
- }
4436
- const AggregationSelector = React.forwardRef(_AggregationSelector);
4437
- function _ColorArrayInput({
4438
- label,
4439
- value,
4440
- onChange
4441
- }, ref) {
4442
- const [values, setValues] = React.useState(Array.isArray(value) ? [...value] : []);
4443
- const add = React.useCallback(() => {
4444
- setValues((s) => [...s, ""]);
4445
- }, [setValues]);
4446
- const del = React.useCallback((index2) => {
4447
- setValues((s) => {
4448
- s.splice(index2, 1);
4449
- return [...s];
4450
- });
4451
- }, [setValues]);
4452
- const changed = React.useMemo(() => {
4453
- return !_.isEqual(values, value);
4454
- }, [values, value]);
4455
- const submit = () => {
4456
- onChange(values.map((s) => s.toString()));
4457
- };
4458
- const theme = useMantineTheme();
4459
- const swatches = React.useMemo(() => {
4460
- return Object.entries(theme.colors).map(([_color, profile]) => profile[6]);
4461
- }, [theme]);
4462
- return /* @__PURE__ */ jsxs(Fragment, {
4463
- children: [/* @__PURE__ */ jsxs(Group, {
4464
- position: "left",
4465
- ref,
4466
- children: [/* @__PURE__ */ jsx(Text, {
4467
- children: label
4468
- }), /* @__PURE__ */ jsx(ActionIcon, {
4469
- mr: 5,
4470
- variant: "filled",
4471
- color: "blue",
4472
- disabled: !changed,
4473
- onClick: submit,
4474
- children: /* @__PURE__ */ jsx(DeviceFloppy, {
4475
- size: 20
4476
- })
4477
- })]
4478
- }), /* @__PURE__ */ jsxs(Group, {
4479
- children: [values.map((v, i) => /* @__PURE__ */ jsx(ColorInput, {
4480
- value: v,
4481
- onChange: (color2) => {
4482
- setValues((s) => {
4483
- s.splice(i, 1, color2);
4484
- return [...s];
4485
- });
4676
+ watch(["x_axis_data_key", "x_axis_name"]);
4677
+ const values = getValues();
4678
+ const changed = React.useMemo(() => {
4679
+ return !_.isEqual(values, conf);
4680
+ }, [values, conf]);
4681
+ return /* @__PURE__ */ jsx(Group, {
4682
+ direction: "column",
4683
+ mt: "md",
4684
+ spacing: "xs",
4685
+ grow: true,
4686
+ children: /* @__PURE__ */ jsxs("form", {
4687
+ onSubmit: handleSubmit(setConf),
4688
+ children: [/* @__PURE__ */ jsxs(Group, {
4689
+ position: "left",
4690
+ py: "md",
4691
+ pl: "md",
4692
+ sx: {
4693
+ borderBottom: "1px solid #eee",
4694
+ background: "#efefef"
4486
4695
  },
4487
- swatches,
4488
- rightSection: /* @__PURE__ */ jsx(ActionIcon, {
4489
- onClick: () => del(i),
4490
- color: "red",
4491
- children: /* @__PURE__ */ jsx(Trash, {
4492
- size: 14
4696
+ children: [/* @__PURE__ */ jsx(Text, {
4697
+ children: "Chart Config"
4698
+ }), /* @__PURE__ */ jsx(ActionIcon, {
4699
+ type: "submit",
4700
+ mr: 5,
4701
+ variant: "filled",
4702
+ color: "blue",
4703
+ disabled: !changed,
4704
+ children: /* @__PURE__ */ jsx(DeviceFloppy, {
4705
+ size: 20
4493
4706
  })
4494
- }),
4495
- sx: {
4496
- width: "45%"
4497
- }
4498
- })), /* @__PURE__ */ jsx(ActionIcon, {
4499
- onClick: add,
4500
- color: "blue",
4501
- variant: "outline",
4502
- children: /* @__PURE__ */ jsx(PlaylistAdd, {
4503
- size: 20
4504
- })
4707
+ })]
4708
+ }), /* @__PURE__ */ jsxs(Accordion, {
4709
+ offsetIcon: false,
4710
+ multiple: true,
4711
+ initialState: {
4712
+ 0: true,
4713
+ 1: true
4714
+ },
4715
+ children: [/* @__PURE__ */ jsx(Accordion.Item, {
4716
+ label: "X Axis",
4717
+ children: /* @__PURE__ */ jsxs(Group, {
4718
+ direction: "row",
4719
+ grow: true,
4720
+ noWrap: true,
4721
+ children: [/* @__PURE__ */ jsx(Controller, {
4722
+ name: "x_axis_data_key",
4723
+ control,
4724
+ render: ({
4725
+ field
4726
+ }) => /* @__PURE__ */ jsx(DataFieldSelector, __spreadValues({
4727
+ label: "X Axis Data Field",
4728
+ required: true,
4729
+ data,
4730
+ sx: {
4731
+ flex: 1
4732
+ }
4733
+ }, field))
4734
+ }), /* @__PURE__ */ jsx(Controller, {
4735
+ name: "x_axis_name",
4736
+ control,
4737
+ render: ({
4738
+ field
4739
+ }) => /* @__PURE__ */ jsx(TextInput, __spreadValues({
4740
+ label: "X Axis Name",
4741
+ sx: {
4742
+ flex: 1
4743
+ }
4744
+ }, field))
4745
+ })]
4746
+ })
4747
+ }), /* @__PURE__ */ jsx(Accordion.Item, {
4748
+ label: "Y Axes",
4749
+ children: /* @__PURE__ */ jsx(YAxesField, {
4750
+ control,
4751
+ watch
4752
+ })
4753
+ }), /* @__PURE__ */ jsx(Accordion.Item, {
4754
+ label: "Series",
4755
+ children: /* @__PURE__ */ jsx(SeriesField, {
4756
+ control,
4757
+ watch,
4758
+ getValues,
4759
+ data
4760
+ })
4761
+ }), /* @__PURE__ */ jsx(Accordion.Item, {
4762
+ label: "Regression Lines",
4763
+ children: /* @__PURE__ */ jsx(RegressionsField, {
4764
+ control,
4765
+ watch,
4766
+ getValues,
4767
+ data
4768
+ })
4769
+ }), /* @__PURE__ */ jsx(Accordion.Item, {
4770
+ label: "Stats",
4771
+ children: /* @__PURE__ */ jsx(StatsField, {
4772
+ control,
4773
+ watch,
4774
+ data
4775
+ })
4776
+ })]
4505
4777
  })]
4506
- })]
4778
+ })
4507
4779
  });
4508
4780
  }
4509
- const ColorArrayInput = React.forwardRef(_ColorArrayInput);
4510
- const marks = [{
4511
- label: "initial",
4512
- value: 0
4513
- }, {
4514
- label: "500",
4515
- value: 25
4516
- }, {
4517
- label: "700",
4518
- value: 50
4519
- }, {
4520
- label: "semibold",
4521
- value: 75
4522
- }, {
4523
- label: "bold",
4524
- value: 100
4525
- }];
4526
- function _MantineFontWeightSlider({
4527
- label,
4528
- value,
4529
- onChange
4530
- }, ref) {
4531
- var _a, _b;
4532
- const [mark, setMark] = React.useState((_b = (_a = marks.find((m2) => m2.label === value)) == null ? void 0 : _a.value) != null ? _b : marks[0].value);
4533
- React.useEffect(() => {
4534
- const match = marks.find((s) => s.value === mark);
4535
- if (match) {
4536
- onChange(match.label);
4781
+ function VizPiePanel({
4782
+ conf: {
4783
+ label_field,
4784
+ value_field
4785
+ },
4786
+ setConf,
4787
+ data
4788
+ }) {
4789
+ const form = useForm$1({
4790
+ initialValues: {
4791
+ label_field,
4792
+ value_field
4537
4793
  }
4538
- }, [mark]);
4539
- return /* @__PURE__ */ jsxs(Group, {
4794
+ });
4795
+ return /* @__PURE__ */ jsx(Group, {
4540
4796
  direction: "column",
4797
+ mt: "md",
4798
+ spacing: "xs",
4541
4799
  grow: true,
4542
- spacing: 0,
4543
- mt: "sm",
4544
- mb: "lg",
4545
- children: [/* @__PURE__ */ jsx(Text, {
4546
- size: "sm",
4547
- children: label
4548
- }), /* @__PURE__ */ jsx(Slider, {
4549
- label: null,
4550
- marks,
4551
- value: mark,
4552
- onChange: setMark,
4553
- step: 25,
4554
- placeholder: "Pick a font size",
4555
- ref
4556
- })]
4557
- });
4558
- }
4559
- const MantineFontWeightSlider = React.forwardRef(_MantineFontWeightSlider);
4560
- function _TextArrayInput({
4561
- label,
4562
- value,
4563
- onChange
4564
- }, ref) {
4565
- const [values, setValues] = React.useState(Array.isArray(value) ? [...value] : []);
4566
- const add = React.useCallback(() => {
4567
- setValues((s) => [...s, ""]);
4568
- }, [setValues]);
4569
- const del = React.useCallback((index2) => {
4570
- setValues((s) => {
4571
- s.splice(index2, 1);
4572
- return [...s];
4573
- });
4574
- }, [setValues]);
4575
- const changed = React.useMemo(() => {
4576
- return !_.isEqual(values, value);
4577
- }, [values, value]);
4578
- const submit = () => {
4579
- onChange(values.map((s) => s.toString()));
4580
- };
4581
- return /* @__PURE__ */ jsxs(Fragment, {
4582
- children: [/* @__PURE__ */ jsxs(Group, {
4583
- position: "left",
4584
- ref,
4585
- children: [/* @__PURE__ */ jsx(Text, {
4586
- children: label
4587
- }), /* @__PURE__ */ jsx(ActionIcon, {
4588
- mr: 5,
4589
- variant: "filled",
4590
- color: "blue",
4591
- disabled: !changed,
4592
- onClick: submit,
4593
- children: /* @__PURE__ */ jsx(DeviceFloppy, {
4594
- size: 20
4595
- })
4596
- })]
4597
- }), /* @__PURE__ */ jsxs(Group, {
4598
- children: [values.map((v, i) => /* @__PURE__ */ jsx(TextInput, {
4599
- value: v,
4600
- onChange: (event) => {
4601
- const newValue = event.currentTarget.value;
4602
- setValues((s) => {
4603
- s.splice(i, 1, newValue);
4604
- return [...s];
4605
- });
4800
+ children: /* @__PURE__ */ jsxs("form", {
4801
+ onSubmit: form.onSubmit(setConf),
4802
+ children: [/* @__PURE__ */ jsxs(Group, {
4803
+ position: "apart",
4804
+ mb: "lg",
4805
+ sx: {
4806
+ position: "relative"
4606
4807
  },
4607
- rightSection: /* @__PURE__ */ jsx(ActionIcon, {
4608
- onClick: () => del(i),
4609
- color: "red",
4610
- children: /* @__PURE__ */ jsx(Trash, {
4611
- size: 14
4808
+ children: [/* @__PURE__ */ jsx(Text, {
4809
+ children: "Pie Config"
4810
+ }), /* @__PURE__ */ jsx(ActionIcon, {
4811
+ type: "submit",
4812
+ mr: 5,
4813
+ variant: "filled",
4814
+ color: "blue",
4815
+ children: /* @__PURE__ */ jsx(DeviceFloppy, {
4816
+ size: 20
4612
4817
  })
4613
- }),
4818
+ })]
4819
+ }), /* @__PURE__ */ jsxs(Group, {
4820
+ direction: "column",
4821
+ mt: "md",
4822
+ spacing: "xs",
4823
+ grow: true,
4824
+ p: "md",
4825
+ mb: "sm",
4614
4826
  sx: {
4615
- width: "45%"
4616
- }
4617
- })), /* @__PURE__ */ jsx(ActionIcon, {
4618
- onClick: add,
4619
- color: "blue",
4620
- variant: "outline",
4621
- children: /* @__PURE__ */ jsx(PlaylistAdd, {
4622
- size: 20
4623
- })
4827
+ border: "1px solid #eee",
4828
+ borderRadius: "5px"
4829
+ },
4830
+ children: [/* @__PURE__ */ jsx(DataFieldSelector, __spreadValues({
4831
+ label: "Label Field",
4832
+ required: true,
4833
+ data
4834
+ }, form.getInputProps("label_field"))), /* @__PURE__ */ jsx(DataFieldSelector, __spreadValues({
4835
+ label: "Value Field",
4836
+ required: true,
4837
+ data
4838
+ }, form.getInputProps("value_field")))]
4624
4839
  })]
4625
- })]
4840
+ })
4626
4841
  });
4627
4842
  }
4628
- const TextArrayInput = React.forwardRef(_TextArrayInput);
4629
- const TemplateInput = React.forwardRef(function TemplateInput2(_a, ref) {
4630
- var _b = _a, {
4631
- value,
4632
- onChange
4633
- } = _b, rest = __objRest(_b, [
4634
- "value",
4635
- "onChange"
4636
- ]);
4637
- return /* @__PURE__ */ jsx(TextInput, __spreadValues({
4638
- ref,
4639
- value,
4640
- onChange
4641
- }, rest));
4642
- });
4643
- function TemplateVariableField({
4644
- value,
4645
- onChange,
4646
- data
4843
+ function VizRichTextPanel({
4844
+ conf,
4845
+ setConf
4647
4846
  }) {
4648
- const colorType = value.color.type;
4649
- const handleChange = (path, newValue) => {
4650
- const v = _.cloneDeep(value);
4651
- _.set(v, path, newValue);
4652
- onChange(v);
4653
- };
4654
- return /* @__PURE__ */ jsxs(Box, {
4655
- px: "sm",
4656
- py: "md",
4657
- children: [/* @__PURE__ */ jsx(Text, {
4658
- weight: "bold",
4659
- pb: 0,
4660
- children: value.name
4661
- }), /* @__PURE__ */ jsx(Divider, {
4662
- my: "xs",
4663
- label: "Data",
4664
- labelPosition: "center"
4665
- }), /* @__PURE__ */ jsxs(Group, {
4666
- direction: "row",
4667
- grow: true,
4668
- noWrap: true,
4669
- children: [/* @__PURE__ */ jsx(TextInput, {
4670
- label: "Name",
4671
- required: true,
4672
- value: value.name,
4673
- onChange: (e) => handleChange("name", e.currentTarget.value)
4674
- }), /* @__PURE__ */ jsx(DataFieldSelector, {
4675
- label: "Data Field",
4676
- required: true,
4677
- data,
4678
- value: value.data_field,
4679
- onChange: (v) => handleChange("data_field", v)
4680
- }), /* @__PURE__ */ jsx(AggregationSelector, {
4681
- label: "Aggregation",
4682
- value: value.aggregation,
4683
- onChange: (v) => handleChange("aggregation", v)
4684
- })]
4685
- }), /* @__PURE__ */ jsx(NumbroFormatSelector, {
4686
- value: value.formatter,
4687
- onChange: (v) => handleChange("formatter", v)
4688
- }), /* @__PURE__ */ jsx(Divider, {
4689
- my: "xs",
4690
- label: "Typography",
4691
- labelPosition: "center"
4692
- }), /* @__PURE__ */ jsx(Group, {
4693
- direction: "column",
4694
- grow: true,
4695
- children: /* @__PURE__ */ jsx(TextInput, {
4696
- label: "Font Size",
4697
- placeholder: "10px, 1em, 1rem, 100%...",
4847
+ const defaultValues = React.useMemo(() => {
4848
+ const {
4849
+ content = ""
4850
+ } = conf;
4851
+ return {
4852
+ content
4853
+ };
4854
+ }, [conf]);
4855
+ React.useEffect(() => {
4856
+ const configMalformed = !_.isEqual(conf, defaultValues);
4857
+ if (configMalformed) {
4858
+ setConf(defaultValues);
4859
+ }
4860
+ }, [conf, defaultValues]);
4861
+ const {
4862
+ control,
4863
+ handleSubmit,
4864
+ watch,
4865
+ getValues
4866
+ } = useForm({
4867
+ defaultValues
4868
+ });
4869
+ watch("content");
4870
+ const values = getValues();
4871
+ const changed = React.useMemo(() => {
4872
+ return !_.isEqual(values, conf);
4873
+ }, [values, conf]);
4874
+ return /* @__PURE__ */ jsx(Group, {
4875
+ direction: "column",
4876
+ mt: "md",
4877
+ spacing: "xs",
4878
+ grow: true,
4879
+ children: /* @__PURE__ */ jsxs("form", {
4880
+ onSubmit: handleSubmit(setConf),
4881
+ children: [/* @__PURE__ */ jsxs(Group, {
4882
+ position: "left",
4883
+ py: "md",
4884
+ pl: "md",
4698
4885
  sx: {
4699
- flex: 1
4886
+ borderBottom: "1px solid #eee",
4887
+ background: "#efefef"
4700
4888
  },
4701
- value: value.size,
4702
- onChange: (e) => handleChange("size", e.currentTarget.value)
4703
- })
4704
- }), /* @__PURE__ */ jsx(Group, {
4705
- position: "apart",
4706
- grow: true,
4707
- sx: {
4708
- "> *": {
4709
- flexGrow: 1,
4710
- maxWidth: "100%"
4711
- }
4712
- },
4713
- children: /* @__PURE__ */ jsx(MantineFontWeightSlider, {
4714
- label: "Font Weight",
4715
- value: value.weight,
4716
- onChange: (v) => handleChange("weight", v)
4717
- })
4718
- }), /* @__PURE__ */ jsx(Divider, {
4719
- my: "xs",
4720
- label: "Style",
4721
- labelPosition: "center"
4722
- }), /* @__PURE__ */ jsxs(Group, {
4723
- direction: "column",
4724
- grow: true,
4725
- children: [/* @__PURE__ */ jsx(Select, {
4726
- label: "Color Type",
4727
- data: [{
4728
- label: "Static Color",
4729
- value: "static"
4730
- }, {
4731
- label: "Continuous Color",
4732
- value: "continuous"
4733
- }],
4734
- value: value.color.type,
4735
- onChange: (v) => handleChange("color.type", v)
4736
- }), colorType === "static" && /* @__PURE__ */ jsx(MantineColorSelector, {
4737
- value: value.color.staticColor,
4738
- onChange: (v) => handleChange("color.staticColor", v)
4739
- }), colorType === "continuous" && /* @__PURE__ */ jsxs(Fragment, {
4740
- children: [/* @__PURE__ */ jsx(TextArrayInput, {
4741
- label: "Value Range",
4742
- value: value.color.valueRange,
4743
- onChange: (v) => handleChange("color.valueRange", v)
4744
- }), /* @__PURE__ */ jsx(ColorArrayInput, {
4745
- label: "Color Range",
4746
- value: value.color.colorRange,
4747
- onChange: (v) => handleChange("color.colorRange", v)
4889
+ children: [/* @__PURE__ */ jsx(Text, {
4890
+ children: "Content"
4891
+ }), /* @__PURE__ */ jsx(ActionIcon, {
4892
+ type: "submit",
4893
+ mr: 5,
4894
+ variant: "filled",
4895
+ color: "blue",
4896
+ disabled: !changed,
4897
+ children: /* @__PURE__ */ jsx(DeviceFloppy, {
4898
+ size: 20
4899
+ })
4748
4900
  })]
4901
+ }), /* @__PURE__ */ jsx(Controller, {
4902
+ name: "content",
4903
+ control,
4904
+ render: ({
4905
+ field
4906
+ }) => /* @__PURE__ */ jsx(RichTextEditor, __spreadValues({
4907
+ sx: {
4908
+ flex: 1
4909
+ }
4910
+ }, field))
4749
4911
  })]
4750
- })]
4912
+ })
4751
4913
  });
4752
4914
  }
4915
+ function updateSchema(legacyConf) {
4916
+ if ("variables" in legacyConf) {
4917
+ return legacyConf;
4918
+ }
4919
+ const {
4920
+ align,
4921
+ size,
4922
+ weight,
4923
+ color: color2,
4924
+ content: {
4925
+ prefix = "",
4926
+ data_field = "value",
4927
+ formatter = {
4928
+ output: "number",
4929
+ mantissa: 0
4930
+ },
4931
+ postfix = ""
4932
+ } = {}
4933
+ } = legacyConf;
4934
+ return {
4935
+ align,
4936
+ template: `${prefix} \${value} ${postfix}`,
4937
+ variables: [
4938
+ {
4939
+ name: "value",
4940
+ data_field,
4941
+ aggregation: "none",
4942
+ formatter,
4943
+ color: color2,
4944
+ weight,
4945
+ size
4946
+ }
4947
+ ]
4948
+ };
4949
+ }
4753
4950
  function VariableField({
4754
4951
  control,
4755
4952
  index: index2,
@@ -4807,21 +5004,7 @@ function VariablesField({
4807
5004
  const controlledFields = fields.map((field, index2) => {
4808
5005
  return __spreadValues(__spreadValues({}, field), watchFieldArray[index2]);
4809
5006
  });
4810
- const add = () => append({
4811
- name: randomId(),
4812
- size: "20px",
4813
- weight: "bold",
4814
- color: {
4815
- type: "static",
4816
- staticColor: "blue"
4817
- },
4818
- data_field: "",
4819
- aggregation: "none",
4820
- formatter: {
4821
- output: "number",
4822
- mantissa: 0
4823
- }
4824
- });
5007
+ const add = () => append(getANewVariable());
4825
5008
  return /* @__PURE__ */ jsxs(Group, {
4826
5009
  direction: "column",
4827
5010
  grow: true,