@datawheel/bespoke 0.3.14 → 0.3.16

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/index.js CHANGED
@@ -24,7 +24,7 @@ import { dataConcat, dataLoad } from 'd3plus-viz';
24
24
  import * as d3plus from 'd3plus-react';
25
25
  import Router, { useRouter } from 'next/router';
26
26
  import { useMediaQuery, useClickOutside, useDisclosure, useDebouncedValue, useSetState, useHotkeys, useFullscreen, getHotkeyHandler } from '@mantine/hooks';
27
- import { IconDice, IconBoxMultiple, IconEyeOff, IconChevronDown, IconInfoCircle, IconRefresh, IconSearch, IconPlus, IconHeading, IconApi, IconPercentage, IconChartBar, IconAlignLeft, IconSelector, IconPhoto, IconAlignCenter, IconAlignRight, IconBallpen, IconDatabase, IconMathFunction, IconUsers, IconLogout, IconTrash, IconX, IconPhotoFilled, IconFileUpload, IconUserCircle, IconEdit, IconCircleDashed, IconServer, IconPencil, IconAlertCircle, IconCircleCheck, IconPlayerPlay, IconCircleX, IconFlag, IconFileAnalytics, IconHome, IconSettingsFilled, IconEye, IconWorldUpload, IconBraces, IconClockHour2, IconAugmentedReality, IconGitMerge, IconGripHorizontal, IconChevronLeft, IconChevronRight, IconPolaroid, IconCircleMinus, IconTable, IconCamera, IconShare, IconCirclePlus, IconLogin, IconWorld, IconLock, IconBinaryTree, IconVariable, IconArrowRightCircle, IconIndentIncrease, IconCodeDots, IconUpload, IconCodePlus, IconLink, IconSparkles, IconClipboardCheck, IconClipboardCopy, IconExternalLink, IconDownload, IconTemplate, IconCode, IconPalette, IconSettings, IconMinimize, IconMaximize, IconRss, IconGlobe, IconLinkOff } from '@tabler/icons-react';
27
+ import { IconDice, IconBoxMultiple, IconEyeOff, IconChevronDown, IconInfoCircle, IconRefresh, IconSearch, IconPlus, IconHeading, IconApi, IconPercentage, IconChartBar, IconAlignLeft, IconSelector, IconPhoto, IconAlignCenter, IconAlignRight, IconBallpen, IconDatabase, IconMathFunction, IconUsers, IconLogout, IconTrash, IconX, IconPhotoFilled, IconFileUpload, IconUserCircle, IconEdit, IconCircleDashed, IconServer, IconPencil, IconAlertCircle, IconCircleCheck, IconPlayerPlay, IconCircleX, IconFlag, IconFileAnalytics, IconHome, IconSettingsFilled, IconEye, IconWorldUpload, IconBraces, IconClockHour2, IconAugmentedReality, IconGitMerge, IconGripHorizontal, IconChevronLeft, IconChevronRight, IconPolaroid, IconCircleMinus, IconTable, IconCamera, IconShare, IconCirclePlus, IconLogin, IconWorld, IconLock, IconBinaryTree, IconVariable, IconArrowRightCircle, IconIndentIncrease, IconCodeDots, IconUpload, IconCodePlus, IconLink, IconSparkles, IconClipboardCheck, IconClipboardCopy, IconExternalLink, IconTemplate, IconCode, IconDownload, IconPalette, IconFileTypeCsv, IconFileTypeJs, IconFileTypeXls, IconSettings, IconMinimize, IconMaximize, IconRss, IconGlobe, IconLinkOff } from '@tabler/icons-react';
28
28
  import dynamic from 'next/dynamic';
29
29
  import Link from 'next/link';
30
30
  import parse2, { Element, domToReact, Text as Text$1 } from 'html-react-parser';
