@devtable/dashboard 1.7.0 → 1.10.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.
@@ -29,13 +29,17 @@ var __objRest = (source, exclude) => {
29
29
  }
30
30
  return target;
31
31
  };
32
+ var __publicField = (obj, key, value) => {
33
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
34
+ return value;
35
+ };
32
36
  import React from "react";
33
37
  import _ from "lodash";
34
38
  import { WidthProvider, Responsive } from "react-grid-layout";
35
- import { Popover, Tooltip, Group, Text, ActionIcon, TextInput, Box, LoadingOverlay, Table, Select, Button, useMantineTheme, ColorSwatch, JsonInput, Anchor, Switch, Slider, Modal, AppShell, Tabs, Menu, Divider, Container, SegmentedControl, Textarea } from "@mantine/core";
39
+ import { Popover, Tooltip, Group, Text, ActionIcon, TextInput, Box, LoadingOverlay, Table, Select, Button, useMantineTheme, ColorSwatch, JsonInput, Anchor, Slider, ColorInput, Accordion, Switch, Modal, AppShell, Tabs, Menu, Divider, Container, SegmentedControl, Textarea } from "@mantine/core";
36
40
  import { useRequest } from "ahooks";
37
41
  import axios from "axios";
38
- import { InfoCircle, DeviceFloppy, Refresh, Trash, Settings, Paint, PlayerPlay, PlaylistAdd, ClipboardText, Database, Recycle, Share } from "tabler-icons-react";
42
+ import { InfoCircle, DeviceFloppy, Refresh, Trash, PlaylistAdd, Settings, Resize, Paint, PlayerPlay, ClipboardText, Database, Recycle, Share } from "tabler-icons-react";
39
43
  import RichTextEditor, { RichTextEditor as RichTextEditor$1 } from "@mantine/rte";
40
44
  import { useInputState, useElementSize, randomId } from "@mantine/hooks";
41
45
  import ReactEChartsCore from "echarts-for-react/lib/core";
@@ -50,6 +54,7 @@ import { formList, useForm as useForm$1 } from "@mantine/form";
50
54
  import { Prism } from "@mantine/prism";
51
55
  var DashboardMode = /* @__PURE__ */ ((DashboardMode2) => {
52
56
  DashboardMode2["Use"] = "use";
57
+ DashboardMode2["Layout"] = "layout";
53
58
  DashboardMode2["Edit"] = "edit";
54
59
  return DashboardMode2;
55
60
  })(DashboardMode || {});
@@ -58,7 +63,9 @@ const initialContext$3 = {
58
63
  freezeLayout: () => {
59
64
  },
60
65
  mode: DashboardMode.Edit,
61
- inEditMode: false
66
+ inEditMode: false,
67
+ inLayoutMode: false,
68
+ inUseMode: true
62
69
  };
63
70
  const LayoutStateContext = React.createContext(initialContext$3);
64
71
  const getRequest = (method) => {
@@ -707,7 +714,7 @@ function VizLineBarChart({
707
714
  y_axis_data_key,
708
715
  y_axis_data_formatter,
709
716
  name,
710
- label_position = "top"
717
+ label_position
711
718
  } = _b, rest = __objRest(_b, [
712
719
  "y_axis_data_key",
713
720
  "y_axis_data_formatter",
@@ -717,7 +724,7 @@ function VizLineBarChart({
717
724
  const ret = __spreadValues({
718
725
  data: data.map((d) => d[y_axis_data_key]),
719
726
  label: {
720
- show: true,
727
+ show: !!label_position,
721
728
  position: label_position
722
729
  },
723
730
  name
@@ -920,7 +927,7 @@ function VizTable({
920
927
  })]
921
928
  }));
922
929
  }
923
- function interpolateString(template, params = {}) {
930
+ function interpolateString$1(template, params = {}) {
924
931
  const extendedParams = __spreadProps(__spreadValues({}, params), {
925
932
  numbro
926
933
  });
@@ -951,7 +958,7 @@ function VizText({
951
958
  sx: {
952
959
  fontSize: size
953
960
  },
954
- children: interpolateString(template, data[0])
961
+ children: interpolateString$1(template, data[0])
955
962
  }), `${template}---${index2}`);
956
963
  })
957
964
  });
@@ -1110,6 +1117,420 @@ function VizPie({
1110
1117
  }
1111
1118
  });
1112
1119
  }
