@datawheel/data-explorer 0.2.4 → 0.2.5

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.
Files changed (2) hide show
  1. package/dist/main.js +194 -142
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -1,7 +1,7 @@
1
- import { keyframes, createStyles, Select, rem, Flex, Title, Text, Group, Button, Box, Anchor, Input, Stack, SimpleGrid, ScrollArea, LoadingOverlay, Table, MultiSelect, Center, Alert, Loader, Modal, NumberInput, Menu, ActionIcon, useMantineTheme, MantineProvider, Paper, useComponentDefaultProps, Switch, ThemeIcon, Tooltip, Tabs, CloseButton, Drawer, Checkbox, UnstyledButton, TextInput, Accordion, Popover, Divider } from '@mantine/core';
1
+ import { keyframes, createStyles, Select, rem, Flex, Title, Text, Group, Button, Box, Anchor, Input, Stack, SimpleGrid, ScrollArea, LoadingOverlay, Table, MultiSelect, Center, Alert, Loader, Modal, NumberInput, Menu, ActionIcon, MantineProvider, Paper, useComponentDefaultProps, Switch, ThemeIcon, Tooltip, useMantineTheme, Tabs, CloseButton, Drawer, Checkbox, UnstyledButton, TextInput, Accordion, Popover, Divider } from '@mantine/core';
2
2
  import { useClipboard, useClickOutside, useFullscreen, useMediaQuery, useDebouncedValue, useDisclosure } from '@mantine/hooks';
3
3
  import { Prism } from '@mantine/prism';
4
- import { IconWorld, IconExternalLink, IconClipboard, IconAlertCircle, IconAlertTriangle, IconSettings, IconMathGreater, IconMathLower, IconArrowsLeftRight, IconCopy, IconDownload, IconDotsVertical, IconArrowsMinimize, IconArrowsMaximize, IconInfoCircleFilled, IconTrash, IconSearch, IconPhotoDown, IconVectorTriangle, IconStack3, IconFilterOff, IconFilter, IconArrowsSort, IconSortDescendingNumbers, IconSortDescendingLetters, IconSortAscendingNumbers, IconSortAscendingLetters, IconLanguage } from '@tabler/icons-react';
4
+ import { IconWorld, IconExternalLink, IconClipboard, IconAlertCircle, IconAlertTriangle, IconSettings, IconMathGreater, IconMathLower, IconArrowsLeftRight, IconCopy, IconDownload, IconDotsVertical, IconArrowsMinimize, IconArrowsMaximize, IconInfoCircleFilled, IconTrash, IconSearch, IconPhotoDown, IconVectorTriangle, IconPlus, IconStack3, IconFilterOff, IconFilter, IconArrowsSort, IconSortDescendingNumbers, IconSortDescendingLetters, IconSortAscendingNumbers, IconSortAscendingLetters, IconLanguage } from '@tabler/icons-react';
5
5
  import * as React10 from 'react';
6
6
  import React10__default, { createContext, forwardRef, useMemo, useCallback, useContext, useState, useEffect, useRef, Suspense, useLayoutEffect } from 'react';
7
7
  import { translationFactory } from '@datawheel/use-translation';
@@ -228,7 +228,7 @@ var defaultTranslation = {
228
228
  json: "JSON",
229
229
  jsonarrays: "JSON Arrays",
230
230
  jsonrecords: "JSON Records",
231
- xls: "XLS"
231
+ xlsx: "XLSX"
232
232
  },
