@datawheel/data-explorer 0.2.9 → 0.2.11

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 +130 -18
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { keyframes, createStyles, Select, rem, Flex, Title, Text, Group, Button, Input, Box, Stack, SimpleGrid, ScrollArea, LoadingOverlay, Table, MultiSelect, Center, NumberInput, Menu, ActionIcon, UnstyledButton, Alert, Loader, Container, Modal, useMantineTheme, MantineProvider, Paper, useComponentDefaultProps, Anchor, Tabs, Switch, ThemeIcon, Tooltip, CloseButton, Drawer, Divider, Checkbox, packSx, Affix, Accordion, Popover } from '@mantine/core';
2
2
  import { useClipboard, useClickOutside, useFullscreen, useDebouncedState, useMediaQuery, useDisclosure } from '@mantine/hooks';
3
- import { IconWorld, IconExternalLink, IconClipboard, IconSettings, IconMathGreater, IconMathLower, IconArrowsLeftRight, IconAlertCircle, IconAlertTriangle, IconCopy, IconDownload, IconDotsVertical, IconArrowRight, IconArrowLeft, IconArrowsMinimize, IconArrowsMaximize, IconTrash, IconInfoCircleFilled, IconSearch, IconPhotoDown, IconVectorTriangle, IconArrowsSort, IconSortDescendingNumbers, IconSortDescendingLetters, IconSortAscendingNumbers, IconSortAscendingLetters, IconPlus, IconStack3, IconFilterOff, IconFilter, IconBox, IconClock, IconHelpCircle, IconLanguage } from '@tabler/icons-react';
3
+ import { IconWorld, IconExternalLink, IconClipboard, IconSettings, IconMathGreater, IconMathLower, IconArrowsLeftRight, IconAlertCircle, IconAlertTriangle, IconCopy, IconDownload, IconDotsVertical, IconArrowRight, IconArrowLeft, IconArrowsMinimize, IconArrowsMaximize, IconTrash, IconInfoCircleFilled, IconSearch, IconPhotoDown, IconVectorTriangle, IconArrowsSort, IconSortDescendingNumbers, IconSortDescendingLetters, IconSortAscendingNumbers, IconSortAscendingLetters, IconPlus, IconStack3, IconFilterOff, IconFilter, IconAdjustments, IconBox, IconClock, IconHelpCircle, IconLanguage } from '@tabler/icons-react';
4
4
  import * as React13 from 'react';
5
5
  import React13__default, { createContext, forwardRef, useMemo, useCallback, useContext, useRef, useEffect, useState, Suspense, useLayoutEffect } from 'react';
6
6
  import { translationFactory } from '@datawheel/use-translation';
@@ -235,6 +235,7 @@ var defaultTranslation = {
235
235
  message_default: "Please wait..."
236
236
  },
237
237
  params: {
238
+ add_metadata: "Add metadata",
238
239
  action_clear: "Clear query",
239
240
  action_clear_description: "Clear all parameters from your current query",
240
241
  action_execute: "Execute query",
@@ -1265,6 +1266,10 @@ var queriesSlice = createSlice({
1265
1266
  query.params.sortDir = payload.dir;
1266
1267
  query.params.sortKey = payload.key;
1267
1268
  },
1269
+ clearSorting(state) {
1270
+ const query = taintCurrentQuery(state);
1271
+ query.params.sortKey = void 0;
1272
+ },
1268
1273
  /**
1269
1274
  * Registers the result of the current QueryItem in the store.
1270
1275
  */
@@ -1334,7 +1339,7 @@ var selectPaginationParams = createSelector(selectCurrentQueryParams, (params) =
1334
1339
  limit: params.pagiLimit || 0,
1335
1340
  offset: params.pagiOffset || 0
1336
1341
  }));
