@prismiq/react 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{CustomSQLEditor-BXB4rf1q.d.cts → CustomSQLEditor-CYlOtecq.d.ts} +10 -3
- package/dist/{CustomSQLEditor-DYeId0Gp.d.ts → CustomSQLEditor-d84v_Cgp.d.cts} +10 -3
- package/dist/{DashboardDialog-LHmrtNQU.d.cts → DashboardDialog-CZD8I-6z.d.cts} +4 -4
- package/dist/{DashboardDialog-B3vYC5Gs.d.ts → DashboardDialog-DBNTVVSp.d.ts} +4 -4
- package/dist/{accessibility-2yy5yqRR.d.cts → accessibility-Bu2mNtaB.d.cts} +1 -1
- package/dist/{accessibility-2yy5yqRR.d.ts → accessibility-Bu2mNtaB.d.ts} +1 -1
- package/dist/charts/index.cjs +27 -27
- package/dist/charts/index.d.cts +2 -2
- package/dist/charts/index.d.ts +2 -2
- package/dist/charts/index.js +2 -2
- package/dist/{chunk-MOAEEF5P.js → chunk-3LDRRDJ6.js} +185 -91
- package/dist/chunk-3LDRRDJ6.js.map +1 -0
- package/dist/{chunk-NK7HKX2J.cjs → chunk-73TPDGXB.cjs} +7 -7
- package/dist/{chunk-NK7HKX2J.cjs.map → chunk-73TPDGXB.cjs.map} +1 -1
- package/dist/{chunk-UPYINBZU.js → chunk-ET7GCREP.js} +502 -46
- package/dist/chunk-ET7GCREP.js.map +1 -0
- package/dist/{chunk-2H5WTH4K.js → chunk-FQ23KG6G.js} +3 -3
- package/dist/{chunk-2H5WTH4K.js.map → chunk-FQ23KG6G.js.map} +1 -1
- package/dist/{chunk-4AVL6GQK.cjs → chunk-KXB2IZI2.cjs} +36 -9
- package/dist/chunk-KXB2IZI2.cjs.map +1 -0
- package/dist/{chunk-EX74SI67.js → chunk-LBE6GIBC.js} +36 -9
- package/dist/chunk-LBE6GIBC.js.map +1 -0
- package/dist/{chunk-NY6TZLST.cjs → chunk-URJH4H6G.cjs} +505 -49
- package/dist/chunk-URJH4H6G.cjs.map +1 -0
- package/dist/{chunk-FEABEF3J.cjs → chunk-VQDFS6VS.cjs} +374 -280
- package/dist/chunk-VQDFS6VS.cjs.map +1 -0
- package/dist/components/index.cjs +55 -55
- package/dist/components/index.d.cts +2 -2
- package/dist/components/index.d.ts +2 -2
- package/dist/components/index.js +2 -2
- package/dist/dashboard/index.cjs +36 -36
- package/dist/dashboard/index.d.cts +3 -3
- package/dist/dashboard/index.d.ts +3 -3
- package/dist/dashboard/index.js +4 -4
- package/dist/export/index.d.cts +1 -1
- package/dist/export/index.d.ts +1 -1
- package/dist/{index-C-Qcuu4Y.d.cts → index-CvKj3SWO.d.cts} +2 -2
- package/dist/{index-rPc7ijt8.d.ts → index-DXGLs1yY.d.ts} +2 -2
- package/dist/index.cjs +127 -127
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -9
- package/dist/index.d.ts +30 -9
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/dist/{types-WrCbOeAV.d.cts → types-j0kPJ9Hz.d.cts} +16 -1
- package/dist/{types-WrCbOeAV.d.ts → types-j0kPJ9Hz.d.ts} +16 -1
- package/dist/utils/index.cjs +15 -15
- package/dist/utils/index.d.cts +5 -21
- package/dist/utils/index.d.ts +5 -21
- package/dist/utils/index.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-4AVL6GQK.cjs.map +0 -1
- package/dist/chunk-EX74SI67.js.map +0 -1
- package/dist/chunk-FEABEF3J.cjs.map +0 -1
- package/dist/chunk-MOAEEF5P.js.map +0 -1
- package/dist/chunk-NY6TZLST.cjs.map +0 -1
- package/dist/chunk-UPYINBZU.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { ScatterChart, PieChart, AreaChart, LineChart, BarChart, MetricCard } from './chunk-
|
|
2
|
-
import { Dropdown, DropdownItem, Icon, DropdownSeparator, Button, Skeleton, EmptyState, Dialog, Input, Checkbox, DialogFooter, useAnalytics, useCrossFilterOptional, useDebouncedLayoutSave, AutoSaveIndicator, ResultsTable, CrossFilterProvider, QueryBuilder, SavedQueryPicker, useSchema, Select, CollapsibleSection, ColorPaletteSelector, FilterBuilder, TableSelector, JoinBuilder, TimeSeriesConfig, CalculatedFieldBuilder } from './chunk-
|
|
1
|
+
import { ScatterChart, PieChart, AreaChart, LineChart, BarChart, MetricCard } from './chunk-FQ23KG6G.js';
|
|
2
|
+
import { Dropdown, DropdownItem, Icon, DropdownSeparator, Button, Skeleton, EmptyState, Dialog, Input, Checkbox, DialogFooter, useAnalytics, useCrossFilterOptional, useDebouncedLayoutSave, AutoSaveIndicator, ResultsTable, CrossFilterProvider, Tooltip, QueryBuilder, SavedQueryPicker, useSchema, Select, CollapsibleSection, ColorPaletteSelector, FilterBuilder, TableSelector, JoinBuilder, TimeSeriesConfig, CalculatedFieldBuilder } from './chunk-ET7GCREP.js';
|
|
3
3
|
import { useTheme } from './chunk-T6STUE7E.js';
|
|
4
|
-
import { formatRelativeTime, createDateFormatters, pivotQueryResult, parseMarkdownSafe, parseColumnRef } from './chunk-
|
|
4
|
+
import { formatRelativeTime, createDateFormatters, pivotQueryResult, parseMarkdownSafe, parseColumnRef } from './chunk-LBE6GIBC.js';
|
|
5
5
|
import { createContext, forwardRef, useState, useEffect, useCallback, useRef, useMemo, useContext } from 'react';
|
|
6
6
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
7
7
|
import { WidthProvider, Responsive } from 'react-grid-layout/legacy';
|
|
@@ -169,6 +169,7 @@ function DashboardProvider({
|
|
|
169
169
|
const clientRef = useRef(client);
|
|
170
170
|
clientRef.current = client;
|
|
171
171
|
const loadedDashboardRef = useRef(null);
|
|
172
|
+
const abortControllerRef = useRef(null);
|
|
172
173
|
const setDashboardData = useCallback((data) => {
|
|
173
174
|
setDashboard(data);
|
|
174
175
|
const defaults = data.filters.filter((f) => f.default_value !== void 0).map((f) => ({
|
|
@@ -187,7 +188,7 @@ function DashboardProvider({
|
|
|
187
188
|
}
|
|
188
189
|
}, []);
|
|
189
190
|
const executeWidgetQuery = useCallback(
|
|
190
|
-
async (widget, currentDashboard, currentFilters, currentCrossFilters, bypassCache = false) => {
|
|
191
|
+
async (widget, currentDashboard, currentFilters, currentCrossFilters, bypassCache = false, signal) => {
|
|
191
192
|
if (!widget.query) {
|
|
192
193
|
return;
|
|
193
194
|
}
|
|
@@ -207,16 +208,21 @@ function DashboardProvider({
|
|
|
207
208
|
currentFilters
|
|
208
209
|
);
|
|
209
210
|
query = applyCrossFiltersToQuery(query, currentCrossFilters, widget.id);
|
|
210
|
-
const result = await client.executeQuery(query, bypassCache);
|
|
211
|
+
const result = await client.executeQuery(query, bypassCache, signal);
|
|
212
|
+
if (signal?.aborted) return;
|
|
211
213
|
setWidgetResults((prev) => ({ ...prev, [widget.id]: result }));
|
|
212
214
|
const refreshTime = result.cached_at ?? Date.now() / 1e3;
|
|
213
215
|
setWidgetRefreshTimes((prev) => ({ ...prev, [widget.id]: refreshTime }));
|
|
214
216
|
} catch (err) {
|
|
217
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
215
220
|
setWidgetErrors((prev) => ({
|
|
216
221
|
...prev,
|
|
217
222
|
[widget.id]: err instanceof Error ? err : new Error("Query failed")
|
|
218
223
|
}));
|
|
219
224
|
} finally {
|
|
225
|
+
if (signal?.aborted) return;
|
|
220
226
|
setWidgetLoading((prev) => ({ ...prev, [widget.id]: false }));
|
|
221
227
|
if (bypassCache) {
|
|
222
228
|
setRefreshingWidgets((prev) => {
|
|
@@ -230,9 +236,10 @@ function DashboardProvider({
|
|
|
230
236
|
[client]
|
|
231
237
|
);
|
|
232
238
|
const executeWidgetsInBatches = useCallback(
|
|
233
|
-
async (widgets, currentDashboard, currentFilters, currentCrossFilters, bypassCache = false, currentBatchSize = batchSize) => {
|
|
239
|
+
async (widgets, currentDashboard, currentFilters, currentCrossFilters, bypassCache = false, currentBatchSize = batchSize, signal) => {
|
|
234
240
|
const widgetsWithQueries = widgets.filter((w) => w.query !== null);
|
|
235
241
|
for (let i = 0; i < widgetsWithQueries.length; i += currentBatchSize) {
|
|
242
|
+
if (signal?.aborted) return;
|
|
236
243
|
const batch = widgetsWithQueries.slice(i, i + currentBatchSize);
|
|
237
244
|
await Promise.all(
|
|
238
245
|
batch.map(
|
|
@@ -241,7 +248,8 @@ function DashboardProvider({
|
|
|
241
248
|
currentDashboard,
|
|
242
249
|
currentFilters,
|
|
243
250
|
currentCrossFilters,
|
|
244
|
-
bypassCache
|
|
251
|
+
bypassCache,
|
|
252
|
+
signal
|
|
245
253
|
)
|
|
246
254
|
)
|
|
247
255
|
);
|
|
@@ -253,16 +261,19 @@ function DashboardProvider({
|
|
|
253
261
|
async (currentDashboard, currentFilters, currentCrossFilters) => {
|
|
254
262
|
const requestId = Math.random().toString(36).substring(2, 11);
|
|
255
263
|
requestIdRef.current = requestId;
|
|
264
|
+
const signal = abortControllerRef.current?.signal;
|
|
256
265
|
await executeWidgetsInBatches(
|
|
257
266
|
currentDashboard.widgets,
|
|
258
267
|
currentDashboard,
|
|
259
268
|
currentFilters,
|
|
260
269
|
currentCrossFilters,
|
|
261
|
-
false
|
|
270
|
+
false,
|
|
262
271
|
// Don't bypass cache on initial load
|
|
272
|
+
batchSize,
|
|
273
|
+
signal
|
|
263
274
|
);
|
|
264
275
|
},
|
|
265
|
-
[executeWidgetsInBatches]
|
|
276
|
+
[executeWidgetsInBatches, batchSize]
|
|
266
277
|
);
|
|
267
278
|
const refreshDashboard = useCallback(async () => {
|
|
268
279
|
if (!dashboard) return;
|
|
@@ -428,13 +439,16 @@ function DashboardProvider({
|
|
|
428
439
|
(w) => visibleWidgets.has(w.id) && w.query !== null && !widgetResults[w.id] && !widgetLoading[w.id]
|
|
429
440
|
);
|
|
430
441
|
if (widgetsToLoad.length > 0) {
|
|
442
|
+
const signal = abortControllerRef.current?.signal;
|
|
431
443
|
executeWidgetsInBatches(
|
|
432
444
|
widgetsToLoad,
|
|
433
445
|
dashboard,
|
|
434
446
|
filterValues,
|
|
435
447
|
crossFilters,
|
|
436
|
-
false
|
|
448
|
+
false,
|
|
437
449
|
// Don't bypass cache
|
|
450
|
+
batchSize,
|
|
451
|
+
signal
|
|
438
452
|
);
|
|
439
453
|
}
|
|
440
454
|
}, [
|
|
@@ -446,7 +460,8 @@ function DashboardProvider({
|
|
|
446
460
|
widgetLoading,
|
|
447
461
|
filterValues,
|
|
448
462
|
crossFilters,
|
|
449
|
-
executeWidgetsInBatches
|
|
463
|
+
executeWidgetsInBatches,
|
|
464
|
+
batchSize
|
|
450
465
|
]);
|
|
451
466
|
const filterValuesKey = JSON.stringify(filterValues);
|
|
452
467
|
const prevFilterValuesRef = useRef(filterValuesKey);
|
|
@@ -459,12 +474,17 @@ function DashboardProvider({
|
|
|
459
474
|
// Only re-execute if previously loaded
|
|
460
475
|
);
|
|
461
476
|
if (widgetsToRefresh.length > 0) {
|
|
477
|
+
abortControllerRef.current?.abort();
|
|
478
|
+
const controller = new AbortController();
|
|
479
|
+
abortControllerRef.current = controller;
|
|
462
480
|
executeWidgetsInBatches(
|
|
463
481
|
widgetsToRefresh,
|
|
464
482
|
dashboard,
|
|
465
483
|
filterValues,
|
|
466
484
|
crossFilters,
|
|
467
|
-
false
|
|
485
|
+
false,
|
|
486
|
+
batchSize,
|
|
487
|
+
controller.signal
|
|
468
488
|
);
|
|
469
489
|
}
|
|
470
490
|
}, [
|
|
@@ -476,8 +496,16 @@ function DashboardProvider({
|
|
|
476
496
|
widgetResults,
|
|
477
497
|
filterValues,
|
|
478
498
|
crossFilters,
|
|
479
|
-
executeWidgetsInBatches
|
|
499
|
+
executeWidgetsInBatches,
|
|
500
|
+
batchSize
|
|
480
501
|
]);
|
|
502
|
+
useEffect(() => {
|
|
503
|
+
const controller = new AbortController();
|
|
504
|
+
abortControllerRef.current = controller;
|
|
505
|
+
return () => {
|
|
506
|
+
controller.abort();
|
|
507
|
+
};
|
|
508
|
+
}, [dashboardId]);
|
|
481
509
|
const contextValue = useMemo(
|
|
482
510
|
() => ({
|
|
483
511
|
dashboard,
|
|
@@ -1450,6 +1478,9 @@ function WidgetContent({
|
|
|
1450
1478
|
if (widget.type === "text") {
|
|
1451
1479
|
return /* @__PURE__ */ jsx("div", { style: containerStyle, children: /* @__PURE__ */ jsx(TextContent, { config: widget.config }) });
|
|
1452
1480
|
}
|
|
1481
|
+
if (!result && !error && widget.query) {
|
|
1482
|
+
return /* @__PURE__ */ jsx("div", { style: containerStyle, children: /* @__PURE__ */ jsx(LoadingState, {}) });
|
|
1483
|
+
}
|
|
1453
1484
|
if (!result || result.row_count === 0) {
|
|
1454
1485
|
return /* @__PURE__ */ jsx("div", { style: containerStyle, children: /* @__PURE__ */ jsx(EmptyState2, {}) });
|
|
1455
1486
|
}
|
|
@@ -1586,10 +1617,22 @@ function WidgetContent({
|
|
|
1586
1617
|
const dimensionColumns = result.columns.filter(
|
|
1587
1618
|
(col) => col !== widget.config.pivot_column && col !== widget.config.value_column
|
|
1588
1619
|
);
|
|
1620
|
+
let pivotColumnFormat;
|
|
1621
|
+
if (widget.config.dateFormats?.[widget.config.pivot_column]) {
|
|
1622
|
+
pivotColumnFormat = widget.config.dateFormats[widget.config.pivot_column];
|
|
1623
|
+
} else if (widget.query) {
|
|
1624
|
+
const pivotCol = widget.query.columns.find(
|
|
1625
|
+
(c) => c.alias === widget.config.pivot_column || c.column === widget.config.pivot_column
|
|
1626
|
+
);
|
|
1627
|
+
if (pivotCol?.date_format) {
|
|
1628
|
+
pivotColumnFormat = pivotCol.date_format;
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1589
1631
|
tableResult = pivotQueryResult(result, {
|
|
1590
1632
|
pivotColumn: widget.config.pivot_column,
|
|
1591
1633
|
valueColumn: widget.config.value_column,
|
|
1592
|
-
dimensionColumns
|
|
1634
|
+
dimensionColumns,
|
|
1635
|
+
pivotColumnFormat
|
|
1593
1636
|
});
|
|
1594
1637
|
}
|
|
1595
1638
|
const tableContainerStyle = {
|
|
@@ -2995,7 +3038,9 @@ function WidgetTypeSelector({
|
|
|
2995
3038
|
borderRadius: theme.radius.sm,
|
|
2996
3039
|
border: `2px solid ${isSelected ? theme.colors.primary : theme.colors.border}`,
|
|
2997
3040
|
cursor: "pointer",
|
|
2998
|
-
transition: "all 0.15s ease"
|
|
3041
|
+
transition: "all 0.15s ease",
|
|
3042
|
+
minWidth: 0
|
|
3043
|
+
// Allow grid item to shrink below content width
|
|
2999
3044
|
});
|
|
3000
3045
|
const iconStyle = (isSelected) => ({
|
|
3001
3046
|
width: "28px",
|
|
@@ -3022,9 +3067,7 @@ function WidgetTypeSelector({
|
|
|
3022
3067
|
const descStyle = {
|
|
3023
3068
|
fontSize: theme.fontSizes.xs,
|
|
3024
3069
|
color: theme.colors.textMuted,
|
|
3025
|
-
whiteSpace: "nowrap"
|
|
3026
|
-
overflow: "hidden",
|
|
3027
|
-
textOverflow: "ellipsis"
|
|
3070
|
+
whiteSpace: "nowrap"
|
|
3028
3071
|
};
|
|
3029
3072
|
return /* @__PURE__ */ jsxs("div", { className: `prismiq-widget-type-selector ${className}`, style: containerStyle, children: [
|
|
3030
3073
|
/* @__PURE__ */ jsx("label", { style: labelStyle, children: "Widget Type" }),
|
|
@@ -3191,19 +3234,26 @@ function MetricConfig({
|
|
|
3191
3234
|
onChange
|
|
3192
3235
|
}) {
|
|
3193
3236
|
const { theme } = useTheme();
|
|
3237
|
+
const { getDisplayName } = useSchema();
|
|
3194
3238
|
const initialTable = query?.tables[0]?.name ?? "";
|
|
3195
3239
|
const initialAggregation = query?.columns[0]?.aggregation ?? "count";
|
|
3196
|
-
const
|
|
3240
|
+
const rawInitialColumn = query?.columns[0]?.column ?? "*";
|
|
3241
|
+
const needsColumnForInitial = AGGREGATIONS.find((a) => a.value === initialAggregation)?.needsColumn ?? false;
|
|
3242
|
+
const initialColumn = rawInitialColumn === "*" && needsColumnForInitial ? "" : rawInitialColumn;
|
|
3243
|
+
const initialFilters = (query?.filters ?? []).map((f) => ({
|
|
3244
|
+
...f,
|
|
3245
|
+
table_id: "t1"
|
|
3246
|
+
}));
|
|
3197
3247
|
const [selectedTable, setSelectedTable] = useState(initialTable);
|
|
3198
3248
|
const [aggregation, setAggregation] = useState(initialAggregation);
|
|
3199
3249
|
const [selectedColumn, setSelectedColumn] = useState(initialColumn);
|
|
3200
|
-
const [filters, setFilters] = useState(
|
|
3250
|
+
const [filters, setFilters] = useState(initialFilters);
|
|
3201
3251
|
const tableOptions = useMemo(() => {
|
|
3202
3252
|
return schema.tables.map((t) => ({
|
|
3203
3253
|
value: t.name,
|
|
3204
|
-
label: t.name
|
|
3254
|
+
label: getDisplayName(t.name)
|
|
3205
3255
|
}));
|
|
3206
|
-
}, [schema.tables]);
|
|
3256
|
+
}, [schema.tables, getDisplayName]);
|
|
3207
3257
|
const currentTable = useMemo(() => {
|
|
3208
3258
|
return schema.tables.find((t) => t.name === selectedTable);
|
|
3209
3259
|
}, [schema.tables, selectedTable]);
|
|
@@ -3218,8 +3268,12 @@ function MetricConfig({
|
|
|
3218
3268
|
const needsColumn = useMemo(() => {
|
|
3219
3269
|
return AGGREGATIONS.find((a) => a.value === aggregation)?.needsColumn ?? false;
|
|
3220
3270
|
}, [aggregation]);
|
|
3271
|
+
const isValidAggregation = useMemo(() => {
|
|
3272
|
+
return AGGREGATIONS.some((a) => a.value === aggregation);
|
|
3273
|
+
}, [aggregation]);
|
|
3221
3274
|
useEffect(() => {
|
|
3222
3275
|
if (!selectedTable) return;
|
|
3276
|
+
if (!isValidAggregation) return;
|
|
3223
3277
|
const tableId = "t1";
|
|
3224
3278
|
const tables = [{ id: tableId, name: selectedTable }];
|
|
3225
3279
|
const column = needsColumn ? selectedColumn : "*";
|
|
@@ -3237,7 +3291,7 @@ function MetricConfig({
|
|
|
3237
3291
|
filters: filters.length > 0 ? filters : void 0
|
|
3238
3292
|
};
|
|
3239
3293
|
onChange(queryDef);
|
|
3240
|
-
}, [selectedTable, aggregation, selectedColumn, needsColumn, filters, onChange]);
|
|
3294
|
+
}, [selectedTable, aggregation, selectedColumn, needsColumn, isValidAggregation, filters, onChange]);
|
|
3241
3295
|
const handleTableChange = useCallback((value) => {
|
|
3242
3296
|
setSelectedTable(value);
|
|
3243
3297
|
setSelectedColumn("");
|
|
@@ -3362,17 +3416,23 @@ function ChartConfig({
|
|
|
3362
3416
|
onChange
|
|
3363
3417
|
}) {
|
|
3364
3418
|
const { theme } = useTheme();
|
|
3419
|
+
const { getDisplayName } = useSchema();
|
|
3365
3420
|
const initialTables = query?.tables ?? [];
|
|
3366
3421
|
const groupByCol = query?.columns.find((c) => c.aggregation === "none");
|
|
3367
3422
|
const initialGroupBy = groupByCol?.column ?? query?.group_by?.[0]?.column ?? "";
|
|
3368
3423
|
const initialGroupByTableId = groupByCol?.table_id ?? query?.tables?.[0]?.id ?? "t1";
|
|
3369
3424
|
const initialDateTrunc = groupByCol?.date_trunc ?? "";
|
|
3370
|
-
const initialMeasures = query?.columns.filter((c) => c.aggregation !== "none").map((c) =>
|
|
3371
|
-
|
|
3372
|
-
column: c.table_id ? `${c.table_id}.${c.column}` : c.column
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3425
|
+
const initialMeasures = query?.columns.filter((c) => c.aggregation !== "none").map((c) => {
|
|
3426
|
+
const isStarWithNonCount = (c.column === "*" || c.column.endsWith(".*")) && c.aggregation !== "count";
|
|
3427
|
+
const column = isStarWithNonCount ? "" : c.table_id ? `${c.table_id}.${c.column}` : c.column;
|
|
3428
|
+
return {
|
|
3429
|
+
column,
|
|
3430
|
+
aggregation: c.aggregation,
|
|
3431
|
+
table_id: c.table_id,
|
|
3432
|
+
// Preserve original alias to maintain compatibility with widget config
|
|
3433
|
+
alias: c.alias
|
|
3434
|
+
};
|
|
3435
|
+
}) ?? [];
|
|
3376
3436
|
const initialJoins = query?.joins ?? [];
|
|
3377
3437
|
const [tables, setTables] = useState(initialTables);
|
|
3378
3438
|
const [joins, setJoins] = useState(initialJoins);
|
|
@@ -3393,9 +3453,9 @@ function ChartConfig({
|
|
|
3393
3453
|
const tableOptions = useMemo(() => {
|
|
3394
3454
|
return schema.tables.map((t) => ({
|
|
3395
3455
|
value: t.name,
|
|
3396
|
-
label: t.name
|
|
3456
|
+
label: getDisplayName(t.name)
|
|
3397
3457
|
}));
|
|
3398
|
-
}, [schema.tables]);
|
|
3458
|
+
}, [schema.tables, getDisplayName]);
|
|
3399
3459
|
const currentTable = useMemo(() => {
|
|
3400
3460
|
return schema.tables.find((t) => t.name === selectedTable);
|
|
3401
3461
|
}, [schema.tables, selectedTable]);
|
|
@@ -3465,7 +3525,7 @@ function ChartConfig({
|
|
|
3465
3525
|
const parsedMeasures = [];
|
|
3466
3526
|
const invalidColumns = [];
|
|
3467
3527
|
validMeasures.forEach((m, i) => {
|
|
3468
|
-
const measureAlias = validMeasures.length > 1 ? `value_${i + 1}` : "value";
|
|
3528
|
+
const measureAlias = m.alias ?? (validMeasures.length > 1 ? `value_${i + 1}` : "value");
|
|
3469
3529
|
if (m.aggregation === "count" && (!m.column || m.column.endsWith(".*") || m.column === "*")) {
|
|
3470
3530
|
parsedMeasures.push({
|
|
3471
3531
|
table_id: m.table_id ?? tables[0]?.id ?? "t1",
|
|
@@ -3529,6 +3589,9 @@ function ChartConfig({
|
|
|
3529
3589
|
setJoins(
|
|
3530
3590
|
(prev) => prev.filter((j) => tableIds.has(j.from_table_id) && tableIds.has(j.to_table_id))
|
|
3531
3591
|
);
|
|
3592
|
+
setFilters(
|
|
3593
|
+
(prev) => prev.filter((f) => tableIds.has(f.table_id))
|
|
3594
|
+
);
|
|
3532
3595
|
if (!tableIds.has(groupByTableId)) {
|
|
3533
3596
|
setGroupByColumn("");
|
|
3534
3597
|
setGroupByTableId(newTables[0]?.id ?? "t1");
|
|
@@ -3783,25 +3846,31 @@ function PieConfig({
|
|
|
3783
3846
|
onChange
|
|
3784
3847
|
}) {
|
|
3785
3848
|
const { theme } = useTheme();
|
|
3849
|
+
const { getDisplayName } = useSchema();
|
|
3786
3850
|
const initialTable = query?.tables[0]?.name ?? "";
|
|
3787
3851
|
const labelCol = query?.columns.find((c) => c.aggregation === "none");
|
|
3788
3852
|
const initialLabel = labelCol?.column ?? "";
|
|
3789
3853
|
const initialDateTrunc = labelCol?.date_trunc ?? "";
|
|
3790
3854
|
const measureCol = query?.columns.find((c) => c.aggregation !== "none");
|
|
3791
|
-
const
|
|
3855
|
+
const rawInitialValueColumn = measureCol?.column ?? "";
|
|
3792
3856
|
const initialAggregation = measureCol?.aggregation ?? "sum";
|
|
3857
|
+
const initialValueColumn = rawInitialValueColumn === "*" && initialAggregation !== "count" ? "" : rawInitialValueColumn;
|
|
3858
|
+
const initialFilters = (query?.filters ?? []).map((f) => ({
|
|
3859
|
+
...f,
|
|
3860
|
+
table_id: "t1"
|
|
3861
|
+
}));
|
|
3793
3862
|
const [selectedTable, setSelectedTable] = useState(initialTable);
|
|
3794
3863
|
const [labelColumn, setLabelColumn] = useState(initialLabel);
|
|
3795
3864
|
const [dateTrunc, setDateTrunc] = useState(initialDateTrunc);
|
|
3796
3865
|
const [valueColumn, setValueColumn] = useState(initialValueColumn);
|
|
3797
3866
|
const [aggregation, setAggregation] = useState(initialAggregation);
|
|
3798
|
-
const [filters, setFilters] = useState(
|
|
3867
|
+
const [filters, setFilters] = useState(initialFilters);
|
|
3799
3868
|
const tableOptions = useMemo(() => {
|
|
3800
3869
|
return schema.tables.map((t) => ({
|
|
3801
3870
|
value: t.name,
|
|
3802
|
-
label: t.name
|
|
3871
|
+
label: getDisplayName(t.name)
|
|
3803
3872
|
}));
|
|
3804
|
-
}, [schema.tables]);
|
|
3873
|
+
}, [schema.tables, getDisplayName]);
|
|
3805
3874
|
const currentTable = useMemo(() => {
|
|
3806
3875
|
return schema.tables.find((t) => t.name === selectedTable);
|
|
3807
3876
|
}, [schema.tables, selectedTable]);
|
|
@@ -3826,8 +3895,12 @@ function PieConfig({
|
|
|
3826
3895
|
label: `${c.name} (${c.data_type})`
|
|
3827
3896
|
}));
|
|
3828
3897
|
}, [currentTable]);
|
|
3898
|
+
const isValidAggregation = useMemo(() => {
|
|
3899
|
+
return AGGREGATIONS3.some((a) => a.value === aggregation);
|
|
3900
|
+
}, [aggregation]);
|
|
3829
3901
|
useEffect(() => {
|
|
3830
3902
|
if (!selectedTable || !labelColumn) return;
|
|
3903
|
+
if (!isValidAggregation) return;
|
|
3831
3904
|
const needsValueColumn = aggregation !== "count";
|
|
3832
3905
|
if (needsValueColumn && !valueColumn) return;
|
|
3833
3906
|
const tableId = "t1";
|
|
@@ -3857,7 +3930,7 @@ function PieConfig({
|
|
|
3857
3930
|
order_by: [{ table_id: tableId, column: labelColumn, direction: "ASC" }]
|
|
3858
3931
|
};
|
|
3859
3932
|
onChange(queryDef);
|
|
3860
|
-
}, [selectedTable, labelColumn, dateTrunc, valueColumn, aggregation, filters, onChange]);
|
|
3933
|
+
}, [selectedTable, labelColumn, dateTrunc, valueColumn, aggregation, isValidAggregation, filters, onChange]);
|
|
3861
3934
|
const handleTableChange = useCallback((value) => {
|
|
3862
3935
|
setSelectedTable(value);
|
|
3863
3936
|
setLabelColumn("");
|
|
@@ -3978,18 +4051,23 @@ function TableConfig({
|
|
|
3978
4051
|
onChange
|
|
3979
4052
|
}) {
|
|
3980
4053
|
const { theme } = useTheme();
|
|
4054
|
+
const { getDisplayName } = useSchema();
|
|
3981
4055
|
const initialTable = query?.tables[0]?.name ?? "";
|
|
3982
4056
|
const initialColumns = query?.columns.map((c) => c.column) ?? [];
|
|
4057
|
+
const initialFilters = (query?.filters ?? []).map((f) => ({
|
|
4058
|
+
...f,
|
|
4059
|
+
table_id: "t1"
|
|
4060
|
+
}));
|
|
3983
4061
|
const [selectedTable, setSelectedTable] = useState(initialTable);
|
|
3984
4062
|
const [selectedColumns, setSelectedColumns] = useState(initialColumns);
|
|
3985
|
-
const [filters, setFilters] = useState(
|
|
4063
|
+
const [filters, setFilters] = useState(initialFilters);
|
|
3986
4064
|
const [limit, setLimit] = useState(query?.limit ?? 100);
|
|
3987
4065
|
const tableOptions = useMemo(() => {
|
|
3988
4066
|
return schema.tables.map((t) => ({
|
|
3989
4067
|
value: t.name,
|
|
3990
|
-
label: t.name
|
|
4068
|
+
label: getDisplayName(t.name)
|
|
3991
4069
|
}));
|
|
3992
|
-
}, [schema.tables]);
|
|
4070
|
+
}, [schema.tables, getDisplayName]);
|
|
3993
4071
|
const currentTable = useMemo(() => {
|
|
3994
4072
|
return schema.tables.find((t) => t.name === selectedTable);
|
|
3995
4073
|
}, [schema.tables, selectedTable]);
|
|
@@ -5303,7 +5381,7 @@ function WidgetEditorPage({
|
|
|
5303
5381
|
widget?.position ?? { x: 0, y: 0, w: 6, h: 4, minW: 2, minH: 2 }
|
|
5304
5382
|
);
|
|
5305
5383
|
const [dataSourceMode, setDataSourceMode] = useState(
|
|
5306
|
-
isNew ? "guided" : widget?.
|
|
5384
|
+
isNew ? "guided" : widget?.config?.data_source_mode ?? "guided"
|
|
5307
5385
|
);
|
|
5308
5386
|
const [previewResult, setPreviewResult] = useState(null);
|
|
5309
5387
|
const [previewLoading, setPreviewLoading] = useState(false);
|
|
@@ -5350,6 +5428,26 @@ function WidgetEditorPage({
|
|
|
5350
5428
|
setPreviewError(null);
|
|
5351
5429
|
}
|
|
5352
5430
|
}, [query, refreshPreview]);
|
|
5431
|
+
const queryHasAdvancedFeatures = useCallback((q) => {
|
|
5432
|
+
if (!q) return false;
|
|
5433
|
+
if (q.tables && q.tables.length > 1 && q.joins && q.joins.length > 0) return true;
|
|
5434
|
+
if (q.calculated_fields && q.calculated_fields.length > 0) return true;
|
|
5435
|
+
if (q.group_by && q.group_by.length > 0) return true;
|
|
5436
|
+
if (q.order_by && q.order_by.length > 0) return true;
|
|
5437
|
+
if (q.limit != null) return true;
|
|
5438
|
+
if (q.offset != null) return true;
|
|
5439
|
+
if (q.time_series) return true;
|
|
5440
|
+
return false;
|
|
5441
|
+
}, []);
|
|
5442
|
+
const handleModeSwitch = useCallback((newMode) => {
|
|
5443
|
+
if (newMode === "guided" && (dataSourceMode === "advanced" || dataSourceMode === "saved") && queryHasAdvancedFeatures(query)) {
|
|
5444
|
+
const confirmed = window.confirm(
|
|
5445
|
+
"This query uses advanced features (e.g. joins, calculated fields, grouping, sorting, pagination, time series) that Guided mode may not fully represent. The query will be preserved but some settings may not be editable in Guided mode.\n\nSwitch to Guided mode?"
|
|
5446
|
+
);
|
|
5447
|
+
if (!confirmed) return;
|
|
5448
|
+
}
|
|
5449
|
+
setDataSourceMode(newMode);
|
|
5450
|
+
}, [dataSourceMode, query, queryHasAdvancedFeatures]);
|
|
5353
5451
|
const handleSavedQuerySelect = useCallback((savedQuery) => {
|
|
5354
5452
|
setQuery(savedQuery.query);
|
|
5355
5453
|
}, []);
|
|
@@ -5366,11 +5464,10 @@ function WidgetEditorPage({
|
|
|
5366
5464
|
id: widget?.id ?? generateId(),
|
|
5367
5465
|
type,
|
|
5368
5466
|
title,
|
|
5369
|
-
config,
|
|
5467
|
+
config: { ...config, data_source_mode: dataSourceMode },
|
|
5370
5468
|
query,
|
|
5371
5469
|
position,
|
|
5372
|
-
hyperlink
|
|
5373
|
-
dataSourceMode
|
|
5470
|
+
hyperlink
|
|
5374
5471
|
};
|
|
5375
5472
|
onSave(savedWidget);
|
|
5376
5473
|
}, [widget, type, title, config, query, position, hyperlink, dataSourceMode, onSave]);
|
|
@@ -5396,7 +5493,8 @@ function WidgetEditorPage({
|
|
|
5396
5493
|
justifyContent: "space-between",
|
|
5397
5494
|
padding: `${theme.spacing.md} ${theme.spacing.lg}`,
|
|
5398
5495
|
borderBottom: `1px solid ${theme.colors.border}`,
|
|
5399
|
-
backgroundColor: theme.colors.surface
|
|
5496
|
+
backgroundColor: theme.colors.surface,
|
|
5497
|
+
flexShrink: 0
|
|
5400
5498
|
};
|
|
5401
5499
|
const headerLeftStyle = {
|
|
5402
5500
|
display: "flex",
|
|
@@ -5427,38 +5525,28 @@ function WidgetEditorPage({
|
|
|
5427
5525
|
};
|
|
5428
5526
|
const bodyStyle = {
|
|
5429
5527
|
flex: 1,
|
|
5430
|
-
|
|
5431
|
-
|
|
5528
|
+
overflow: "auto",
|
|
5529
|
+
display: "grid",
|
|
5530
|
+
gridTemplateColumns: "360px 1fr"
|
|
5432
5531
|
};
|
|
5433
5532
|
const leftPanelStyle = {
|
|
5434
|
-
width: "320px",
|
|
5435
|
-
flexShrink: 0,
|
|
5436
5533
|
borderRight: `1px solid ${theme.colors.border}`,
|
|
5437
|
-
overflow: "auto",
|
|
5438
5534
|
padding: theme.spacing.md,
|
|
5535
|
+
paddingBottom: theme.spacing.xl,
|
|
5439
5536
|
display: "flex",
|
|
5440
5537
|
flexDirection: "column",
|
|
5441
5538
|
gap: theme.spacing.lg
|
|
5442
5539
|
};
|
|
5443
5540
|
const mainPanelStyle = {
|
|
5444
|
-
|
|
5445
|
-
display: "flex",
|
|
5446
|
-
flexDirection: "column",
|
|
5447
|
-
minHeight: 0
|
|
5541
|
+
minWidth: 0
|
|
5448
5542
|
};
|
|
5449
5543
|
const previewPanelStyle = {
|
|
5450
|
-
height: "
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
borderBottom: `1px solid ${theme.colors.border}`
|
|
5454
|
-
};
|
|
5455
|
-
const dataSourcePanelStyle = {
|
|
5456
|
-
flex: "1 1 auto",
|
|
5457
|
-
display: "flex",
|
|
5458
|
-
flexDirection: "column",
|
|
5459
|
-
minHeight: 0,
|
|
5544
|
+
height: "440px",
|
|
5545
|
+
padding: theme.spacing.lg,
|
|
5546
|
+
borderBottom: `1px solid ${theme.colors.border}`,
|
|
5460
5547
|
overflow: "hidden"
|
|
5461
5548
|
};
|
|
5549
|
+
const dataSourcePanelStyle = {};
|
|
5462
5550
|
const dataSourceHeaderStyle = {
|
|
5463
5551
|
display: "flex",
|
|
5464
5552
|
alignItems: "center",
|
|
@@ -5478,15 +5566,12 @@ function WidgetEditorPage({
|
|
|
5478
5566
|
transition: "all 0.15s ease"
|
|
5479
5567
|
});
|
|
5480
5568
|
const dataSourceContentStyle = {
|
|
5481
|
-
flex: "1 1 auto",
|
|
5482
|
-
overflow: "auto",
|
|
5483
5569
|
padding: theme.spacing.md,
|
|
5484
|
-
paddingBottom: "
|
|
5485
|
-
// Extra
|
|
5486
|
-
minHeight: "250px"
|
|
5570
|
+
paddingBottom: "200px"
|
|
5571
|
+
// Extra padding to create scroll room for filters
|
|
5487
5572
|
};
|
|
5488
5573
|
const sectionStyle = {
|
|
5489
|
-
|
|
5574
|
+
// Note: Parent has flex gap for spacing between sections
|
|
5490
5575
|
};
|
|
5491
5576
|
const sectionTitleStyle = {
|
|
5492
5577
|
fontSize: theme.fontSizes.xs,
|
|
@@ -5880,30 +5965,39 @@ function WidgetEditorPage({
|
|
|
5880
5965
|
/* @__PURE__ */ jsxs("div", { style: dataSourceHeaderStyle, children: [
|
|
5881
5966
|
/* @__PURE__ */ jsx("span", { style: { fontSize: theme.fontSizes.sm, fontWeight: 500, marginRight: "auto" }, children: "Data Source" }),
|
|
5882
5967
|
/* @__PURE__ */ jsx(
|
|
5883
|
-
|
|
5884
|
-
{
|
|
5885
|
-
type: "button",
|
|
5886
|
-
style: tabStyle(dataSourceMode === "guided"),
|
|
5887
|
-
onClick: () => setDataSourceMode("guided"),
|
|
5888
|
-
children: "Guided"
|
|
5889
|
-
}
|
|
5890
|
-
),
|
|
5891
|
-
/* @__PURE__ */ jsx(
|
|
5892
|
-
"button",
|
|
5968
|
+
Tooltip,
|
|
5893
5969
|
{
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
children:
|
|
5970
|
+
content: "Quick setup: pick columns from dropdowns to build your chart",
|
|
5971
|
+
position: "bottom",
|
|
5972
|
+
style: { whiteSpace: "normal" },
|
|
5973
|
+
children: /* @__PURE__ */ jsx(
|
|
5974
|
+
"button",
|
|
5975
|
+
{
|
|
5976
|
+
type: "button",
|
|
5977
|
+
"data-testid": "data-source-mode-guided",
|
|
5978
|
+
style: tabStyle(dataSourceMode === "guided"),
|
|
5979
|
+
onClick: () => handleModeSwitch("guided"),
|
|
5980
|
+
children: "Guided"
|
|
5981
|
+
}
|
|
5982
|
+
)
|
|
5898
5983
|
}
|
|
5899
5984
|
),
|
|
5900
5985
|
/* @__PURE__ */ jsx(
|
|
5901
|
-
|
|
5986
|
+
Tooltip,
|
|
5902
5987
|
{
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
children:
|
|
5988
|
+
content: "Full control: combine tables, add filters, and create custom calculations",
|
|
5989
|
+
position: "bottom",
|
|
5990
|
+
style: { whiteSpace: "normal" },
|
|
5991
|
+
children: /* @__PURE__ */ jsx(
|
|
5992
|
+
"button",
|
|
5993
|
+
{
|
|
5994
|
+
type: "button",
|
|
5995
|
+
"data-testid": "data-source-mode-advanced",
|
|
5996
|
+
style: tabStyle(dataSourceMode === "advanced"),
|
|
5997
|
+
onClick: () => handleModeSwitch("advanced"),
|
|
5998
|
+
children: "Advanced"
|
|
5999
|
+
}
|
|
6000
|
+
)
|
|
5907
6001
|
}
|
|
5908
6002
|
)
|
|
5909
6003
|
] }),
|
|
@@ -7506,5 +7600,5 @@ var DashboardDialog = forwardRef(
|
|
|
7506
7600
|
);
|
|
7507
7601
|
|
|
7508
7602
|
export { Dashboard, DashboardCard, DashboardContext, DashboardDialog, DashboardEditor, DashboardLayout, DashboardList, DashboardProvider, DateRangeFilter, EditableDashboardLayout, EditorToolbar, FilterBar, LazyWidget, MultiSelectFilter, SelectFilter, TextFilter, Widget, WidgetContainer, WidgetContent, WidgetEditor, WidgetEditorPage, WidgetHeader, WidgetPalette, WidgetPlaceholder, WidgetPreview, WidgetTypeSelector, useAutoRefresh, useDashboard, useDashboardFilters, useFullscreen, useWidget, useWidgetVisibility };
|
|
7509
|
-
//# sourceMappingURL=chunk-
|
|
7510
|
-
//# sourceMappingURL=chunk-
|
|
7603
|
+
//# sourceMappingURL=chunk-3LDRRDJ6.js.map
|
|
7604
|
+
//# sourceMappingURL=chunk-3LDRRDJ6.js.map
|