@@ -908,7 +908,8 @@ var init_valueInOptions = __esm({
908
908
  if (type === SELECTOR_TYPES.SINGLE) {
909
909
  return options.find((obj) => obj.id === value);
910
910
  }
911
- return Array.isArray(value) && value.every((d) => options.map((o) => o.id).includes(d));
911
+ const multiValue = Array.isArray(value) ? value : value.split(",");
912
+ return Array.isArray(multiValue) && multiValue.every((d) => options.map((o) => o.id).includes(d));
912
913
  };
913
914
  }
914
915
  });
@@ -7272,9 +7273,18 @@ init_varSwapRecursive();
7272
7273
  init_runConsumers();
7273
7274
  init_consts();
7274
7275
  var formatOptions = {
7275
- csv: "CSV",
7276
- json: "JSON",
7277
- xlsx: "XLSX"
7276
+ csv: {
7277
+ extension: "CSV",
7278
+ icon: IconFileTypeCsv
7279
+ },
7280
+ json: {
7281
+ extension: "JSON",
7282
+ icon: IconFileTypeJs
7283
+ },
7284
+ xlsx: {
7285
+ extension: "XLSX",
7286
+ icon: IconFileTypeXls
7287
+ }
7278
7288
  };
7279
7289
  var DEFAULT_TRANSLATIONS2 = {
7280
7290
  "data_source": "Data Source",
@@ -7293,7 +7303,7 @@ var DEFAULT_TRANSLATIONS2 = {
7293
7303
  "rows_preview": "(First {nrows} rows as preview)",
7294
7304
  "choose_format": "Choose format",
7295
7305
  "processing_file": "Processing file...",
7296
- "download": "Download full selected dataset in {fmt} format",
7306
+ "download": "Download data as",
7297
7307
  "preview": "Preview",
7298
7308
  "copy": "Click to copy",
7299
7309
  "copied": "Copied!"
@@ -7330,9 +7340,9 @@ function DataTab(props) {
7330
7340
  const [selectedSource, setSelectedSource] = useState();
7331
7341
  const [selectedDataset, setSelectedDataset] = useState();
7332
7342
  const [fileProcessing, setFileProcessing] = useState(false);
7333
- const [fileFormat, setFileFormat] = useState(formatOptions.csv);
7334
7343
  const [previewsSource, setPreviewsSource] = useState({});
7335
- const [loadingPreview, setLoadingPreview] = useState(false);
7344
+ const [loadingPreview, setLoadingPreview] = useState(true);
7345
+ const [loadingSources, setLoadingSources] = useState(true);
7336
7346
  const { sectionVariables, setSectionVariables, resetSectionVariables } = useSectionVariables(section.id);
7337
7347
  const blockIds = section.blocks || [];
7338
7348
  const state = useAppSelector((state2) => state2);
@@ -7461,6 +7471,7 @@ function DataTab(props) {
7461
7471
  }
7462
7472
  }
7463
7473
  }
7474
+ setLoadingSources(false);
7464
7475
  }
7465
7476
  }, [blocksData]);
7466
7477
  useEffect(() => {
@@ -7502,28 +7513,28 @@ function DataTab(props) {
7502
7513
  }
7503
7514
  }
7504
7515
  }, [selectedDataset, selectedSource]);