1337
- createSelector(selectCurrentQueryParams, (params) => ({
1342
+ var selectSortingParams = createSelector(selectCurrentQueryParams, (params) => ({
1338
1343
  sortKey: params.sortKey || "",
1339
1344
  sortDir: params.sortDir
1340
1345
  }));
@@ -2193,7 +2198,7 @@ createSelector(
2193
2198
  selectOlapDimensionItems,
2194
2199
  (dimensions) => Object.fromEntries(dimensions.map((item) => [item.name, item]))
2195
2200
  );
2196
- createSelector(
2201
+ var selectLevelTriadMap = createSelector(
2197
2202
  selectOlapCube,
2198
2203
  (cube) => cube ? mapDimensionHierarchyLevels(cube) : {}
2199
2204
  );
@@ -2797,7 +2802,19 @@ function FullScreenSVG() {
2797
2802
  }
2798
2803
 
2799
2804
  // src/components/TableView.tsx
2800
- var removeColumn = (actions2, entity, measures, drilldowns) => {
2805
+ function isColumnSorted(column, key) {
2806
+ return column == key;
2807
+ }
2808
+ var propertiesUpdateHandler = (actions2, item, activeProps) => {
2809
+ const properties = item.properties.map(
2810
+ (prop) => buildProperty({
2811
+ ...prop,
2812
+ active: activeProps.includes(prop.key)
2813
+ })
2814
+ );
2815
+ actions2.updateDrilldown({ ...item, properties });
2816
+ };
2817
+ var removeColumn = (actions2, entity, measures, drilldowns, type) => {
2801
2818
  if ("aggregator" in entity) {
2802
2819
  const measure = measures.find((d) => d.name === entity.name);
2803
2820
  measure && actions2.updateMeasure({ ...measure, active: false });
@@ -2806,10 +2823,21 @@ var removeColumn = (actions2, entity, measures, drilldowns) => {
2806
2823
  const drilldown = drilldowns.find((d) => d.level === entity.name);
2807
2824
  drilldown && actions2.updateDrilldown({ ...drilldown, active: false });
2808
2825
  }
2826
+ if (isProperty(type)) {
2827
+ const activeDrilldowns = drilldowns.filter((d) => d.active);
2828
+ const drilldown = activeDrilldowns.find(
2829
+ (dd) => dd.properties.some((property) => property.name === entity.name)
2830
+ );
2831
+ const activeProperties = drilldown == null ? void 0 : drilldown.properties.filter((p) => p.active).filter((p) => p.name !== entity.name).filter((p) => p.active).map((p) => p.name);
2832
+ if (drilldown && activeProperties) {
2833
+ propertiesUpdateHandler(actions2, drilldown, activeProperties);
2834
+ }
2835
+ }
2809
2836
  };
2837
+ var isProperty = (entity) => entity === "property";
2810
2838
  function showTrashIcon(columns, type) {
2811
2839
  const result = columns.filter((c) => c.entityType === type);
2812
- return result.length > 1;
2840
+ return result.length > 1 || isProperty(type);
2813
2841
  }
2814
2842
  var getActionIcon = (entityType) => {
2815
2843
  if (entityType === "measure") {
@@ -2824,6 +2852,8 @@ var getEntityText = (entityType) => {
2824
2852
  return "Metric";
2825
2853
  case "level":
2826
2854
  return "Dimension";
2855
+ case "property":
2856
+ return "Property";
2827
2857
  default:
2828
2858
  return "";
2829
2859
  }
@@ -3026,6 +3056,7 @@ function useTable({
3026
3056
  const { currentFormats, getAvailableKeys, getFormatter, getFormatterKey, setFormat } = useFormatter(
3027
3057
  cube.measures
3028
3058
  );
3059
+ const { sortKey, sortDir } = useSelector$1(selectSortingParams);
3029
3060
  const columns = useMemo(() => {
3030
3061
  const indexColumn = {
3031
3062
  id: "#",
@@ -3066,22 +3097,33 @@ function useTable({
3066
3097
  return 0;
3067
3098
  },
3068
3099
  Header: ({ column: column2 }) => {
3100
+ const isSorted = isColumnSorted(entity.name, sortKey);
3069
3101
  return /* @__PURE__ */ React13__default.createElement(Box, { mb: rem(5), key: "header" }, /* @__PURE__ */ React13__default.createElement(Flex, { justify: "center", align: "center" }, /* @__PURE__ */ React13__default.createElement(Box, { sx: { flexGrow: 1 } }, /* @__PURE__ */ React13__default.createElement(Flex, { gap: "xs", align: "center" }, getActionIcon(entityType), /* @__PURE__ */ React13__default.createElement(Text, { size: "sm" }, header), /* @__PURE__ */ React13__default.createElement(
3070
3102
  ActionIcon,
3071
3103
  {
3072
3104
  key: `sort-${header}`,
3073
3105
  size: 22,
3074
3106
  ml: rem(5),
3075
- onClick: column2.getToggleSortingHandler()
3107
+ onClick: () => {
3108
+ if (!isSorted) {
3109
+ actions2.updateSorting({ key: entity.name, dir: "desc" });
3110
+ }
3111
+ if (isSorted && sortDir === "desc") {
3112
+ actions2.updateSorting({ key: entity.name, dir: "asc" });
3113
+ }
3114
+ if (isSorted && sortDir === "asc") {
3115
+ actions2.clearSorting();
3116
+ }
3117
+ }
3076
3118
  },
3077
- getSortIcon(column2.getIsSorted(), entityType)
3119
+ getSortIcon(isSorted ? sortDir : false, entityType)
3078
3120
  ))), /* @__PURE__ */ React13__default.createElement(
3079
3121
  CustomActionIcon_default,
3080
3122
  {
3081
3123
  label: `At least one ${getEntityText(entityType)} is required.`,
3082
3124
  key: `remove-${column2.columnDef.header}`,
3083
3125
  disabled: !showTrashIcon(finalKeys, entityType),
3084
- onClick: () => removeColumn(actions2, entity, measures, drilldowns),
3126
+ onClick: () => removeColumn(actions2, entity, measures, drilldowns, entityType),
3085
3127
  showTooltip: !showTrashIcon(finalKeys, entityType),
3086
3128
  size: 25,
3087
3129
  ml: rem(5)
@@ -3197,7 +3239,7 @@ function useTable({
3197
3239
  enableHiding: false,
3198
3240
  manualFiltering: true,
3199
3241
  manualPagination: true,
3200
- manualSorting: false,
3242
+ manualSorting: true,
3201
3243
  rowCount: totalRowCount,
3202
3244
  state: {
3203
3245
  isLoading: isLoading || data === void 0 || isTransitionState,
@@ -3430,7 +3472,17 @@ function AddColumnsDrawer() {
3430
3472
  },
3431
3473
  /* @__PURE__ */ React13__default.createElement(MeasuresOptions, null),
3432
3474
  /* @__PURE__ */ React13__default.createElement(DrillDownOptions, null)
3433
- ), /* @__PURE__ */ React13__default.createElement(Group, { position: "center", sx: { flexWrap: "nowrap" } }, smallerThanMd ? /* @__PURE__ */ React13__default.createElement(ActionIcon, { onClick: open, size: "md", variant: "filled", color: theme.primaryColor }, /* @__PURE__ */ React13__default.createElement(IconStack3, { size: "0.75rem" })) : /* @__PURE__ */ React13__default.createElement(Button, { id: "dex-column-btn", leftIcon: /* @__PURE__ */ React13__default.createElement(IconPlus, { size: "1.2rem" }), onClick: open, m: "md", size: "sm" }, t("params.add_columns"))));
3475
+ ), /* @__PURE__ */ React13__default.createElement(Group, { position: "center", sx: { flexWrap: "nowrap" } }, smallerThanMd ? /* @__PURE__ */ React13__default.createElement(ActionIcon, { onClick: open, size: "md", variant: "filled", color: theme.primaryColor }, /* @__PURE__ */ React13__default.createElement(IconStack3, { size: "0.75rem" })) : /* @__PURE__ */ React13__default.createElement(
3476
+ Button,
3477
+ {
3478
+ id: "dex-column-btn",
3479
+ leftIcon: /* @__PURE__ */ React13__default.createElement(IconPlus, { size: "1.2rem" }),
3480
+ onClick: open,
3481
+ m: "md",
3482
+ size: "sm"
3483
+ },
3484
+ t("params.add_columns")
3485
+ )));
3434
3486
  }
3435
3487
  function DrillDownOptions() {
3436
3488
  const locale = useSelector$1(selectLocale);
@@ -3468,13 +3520,22 @@ function DimensionItem({
3468
3520
  activeItems
3469
3521
  }
3470
3522
  ));
3471
- return /* @__PURE__ */ React13__default.createElement("div", { key: dimension.name, className: "dex-dimension-control", id: `dex-dimension-${dimension.name}` }, /* @__PURE__ */ React13__default.createElement(
3472
- Divider,
3523
+ return /* @__PURE__ */ React13__default.createElement(
3524
+ "div",
3473
3525
  {
3474
- my: "md",
3475
- label: /* @__PURE__ */ React13__default.createElement(Group, null, getIconForDimensionType(dimension.type), /* @__PURE__ */ React13__default.createElement(Text, { italic: true }, getCaption(dimension, locale)))
3476
- }
3477
- ), options);
3526
+ key: dimension.name,
3527
+ className: "dex-dimension-control",
3528
+ id: `dex-dimension-${dimension.name}`
3529
+ },
3530
+ /* @__PURE__ */ React13__default.createElement(
3531
+ Divider,
3532
+ {
3533
+ my: "md",
3534
+ label: /* @__PURE__ */ React13__default.createElement(Group, null, getIconForDimensionType(dimension.type), /* @__PURE__ */ React13__default.createElement(Text, { italic: true }, getCaption(dimension, locale)))
3535
+ }
3536
+ ),
3537
+ options
3538
+ );
3478
3539
  }
3479
3540
  function HierarchyItem({
3480
3541
  dimension,
@@ -3524,6 +3585,7 @@ function LevelItem({
3524
3585
  depth = 0
3525
3586
  }) {
3526
3587
  const [activeFilter, setActiveFilter] = useState(false);
3588
+ const [activePropertiesFilter, setActiveProperties] = useState(false);
3527
3589
  const { translate: t } = useTranslation();
3528
3590
  const actions2 = useActions();
3529
3591
  const cutItems = useSelector$1(selectCutItems);
@@ -3584,6 +3646,7 @@ function LevelItem({
3584
3646
  const isDisabled = isOtherHierarchySelected && !checked;
3585
3647
  if (!currentDrilldown) return;
3586
3648
  const paddingLeft = `${5 * depth + 5}px`;
3649
+ const properities = currentDrilldown.properties.length ? currentDrilldown.properties : null;
3587
3650
  return currentDrilldown && /* @__PURE__ */ React13__default.createElement(React13__default.Fragment, null, /* @__PURE__ */ React13__default.createElement(Group, { className: "dex-level-control", mt: "sm", position: "apart", key: level.name, noWrap: true }, /* @__PURE__ */ React13__default.createElement(
3588
3651
  Checkbox,
3589
3652
  {
@@ -3612,7 +3675,7 @@ function LevelItem({
3612
3675
  disabled: isDisabled
3613
3676
  },
3614
3677
  activeFilter ? /* @__PURE__ */ React13__default.createElement(IconFilterOff, null) : /* @__PURE__ */ React13__default.createElement(IconFilter, null)
3615
- ), /* @__PURE__ */ React13__default.createElement(ThemeIcon, { size: "xs", color: "gray", variant: "light", bg: "transparent" }, /* @__PURE__ */ React13__default.createElement(StackSVG, null)))), activeFilter && /* @__PURE__ */ React13__default.createElement(Box, { pt: "md" }, /* @__PURE__ */ React13__default.createElement(
3678
+ ), properities && /* @__PURE__ */ React13__default.createElement(Tooltip, { label: t("params.add_metadata") }, /* @__PURE__ */ React13__default.createElement(ActionIcon, { onClick: () => setActiveProperties((value) => !value) }, /* @__PURE__ */ React13__default.createElement(IconAdjustments, null))), /* @__PURE__ */ React13__default.createElement(ThemeIcon, { size: "xs", color: "gray", variant: "light", bg: "transparent" }, /* @__PURE__ */ React13__default.createElement(StackSVG, null)))), activeFilter && /* @__PURE__ */ React13__default.createElement(Box, { pt: "md" }, /* @__PURE__ */ React13__default.createElement(
3616
3679
  MultiSelect,
3617
3680
  {
3618
3681
  sx: { flex: "1 1 100%" },
@@ -3636,7 +3699,56 @@ function LevelItem({
3636
3699
  nothingFound: "Nothing found",
3637
3700
  disabled: isDisabled
3638
3701
  }
3639
- )));
3702
+ )), activePropertiesFilter && /* @__PURE__ */ React13__default.createElement(PropertiesMultiSelect, { item: currentDrilldown }));
3703
+ }
3704
+ function PropertiesMultiSelect({ item }) {
3705
+ const levelTriadMap = useSelector$1(selectLevelTriadMap);
3706
+ const locale = useSelector$1(selectLocale);
3707
+ const actions2 = useActions();
3708
+ const { translate: t } = useTranslation();
3709
+ const propertiesUpdateHandler2 = useCallback(
3710
+ (activeProps) => {
3711
+ const properties = item.properties.map(
3712
+ (prop) => buildProperty({
3713
+ ...prop,
3714
+ active: activeProps.includes(prop.key)
3715
+ })
3716
+ );
3717
+ actions2.updateDrilldown({ ...item, properties });
3718
+ },
3719
+ [item]
3720
+ );
3721
+ const activeProperties = filterMap(
3722
+ item.properties,
3723
+ (item2) => isActiveItem(item2) ? item2.key : null
3724
+ );
3725
+ const label = useMemo(() => {
3726
+ const triad = levelTriadMap[`${item.level}`];
3727
+ const triadCaptions = triad.map((item2) => getCaption(item2, locale.code));
3728
+ return t("params.tag_drilldowns", {
3729
+ abbr: abbreviateFullName(triadCaptions, t("params.tag_drilldowns_abbrjoint")),
3730
+ dimension: triadCaptions[0],
3731
+ hierarchy: triadCaptions[1],
3732
+ level: triadCaptions[2],
3733
+ propCount: activeProperties.length
3734
+ });
3735
+ }, [activeProperties.join("-"), item, locale.code]);
3736
+ return /* @__PURE__ */ React13__default.createElement(Box, { pt: "md" }, /* @__PURE__ */ React13__default.createElement(
3737
+ MultiSelect,
3738
+ {
3739
+ sx: { flex: "1 1 100%" },
3740
+ searchable: true,
3741
+ onChange: propertiesUpdateHandler2,
3742
+ value: activeProperties || [],
3743
+ placeholder: `Filter by ${label}`,
3744
+ data: item.properties.map((property) => ({
3745
+ value: String(property.key),
3746
+ label: property.name
3747
+ })),
3748
+ clearable: true,
3749
+ nothingFound: "Nothing found"
3750
+ }
3751
+ ));
3640
3752
  }
3641
3753
  function getFilterfnKey(type) {
3642
3754
  switch (type) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datawheel/data-explorer",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
4
4
  "exports": {
5
5
  ".": {
6
6
  "import": "./dist/main.js"