@datawheel/data-explorer 1.3.3 → 1.4.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.
- package/dist/main.d.mts +1 -0
- package/dist/main.mjs +276 -48
- package/package.json +1 -1
package/dist/main.d.mts
CHANGED
|
@@ -451,6 +451,7 @@ interface FilterItem extends QueryParamsItem {
|
|
|
451
451
|
conditionOne: [`${Comparison}`, string, number];
|
|
452
452
|
conditionTwo?: [`${Comparison}`, string, number];
|
|
453
453
|
joint: "and" | "or";
|
|
454
|
+
type?: "greaterThan" | "lessThan" | "between";
|
|
454
455
|
}
|
|
455
456
|
interface MeasureItem extends QueryParamsItem {
|
|
456
457
|
name: string;
|
package/dist/main.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { keyframes, createStyles, Select, Center, Text, rem, Input, Box, Stack, Group, Button, SimpleGrid, Flex, ScrollArea, LoadingOverlay, Table, MultiSelect, NumberInput, Menu, ActionIcon, UnstyledButton, Loader, Container, Title, useMantineTheme, TextInput, CopyButton, MantineProvider, Alert, Space, Modal, Tooltip, useComponentDefaultProps, Skeleton, Anchor, Paper, packSx, CloseButton, Tabs, ThemeIcon, Drawer, Switch, Divider, Accordion, Popover, Checkbox } from '@mantine/core';
|
|
1
|
+
import { keyframes, createStyles, Select, Center, Text, rem, Input, Box, Stack, Group, Button, SimpleGrid, Flex, ScrollArea, LoadingOverlay, Table, MultiSelect, NumberInput, Menu, ActionIcon, UnstyledButton, Loader, Container, Title, useMantineTheme, TextInput, CopyButton, MantineProvider, Alert, Space, Pagination, Modal, Tooltip, useComponentDefaultProps, Skeleton, Anchor, Paper, packSx, CloseButton, Tabs, ThemeIcon, Drawer, Switch, Divider, Accordion, Popover, Checkbox } from '@mantine/core';
|
|
2
2
|
import { useClipboard, useDebouncedState, useMediaQuery, useFullscreen, useDisclosure } from '@mantine/hooks';
|
|
3
3
|
import { IconWorld, IconExternalLink, IconClipboard, IconSettings, IconMathGreater, IconMathLower, IconArrowsLeftRight, IconWorldWww, IconClipboardCheck, IconAlertCircle, IconAlertTriangle, IconLanguage, IconCopy, IconArrowLeft, IconArrowRight, IconX, IconChevronLeft, IconChevronRight, IconVectorTriangle, IconPhotoDown, IconDownload, IconArrowsMinimize, IconArrowsMaximize, IconCheck, IconShare, IconSearch, IconDotsVertical, IconTrash, IconPlus, IconStack3, IconInfoCircleFilled, IconArrowsSort, IconSortDescendingNumbers, IconSortDescendingLetters, IconSortAscendingNumbers, IconSortAscendingLetters, IconHelpCircle, IconFilterOff, IconFilter, IconBox, IconClock, IconAdjustments } from '@tabler/icons-react';
|
|
4
4
|
import * as React15 from 'react';
|
|
5
|
-
import React15__default, { createContext, forwardRef, useMemo, useCallback, useContext, useRef, useEffect, useState, Suspense, useLayoutEffect } from 'react';
|
|
5
|
+
import React15__default, { createContext, forwardRef, useMemo, memo, useCallback, useContext, useRef, useEffect, useState, Suspense, useLayoutEffect } from 'react';
|
|
6
6
|
import { translationFactory } from '@datawheel/use-translation';
|
|
7
7
|
import { createSlice, createSelector, combineReducers, configureStore, bindActionCreators } from '@reduxjs/toolkit';
|
|
8
8
|
import { useSelector as useSelector$1, useStore, Provider as Provider$1 } from 'react-redux';
|
|
9
9
|
import { useNavigate, BrowserRouter, useLocation } from 'react-router-dom';
|
|
10
|
-
import { VizbuilderProvider, useVizbuilderContext, ErrorBoundary, useD3plusConfig } from '@datawheel/vizbuilder/react';
|
|
10
|
+
import { VizbuilderProvider, useVizbuilderContext, d3plusConfigBuilder, ErrorBoundary, useD3plusConfig } from '@datawheel/vizbuilder/react';
|
|
11
11
|
import { QueryClient, useQuery, QueryClientProvider, keepPreviousData, useMutation } from '@tanstack/react-query';
|
|
12
12
|
import { assign } from 'd3plus-common';
|
|
13
13
|
import identity2 from 'lodash-es/identity';
|
|
@@ -369,7 +369,8 @@ function getAnnotation(item, key, locale = "xx") {
|
|
|
369
369
|
return ann[`${key}_${locale}`] || ann[`${key}_${locale.slice(0, 2)}`] || ann[key];
|
|
370
370
|
}
|
|
371
371
|
function parseNumeric(value, elseValue) {
|
|
372
|
-
|
|
372
|
+
const result = Number.parseFloat(String(value));
|
|
373
|
+
return Number.isFinite(result) ? result : elseValue;
|
|
373
374
|
}
|
|
374
375
|
|
|
375
376
|
// src/utils/array.ts
|
|
@@ -786,15 +787,16 @@ function buildFilter(props) {
|
|
|
786
787
|
measure: props.measure || `${props.name}`,
|
|
787
788
|
conditionOne: props.conditionOne || [
|
|
788
789
|
props.const1 ? `${props.const1[0]}` : `${"gt" /* GT */}`,
|
|
789
|
-
props.const1 ? props.const1[1].toString() : props.inputtedValue || "
|
|
790
|
-
props.const1 ? props.const1[1] : parseNumeric(props.interpretedValue,
|
|
790
|
+
props.const1 ? props.const1[1].toString() : props.inputtedValue || "",
|
|
791
|
+
props.const1 ? props.const1[1] : parseNumeric(props.interpretedValue, NaN)
|
|
791
792
|
],
|
|
792
|
-
conditionTwo: props.conditionTwo || [
|
|
793
|
-
|
|
794
|
-
props.const2
|
|
795
|
-
props.const2
|
|
796
|
-
],
|
|
797
|
-
joint: props.joint === "or" ? "or" : "and"
|
|
793
|
+
conditionTwo: props.conditionTwo || (props.const2 ? [
|
|
794
|
+
`${props.const2[0]}`,
|
|
795
|
+
props.const2[1].toString(),
|
|
796
|
+
parseNumeric(props.const2[1].toString(), NaN)
|
|
797
|
+
] : void 0),
|
|
798
|
+
joint: props.joint === "or" ? "or" : "and",
|
|
799
|
+
type: props.type
|
|
798
800
|
};
|
|
799
801
|
}
|
|
800
802
|
function buildMeasure(props) {
|
|
@@ -978,13 +980,28 @@ function filterParse(item) {
|
|
|
978
980
|
const condition = item.slice(indexName + 1);
|
|
979
981
|
const joint = condition.includes(".and.") ? "and" : "or";
|
|
980
982
|
const [cond1, cond2] = condition.split(`.${joint}.`);
|
|
983
|
+
const conditionOne = filterParseCondition(cond1);
|
|
984
|
+
const conditionTwo = cond2 ? filterParseCondition(cond2) : void 0;
|
|
985
|
+
let type;
|
|
986
|
+
if (conditionOne && conditionTwo) {
|
|
987
|
+
if (conditionOne[0] === "gte" /* GTE */ && conditionTwo[0] === "lte" /* LTE */) {
|
|
988
|
+
type = "between";
|
|
989
|
+
}
|
|
990
|
+
} else if (conditionOne) {
|
|
991
|
+
if (conditionOne[0] === "gte" /* GTE */ || conditionOne[0] === "gt" /* GT */) {
|
|
992
|
+
type = "greaterThan";
|
|
993
|
+
} else if (conditionOne[0] === "lte" /* LTE */ || conditionOne[0] === "lt" /* LT */) {
|
|
994
|
+
type = "lessThan";
|
|
995
|
+
}
|
|
996
|
+
}
|
|
981
997
|
return {
|
|
982
998
|
key: Math.random().toString(16).slice(2),
|
|
983
999
|
active: true,
|
|
984
1000
|
measure: item.slice(0, indexName),
|
|
985
1001
|
joint,
|
|
986
|
-
conditionOne
|
|
987
|
-
conditionTwo
|
|
1002
|
+
conditionOne,
|
|
1003
|
+
conditionTwo,
|
|
1004
|
+
type
|
|
988
1005
|
};
|
|
989
1006
|
}
|
|
990
1007
|
|
|
@@ -2103,6 +2120,14 @@ function QueryProvider({ children, defaultCube }) {
|
|
|
2103
2120
|
});
|
|
2104
2121
|
});
|
|
2105
2122
|
if (newQuery) {
|
|
2123
|
+
Object.values(newQuery.params.filters).forEach((filter) => {
|
|
2124
|
+
const currentFilter = Object.values(queryItem.params.filters).find(
|
|
2125
|
+
(f) => f.measure === filter.measure
|
|
2126
|
+
);
|
|
2127
|
+
if (currentFilter) {
|
|
2128
|
+
filter.type = currentFilter.type;
|
|
2129
|
+
}
|
|
2130
|
+
});
|
|
2106
2131
|
const promises = [...restDrilldowns, ...Object.values(newQuery.params.drilldowns)].map(
|
|
2107
2132
|
(dd) => {
|
|
2108
2133
|
const currentDrilldown = queryItem.params.drilldowns[dd.key];
|
|
@@ -3117,26 +3142,60 @@ function getFiltersConditions(fn, value) {
|
|
|
3117
3142
|
const comparisonMap = /* @__PURE__ */ new Map([
|
|
3118
3143
|
[
|
|
3119
3144
|
"greaterThan",
|
|
3120
|
-
(value2) =>
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3145
|
+
(value2) => {
|
|
3146
|
+
const val = value2[0] === "" ? "" : String(value2[0]);
|
|
3147
|
+
const num = value2[0] === "" ? NaN : Number(value2[0]);
|
|
3148
|
+
return {
|
|
3149
|
+
conditionOne: ["gte" /* GTE */, val, num],
|
|
3150
|
+
conditionTwo: void 0,
|
|
3151
|
+
type: "greaterThan"
|
|
3152
|
+
};
|
|
3153
|
+
}
|
|
3124
3154
|
],
|
|
3125
3155
|
[
|
|
3126
3156
|
"lessThan",
|
|
3127
|
-
(value2) =>
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3157
|
+
(value2) => {
|
|
3158
|
+
const val = value2[0] === "" ? "" : String(value2[0]);
|
|
3159
|
+
const num = value2[0] === "" ? NaN : Number(value2[0]);
|
|
3160
|
+
return {
|
|
3161
|
+
conditionOne: ["lte" /* LTE */, val, num],
|
|
3162
|
+
conditionTwo: void 0,
|
|
3163
|
+
type: "lessThan"
|
|
3164
|
+
};
|
|
3165
|
+
}
|
|
3131
3166
|
],
|
|
3132
3167
|
[
|
|
3133
3168
|
"between",
|
|
3134
3169
|
(values) => {
|
|
3135
3170
|
const [min, max] = values;
|
|
3171
|
+
const isMinValid = min !== "" && min !== null && min !== void 0;
|
|
3172
|
+
const isMaxValid = max !== "" && max !== null && max !== void 0;
|
|
3173
|
+
if (isMinValid && isMaxValid) {
|
|
3174
|
+
return {
|
|
3175
|
+
conditionOne: ["gte" /* GTE */, String(min), Number(min)],
|
|
3176
|
+
conditionTwo: ["lte" /* LTE */, String(max), Number(max)],
|
|
3177
|
+
joint: "and",
|
|
3178
|
+
type: "between"
|
|
3179
|
+
};
|
|
3180
|
+
}
|
|
3181
|
+
if (isMinValid) {
|
|
3182
|
+
return {
|
|
3183
|
+
conditionOne: ["gte" /* GTE */, String(min), Number(min)],
|
|
3184
|
+
conditionTwo: void 0,
|
|
3185
|
+
type: "between"
|
|
3186
|
+
};
|
|
3187
|
+
}
|
|
3188
|
+
if (isMaxValid) {
|
|
3189
|
+
return {
|
|
3190
|
+
conditionOne: ["lte" /* LTE */, String(max), Number(max)],
|
|
3191
|
+
conditionTwo: void 0,
|
|
3192
|
+
type: "between"
|
|
3193
|
+
};
|
|
3194
|
+
}
|
|
3136
3195
|
return {
|
|
3137
|
-
conditionOne: ["gte" /* GTE */,
|
|
3138
|
-
conditionTwo:
|
|
3139
|
-
|
|
3196
|
+
conditionOne: ["gte" /* GTE */, "", NaN],
|
|
3197
|
+
conditionTwo: void 0,
|
|
3198
|
+
type: "between"
|
|
3140
3199
|
};
|
|
3141
3200
|
}
|
|
3142
3201
|
]
|
|
@@ -4132,6 +4191,9 @@ function getFilterfnKey(type) {
|
|
|
4132
4191
|
}
|
|
4133
4192
|
}
|
|
4134
4193
|
function getFilterFn(filter) {
|
|
4194
|
+
if (filter.type) {
|
|
4195
|
+
return filter.type;
|
|
4196
|
+
}
|
|
4135
4197
|
if (filter.conditionOne && filter.conditionTwo) {
|
|
4136
4198
|
if (filter.conditionOne[0] === "gte" /* GTE */ && filter.conditionTwo[0] === "lte" /* LTE */) {
|
|
4137
4199
|
return "between";
|
|
@@ -4163,13 +4225,14 @@ function NumberInputComponent({ text, filter }) {
|
|
|
4163
4225
|
};
|
|
4164
4226
|
}, [debouncedUpdateUrl]);
|
|
4165
4227
|
function getFilterValue(filter2) {
|
|
4166
|
-
return isNotValid(filter2.conditionOne[2])
|
|
4228
|
+
return isNotValid(filter2.conditionOne[2]) ? "" : filter2.conditionOne[2];
|
|
4167
4229
|
}
|
|
4168
4230
|
function onInputChange({ filter: filter2, value }) {
|
|
4169
4231
|
const isEmpty = value === "";
|
|
4170
|
-
const
|
|
4232
|
+
const currentType = getFilterFn(filter2) || "greaterThan";
|
|
4233
|
+
const conditions = getFiltersConditions(currentType, [value]) || {};
|
|
4171
4234
|
const active = !isEmpty;
|
|
4172
|
-
const newFilter = buildFilter({ ...filter2, active, ...conditions });
|
|
4235
|
+
const newFilter = buildFilter({ ...filter2, active, ...conditions, type: currentType });
|
|
4173
4236
|
actions2.updateFilter(newFilter);
|
|
4174
4237
|
const newQuery = buildQuery(cloneDeep(queryItem));
|
|
4175
4238
|
newQuery.params.filters[filter2.key] = newFilter;
|
|
@@ -4204,9 +4267,10 @@ var MinMax = ({ filter, hideControls, ...rest }) => {
|
|
|
4204
4267
|
}, [debouncedUpdateUrl]);
|
|
4205
4268
|
function onInputChangeMinMax(props) {
|
|
4206
4269
|
const { filter: filter2, min: min2, max: max2 } = props;
|
|
4207
|
-
const
|
|
4208
|
-
const
|
|
4209
|
-
const
|
|
4270
|
+
const currentType = getFilterFn(filter2) || "between";
|
|
4271
|
+
const conditions = getFiltersConditions(currentType, [min2, max2]) || {};
|
|
4272
|
+
const active = min2 !== "" || max2 !== "";
|
|
4273
|
+
const newFilter = buildFilter({ ...filter2, active, ...conditions, type: currentType });
|
|
4210
4274
|
actions2.updateFilter(newFilter);
|
|
4211
4275
|
const newQuery = buildQuery(cloneDeep(queryItem));
|
|
4212
4276
|
newQuery.params.filters[filter2.key] = newFilter;
|
|
@@ -4214,7 +4278,7 @@ var MinMax = ({ filter, hideControls, ...rest }) => {
|
|
|
4214
4278
|
}
|
|
4215
4279
|
function getFilterValue(condition) {
|
|
4216
4280
|
if (condition) {
|
|
4217
|
-
return isNotValid(condition[2])
|
|
4281
|
+
return isNotValid(condition[2]) ? "" : condition[2];
|
|
4218
4282
|
}
|
|
4219
4283
|
return "";
|
|
4220
4284
|
}
|
|
@@ -4244,14 +4308,26 @@ var MinMax = ({ filter, hideControls, ...rest }) => {
|
|
|
4244
4308
|
};
|
|
4245
4309
|
function FilterFnsMenu({ filter }) {
|
|
4246
4310
|
const actions2 = useActions();
|
|
4311
|
+
const updateUrl = useUpdateUrl();
|
|
4312
|
+
const queryItem = useSelector$1(selectCurrentQueryItem);
|
|
4247
4313
|
const { translate: t } = useTranslation();
|
|
4248
4314
|
return /* @__PURE__ */ React15__default.createElement(React15__default.Fragment, null, /* @__PURE__ */ React15__default.createElement(Menu, { shadow: "md", width: 200 }, /* @__PURE__ */ React15__default.createElement(Menu.Target, null, /* @__PURE__ */ React15__default.createElement(ActionIcon, { size: "xs" }, /* @__PURE__ */ React15__default.createElement(IconSettings, null))), /* @__PURE__ */ React15__default.createElement(Menu.Dropdown, null, /* @__PURE__ */ React15__default.createElement(Menu.Label, null, t("params.filter_mode")), /* @__PURE__ */ React15__default.createElement(
|
|
4249
4315
|
Menu.Item,
|
|
4250
4316
|
{
|
|
4251
4317
|
icon: /* @__PURE__ */ React15__default.createElement(IconMathGreater, { size: 14 }),
|
|
4252
4318
|
onClick: () => {
|
|
4253
|
-
const
|
|
4254
|
-
|
|
4319
|
+
const currentType = "greaterThan";
|
|
4320
|
+
const conditions = getFiltersConditions(currentType, [""]) || {};
|
|
4321
|
+
const newFilter = buildFilter({
|
|
4322
|
+
...filter,
|
|
4323
|
+
...conditions,
|
|
4324
|
+
active: false,
|
|
4325
|
+
type: currentType
|
|
4326
|
+
});
|
|
4327
|
+
actions2.updateFilter(newFilter);
|
|
4328
|
+
const newQuery = buildQuery(cloneDeep(queryItem));
|
|
4329
|
+
newQuery.params.filters[filter.key] = newFilter;
|
|
4330
|
+
updateUrl(newQuery);
|
|
4255
4331
|
}
|
|
4256
4332
|
},
|
|
4257
4333
|
t("comparison.GT")
|
|
@@ -4260,8 +4336,18 @@ function FilterFnsMenu({ filter }) {
|
|
|
4260
4336
|
{
|
|
4261
4337
|
icon: /* @__PURE__ */ React15__default.createElement(IconMathLower, { size: 14 }),
|
|
4262
4338
|
onClick: () => {
|
|
4263
|
-
const
|
|
4264
|
-
|
|
4339
|
+
const currentType = "lessThan";
|
|
4340
|
+
const conditions = getFiltersConditions(currentType, [""]) || {};
|
|
4341
|
+
const newFilter = buildFilter({
|
|
4342
|
+
...filter,
|
|
4343
|
+
...conditions,
|
|
4344
|
+
active: false,
|
|
4345
|
+
type: currentType
|
|
4346
|
+
});
|
|
4347
|
+
actions2.updateFilter(newFilter);
|
|
4348
|
+
const newQuery = buildQuery(cloneDeep(queryItem));
|
|
4349
|
+
newQuery.params.filters[filter.key] = newFilter;
|
|
4350
|
+
updateUrl(newQuery);
|
|
4265
4351
|
}
|
|
4266
4352
|
},
|
|
4267
4353
|
t("comparison.LT")
|
|
@@ -4270,8 +4356,18 @@ function FilterFnsMenu({ filter }) {
|
|
|
4270
4356
|
{
|
|
4271
4357
|
icon: /* @__PURE__ */ React15__default.createElement(IconArrowsLeftRight, { size: 14 }),
|
|
4272
4358
|
onClick: () => {
|
|
4273
|
-
const
|
|
4274
|
-
|
|
4359
|
+
const currentType = "between";
|
|
4360
|
+
const conditions = getFiltersConditions(currentType, ["", ""]) || {};
|
|
4361
|
+
const newFilter = buildFilter({
|
|
4362
|
+
...filter,
|
|
4363
|
+
...conditions,
|
|
4364
|
+
active: false,
|
|
4365
|
+
type: currentType
|
|
4366
|
+
});
|
|
4367
|
+
actions2.updateFilter(newFilter);
|
|
4368
|
+
const newQuery = buildQuery(cloneDeep(queryItem));
|
|
4369
|
+
newQuery.params.filters[filter.key] = newFilter;
|
|
4370
|
+
updateUrl(newQuery);
|
|
4275
4371
|
}
|
|
4276
4372
|
},
|
|
4277
4373
|
t("comparison.BT")
|
|
@@ -6649,6 +6745,31 @@ var iconByFormat = {
|
|
|
6649
6745
|
png: IconPhotoDown,
|
|
6650
6746
|
svg: IconVectorTriangle
|
|
6651
6747
|
};
|
|
6748
|
+
var ChartRenderer = memo((props) => {
|
|
6749
|
+
const { ChartComponent, config, containerRef, overlayRef, onReady } = props;
|
|
6750
|
+
React15__default.useEffect(() => {
|
|
6751
|
+
const box = containerRef.current;
|
|
6752
|
+
if (!box) return;
|
|
6753
|
+
const checkSvg = () => {
|
|
6754
|
+
const svg = box.querySelector("svg");
|
|
6755
|
+
if (svg) {
|
|
6756
|
+
if (overlayRef.current) {
|
|
6757
|
+
overlayRef.current.style.display = "none";
|
|
6758
|
+
}
|
|
6759
|
+
onReady();
|
|
6760
|
+
return true;
|
|
6761
|
+
}
|
|
6762
|
+
return false;
|
|
6763
|
+
};
|
|
6764
|
+
if (checkSvg()) return;
|
|
6765
|
+
const observer = new MutationObserver(() => {
|
|
6766
|
+
if (checkSvg()) observer.disconnect();
|
|
6767
|
+
});
|
|
6768
|
+
observer.observe(box, { childList: true, subtree: true });
|
|
6769
|
+
return () => observer.disconnect();
|
|
6770
|
+
}, [containerRef, overlayRef, onReady]);
|
|
6771
|
+
return /* @__PURE__ */ React15__default.createElement(ChartComponent, { config });
|
|
6772
|
+
});
|
|
6652
6773
|
function ChartCard(props) {
|
|
6653
6774
|
const { chart, isFullMode, onFocus, height } = props;
|
|
6654
6775
|
const { dataset } = chart.datagroup;
|
|
@@ -6723,8 +6844,46 @@ function ChartCard(props) {
|
|
|
6723
6844
|
copied ? translate("share_copied") : translate("action_share")
|
|
6724
6845
|
));
|
|
6725
6846
|
}, [translate]);
|
|
6847
|
+
const [isLoaded, setIsLoaded] = useState(false);
|
|
6848
|
+
const [shouldRenderChart, setShouldRenderChart] = useState(false);
|
|
6849
|
+
const overlayRef = useRef(null);
|
|
6850
|
+
React15__default.useEffect(() => {
|
|
6851
|
+
setIsLoaded(false);
|
|
6852
|
+
setShouldRenderChart(false);
|
|
6853
|
+
if (overlayRef.current) {
|
|
6854
|
+
overlayRef.current.style.display = "block";
|
|
6855
|
+
}
|
|
6856
|
+
}, [chart.key]);
|
|
6857
|
+
React15__default.useEffect(() => {
|
|
6858
|
+
if (ChartComponent && (inView || hasBeenInView) && !shouldRenderChart) {
|
|
6859
|
+
const timer = setTimeout(() => {
|
|
6860
|
+
window.requestAnimationFrame(() => {
|
|
6861
|
+
window.requestAnimationFrame(() => {
|
|
6862
|
+
setShouldRenderChart(true);
|
|
6863
|
+
});
|
|
6864
|
+
});
|
|
6865
|
+
}, 500);
|
|
6866
|
+
return () => clearTimeout(timer);
|
|
6867
|
+
}
|
|
6868
|
+
}, [ChartComponent, inView, hasBeenInView, shouldRenderChart]);
|
|
6869
|
+
React15__default.useEffect(() => {
|
|
6870
|
+
const box = nodeRef.current;
|
|
6871
|
+
if (!box || !shouldRenderChart || isLoaded) return;
|
|
6872
|
+
const observer = new MutationObserver(() => {
|
|
6873
|
+
const svg = box.querySelector("svg");
|
|
6874
|
+
if (svg) {
|
|
6875
|
+
window.requestAnimationFrame(() => setIsLoaded(true));
|
|
6876
|
+
observer.disconnect();
|
|
6877
|
+
}
|
|
6878
|
+
});
|
|
6879
|
+
observer.observe(box, { childList: true, subtree: true });
|
|
6880
|
+
if (box.querySelector("svg")) {
|
|
6881
|
+
setIsLoaded(true);
|
|
6882
|
+
}
|
|
6883
|
+
return () => observer.disconnect();
|
|
6884
|
+
}, [shouldRenderChart, isLoaded]);
|
|
6726
6885
|
if (!ChartComponent || !config) return null;
|
|
6727
|
-
const resolvedHeight = height ? height : isFullMode ? "calc(100vh - 3rem)" :
|
|
6886
|
+
const resolvedHeight = height ? height : isFullMode ? "calc(100vh - 3rem)" : "calc((80vh - 4rem) / 2)";
|
|
6728
6887
|
return /* @__PURE__ */ React15__default.createElement(ErrorBoundary, { ErrorContent: CardErrorComponent }, /* @__PURE__ */ React15__default.createElement(
|
|
6729
6888
|
Paper,
|
|
6730
6889
|
{
|
|
@@ -6735,11 +6894,42 @@ function ChartCard(props) {
|
|
|
6735
6894
|
/* @__PURE__ */ React15__default.createElement(Stack, { spacing: "xs", p: "xs", style: { position: "relative" }, h: "100%", w: "100%" }, /* @__PURE__ */ React15__default.createElement(Group, { position: "center", spacing: "xs", align: "center" }, isFullMode && shareButton, downloadButtons, onFocus && focusButton), /* @__PURE__ */ React15__default.createElement(
|
|
6736
6895
|
Box,
|
|
6737
6896
|
{
|
|
6738
|
-
style: { flex: "1 1 auto" },
|
|
6897
|
+
style: { flex: "1 1 auto", position: "relative" },
|
|
6739
6898
|
ref: setRefs,
|
|
6740
6899
|
sx: { "& > .viz": { height: "100%" } }
|
|
6741
6900
|
},
|
|
6742
|
-
|
|
6901
|
+
/* @__PURE__ */ React15__default.createElement(
|
|
6902
|
+
Box,
|
|
6903
|
+
{
|
|
6904
|
+
ref: overlayRef,
|
|
6905
|
+
style: {
|
|
6906
|
+
position: "absolute",
|
|
6907
|
+
top: 0,
|
|
6908
|
+
left: 0,
|
|
6909
|
+
right: 0,
|
|
6910
|
+
bottom: 0,
|
|
6911
|
+
zIndex: 100
|
|
6912
|
+
}
|
|
6913
|
+
},
|
|
6914
|
+
/* @__PURE__ */ React15__default.createElement(
|
|
6915
|
+
LoadingOverlay,
|
|
6916
|
+
{
|
|
6917
|
+
visible: !isLoaded,
|
|
6918
|
+
overlayBlur: 2,
|
|
6919
|
+
transitionDuration: 0
|
|
6920
|
+
}
|
|
6921
|
+
)
|
|
6922
|
+
),
|
|
6923
|
+
ChartComponent && (inView || hasBeenInView) && shouldRenderChart ? /* @__PURE__ */ React15__default.createElement(
|
|
6924
|
+
ChartRenderer,
|
|
6925
|
+
{
|
|
6926
|
+
ChartComponent,
|
|
6927
|
+
config,
|
|
6928
|
+
containerRef: nodeRef,
|
|
6929
|
+
overlayRef,
|
|
6930
|
+
onReady: () => setIsLoaded(true)
|
|
6931
|
+
}
|
|
6932
|
+
) : /* @__PURE__ */ React15__default.createElement("div", { style: { height: "100%", width: "100%" } })
|
|
6743
6933
|
))
|
|
6744
6934
|
));
|
|
6745
6935
|
}
|
|
@@ -6795,8 +6985,12 @@ function Vizbuilder(props) {
|
|
|
6795
6985
|
chartLimits,
|
|
6796
6986
|
chartTypes,
|
|
6797
6987
|
datacap,
|
|
6988
|
+
getFormatter,
|
|
6798
6989
|
getTopojsonConfig,
|
|
6799
6990
|
NonIdealState: NonIdealState2,
|
|
6991
|
+
postprocessConfig,
|
|
6992
|
+
showConfidenceInt,
|
|
6993
|
+
translate,
|
|
6800
6994
|
ViewErrorComponent
|
|
6801
6995
|
} = useVizbuilderContext();
|
|
6802
6996
|
const { actions: actions2 } = useSettings();
|
|
@@ -6812,21 +7006,46 @@ function Vizbuilder(props) {
|
|
|
6812
7006
|
});
|
|
6813
7007
|
return Object.fromEntries(charts2.map((chart2) => [chart2.key, chart2]));
|
|
6814
7008
|
}, [chartLimits, chartTypes, datacap, datasets, getTopojsonConfig]);
|
|
7009
|
+
const filteredCharts = useMemo(() => {
|
|
7010
|
+
const list = Object.values(charts);
|
|
7011
|
+
const builderParams = {
|
|
7012
|
+
fullMode: false,
|
|
7013
|
+
getFormatter,
|
|
7014
|
+
showConfidenceInt,
|
|
7015
|
+
t: translate
|
|
7016
|
+
};
|
|
7017
|
+
return list.filter((chart2) => {
|
|
7018
|
+
const builder = d3plusConfigBuilder[chart2.type];
|
|
7019
|
+
if (!builder) return false;
|
|
7020
|
+
const config = builder(chart2, builderParams);
|
|
7021
|
+
const finalConfig = postprocessConfig(config, chart2, builderParams);
|
|
7022
|
+
return finalConfig !== false;
|
|
7023
|
+
});
|
|
7024
|
+
}, [charts, getFormatter, postprocessConfig, showConfidenceInt, translate]);
|
|
7025
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
7026
|
+
const pageSize = 4;
|
|
7027
|
+
useEffect(() => {
|
|
7028
|
+
setCurrentPage(1);
|
|
7029
|
+
}, [datasets, charts]);
|
|
6815
7030
|
const content = useMemo(() => {
|
|
6816
7031
|
const isLoading = datasets.some((dataset) => Object.keys(dataset.columns).length === 0);
|
|
6817
7032
|
if (isLoading) {
|
|
6818
7033
|
console.debug("Loading datasets...", datasets);
|
|
6819
7034
|
return /* @__PURE__ */ React15__default.createElement(NonIdealState2, { status: "loading" });
|
|
6820
7035
|
}
|
|
6821
|
-
const chartList =
|
|
6822
|
-
|
|
7036
|
+
const chartList = filteredCharts.slice(
|
|
7037
|
+
(currentPage - 1) * pageSize,
|
|
7038
|
+
currentPage * pageSize
|
|
7039
|
+
);
|
|
7040
|
+
if (filteredCharts.length === 0) {
|
|
6823
7041
|
if (datasets.length === 1 && datasets[0].data.length === 1) {
|
|
6824
7042
|
return /* @__PURE__ */ React15__default.createElement(NonIdealState2, { status: "one-row" });
|
|
6825
7043
|
}
|
|
6826
7044
|
return /* @__PURE__ */ React15__default.createElement(NonIdealState2, { status: "empty" });
|
|
6827
7045
|
}
|
|
6828
7046
|
const isSingleChart = chartList.length === 1;
|
|
6829
|
-
|
|
7047
|
+
const totalPages = Math.ceil(filteredCharts.length / pageSize);
|
|
7048
|
+
return /* @__PURE__ */ React15__default.createElement(Stack, { spacing: "xl" }, /* @__PURE__ */ React15__default.createElement(
|
|
6830
7049
|
"div",
|
|
6831
7050
|
{
|
|
6832
7051
|
className: cx("vb-scrollcontainer", classes.grid, {
|
|
@@ -6854,8 +7073,17 @@ function Vizbuilder(props) {
|
|
|
6854
7073
|
}
|
|
6855
7074
|
);
|
|
6856
7075
|
})
|
|
6857
|
-
)
|
|
6858
|
-
|
|
7076
|
+
), totalPages > 1 && /* @__PURE__ */ React15__default.createElement(
|
|
7077
|
+
Pagination,
|
|
7078
|
+
{
|
|
7079
|
+
total: totalPages,
|
|
7080
|
+
value: currentPage,
|
|
7081
|
+
onChange: setCurrentPage,
|
|
7082
|
+
position: "center",
|
|
7083
|
+
mb: "xl"
|
|
7084
|
+
}
|
|
7085
|
+
));
|
|
7086
|
+
}, [filteredCharts, currentPage, classes, cx, datasets, NonIdealState2, actions2]);
|
|
6859
7087
|
const currentChart = (queryItem == null ? void 0 : queryItem.chart) || "";
|
|
6860
7088
|
const chart = charts[currentChart];
|
|
6861
7089
|
return /* @__PURE__ */ React15__default.createElement("div", { className: cls("vb-wrapper", classes.wrapper, props.className) }, props.customHeader, /* @__PURE__ */ React15__default.createElement(ErrorBoundary, { ErrorContent: ViewErrorComponent }, content), props.customFooter, /* @__PURE__ */ React15__default.createElement(
|
|
@@ -6883,7 +7111,7 @@ function useVizbuilderData() {
|
|
|
6883
7111
|
});
|
|
6884
7112
|
return query;
|
|
6885
7113
|
}
|
|
6886
|
-
var
|
|
7114
|
+
var LoadingOverlay4 = () => {
|
|
6887
7115
|
const { translate: t } = useTranslation();
|
|
6888
7116
|
const { loading: isLoading, message } = useSelector$1(selectLoadingState);
|
|
6889
7117
|
const description = !message ? void 0 : message.type === "HEAVY_QUERY" ? t("loading.message_heavyquery", message) : (
|
|
@@ -6910,7 +7138,7 @@ function VizbuilderView(props) {
|
|
|
6910
7138
|
const { cube, params } = props;
|
|
6911
7139
|
const query = useVizbuilderData();
|
|
6912
7140
|
if (query.isLoading) {
|
|
6913
|
-
return /* @__PURE__ */ React15__default.createElement(
|
|
7141
|
+
return /* @__PURE__ */ React15__default.createElement(LoadingOverlay4, { visible: true });
|
|
6914
7142
|
}
|
|
6915
7143
|
const data = query.data;
|
|
6916
7144
|
const types = (_a = query.data) == null ? void 0 : _a.types;
|