7505
- const getFileName = (nameformat, fileFormat2) => {
7506
- const finalNameFormat = nameformat === fileFormat2 ? "" : `-${nameformat}`.toLowerCase();
7516
+ const getFileName = (nameformat, fileFormat) => {
7517
+ const finalNameFormat = nameformat === fileFormat ? "" : `-${nameformat}`.toLowerCase();
7507
7518
  if (selectedSource) {
7508
7519
  const fileIndex = selectedSource.data.length > 1 && selectedDataset ? `-${parseInt(selectedDataset, 10) + 1}` : "";
7509
- return `${slugify_default(selectedSource.fileName)}${finalNameFormat}${fileIndex}.${fileFormat2.toLowerCase()}`;
7520
+ return `${slugify_default(selectedSource.fileName)}${finalNameFormat}${fileIndex}.${fileFormat.toLowerCase()}`;
7510
7521
  }
7511
- return `${finalNameFormat}.${fileFormat2}`;
7522
+ return `${finalNameFormat}.${fileFormat}`;
7512
7523
  };
7513
- const onSaveClick = async () => {
7524
+ const onSaveClick = async (fileFormat) => {
7514
7525
  if (selectedSource) {
7515
7526
  setFileProcessing(true);
7516
7527
  const zipFile = new JSZip();
7517
7528
  const filename = getFileName(fileFormat, fileFormat);
7518
7529
  try {
7519
7530
  switch (fileFormat) {
7520
- case formatOptions.json:
7531
+ case formatOptions.json.extension:
7521
7532
  zipFile.file(filename, JSON.stringify(currentPreview));
7522
7533
  break;
7523
- case formatOptions.csv:
7534
+ case formatOptions.csv.extension:
7524
7535
  zipFile.file(filename, csvFormat(currentPreview));
7525
7536
  break;
7526
- case formatOptions.xlsx:
7537
+ case formatOptions.xlsx.extension:
7527
7538
  const { utils, write } = await import('xlsx');
7528
7539
  const wb = utils.book_new();
7529
7540
  utils.book_append_sheet(
@@ -7570,8 +7581,9 @@ function DataTab(props) {
7570
7581
  )), [sourcesOptions, selectedSource, sourcesToLoad]);
7571
7582
  return /* @__PURE__ */ jsxs(Stack, { className: "cms-section-options-data", children: [
7572
7583
  /* @__PURE__ */ jsx(Space, { h: "xs" }),
7573
- sourcesOptions.length === 0 && /* @__PURE__ */ jsx("p", { children: "No data sources defined." }),
7574
- sourcesOptions.length > 1 && /* @__PURE__ */ jsx(Input.Wrapper, { label: `${translations["choose_data_src"]}:`, children: /* @__PURE__ */ jsx(Group, { spacing: "xs", children: sourcesButtons }) }),
7584
+ /* @__PURE__ */ jsx(LoadingOverlay, { visible: loadingSources, overlayBlur: 2 }),
7585
+ sourcesOptions.length === 0 && !loadingSources && /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: "1rem" }), title: "Oops!", children: translations["no_data_src"] }),
7586
+ sourcesOptions.length > 1 && sourcesOptions.length === sourcesToLoad.length && !loadingSources && /* @__PURE__ */ jsx(Input.Wrapper, { label: `${translations["choose_data_src"]}:`, children: /* @__PURE__ */ jsx(Group, { spacing: "xs", children: sourcesButtons }) }),
7575
7587
  selectedSource && selectedDataset && /* @__PURE__ */ jsx(Stack, { spacing: "xs", children: /* @__PURE__ */ jsx(
7576
7588
  Input.Wrapper,
7577
7589
  {
@@ -7596,7 +7608,7 @@ function DataTab(props) {
7596
7608
  /* @__PURE__ */ jsx(
7597
7609
  CopyButton,
7598
7610
  {
7599
- value: selectedSource.data[selectedDataset] === "string" ? selectedSource.data[selectedDataset] : "",
7611
+ value: typeof selectedSource.data[selectedDataset] === "string" ? selectedSource.data[selectedDataset] : "",
7600
7612
  timeout: 2e3,
7601
7613
  children: ({ copied, copy }) => /* @__PURE__ */ jsx(Tooltip, { label: copied ? translations["copied"] : translations["copy"], withArrow: true, position: "top", children: /* @__PURE__ */ jsx(
7602
7614
  ActionIcon,
@@ -7621,32 +7633,21 @@ function DataTab(props) {
7621
7633
  children: translations["open_in_window"].replace("{src}", selectedSource.title)
7622
7634
  }
7623
7635
  ) }),
7624
- /* @__PURE__ */ jsxs(Stack, { pos: "relative", mih: "450px", children: [
7625
- /* @__PURE__ */ jsx(LoadingOverlay, { visible: loadingPreview }),
7636
+ /* @__PURE__ */ jsxs(Stack, { pos: "relative", mih: "430px", children: [
7637
+ /* @__PURE__ */ jsx(LoadingOverlay, { visible: loadingPreview && sourcesOptions.length > 0, overlayBlur: 2 }),
7626
7638
  selectedSource && !loadingPreview && currentPreview.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
7627
- /* @__PURE__ */ jsx(Box, { h: "300px", children: /* @__PURE__ */ jsx(SortableTable, { data: currentPreview.slice(0, PREVIEW_SIZE) }) }),
7628
- /* @__PURE__ */ jsx(Space, { h: "xs" }),
7629
- /* @__PURE__ */ jsx(Input.Wrapper, { label: `${translations["choose_format"]}: ${getFileName(fileFormat, fileFormat)}`, children: /* @__PURE__ */ jsx(Button.Group, { children: Object.keys(formatOptions).map((format2) => /* @__PURE__ */ jsx(
7630
- Button,
7631
- {
7632
- leftIcon: /* @__PURE__ */ jsx(IconTable, { size: 16 }),
7633
- onClick: () => setFileFormat(formatOptions[format2]),
7634
- variant: fileFormat === formatOptions[format2] ? "filled" : "default",
7635
- fullWidth: true,
7636
- children: formatOptions[format2]
7637
- },
7638
- `format-${format2}`
7639
- )) }) }),
7640
- /* @__PURE__ */ jsx(
7639
+ /* @__PURE__ */ jsx(Box, { h: "350px", children: /* @__PURE__ */ jsx(SortableTable, { data: currentPreview.slice(0, PREVIEW_SIZE) }) }),
7640
+ /* @__PURE__ */ jsx(Input.Wrapper, { label: `${translations["download"]}:`, children: /* @__PURE__ */ jsx(Button.Group, { children: Object.values(formatOptions).map((format2) => /* @__PURE__ */ jsx(
7641
7641
  Button,
7642
7642
  {
7643
- leftIcon: /* @__PURE__ */ jsx(IconDownload, { size: 16 }),
7643
+ leftIcon: /* @__PURE__ */ jsx(format2.icon, { size: 24 }),
7644
+ onClick: () => onSaveClick(format2.extension),
7644
7645
  loading: fileProcessing,
7645
- onClick: onSaveClick,
7646
7646
  fullWidth: true,
7647
- children: /* @__PURE__ */ jsx("span", { children: fileProcessing ? translations["processing_file"] : translations["download"].replace("{fmt}", fileFormat) })
7648
- }
7649
- )
7647
+ children: format2.extension
7648
+ },
7649
+ `format-${format2.extension}`
7650
+ )) }) })
7650
7651
  ] })
7651
7652
  ] })
7652
7653
  ] });
@@ -7677,7 +7678,7 @@ var DEFAULT_TRANSLATIONS3 = {
7677
7678
  function ImageTab(props) {
7678
7679
  const { section } = props;
7679
7680
  const blocksIds = section.blocks || [];
7680
- const vizBlocks = useAppSelector((state) => blocksIds.map((blockId) => state.records.entities.block[blockId]).filter((block) => block.type === "visualization"));
7681
+ const vizBlocks = useAppSelector((state) => blocksIds.map((blockId) => state.records.entities.block[blockId]).filter((block) => block.type === "visualization" && state.variables.status[block.id].allowed));
7681
7682
  const [imageContext, setImageContext] = useState(contextOptions.section);
7682
7683
  const [imageFormat, setImageFormat] = useState(formatOptions2.png);
7683
7684
  const [imageProcessing, setImageProcessing] = useState(false);
@@ -7805,31 +7806,35 @@ function ImageTab(props) {
7805
7806
  }, [vizSelected]);
7806
7807
  return /* @__PURE__ */ jsxs(Stack, { className: "cms-section-options-image", children: [
7807
7808
  /* @__PURE__ */ jsx(Space, { h: "xs" }),
7808
- /* @__PURE__ */ jsx(Input.Wrapper, { label: `${translations["choose_area"]}:`, children: /* @__PURE__ */ jsxs(Button.Group, { children: [
7809
- /* @__PURE__ */ jsx(
7810
- Button,
7811
- {
7812
- leftIcon: /* @__PURE__ */ jsx(IconTemplate, { size: 16 }),
7813
- onClick: () => {
7814
- setImageContext(contextOptions.section);
7815
- setImageFormat(formatOptions2.png);
7809
+ /* @__PURE__ */ jsx(Input.Wrapper, { label: `${translations["choose_area"]}:`, children: /* @__PURE__ */ jsx(
7810
+ SegmentedControl,
7811
+ {
7812
+ fullWidth: true,
7813
+ value: imageContext,
7814
+ data: [
7815
+ {
7816
+ value: contextOptions.section,
7817
+ label: /* @__PURE__ */ jsxs(Center, { children: [
7818
+ /* @__PURE__ */ jsx(IconTemplate, { size: "1rem" }),
7819
+ /* @__PURE__ */ jsx(Box, { ml: 10, children: translations["entire_section"] })
7820
+ ] })
7816
7821
  },
7817
- variant: imageContext === contextOptions.section ? "filled" : "default",
7818
- fullWidth: true,
7819
- children: translations["entire_section"]
7820
- }
7821
- ),
7822
- vizAvailable.length > 0 && /* @__PURE__ */ jsx(
7823
- Button,
7824
- {
7825
- leftIcon: /* @__PURE__ */ jsx(IconChartBar, { size: 16 }),
7826
- onClick: () => setImageContext(contextOptions.viz),
7827
- variant: imageContext === contextOptions.viz ? "filled" : "default",
7828
- fullWidth: true,
7829
- children: translations["viz_only"]
7822
+ {
7823
+ value: contextOptions.viz,
7824
+ label: /* @__PURE__ */ jsxs(Center, { children: [
7825
+ /* @__PURE__ */ jsx(IconChartBar, { size: "1rem" }),
7826
+ /* @__PURE__ */ jsx(Box, { ml: 10, children: translations["viz_only"] })
7827
+ ] })
7828
+ }
7829
+ ],
7830
+ onChange: (newValue) => {
7831
+ setImageContext(newValue);
7832
+ if (newValue === contextOptions.section) {
7833
+ setImageFormat(formatOptions2.png);
7834
+ }
7830
7835
  }
7831
- )
7832
- ] }) }),
7836
+ }
7837
+ ) }),
7833
7838
  imageContext === contextOptions.viz && vizAvailable.length > 0 && /* @__PURE__ */ jsxs(
7834
7839
  Input.Wrapper,
7835
7840
  {
package/dist/server.js CHANGED
@@ -4222,7 +4222,8 @@ var valueInOptions_default = (type, value, options) => {
4222
4222
  if (type === SELECTOR_TYPES.SINGLE) {
4223
4223
  return options.find((obj) => obj.id === value);
4224
4224
  }
4225
- return Array.isArray(value) && value.every((d) => options.map((o) => o.id).includes(d));
4225
+ const multiValue = Array.isArray(value) ? value : value.split(",");
4226
+ return Array.isArray(multiValue) && multiValue.every((d) => options.map((o) => o.id).includes(d));
4226
4227
  };
4227
4228
 
4228
4229
  // libs/selectors/runSelector.js
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datawheel/bespoke",
3
- "version": "0.3.14",
3
+ "version": "0.3.16",
4
4
  "description": "Content management system for creating automated data reports",
5
5
  "exports": {
6
6
  ".": {