@datawheel/data-explorer 1.3.3 → 1.4.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/main.d.mts +7 -0
- package/dist/main.mjs +296 -53
- 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;
|
|
@@ -462,6 +463,7 @@ interface PropertyItem extends QueryParamsItem {
|
|
|
462
463
|
}
|
|
463
464
|
|
|
464
465
|
type Formatter = (value: number | null, locale?: string) => string;
|
|
466
|
+
type DrilldownFormatter = (value: string | null, locale?: string) => string;
|
|
465
467
|
interface PanelDescriptor {
|
|
466
468
|
key: string;
|
|
467
469
|
label: string;
|
|
@@ -1145,6 +1147,10 @@ declare function ExplorerComponent<Locale extends string>(props: {
|
|
|
1145
1147
|
* that are displayed next to the value.
|
|
1146
1148
|
* */
|
|
1147
1149
|
idFormatters?: Record<string, Formatter>;
|
|
1150
|
+
/**
|
|
1151
|
+
* Defines an index of formatter functions available for drilldowns.
|
|
1152
|
+
* */
|
|
1153
|
+
drilldownFormatters?: Record<string, DrilldownFormatter>;
|
|
1148
1154
|
/**
|
|
1149
1155
|
* Defines an alternative height for the component structure.
|
|
1150
1156
|
* @default "100vh"
|
|
@@ -1332,6 +1338,7 @@ interface SettingsContextProps {
|
|
|
1332
1338
|
defaultMembersFilter: "id" | "name" | "any";
|
|
1333
1339
|
formatters: Record<string, Formatter>;
|
|
1334
1340
|
idFormatters: Record<string, Formatter>;
|
|
1341
|
+
drilldownFormatters: Record<string, DrilldownFormatter>;
|
|
1335
1342
|
previewLimit: number;
|
|
1336
1343
|
panels: PanelDescriptor[];
|
|
1337
1344
|
paginationConfig: Pagination;
|
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
|
|
@@ -599,6 +600,7 @@ function SettingsProvider(props) {
|
|
|
599
600
|
defaultMembersFilter: props.defaultMembersFilter || "id",
|
|
600
601
|
formatters: props.formatters || {},
|
|
601
602
|
idFormatters: props.idFormatters || {},
|
|
603
|
+
drilldownFormatters: props.drilldownFormatters || {},
|
|
602
604
|
panels: props.panels,
|
|
603
605
|
previewLimit: props.previewLimit || 50,
|
|
604
606
|
paginationConfig: (_a = props.pagination) != null ? _a : { rowsLimits: [100, 300, 500, 1e3], defaultLimit: 100 },
|
|
@@ -712,6 +714,10 @@ function useidFormatters() {
|
|
|
712
714
|
const { idFormatters } = useSettings();
|
|
713
715
|
return { idFormatters };
|
|
714
716
|
}
|
|
717
|
+
function useDrilldownFormatters() {
|
|
718
|
+
const { drilldownFormatters } = useSettings();
|
|
719
|
+
return { drilldownFormatters };
|
|
720
|
+
}
|
|
715
721
|
|
|
716
722
|
// src/utils/structs.ts
|
|
717
723
|
function buildQuery(props) {
|
|
@@ -786,15 +792,16 @@ function buildFilter(props) {
|
|
|
786
792
|
measure: props.measure || `${props.name}`,
|
|
787
793
|
conditionOne: props.conditionOne || [
|
|
788
794
|
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,
|
|
791
|
-
],
|
|
792
|
-
conditionTwo: props.conditionTwo || [
|
|
793
|
-
props.const2 ? `${props.const2[0]}` : `${"gt" /* GT */}`,
|
|
794
|
-
props.const2 ? props.const2[1].toString() : props.inputtedValue || "0",
|
|
795
|
-
props.const2 ? props.const2[1] : parseNumeric(props.interpretedValue, 0)
|
|
795
|
+
props.const1 ? props.const1[1].toString() : props.inputtedValue || "",
|
|
796
|
+
props.const1 ? props.const1[1] : parseNumeric(props.interpretedValue, NaN)
|
|
796
797
|
],
|
|
797
|
-
|
|
798
|
+
conditionTwo: props.conditionTwo || (props.const2 ? [
|
|
799
|
+
`${props.const2[0]}`,
|
|
800
|
+
props.const2[1].toString(),
|
|
801
|
+
parseNumeric(props.const2[1].toString(), NaN)
|
|
802
|
+
] : void 0),
|
|
803
|
+
joint: props.joint === "or" ? "or" : "and",
|
|
804
|
+
type: props.type
|
|
798
805
|
};
|
|
799
806
|
}
|
|
800
807
|
function buildMeasure(props) {
|
|
@@ -978,13 +985,28 @@ function filterParse(item) {
|
|
|
978
985
|
const condition = item.slice(indexName + 1);
|
|
979
986
|
const joint = condition.includes(".and.") ? "and" : "or";
|
|
980
987
|
const [cond1, cond2] = condition.split(`.${joint}.`);
|
|
988
|
+
const conditionOne = filterParseCondition(cond1);
|
|
989
|
+
const conditionTwo = cond2 ? filterParseCondition(cond2) : void 0;
|
|
990
|
+
let type;
|
|
991
|
+
if (conditionOne && conditionTwo) {
|
|
992
|
+
if (conditionOne[0] === "gte" /* GTE */ && conditionTwo[0] === "lte" /* LTE */) {
|
|
993
|
+
type = "between";
|
|
994
|
+
}
|
|
995
|
+
} else if (conditionOne) {
|
|
996
|
+
if (conditionOne[0] === "gte" /* GTE */ || conditionOne[0] === "gt" /* GT */) {
|
|
997
|
+
type = "greaterThan";
|
|
998
|
+
} else if (conditionOne[0] === "lte" /* LTE */ || conditionOne[0] === "lt" /* LT */) {
|
|
999
|
+
type = "lessThan";
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
981
1002
|
return {
|
|
982
1003
|
key: Math.random().toString(16).slice(2),
|
|
983
1004
|
active: true,
|
|
984
1005
|
measure: item.slice(0, indexName),
|
|
985
1006
|
joint,
|
|
986
|
-
conditionOne
|
|
987
|
-
conditionTwo
|
|
1007
|
+
conditionOne,
|
|
1008
|
+
conditionTwo,
|
|
1009
|
+
type
|
|
988
1010
|
};
|
|
989
1011
|
}
|
|
990
1012
|
|
|
@@ -2103,6 +2125,14 @@ function QueryProvider({ children, defaultCube }) {
|
|
|
2103
2125
|
});
|
|
2104
2126
|
});
|
|
2105
2127
|
if (newQuery) {
|
|
2128
|
+
Object.values(newQuery.params.filters).forEach((filter) => {
|
|
2129
|
+
const currentFilter = Object.values(queryItem.params.filters).find(
|
|
2130
|
+
(f) => f.measure === filter.measure
|
|
2131
|
+
);
|
|
2132
|
+
if (currentFilter) {
|
|
2133
|
+
filter.type = currentFilter.type;
|
|
2134
|
+
}
|
|
2135
|
+
});
|
|
2106
2136
|
const promises = [...restDrilldowns, ...Object.values(newQuery.params.drilldowns)].map(
|
|
2107
2137
|
(dd) => {
|
|
2108
2138
|
const currentDrilldown = queryItem.params.drilldowns[dd.key];
|
|
@@ -3117,26 +3147,60 @@ function getFiltersConditions(fn, value) {
|
|
|
3117
3147
|
const comparisonMap = /* @__PURE__ */ new Map([
|
|
3118
3148
|
[
|
|
3119
3149
|
"greaterThan",
|
|
3120
|
-
(value2) =>
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3150
|
+
(value2) => {
|
|
3151
|
+
const val = value2[0] === "" ? "" : String(value2[0]);
|
|
3152
|
+
const num = value2[0] === "" ? NaN : Number(value2[0]);
|
|
3153
|
+
return {
|
|
3154
|
+
conditionOne: ["gte" /* GTE */, val, num],
|
|
3155
|
+
conditionTwo: void 0,
|
|
3156
|
+
type: "greaterThan"
|
|
3157
|
+
};
|
|
3158
|
+
}
|
|
3124
3159
|
],
|
|
3125
3160
|
[
|
|
3126
3161
|
"lessThan",
|
|
3127
|
-
(value2) =>
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3162
|
+
(value2) => {
|
|
3163
|
+
const val = value2[0] === "" ? "" : String(value2[0]);
|
|
3164
|
+
const num = value2[0] === "" ? NaN : Number(value2[0]);
|
|
3165
|
+
return {
|
|
3166
|
+
conditionOne: ["lte" /* LTE */, val, num],
|
|
3167
|
+
conditionTwo: void 0,
|
|
3168
|
+
type: "lessThan"
|
|
3169
|
+
};
|
|
3170
|
+
}
|
|
3131
3171
|
],
|
|
3132
3172
|
[
|
|
3133
3173
|
"between",
|
|
3134
3174
|
(values) => {
|
|
3135
3175
|
const [min, max] = values;
|
|
3176
|
+
const isMinValid = min !== "" && min !== null && min !== void 0;
|
|
3177
|
+
const isMaxValid = max !== "" && max !== null && max !== void 0;
|
|
3178
|
+
if (isMinValid && isMaxValid) {
|
|
3179
|
+
return {
|
|
3180
|
+
conditionOne: ["gte" /* GTE */, String(min), Number(min)],
|
|
3181
|
+
conditionTwo: ["lte" /* LTE */, String(max), Number(max)],
|
|
3182
|
+
joint: "and",
|
|
3183
|
+
type: "between"
|
|
3184
|
+
};
|
|
3185
|
+
}
|
|
3186
|
+
if (isMinValid) {
|
|
3187
|
+
return {
|
|
3188
|
+
conditionOne: ["gte" /* GTE */, String(min), Number(min)],
|
|
3189
|
+
conditionTwo: void 0,
|
|
3190
|
+
type: "between"
|
|
3191
|
+
};
|
|
3192
|
+
}
|
|
3193
|
+
if (isMaxValid) {
|
|
3194
|
+
return {
|
|
3195
|
+
conditionOne: ["lte" /* LTE */, String(max), Number(max)],
|
|
3196
|
+
conditionTwo: void 0,
|
|
3197
|
+
type: "between"
|
|
3198
|
+
};
|
|
3199
|
+
}
|
|
3136
3200
|
return {
|
|
3137
|
-
conditionOne: ["gte" /* GTE */,
|
|
3138
|
-
conditionTwo:
|
|
3139
|
-
|
|
3201
|
+
conditionOne: ["gte" /* GTE */, "", NaN],
|
|
3202
|
+
conditionTwo: void 0,
|
|
3203
|
+
type: "between"
|
|
3140
3204
|
};
|
|
3141
3205
|
}
|
|
3142
3206
|
]
|
|
@@ -3259,6 +3323,7 @@ function useTable({
|
|
|
3259
3323
|
const { translate: t } = useTranslation();
|
|
3260
3324
|
const { getFormat, getFormatter } = useFormatter();
|
|
3261
3325
|
const { idFormatters } = useidFormatters();
|
|
3326
|
+
const { drilldownFormatters } = useDrilldownFormatters();
|
|
3262
3327
|
const { sortKey, sortDir } = useSelector$1(selectSortingParams);
|
|
3263
3328
|
const theme = useMantineTheme();
|
|
3264
3329
|
const isSmallerThanMd = useMediaQuery(
|
|
@@ -3412,6 +3477,8 @@ function useTable({
|
|
|
3412
3477
|
const row = cell.row;
|
|
3413
3478
|
const cellId = row.original[`${cell.column.id} ID`];
|
|
3414
3479
|
const idFormatter = idFormatters[`${keyCol.localeLabel} ID`];
|
|
3480
|
+
const drilldownFormatter = drilldownFormatters[`${keyCol.localeLabel}`] || drilldownFormatters[`${entity.name}`];
|
|
3481
|
+
const formattedValue = drilldownFormatter ? drilldownFormatter(cellValue, locale) : cellValue;
|
|
3415
3482
|
return /* @__PURE__ */ React15__default.createElement(Flex, { justify: "space-between", sx: { width: "100%", maxWidth: 400 }, gap: "sm" }, /* @__PURE__ */ React15__default.createElement(
|
|
3416
3483
|
Text,
|
|
3417
3484
|
{
|
|
@@ -3422,7 +3489,7 @@ function useTable({
|
|
|
3422
3489
|
textOverflow: "ellipsis"
|
|
3423
3490
|
}
|
|
3424
3491
|
},
|
|
3425
|
-
|
|
3492
|
+
formattedValue
|
|
3426
3493
|
), /* @__PURE__ */ React15__default.createElement(Box, null, cellId && /* @__PURE__ */ React15__default.createElement(Text, { color: "dimmed" }, idFormatter ? idFormatter(cellId) : cellId)));
|
|
3427
3494
|
}
|
|
3428
3495
|
};
|
|
@@ -3723,12 +3790,13 @@ var MultiFilter = ({ header }) => {
|
|
|
3723
3790
|
const { translate: t } = useTranslation();
|
|
3724
3791
|
const cutItems = useSelector$1(selectCutItems);
|
|
3725
3792
|
const drilldownItems = useSelector$1(selectDrilldownItems);
|
|
3726
|
-
useSelector$1(selectLocale);
|
|
3727
|
-
header.column.id;
|
|
3793
|
+
const locale = useSelector$1(selectLocale);
|
|
3794
|
+
const label = header.column.id;
|
|
3728
3795
|
const localeLabel = header.column.columnDef.header;
|
|
3729
3796
|
const drilldown = drilldownItems.find((d) => d.level === header.column.id);
|
|
3730
3797
|
const actions2 = useActions();
|
|
3731
3798
|
const { idFormatters } = useidFormatters();
|
|
3799
|
+
const { drilldownFormatters } = useDrilldownFormatters();
|
|
3732
3800
|
const navigate = useNavigate();
|
|
3733
3801
|
const debouncedUpdateUrl = useMemo(
|
|
3734
3802
|
() => debounce((query2) => {
|
|
@@ -3772,11 +3840,13 @@ var MultiFilter = ({ header }) => {
|
|
|
3772
3840
|
value: cut.members || [],
|
|
3773
3841
|
data: drilldown.members.map((m) => {
|
|
3774
3842
|
const idFormatter = idFormatters[`${localeLabel} ID`];
|
|
3843
|
+
const drilldownFormatter = drilldownFormatters[`${localeLabel}`] || drilldownFormatters[`${label}`];
|
|
3775
3844
|
const formattedKey = idFormatter ? idFormatter(m.key) : m.key;
|
|
3776
3845
|
const key = formattedKey ? `(${formattedKey})` : formattedKey;
|
|
3846
|
+
const formattedCaption = drilldownFormatter ? drilldownFormatter(m.caption || m.key, locale.code) : m.caption;
|
|
3777
3847
|
return {
|
|
3778
3848
|
value: `${m.key}`,
|
|
3779
|
-
label:
|
|
3849
|
+
label: formattedCaption ? `${formattedCaption} ${key}` : `${key}`
|
|
3780
3850
|
};
|
|
3781
3851
|
}),
|
|
3782
3852
|
clearButtonProps: { "aria-label": "Clear selection" },
|
|
@@ -3949,6 +4019,7 @@ function LevelItem({
|
|
|
3949
4019
|
const drilldowns = useSelector$1(selectDrilldownMap);
|
|
3950
4020
|
useSelector$1(selectDrilldownItems);
|
|
3951
4021
|
const { idFormatters } = useidFormatters();
|
|
4022
|
+
const { drilldownFormatters } = useDrilldownFormatters();
|
|
3952
4023
|
const label = useMemo(() => {
|
|
3953
4024
|
const captions = [
|
|
3954
4025
|
getCaption(dimension, locale),
|
|
@@ -4057,11 +4128,13 @@ function LevelItem({
|
|
|
4057
4128
|
value: (cut == null ? void 0 : cut.members) || [],
|
|
4058
4129
|
data: currentDrilldown.members.map((m) => {
|
|
4059
4130
|
const idFormatter = idFormatters[`${label} ID`];
|
|
4131
|
+
const drilldownFormatter = drilldownFormatters[`${label}`];
|
|
4060
4132
|
const formattedKey = idFormatter ? idFormatter(m.key) : m.key;
|
|
4061
4133
|
const key = formattedKey ? `(${formattedKey})` : formattedKey;
|
|
4134
|
+
const formattedCaption = drilldownFormatter ? drilldownFormatter(m.caption || m.key, locale) : m.caption;
|
|
4062
4135
|
return {
|
|
4063
4136
|
value: `${m.key}`,
|
|
4064
|
-
label:
|
|
4137
|
+
label: formattedCaption ? `${formattedCaption} ${key}` : `${key}`
|
|
4065
4138
|
};
|
|
4066
4139
|
}),
|
|
4067
4140
|
clearable: true,
|
|
@@ -4132,6 +4205,9 @@ function getFilterfnKey(type) {
|
|
|
4132
4205
|
}
|
|
4133
4206
|
}
|
|
4134
4207
|
function getFilterFn(filter) {
|
|
4208
|
+
if (filter.type) {
|
|
4209
|
+
return filter.type;
|
|
4210
|
+
}
|
|
4135
4211
|
if (filter.conditionOne && filter.conditionTwo) {
|
|
4136
4212
|
if (filter.conditionOne[0] === "gte" /* GTE */ && filter.conditionTwo[0] === "lte" /* LTE */) {
|
|
4137
4213
|
return "between";
|
|
@@ -4163,13 +4239,14 @@ function NumberInputComponent({ text, filter }) {
|
|
|
4163
4239
|
};
|
|
4164
4240
|
}, [debouncedUpdateUrl]);
|
|
4165
4241
|
function getFilterValue(filter2) {
|
|
4166
|
-
return isNotValid(filter2.conditionOne[2])
|
|
4242
|
+
return isNotValid(filter2.conditionOne[2]) ? "" : filter2.conditionOne[2];
|
|
4167
4243
|
}
|
|
4168
4244
|
function onInputChange({ filter: filter2, value }) {
|
|
4169
4245
|
const isEmpty = value === "";
|
|
4170
|
-
const
|
|
4246
|
+
const currentType = getFilterFn(filter2) || "greaterThan";
|
|
4247
|
+
const conditions = getFiltersConditions(currentType, [value]) || {};
|
|
4171
4248
|
const active = !isEmpty;
|
|
4172
|
-
const newFilter = buildFilter({ ...filter2, active, ...conditions });
|
|
4249
|
+
const newFilter = buildFilter({ ...filter2, active, ...conditions, type: currentType });
|
|
4173
4250
|
actions2.updateFilter(newFilter);
|
|
4174
4251
|
const newQuery = buildQuery(cloneDeep(queryItem));
|
|
4175
4252
|
newQuery.params.filters[filter2.key] = newFilter;
|
|
@@ -4204,9 +4281,10 @@ var MinMax = ({ filter, hideControls, ...rest }) => {
|
|
|
4204
4281
|
}, [debouncedUpdateUrl]);
|
|
4205
4282
|
function onInputChangeMinMax(props) {
|
|
4206
4283
|
const { filter: filter2, min: min2, max: max2 } = props;
|
|
4207
|
-
const
|
|
4208
|
-
const
|
|
4209
|
-
const
|
|
4284
|
+
const currentType = getFilterFn(filter2) || "between";
|
|
4285
|
+
const conditions = getFiltersConditions(currentType, [min2, max2]) || {};
|
|
4286
|
+
const active = min2 !== "" || max2 !== "";
|
|
4287
|
+
const newFilter = buildFilter({ ...filter2, active, ...conditions, type: currentType });
|
|
4210
4288
|
actions2.updateFilter(newFilter);
|
|
4211
4289
|
const newQuery = buildQuery(cloneDeep(queryItem));
|
|
4212
4290
|
newQuery.params.filters[filter2.key] = newFilter;
|
|
@@ -4214,7 +4292,7 @@ var MinMax = ({ filter, hideControls, ...rest }) => {
|
|
|
4214
4292
|
}
|
|
4215
4293
|
function getFilterValue(condition) {
|
|
4216
4294
|
if (condition) {
|
|
4217
|
-
return isNotValid(condition[2])
|
|
4295
|
+
return isNotValid(condition[2]) ? "" : condition[2];
|
|
4218
4296
|
}
|
|
4219
4297
|
return "";
|
|
4220
4298
|
}
|
|
@@ -4244,14 +4322,26 @@ var MinMax = ({ filter, hideControls, ...rest }) => {
|
|
|
4244
4322
|
};
|
|
4245
4323
|
function FilterFnsMenu({ filter }) {
|
|
4246
4324
|
const actions2 = useActions();
|
|
4325
|
+
const updateUrl = useUpdateUrl();
|
|
4326
|
+
const queryItem = useSelector$1(selectCurrentQueryItem);
|
|
4247
4327
|
const { translate: t } = useTranslation();
|
|
4248
4328
|
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
4329
|
Menu.Item,
|
|
4250
4330
|
{
|
|
4251
4331
|
icon: /* @__PURE__ */ React15__default.createElement(IconMathGreater, { size: 14 }),
|
|
4252
4332
|
onClick: () => {
|
|
4253
|
-
const
|
|
4254
|
-
|
|
4333
|
+
const currentType = "greaterThan";
|
|
4334
|
+
const conditions = getFiltersConditions(currentType, [""]) || {};
|
|
4335
|
+
const newFilter = buildFilter({
|
|
4336
|
+
...filter,
|
|
4337
|
+
...conditions,
|
|
4338
|
+
active: false,
|
|
4339
|
+
type: currentType
|
|
4340
|
+
});
|
|
4341
|
+
actions2.updateFilter(newFilter);
|
|
4342
|
+
const newQuery = buildQuery(cloneDeep(queryItem));
|
|
4343
|
+
newQuery.params.filters[filter.key] = newFilter;
|
|
4344
|
+
updateUrl(newQuery);
|
|
4255
4345
|
}
|
|
4256
4346
|
},
|
|
4257
4347
|
t("comparison.GT")
|
|
@@ -4260,8 +4350,18 @@ function FilterFnsMenu({ filter }) {
|
|
|
4260
4350
|
{
|
|
4261
4351
|
icon: /* @__PURE__ */ React15__default.createElement(IconMathLower, { size: 14 }),
|
|
4262
4352
|
onClick: () => {
|
|
4263
|
-
const
|
|
4264
|
-
|
|
4353
|
+
const currentType = "lessThan";
|
|
4354
|
+
const conditions = getFiltersConditions(currentType, [""]) || {};
|
|
4355
|
+
const newFilter = buildFilter({
|
|
4356
|
+
...filter,
|
|
4357
|
+
...conditions,
|
|
4358
|
+
active: false,
|
|
4359
|
+
type: currentType
|
|
4360
|
+
});
|
|
4361
|
+
actions2.updateFilter(newFilter);
|
|
4362
|
+
const newQuery = buildQuery(cloneDeep(queryItem));
|
|
4363
|
+
newQuery.params.filters[filter.key] = newFilter;
|
|
4364
|
+
updateUrl(newQuery);
|
|
4265
4365
|
}
|
|
4266
4366
|
},
|
|
4267
4367
|
t("comparison.LT")
|
|
@@ -4270,8 +4370,18 @@ function FilterFnsMenu({ filter }) {
|
|
|
4270
4370
|
{
|
|
4271
4371
|
icon: /* @__PURE__ */ React15__default.createElement(IconArrowsLeftRight, { size: 14 }),
|
|
4272
4372
|
onClick: () => {
|
|
4273
|
-
const
|
|
4274
|
-
|
|
4373
|
+
const currentType = "between";
|
|
4374
|
+
const conditions = getFiltersConditions(currentType, ["", ""]) || {};
|
|
4375
|
+
const newFilter = buildFilter({
|
|
4376
|
+
...filter,
|
|
4377
|
+
...conditions,
|
|
4378
|
+
active: false,
|
|
4379
|
+
type: currentType
|
|
4380
|
+
});
|
|
4381
|
+
actions2.updateFilter(newFilter);
|
|
4382
|
+
const newQuery = buildQuery(cloneDeep(queryItem));
|
|
4383
|
+
newQuery.params.filters[filter.key] = newFilter;
|
|
4384
|
+
updateUrl(newQuery);
|
|
4275
4385
|
}
|
|
4276
4386
|
},
|
|
4277
4387
|
t("comparison.BT")
|
|
@@ -6528,6 +6638,7 @@ function ExplorerComponent(props) {
|
|
|
6528
6638
|
defaultMembersFilter: props.defaultMembersFilter,
|
|
6529
6639
|
formatters: props.formatters,
|
|
6530
6640
|
idFormatters: props.idFormatters,
|
|
6641
|
+
drilldownFormatters: props.drilldownFormatters,
|
|
6531
6642
|
withPermalink: props.withPermalink,
|
|
6532
6643
|
panels,
|
|
6533
6644
|
pagination,
|
|
@@ -6649,6 +6760,31 @@ var iconByFormat = {
|
|
|
6649
6760
|
png: IconPhotoDown,
|
|
6650
6761
|
svg: IconVectorTriangle
|
|
6651
6762
|
};
|
|
6763
|
+
var ChartRenderer = memo((props) => {
|
|
6764
|
+
const { ChartComponent, config, containerRef, overlayRef, onReady } = props;
|
|
6765
|
+
React15__default.useEffect(() => {
|
|
6766
|
+
const box = containerRef.current;
|
|
6767
|
+
if (!box) return;
|
|
6768
|
+
const checkSvg = () => {
|
|
6769
|
+
const svg = box.querySelector("svg");
|
|
6770
|
+
if (svg) {
|
|
6771
|
+
if (overlayRef.current) {
|
|
6772
|
+
overlayRef.current.style.display = "none";
|
|
6773
|
+
}
|
|
6774
|
+
onReady();
|
|
6775
|
+
return true;
|
|
6776
|
+
}
|
|
6777
|
+
return false;
|
|
6778
|
+
};
|
|
6779
|
+
if (checkSvg()) return;
|
|
6780
|
+
const observer = new MutationObserver(() => {
|
|
6781
|
+
if (checkSvg()) observer.disconnect();
|
|
6782
|
+
});
|
|
6783
|
+
observer.observe(box, { childList: true, subtree: true });
|
|
6784
|
+
return () => observer.disconnect();
|
|
6785
|
+
}, [containerRef, overlayRef, onReady]);
|
|
6786
|
+
return /* @__PURE__ */ React15__default.createElement(ChartComponent, { config });
|
|
6787
|
+
});
|
|
6652
6788
|
function ChartCard(props) {
|
|
6653
6789
|
const { chart, isFullMode, onFocus, height } = props;
|
|
6654
6790
|
const { dataset } = chart.datagroup;
|
|
@@ -6723,8 +6859,46 @@ function ChartCard(props) {
|
|
|
6723
6859
|
copied ? translate("share_copied") : translate("action_share")
|
|
6724
6860
|
));
|
|
6725
6861
|
}, [translate]);
|
|
6862
|
+
const [isLoaded, setIsLoaded] = useState(false);
|
|
6863
|
+
const [shouldRenderChart, setShouldRenderChart] = useState(false);
|
|
6864
|
+
const overlayRef = useRef(null);
|
|
6865
|
+
React15__default.useEffect(() => {
|
|
6866
|
+
setIsLoaded(false);
|
|
6867
|
+
setShouldRenderChart(false);
|
|
6868
|
+
if (overlayRef.current) {
|
|
6869
|
+
overlayRef.current.style.display = "block";
|
|
6870
|
+
}
|
|
6871
|
+
}, [chart.key]);
|
|
6872
|
+
React15__default.useEffect(() => {
|
|
6873
|
+
if (ChartComponent && (inView || hasBeenInView) && !shouldRenderChart) {
|
|
6874
|
+
const timer = setTimeout(() => {
|
|
6875
|
+
window.requestAnimationFrame(() => {
|
|
6876
|
+
window.requestAnimationFrame(() => {
|
|
6877
|
+
setShouldRenderChart(true);
|
|
6878
|
+
});
|
|
6879
|
+
});
|
|
6880
|
+
}, 500);
|
|
6881
|
+
return () => clearTimeout(timer);
|
|
6882
|
+
}
|
|
6883
|
+
}, [ChartComponent, inView, hasBeenInView, shouldRenderChart]);
|
|
6884
|
+
React15__default.useEffect(() => {
|
|
6885
|
+
const box = nodeRef.current;
|
|
6886
|
+
if (!box || !shouldRenderChart || isLoaded) return;
|
|
6887
|
+
const observer = new MutationObserver(() => {
|
|
6888
|
+
const svg = box.querySelector("svg");
|
|
6889
|
+
if (svg) {
|
|
6890
|
+
window.requestAnimationFrame(() => setIsLoaded(true));
|
|
6891
|
+
observer.disconnect();
|
|
6892
|
+
}
|
|
6893
|
+
});
|
|
6894
|
+
observer.observe(box, { childList: true, subtree: true });
|
|
6895
|
+
if (box.querySelector("svg")) {
|
|
6896
|
+
setIsLoaded(true);
|
|
6897
|
+
}
|
|
6898
|
+
return () => observer.disconnect();
|
|
6899
|
+
}, [shouldRenderChart, isLoaded]);
|
|
6726
6900
|
if (!ChartComponent || !config) return null;
|
|
6727
|
-
const resolvedHeight = height ? height : isFullMode ? "calc(100vh - 3rem)" :
|
|
6901
|
+
const resolvedHeight = height ? height : isFullMode ? "calc(100vh - 3rem)" : "calc((80vh - 4rem) / 2)";
|
|
6728
6902
|
return /* @__PURE__ */ React15__default.createElement(ErrorBoundary, { ErrorContent: CardErrorComponent }, /* @__PURE__ */ React15__default.createElement(
|
|
6729
6903
|
Paper,
|
|
6730
6904
|
{
|
|
@@ -6735,11 +6909,42 @@ function ChartCard(props) {
|
|
|
6735
6909
|
/* @__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
6910
|
Box,
|
|
6737
6911
|
{
|
|
6738
|
-
style: { flex: "1 1 auto" },
|
|
6912
|
+
style: { flex: "1 1 auto", position: "relative" },
|
|
6739
6913
|
ref: setRefs,
|
|
6740
6914
|
sx: { "& > .viz": { height: "100%" } }
|
|
6741
6915
|
},
|
|
6742
|
-
|
|
6916
|
+
/* @__PURE__ */ React15__default.createElement(
|
|
6917
|
+
Box,
|
|
6918
|
+
{
|
|
6919
|
+
ref: overlayRef,
|
|
6920
|
+
style: {
|
|
6921
|
+
position: "absolute",
|
|
6922
|
+
top: 0,
|
|
6923
|
+
left: 0,
|
|
6924
|
+
right: 0,
|
|
6925
|
+
bottom: 0,
|
|
6926
|
+
zIndex: 100
|
|
6927
|
+
}
|
|
6928
|
+
},
|
|
6929
|
+
/* @__PURE__ */ React15__default.createElement(
|
|
6930
|
+
LoadingOverlay,
|
|
6931
|
+
{
|
|
6932
|
+
visible: !isLoaded,
|
|
6933
|
+
overlayBlur: 2,
|
|
6934
|
+
transitionDuration: 0
|
|
6935
|
+
}
|
|
6936
|
+
)
|
|
6937
|
+
),
|
|
6938
|
+
ChartComponent && (inView || hasBeenInView) && shouldRenderChart ? /* @__PURE__ */ React15__default.createElement(
|
|
6939
|
+
ChartRenderer,
|
|
6940
|
+
{
|
|
6941
|
+
ChartComponent,
|
|
6942
|
+
config,
|
|
6943
|
+
containerRef: nodeRef,
|
|
6944
|
+
overlayRef,
|
|
6945
|
+
onReady: () => setIsLoaded(true)
|
|
6946
|
+
}
|
|
6947
|
+
) : /* @__PURE__ */ React15__default.createElement("div", { style: { height: "100%", width: "100%" } })
|
|
6743
6948
|
))
|
|
6744
6949
|
));
|
|
6745
6950
|
}
|
|
@@ -6795,8 +7000,12 @@ function Vizbuilder(props) {
|
|
|
6795
7000
|
chartLimits,
|
|
6796
7001
|
chartTypes,
|
|
6797
7002
|
datacap,
|
|
7003
|
+
getFormatter,
|
|
6798
7004
|
getTopojsonConfig,
|
|
6799
7005
|
NonIdealState: NonIdealState2,
|
|
7006
|
+
postprocessConfig,
|
|
7007
|
+
showConfidenceInt,
|
|
7008
|
+
translate,
|
|
6800
7009
|
ViewErrorComponent
|
|
6801
7010
|
} = useVizbuilderContext();
|
|
6802
7011
|
const { actions: actions2 } = useSettings();
|
|
@@ -6812,21 +7021,46 @@ function Vizbuilder(props) {
|
|
|
6812
7021
|
});
|
|
6813
7022
|
return Object.fromEntries(charts2.map((chart2) => [chart2.key, chart2]));
|
|
6814
7023
|
}, [chartLimits, chartTypes, datacap, datasets, getTopojsonConfig]);
|
|
7024
|
+
const filteredCharts = useMemo(() => {
|
|
7025
|
+
const list = Object.values(charts);
|
|
7026
|
+
const builderParams = {
|
|
7027
|
+
fullMode: false,
|
|
7028
|
+
getFormatter,
|
|
7029
|
+
showConfidenceInt,
|
|
7030
|
+
t: translate
|
|
7031
|
+
};
|
|
7032
|
+
return list.filter((chart2) => {
|
|
7033
|
+
const builder = d3plusConfigBuilder[chart2.type];
|
|
7034
|
+
if (!builder) return false;
|
|
7035
|
+
const config = builder(chart2, builderParams);
|
|
7036
|
+
const finalConfig = postprocessConfig(config, chart2, builderParams);
|
|
7037
|
+
return finalConfig !== false;
|
|
7038
|
+
});
|
|
7039
|
+
}, [charts, getFormatter, postprocessConfig, showConfidenceInt, translate]);
|
|
7040
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
7041
|
+
const pageSize = 4;
|
|
7042
|
+
useEffect(() => {
|
|
7043
|
+
setCurrentPage(1);
|
|
7044
|
+
}, [datasets, charts]);
|
|
6815
7045
|
const content = useMemo(() => {
|
|
6816
7046
|
const isLoading = datasets.some((dataset) => Object.keys(dataset.columns).length === 0);
|
|
6817
7047
|
if (isLoading) {
|
|
6818
7048
|
console.debug("Loading datasets...", datasets);
|
|
6819
7049
|
return /* @__PURE__ */ React15__default.createElement(NonIdealState2, { status: "loading" });
|
|
6820
7050
|
}
|
|
6821
|
-
const chartList =
|
|
6822
|
-
|
|
7051
|
+
const chartList = filteredCharts.slice(
|
|
7052
|
+
(currentPage - 1) * pageSize,
|
|
7053
|
+
currentPage * pageSize
|
|
7054
|
+
);
|
|
7055
|
+
if (filteredCharts.length === 0) {
|
|
6823
7056
|
if (datasets.length === 1 && datasets[0].data.length === 1) {
|
|
6824
7057
|
return /* @__PURE__ */ React15__default.createElement(NonIdealState2, { status: "one-row" });
|
|
6825
7058
|
}
|
|
6826
7059
|
return /* @__PURE__ */ React15__default.createElement(NonIdealState2, { status: "empty" });
|
|
6827
7060
|
}
|
|
6828
7061
|
const isSingleChart = chartList.length === 1;
|
|
6829
|
-
|
|
7062
|
+
const totalPages = Math.ceil(filteredCharts.length / pageSize);
|
|
7063
|
+
return /* @__PURE__ */ React15__default.createElement(Stack, { spacing: "xl" }, /* @__PURE__ */ React15__default.createElement(
|
|
6830
7064
|
"div",
|
|
6831
7065
|
{
|
|
6832
7066
|
className: cx("vb-scrollcontainer", classes.grid, {
|
|
@@ -6854,8 +7088,17 @@ function Vizbuilder(props) {
|
|
|
6854
7088
|
}
|
|
6855
7089
|
);
|
|
6856
7090
|
})
|
|
6857
|
-
)
|
|
6858
|
-
|
|
7091
|
+
), totalPages > 1 && /* @__PURE__ */ React15__default.createElement(
|
|
7092
|
+
Pagination,
|
|
7093
|
+
{
|
|
7094
|
+
total: totalPages,
|
|
7095
|
+
value: currentPage,
|
|
7096
|
+
onChange: setCurrentPage,
|
|
7097
|
+
position: "center",
|
|
7098
|
+
mb: "xl"
|
|
7099
|
+
}
|
|
7100
|
+
));
|
|
7101
|
+
}, [filteredCharts, currentPage, classes, cx, datasets, NonIdealState2, actions2]);
|
|
6859
7102
|
const currentChart = (queryItem == null ? void 0 : queryItem.chart) || "";
|
|
6860
7103
|
const chart = charts[currentChart];
|
|
6861
7104
|
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 +7126,7 @@ function useVizbuilderData() {
|
|
|
6883
7126
|
});
|
|
6884
7127
|
return query;
|
|
6885
7128
|
}
|
|
6886
|
-
var
|
|
7129
|
+
var LoadingOverlay4 = () => {
|
|
6887
7130
|
const { translate: t } = useTranslation();
|
|
6888
7131
|
const { loading: isLoading, message } = useSelector$1(selectLoadingState);
|
|
6889
7132
|
const description = !message ? void 0 : message.type === "HEAVY_QUERY" ? t("loading.message_heavyquery", message) : (
|
|
@@ -6910,7 +7153,7 @@ function VizbuilderView(props) {
|
|
|
6910
7153
|
const { cube, params } = props;
|
|
6911
7154
|
const query = useVizbuilderData();
|
|
6912
7155
|
if (query.isLoading) {
|
|
6913
|
-
return /* @__PURE__ */ React15__default.createElement(
|
|
7156
|
+
return /* @__PURE__ */ React15__default.createElement(LoadingOverlay4, { visible: true });
|
|
6914
7157
|
}
|
|
6915
7158
|
const data = query.data;
|
|
6916
7159
|
const types = (_a = query.data) == null ? void 0 : _a.types;
|