@devtable/dashboard 1.8.0 → 1.9.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, Resize, 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";
@@ -923,7 +927,7 @@ function VizTable({
923
927
  })]
924
928
  }));
925
929
  }
926
- function interpolateString(template, params = {}) {
930
+ function interpolateString$1(template, params = {}) {
927
931
  const extendedParams = __spreadProps(__spreadValues({}, params), {
928
932
  numbro
929
933
  });
@@ -954,7 +958,7 @@ function VizText({
954
958
  sx: {
955
959
  fontSize: size
956
960
  },
957
- children: interpolateString(template, data[0])
961
+ children: interpolateString$1(template, data[0])
958
962
  }), `${template}---${index2}`);
959
963
  })
960
964
  });
@@ -1113,6 +1117,420 @@ function VizPie({
1113
1117
  }
1114
1118
  });
1115
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
+ }
1116
1534
  function renderViz(width, height, data, viz) {
1117
1535
  const props = {
1118
1536
  width,
@@ -1129,6 +1547,8 @@ function renderViz(width, height, data, viz) {
1129
1547
  return /* @__PURE__ */ jsx(VizTable, __spreadValues({}, props));
1130
1548
  case "text":
1131
1549
  return /* @__PURE__ */ jsx(VizText, __spreadValues({}, props));
1550
+ case "stats":
1551
+ return /* @__PURE__ */ jsx(VizStats, __spreadValues({}, props));
1132
1552
  case "bar-3d":
1133
1553
  return /* @__PURE__ */ jsx(VizBar3D, __spreadValues({}, props));
1134
1554
  case "pie":
@@ -1352,8 +1772,8 @@ function MantineColorSelector({
1352
1772
  }) {
1353
1773
  const theme = useMantineTheme();
1354
1774
  const themeColors = React.useMemo(() => {
1355
- return Object.entries(theme.colors).map(([color, profile]) => ({
1356
- label: color,
1775
+ return Object.entries(theme.colors).map(([color2, profile]) => ({
1776
+ label: color2,
1357
1777
  value: profile[6]
1358
1778
  }));
1359
1779
  }, [theme]);
@@ -1451,7 +1871,7 @@ function withDefaults(series) {
1451
1871
  y_axis_data_formatter = "",
1452
1872
  label_position = "top",
1453
1873
  stack = "1",
1454
- color = "black"
1874
+ color: color2 = "black"
1455
1875
  }) {
1456
1876
  return {
1457
1877
  type,
@@ -1461,7 +1881,7 @@ function withDefaults(series) {
1461
1881
  y_axis_data_formatter,
1462
1882
  label_position,
1463
1883
  stack,
1464
- color
1884
+ color: color2
1465
1885
  };
1466
1886
  }
1467
1887
  return series.map(setDefaults);
@@ -1704,6 +2124,374 @@ function VizPiePanel({
1704
2124
  })
1705
2125
  });
1706
2126
  }
2127
+ const marks = [{
2128
+ label: "initial",
2129
+ value: 0
2130
+ }, {
2131
+ label: "500",
2132
+ value: 25
2133
+ }, {
2134
+ label: "700",
2135
+ value: 50
2136
+ }, {
2137
+ label: "semibold",
2138
+ value: 75
2139
+ }, {
2140
+ label: "bold",
2141
+ value: 100
2142
+ }];
2143
+ function MantineFontWeightSlider({
2144
+ label,
2145
+ value,
2146
+ onChange
2147
+ }) {
2148
+ var _a, _b;
2149
+ const [mark, setMark] = React.useState((_b = (_a = marks.find((m2) => m2.label === value)) == null ? void 0 : _a.value) != null ? _b : marks[0].value);
2150
+ React.useEffect(() => {
2151
+ const match = marks.find((s) => s.value === mark);
2152
+ if (match) {
2153
+ onChange(match.label);
2154
+ }
2155
+ }, [mark]);
2156
+ return /* @__PURE__ */ jsxs(Group, {
2157
+ direction: "column",
2158
+ grow: true,
2159
+ spacing: "xs",
2160
+ mb: "lg",
2161
+ children: [/* @__PURE__ */ jsx(Text, {
2162
+ children: label
2163
+ }), /* @__PURE__ */ jsx(Slider, {
2164
+ label: null,
2165
+ marks,
2166
+ value: mark,
2167
+ onChange: setMark,
2168
+ step: 25,
2169
+ placeholder: "Pick a font size"
2170
+ })]
2171
+ });
2172
+ }
2173
+ function TextArrayInput({
2174
+ label,
2175
+ value,
2176
+ onChange
2177
+ }) {
2178
+ const [values, setValues] = React.useState(Array.isArray(value) ? [...value] : []);
2179
+ const add = React.useCallback(() => {
2180
+ setValues((s) => [...s, ""]);
2181
+ }, [setValues]);
2182
+ const del = React.useCallback((index2) => {
2183
+ setValues((s) => {
2184
+ s.splice(index2, 1);
2185
+ return [...s];
2186
+ });
2187
+ }, [setValues]);
2188
+ const changed = React.useMemo(() => {
2189
+ return !_.isEqual(values, value);
2190
+ }, [values, value]);
2191
+ const submit = () => {
2192
+ onChange(values.map((s) => s.toString()));
2193
+ };
2194
+ return /* @__PURE__ */ jsxs(Fragment, {
2195
+ children: [/* @__PURE__ */ jsxs(Group, {
2196
+ position: "left",
2197
+ children: [/* @__PURE__ */ jsx(Text, {
2198
+ children: label
2199
+ }), /* @__PURE__ */ jsx(ActionIcon, {
2200
+ mr: 5,
2201
+ variant: "filled",
2202
+ color: "blue",
2203
+ disabled: !changed,
2204
+ onClick: submit,
2205
+ children: /* @__PURE__ */ jsx(DeviceFloppy, {
2206
+ size: 20
2207
+ })
2208
+ })]
2209
+ }), /* @__PURE__ */ jsxs(Group, {
2210
+ children: [values.map((v, i) => /* @__PURE__ */ jsx(TextInput, {
2211
+ value: v,
2212
+ onChange: (event) => {
2213
+ const newValue = event.currentTarget.value;
2214
+ setValues((s) => {
2215
+ s.splice(i, 1, newValue);
2216
+ return [...s];
2217
+ });
2218
+ },
2219
+ rightSection: /* @__PURE__ */ jsx(ActionIcon, {
2220
+ onClick: () => del(i),
2221
+ color: "red",
2222
+ children: /* @__PURE__ */ jsx(Trash, {
2223
+ size: 14
2224
+ })
2225
+ }),
2226
+ sx: {
2227
+ width: "45%"
2228
+ }
2229
+ })), /* @__PURE__ */ jsx(ActionIcon, {
2230
+ onClick: add,
2231
+ color: "blue",
2232
+ variant: "outline",
2233
+ children: /* @__PURE__ */ jsx(PlaylistAdd, {
2234
+ size: 20
2235
+ })
2236
+ })]
2237
+ })]
2238
+ });
2239
+ }
2240
+ function ColorArrayInput({
2241
+ label,
2242
+ value,
2243
+ onChange
2244
+ }) {
2245
+ const [values, setValues] = React.useState(Array.isArray(value) ? [...value] : []);
2246
+ const add = React.useCallback(() => {
2247
+ setValues((s) => [...s, ""]);
2248
+ }, [setValues]);
2249
+ const del = React.useCallback((index2) => {
2250
+ setValues((s) => {
2251
+ s.splice(index2, 1);
2252
+ return [...s];
2253
+ });
2254
+ }, [setValues]);
2255
+ const changed = React.useMemo(() => {
2256
+ return !_.isEqual(values, value);
2257
+ }, [values, value]);
2258
+ const submit = () => {
2259
+ onChange(values.map((s) => s.toString()));
2260
+ };
2261
+ const theme = useMantineTheme();
2262
+ const swatches = React.useMemo(() => {
2263
+ return Object.entries(theme.colors).map(([_color, profile]) => profile[6]);
2264
+ }, [theme]);
2265
+ return /* @__PURE__ */ jsxs(Fragment, {
2266
+ children: [/* @__PURE__ */ jsxs(Group, {
2267
+ position: "left",
2268
+ children: [/* @__PURE__ */ jsx(Text, {
2269
+ children: label
2270
+ }), /* @__PURE__ */ jsx(ActionIcon, {
2271
+ mr: 5,
2272
+ variant: "filled",
2273
+ color: "blue",
2274
+ disabled: !changed,
2275
+ onClick: submit,
2276
+ children: /* @__PURE__ */ jsx(DeviceFloppy, {
2277
+ size: 20
2278
+ })
2279
+ })]
2280
+ }), /* @__PURE__ */ jsxs(Group, {
2281
+ children: [values.map((v, i) => /* @__PURE__ */ jsx(ColorInput, {
2282
+ value: v,
2283
+ onChange: (color2) => {
2284
+ setValues((s) => {
2285
+ s.splice(i, 1, color2);
2286
+ return [...s];
2287
+ });
2288
+ },
2289
+ swatches,
2290
+ rightSection: /* @__PURE__ */ jsx(ActionIcon, {
2291
+ onClick: () => del(i),
2292
+ color: "red",
2293
+ children: /* @__PURE__ */ jsx(Trash, {
2294
+ size: 14
2295
+ })
2296
+ }),
2297
+ sx: {
2298
+ width: "45%"
2299
+ }
2300
+ })), /* @__PURE__ */ jsx(ActionIcon, {
2301
+ onClick: add,
2302
+ color: "blue",
2303
+ variant: "outline",
2304
+ children: /* @__PURE__ */ jsx(PlaylistAdd, {
2305
+ size: 20
2306
+ })
2307
+ })]
2308
+ })]
2309
+ });
2310
+ }
2311
+ function VizStatsPanel({
2312
+ conf,
2313
+ setConf
2314
+ }) {
2315
+ const defaultValues = _.merge({}, {
2316
+ align: "center",
2317
+ size: "100px",
2318
+ template: "",
2319
+ weight: "bold",
2320
+ color: {
2321
+ type: "static",
2322
+ staticColor: "red"
2323
+ }
2324
+ }, conf);
2325
+ const {
2326
+ control,
2327
+ handleSubmit,
2328
+ watch,
2329
+ formState: {
2330
+ isDirty
2331
+ }
2332
+ } = useForm({
2333
+ defaultValues
2334
+ });
2335
+ const colorType = watch("color.type");
2336
+ watch("color.valueField");
2337
+ return /* @__PURE__ */ jsx(Group, {
2338
+ direction: "column",
2339
+ mt: "md",
2340
+ spacing: "xs",
2341
+ grow: true,
2342
+ noWrap: true,
2343
+ children: /* @__PURE__ */ jsxs("form", {
2344
+ onSubmit: handleSubmit(setConf),
2345
+ children: [/* @__PURE__ */ jsxs(Group, {
2346
+ position: "left",
2347
+ py: "md",
2348
+ pl: "md",
2349
+ sx: {
2350
+ borderBottom: "1px solid #eee",
2351
+ background: "#efefef"
2352
+ },
2353
+ children: [/* @__PURE__ */ jsx(Text, {
2354
+ weight: 500,
2355
+ children: "Stats Configurations"
2356
+ }), /* @__PURE__ */ jsx(ActionIcon, {
2357
+ type: "submit",
2358
+ mr: 5,
2359
+ variant: "filled",
2360
+ color: "blue",
2361
+ disabled: !isDirty,
2362
+ children: /* @__PURE__ */ jsx(DeviceFloppy, {
2363
+ size: 20
2364
+ })
2365
+ })]
2366
+ }), /* @__PURE__ */ jsxs(Accordion, {
2367
+ offsetIcon: false,
2368
+ multiple: true,
2369
+ initialState: {
2370
+ 0: true,
2371
+ 2: true
2372
+ },
2373
+ children: [/* @__PURE__ */ jsx(Accordion.Item, {
2374
+ label: "Content",
2375
+ children: /* @__PURE__ */ jsx(Group, {
2376
+ direction: "column",
2377
+ grow: true,
2378
+ children: /* @__PURE__ */ jsx(Controller, {
2379
+ name: "template",
2380
+ control,
2381
+ render: ({
2382
+ field
2383
+ }) => /* @__PURE__ */ jsx(TextInput, __spreadValues({
2384
+ placeholder: "Time: ${new Date().toISOString()}",
2385
+ label: "Content Template",
2386
+ required: true,
2387
+ sx: {
2388
+ flex: 1
2389
+ }
2390
+ }, field))
2391
+ })
2392
+ })
2393
+ }), /* @__PURE__ */ jsxs(Accordion.Item, {
2394
+ label: "Font",
2395
+ children: [/* @__PURE__ */ jsx(Group, {
2396
+ direction: "column",
2397
+ grow: true,
2398
+ children: /* @__PURE__ */ jsx(Controller, {
2399
+ name: "size",
2400
+ control,
2401
+ render: ({
2402
+ field
2403
+ }) => /* @__PURE__ */ jsx(TextInput, __spreadValues({
2404
+ label: "Font Size",
2405
+ placeholder: "10px, 1em, 1rem, 100%...",
2406
+ sx: {
2407
+ flex: 1
2408
+ }
2409
+ }, field))
2410
+ })
2411
+ }), /* @__PURE__ */ jsx(Group, {
2412
+ position: "apart",
2413
+ grow: true,
2414
+ sx: {
2415
+ "> *": {
2416
+ flexGrow: 1,
2417
+ maxWidth: "100%"
2418
+ }
2419
+ },
2420
+ children: /* @__PURE__ */ jsx(Controller, {
2421
+ name: "weight",
2422
+ control,
2423
+ render: ({
2424
+ field
2425
+ }) => /* @__PURE__ */ jsx(MantineFontWeightSlider, __spreadValues({
2426
+ label: "Font Weight"
2427
+ }, field))
2428
+ })
2429
+ })]
2430
+ }), /* @__PURE__ */ jsx(Accordion.Item, {
2431
+ label: "Color",
2432
+ children: /* @__PURE__ */ jsxs(Group, {
2433
+ direction: "column",
2434
+ grow: true,
2435
+ children: [/* @__PURE__ */ jsx(Controller, {
2436
+ name: "color.type",
2437
+ control,
2438
+ render: ({
2439
+ field
2440
+ }) => /* @__PURE__ */ jsx(Select, __spreadValues({
2441
+ label: "Color Type",
2442
+ data: [{
2443
+ label: "Static Color",
2444
+ value: "static"
2445
+ }, {
2446
+ label: "Continuous Color",
2447
+ value: "continuous"
2448
+ }]
2449
+ }, field))
2450
+ }), colorType === "static" && /* @__PURE__ */ jsx(Controller, {
2451
+ name: "color.staticColor",
2452
+ control,
2453
+ render: ({
2454
+ field
2455
+ }) => /* @__PURE__ */ jsx(MantineColorSelector, __spreadValues({}, field))
2456
+ }), colorType === "continuous" && /* @__PURE__ */ jsxs(Fragment, {
2457
+ children: [/* @__PURE__ */ jsx(Controller, {
2458
+ name: "color.valueField",
2459
+ control,
2460
+ defaultValue: "",
2461
+ render: ({
2462
+ field
2463
+ }) => /* @__PURE__ */ jsx(TextInput, __spreadValues({
2464
+ placeholder: "Calculate color with this field",
2465
+ label: "Value Field",
2466
+ required: true,
2467
+ sx: {
2468
+ flex: 1
2469
+ }
2470
+ }, field))
2471
+ }), /* @__PURE__ */ jsx(Controller, {
2472
+ name: "color.valueRange",
2473
+ control,
2474
+ render: ({
2475
+ field
2476
+ }) => /* @__PURE__ */ jsx(TextArrayInput, __spreadValues({
2477
+ label: "Value Range"
2478
+ }, field))
2479
+ }), /* @__PURE__ */ jsx(Controller, {
2480
+ name: "color.colorRange",
2481
+ control,
2482
+ render: ({
2483
+ field
2484
+ }) => /* @__PURE__ */ jsx(ColorArrayInput, __spreadValues({
2485
+ label: "Color Range"
2486
+ }, field))
2487
+ })]
2488
+ })]
2489
+ })
2490
+ })]
2491
+ })]
2492
+ })
2493
+ });
2494
+ }
1707
2495
  function SunburstPanel({
1708
2496
  conf: {
1709
2497
  label_field,
@@ -1788,16 +2576,16 @@ function ValueTypeSelector({
1788
2576
  sx
1789
2577
  });
1790
2578
  }
1791
- function VizTablePanel(_a) {
1792
- var _b = _a, {
1793
- conf: _c
1794
- } = _b, _d = _c, {
2579
+ function VizTablePanel(_e) {
2580
+ var _f = _e, {
2581
+ conf: _g
2582
+ } = _f, _h = _g, {
1795
2583
  columns
1796
- } = _d, restConf = __objRest(_d, [
2584
+ } = _h, restConf = __objRest(_h, [
1797
2585
  "columns"
1798
2586
  ]), {
1799
2587
  setConf
1800
- } = _b;
2588
+ } = _f;
1801
2589
  const form = useForm$1({
1802
2590
  initialValues: __spreadValues({
1803
2591
  id_field: "id",
@@ -2009,52 +2797,6 @@ function VizTablePanel(_a) {
2009
2797
  })
2010
2798
  });
2011
2799
  }
2012
- const marks = [{
2013
- label: "initial",
2014
- value: 0
2015
- }, {
2016
- label: "500",
2017
- value: 25
2018
- }, {
2019
- label: "700",
2020
- value: 50
2021
- }, {
2022
- label: "semibold",
2023
- value: 75
2024
- }, {
2025
- label: "bold",
2026
- value: 100
2027
- }];
2028
- function MantineFontWeightSlider({
2029
- label,
2030
- value,
2031
- onChange
2032
- }) {
2033
- var _a, _b;
2034
- const [mark, setMark] = React.useState((_b = (_a = marks.find((m2) => m2.label === value)) == null ? void 0 : _a.value) != null ? _b : marks[0].value);
2035
- React.useEffect(() => {
2036
- const match = marks.find((s) => s.value === mark);
2037
- if (match) {
2038
- onChange(match.label);
2039
- }
2040
- }, [mark]);
2041
- return /* @__PURE__ */ jsxs(Group, {
2042
- direction: "column",
2043
- grow: true,
2044
- spacing: "xs",
2045
- mb: "lg",
2046
- children: [/* @__PURE__ */ jsx(Text, {
2047
- children: label
2048
- }), /* @__PURE__ */ jsx(Slider, {
2049
- label: null,
2050
- marks,
2051
- value: mark,
2052
- onChange: setMark,
2053
- step: 25,
2054
- placeholder: "Pick a font size"
2055
- })]
2056
- });
2057
- }
2058
2800
  const sampleParagraphs = [{
2059
2801
  align: "center",
2060
2802
  size: "xl",
@@ -2194,6 +2936,10 @@ const types = [{
2194
2936
  value: "text",
2195
2937
  label: "Text",
2196
2938
  Panel: VizTextPanel
2939
+ }, {
2940
+ value: "stats",
2941
+ label: "Stats",
2942
+ Panel: VizStatsPanel
2197
2943
  }, {
2198
2944
  value: "table",
2199
2945
  label: "Table",
@@ -2799,7 +3545,8 @@ function DataSourceForm({
2799
3545
  });
2800
3546
  }
2801
3547
  function DataSourceEditor({
2802
- id
3548
+ id,
3549
+ setID
2803
3550
  }) {
2804
3551
  const {
2805
3552
  dataSources,
@@ -2819,7 +3566,8 @@ function DataSourceEditor({
2819
3566
  prevs.splice(index22, 1, value);
2820
3567
  return [...prevs];
2821
3568
  });
2822
- }, [id, dataSources, setDataSources]);
3569
+ setID(value.id);
3570
+ }, [id, dataSources, setDataSources, setID]);
2823
3571
  if (!id) {
2824
3572
  return null;
2825
3573
  }
@@ -2951,7 +3699,8 @@ function EditDataSourcesModal({
2951
3699
  setID
2952
3700
  }),
2953
3701
  children: [/* @__PURE__ */ jsx(DataSourceEditor, {
2954
- id
3702
+ id,
3703
+ setID
2955
3704
  }), /* @__PURE__ */ jsx(DataPreview, {
2956
3705
  id
2957
3706
  })]
@@ -3044,46 +3793,48 @@ WHERE \${author_time_condition}`;
3044
3793
  }) => {
3045
3794
  setSQLSnippets(snippets);
3046
3795
  };
3047
- return /* @__PURE__ */ jsxs(Group, {
3796
+ return /* @__PURE__ */ jsx(Group, {
3048
3797
  direction: "column",
3049
3798
  grow: true,
3050
3799
  sx: {
3051
3800
  border: "1px solid #eee"
3052
3801
  },
3053
- children: [/* @__PURE__ */ jsxs(Group, {
3054
- position: "left",
3055
- pl: "md",
3056
- py: "md",
3057
- sx: {
3058
- borderBottom: "1px solid #eee",
3059
- background: "#efefef",
3060
- flexGrow: 0
3061
- },
3062
- children: [/* @__PURE__ */ jsx(Text, {
3063
- weight: 500,
3064
- children: "SQL Snippets"
3065
- }), /* @__PURE__ */ jsx(ActionIcon, {
3066
- type: "submit",
3067
- mr: 5,
3068
- variant: "filled",
3069
- color: "blue",
3070
- disabled: !changed,
3071
- children: /* @__PURE__ */ jsx(DeviceFloppy, {
3072
- size: 20
3073
- })
3074
- })]
3075
- }), /* @__PURE__ */ jsxs(Group, {
3076
- px: "md",
3077
- pb: "md",
3078
- children: [/* @__PURE__ */ jsx(Prism, {
3079
- language: "sql",
3802
+ children: /* @__PURE__ */ jsxs("form", {
3803
+ onSubmit: form.onSubmit(submit),
3804
+ children: [/* @__PURE__ */ jsxs(Group, {
3805
+ position: "left",
3806
+ pl: "md",
3807
+ py: "md",
3080
3808
  sx: {
3081
- width: "100%"
3809
+ borderBottom: "1px solid #eee",
3810
+ background: "#efefef",
3811
+ flexGrow: 0
3082
3812
  },
3083
- noCopy: true,
3084
- trim: false,
3085
- colorScheme: "dark",
3086
- children: `-- You may refer context data *by name*
3813
+ children: [/* @__PURE__ */ jsx(Text, {
3814
+ weight: 500,
3815
+ children: "SQL Snippets"
3816
+ }), /* @__PURE__ */ jsx(ActionIcon, {
3817
+ type: "submit",
3818
+ mr: 5,
3819
+ variant: "filled",
3820
+ color: "blue",
3821
+ disabled: !changed,
3822
+ children: /* @__PURE__ */ jsx(DeviceFloppy, {
3823
+ size: 20
3824
+ })
3825
+ })]
3826
+ }), /* @__PURE__ */ jsxs(Group, {
3827
+ px: "md",
3828
+ pb: "md",
3829
+ children: [/* @__PURE__ */ jsx(Prism, {
3830
+ language: "sql",
3831
+ sx: {
3832
+ width: "100%"
3833
+ },
3834
+ noCopy: true,
3835
+ trim: false,
3836
+ colorScheme: "dark",
3837
+ children: `-- You may refer context data *by name*
3087
3838
  -- in SQL or VizConfig.
3088
3839
 
3089
3840
  ${sampleSQL}
@@ -3091,15 +3842,13 @@ ${sampleSQL}
3091
3842
  -- where author_time_condition is:
3092
3843
  author_time BETWEEN '\${timeRange?.[0].toISOString()}' AND '\${timeRange?.[1].toISOString()}'
3093
3844
  `
3094
- }), /* @__PURE__ */ jsx(Group, {
3095
- direction: "column",
3096
- sx: {
3097
- width: "100%",
3098
- position: "relative"
3099
- },
3100
- grow: true,
3101
- children: /* @__PURE__ */ jsxs("form", {
3102
- onSubmit: form.onSubmit(submit),
3845
+ }), /* @__PURE__ */ jsxs(Group, {
3846
+ direction: "column",
3847
+ sx: {
3848
+ width: "100%",
3849
+ position: "relative"
3850
+ },
3851
+ grow: true,
3103
3852
  children: [form.values.snippets.map((_item, index2) => /* @__PURE__ */ jsxs(Group, {
3104
3853
  direction: "column",
3105
3854
  grow: true,
@@ -3144,9 +3893,9 @@ author_time BETWEEN '\${timeRange?.[0].toISOString()}' AND '\${timeRange?.[1].to
3144
3893
  children: "Add a snippet"
3145
3894
  })
3146
3895
  })]
3147
- })
3896
+ })]
3148
3897
  })]
3149
- })]
3898
+ })
3150
3899
  });
3151
3900
  }
3152
3901
  function EditSQLSnippetsModal({