@datawheel/bespoke 0.2.1 → 0.2.3

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
@@ -16,7 +16,7 @@ import { Notifications, notifications } from '@mantine/notifications';
16
16
  import React, { forwardRef, useMemo, useState, useCallback, useContext, useEffect, createContext, memo, useRef, Fragment as Fragment$1, createElement } from 'react';
17
17
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
18
18
  import { useDispatch, useSelector } from 'react-redux';
19
- import { Stack, Text, Badge, Group, useMantineTheme, Flex, packSx, Tooltip, ActionIcon, Modal, Button, SegmentedControl, Select, MultiSelect, Center, Grid, Card, Image, Title, Radio, NumberInput, TextInput, Switch, Box, List, Menu, Anchor, MantineProvider, Divider, Burger, Navbar, ScrollArea, Avatar, AppShell, UnstyledButton, ThemeIcon, LoadingOverlay, Skeleton, Container, Loader, Alert, Collapse, Space, Code, Textarea, rem, Paper, Input, Popover, Checkbox, Drawer, Overlay, SimpleGrid, Autocomplete, Tabs, Header, px, FileInput, Accordion, HoverCard, CopyButton, Col } from '@mantine/core';
19
+ import { Stack, Text, Badge, Group, useMantineTheme, Flex, packSx, Tooltip, ActionIcon, Modal, Button, SegmentedControl, Select, MultiSelect, Center, Grid, Title, Radio, NumberInput, TextInput, Switch, Box, List, Menu, Anchor, MantineProvider, Divider, Burger, Navbar, ScrollArea, Avatar, AppShell, UnstyledButton, ThemeIcon, LoadingOverlay, Skeleton, Image, Card, Container, Loader, Alert, Collapse, Space, Code, Textarea, rem, Paper, Input, Popover, Checkbox, Drawer, Overlay, SimpleGrid, Autocomplete, Tabs, Header, px, FileInput, Accordion, HoverCard, CopyButton, Col } from '@mantine/core';
20
20
  import { dataConcat } from 'd3plus-viz';
21
21
  import * as d3plus from 'd3plus-react';
22
22
  import Router, { useRouter } from 'next/router';
@@ -333,7 +333,8 @@ var init_cms = __esm({
333
333
  });
334
334
  ALLOWED = {
335
335
  ALLOWED: "allowed",
336
- ALLOWED_LOGIC: "allowedLogic"
336
+ ALLOWED_LOGIC: "allowedLogic",
337
+ IGNORE_CASCADE: "ignoreCascade"
337
338
  };