1120
+ var invariant = function() {
1121
+ };
1122
+ const clamp$1 = (min, max, v) => Math.min(Math.max(v, min), max);
1123
+ const progress = (from, to, value) => {
1124
+ const toFromDifference = to - from;
1125
+ return toFromDifference === 0 ? 1 : (value - from) / toFromDifference;
1126
+ };
1127
+ const mix = (from, to, progress2) => -progress2 * from + progress2 * to + from;
1128
+ const clamp = (min, max) => (v) => Math.max(Math.min(v, max), min);
1129
+ const sanitize = (v) => v % 1 ? Number(v.toFixed(5)) : v;
1130
+ const floatRegex = /(-)?([\d]*\.?[\d])+/g;
1131
+ const colorRegex = /(#[0-9a-f]{6}|#[0-9a-f]{3}|#(?:[0-9a-f]{2}){2,4}|(rgb|hsl)a?\((-?[\d\.]+%?[,\s]+){2,3}\s*\/*\s*[\d\.]+%?\))/gi;
1132
+ const singleColorRegex = /^(#[0-9a-f]{3}|#(?:[0-9a-f]{2}){2,4}|(rgb|hsl)a?\((-?[\d\.]+%?[,\s]+){2,3}\s*\/*\s*[\d\.]+%?\))$/i;
1133
+ function isString(v) {
1134
+ return typeof v === "string";
1135
+ }
1136
+ const number = {
1137
+ test: (v) => typeof v === "number",
1138
+ parse: parseFloat,
1139
+ transform: (v) => v
1140
+ };
1141
+ const alpha = Object.assign(Object.assign({}, number), { transform: clamp(0, 1) });
1142
+ Object.assign(Object.assign({}, number), { default: 1 });
1143
+ const createUnitType = (unit) => ({
1144
+ test: (v) => isString(v) && v.endsWith(unit) && v.split(" ").length === 1,
1145
+ parse: parseFloat,
1146
+ transform: (v) => `${v}${unit}`
1147
+ });
1148
+ const percent = createUnitType("%");
1149
+ Object.assign(Object.assign({}, percent), { parse: (v) => percent.parse(v) / 100, transform: (v) => percent.transform(v * 100) });
1150
+ const isColorString = (type, testProp) => (v) => {
1151
+ return Boolean(isString(v) && singleColorRegex.test(v) && v.startsWith(type) || testProp && Object.prototype.hasOwnProperty.call(v, testProp));
1152
+ };
1153
+ const splitColor = (aName, bName, cName) => (v) => {
1154
+ if (!isString(v))
1155
+ return v;
1156
+ const [a, b, c, alpha2] = v.match(floatRegex);
1157
+ return {
1158
+ [aName]: parseFloat(a),
1159
+ [bName]: parseFloat(b),
1160
+ [cName]: parseFloat(c),
1161
+ alpha: alpha2 !== void 0 ? parseFloat(alpha2) : 1
1162
+ };
1163
+ };
1164
+ const hsla = {
1165
+ test: isColorString("hsl", "hue"),
1166
+ parse: splitColor("hue", "saturation", "lightness"),
1167
+ transform: ({ hue, saturation, lightness, alpha: alpha$1 = 1 }) => {
1168
+ return "hsla(" + Math.round(hue) + ", " + percent.transform(sanitize(saturation)) + ", " + percent.transform(sanitize(lightness)) + ", " + sanitize(alpha.transform(alpha$1)) + ")";
1169
+ }
1170
+ };
1171
+ const clampRgbUnit = clamp(0, 255);
1172
+ const rgbUnit = Object.assign(Object.assign({}, number), { transform: (v) => Math.round(clampRgbUnit(v)) });
1173
+ const rgba = {
1174
+ test: isColorString("rgb", "red"),
1175
+ parse: splitColor("red", "green", "blue"),
1176
+ transform: ({ red, green, blue, alpha: alpha$1 = 1 }) => "rgba(" + rgbUnit.transform(red) + ", " + rgbUnit.transform(green) + ", " + rgbUnit.transform(blue) + ", " + sanitize(alpha.transform(alpha$1)) + ")"
1177
+ };
1178
+ function parseHex(v) {
1179
+ let r = "";
1180
+ let g = "";
1181
+ let b = "";
1182
+ let a = "";
1183
+ if (v.length > 5) {
1184
+ r = v.substr(1, 2);
1185
+ g = v.substr(3, 2);
1186
+ b = v.substr(5, 2);
1187
+ a = v.substr(7, 2);
1188
+ } else {
1189
+ r = v.substr(1, 1);
1190
+ g = v.substr(2, 1);
1191
+ b = v.substr(3, 1);
1192
+ a = v.substr(4, 1);
1193
+ r += r;
1194
+ g += g;
1195
+ b += b;
1196
+ a += a;
1197
+ }
1198
+ return {
1199
+ red: parseInt(r, 16),
1200
+ green: parseInt(g, 16),
1201
+ blue: parseInt(b, 16),
1202
+ alpha: a ? parseInt(a, 16) / 255 : 1
1203
+ };
1204
+ }
1205
+ const hex = {
1206
+ test: isColorString("#"),
1207
+ parse: parseHex,
1208
+ transform: rgba.transform
1209
+ };
1210
+ const color = {
1211
+ test: (v) => rgba.test(v) || hex.test(v) || hsla.test(v),
1212
+ parse: (v) => {
1213
+ if (rgba.test(v)) {
1214
+ return rgba.parse(v);
1215
+ } else if (hsla.test(v)) {
1216
+ return hsla.parse(v);
1217
+ } else {
1218
+ return hex.parse(v);
1219
+ }
1220
+ },
1221
+ transform: (v) => {
1222
+ return isString(v) ? v : v.hasOwnProperty("red") ? rgba.transform(v) : hsla.transform(v);
1223
+ }
1224
+ };
1225
+ const colorToken = "${c}";
1226
+ const numberToken = "${n}";
1227
+ function test(v) {
1228
+ var _a, _b, _c, _d;
1229
+ return isNaN(v) && isString(v) && ((_b = (_a = v.match(floatRegex)) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) + ((_d = (_c = v.match(colorRegex)) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0) > 0;
1230
+ }
1231
+ function analyse$1(v) {
1232
+ if (typeof v === "number")
1233
+ v = `${v}`;
1234
+ const values = [];
1235
+ let numColors = 0;
1236
+ const colors = v.match(colorRegex);
1237
+ if (colors) {
1238
+ numColors = colors.length;
1239
+ v = v.replace(colorRegex, colorToken);
1240
+ values.push(...colors.map(color.parse));
1241
+ }
1242
+ const numbers = v.match(floatRegex);
1243
+ if (numbers) {
1244
+ v = v.replace(floatRegex, numberToken);
1245
+ values.push(...numbers.map(number.parse));
1246
+ }
1247
+ return { values, numColors, tokenised: v };
1248
+ }
1249
+ function parse(v) {
1250
+ return analyse$1(v).values;
1251
+ }
1252
+ function createTransformer(v) {
1253
+ const { values, numColors, tokenised } = analyse$1(v);
1254
+ const numValues = values.length;
1255
+ return (v2) => {
1256
+ let output = tokenised;
1257
+ for (let i = 0; i < numValues; i++) {
1258
+ output = output.replace(i < numColors ? colorToken : numberToken, i < numColors ? color.transform(v2[i]) : sanitize(v2[i]));
1259
+ }
1260
+ return output;
1261
+ };
1262
+ }
1263
+ const convertNumbersToZero = (v) => typeof v === "number" ? 0 : v;
1264
+ function getAnimatableNone(v) {
1265
+ const parsed = parse(v);
1266
+ const transformer = createTransformer(v);
1267
+ return transformer(parsed.map(convertNumbersToZero));
1268
+ }
1269
+ const complex = { test, parse, createTransformer, getAnimatableNone };
1270
+ function hueToRgb(p2, q2, t) {
1271
+ if (t < 0)
1272
+ t += 1;
1273
+ if (t > 1)
1274
+ t -= 1;
1275
+ if (t < 1 / 6)
1276
+ return p2 + (q2 - p2) * 6 * t;
1277
+ if (t < 1 / 2)
1278
+ return q2;
1279
+ if (t < 2 / 3)
1280
+ return p2 + (q2 - p2) * (2 / 3 - t) * 6;
1281
+ return p2;
1282
+ }
1283
+ function hslaToRgba({ hue, saturation, lightness, alpha: alpha2 }) {
1284
+ hue /= 360;
1285
+ saturation /= 100;
1286
+ lightness /= 100;
1287
+ let red = 0;
1288
+ let green = 0;
1289
+ let blue = 0;
1290
+ if (!saturation) {
1291
+ red = green = blue = lightness;
1292
+ } else {
1293
+ const q2 = lightness < 0.5 ? lightness * (1 + saturation) : lightness + saturation - lightness * saturation;
1294
+ const p2 = 2 * lightness - q2;
1295
+ red = hueToRgb(p2, q2, hue + 1 / 3);
1296
+ green = hueToRgb(p2, q2, hue);
1297
+ blue = hueToRgb(p2, q2, hue - 1 / 3);
1298
+ }
1299
+ return {
1300
+ red: Math.round(red * 255),
1301
+ green: Math.round(green * 255),
1302
+ blue: Math.round(blue * 255),
1303
+ alpha: alpha2
1304
+ };
1305
+ }
1306
+ const mixLinearColor = (from, to, v) => {
1307
+ const fromExpo = from * from;
1308
+ const toExpo = to * to;
1309
+ return Math.sqrt(Math.max(0, v * (toExpo - fromExpo) + fromExpo));
1310
+ };
1311
+ const colorTypes = [hex, rgba, hsla];
1312
+ const getColorType = (v) => colorTypes.find((type) => type.test(v));
1313
+ const mixColor = (from, to) => {
1314
+ let fromColorType = getColorType(from);
1315
+ let toColorType = getColorType(to);
1316
+ let fromColor = fromColorType.parse(from);
1317
+ let toColor = toColorType.parse(to);
1318
+ if (fromColorType === hsla) {
1319
+ fromColor = hslaToRgba(fromColor);
1320
+ fromColorType = rgba;
1321
+ }
1322
+ if (toColorType === hsla) {
1323
+ toColor = hslaToRgba(toColor);
1324
+ toColorType = rgba;
1325
+ }
1326
+ const blended = Object.assign({}, fromColor);
1327
+ return (v) => {
1328
+ for (const key in blended) {
1329
+ if (key !== "alpha") {
1330
+ blended[key] = mixLinearColor(fromColor[key], toColor[key], v);
1331
+ }
1332
+ }
1333
+ blended.alpha = mix(fromColor.alpha, toColor.alpha, v);
1334
+ return fromColorType.transform(blended);
1335
+ };
1336
+ };
1337
+ const isNum = (v) => typeof v === "number";
1338
+ const combineFunctions = (a, b) => (v) => b(a(v));
1339
+ const pipe = (...transformers) => transformers.reduce(combineFunctions);
1340
+ function getMixer(origin, target) {
1341
+ if (isNum(origin)) {
1342
+ return (v) => mix(origin, target, v);
1343
+ } else if (color.test(origin)) {
1344
+ return mixColor(origin, target);
1345
+ } else {
1346
+ return mixComplex(origin, target);
1347
+ }
1348
+ }
1349
+ const mixArray = (from, to) => {
1350
+ const output = [...from];
1351
+ const numValues = output.length;
1352
+ const blendValue = from.map((fromThis, i) => getMixer(fromThis, to[i]));
1353
+ return (v) => {
1354
+ for (let i = 0; i < numValues; i++) {
1355
+ output[i] = blendValue[i](v);
1356
+ }
1357
+ return output;
1358
+ };
1359
+ };
1360
+ const mixObject = (origin, target) => {
1361
+ const output = Object.assign(Object.assign({}, origin), target);
1362
+ const blendValue = {};
1363
+ for (const key in output) {
1364
+ if (origin[key] !== void 0 && target[key] !== void 0) {
1365
+ blendValue[key] = getMixer(origin[key], target[key]);
1366
+ }
1367
+ }
1368
+ return (v) => {
1369
+ for (const key in blendValue) {
1370
+ output[key] = blendValue[key](v);
1371
+ }
1372
+ return output;
1373
+ };
1374
+ };
1375
+ function analyse(value) {
1376
+ const parsed = complex.parse(value);
1377
+ const numValues = parsed.length;
1378
+ let numNumbers = 0;
1379
+ let numRGB = 0;
1380
+ let numHSL = 0;
1381
+ for (let i = 0; i < numValues; i++) {
1382
+ if (numNumbers || typeof parsed[i] === "number") {
1383
+ numNumbers++;
1384
+ } else {
1385
+ if (parsed[i].hue !== void 0) {
1386
+ numHSL++;
1387
+ } else {
1388
+ numRGB++;
1389
+ }
1390
+ }
1391
+ }
1392
+ return { parsed, numNumbers, numRGB, numHSL };
1393
+ }
1394
+ const mixComplex = (origin, target) => {
1395
+ const template = complex.createTransformer(target);
1396
+ const originStats = analyse(origin);
1397
+ const targetStats = analyse(target);
1398
+ const canInterpolate = originStats.numHSL === targetStats.numHSL && originStats.numRGB === targetStats.numRGB && originStats.numNumbers >= targetStats.numNumbers;
1399
+ if (canInterpolate) {
1400
+ return pipe(mixArray(originStats.parsed, targetStats.parsed), template);
1401
+ } else {
1402
+ return (p2) => `${p2 > 0 ? target : origin}`;
1403
+ }
1404
+ };
1405
+ const mixNumber = (from, to) => (p2) => mix(from, to, p2);
1406
+ function detectMixerFactory(v) {
1407
+ if (typeof v === "number") {
1408
+ return mixNumber;
1409
+ } else if (typeof v === "string") {
1410
+ if (color.test(v)) {
1411
+ return mixColor;
1412
+ } else {
1413
+ return mixComplex;
1414
+ }
1415
+ } else if (Array.isArray(v)) {
1416
+ return mixArray;
1417
+ } else if (typeof v === "object") {
1418
+ return mixObject;
1419
+ }
1420
+ }
1421
+ function createMixers(output, ease, customMixer) {
1422
+ const mixers = [];
1423
+ const mixerFactory = customMixer || detectMixerFactory(output[0]);
1424
+ const numMixers = output.length - 1;
1425
+ for (let i = 0; i < numMixers; i++) {
1426
+ let mixer = mixerFactory(output[i], output[i + 1]);
1427
+ if (ease) {
1428
+ const easingFunction = Array.isArray(ease) ? ease[i] : ease;
1429
+ mixer = pipe(easingFunction, mixer);
1430
+ }
1431
+ mixers.push(mixer);
1432
+ }
1433
+ return mixers;
1434
+ }
1435
+ function fastInterpolate([from, to], [mixer]) {
1436
+ return (v) => mixer(progress(from, to, v));
1437
+ }
1438
+ function slowInterpolate(input, mixers) {
1439
+ const inputLength = input.length;
1440
+ const lastInputIndex = inputLength - 1;
1441
+ return (v) => {
1442
+ let mixerIndex = 0;
1443
+ let foundMixerIndex = false;
1444
+ if (v <= input[0]) {
1445
+ foundMixerIndex = true;
1446
+ } else if (v >= input[lastInputIndex]) {
1447
+ mixerIndex = lastInputIndex - 1;
1448
+ foundMixerIndex = true;
1449
+ }
1450
+ if (!foundMixerIndex) {
1451
+ let i = 1;
1452
+ for (; i < inputLength; i++) {
1453
+ if (input[i] > v || i === lastInputIndex) {
1454
+ break;
1455
+ }
1456
+ }
1457
+ mixerIndex = i - 1;
1458
+ }
1459
+ const progressInRange = progress(input[mixerIndex], input[mixerIndex + 1], v);
1460
+ return mixers[mixerIndex](progressInRange);
1461
+ };
1462
+ }
1463
+ function interpolate(input, output, { clamp: isClamp = true, ease, mixer } = {}) {
1464
+ const inputLength = input.length;
1465
+ invariant(inputLength === output.length);
1466
+ invariant(!ease || !Array.isArray(ease) || ease.length === inputLength - 1);
1467
+ if (input[0] > input[inputLength - 1]) {
1468
+ input = [].concat(input);
1469
+ output = [].concat(output);
1470
+ input.reverse();
1471
+ output.reverse();
1472
+ }
1473
+ const mixers = createMixers(output, ease, mixer);
1474
+ const interpolator = inputLength === 2 ? fastInterpolate(input, mixers) : slowInterpolate(input, mixers);
1475
+ return isClamp ? (v) => interpolator(clamp$1(input[0], input[inputLength - 1], v)) : interpolator;
1476
+ }
1477
+ class InterpolateColor {
1478
+ constructor({ valueRange, colorRange }) {
1479
+ __publicField(this, "mapper");
1480
+ this.mapper = interpolate(valueRange, colorRange);
1481
+ }
1482
+ getColor(value) {
1483
+ return this.mapper(value);
1484
+ }
1485
+ }
1486
+ function interpolateString(template, params = {}) {
1487
+ const extendedParams = __spreadProps(__spreadValues({}, params), {
1488
+ numbro
1489
+ });
1490
+ const names = Object.keys(extendedParams);
1491
+ const vals = Object.values(extendedParams);
1492
+ try {
1493
+ return new Function(...names, `return \`${template}\`;`)(...vals);
1494
+ } catch (error) {
1495
+ return error.message;
1496
+ }
1497
+ }
1498
+ function getColorByColorConf(conf, dataRow) {
1499
+ if (conf.type === "static") {
1500
+ return conf.staticColor;
1501
+ }
1502
+ if (conf.type === "continuous") {
1503
+ const mapper = new InterpolateColor(conf);
1504
+ const value = dataRow[conf.valueField];
1505
+ return mapper.getColor(value);
1506
+ }
1507
+ return "black";
1508
+ }
1509
+ function VizStats(_a) {
1510
+ var _b = _a, {
1511
+ conf: _c
1512
+ } = _b, _d = _c, {
1513
+ template,
1514
+ size,
1515
+ color: color2
1516
+ } = _d, rest = __objRest(_d, [
1517
+ "template",
1518
+ "size",
1519
+ "color"
1520
+ ]), {
1521
+ data
1522
+ } = _b;
1523
+ const finalColor = React.useMemo(() => {
1524
+ return getColorByColorConf(color2, data[0]);
1525
+ }, [color2, data]);
1526
+ return /* @__PURE__ */ jsx(Text, __spreadProps(__spreadValues({}, rest), {
1527
+ color: finalColor,
1528
+ sx: {
1529
+ fontSize: size
1530
+ },
1531
+ children: interpolateString(template, data[0])
1532
+ }));
1533
+ }
1113
1534
  function renderViz(width, height, data, viz) {
1114
1535
  const props = {
1115
1536
  width,
@@ -1126,6 +1547,8 @@ function renderViz(width, height, data, viz) {
1126
1547
  return /* @__PURE__ */ jsx(VizTable, __spreadValues({}, props));
1127
1548
  case "text":
1128
1549
  return /* @__PURE__ */ jsx(VizText, __spreadValues({}, props));
1550
+ case "stats":
1551
+ return /* @__PURE__ */ jsx(VizStats, __spreadValues({}, props));
1129
1552
  case "bar-3d":
1130
1553
  return /* @__PURE__ */ jsx(VizBar3D, __spreadValues({}, props));
1131
1554
  case "pie":
@@ -1349,8 +1772,8 @@ function MantineColorSelector({
1349
1772
  }) {
1350
1773
  const theme = useMantineTheme();
1351
1774
  const themeColors = React.useMemo(() => {
1352
- return Object.entries(theme.colors).map(([color, profile]) => ({
1353
- label: color,
1775
+ return Object.entries(theme.colors).map(([color2, profile]) => ({
1776
+ label: color2,
1354
1777
  value: profile[6]
1355
1778
  }));
1356
1779
  }, [theme]);
@@ -1400,6 +1823,9 @@ const numbroFormatExample = JSON.stringify({
1400
1823
  mantissa: 2
1401
1824
  }, null, 2);
1402
1825
  const labelPositions = [{
1826
+ label: "off",
1827
+ value: ""
1828
+ }, {
1403
1829
  label: "top",
1404
1830
  value: "top"
1405
1831
  }, {
@@ -1439,6 +1865,106 @@ const labelPositions = [{
1439
1865
  label: "insideBottomRight",
1440
1866
  value: "insideBottomRight"
1441
1867
  }];
1868
+ function SeriesItemField({
1869
+ form,
1870
+ index: index2
1871
+ }) {
1872
+ const value = form.values.series[index2];
1873
+ const {
1874
+ type
1875
+ } = value;
1876
+ return /* @__PURE__ */ jsxs(Group, {
1877
+ direction: "column",
1878
+ grow: true,
1879
+ my: 0,
1880
+ p: "md",
1881
+ pr: 40,
1882
+ sx: {
1883
+ border: "1px solid #eee",
1884
+ position: "relative"
1885
+ },
1886
+ children: [/* @__PURE__ */ jsxs(Group, {
1887
+ direction: "row",
1888
+ grow: true,
1889
+ noWrap: true,
1890
+ children: [/* @__PURE__ */ jsx(Select, __spreadValues({
1891
+ label: "Type",
1892
+ data: [{
1893
+ label: "Line",
1894
+ value: "line"
1895
+ }, {
1896
+ label: "Bar",
1897
+ value: "bar"
1898
+ }, {
1899
+ label: "Scatter",
1900
+ value: "scatter",
1901
+ disabled: true
1902
+ }]
1903
+ }, form.getListInputProps("series", index2, "type"))), /* @__PURE__ */ jsx(TextInput, __spreadValues({
1904
+ label: "Name",
1905
+ required: true,
1906
+ sx: {
1907
+ flex: 1
1908
+ }
1909
+ }, form.getListInputProps("series", index2, "name"))), /* @__PURE__ */ jsx(TextInput, __spreadValues({
1910
+ label: "Value key",
1911
+ required: true
1912
+ }, form.getListInputProps("series", index2, "y_axis_data_key")))]
1913
+ }), /* @__PURE__ */ jsxs(Group, {
1914
+ direction: "row",
1915
+ grow: true,
1916
+ noWrap: true,
1917
+ align: "top",
1918
+ children: [type === "bar" && /* @__PURE__ */ jsx(Fragment, {
1919
+ children: /* @__PURE__ */ jsx(TextInput, __spreadValues({
1920
+ label: "Stack",
1921
+ placeholder: "Stack bars by this ID"
1922
+ }, form.getListInputProps("series", index2, "stack")))
1923
+ }), /* @__PURE__ */ jsx(Select, __spreadValues({
1924
+ label: "Label Position",
1925
+ data: labelPositions
1926
+ }, form.getListInputProps("series", index2, "label_position"))), /* @__PURE__ */ jsx(JsonInput, __spreadValues({
1927
+ sx: {
1928
+ label: {
1929
+ width: "100%"
1930
+ }
1931
+ },
1932
+ label: /* @__PURE__ */ jsxs(Group, {
1933
+ position: "apart",
1934
+ children: [/* @__PURE__ */ jsx(Text, {
1935
+ children: "Value Formatter"
1936
+ }), /* @__PURE__ */ jsx(Anchor, {
1937
+ href: "https://numbrojs.com/format.html",
1938
+ target: "_blank",
1939
+ children: "Formats"
1940
+ })]
1941
+ }),
1942
+ placeholder: numbroFormatExample,
1943
+ minRows: 4,
1944
+ maxRows: 12,
1945
+ autosize: true
1946
+ }, form.getListInputProps("series", index2, "y_axis_data_formatter")))]
1947
+ }), /* @__PURE__ */ jsxs(Group, {
1948
+ direction: "column",
1949
+ grow: true,
1950
+ children: [/* @__PURE__ */ jsx(Text, {
1951
+ children: "Color"
1952
+ }), /* @__PURE__ */ jsx(MantineColorSelector, __spreadValues({}, form.getListInputProps("series", index2, "color")))]
1953
+ }), /* @__PURE__ */ jsx(ActionIcon, {
1954
+ color: "red",
1955
+ variant: "hover",
1956
+ onClick: () => form.removeListItem("series", index2),
1957
+ sx: {
1958
+ position: "absolute",
1959
+ top: 15,
1960
+ right: 5
1961
+ },
1962
+ children: /* @__PURE__ */ jsx(Trash, {
1963
+ size: 16
1964
+ })
1965
+ })]
1966
+ }, index2);
1967
+ }
1442
1968
  function withDefaults(series) {
1443
1969
  function setDefaults({
1444
1970
  type,
@@ -1448,7 +1974,7 @@ function withDefaults(series) {
1448
1974
  y_axis_data_formatter = "",
1449
1975
  label_position = "top",
1450
1976
  stack = "1",
1451
- color = "black"
1977
+ color: color2 = "black"
1452
1978
  }) {
1453
1979
  return {
1454
1980
  type,
@@ -1458,7 +1984,7 @@ function withDefaults(series) {
1458
1984
  y_axis_data_formatter,
1459
1985
  label_position,
1460
1986
  stack,
1461
- color
1987
+ color: color2
1462
1988
  };
1463
1989
  }
1464
1990
  return series.map(setDefaults);
@@ -1548,82 +2074,10 @@ function VizLineBarChartPanel({
1548
2074
  mt: "xl",
1549
2075
  mb: 0,
1550
2076
  children: "Series"
1551
- }), form.values.series.map((item, index2) => /* @__PURE__ */ jsxs(Group, {
1552
- direction: "column",
1553
- grow: true,
1554
- my: 0,
1555
- p: "md",
1556
- pr: 40,
1557
- sx: {
1558
- border: "1px solid #eee",
1559
- position: "relative"
1560
- },
1561
- children: [/* @__PURE__ */ jsxs(Group, {
1562
- direction: "row",
1563
- grow: true,
1564
- noWrap: true,
1565
- children: [/* @__PURE__ */ jsx(TextInput, __spreadValues({
1566
- label: "Name",
1567
- required: true,
1568
- sx: {
1569
- flex: 1
1570
- }
1571
- }, form.getListInputProps("series", index2, "name"))), /* @__PURE__ */ jsx(TextInput, __spreadValues({
1572
- label: "Stack",
1573
- placeholder: "Stack bars by this ID"
1574
- }, form.getListInputProps("series", index2, "stack"))), /* @__PURE__ */ jsx(TextInput, __spreadValues({
1575
- label: "Value key",
1576
- required: true
1577
- }, form.getListInputProps("series", index2, "y_axis_data_key")))]
1578
- }), /* @__PURE__ */ jsxs(Group, {
1579
- direction: "row",
1580
- grow: true,
1581
- noWrap: true,
1582
- align: "top",
1583
- children: [/* @__PURE__ */ jsx(Select, __spreadValues({
1584
- label: "Label Position",
1585
- data: labelPositions
1586
- }, form.getListInputProps("series", index2, "label_position"))), /* @__PURE__ */ jsx(JsonInput, __spreadValues({
1587
- sx: {
1588
- label: {
1589
- width: "100%"
1590
- }
1591
- },
1592
- label: /* @__PURE__ */ jsxs(Group, {
1593
- position: "apart",
1594
- children: [/* @__PURE__ */ jsx(Text, {
1595
- children: "Value Formatter"
1596
- }), /* @__PURE__ */ jsx(Anchor, {
1597
- href: "https://numbrojs.com/format.html",
1598
- target: "_blank",
1599
- children: "Formats"
1600
- })]
1601
- }),
1602
- placeholder: numbroFormatExample,
1603
- minRows: 4,
1604
- maxRows: 12,
1605
- autosize: true
1606
- }, form.getListInputProps("series", index2, "y_axis_data_formatter")))]
1607
- }), /* @__PURE__ */ jsxs(Group, {
1608
- direction: "column",
1609
- grow: true,
1610
- children: [/* @__PURE__ */ jsx(Text, {
1611
- children: "Color"
1612
- }), /* @__PURE__ */ jsx(MantineColorSelector, __spreadValues({}, form.getListInputProps("series", index2, "color")))]
1613
- }), /* @__PURE__ */ jsx(ActionIcon, {
1614
- color: "red",
1615
- variant: "hover",
1616
- onClick: () => form.removeListItem("series", index2),
1617
- sx: {
1618
- position: "absolute",
1619
- top: 15,
1620
- right: 5
1621
- },
1622
- children: /* @__PURE__ */ jsx(Trash, {
1623
- size: 16
1624
- })
1625
- })]
1626
- }, index2)), /* @__PURE__ */ jsx(Group, {
2077
+ }), form.values.series.map((_item, index2) => /* @__PURE__ */ jsx(SeriesItemField, {
2078
+ form,
2079
+ index: index2
2080
+ })), /* @__PURE__ */ jsx(Group, {
1627
2081
  position: "center",
1628
2082
  mt: "xs",
1629
2083
  children: /* @__PURE__ */ jsx(Button, {
@@ -1701,75 +2155,443 @@ function VizPiePanel({
1701
2155
  })
1702
2156
  });
1703
2157
  }
1704
- function SunburstPanel({
1705
- conf: {
1706
- label_field,
1707
- value_field
1708
- },
1709
- setConf
2158
+ const marks = [{
2159
+ label: "initial",
2160
+ value: 0
2161
+ }, {
2162
+ label: "500",
2163
+ value: 25
2164
+ }, {
2165
+ label: "700",
2166
+ value: 50
2167
+ }, {
2168
+ label: "semibold",
2169
+ value: 75
2170
+ }, {
2171
+ label: "bold",
2172
+ value: 100
2173
+ }];
2174
+ function MantineFontWeightSlider({
2175
+ label,
2176
+ value,
2177
+ onChange
1710
2178
  }) {
1711
- const form = useForm$1({
1712
- initialValues: {
1713
- label_field,
1714
- value_field
2179
+ var _a, _b;
2180
+ const [mark, setMark] = React.useState((_b = (_a = marks.find((m2) => m2.label === value)) == null ? void 0 : _a.value) != null ? _b : marks[0].value);
2181
+ React.useEffect(() => {
2182
+ const match = marks.find((s) => s.value === mark);
2183
+ if (match) {
2184
+ onChange(match.label);
1715
2185
  }
1716
- });
1717
- return /* @__PURE__ */ jsx(Group, {
2186
+ }, [mark]);
2187
+ return /* @__PURE__ */ jsxs(Group, {
1718
2188
  direction: "column",
1719
- mt: "md",
1720
- spacing: "xs",
1721
2189
  grow: true,
1722
- children: /* @__PURE__ */ jsxs("form", {
1723
- onSubmit: form.onSubmit(setConf),
1724
- children: [/* @__PURE__ */ jsxs(Group, {
1725
- position: "apart",
1726
- mb: "lg",
1727
- sx: {
1728
- position: "relative"
1729
- },
1730
- children: [/* @__PURE__ */ jsx(Text, {
1731
- children: "Sunburst Config"
1732
- }), /* @__PURE__ */ jsx(ActionIcon, {
1733
- type: "submit",
1734
- mr: 5,
1735
- variant: "filled",
1736
- color: "blue",
1737
- children: /* @__PURE__ */ jsx(DeviceFloppy, {
1738
- size: 20
1739
- })
1740
- })]
1741
- }), /* @__PURE__ */ jsxs(Group, {
1742
- direction: "column",
1743
- mt: "md",
1744
- spacing: "xs",
1745
- grow: true,
1746
- p: "md",
1747
- mb: "sm",
1748
- sx: {
1749
- border: "1px solid #eee",
1750
- borderRadius: "5px"
1751
- },
1752
- children: [/* @__PURE__ */ jsx(TextInput, __spreadValues({
1753
- label: "Label Field",
1754
- required: true,
1755
- sx: {
1756
- flex: 1
1757
- }
1758
- }, form.getInputProps("label_field"))), /* @__PURE__ */ jsx(TextInput, __spreadValues({
1759
- label: "Value Field",
1760
- placeholder: "get column value by this field",
1761
- required: true,
1762
- sx: {
1763
- flex: 1
1764
- }
1765
- }, form.getInputProps("value_field")))]
1766
- })]
1767
- })
2190
+ spacing: "xs",
2191
+ mb: "lg",
2192
+ children: [/* @__PURE__ */ jsx(Text, {
2193
+ children: label
2194
+ }), /* @__PURE__ */ jsx(Slider, {
2195
+ label: null,
2196
+ marks,
2197
+ value: mark,
2198
+ onChange: setMark,
2199
+ step: 25,
2200
+ placeholder: "Pick a font size"
2201
+ })]
1768
2202
  });
1769
2203
  }
1770
- const valueTypes = Object.values(ValueType).map((v) => ({
1771
- label: v,
1772
- value: v
2204
+ function TextArrayInput({
2205
+ label,
2206
+ value,
2207
+ onChange
2208
+ }) {
2209
+ const [values, setValues] = React.useState(Array.isArray(value) ? [...value] : []);
2210
+ const add = React.useCallback(() => {
2211
+ setValues((s) => [...s, ""]);
2212
+ }, [setValues]);
2213
+ const del = React.useCallback((index2) => {
2214
+ setValues((s) => {
2215
+ s.splice(index2, 1);
2216
+ return [...s];
2217
+ });
2218
+ }, [setValues]);
2219
+ const changed = React.useMemo(() => {
2220
+ return !_.isEqual(values, value);
2221
+ }, [values, value]);
2222
+ const submit = () => {
2223
+ onChange(values.map((s) => s.toString()));
2224
+ };
2225
+ return /* @__PURE__ */ jsxs(Fragment, {
2226
+ children: [/* @__PURE__ */ jsxs(Group, {
2227
+ position: "left",
2228
+ children: [/* @__PURE__ */ jsx(Text, {
2229
+ children: label
2230
+ }), /* @__PURE__ */ jsx(ActionIcon, {
2231
+ mr: 5,
2232
+ variant: "filled",
2233
+ color: "blue",
2234
+ disabled: !changed,
2235
+ onClick: submit,
2236
+ children: /* @__PURE__ */ jsx(DeviceFloppy, {
2237
+ size: 20
2238
+ })
2239
+ })]
2240
+ }), /* @__PURE__ */ jsxs(Group, {
2241
+ children: [values.map((v, i) => /* @__PURE__ */ jsx(TextInput, {
2242
+ value: v,
2243
+ onChange: (event) => {
2244
+ const newValue = event.currentTarget.value;
2245
+ setValues((s) => {
2246
+ s.splice(i, 1, newValue);
2247
+ return [...s];
2248
+ });
2249
+ },
2250
+ rightSection: /* @__PURE__ */ jsx(ActionIcon, {
2251
+ onClick: () => del(i),
2252
+ color: "red",
2253
+ children: /* @__PURE__ */ jsx(Trash, {
2254
+ size: 14
2255
+ })
2256
+ }),
2257
+ sx: {
2258
+ width: "45%"
2259
+ }
2260
+ })), /* @__PURE__ */ jsx(ActionIcon, {
2261
+ onClick: add,
2262
+ color: "blue",
2263
+ variant: "outline",
2264
+ children: /* @__PURE__ */ jsx(PlaylistAdd, {
2265
+ size: 20
2266
+ })
2267
+ })]
2268
+ })]
2269
+ });
2270
+ }
2271
+ function ColorArrayInput({
2272
+ label,
2273
+ value,
2274
+ onChange
2275
+ }) {
2276
+ const [values, setValues] = React.useState(Array.isArray(value) ? [...value] : []);
2277
+ const add = React.useCallback(() => {
2278
+ setValues((s) => [...s, ""]);
2279
+ }, [setValues]);
2280
+ const del = React.useCallback((index2) => {
2281
+ setValues((s) => {
2282
+ s.splice(index2, 1);
2283
+ return [...s];
2284
+ });
2285
+ }, [setValues]);
2286
+ const changed = React.useMemo(() => {
2287
+ return !_.isEqual(values, value);
2288
+ }, [values, value]);
2289
+ const submit = () => {
2290
+ onChange(values.map((s) => s.toString()));
2291
+ };
2292
+ const theme = useMantineTheme();
2293
+ const swatches = React.useMemo(() => {
2294
+ return Object.entries(theme.colors).map(([_color, profile]) => profile[6]);
2295
+ }, [theme]);
2296
+ return /* @__PURE__ */ jsxs(Fragment, {
2297
+ children: [/* @__PURE__ */ jsxs(Group, {
2298
+ position: "left",
2299
+ children: [/* @__PURE__ */ jsx(Text, {
2300
+ children: label
2301
+ }), /* @__PURE__ */ jsx(ActionIcon, {
2302
+ mr: 5,
2303
+ variant: "filled",
2304
+ color: "blue",
2305
+ disabled: !changed,
2306
+ onClick: submit,
2307
+ children: /* @__PURE__ */ jsx(DeviceFloppy, {
2308
+ size: 20
2309
+ })
2310
+ })]
2311
+ }), /* @__PURE__ */ jsxs(Group, {
2312
+ children: [values.map((v, i) => /* @__PURE__ */ jsx(ColorInput, {
2313
+ value: v,
2314
+ onChange: (color2) => {
2315
+ setValues((s) => {
2316
+ s.splice(i, 1, color2);
2317
+ return [...s];
2318
+ });
2319
+ },
2320
+ swatches,
2321
+ rightSection: /* @__PURE__ */ jsx(ActionIcon, {
2322
+ onClick: () => del(i),
2323
+ color: "red",
2324
+ children: /* @__PURE__ */ jsx(Trash, {
2325
+ size: 14
2326
+ })
2327
+ }),
2328
+ sx: {
2329
+ width: "45%"
2330
+ }
2331
+ })), /* @__PURE__ */ jsx(ActionIcon, {
2332
+ onClick: add,
2333
+ color: "blue",
2334
+ variant: "outline",
2335
+ children: /* @__PURE__ */ jsx(PlaylistAdd, {
2336
+ size: 20
2337
+ })
2338
+ })]
2339
+ })]
2340
+ });
2341
+ }
2342
+ function VizStatsPanel({
2343
+ conf,
2344
+ setConf
2345
+ }) {
2346
+ const defaultValues = _.merge({}, {
2347
+ align: "center",
2348
+ size: "100px",
2349
+ template: "",
2350
+ weight: "bold",
2351
+ color: {
2352
+ type: "static",
2353
+ staticColor: "red"
2354
+ }
2355
+ }, conf);
2356
+ const {
2357
+ control,
2358
+ handleSubmit,
2359
+ watch,
2360
+ formState: {
2361
+ isDirty
2362
+ }
2363
+ } = useForm({
2364
+ defaultValues
2365
+ });
2366
+ const colorType = watch("color.type");
2367
+ watch("color.valueField");
2368
+ return /* @__PURE__ */ jsx(Group, {
2369
+ direction: "column",
2370
+ mt: "md",
2371
+ spacing: "xs",
2372
+ grow: true,
2373
+ noWrap: true,
2374
+ children: /* @__PURE__ */ jsxs("form", {
2375
+ onSubmit: handleSubmit(setConf),
2376
+ children: [/* @__PURE__ */ jsxs(Group, {
2377
+ position: "left",
2378
+ py: "md",
2379
+ pl: "md",
2380
+ sx: {
2381
+ borderBottom: "1px solid #eee",
2382
+ background: "#efefef"
2383
+ },
2384
+ children: [/* @__PURE__ */ jsx(Text, {
2385
+ weight: 500,
2386
+ children: "Stats Configurations"
2387
+ }), /* @__PURE__ */ jsx(ActionIcon, {
2388
+ type: "submit",
2389
+ mr: 5,
2390
+ variant: "filled",
2391
+ color: "blue",
2392
+ disabled: !isDirty,
2393
+ children: /* @__PURE__ */ jsx(DeviceFloppy, {
2394
+ size: 20
2395
+ })
2396
+ })]
2397
+ }), /* @__PURE__ */ jsxs(Accordion, {
2398
+ offsetIcon: false,
2399
+ multiple: true,
2400
+ initialState: {
2401
+ 0: true,
2402
+ 2: true
2403
+ },
2404
+ children: [/* @__PURE__ */ jsx(Accordion.Item, {
2405
+ label: "Content",
2406
+ children: /* @__PURE__ */ jsx(Group, {
2407
+ direction: "column",
2408
+ grow: true,
2409
+ children: /* @__PURE__ */ jsx(Controller, {
2410
+ name: "template",
2411
+ control,
2412
+ render: ({
2413
+ field
2414
+ }) => /* @__PURE__ */ jsx(TextInput, __spreadValues({
2415
+ placeholder: "Time: ${new Date().toISOString()}",
2416
+ label: "Content Template",
2417
+ required: true,
2418
+ sx: {
2419
+ flex: 1
2420
+ }
2421
+ }, field))
2422
+ })
2423
+ })
2424
+ }), /* @__PURE__ */ jsxs(Accordion.Item, {
2425
+ label: "Font",
2426
+ children: [/* @__PURE__ */ jsx(Group, {
2427
+ direction: "column",
2428
+ grow: true,
2429
+ children: /* @__PURE__ */ jsx(Controller, {
2430
+ name: "size",
2431
+ control,
2432
+ render: ({
2433
+ field
2434
+ }) => /* @__PURE__ */ jsx(TextInput, __spreadValues({
2435
+ label: "Font Size",
2436
+ placeholder: "10px, 1em, 1rem, 100%...",
2437
+ sx: {
2438
+ flex: 1
2439
+ }
2440
+ }, field))
2441
+ })
2442
+ }), /* @__PURE__ */ jsx(Group, {
2443
+ position: "apart",
2444
+ grow: true,
2445
+ sx: {
2446
+ "> *": {
2447
+ flexGrow: 1,
2448
+ maxWidth: "100%"
2449
+ }
2450
+ },
2451
+ children: /* @__PURE__ */ jsx(Controller, {
2452
+ name: "weight",
2453
+ control,
2454
+ render: ({
2455
+ field
2456
+ }) => /* @__PURE__ */ jsx(MantineFontWeightSlider, __spreadValues({
2457
+ label: "Font Weight"
2458
+ }, field))
2459
+ })
2460
+ })]
2461
+ }), /* @__PURE__ */ jsx(Accordion.Item, {
2462
+ label: "Color",
2463
+ children: /* @__PURE__ */ jsxs(Group, {
2464
+ direction: "column",
2465
+ grow: true,
2466
+ children: [/* @__PURE__ */ jsx(Controller, {
2467
+ name: "color.type",
2468
+ control,
2469
+ render: ({
2470
+ field
2471
+ }) => /* @__PURE__ */ jsx(Select, __spreadValues({
2472
+ label: "Color Type",
2473
+ data: [{
2474
+ label: "Static Color",
2475
+ value: "static"
2476
+ }, {
2477
+ label: "Continuous Color",
2478
+ value: "continuous"
2479
+ }]
2480
+ }, field))
2481
+ }), colorType === "static" && /* @__PURE__ */ jsx(Controller, {
2482
+ name: "color.staticColor",
2483
+ control,
2484
+ render: ({
2485
+ field
2486
+ }) => /* @__PURE__ */ jsx(MantineColorSelector, __spreadValues({}, field))
2487
+ }), colorType === "continuous" && /* @__PURE__ */ jsxs(Fragment, {
2488
+ children: [/* @__PURE__ */ jsx(Controller, {
2489
+ name: "color.valueField",
2490
+ control,
2491
+ defaultValue: "",
2492
+ render: ({
2493
+ field
2494
+ }) => /* @__PURE__ */ jsx(TextInput, __spreadValues({
2495
+ placeholder: "Calculate color with this field",
2496
+ label: "Value Field",
2497
+ required: true,
2498
+ sx: {
2499
+ flex: 1
2500
+ }
2501
+ }, field))
2502
+ }), /* @__PURE__ */ jsx(Controller, {
2503
+ name: "color.valueRange",
2504
+ control,
2505
+ render: ({
2506
+ field
2507
+ }) => /* @__PURE__ */ jsx(TextArrayInput, __spreadValues({
2508
+ label: "Value Range"
2509
+ }, field))
2510
+ }), /* @__PURE__ */ jsx(Controller, {
2511
+ name: "color.colorRange",
2512
+ control,
2513
+ render: ({
2514
+ field
2515
+ }) => /* @__PURE__ */ jsx(ColorArrayInput, __spreadValues({
2516
+ label: "Color Range"
2517
+ }, field))
2518
+ })]
2519
+ })]
2520
+ })
2521
+ })]
2522
+ })]
2523
+ })
2524
+ });
2525
+ }
2526
+ function SunburstPanel({
2527
+ conf: {
2528
+ label_field,
2529
+ value_field
2530
+ },
2531
+ setConf
2532
+ }) {
2533
+ const form = useForm$1({
2534
+ initialValues: {
2535
+ label_field,
2536
+ value_field
2537
+ }
2538
+ });
2539
+ return /* @__PURE__ */ jsx(Group, {
2540
+ direction: "column",
2541
+ mt: "md",
2542
+ spacing: "xs",
2543
+ grow: true,
2544
+ children: /* @__PURE__ */ jsxs("form", {
2545
+ onSubmit: form.onSubmit(setConf),
2546
+ children: [/* @__PURE__ */ jsxs(Group, {
2547
+ position: "apart",
2548
+ mb: "lg",
2549
+ sx: {
2550
+ position: "relative"
2551
+ },
2552
+ children: [/* @__PURE__ */ jsx(Text, {
2553
+ children: "Sunburst Config"
2554
+ }), /* @__PURE__ */ jsx(ActionIcon, {
2555
+ type: "submit",
2556
+ mr: 5,
2557
+ variant: "filled",
2558
+ color: "blue",
2559
+ children: /* @__PURE__ */ jsx(DeviceFloppy, {
2560
+ size: 20
2561
+ })
2562
+ })]
2563
+ }), /* @__PURE__ */ jsxs(Group, {
2564
+ direction: "column",
2565
+ mt: "md",
2566
+ spacing: "xs",
2567
+ grow: true,
2568
+ p: "md",
2569
+ mb: "sm",
2570
+ sx: {
2571
+ border: "1px solid #eee",
2572
+ borderRadius: "5px"
2573
+ },
2574
+ children: [/* @__PURE__ */ jsx(TextInput, __spreadValues({
2575
+ label: "Label Field",
2576
+ required: true,
2577
+ sx: {
2578
+ flex: 1
2579
+ }
2580
+ }, form.getInputProps("label_field"))), /* @__PURE__ */ jsx(TextInput, __spreadValues({
2581
+ label: "Value Field",
2582
+ placeholder: "get column value by this field",
2583
+ required: true,
2584
+ sx: {
2585
+ flex: 1
2586
+ }
2587
+ }, form.getInputProps("value_field")))]
2588
+ })]
2589
+ })
2590
+ });
2591
+ }
2592
+ const valueTypes = Object.values(ValueType).map((v) => ({
2593
+ label: v,
2594
+ value: v
1773
2595
  }));
1774
2596
  function ValueTypeSelector({
1775
2597
  label,
@@ -1785,16 +2607,16 @@ function ValueTypeSelector({
1785
2607
  sx
1786
2608
  });
1787
2609
  }
1788
- function VizTablePanel(_a) {
1789
- var _b = _a, {
1790
- conf: _c
1791
- } = _b, _d = _c, {
2610
+ function VizTablePanel(_e) {
2611
+ var _f = _e, {
2612
+ conf: _g
2613
+ } = _f, _h = _g, {
1792
2614
  columns
1793
- } = _d, restConf = __objRest(_d, [
2615
+ } = _h, restConf = __objRest(_h, [
1794
2616
  "columns"
1795
2617
  ]), {
1796
2618
  setConf
1797
- } = _b;
2619
+ } = _f;
1798
2620
  const form = useForm$1({
1799
2621
  initialValues: __spreadValues({
1800
2622
  id_field: "id",
@@ -2006,52 +2828,6 @@ function VizTablePanel(_a) {
2006
2828
  })
2007
2829
  });
2008
2830
  }
2009
- const marks = [{
2010
- label: "initial",
2011
- value: 0
2012
- }, {
2013
- label: "500",
2014
- value: 25
2015
- }, {
2016
- label: "700",
2017
- value: 50
2018
- }, {
2019
- label: "semibold",
2020
- value: 75
2021
- }, {
2022
- label: "bold",
2023
- value: 100
2024
- }];
2025
- function MantineFontWeightSlider({
2026
- label,
2027
- value,
2028
- onChange
2029
- }) {
2030
- var _a, _b;
2031
- const [mark, setMark] = React.useState((_b = (_a = marks.find((m2) => m2.label === value)) == null ? void 0 : _a.value) != null ? _b : marks[0].value);
2032
- React.useEffect(() => {
2033
- const match = marks.find((s) => s.value === mark);
2034
- if (match) {
2035
- onChange(match.label);
2036
- }
2037
- }, [mark]);
2038
- return /* @__PURE__ */ jsxs(Group, {
2039
- direction: "column",
2040
- grow: true,
2041
- spacing: "xs",
2042
- mb: "lg",
2043
- children: [/* @__PURE__ */ jsx(Text, {
2044
- children: label
2045
- }), /* @__PURE__ */ jsx(Slider, {
2046
- label: null,
2047
- marks,
2048
- value: mark,
2049
- onChange: setMark,
2050
- step: 25,
2051
- placeholder: "Pick a font size"
2052
- })]
2053
- });
2054
- }
2055
2831
  const sampleParagraphs = [{
2056
2832
  align: "center",
2057
2833
  size: "xl",
@@ -2191,6 +2967,10 @@ const types = [{
2191
2967
  value: "text",
2192
2968
  label: "Text",
2193
2969
  Panel: VizTextPanel
2970
+ }, {
2971
+ value: "stats",
2972
+ label: "Stats",
2973
+ Panel: VizStatsPanel
2194
2974
  }, {
2195
2975
  value: "table",
2196
2976
  label: "Table",
@@ -2579,10 +3359,15 @@ function ModeToggler({
2579
3359
  size: 20
2580
3360
  }), "Use"),
2581
3361
  value: DashboardMode.Use
3362
+ }, {
3363
+ label: renderLabel(/* @__PURE__ */ jsx(Resize, {
3364
+ size: 20
3365
+ }), "Layout"),
3366
+ value: DashboardMode.Layout
2582
3367
  }, {
2583
3368
  label: renderLabel(/* @__PURE__ */ jsx(Paint, {
2584
3369
  size: 20
2585
- }), "Edit"),
3370
+ }), "Content"),
2586
3371
  value: DashboardMode.Edit
2587
3372
  }]
2588
3373
  });
@@ -2791,7 +3576,8 @@ function DataSourceForm({
2791
3576
  });
2792
3577
  }
2793
3578
  function DataSourceEditor({
2794
- id
3579
+ id,
3580
+ setID
2795
3581
  }) {
2796
3582
  const {
2797
3583
  dataSources,
@@ -2811,7 +3597,8 @@ function DataSourceEditor({
2811
3597
  prevs.splice(index22, 1, value);
2812
3598
  return [...prevs];
2813
3599
  });
2814
- }, [id, dataSources, setDataSources]);
3600
+ setID(value.id);
3601
+ }, [id, dataSources, setDataSources, setID]);
2815
3602
  if (!id) {
2816
3603
  return null;
2817
3604
  }
@@ -2943,7 +3730,8 @@ function EditDataSourcesModal({
2943
3730
  setID
2944
3731
  }),
2945
3732
  children: [/* @__PURE__ */ jsx(DataSourceEditor, {
2946
- id
3733
+ id,
3734
+ setID
2947
3735
  }), /* @__PURE__ */ jsx(DataPreview, {
2948
3736
  id
2949
3737
  })]
@@ -3036,46 +3824,48 @@ WHERE \${author_time_condition}`;
3036
3824
  }) => {
3037
3825
  setSQLSnippets(snippets);
3038
3826
  };
3039
- return /* @__PURE__ */ jsxs(Group, {
3827
+ return /* @__PURE__ */ jsx(Group, {
3040
3828
  direction: "column",
3041
3829
  grow: true,
3042
3830
  sx: {
3043
3831
  border: "1px solid #eee"
3044
3832
  },
3045
- children: [/* @__PURE__ */ jsxs(Group, {
3046
- position: "left",
3047
- pl: "md",
3048
- py: "md",
3049
- sx: {
3050
- borderBottom: "1px solid #eee",
3051
- background: "#efefef",
3052
- flexGrow: 0
3053
- },
3054
- children: [/* @__PURE__ */ jsx(Text, {
3055
- weight: 500,
3056
- children: "SQL Snippets"
3057
- }), /* @__PURE__ */ jsx(ActionIcon, {
3058
- type: "submit",
3059
- mr: 5,
3060
- variant: "filled",
3061
- color: "blue",
3062
- disabled: !changed,
3063
- children: /* @__PURE__ */ jsx(DeviceFloppy, {
3064
- size: 20
3065
- })
3066
- })]
3067
- }), /* @__PURE__ */ jsxs(Group, {
3068
- px: "md",
3069
- pb: "md",
3070
- children: [/* @__PURE__ */ jsx(Prism, {
3071
- language: "sql",
3833
+ children: /* @__PURE__ */ jsxs("form", {
3834
+ onSubmit: form.onSubmit(submit),
3835
+ children: [/* @__PURE__ */ jsxs(Group, {
3836
+ position: "left",
3837
+ pl: "md",
3838
+ py: "md",
3072
3839
  sx: {
3073
- width: "100%"
3840
+ borderBottom: "1px solid #eee",
3841
+ background: "#efefef",
3842
+ flexGrow: 0
3074
3843
  },
3075
- noCopy: true,
3076
- trim: false,
3077
- colorScheme: "dark",
3078
- children: `-- You may refer context data *by name*
3844
+ children: [/* @__PURE__ */ jsx(Text, {
3845
+ weight: 500,
3846
+ children: "SQL Snippets"
3847
+ }), /* @__PURE__ */ jsx(ActionIcon, {
3848
+ type: "submit",
3849
+ mr: 5,
3850
+ variant: "filled",
3851
+ color: "blue",
3852
+ disabled: !changed,
3853
+ children: /* @__PURE__ */ jsx(DeviceFloppy, {
3854
+ size: 20
3855
+ })
3856
+ })]
3857
+ }), /* @__PURE__ */ jsxs(Group, {
3858
+ px: "md",
3859
+ pb: "md",
3860
+ children: [/* @__PURE__ */ jsx(Prism, {
3861
+ language: "sql",
3862
+ sx: {
3863
+ width: "100%"
3864
+ },
3865
+ noCopy: true,
3866
+ trim: false,
3867
+ colorScheme: "dark",
3868
+ children: `-- You may refer context data *by name*
3079
3869
  -- in SQL or VizConfig.
3080
3870
 
3081
3871
  ${sampleSQL}
@@ -3083,15 +3873,13 @@ ${sampleSQL}
3083
3873
  -- where author_time_condition is:
3084
3874
  author_time BETWEEN '\${timeRange?.[0].toISOString()}' AND '\${timeRange?.[1].toISOString()}'
3085
3875
  `
3086
- }), /* @__PURE__ */ jsx(Group, {
3087
- direction: "column",
3088
- sx: {
3089
- width: "100%",
3090
- position: "relative"
3091
- },
3092
- grow: true,
3093
- children: /* @__PURE__ */ jsxs("form", {
3094
- onSubmit: form.onSubmit(submit),
3876
+ }), /* @__PURE__ */ jsxs(Group, {
3877
+ direction: "column",
3878
+ sx: {
3879
+ width: "100%",
3880
+ position: "relative"
3881
+ },
3882
+ grow: true,
3095
3883
  children: [form.values.snippets.map((_item, index2) => /* @__PURE__ */ jsxs(Group, {
3096
3884
  direction: "column",
3097
3885
  grow: true,
@@ -3136,9 +3924,9 @@ author_time BETWEEN '\${timeRange?.[0].toISOString()}' AND '\${timeRange?.[1].to
3136
3924
  children: "Add a snippet"
3137
3925
  })
3138
3926
  })]
3139
- })
3927
+ })]
3140
3928
  })]
3141
- })]
3929
+ })
3142
3930
  });
3143
3931
  }
3144
3932
  function EditSQLSnippetsModal({
@@ -3194,13 +3982,17 @@ function DashboardActions({
3194
3982
  addPanel,
3195
3983
  saveChanges
3196
3984
  }) {
3985
+ const {
3986
+ inLayoutMode,
3987
+ inEditMode,
3988
+ inUseMode
3989
+ } = React.useContext(LayoutStateContext);
3197
3990
  const [dataSourcesOpened, setDataSourcesOpened] = React.useState(false);
3198
3991
  const openDataSources = () => setDataSourcesOpened(true);
3199
3992
  const closeDataSources = () => setDataSourcesOpened(false);
3200
3993
  const [sqlSnippetsOpened, setSQLSnippetsOpened] = React.useState(false);
3201
3994
  const openSQLSnippets = () => setSQLSnippetsOpened(true);
3202
3995
  const closeSQLSnippets = () => setSQLSnippetsOpened(false);
3203
- const inEditMode = mode === DashboardMode.Edit;
3204
3996
  return /* @__PURE__ */ jsxs(Group, {
3205
3997
  position: "apart",
3206
3998
  pt: "sm",
@@ -3211,59 +4003,57 @@ function DashboardActions({
3211
4003
  mode,
3212
4004
  setMode
3213
4005
  })
3214
- }), inEditMode && /* @__PURE__ */ jsxs(Fragment, {
3215
- children: [/* @__PURE__ */ jsxs(Group, {
3216
- position: "right",
3217
- children: [/* @__PURE__ */ jsx(Button, {
3218
- variant: "default",
3219
- size: "sm",
3220
- onClick: addPanel,
3221
- leftIcon: /* @__PURE__ */ jsx(PlaylistAdd, {
3222
- size: 20
3223
- }),
3224
- children: "Add a Panel"
3225
- }), /* @__PURE__ */ jsx(Button, {
3226
- variant: "default",
3227
- size: "sm",
3228
- onClick: openSQLSnippets,
3229
- leftIcon: /* @__PURE__ */ jsx(ClipboardText, {
3230
- size: 20
3231
- }),
3232
- children: "SQL Snippets"
3233
- }), /* @__PURE__ */ jsx(Button, {
3234
- variant: "default",
3235
- size: "sm",
3236
- onClick: openDataSources,
3237
- leftIcon: /* @__PURE__ */ jsx(Database, {
3238
- size: 20
3239
- }),
3240
- children: "Data Sources"
3241
- }), /* @__PURE__ */ jsx(Button, {
3242
- variant: "default",
3243
- size: "sm",
3244
- onClick: saveChanges,
3245
- disabled: !hasChanges,
3246
- leftIcon: /* @__PURE__ */ jsx(DeviceFloppy, {
3247
- size: 20
3248
- }),
3249
- children: "Save Changes"
3250
- }), /* @__PURE__ */ jsx(Button, {
3251
- color: "red",
3252
- size: "sm",
3253
- disabled: !hasChanges,
3254
- leftIcon: /* @__PURE__ */ jsx(Recycle, {
3255
- size: 20
3256
- }),
3257
- children: "Revert Changes"
3258
- })]
3259
- }), /* @__PURE__ */ jsx(EditDataSourcesModal, {
3260
- opened: dataSourcesOpened,
3261
- close: closeDataSources
3262
- }), /* @__PURE__ */ jsx(EditSQLSnippetsModal, {
3263
- opened: sqlSnippetsOpened,
3264
- close: closeSQLSnippets
4006
+ }), /* @__PURE__ */ jsxs(Group, {
4007
+ position: "right",
4008
+ children: [inLayoutMode && /* @__PURE__ */ jsx(Button, {
4009
+ variant: "default",
4010
+ size: "sm",
4011
+ onClick: addPanel,
4012
+ leftIcon: /* @__PURE__ */ jsx(PlaylistAdd, {
4013
+ size: 20
4014
+ }),
4015
+ children: "Add a Panel"
4016
+ }), inEditMode && /* @__PURE__ */ jsx(Button, {
4017
+ variant: "default",
4018
+ size: "sm",
4019
+ onClick: openSQLSnippets,
4020
+ leftIcon: /* @__PURE__ */ jsx(ClipboardText, {
4021
+ size: 20
4022
+ }),
4023
+ children: "SQL Snippets"
4024
+ }), inEditMode && /* @__PURE__ */ jsx(Button, {
4025
+ variant: "default",
4026
+ size: "sm",
4027
+ onClick: openDataSources,
4028
+ leftIcon: /* @__PURE__ */ jsx(Database, {
4029
+ size: 20
4030
+ }),
4031
+ children: "Data Sources"
4032
+ }), !inUseMode && /* @__PURE__ */ jsx(Button, {
4033
+ variant: "default",
4034
+ size: "sm",
4035
+ onClick: saveChanges,
4036
+ disabled: !hasChanges,
4037
+ leftIcon: /* @__PURE__ */ jsx(DeviceFloppy, {
4038
+ size: 20
4039
+ }),
4040
+ children: "Save Changes"
4041
+ }), !inUseMode && /* @__PURE__ */ jsx(Button, {
4042
+ color: "red",
4043
+ size: "sm",
4044
+ disabled: !hasChanges,
4045
+ leftIcon: /* @__PURE__ */ jsx(Recycle, {
4046
+ size: 20
4047
+ }),
4048
+ children: "Revert Changes"
3265
4049
  })]
3266
- }), !inEditMode && /* @__PURE__ */ jsx(Button, {
4050
+ }), /* @__PURE__ */ jsx(EditDataSourcesModal, {
4051
+ opened: dataSourcesOpened,
4052
+ close: closeDataSources
4053
+ }), /* @__PURE__ */ jsx(EditSQLSnippetsModal, {
4054
+ opened: sqlSnippetsOpened,
4055
+ close: closeSQLSnippets
4056
+ }), inUseMode && /* @__PURE__ */ jsx(Button, {
3267
4057
  variant: "default",
3268
4058
  size: "sm",
3269
4059
  disabled: true,
@@ -3337,6 +4127,8 @@ function Dashboard({
3337
4127
  });
3338
4128
  };
3339
4129
  const inEditMode = mode === DashboardMode.Edit;
4130
+ const inLayoutMode = mode === DashboardMode.Layout;
4131
+ const inUseMode = mode === DashboardMode.Use;
3340
4132
  const definitions = React.useMemo(() => ({
3341
4133
  sqlSnippets,
3342
4134
  setSQLSnippets,
@@ -3354,7 +4146,9 @@ function Dashboard({
3354
4146
  layoutFrozen,
3355
4147
  freezeLayout,
3356
4148
  mode,
3357
- inEditMode
4149
+ inEditMode,
4150
+ inLayoutMode,
4151
+ inUseMode
3358
4152
  },
3359
4153
  children: [/* @__PURE__ */ jsx(DashboardActions, {
3360
4154
  mode,
@@ -3365,8 +4159,8 @@ function Dashboard({
3365
4159
  }), /* @__PURE__ */ jsx(DashboardLayout, {
3366
4160
  panels,
3367
4161
  setPanels,
3368
- isDraggable: inEditMode && !layoutFrozen,
3369
- isResizable: inEditMode && !layoutFrozen,
4162
+ isDraggable: inLayoutMode,
4163
+ isResizable: inLayoutMode,
3370
4164
  onRemoveItem: removePanelByID,
3371
4165
  setLocalCols,
3372
4166
  setBreakpoint
@@ -3433,7 +4227,9 @@ function ReadOnlyDashboard({
3433
4227
  freezeLayout: () => {
3434
4228
  },
3435
4229
  mode: DashboardMode.Use,
3436
- inEditMode: false
4230
+ inEditMode: false,
4231
+ inLayoutMode: false,
4232
+ inUseMode: true
3437
4233
  },
3438
4234
  children: /* @__PURE__ */ jsx(ReadOnlyDashboardLayout, {
3439
4235
  panels: dashboard.panels