233
233
  loading: {
234
234
  title: "Loading...",
@@ -803,6 +803,9 @@ var serverSlice = createSlice({
803
803
  updateServer(state, action) {
804
804
  return { ...state, ...action.payload };
805
805
  },
806
+ resetServer(state, action) {
807
+ return { ...initialState };
808
+ },
806
809
  /**
807
810
  * Updates the type of endpoint to use in the current query.
808
811
  */
@@ -827,16 +830,18 @@ var selectServerSoftware = createSelector(selectServerState, (server) => server.
827
830
  var selectServerEndpoint = createSelector(selectServerState, (server) => server.endpoint);
828
831
  var selectServerFormatsEnabled = createSelector(
829
832
  selectServerSoftware,
830
- (software) => software === TesseractDataSource.softwareName ? [Format.csv, Format.jsonarrays, Format.jsonrecords] : [Format.csv, Format.json, Format.jsonrecords, Format.xls]
833
+ (software) => software === TesseractDataSource.softwareName ? [Format.csv, Format.jsonarrays, Format.jsonrecords] : [
834
+ Format.csv,
835
+ // Format.jsonarrays,
836
+ Format.jsonrecords,
837
+ Format.xlsx
838
+ ]
831
839
  );
832
840
  createSelector(
833
841
  selectServerSoftware,
834
842
  (software) => software === TesseractDataSource.softwareName ? ["debug", "exclude_default_members", "parents", "sparse"] : ["debug", "distinct", "nonempty", "parents", "sparse"]
835
843
  );
836
- var selectOlapCubeMap = createSelector(
837
- selectServerState,
838
- (server) => server.cubeMap
839
- );
844
+ var selectOlapCubeMap = createSelector(selectServerState, (server) => server.cubeMap);
840
845
  createSelector(selectOlapCubeMap, getKeys);
841
846
  var selectOlapCubeItems = createSelector(selectOlapCubeMap, getValues);
842
847
 
@@ -1178,6 +1183,9 @@ var loadingActions = {
1178
1183
  return { type: `${name3}/setLoadingState:${status}`, payload: message };
1179
1184
  }
1180
1185
  };
1186
+ function selectLoadingState(state) {
1187
+ return state[name3];
1188
+ }
1181
1189
  function isFetchingAction(action) {
1182
1190
  return action.type.endsWith(`:${LOADINGSTATUS.FETCHING}`);
1183
1191
  }
@@ -1367,9 +1375,12 @@ function parseStateFromSearchParams(query) {
1367
1375
  function usePermalink(isEnabled, options) {
1368
1376
  const cubeMap = useSelector(selectOlapCubeMap);
1369
1377
  const { isDirty, panel, params } = useSelector(selectCurrentQueryItem);
1370
- const listener = useCallback((evt) => {
1371
- evt.state && options.onChange(evt.state);
1372
- }, [options.onChange]);
1378
+ const listener = useCallback(
1379
+ (evt) => {
1380
+ evt.state && options.onChange(evt.state);
1381
+ },
1382
+ [options.onChange]
1383
+ );
1373
1384
  useEffect(() => {
1374
1385
  if (isEnabled) {
1375
1386
  window.addEventListener("popstate", listener);
@@ -1392,6 +1403,31 @@ function usePermalink(isEnabled, options) {
1392
1403
  }, [cubeMap, isDirty, panel]);
1393
1404
  return null;
1394
1405
  }
1406
+ function useUpdatePermaLink({
1407
+ isFetched,
1408
+ cube,
1409
+ enabled,
1410
+ isLoading
1411
+ }) {
1412
+ const { panel, params } = useSelector(selectCurrentQueryItem);
1413
+ useEffect(() => {
1414
+ if (isFetched && cube && enabled && !isLoading) {
1415
+ const currPermalink = window.location.search.slice(1);
1416
+ const nextPermalink = serializePermalink(params, panel);
1417
+ if (currPermalink !== nextPermalink) {
1418
+ const nextLocation = `${window.location.pathname}?${nextPermalink}`;
1419
+ window.history.pushState(params, "", nextLocation);
1420
+ }
1421
+ }
1422
+ }, [isFetched, cube, params, panel, enabled, isLoading]);
1423
+ }
1424
+ function useKey() {
1425
+ const { panel, params } = useSelector(selectCurrentQueryItem);
1426
+ if (Object.keys(params.drilldowns).length > 0 && Object.keys(params.measures).length > 0) {
1427
+ return serializePermalink(params, panel);
1428
+ }
1429
+ return false;
1430
+ }
1395
1431
 
1396
1432
  // src/hooks/settings.tsx
1397
1433
  var SettingsContext = createContext(void 0);
@@ -1691,6 +1727,7 @@ function willDownloadQuery(format2) {
1691
1727
  return olapClient.getCube(params.cube).then((cube) => {
1692
1728
  const filename = `${cube.name}_${(/* @__PURE__ */ new Date()).toISOString()}`;
1693
1729
  const queryParams = { ...params, pagiLimit: 0, pagiOffset: 0 };
1730
+ console.log({ format: format2 });
1694
1731
  const query = applyQueryParams(cube.query, queryParams, { previewLimit }).setFormat(format2);
1695
1732
  const dataURL = query.toString("logiclayer").replace(olapClient.datasource.serverUrl, "");
1696
1733
  return Promise.all([
@@ -1739,7 +1776,7 @@ function willExecuteQuery({ limit, offset } = {}) {
1739
1776
  (result) => {
1740
1777
  const [aggregation] = result;
1741
1778
  const { data, headers, status } = aggregation;
1742
- !isPrefetch && dispatch(
1779
+ dispatch(
1743
1780
  queriesActions.updateResult({
1744
1781
  data: data == null ? void 0 : data.data,
1745
1782
  types: (data == null ? void 0 : data.data.length) ? describeData(cube.toJSON(), params, data == null ? void 0 : data.data) : currentResult.types,
@@ -1751,7 +1788,7 @@ function willExecuteQuery({ limit, offset } = {}) {
1751
1788
  );
1752
1789
  return {
1753
1790
  data,
1754
- types: (data == null ? void 0 : data.data.length) ? describeData(cube.toJSON(), params, data == null ? void 0 : data.data) : currentResult.types
1791
+ types: (data == null ? void 0 : data.data.length) ? describeData(cube.toJSON(), params, data == null ? void 0 : data.data) : {}
1755
1792
  };
1756
1793
  },
1757
1794
  (error) => {
@@ -1948,6 +1985,8 @@ function useSetup(serverConfig, locale, defaultCube) {
1948
1985
  actions2.updateLocaleList(cleanLocale);
1949
1986
  }, [cleanLocale]);
1950
1987
  useEffect(() => {
1988
+ actions2.resetServer({});
1989
+ actions2.resetAllParams({});
1951
1990
  actions2.setLoadingState("FETCHING");
1952
1991
  setDone(false);
1953
1992
  actions2.willSetupClient(serverConfig).then(() => actions2.willReloadCubes()).then((cubeMap) => {
@@ -2439,7 +2478,8 @@ function CubeSource() {
2439
2478
 
2440
2479
  // src/components/TableFooter.tsx
2441
2480
  function TableFooter(props) {
2442
- const { result, table } = props;
2481
+ const loading = useSelector$1(selectLoadingState);
2482
+ const { result, table, data = [], isLoading } = props;
2443
2483
  const { translate: t } = useTranslation();
2444
2484
  const { url } = result;
2445
2485
  const { copy, copied } = useClipboard({ timeout: 1e3 });
@@ -2459,11 +2499,11 @@ function TableFooter(props) {
2459
2499
  gap: "sm"
2460
2500
  },
2461
2501
  /* @__PURE__ */ React10__default.createElement(CubeSource, null),
2462
- /* @__PURE__ */ React10__default.createElement(Group, { position: "right", spacing: "sm" }, /* @__PURE__ */ React10__default.createElement(Text, { c: "dimmed" }, t("results.count_rows", { n: totalRowCount })), showPagination && /* @__PURE__ */ React10__default.createElement(MRT_TablePagination, { table }), /* @__PURE__ */ React10__default.createElement(ApiAndCsvButtons, { copied, copyHandler, url }))
2502
+ !loading.loading && !isLoading && /* @__PURE__ */ React10__default.createElement(Group, { position: "right", spacing: "sm" }, totalRowCount && /* @__PURE__ */ React10__default.createElement(Text, { c: "dimmed" }, t("results.count_rows", { n: totalRowCount })), showPagination && /* @__PURE__ */ React10__default.createElement(MRT_TablePagination, { table }), /* @__PURE__ */ React10__default.createElement(ApiAndCsvButtons, { copied, copyHandler, url, data }))
2463
2503
  ));
2464
2504
  }
2465
2505
  var ApiAndCsvButtons = (props) => {
2466
- const { copied, copyHandler, url } = props;
2506
+ const { copied, copyHandler, url, data } = props;
2467
2507
  const { translate: t } = useTranslation();
2468
2508
  return /* @__PURE__ */ React10__default.createElement(Box, { id: "query-results-debug-view" }, /* @__PURE__ */ React10__default.createElement(Group, { spacing: "xs" }, url && /* @__PURE__ */ React10__default.createElement(
2469
2509
  Button,
@@ -2476,12 +2516,11 @@ var ApiAndCsvButtons = (props) => {
2476
2516
  },
2477
2517
  copied ? t("action_copy_done") : t("action_copy"),
2478
2518
  " API"
2479
- ), /* @__PURE__ */ React10__default.createElement(DownloadQuery, null)));
2519
+ ), /* @__PURE__ */ React10__default.createElement(DownloadQuery, { data })));
2480
2520
  };
2481
- var DownloadQuery = () => {
2521
+ var DownloadQuery = ({ data }) => {
2482
2522
  const actions2 = useActions();
2483
2523
  const { translate: t } = useTranslation();
2484
- const { isDirty, result } = useSelector$1(selectCurrentQueryItem);
2485
2524
  const formats = useSelector$1(selectServerFormatsEnabled);
2486
2525
  const csv = formats.find((format2) => format2 === "csv");
2487
2526
  const components = [];
@@ -2501,7 +2540,7 @@ var DownloadQuery = () => {
2501
2540
  )
2502
2541
  );
2503
2542
  }
2504
- if (components.length === 0 || result.data.length === 0) {
2543
+ if (components.length === 0 || data.length === 0) {
2505
2544
  return null;
2506
2545
  }
2507
2546
  return /* @__PURE__ */ React10__default.createElement(Box, { id: "button-group-download-results" }, /* @__PURE__ */ React10__default.createElement(Group, { spacing: "xs" }, components, /* @__PURE__ */ React10__default.createElement(MenuOpts, { formats: formats.filter((f) => f !== "csv") })));
@@ -2675,7 +2714,7 @@ function AddColumnsDrawer() {
2675
2714
  opened,
2676
2715
  position: "right",
2677
2716
  onClose: close2,
2678
- title: /* @__PURE__ */ React10__default.createElement(Group, null, /* @__PURE__ */ React10__default.createElement(IconStack3, { size: "1rem" }), /* @__PURE__ */ React10__default.createElement(Text, { fw: 700 }, t("params.add_columns"))),
2717
+ title: /* @__PURE__ */ React10__default.createElement(Group, null, /* @__PURE__ */ React10__default.createElement(IconPlus, { size: "1.2rem" }), /* @__PURE__ */ React10__default.createElement(Text, { fw: 700 }, t("params.add_columns"))),
2679
2718
  styles: (t2) => ({
2680
2719
  inner: {
2681
2720
  position: "absolute",
@@ -2695,13 +2734,14 @@ function AddColumnsDrawer() {
2695
2734
  },
2696
2735
  /* @__PURE__ */ React10__default.createElement(MeasuresOptions, null),
2697
2736
  /* @__PURE__ */ React10__default.createElement(DrillDownOptions, null)
2698
- ), /* @__PURE__ */ React10__default.createElement(Group, { position: "center" }, smallerThanMd ? /* @__PURE__ */ React10__default.createElement(ActionIcon, { onClick: open, size: "md", variant: "filled", color: theme.primaryColor }, /* @__PURE__ */ React10__default.createElement(IconStack3, { size: "0.75rem" })) : /* @__PURE__ */ React10__default.createElement(Button, { leftIcon: /* @__PURE__ */ React10__default.createElement(IconStack3, { size: "1rem" }), onClick: open, m: "md", size: "xs" }, t("params.add_columns"))));
2737
+ ), /* @__PURE__ */ React10__default.createElement(Group, { position: "center", sx: { flexWrap: "nowrap" } }, smallerThanMd ? /* @__PURE__ */ React10__default.createElement(ActionIcon, { onClick: open, size: "md", variant: "filled", color: theme.primaryColor }, /* @__PURE__ */ React10__default.createElement(IconStack3, { size: "0.75rem" })) : /* @__PURE__ */ React10__default.createElement(Button, { leftIcon: /* @__PURE__ */ React10__default.createElement(IconPlus, { size: "1.2rem" }), onClick: open, m: "md", size: "sm" }, t("params.add_columns"))));
2699
2738
  }
2700
2739
  function DrillDownOptions() {
2701
2740
  const locale = useSelector$1(selectLocale);
2702
2741
  const selectedDimensions = useSelector$1(selectDrilldownItems);
2703
2742
  const dimensions = useSelector$1(selectOlapDimensionItems) || [];
2704
2743
  const activeItems = selectedDimensions.filter((i) => i.active);
2744
+ const activeCount = activeItems.length;
2705
2745
  const options = useMemo(
2706
2746
  () => dimensions.map((dimension) => /* @__PURE__ */ React10__default.createElement(
2707
2747
  DimensionItem,
@@ -2709,14 +2749,15 @@ function DrillDownOptions() {
2709
2749
  dimension,
2710
2750
  locale: locale.code,
2711
2751
  key: dimension.uri,
2712
- activeItems
2752
+ activeItems,
2753
+ activeCount
2713
2754
  }
2714
2755
  )),
2715
- [dimensions, activeItems]
2756
+ [dimensions, activeItems, activeCount]
2716
2757
  );
2717
2758
  return options;
2718
2759
  }
2719
- function DimensionItem({ dimension, locale, activeItems }) {
2760
+ function DimensionItem({ dimension, locale, activeItems, activeCount }) {
2720
2761
  const isChildSubMenu = dimension.hierarchies.length !== 1;
2721
2762
  const options = dimension.hierarchies.map((hie) => /* @__PURE__ */ React10__default.createElement(
2722
2763
  HierarchyItem,
@@ -2726,7 +2767,8 @@ function DimensionItem({ dimension, locale, activeItems }) {
2726
2767
  isSubMenu: isChildSubMenu,
2727
2768
  key: hie.uri,
2728
2769
  locale,
2729
- activeItems
2770
+ activeItems,
2771
+ activeCount
2730
2772
  }
2731
2773
  ));
2732
2774
  if (!isChildSubMenu) {
@@ -2734,7 +2776,7 @@ function DimensionItem({ dimension, locale, activeItems }) {
2734
2776
  }
2735
2777
  return options;
2736
2778
  }
2737
- function HierarchyItem({ dimension, hierarchy, isSubMenu, locale, activeItems }) {
2779
+ function HierarchyItem({ dimension, hierarchy, isSubMenu, locale, activeItems, activeCount }) {
2738
2780
  const { translate: t } = useTranslation();
2739
2781
  useMemo(() => {
2740
2782
  const captions = [getCaption(dimension, locale), getCaption(hierarchy, locale)];
@@ -2757,7 +2799,8 @@ function HierarchyItem({ dimension, hierarchy, isSubMenu, locale, activeItems })
2757
2799
  key: lvl.uri,
2758
2800
  level: lvl,
2759
2801
  locale,
2760
- activeItems
2802
+ activeItems,
2803
+ activeCount
2761
2804
  }
2762
2805
  ));
2763
2806
  if (!isChildSubMenu) {
@@ -2765,14 +2808,14 @@ function HierarchyItem({ dimension, hierarchy, isSubMenu, locale, activeItems })
2765
2808
  }
2766
2809
  return options;
2767
2810
  }
2768
- function LevelItem({ dimension, hierarchy, isSubMenu, level, locale, activeItems }) {
2811
+ function LevelItem({ dimension, hierarchy, isSubMenu, level, locale, activeItems, activeCount }) {
2769
2812
  const [activeFilter, setActiveFilter] = useState(false);
2770
2813
  const { translate: t } = useTranslation();
2771
2814
  const actions2 = useActions();
2772
2815
  const cutItems = useSelector$1(selectCutItems);
2773
- const dimensions = useSelector$1(selectOlapDimensionItems);
2774
2816
  const drilldowns = useSelector$1(selectDrilldownMap);
2775
2817
  const ditems = useSelector$1(selectDrilldownItems);
2818
+ const dimensions = useSelector$1(selectOlapDimensionItems);
2776
2819
  const label = useMemo(() => {
2777
2820
  const captions = [
2778
2821
  getCaption(dimension, locale),
@@ -2814,6 +2857,9 @@ function LevelItem({ dimension, hierarchy, isSubMenu, level, locale, activeItems
2814
2857
  return drilldown;
2815
2858
  }
2816
2859
  const currentDrilldown = drilldowns[stringifyName(level)];
2860
+ const isOtherHierarchySelected = activeItems.some(
2861
+ (activeItem) => activeItem.dimension === dimension.name && activeItem.hierarchy !== hierarchy.name
2862
+ );
2817
2863
  useLayoutEffect(() => {
2818
2864
  if (!drilldowns[stringifyName(level)] && !ditems.find((d) => d.uniqueName === buildDrilldown(level).uniqueName)) {
2819
2865
  createDrilldown(level, cutItems);
@@ -2826,10 +2872,13 @@ function LevelItem({ dimension, hierarchy, isSubMenu, level, locale, activeItems
2826
2872
  actions2.updateCut({ ...item, members });
2827
2873
  }, []);
2828
2874
  const checked = activeItems.map(stringifyName).includes(stringifyName(level));
2875
+ const disableUncheck = activeCount === 1 && checked;
2876
+ const isDisabled = isOtherHierarchySelected && !checked;
2829
2877
  if (!currentDrilldown) return;
2830
2878
  return currentDrilldown && /* @__PURE__ */ React10__default.createElement(React10__default.Fragment, null, /* @__PURE__ */ React10__default.createElement(Group, { mt: "sm", position: "apart", key: level.uri, noWrap: true }, /* @__PURE__ */ React10__default.createElement(
2831
2879
  Checkbox,
2832
2880
  {
2881
+ sx: { cursor: "pointer" },
2833
2882
  onChange: () => {
2834
2883
  if (cut) {
2835
2884
  const active = checked ? false : cut.members.length ? true : false;
@@ -2839,9 +2888,18 @@ function LevelItem({ dimension, hierarchy, isSubMenu, level, locale, activeItems
2839
2888
  },
2840
2889
  checked,
2841
2890
  label,
2842
- size: "xs"
2891
+ size: "xs",
2892
+ disabled: isDisabled || disableUncheck
2843
2893
  }
2844
- ), /* @__PURE__ */ React10__default.createElement(Group, null, /* @__PURE__ */ React10__default.createElement(ActionIcon, { size: "sm", onClick: () => setActiveFilter((value) => !value) }, activeFilter ? /* @__PURE__ */ React10__default.createElement(IconFilterOff, null) : /* @__PURE__ */ React10__default.createElement(IconFilter, null)), /* @__PURE__ */ React10__default.createElement(ThemeIcon, { size: "xs", color: "gray", variant: "light", bg: "transparent" }, /* @__PURE__ */ React10__default.createElement(StackSVG, null)))), activeFilter && /* @__PURE__ */ React10__default.createElement(Box, { pt: "md" }, /* @__PURE__ */ React10__default.createElement(
2894
+ ), /* @__PURE__ */ React10__default.createElement(Group, { sx: { flexWrap: "nowrap" } }, /* @__PURE__ */ React10__default.createElement(
2895
+ ActionIcon,
2896
+ {
2897
+ size: "sm",
2898
+ onClick: () => setActiveFilter((value) => !value),
2899
+ disabled: isDisabled
2900
+ },
2901
+ activeFilter ? /* @__PURE__ */ React10__default.createElement(IconFilterOff, null) : /* @__PURE__ */ React10__default.createElement(IconFilter, null)
2902
+ ), /* @__PURE__ */ React10__default.createElement(ThemeIcon, { size: "xs", color: "gray", variant: "light", bg: "transparent" }, /* @__PURE__ */ React10__default.createElement(StackSVG, null)))), activeFilter && /* @__PURE__ */ React10__default.createElement(Box, { pt: "md" }, /* @__PURE__ */ React10__default.createElement(
2845
2903
  MultiSelect,
2846
2904
  {
2847
2905
  sx: { flex: "1 1 100%" },
@@ -2862,7 +2920,8 @@ function LevelItem({ dimension, hierarchy, isSubMenu, level, locale, activeItems
2862
2920
  label: m.caption ? `${m.caption} ${m.key}` : m.name
2863
2921
  })),
2864
2922
  clearable: true,
2865
- nothingFound: "Nothing found"
2923
+ nothingFound: "Nothing found",
2924
+ disabled: isDisabled
2866
2925
  }
2867
2926
  )));
2868
2927
  }
@@ -2891,20 +2950,12 @@ function getFilterFn(filter) {
2891
2950
  return "lessThan";
2892
2951
  }
2893
2952
  }
2894
- function getFilterValue(filter) {
2895
- const filterFn = getFilterFn(filter);
2896
- const isBetween = filterFn === "between";
2897
- if (isBetween && filter.conditionTwo) {
2898
- return [filter.conditionOne[2], filter.conditionTwo[2]];
2899
- }
2900
- return filter.conditionOne[2];
2901
- }
2902
2953
  function isNotValid(value) {
2903
2954
  return value === null || value === void 0 || Number.isNaN(value);
2904
2955
  }
2905
2956
  function NumberInputComponent({ text, filter }) {
2906
2957
  const actions2 = useActions();
2907
- function getFilterValue2(filter2) {
2958
+ function getFilterValue(filter2) {
2908
2959
  return isNotValid(filter2.conditionOne[2]) || filter2.conditionOne[2] === 0 ? "" : filter2.conditionOne[2];
2909
2960
  }
2910
2961
  function onInputChange({ filter: filter2, value }) {
@@ -2918,7 +2969,7 @@ function NumberInputComponent({ text, filter }) {
2918
2969
  {
2919
2970
  description: text,
2920
2971
  placeholder: text,
2921
- value: getFilterValue2(filter),
2972
+ value: getFilterValue(filter),
2922
2973
  onChange: (value) => onInputChange({ filter, value }),
2923
2974
  sx: { flex: "1 1 auto" },
2924
2975
  size: "xs"
@@ -2933,14 +2984,14 @@ function MinMax({ filter, ...rest }) {
2933
2984
  const active = Boolean(min2) && Boolean(max2);
2934
2985
  actions2.updateFilter(buildFilter({ ...filter2, active, ...conditions }));
2935
2986
  }
2936
- function getFilterValue2(condition) {
2987
+ function getFilterValue(condition) {
2937
2988
  if (condition) {
2938
2989
  return isNotValid(condition[2]) || condition[2] === 0 ? "" : condition[2];
2939
2990
  }
2940
2991
  return "";
2941
2992
  }
2942
- const min = getFilterValue2(filter.conditionOne);
2943
- const max = getFilterValue2(filter.conditionTwo);
2993
+ const min = getFilterValue(filter.conditionOne);
2994
+ const max = getFilterValue(filter.conditionTwo);
2944
2995
  return /* @__PURE__ */ React10__default.createElement(Flex, { gap: "xs" }, /* @__PURE__ */ React10__default.createElement(
2945
2996
  NumberInput,
2946
2997
  {
@@ -3044,18 +3095,23 @@ function FilterItem4({
3044
3095
  const isBetween = filterFn === "between";
3045
3096
  const checked = activeItems.map((active) => active.measure.name).includes(measure.name);
3046
3097
  const actions2 = useActions();
3098
+ const isLastSelected = activeItems.length === 1 && checked;
3047
3099
  return /* @__PURE__ */ React10__default.createElement(Box, { key: measure.name }, /* @__PURE__ */ React10__default.createElement(Group, { mt: "sm", position: "apart" }, /* @__PURE__ */ React10__default.createElement(
3048
3100
  Checkbox,
3049
3101
  {
3102
+ sx: { cursor: "pointer" },
3050
3103
  onChange: () => {
3051
- actions2.updateMeasure({ ...measure, active: !measure.active });
3052
- actions2.updateFilter({ ...filter, active: checked ? false : true });
3104
+ if (!isLastSelected) {
3105
+ actions2.updateMeasure({ ...measure, active: !measure.active });
3106
+ actions2.updateFilter({ ...filter, active: checked ? false : true });
3107
+ }
3053
3108
  },
3054
3109
  checked,
3055
3110
  label: measure.name,
3056
- size: "xs"
3111
+ size: "xs",
3112
+ disabled: isLastSelected
3057
3113
  }
3058
- ), /* @__PURE__ */ React10__default.createElement(Group, null, activeFilter && /* @__PURE__ */ React10__default.createElement(FilterFnsMenu, { filter }), /* @__PURE__ */ React10__default.createElement(ActionIcon, { size: "xs", onClick: () => setActiveFilter((value) => !value) }, activeFilter ? /* @__PURE__ */ React10__default.createElement(IconFilterOff, null) : /* @__PURE__ */ React10__default.createElement(IconFilter, null)), /* @__PURE__ */ React10__default.createElement(ThemeIcon, { size: "xs", color: "gray", variant: "light", bg: "transparent" }, /* @__PURE__ */ React10__default.createElement(BarsSVG, null)))), activeFilter && /* @__PURE__ */ React10__default.createElement(Box, { pt: "md" }, isBetween ? /* @__PURE__ */ React10__default.createElement(MinMax, { filter }) : /* @__PURE__ */ React10__default.createElement(NumberInputComponent, { text, filter })));
3114
+ ), /* @__PURE__ */ React10__default.createElement(Group, { sx: { flexWrap: "nowrap" } }, activeFilter && /* @__PURE__ */ React10__default.createElement(FilterFnsMenu, { filter }), /* @__PURE__ */ React10__default.createElement(ActionIcon, { size: "xs", onClick: () => setActiveFilter((value) => !value) }, activeFilter ? /* @__PURE__ */ React10__default.createElement(IconFilterOff, null) : /* @__PURE__ */ React10__default.createElement(IconFilter, null)), /* @__PURE__ */ React10__default.createElement(ThemeIcon, { size: "xs", color: "gray", variant: "light", bg: "transparent" }, /* @__PURE__ */ React10__default.createElement(BarsSVG, null)))), activeFilter && /* @__PURE__ */ React10__default.createElement(Box, { pt: "md" }, isBetween ? /* @__PURE__ */ React10__default.createElement(MinMax, { filter }) : /* @__PURE__ */ React10__default.createElement(NumberInputComponent, { text, filter })));
3059
3115
  }
3060
3116
  var DrawerMenu_default = AddColumnsDrawer;
3061
3117
  var removeColumn = (actions2, entity, measures, drilldowns) => {
@@ -3138,31 +3194,28 @@ function getFiltersConditions(fn, value) {
3138
3194
  ]);
3139
3195
  return (_a = comparisonMap.get(fn)) == null ? void 0 : _a(value);
3140
3196
  }
3141
- function useTableData({ columns, filters, cuts, pagination }) {
3142
- const normalizedFilters = filters.map((filter) => ({
3143
- id: filter.measure,
3144
- value: getFilterValue(filter)
3145
- // fn: getFilterFn(filter)
3146
- }));
3147
- const normalizedCuts = cuts.map((cut) => ({ id: cut.uniqueName, members: cut.members }));
3148
- const filterKey = JSON.stringify(normalizedFilters);
3149
- const cutKey = JSON.stringify(normalizedCuts);
3197
+ function useTableData({ columns, pagination, cube }) {
3198
+ const { code: locale } = useSelector$1(selectLocale);
3199
+ const permaKey = useKey();
3200
+ const loadingState = useSelector$1(selectLoadingState);
3150
3201
  const actions2 = useActions();
3151
- const columnsStr = JSON.stringify(columns.sort());
3152
3202
  const page = pagination.pageIndex;
3153
- const enabled = Boolean(columns.length) || Boolean(filters.length) || Boolean(cuts.length);
3154
- const initialKey = enabled ? [columnsStr, filterKey, cutKey, page] : "";
3203
+ const enabled = Boolean(columns.length);
3204
+ const initialKey = permaKey ? [permaKey, page] : permaKey;
3155
3205
  const [filterKeydebouced, setDebouncedTerm] = useState(initialKey);
3156
3206
  useEffect(() => {
3157
- if (!enabled) return;
3158
- const handler = debounce(() => {
3159
- const term = [columnsStr, filterKey, cutKey, page];
3160
- setDebouncedTerm(term);
3161
- }, 800);
3207
+ if (!enabled && permaKey) return;
3208
+ const handler = debounce(
3209
+ () => {
3210
+ const term = [permaKey, page];
3211
+ setDebouncedTerm(term);
3212
+ },
3213
+ loadingState.loading ? 0 : 800
3214
+ );
3162
3215
  handler();
3163
3216
  return () => handler.cancel();
3164
- }, [columnsStr, filterKey, cutKey, page, enabled]);
3165
- return useQuery({
3217
+ }, [page, enabled, cube, locale, permaKey]);
3218
+ const query = useQuery({
3166
3219
  queryKey: ["table", filterKeydebouced],
3167
3220
  queryFn: () => {
3168
3221
  return actions2.willExecuteQuery().then((res) => {
@@ -3174,49 +3227,52 @@ function useTableData({ columns, filters, cuts, pagination }) {
3174
3227
  staleTime: 3e5,
3175
3228
  enabled: enabled && !!filterKeydebouced
3176
3229
  });
3230
+ const client = useQueryClient();
3231
+ const cachedData = client.getQueryData(["table", filterKeydebouced]);
3232
+ useUpdatePermaLink({ isFetched: Boolean(cachedData), cube, enabled, isLoading: query.isLoading });
3233
+ return query;
3177
3234
  }
3178
3235
  function usePrefetch({
3179
- data,
3180
3236
  isPlaceholderData,
3181
3237
  limit,
3182
- offset,
3183
3238
  totalRowCount,
3184
- columns,
3185
- cuts,
3186
- filters,
3187
3239
  pagination,
3188
3240
  isFetching
3189
3241
  }) {
3242
+ const { code: locale } = useSelector$1(selectLocale);
3190
3243
  const queryClient2 = useQueryClient();
3191
3244
  const actions2 = useActions();
3245
+ const paramKey = useKey();
3192
3246
  const page = pagination.pageIndex + 1;
3193
3247
  const hasMore = page * pagination.pageSize <= totalRowCount;
3194
3248
  const off = page * pagination.pageSize;
3195
- const normalizedFilters = filters.map((filter) => ({
3196
- id: filter.measure,
3197
- value: getFilterValue(filter)
3198
- // fn: getFilterFn(filter)
3199
- }));
3200
- const normalizedCuts = cuts.map((cut) => ({ id: cut.uniqueName, members: cut.members }));
3201
- const filterKey = JSON.stringify(normalizedFilters);
3202
- const cutKey = JSON.stringify(normalizedCuts);
3203
- const columnsStr = JSON.stringify(columns.sort());
3204
- const key = [columnsStr, filterKey, cutKey, page];
3249
+ const key = [paramKey, page];
3205
3250
  React10__default.useEffect(() => {
3206
3251
  if (!isPlaceholderData && hasMore && !isFetching) {
3207
3252
  queryClient2.prefetchQuery({
3208
3253
  queryKey: ["table", key],
3209
3254
  queryFn: () => {
3210
3255
  return actions2.willExecuteQuery({ offset: off, limit }).then((res) => {
3211
- const { data: data2, types } = res;
3212
- const { data: tableData, page: page2 } = data2;
3256
+ const { data, types } = res;
3257
+ const { data: tableData, page: page2 } = data;
3213
3258
  return { data: tableData != null ? tableData : [], types, page: page2 };
3214
3259
  });
3215
3260
  },
3216
3261
  staleTime: 3e5
3217
3262
  });
3218
3263
  }
3219
- }, [limit, page, isPlaceholderData, key, queryClient2, hasMore, off, isFetching]);
3264
+ }, [
3265
+ limit,
3266
+ page,
3267
+ isPlaceholderData,
3268
+ key,
3269
+ queryClient2,
3270
+ hasMore,
3271
+ off,
3272
+ isFetching,
3273
+ locale,
3274
+ paramKey
3275
+ ]);
3220
3276
  }
3221
3277
  function useTable({
3222
3278
  cube,
@@ -3225,16 +3281,16 @@ function useTable({
3225
3281
  columnSorting = () => 0,
3226
3282
  ...mantineTableProps
3227
3283
  }) {
3228
- const { types } = result;
3229
3284
  const filterItems = useSelector$1(selectFilterItems);
3230
3285
  const filtersMap = useSelector$1(selectFilterMap);
3231
3286
  const measuresOlap = useSelector$1(selectOlapMeasureItems);
3232
3287
  const measuresMap = useSelector$1(selectMeasureMap);
3233
3288
  const drilldowns = useSelector$1(selectDrilldownItems);
3234
3289
  const measures = useSelector$1(selectMeasureItems);
3290
+ useSelector$1(selectCutItems);
3235
3291
  const actions2 = useActions();
3236
- const itemsCuts = useSelector$1(selectCutItems);
3237
3292
  const { limit, offset } = useSelector$1(selectPaginationParams);
3293
+ useSelector$1(selectLoadingState);
3238
3294
  const [pagination, setPagination] = useState({
3239
3295
  pageIndex: offset,
3240
3296
  pageSize: limit
@@ -3268,27 +3324,19 @@ function useTable({
3268
3324
  return { measure, filter };
3269
3325
  });
3270
3326
  }, [measuresMap, measuresOlap, filtersMap, filterItems]);
3271
- const { isLoading, isFetching, isError, data, isPlaceholderData } = useTableData({
3327
+ const { isLoading, isFetching, isFetched, isError, data, isPlaceholderData, status, fetchStatus } = useTableData({
3272
3328
  columns: finalUniqueKeys,
3273
- filters: filterItems.filter(
3274
- (f) => isActiveItem(f) && isActiveItem(measures.find((m) => m.name === f.measure) || { active: false })
3275
- ),
3276
- cuts: itemsCuts.filter(isActiveCut),
3277
- pagination
3329
+ pagination,
3330
+ cube: cube.name
3278
3331
  });
3279
3332
  const tableData = (data == null ? void 0 : data.data) || [];
3280
- const tableTypes = (data == null ? void 0 : data.types) || types;
3333
+ const tableTypes = (data == null ? void 0 : data.types) || {};
3281
3334
  const totalRowCount = data == null ? void 0 : data.page.total;
3282
3335
  const finalKeys = Object.values(tableTypes).filter((t2) => !t2.isId).filter(columnFilter).sort(columnSorting);
3283
3336
  usePrefetch({
3284
- data: tableData,
3285
3337
  isPlaceholderData,
3286
- offset,
3287
3338
  limit,
3288
3339
  totalRowCount,
3289
- columns: finalUniqueKeys,
3290
- filters: filterItems.filter(isActiveItem),
3291
- cuts: itemsCuts.filter(isActiveCut),
3292
3340
  pagination,
3293
3341
  isFetching: isFetching || isLoading
3294
3342
  });
@@ -3465,6 +3513,8 @@ function useTable({
3465
3513
  }),
3466
3514
  [isError]
3467
3515
  );
3516
+ const isTransitionState = status !== "success" && !isError;
3517
+ const isLoad = isLoading || data === void 0 || isTransitionState;
3468
3518
  const table = useMantineReactTable({
3469
3519
  columns,
3470
3520
  data: tableData,
@@ -3475,7 +3525,7 @@ function useTable({
3475
3525
  manualSorting: false,
3476
3526
  rowCount: totalRowCount,
3477
3527
  state: {
3478
- isLoading: isLoading || isFetching || data === void 0,
3528
+ isLoading: isLoading || data === void 0 || isTransitionState,
3479
3529
  pagination,
3480
3530
  showAlertBanner: isError,
3481
3531
  showProgressBars: isFetching || isLoading
@@ -3483,10 +3533,11 @@ function useTable({
3483
3533
  ...constTableProps,
3484
3534
  ...mantineTableProps
3485
3535
  });
3486
- return { table, isError, isLoading, data: tableData, columns };
3536
+ return { table, isError, isLoading: isLoad, data: tableData, columns };
3487
3537
  }
3488
- function TableView({ table, result, isError, isLoading = false, data, columns }) {
3538
+ function TableView({ table, result, isError, isLoading = false, data }) {
3489
3539
  const isData = Boolean(table.getRowModel().rows.length);
3540
+ const loadingState = useSelector$1(selectLoadingState);
3490
3541
  return /* @__PURE__ */ React10__default.createElement(Box, { sx: { height: "100%" } }, /* @__PURE__ */ React10__default.createElement(Flex, { direction: "column", justify: "space-between", sx: { height: "100%", flex: "1 1 auto" } }, /* @__PURE__ */ React10__default.createElement(MRT_ProgressBar, { isTopToolbar: false, table }), /* @__PURE__ */ React10__default.createElement(
3491
3542
  ScrollArea,
3492
3543
  {
@@ -3497,7 +3548,7 @@ function TableView({ table, result, isError, isLoading = false, data, columns })
3497
3548
  overflow: "scroll"
3498
3549
  }
3499
3550
  },
3500
- /* @__PURE__ */ React10__default.createElement(LoadingOverlay, { visible: columns.length === 0 && isLoading }),
3551
+ /* @__PURE__ */ React10__default.createElement(LoadingOverlay, { visible: isLoading || loadingState.loading }),
3501
3552
  /* @__PURE__ */ React10__default.createElement(
3502
3553
  Table,
3503
3554
  {
@@ -3571,7 +3622,7 @@ function TableView({ table, result, isError, isLoading = false, data, columns })
3571
3622
  )))))
3572
3623
  ),
3573
3624
  !isData && !isError && !isLoading && /* @__PURE__ */ React10__default.createElement(NoRecords, null)
3574
- ), /* @__PURE__ */ React10__default.createElement(MRT_ToolbarAlertBanner, { stackAlertBanner: true, table }), /* @__PURE__ */ React10__default.createElement(TableFooter_default, { table, data, result })));
3625
+ ), /* @__PURE__ */ React10__default.createElement(MRT_ToolbarAlertBanner, { stackAlertBanner: true, table }), /* @__PURE__ */ React10__default.createElement(TableFooter_default, { table, data, result, isLoading })));
3575
3626
  }
3576
3627
  var ColumnFilterCell = ({
3577
3628
  header,
@@ -3882,7 +3933,7 @@ function SuccessResult(props) {
3882
3933
  w: "100%"
3883
3934
  },
3884
3935
  /* @__PURE__ */ React10__default.createElement(ExplorerTabs, { panels, onChange: tabHandler, value: panelKey }),
3885
- (!queryItem.panel || queryItem.panel === "table") && /* @__PURE__ */ React10__default.createElement(Group, { sx: { display: "flex", flex: "0 1 auto" }, mr: "sm", noWrap: true }, /* @__PURE__ */ React10__default.createElement(DrawerMenu_default, null), /* @__PURE__ */ React10__default.createElement(Toolbar, { table, fullscreen }))
3936
+ (!queryItem.panel || queryItem.panel === "table") && /* @__PURE__ */ React10__default.createElement(Group, { sx: { display: "flex", flex: "0 1 auto", gap: "0.5rem" }, mr: "sm", noWrap: true }, /* @__PURE__ */ React10__default.createElement(Toolbar, { table, fullscreen }), /* @__PURE__ */ React10__default.createElement(DrawerMenu_default, null))
3886
3937
  ), isPreviewMode && /* @__PURE__ */ React10__default.createElement(Alert, { id: "alert-load-all-results", color: "yellow", radius: 0, sx: { flex: "0 0 auto" } }, /* @__PURE__ */ React10__default.createElement(Group, { position: "apart" }, /* @__PURE__ */ React10__default.createElement(Text, null, /* @__PURE__ */ React10__default.createElement(Text, { fw: 700, span: true }, t("previewMode.title_preview"), ":", " "), /* @__PURE__ */ React10__default.createElement(Text, { span: true }, t("previewMode.description_preview", { limit: previewLimit }))), /* @__PURE__ */ React10__default.createElement(PreviewModeSwitch, null))), /* @__PURE__ */ React10__default.createElement(Box, { id: "query-results-content", sx: { flex: "1 1", height: "calc(100% - 60px)" } }, /* @__PURE__ */ React10__default.createElement(Suspense, { fallback: props.children }, /* @__PURE__ */ React10__default.createElement(Flex, { h: "100%" }, /* @__PURE__ */ React10__default.createElement(Box, { sx: { flex: "1 1", overflowX: "scroll" } }, /* @__PURE__ */ React10__default.createElement(
3887
3938
  CurrentComponent,
3888
3939
  {
@@ -4372,31 +4423,17 @@ init_esm_shims();
4372
4423
  init_esm_shims();
4373
4424
  function useSelectCube(onSelectCube) {
4374
4425
  const { updateMeasure, updateCut, updateDrilldown, willFetchMembers: willFetchMembers2 } = useActions();
4375
- useCallback((level, dimensions) => {
4376
- const drilldownItem = buildDrilldown(level);
4377
- createCutHandler2(level);
4378
- updateDrilldown(drilldownItem);
4379
- return willFetchMembers2({ ...level, level: level.name }).then((members) => {
4380
- const dimension = dimensions.find((dim) => dim.name === level.dimension);
4381
- if (!dimension) return;
4382
- return updateDrilldown({
4383
- ...drilldownItem,
4384
- dimType: dimension.dimensionType,
4385
- memberCount: members.length,
4386
- members
4387
- });
4388
- });
4389
- }, []);
4426
+ const actions2 = useActions();
4390
4427
  const createCutHandler2 = React10__default.useCallback((level) => {
4391
4428
  const cutItem = buildCut({ ...level });
4392
4429
  cutItem.active = false;
4393
4430
  updateCut(cutItem);
4394
4431
  }, []);
4395
- function createDrilldown(level, dimensions) {
4432
+ async function createDrilldown(level, dimensions) {
4396
4433
  const drilldown = buildDrilldown({ ...level, key: stringifyName(level), active: true });
4397
4434
  updateDrilldown(drilldown);
4398
4435
  createCutHandler2({ ...level, key: stringifyName(level) });
4399
- willFetchMembers2({ ...level, level: level.name }).then((members) => {
4436
+ await willFetchMembers2({ ...level, level: level.name }).then((members) => {
4400
4437
  const dimension = dimensions.find((dim) => dim.name === level.dimension);
4401
4438
  if (!dimension) return;
4402
4439
  updateDrilldown({
@@ -4413,9 +4450,8 @@ function useSelectCube(onSelectCube) {
4413
4450
  const drilldowns = deriveDrilldowns(dimensions);
4414
4451
  if (measure && drilldowns.length > 0) {
4415
4452
  updateMeasure({ ...measure, active: true });
4416
- for (const level of drilldowns) {
4417
- createDrilldown(level, dimensions);
4418
- }
4453
+ const promises = drilldowns.map((level) => createDrilldown(level, dimensions));
4454
+ return Promise.all(promises).then(() => actions2.setLoadingState("SUCCESS"));
4419
4455
  }
4420
4456
  });
4421
4457
  }
@@ -4570,9 +4606,10 @@ function getCube(items, table, subtopic, locale) {
4570
4606
  return cube;
4571
4607
  }
4572
4608
  function useBuildGraph(items, locale, graph, setGraph) {
4609
+ const [filteredItems, setFilteredItems] = useState([]);
4573
4610
  useEffect(() => {
4574
4611
  const graph2 = new graph_default();
4575
- items.map((item) => {
4612
+ const filteredItems2 = items.map((item) => {
4576
4613
  const { name: name4 } = item;
4577
4614
  const topic = getAnnotation(item, "topic", locale);
4578
4615
  const subtopic = getAnnotation(item, "subtopic", locale);
@@ -4584,13 +4621,15 @@ function useBuildGraph(items, locale, graph, setGraph) {
4584
4621
  graph2.addNode(name4);
4585
4622
  graph2.addEdge(topic, subtopic);
4586
4623
  graph2.addEdge(subtopic, name4);
4624
+ return item;
4587
4625
  }
4588
- return item;
4589
- });
4590
- graph2.items = items;
4626
+ return null;
4627
+ }).filter(Boolean);
4628
+ setFilteredItems(filteredItems2);
4629
+ graph2.items = filteredItems2;
4591
4630
  setGraph(graph2);
4592
4631
  }, [items, locale, setGraph]);
4593
- return { graph };
4632
+ return { graph, filteredItems };
4594
4633
  }
4595
4634
  function CubeTree({
4596
4635
  items,
@@ -4599,20 +4638,26 @@ function CubeTree({
4599
4638
  }) {
4600
4639
  const { graph, setGraph, map, input } = useSideBar();
4601
4640
  const { translate: t } = useTranslation();
4602
- useBuildGraph(items, locale, graph, setGraph);
4641
+ const { filteredItems } = useBuildGraph(items, locale, graph, setGraph);
4603
4642
  const actions2 = useActions();
4643
+ const query = useSelector$1(selectCurrentQueryParams);
4604
4644
  const onSelectCube = (table, subtopic) => {
4605
4645
  const cube = items.find(
4606
4646
  (item) => item.name === table && getAnnotation(item, "subtopic", locale) === subtopic
4607
4647
  );
4608
4648
  if (cube) {
4609
- actions2.resetDrilldowns({});
4610
- actions2.resetCuts({});
4611
- actions2.resetMeasures({});
4649
+ const { drilldowns, cuts, filters, measures, ...newQuery } = query;
4650
+ actions2.setLoadingState("FETCHING");
4651
+ actions2.resetAllParams(newQuery);
4652
+ actions2.updateResult({ data: [], types: {}, url: "", status: 200 });
4612
4653
  return actions2.willSetCube(cube.name);
4613
4654
  }
4614
4655
  };
4615
- const topics = useMemo(() => getKeys2(items, "topic", locale), [items, locale]);
4656
+ let topics = useMemo(
4657
+ () => getKeys2(filteredItems, "topic", locale),
4658
+ [filteredItems, locale]
4659
+ );
4660
+ topics = [topics[0], topics[1]];
4616
4661
  if (input.length > 0 && map && !(map.size > 0)) {
4617
4662
  return /* @__PURE__ */ React10__default.createElement(Text, { ta: "center", fz: "xs", my: "sm", italic: true }, t("params.label_no_results"));
4618
4663
  }
@@ -4822,10 +4867,14 @@ var useStyles4 = createStyles((theme, params) => ({
4822
4867
  }
4823
4868
  }));
4824
4869
  function ExplorerContent(props) {
4825
- useMantineTheme();
4826
- useState(false);
4870
+ const { setSource } = props;
4827
4871
  const translation = useTranslation();
4828
- useSetup(props.source, props.dataLocale, props.defaultCube);
4872
+ const done = useSetup(props.source, props.dataLocale, props.defaultCube);
4873
+ useEffect(() => {
4874
+ if (setSource) {
4875
+ setSource({ loading: !done });
4876
+ }
4877
+ }, [setSource, done]);
4829
4878
  const { classes } = useStyles4({ height: props.height });
4830
4879
  useEffect(() => {
4831
4880
  if (props.uiLocale) translation.setLocale(props.uiLocale);
@@ -5506,7 +5555,9 @@ function ExplorerComponent(props) {
5506
5555
  previewLimit = 50,
5507
5556
  withinMantineProvider = true,
5508
5557
  withinReduxProvider = false,
5509
- withMultiQuery = false
5558
+ withMultiQuery = false,
5559
+ setSource,
5560
+ source
5510
5561
  } = props;
5511
5562
  const locale = useMemo(() => dataLocale.toString().split(","), [dataLocale]);
5512
5563
  const panels = useMemo(
@@ -5540,11 +5591,12 @@ function ExplorerComponent(props) {
5540
5591
  /* @__PURE__ */ React10__default.createElement(TranslationProvider, { defaultLocale: props.uiLocale, translations: props.translations }, /* @__PURE__ */ React10__default.createElement(
5541
5592
  ExplorerContent,
5542
5593
  {
5594
+ setSource,
5543
5595
  dataLocale: locale,
5544
5596
  defaultOpenParams,
5545
5597
  height,
5546
5598
  panels,
5547
- source: props.source,
5599
+ source,
5548
5600
  splash: props.splash,
5549
5601
  uiLocale: props.uiLocale,
5550
5602
  defaultCube: props.defaultCube,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datawheel/data-explorer",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "exports": {
5
5
  ".": {
6
6
  "import": "./dist/main.js"