338
339
  ACCESS = {
339
340
  ACCESS: "access",
@@ -1123,7 +1124,7 @@ async function runSingleBlock(block, formatterFunctions, blockContext, readMembe
1123
1124
  return {
1124
1125
  outputVariables: {},
1125
1126
  renderVariables: {},
1126
- status: { allowed: false }
1127
+ status: { allowed: false, hiddenByCascade: block.id }
1127
1128
  };
1128
1129
  }
1129
1130
  if (unswappedAPI) {
@@ -1427,13 +1428,20 @@ var init_runConsumers = __esm({
1427
1428
  const runningTask = dependenciesDone.then(async () => {
1428
1429
  const variables = block.inputs.reduce((acc, d) => ({ ...acc, ...variablesById[d] }), attributes);
1429
1430
  const inputNotAllowed = block.inputs.find(
1430
- (iid) => !statusById[iid].allowed || statusById[iid].hiddenByCascade
1431
+ (iid) => {
1432
+ const ignoreInputs = block.settings?.ignoreCascade ? block.settings?.ignoreCascade : [];
1433
+ if (ignoreInputs.includes(iid)) {
1434
+ return false;
1435
+ }
1436
+ return !statusById[iid].allowed || statusById[iid].hiddenByCascade;
1437
+ }
1431
1438
  );
1432
1439
  if (inputNotAllowed) {
1433
1440
  statusById[bid2] = {
1434
1441
  allowed: false,
1435
1442
  hiddenByCascade: statusById[inputNotAllowed].hiddenByCascade || inputNotAllowed
1436
1443
  };
1444
+ variablesById[bid2] = {};
1437
1445
  return;
1438
1446
  }
1439
1447
  const startBlock = /* @__PURE__ */ new Date();
@@ -1442,7 +1450,8 @@ var init_runConsumers = __esm({
1442
1450
  formatterFunctions,
1443
1451
  {
1444
1452
  ...parsedBlockContext,
1445
- variables
1453
+ variables,
1454
+ locale: variables.locale
1446
1455
  },
1447
1456
  readMemberFn
1448
1457
  ).then(({ outputVariables, status }) => {
@@ -1454,13 +1463,17 @@ var init_runConsumers = __esm({
1454
1463
  allowed: false,
1455
1464
  error: status.error
1456
1465
  };
1466
+ variablesById[bid2] = {};
1457
1467
  }
1458
1468
  }
1459
1469
  if (
1460
1470
  // store output variables for block that:
1461
1471
  (block.consumers.length > 0 || [BLOCK_TYPES.GENERATOR, BLOCK_TYPES.RELATED].includes(block.type)) && status.allowed && Object.keys(outputVariables).length > 0
1462
- )
1472
+ ) {
1463
1473
  variablesById[bid2] = outputVariables;
1474
+ } else {
1475
+ variablesById[bid2] = {};
1476
+ }
1464
1477
  if (mode === "report") {
1465
1478
  statusById[bid2] = { allowed: status.allowed };
1466
1479
  if (block.type === BLOCK_TYPES.GENERATOR && status.api) {
@@ -3566,57 +3579,98 @@ init_esm_shims();
3566
3579
  // frontend/components/explore/ExploreTile.tsx
3567
3580
  init_esm_shims();
3568
3581
  init_store2();
3569
- function ExploreTile({ profile, profilePrefix, onSelect }) {
3570
- const currentLocale = useAppSelector((state) => state.status.currentLocale);
3571
- const localeDefault9 = useAppSelector((state) => state.status.localeDefault);
3572
- const localePrefix = currentLocale === localeDefault9 ? "" : `/${currentLocale}`;
3573
- const url = `${localePrefix}${profilePrefix}${profile.path}`;
3574
- const router = useRouter();
3575
- const images = profile.members.map((m) => /* @__PURE__ */ jsx(
3582
+
3583
+ // frontend/hooks/useBespokeStyles.ts
3584
+ init_esm_shims();
3585
+ function useBespokeStyles() {
3586
+ const theme = useMantineTheme();
3587
+ return theme.other.bespokeStyles ?? {};
3588
+ }
3589
+ function ReportTile({ reportName, members, href, onClick }) {
3590
+ const images = members.map((m) => /* @__PURE__ */ jsx(
3576
3591
  Image,
3577
3592
  {
3578
- src: `/api/cms/member/image.png?member=${m.id}&size=thumb`,
3593
+ src: m.image.src,
3579
3594
  height: 160,
3580
3595
  imageProps: { loading: "lazy" },
3581
3596
  alt: m.name
3582
3597
  },
3583
3598
  m.id
3584
3599
  ));
3585
- const names = profile.members.map((m) => /* @__PURE__ */ jsxs(Stack, { children: [
3600
+ const names = members.map((m) => /* @__PURE__ */ jsxs(Stack, { children: [
3586
3601
  /* @__PURE__ */ jsx(Text, { weight: 500, children: m.name }),
3587
- /* @__PURE__ */ jsx(Badge, { color: "green", variant: "light", children: m.metadata.variant.name })
3602
+ /* @__PURE__ */ jsx(Badge, { color: "green", variant: "light", children: m.variant })
3588
3603
  ] }, m.id));
3604
+ return /* @__PURE__ */ jsxs(Card, { shadow: "sm", p: "lg", radius: "md", withBorder: true, children: [
3605
+ /* @__PURE__ */ jsx(Card.Section, { children: /* @__PURE__ */ jsx(Group, { grow: true, spacing: 0, children: images }) }),
3606
+ /* @__PURE__ */ jsx(Group, { position: "apart", mt: "md", mb: "xs", children: names }),
3607
+ /* @__PURE__ */ jsx("a", { href, onClick, children: /* @__PURE__ */ jsx(Button, { variant: "light", color: "blue", fullWidth: true, mt: "md", radius: "md", children: `See ${reportName} Report` }) })
3608
+ ] });
3609
+ }
3610
+ var useCustomTile = (reportTile) => {
3611
+ const { components } = useBespokeStyles();
3612
+ let Tile = ReportTile;
3613
+ if (components?.ReportTile) {
3614
+ Tile = components?.ReportTile;
3615
+ }
3616
+ if (reportTile) {
3617
+ Tile = reportTile;
3618
+ }
3619
+ return Tile;
3620
+ };
3621
+ function ExploreTile({ profile, profilePrefix, onSelect, reportTile }) {
3622
+ const currentLocale = useAppSelector((state) => state.status.currentLocale);
3623
+ const localeDefault9 = useAppSelector((state) => state.status.localeDefault);
3624
+ const localePrefix = currentLocale === localeDefault9 ? "" : `/${currentLocale}`;
3625
+ const url = `${localePrefix}${profilePrefix}${profile.path}`;
3626
+ const router = useRouter();
3627
+ const members = profile.members.map((m) => ({
3628
+ name: m.name,
3629
+ id: m.id,
3630
+ variant: m.metadata.variant.name,
3631
+ image: {
3632
+ src: `/api/cms/member/image.png?member=${m.id}&size=thumb`,
3633
+ alt: m.name
3634
+ }
3635
+ }));
3589
3636
  const onItemSubmit = (innerUrl) => {
3590
3637
  router.push(`${innerUrl}`);
3591
3638
  if (onSelect)
3592
3639
  onSelect();
3593
3640
  };
3594
- return /* @__PURE__ */ jsx(Grid.Col, { xs: 12, sm: 6, md: 4, lg: 4, xl: 3, children: /* @__PURE__ */ jsxs(Card, { shadow: "sm", p: "lg", radius: "md", withBorder: true, children: [
3595
- /* @__PURE__ */ jsx(Card.Section, { children: /* @__PURE__ */ jsx(Group, { grow: true, spacing: 0, children: images }) }),
3596
- /* @__PURE__ */ jsx(Group, { position: "apart", mt: "md", mb: "xs", children: names }),
3597
- /* @__PURE__ */ jsx(
3598
- "a",
3599
- {
3600
- href: url,
3601
- onClick: (evt) => {
3602
- evt.preventDefault();
3603
- onItemSubmit(url);
3604
- },
3605
- children: /* @__PURE__ */ jsx(Button, { variant: "light", color: "blue", fullWidth: true, mt: "md", radius: "md", children: `See ${profile.report.name} Report` })
3606
- }
3607
- )
3608
- ] }) }, profile.id);
3641
+ const handleClick = (evt) => {
3642
+ evt.preventDefault();
3643
+ onItemSubmit(url);
3644
+ };
3645
+ const Tile = useCustomTile(reportTile);
3646
+ return /* @__PURE__ */ jsx(Grid.Col, { xs: 12, sm: 6, md: 4, lg: 4, xl: 3, children: /* @__PURE__ */ jsx(
3647
+ Tile,
3648
+ {
3649
+ reportName: profile.report.name,
3650
+ members,
3651
+ href: url,
3652
+ onClick: handleClick
3653
+ }
3654
+ ) }, profile.id);
3609
3655
  }
3610
3656
  var ExploreTile_default = ExploreTile;
3611
- function ExploreResults({ results = [], profilePrefix, onSelect = () => {
3612
- } }) {
3657
+ function ExploreResults({ results = [], profilePrefix, onSelect = () => void 0, reportTile }) {
3613
3658
  const [scrollSize, setScrollSize] = useState(500);
3614
3659
  useEffect(() => {
3615
3660
  const { innerHeight } = window;
3616
3661
  setScrollSize(innerHeight - 200);
3617
3662
  }, []);
3618
3663
  return /* @__PURE__ */ jsx(ScrollArea, { offsetScrollbars: true, type: "always", style: { height: scrollSize }, children: /* @__PURE__ */ jsx(Grid, { align: "stretch", children: results.map(
3619
- (item) => /* @__PURE__ */ jsx(ExploreTile_default, { profile: item, profilePrefix, onSelect }, item.id)
3664
+ (item) => /* @__PURE__ */ jsx(
3665
+ ExploreTile_default,
3666
+ {
3667
+ profile: item,
3668
+ profilePrefix,
3669
+ reportTile,
3670
+ onSelect
3671
+ },
3672
+ item.id
3673
+ )
3620
3674
  ) }) });
3621
3675
  }
3622
3676
  var ExploreResults_default = ExploreResults;
@@ -3628,7 +3682,8 @@ function BespokeExplore({
3628
3682
  profilePrefix,
3629
3683
  initialReportId,
3630
3684
  initialVariantId,
3631
- onSelect
3685
+ onSelect,
3686
+ reportTile
3632
3687
  }) {
3633
3688
  const dispatch = useAppDispatch();
3634
3689
  const defaultFilters = {
@@ -3726,7 +3781,7 @@ function BespokeExplore({
3726
3781
  ),
3727
3782
  /* @__PURE__ */ jsx(LoadingOverlay, { visible: loading }),
3728
3783
  !loading && results.length === 0 && /* @__PURE__ */ jsx(Alert, { title: "No results", color: "blue", children: "Try another search or filter." }),
3729
- !loading && /* @__PURE__ */ jsx(ExploreResults_default, { results, profilePrefix, onSelect })
3784
+ !loading && /* @__PURE__ */ jsx(ExploreResults_default, { results, profilePrefix, onSelect, reportTile })
3730
3785
  ] });
3731
3786
  }
3732
3787
  var Explore_default = BespokeExplore;
@@ -3787,16 +3842,29 @@ var SearchItem = forwardRef(
3787
3842
  }, ref) => {
3788
3843
  const names = members.map((m) => /* @__PURE__ */ jsxs(Stack, { align: "center", children: [
3789
3844
  /* @__PURE__ */ jsx(Text, { weight: 500, children: m.name }),
3790
- /* @__PURE__ */ jsx(Badge, { color: "green", variant: "light", children: m.metadata.variant.name })
3845
+ /* @__PURE__ */ jsx(Badge, { color: "green", variant: "light", children: m.variant })
3791
3846
  ] }, m.id));
3792
3847
  return /* @__PURE__ */ jsx("div", { ref, children: /* @__PURE__ */ jsx(Group, { position: "apart", grow: true, ...others, children: names }) }, uniqueKey);
3793
3848
  }
3794
3849
  );
3795
3850
  var SearchItem_default = SearchItem;
3851
+ var useCustomItem = (reportItem) => {
3852
+ const { components } = useBespokeStyles();
3853
+ let Tile = SearchItem_default;
3854
+ if (components?.ReportItem) {
3855
+ Tile = components?.ReportItem;
3856
+ }
3857
+ if (reportItem) {
3858
+ Tile = reportItem;
3859
+ }
3860
+ return Tile;
3861
+ };
3796
3862
  function BespokeSearch({ locale, profilePrefix, autocompleteProps = {}, children }) {
3797
3863
  const dispatch = useAppDispatch();
3798
3864
  const currentLocale = useAppSelector((state) => state.status.currentLocale);
3799
3865
  const localeDefault9 = useAppSelector((state) => state.status.localeDefault);
3866
+ const localePrefix = currentLocale === localeDefault9 ? "" : `/${currentLocale}`;
3867
+ const ItemRenderer = useCustomItem(autocompleteProps ? autocompleteProps.itemComponent : null);
3800
3868
  const router = useRouter();
3801
3869
  const [query, setQuery] = useState("");
3802
3870
  const [debouncedQuery, cancel] = useDebouncedValue(query, 500);
@@ -3824,8 +3892,22 @@ function BespokeSearch({ locale, profilePrefix, autocompleteProps = {}, children
3824
3892
  dispatch(actions_exports.reportSearch(params)).then((value) => {
3825
3893
  if (value && value.results) {
3826
3894
  setResults(value.results.map((r) => {
3827
- r.value = `VALUE: ${r.id}`;
3828
- return r;
3895
+ return {
3896
+ id: r.id,
3897
+ reportName: r.report.name,
3898
+ href: `${localePrefix}${profilePrefix}${r.path}`,
3899
+ value: `VALUE: ${r.id}`,
3900
+ // Required for Autocomplete to generate keys.
3901
+ members: r.members.map((m) => ({
3902
+ name: m.name,
3903
+ id: m.id,
3904
+ variant: m.metadata.variant.name,
3905
+ image: {
3906
+ src: `/api/cms/member/image.png?member=${m.id}&size=thumb`,
3907
+ alt: m.name
3908
+ }
3909
+ }))
3910
+ };
3829
3911
  }));
3830
3912
  }
3831
3913
  setLoading(false);
@@ -3862,9 +3944,7 @@ function BespokeSearch({ locale, profilePrefix, autocompleteProps = {}, children
3862
3944
  const onItemSubmit = (item) => {
3863
3945
  setRedirecting(true);
3864
3946
  setVisible(false);
3865
- const localePrefix = currentLocale === localeDefault9 ? "" : `/${currentLocale}`;
3866
- const url = `${localePrefix}${profilePrefix}${item.path}`;
3867
- router.push(url);
3947
+ router.push(item.href);
3868
3948
  };
3869
3949
  const onChange = (searchTerm) => {
3870
3950
  if (!searchTerm.includes("VALUE:")) {
@@ -3882,7 +3962,7 @@ function BespokeSearch({ locale, profilePrefix, autocompleteProps = {}, children
3882
3962
  Autocomplete,
3883
3963
  {
3884
3964
  value: query,
3885
- itemComponent: SearchItem_default,
3965
+ itemComponent: ItemRenderer,
3886
3966
  onItemSubmit,
3887
3967
  onChange,
3888
3968
  filter: () => true,
@@ -4274,7 +4354,7 @@ function useInitialState(pathSegmentsKey) {
4274
4354
  const hasParams = Object.keys(query).some((key) => key !== pathSegmentsKey);
4275
4355
  if ((hasParams || privateBlocks.blocks.length > 0) && privateBlocks.resolved) {
4276
4356
  const selectorIds = Object.keys(query).map((d) => Number(d.match(/\d+/)));
4277
- const revalidateBlocks = selectorIds.concat(privateBlocks.blocks);
4357
+ const revalidateBlocks = selectorIds.filter((id) => id !== 0).concat(privateBlocks.blocks);
4278
4358
  Promise.all(
4279
4359
  revalidateBlocks.map((bid) => {
4280
4360
  const block = blockRecords[bid];
@@ -4518,41 +4598,30 @@ function RelatedView(props) {
4518
4598
  const localeDefault9 = useAppSelector((state) => state.status.localeDefault);
4519
4599
  const profilePrefix = useProfilePrefix();
4520
4600
  const router = useRouter();
4601
+ const { components } = useBespokeStyles();
4521
4602
  if (!related_reports?.length)
4522
4603
  return;
4523
4604
  const localePrefix = currentLocale === localeDefault9 ? "" : `/${currentLocale}`;
4524
4605
  const onItemSubmit = (innerUrl) => {
4525
4606
  router.push(`${innerUrl}`);
4526
4607
  };
4608
+ const Tile = components?.ReportTile ? components?.ReportTile : ReportTile;
4527
4609
  return /* @__PURE__ */ jsx(Grid, { children: related_reports.map((report) => {
4528
4610
  const url = `${localePrefix}${profilePrefix}/${report.variant_slug}/${report.slug}`;
4529
- return /* @__PURE__ */ jsx(Grid.Col, { xs: 12, sm: 6, md: 4, lg: 4, xl: 3, children: /* @__PURE__ */ jsxs(Card, { shadow: "sm", p: "lg", radius: "md", withBorder: true, children: [
4530
- /* @__PURE__ */ jsx(Card.Section, { children: /* @__PURE__ */ jsx(Group, { grow: true, spacing: 0, children: /* @__PURE__ */ jsx(
4531
- Image,
4532
- {
4533
- src: `/api/cms/member/image.png?member=${report.content_id}&size=thumb`,
4534
- height: 160,
4535
- imageProps: { loading: "lazy" },
4536
- alt: report.name
4537
- },
4538
- report.content_id
4539
- ) }) }),
4540
- /* @__PURE__ */ jsx(Group, { position: "apart", mt: "md", mb: "xs", children: /* @__PURE__ */ jsxs(Stack, { children: [
4541
- /* @__PURE__ */ jsx(Text, { weight: 500, children: report.name }),
4542
- /* @__PURE__ */ jsx(Badge, { color: "green", variant: "light", children: report.variant_name })
4543
- ] }, report.content_id) }),
4544
- /* @__PURE__ */ jsx(
4545
- "a",
4546
- {
4547
- href: url,
4548
- onClick: (evt) => {
4549
- evt.preventDefault();
4550
- onItemSubmit(url);
4551
- },
4552
- children: /* @__PURE__ */ jsx(Button, { variant: "light", color: "blue", fullWidth: true, mt: "md", radius: "md", children: `See ${report.name} Report` })
4553
- }
4554
- )
4555
- ] }) }, report.content_id);
4611
+ const members = [{
4612
+ name: report.name,
4613
+ id: report.content_id,
4614
+ variant: report.variant_name,
4615
+ image: {
4616
+ src: `/api/cms/member/image.png?member=${report.content_id}&size=thumb`,
4617
+ alt: report.name
4618
+ }
4619
+ }];
4620
+ const handleClick = (evt) => {
4621
+ evt.preventDefault();
4622
+ onItemSubmit(url);
4623
+ };
4624
+ return /* @__PURE__ */ jsx(Grid.Col, { xs: 12, sm: 6, md: 4, lg: 4, xl: 3, children: /* @__PURE__ */ jsx(Tile, { reportName: report.report_name, members, href: url, onClick: handleClick }) }, report.content_id);
4556
4625
  }) });
4557
4626
  }
4558
4627
 
@@ -6088,7 +6157,6 @@ function DataTab(props) {
6088
6157
  const sourcesOptions = useAppSelector((state) => {
6089
6158
  const dataInformation = [];
6090
6159
  blocksIds.map((blockId) => state.records.entities.block[blockId]).filter((block) => [BLOCK_TYPES.GENERATOR, BLOCK_TYPES.VIZ].includes(block.type)).map((block) => {
6091
- console.log(state.variables.status[block.id]);
6092
6160
  if (block.type === BLOCK_TYPES.GENERATOR) {
6093
6161
  const api = state.variables.variables[block.id]._api || state.variables.status[block.id].api;
6094
6162
  if (api) {
@@ -6758,13 +6826,6 @@ function Options(props) {
6758
6826
  ] });
6759
6827
  }
6760
6828
 
6761
- // frontend/hooks/useBespokeStyles.ts
6762
- init_esm_shims();
6763
- function useBespokeStyles() {
6764
- const theme = useMantineTheme();
6765
- return theme.other.bespokeStyles || {};
6766
- }
6767
-
6768
6829
  // components/sections/SectionMenu.tsx
6769
6830
  init_esm_shims();
6770
6831
 
@@ -9540,13 +9601,13 @@ function BlockPreview(props) {
9540
9601
  width: "100%",
9541
9602
  height: "100%",
9542
9603
  position: "absolute",
9543
- top: -1,
9544
- left: -1,
9545
- opacity: 0.3,
9546
- zIndex: 5,
9604
+ top: 0,
9605
+ left: 0,
9606
+ opacity: 0.9,
9607
+ zIndex: 4,
9547
9608
  pointerEvents: "none"
9548
9609
  };
9549
- const allowedOverlay = /* @__PURE__ */ jsx("div", { style: { ...overlayStyle, backgroundColor: "pink" } });
9610
+ const allowedOverlay = /* @__PURE__ */ jsx("div", { style: { ...overlayStyle, backgroundColor: "pink" }, children: /* @__PURE__ */ jsx(Center, { h: "100%", children: /* @__PURE__ */ jsx(Text, { size: "sm", tt: "capitalize", italic: true, children: blockStatus.hiddenByCascade === block.id ? `${block.type} not allowed` : `${block.type} hidden by block ${blockStatus.hiddenByCascade}` }) }) });
9550
9611
  if (!content)
9551
9612
  return null;
9552
9613
  const { error, log } = status;
@@ -9637,35 +9698,6 @@ var BlockPreview_default = withFetcher(BlockPreview, useBlockRef);
9637
9698
  // components/blocks/BlockSettings.tsx
9638
9699
  init_esm_shims();
9639
9700
  init_cms();
9640
-
9641
- // components/blocks/VizSettings.tsx
9642
- init_esm_shims();
9643
- init_getBlockContent();
9644
- init_store2();
9645
- function VizSettings({ id, onChange }) {
9646
- const block = useBlockRef(id).data;
9647
- const content = getBlockContent(block);
9648
- const logic = content?.logic || "";
9649
- const handleChange = (value) => {
9650
- onChange({ logic: value });
9651
- };
9652
- return /* @__PURE__ */ jsxs("div", { children: [
9653
- /* @__PURE__ */ jsx("span", { children: "Viz Options" }),
9654
- /* @__PURE__ */ jsx(
9655
- MonacoWrapper_default,
9656
- {
9657
- monacoOptions: {
9658
- onChange: handleChange,
9659
- value: logic
9660
- }
9661
- },
9662
- "code-editor"
9663
- )
9664
- ] });
9665
- }
9666
- var VizSettings_default = VizSettings;
9667
-
9668
- // components/blocks/BlockSettings.tsx
9669
9701
  init_store2();
9670
9702
  init_hooks();
9671
9703
  function BlockSettings({ id, setBlockSettings, setBlockContent }) {
@@ -9676,9 +9708,9 @@ function BlockSettings({ id, setBlockSettings, setBlockContent }) {
9676
9708
  const [roles, setRoles] = useState([]);
9677
9709
  const variables = useInputVariablesFlat(id);
9678
9710
  const allowedOptions = useMemo(() => [
9679
- { value: "always", label: "always" },
9680
- { value: "never", label: "never" }
9681
- ].concat(Object.keys(variables).map((d) => ({ value: d, label: `${d}: ${variables[d]}` }))), [variables]);
9711
+ { value: "always", label: "always", group: "Static" },
9712
+ { value: "never", label: "never", group: "Static" }
9713
+ ].concat(Object.keys(variables).map((d) => ({ value: d, label: `${d}: ${variables[d]}`, group: "Based on variable" }))), [variables]);
9682
9714
  const accessOptions = useMemo(() => [
9683
9715
  { value: "public", label: "Public block, (all visitors)", group: "Exclusive" },
9684
9716
  { value: "guest", label: "Guest only block, (non logged visitors)", group: "Exclusive" },
@@ -9741,6 +9773,9 @@ function BlockSettings({ id, setBlockSettings, setBlockContent }) {
9741
9773
  [BLOCK_SETTINGS.ALLOWED_LOGIC]: allowedLogic
9742
9774
  });
9743
9775
  };
9776
+ const handleChangeCascadeDropdown = (value) => {
9777
+ setBlockSettings({ [BLOCK_SETTINGS.IGNORE_CASCADE]: value });
9778
+ };
9744
9779
  const blocks = useAppSelector((state) => state.records.entities.block);
9745
9780
  const consumers = block.consumers.filter((cid) => blocks[cid].section_id !== block.section_id);
9746
9781
  const isShared = Boolean(consumers.length);
@@ -9751,27 +9786,44 @@ function BlockSettings({ id, setBlockSettings, setBlockContent }) {
9751
9786
  i < consumers.length - 1 && consumers.length > 1 ? ", " : ""
9752
9787
  ] })
9753
9788
  );
9789
+ const ignoreOptions = block.inputs.map((blockId) => ({
9790
+ label: `${blocks[blockId]?.type} - ${blocks[blockId]?.id}`,
9791
+ value: blockId
9792
+ }));
9754
9793
  return /* @__PURE__ */ jsxs(Group, { grow: true, align: "flex-start", children: [
9755
9794
  /* @__PURE__ */ jsxs(Stack, { justify: "flex-start", children: [
9756
- /* @__PURE__ */ jsx(Title, { order: 4, children: "Allowed" }),
9795
+ /* @__PURE__ */ jsx(Title, { order: 4, children: "Visibility" }),
9757
9796
  /* @__PURE__ */ jsx(
9758
9797
  Select,
9759
9798
  {
9799
+ label: "Show",
9800
+ description: "Set visibility setting for this block. A hidden block will not run or export variables to its consumers. As a result, all its consumers will be hidden too.",
9760
9801
  defaultValue: block.settings[BLOCK_SETTINGS.ALLOWED] || "always",
9761
9802
  onChange: handleChangeAllowedDropdown,
9762
9803
  data: allowedOptions
9763
9804
  }
9764
9805
  ),
9765
- /* @__PURE__ */ jsx(Title, { order: 4, children: "Access" }),
9806
+ [BLOCK_TYPES.GENERATOR, BLOCK_TYPES.VIZ].includes(block.type) && /* @__PURE__ */ jsx(
9807
+ MultiSelect,
9808
+ {
9809
+ label: "Ignore cascade",
9810
+ description: "Set block as visible even if the selected inputs are hidden.",
9811
+ defaultValue: block.settings[BLOCK_SETTINGS.IGNORE_CASCADE] || [],
9812
+ data: ignoreOptions,
9813
+ onChange: handleChangeCascadeDropdown
9814
+ }
9815
+ ),
9766
9816
  /* @__PURE__ */ jsx(
9767
9817
  MultiSelect,
9768
9818
  {
9819
+ label: "Privacy",
9820
+ description: "This block will be shown based on the selected auth0 roles.",
9769
9821
  data: [...accessOptions, ...rolesOptions],
9770
9822
  value: accessSelected,
9771
9823
  onChange: handleAccessChange
9772
9824
  }
9773
9825
  ),
9774
- /* @__PURE__ */ jsx(Title, { order: 4, children: "Sharing" }),
9826
+ /* @__PURE__ */ jsx(Title, { order: 4, children: "Output" }),
9775
9827
  isShared && block.shared && /* @__PURE__ */ jsxs(Text, { size: "xs", color: "red.4", sx: { display: "flex", alignItems: "flex-start", gap: "0.4rem" }, children: [
9776
9828
  /* @__PURE__ */ jsx(IconAlertCircle, { size: "1.2rem" }),
9777
9829
  /* @__PURE__ */ jsxs(Text, { color: "black", span: true, inherit: true, children: [
@@ -9782,8 +9834,10 @@ function BlockSettings({ id, setBlockSettings, setBlockContent }) {
9782
9834
  ] })
9783
9835
  ] }),
9784
9836
  /* @__PURE__ */ jsx(
9785
- SegmentedControl,
9837
+ Select,
9786
9838
  {
9839
+ label: "Block scope",
9840
+ description: "Select the scope for the variables exported by this block. Section-wide (available only to blocks in the same section) or Report-wide (available to any block inside the report).",
9787
9841
  defaultValue: String(block.shared),
9788
9842
  disabled: isShared && block.shared,
9789
9843
  onChange: (e) => handleChange("shared", e === "true"),
@@ -9791,8 +9845,7 @@ function BlockSettings({ id, setBlockSettings, setBlockContent }) {
9791
9845
  }
9792
9846
  ),
9793
9847
  /* @__PURE__ */ jsx(Title, { order: 4, children: "Danger zone" }),
9794
- /* @__PURE__ */ jsx(Button, { variant: "outline", color: "red", onClick: maybeDelete, children: "Delete Block" }),
9795
- block.type === BLOCK_TYPES.VIZ && /* @__PURE__ */ jsx(VizSettings_default, { id, onChange: setBlockContent })
9848
+ /* @__PURE__ */ jsx(Button, { variant: "outline", color: "red", onClick: maybeDelete, children: "Delete Block" })
9796
9849
  ] }),
9797
9850
  /* @__PURE__ */ jsxs(Stack, { justify: "flex-start", children: [
9798
9851
  /* @__PURE__ */ jsx(Title, { order: 4, children: "Block settings (all locales)" }),
@@ -10129,7 +10182,7 @@ function VariableList({ id, setInlineId }) {
10129
10182
  /* @__PURE__ */ jsx(
10130
10183
  Divider,
10131
10184
  {
10132
- label: block ? titleCase(block.type) : "Dimension Attributes",
10185
+ label: block ? `${titleCase(block.type)} ${block.id} Variables` : "Dimension Variables",
10133
10186
  labelPosition: "center",
10134
10187
  mt: "lg"
10135
10188
  }
@@ -10783,7 +10836,7 @@ function BlockElement({
10783
10836
  top: px(theme.spacing.xs) / 2,
10784
10837
  backgroundColor: theme.colors.gray[2],
10785
10838
  borderRadius: theme.radius.sm,
10786
- zIndex: 2
10839
+ zIndex: 5
10787
10840
  },
10788
10841
  children: [
10789
10842
  isInput || isConsumer ? /* @__PURE__ */ jsx(ActionIcon, { children: isInput ? /* @__PURE__ */ jsx(IconLogout, { size: 20, color: theme.colors.red[5] }) : /* @__PURE__ */ jsx(IconLogin, { size: 20, color: theme.colors.green[5] }) }, "globe") : null,
package/dist/server.js CHANGED
@@ -240,6 +240,12 @@ async function searchUsersByMetadata(key, value) {
240
240
  search_engine: "v3",
241
241
  q: `app_metadata.${key}:"${value}"`
242
242
  });
243
+ for (let index = 0; index < users.length; index++) {
244
+ const u = users[index];
245
+ u.bespoke_app_metadata = u.app_metadata || {};
246
+ delete u.app_metadata;
247
+ u.bespoke_roles = (await managementClient.users.getRoles({ id: u.user_id })).map((r) => r.name);
248
+ }
243
249
  return users;
244
250
  } catch (error) {
245
251
  console.error(error);
@@ -4261,7 +4267,7 @@ async function runSingleBlock(block, formatterFunctions, blockContext, readMembe
4261
4267
  return {
4262
4268
  outputVariables: {},
4263
4269
  renderVariables: {},
4264
- status: { allowed: false }
4270
+ status: { allowed: false, hiddenByCascade: block.id }
4265
4271
  };
4266
4272
  }
4267
4273
  if (unswappedAPI) {
@@ -4532,13 +4538,20 @@ var runConsumersV2 = async (blocks, sections, bid, formatterFunctions, blockCont
4532
4538
  const runningTask = dependenciesDone.then(async () => {
4533
4539
  const variables = block.inputs.reduce((acc, d) => ({ ...acc, ...variablesById[d] }), attributes);
4534
4540
  const inputNotAllowed = block.inputs.find(
4535
- (iid) => !statusById[iid].allowed || statusById[iid].hiddenByCascade
4541
+ (iid) => {
4542
+ const ignoreInputs = block.settings?.ignoreCascade ? block.settings?.ignoreCascade : [];
4543
+ if (ignoreInputs.includes(iid)) {
4544
+ return false;
4545
+ }
4546
+ return !statusById[iid].allowed || statusById[iid].hiddenByCascade;
4547
+ }
4536
4548
  );
4537
4549
  if (inputNotAllowed) {
4538
4550
  statusById[bid2] = {
4539
4551
  allowed: false,
4540
4552
  hiddenByCascade: statusById[inputNotAllowed].hiddenByCascade || inputNotAllowed
4541
4553
  };
4554
+ variablesById[bid2] = {};
4542
4555
  return;
4543
4556
  }
4544
4557
  const startBlock = /* @__PURE__ */ new Date();
@@ -4547,7 +4560,8 @@ var runConsumersV2 = async (blocks, sections, bid, formatterFunctions, blockCont
4547
4560
  formatterFunctions,
4548
4561
  {
4549
4562
  ...parsedBlockContext,
4550
- variables
4563
+ variables,
4564
+ locale: variables.locale
4551
4565
  },
4552
4566
  readMemberFn
4553
4567
  ).then(({ outputVariables, status }) => {
@@ -4559,13 +4573,17 @@ var runConsumersV2 = async (blocks, sections, bid, formatterFunctions, blockCont
4559
4573
  allowed: false,
4560
4574
  error: status.error
4561
4575
  };
4576
+ variablesById[bid2] = {};
4562
4577
  }
4563
4578
  }
4564
4579
  if (
4565
4580
  // store output variables for block that:
4566
4581
  (block.consumers.length > 0 || [BLOCK_TYPES.GENERATOR, BLOCK_TYPES.RELATED].includes(block.type)) && status.allowed && Object.keys(outputVariables).length > 0
4567
- )
4582
+ ) {
4568
4583
  variablesById[bid2] = outputVariables;
4584
+ } else {
4585
+ variablesById[bid2] = {};
4586
+ }
4569
4587
  if (mode === "report") {
4570
4588
  statusById[bid2] = { allowed: status.allowed };
4571
4589
  if (block.type === BLOCK_TYPES.GENERATOR && status.api) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datawheel/bespoke",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Content management system for creating automated data reports",
5
5
  "exports": {
6
6
  ".": {