@datawheel/bespoke 0.1.27 → 0.1.29

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,12 +16,12 @@ import { Notifications, notifications } from '@mantine/notifications';
16
16
  import React, { forwardRef, useMemo, useState, useCallback, useContext, useEffect, createContext, 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, Tooltip, ActionIcon, Center, useMantineTheme, Modal, Button, Flex, SegmentedControl, Select, MultiSelect, Title, Box, List, Menu, Anchor, MantineProvider, Divider, Burger, Navbar, ScrollArea, Avatar, AppShell, UnstyledButton, ThemeIcon, LoadingOverlay, Skeleton, Container, TextInput, Loader, Alert, Collapse, Card, Space, Code, Textarea, rem, Overlay, Grid, Input, Popover, Checkbox, Radio, Switch, Drawer, Autocomplete, Tabs, Header, px, SimpleGrid, Image, Paper, FileInput, Accordion, HoverCard, CopyButton, NumberInput, Col } from '@mantine/core';
19
+ import { Stack, Text, Badge, Group, useMantineTheme, Flex, packSx, Tooltip, ActionIcon, Center, Modal, Button, SegmentedControl, Select, MultiSelect, Title, Box, List, Menu, Anchor, MantineProvider, Divider, Burger, Navbar, ScrollArea, Avatar, AppShell, UnstyledButton, ThemeIcon, LoadingOverlay, Skeleton, Container, TextInput, Loader, Alert, Collapse, Card, Space, Code, Textarea, rem, Paper, Grid, Input, Popover, Checkbox, Radio, Switch, Drawer, Overlay, SimpleGrid, Autocomplete, Tabs, Header, px, Image, FileInput, Accordion, HoverCard, CopyButton, NumberInput, 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';
23
- import { IconInfoCircle, IconSearch, IconAlignLeft, IconAlignCenter, IconAlignRight, IconBoxMargin, IconTable, IconMathFunction, IconUsers, IconLogout, IconTrash, IconUserCircle, IconEdit, IconDatabase, IconServer, IconPencil, IconAlertCircle, IconCircleCheck, IconPlayerPlay, IconAlarmFilled, IconBox, IconLink, IconCirclePlus, IconCircleX, IconFlag, IconFileAnalytics, IconPlus, IconX, IconChevronDown, IconCamera, IconShare, IconCircleDashed, IconListSearch, IconExternalLink, IconSettings, IconFileOff, IconFilesOff, IconHierarchy3, IconMenu, IconRefresh, IconPolaroid, IconCircleMinus, IconEyeOff, IconChevronLeft, IconChevronRight, IconLogin, IconWorld, IconLock, IconVariable, IconArrowRightCircle, IconDownload, IconTemplate, IconChartBar, IconCode, IconUpload, IconCodePlus, IconClipboardCheck, IconClipboardCopy, IconPalette, IconEye, IconMinimize, IconMaximize, IconRss, IconGlobe } from '@tabler/icons-react';
24
- import { useMediaQuery, useDisclosure, useDebouncedValue, useSetState, useHotkeys, useFullscreen, getHotkeyHandler } from '@mantine/hooks';
23
+ import { IconInfoCircle, IconSearch, IconAlignLeft, IconAlignCenter, IconAlignRight, IconBoxMargin, IconTable, IconMathFunction, IconUsers, IconLogout, IconTrash, IconUserCircle, IconEdit, IconDatabase, IconServer, IconPencil, IconAlertCircle, IconCircleCheck, IconPlayerPlay, IconAlarmFilled, IconBox, IconLink, IconCircleX, IconFlag, IconCirclePlus, IconFileAnalytics, IconPlus, IconX, IconChevronDown, IconCamera, IconShare, IconCircleDashed, IconListSearch, IconExternalLink, IconSettings, IconFileOff, IconFilesOff, IconHierarchy3, IconMenu, IconRefresh, IconPolaroid, IconCircleMinus, IconEyeOff, IconChevronLeft, IconChevronRight, IconLogin, IconWorld, IconLock, IconVariable, IconArrowRightCircle, IconDownload, IconTemplate, IconChartBar, IconCode, IconUpload, IconCodePlus, IconClipboardCheck, IconClipboardCopy, IconPalette, IconEye, IconMinimize, IconMaximize, IconRss, IconGlobe } from '@tabler/icons-react';
24
+ import { useMediaQuery, useDisclosure, useDebouncedValue, useHotkeys, useFullscreen, getHotkeyHandler } from '@mantine/hooks';
25
25
  import dynamic from 'next/dynamic';
26
26
  import Link from 'next/link';
27
27
  import parse2, { Element, domToReact, Text as Text$1 } from 'html-react-parser';
@@ -1091,6 +1091,20 @@ async function runSingleBlock(block, formatterFunctions, blockContext, readMembe
1091
1091
  let apiResponse;
1092
1092
  let duration = null;
1093
1093
  let api = null;
1094
+ if (!allowed) {
1095
+ return {
1096
+ outputVariables: {},
1097
+ renderVariables: {},
1098
+ status: {
1099
+ api: null,
1100
+ duration: null,
1101
+ resp: null,
1102
+ log: [],
1103
+ error: null,
1104
+ allowed: false
1105
+ }
1106
+ };
1107
+ }
1094
1108
  if (unswappedAPI) {
1095
1109
  api = swapAPI(unswappedAPI, formatterFunctions, blockContext);
1096
1110
  const isAbsolute = new RegExp("^(?:[a-z+]+:)?//", "i");
@@ -1103,7 +1117,7 @@ async function runSingleBlock(block, formatterFunctions, blockContext, readMembe
1103
1117
  return result;
1104
1118
  }, (e) => {
1105
1119
  if (verbose2)
1106
- console.error(`Error fetching ${api}: ${e.message}`);
1120
+ console.error(`Error fetching ${api} block ${block.id}: ${e.message}`);
1107
1121
  return { data: {}, requestDuration: 0 };
1108
1122
  });
1109
1123
  resp = apiResponse.data;
@@ -1237,7 +1251,7 @@ var init_runConsumers = __esm({
1237
1251
  allowed = false;
1238
1252
  } else {
1239
1253
  const parsedBlockContext = parseBlockContext(blockContext);
1240
- const { vars, error, output } = mortarEval_default(
1254
+ const { error, output } = mortarEval_default(
1241
1255
  "variables",
1242
1256
  variables,
1243
1257
  block.settings.allowedLogic || "return false;",
@@ -1251,11 +1265,11 @@ var init_runConsumers = __esm({
1251
1265
  }
1252
1266
  return allowed;
1253
1267
  };
1254
- runConsumersV2 = async (blocks, sections, bid, formatterFunctions, blockContext, initialVariables = {}, readMemberFn, mode = "section") => {
1268
+ runConsumersV2 = async (blocks, sections, bid, formatterFunctions, blockContext, initialState4 = {}, readMemberFn, mode = "section") => {
1255
1269
  if (!bid && !sections)
1256
- return { variables: { ...initialVariables } };
1257
- const variablesById = { ...initialVariables };
1258
- const statusById = {};
1270
+ return { ...initialState4 };
1271
+ const variablesById = { ...initialState4.variables ?? {} };
1272
+ const statusById = { ...initialState4.status ?? {} };
1259
1273
  const parsedBlockContext = parseBlockContext(blockContext);
1260
1274
  const attributes = parsedBlockContext.variables;
1261
1275
  const rootBlocks = bid ? { [bid]: blocks[bid] } : sections.reduce((rootBlocks2, { id }) => ({ ...rootBlocks2, ...getRootBlocksForSection_default(id, blocks) }), {});
@@ -1277,6 +1291,19 @@ var init_runConsumers = __esm({
1277
1291
  );
1278
1292
  const runningTask = dependenciesDone.then(() => {
1279
1293
  const variables = block.inputs.reduce((acc, d) => ({ ...acc, ...variablesById[d] }), attributes);
1294
+ const inputNotAllowed = block.inputs.find((iid) => !statusById[iid].allowed || statusById[iid].hiddenByCascade);
1295
+ if (inputNotAllowed) {
1296
+ statusById[bid2] = {
1297
+ api: null,
1298
+ duration: null,
1299
+ resp: null,
1300
+ log: [],
1301
+ error: null,
1302
+ allowed: false,
1303
+ hiddenByCascade: statusById[inputNotAllowed].hiddenByCascade || inputNotAllowed
1304
+ };
1305
+ return;
1306
+ }
1280
1307
  return runSingleBlock(
1281
1308
  block,
1282
1309
  formatterFunctions,
@@ -1295,7 +1322,10 @@ var init_runConsumers = __esm({
1295
1322
  await Promise.all(Array.from(runningBlocks.values()));
1296
1323
  }
1297
1324
  await runTasksInParallel(orderedDAG, blocks);
1298
- return { variables: { ...initialVariables, ...variablesById }, status: statusById };
1325
+ return {
1326
+ variables: { ...initialState4.variables ?? {}, ...variablesById },
1327
+ status: { ...initialState4.status ?? {}, ...statusById }
1328
+ };
1299
1329
  };
1300
1330
  getDurationColor = (duration) => {
1301
1331
  if (duration < 250)
@@ -1470,11 +1500,11 @@ var init_FUNC = __esm({
1470
1500
  "libs/FUNC.js"() {
1471
1501
  init_esm_shims();
1472
1502
  init_libs();
1473
- parse = (config, formatters = {}, locale = "en", actions = {}, extraGlobals = {}) => {
1503
+ parse = (config, formatters2 = {}, locale = "en", actions = {}, extraGlobals = {}) => {
1474
1504
  const globals = {
1475
1505
  setVariables: actions.onSetVariables ? actions.onSetVariables : (d) => d,
1476
1506
  openModal: actions.onOpenModal ? actions.onOpenModal : (d) => d,
1477
- formatters,
1507
+ formatters: formatters2,
1478
1508
  libs: libraries,
1479
1509
  locale,
1480
1510
  ...extraGlobals
@@ -1608,7 +1638,7 @@ var init_lib2 = __esm({
1608
1638
  statusPayload
1609
1639
  };
1610
1640
  };
1611
- funcifyFormattersByLocale = (formatters = [], locale = localeDefault3) => formatters.reduce((acc, f) => {
1641
+ funcifyFormattersByLocale = (formatters2 = [], locale = localeDefault3) => formatters2.reduce((acc, f) => {
1612
1642
  const formatterFn = parse({ vars: ["n"], logic: f.content.logic }, {}, locale, {});
1613
1643
  acc[f.name] = formatterFn;
1614
1644
  return acc;
@@ -2439,15 +2469,15 @@ var init_actions = __esm({
2439
2469
  });
2440
2470
  function ResourceProvider(props) {
2441
2471
  const { pathSegment, profilePrefix } = props;
2442
- const formatters = useFormatterList();
2472
+ const formatters2 = useFormatterList();
2443
2473
  const value = useMemo(() => ({
2444
2474
  profilePrefix,
2445
2475
  pathSegment,
2446
2476
  formatterFunctions: locales3.reduce((acc, locale) => ({
2447
2477
  ...acc,
2448
- [locale]: formatters.data ? funcifyFormattersByLocale(formatters.data, locale) : {}
2478
+ [locale]: formatters2.data ? funcifyFormattersByLocale(formatters2.data, locale) : {}
2449
2479
  }), {})
2450
- }), [formatters, pathSegment, profilePrefix]);
2480
+ }), [formatters2, pathSegment, profilePrefix]);
2451
2481
  return /* @__PURE__ */ jsx(ResourceContext.Provider, { value, children: props.children });
2452
2482
  }
2453
2483
  function useBespoke() {
@@ -2678,7 +2708,7 @@ var init_store = __esm({
2678
2708
  storeWrapper = createWrapper(storeFactory);
2679
2709
  }
2680
2710
  });
2681
- function withFetcher(Component, useRef7) {
2711
+ function withFetcher(Component, useRef8) {
2682
2712
  const ComponentWithFetcher = (props) => {
2683
2713
  const {
2684
2714
  id,
@@ -2686,7 +2716,7 @@ function withFetcher(Component, useRef7) {
2686
2716
  skelWidth,
2687
2717
  ...otherProps
2688
2718
  } = props;
2689
- const ref = useRef7(id);
2719
+ const ref = useRef8(id);
2690
2720
  if (ref.isUninitialized || ref.isFetching) {
2691
2721
  return /* @__PURE__ */ jsx(Skeleton, { width: skelWidth, height: skelHeight });
2692
2722
  }
@@ -2742,10 +2772,10 @@ var init_d3plusPropify = __esm({
2742
2772
  <strong>${frontEndMessage}</strong>
2743
2773
  </p>`
2744
2774
  };
2745
- propify = (logic, formatters, variables = {}, locale = localeDefault7, id = null, actions = {}, globals = {}) => {
2775
+ propify = (logic, formatters2, variables = {}, locale = localeDefault7, id = null, actions = {}, globals = {}) => {
2746
2776
  let config;
2747
2777
  try {
2748
- config = parse({ vars: ["variables"], logic }, formatters, locale, actions, globals)(variables);
2778
+ config = parse({ vars: ["variables"], logic }, formatters2, locale, actions, globals)(variables);
2749
2779
  } catch (e) {
2750
2780
  console.error(`Parsing Error in propify (ID: ${id})`);
2751
2781
  console.error(`Error message: ${e.message}`);
@@ -2815,6 +2845,37 @@ var init_defaultConfig = __esm({
2815
2845
  };
2816
2846
  }
2817
2847
  });
2848
+ var ErrorBoundary;
2849
+ var init_ErrorBoundary = __esm({
2850
+ "views/ErrorBoundary.tsx"() {
2851
+ init_esm_shims();
2852
+ ErrorBoundary = class extends React.Component {
2853
+ constructor(props) {
2854
+ super(props);
2855
+ this.state = { hasError: false };
2856
+ }
2857
+ static getDerivedStateFromError(error) {
2858
+ return { hasError: true };
2859
+ }
2860
+ componentDidCatch(error, info) {
2861
+ console.log("Error information:", info.componentStack);
2862
+ notifications.show({
2863
+ autoClose: false,
2864
+ color: "red",
2865
+ id: "revalidate-error",
2866
+ message: "Check the console for more details",
2867
+ title: error.message
2868
+ });
2869
+ }
2870
+ render() {
2871
+ if (this.state.hasError) {
2872
+ return this.props.fallback;
2873
+ }
2874
+ return this.props.children;
2875
+ }
2876
+ };
2877
+ }
2878
+ });
2818
2879
 
2819
2880
  // frontend/components/report/blocks/Viz.tsx
2820
2881
  var Viz_exports = {};
@@ -2847,17 +2908,17 @@ function Viz(config) {
2847
2908
  if (!vizTypes[type])
2848
2909
  vizProps.config = { error: `"${type}" is not a valid Visualization Type` };
2849
2910
  const Visualization = vizTypes[fallbackType];
2850
- vizProps.config = { ...vizProps.config, ...configOverride };
2851
- const vizConfig = { locale, variables, ...vizProps.config };
2911
+ const { _data, ...vizPropsConfig } = vizProps.config;
2912
+ const vizConfig = { locale, variables, ...vizPropsConfig, ...configOverride };
2852
2913
  return /* @__PURE__ */ jsx(
2853
2914
  "div",
2854
2915
  {
2855
2916
  style: {
2856
2917
  display: "flex",
2857
2918
  flex: "1 1 100%",
2858
- minHeight: 500
2919
+ minHeight: 400
2859
2920
  },
2860
- children: /* @__PURE__ */ jsx(
2921
+ children: /* @__PURE__ */ jsx(ErrorBoundary, { fallback: /* @__PURE__ */ jsx("p", { children: "Error in d3plus viz config." }), children: /* @__PURE__ */ jsx(
2861
2922
  Visualization,
2862
2923
  {
2863
2924
  style: { flex: 1 },
@@ -2878,7 +2939,7 @@ function Viz(config) {
2878
2939
  config: { ...defaultConfig_default, ...vizConfig }
2879
2940
  },
2880
2941
  "viz-key"
2881
- )
2942
+ ) })
2882
2943
  }
2883
2944
  );
2884
2945
  }
@@ -2892,6 +2953,7 @@ var init_Viz = __esm({
2892
2953
  init_hooks();
2893
2954
  init_defaultConfig();
2894
2955
  init_hooks();
2956
+ init_ErrorBoundary();
2895
2957
  vizTypes = {
2896
2958
  ...d3plus
2897
2959
  };
@@ -3083,8 +3145,8 @@ function Viz2({
3083
3145
  if (debugMessage) {
3084
3146
  return /* @__PURE__ */ jsx(Center, { style: { height: "100%" }, children: /* @__PURE__ */ jsx(Badge, { color: "gray", variant: "outline", children: debugMessage }, "type") });
3085
3147
  }
3086
- vizProps.config = { ...vizProps.config, ...configOverride };
3087
- const vizConfig = { locale, variables, ...vizProps.config };
3148
+ const { _data, ...vizPropsConfig } = vizProps.config;
3149
+ const vizConfig = { locale, variables, ...vizPropsConfig, ...configOverride };
3088
3150
  if (context.print)
3089
3151
  vizConfig.detectVisible = false;
3090
3152
  !context.print && type !== "Graphic" && type !== "HTML";
@@ -3095,7 +3157,7 @@ function Viz2({
3095
3157
  display: "flex",
3096
3158
  flex: "1 1 100%"
3097
3159
  },
3098
- children: /* @__PURE__ */ jsx(
3160
+ children: /* @__PURE__ */ jsx(ErrorBoundary, { fallback: /* @__PURE__ */ jsx("p", { children: "Error in d3plus viz config." }), children: /* @__PURE__ */ jsx(
3099
3161
  Visualization,
3100
3162
  {
3101
3163
  style: { flex: 1 },
@@ -3116,7 +3178,7 @@ function Viz2({
3116
3178
  config: { ...defaultConfig_default, ...vizConfig }
3117
3179
  },
3118
3180
  "viz-key"
3119
- )
3181
+ ) })
3120
3182
  }
3121
3183
  );
3122
3184
  }
@@ -3133,6 +3195,7 @@ var init_Viz2 = __esm({
3133
3195
  init_d3plusPropify();
3134
3196
  init_getBlockContent();
3135
3197
  init_hooks();
3198
+ init_ErrorBoundary();
3136
3199
  useAppContext = () => ({});
3137
3200
  CustomVizzes = {};
3138
3201
  vizTypes2 = {
@@ -3867,9 +3930,10 @@ function useOnChangeSelector(blockId, section, selectorIdentifier) {
3867
3930
  const attributes = useAppSelector((state2) => state2.variables.attributes);
3868
3931
  const blockRecords = selectBlockRecords(state);
3869
3932
  const formatterList = selectFormatterList(state);
3870
- const formatters = funcifyFormattersByLocale(formatterList, localeDefault4);
3933
+ const formatters2 = funcifyFormattersByLocale(formatterList, localeDefault4);
3871
3934
  const variables = useInputVariablesFlat(blockId);
3872
3935
  const initialVariables = useAppSelector((state2) => state2.variables.variables);
3936
+ const initialStatus = useAppSelector((state2) => state2.variables.status);
3873
3937
  const readMemberFn = useReadMemberFn();
3874
3938
  const callback = useCallback(
3875
3939
  (value) => {
@@ -3883,9 +3947,12 @@ function useOnChangeSelector(blockId, section, selectorIdentifier) {
3883
3947
  blockRecords,
3884
3948
  void 0,
3885
3949
  blockId,
3886
- formatters,
3950
+ formatters2,
3887
3951
  blockContext,
3888
- initialVariables,
3952
+ {
3953
+ variables: initialVariables,
3954
+ status: initialStatus
3955
+ },
3889
3956
  readMemberFn,
3890
3957
  "report"
3891
3958
  ).then((data) => {
@@ -3903,7 +3970,7 @@ function useOnChangeSelector(blockId, section, selectorIdentifier) {
3903
3970
  query,
3904
3971
  blockRecords,
3905
3972
  dispatch,
3906
- formatters,
3973
+ formatters2,
3907
3974
  router,
3908
3975
  variables.attributes
3909
3976
  ]
@@ -4002,8 +4069,9 @@ function useInitialState(pathSegmentsKey) {
4002
4069
  const attributes = useAppSelector((state2) => state2.variables.attributes);
4003
4070
  const blockRecords = selectBlockRecords(state);
4004
4071
  const formatterList = selectFormatterList(state);
4005
- const formatters = funcifyFormattersByLocale(formatterList, localeDefault4);
4072
+ const formatters2 = funcifyFormattersByLocale(formatterList, localeDefault4);
4006
4073
  const variables = useAppSelector((state2) => state2.variables.variables);
4074
+ const status = useAppSelector((state2) => state2.variables.status);
4007
4075
  const readMemberFn = useReadMemberFn();
4008
4076
  useEffect(() => {
4009
4077
  if (!isLoading && user && report_id) {
@@ -4045,9 +4113,9 @@ function useInitialState(pathSegmentsKey) {
4045
4113
  blockRecords,
4046
4114
  void 0,
4047
4115
  bid,
4048
- formatters,
4116
+ formatters2,
4049
4117
  blockContext,
4050
- variables,
4118
+ { variables, status },
4051
4119
  readMemberFn,
4052
4120
  "report"
4053
4121
  ).then((data) => {
@@ -4118,12 +4186,14 @@ function createOutline(elements, variables) {
4118
4186
  function useContentOutline(min = 1, max = 6, headings = []) {
4119
4187
  const state = useAppSelector((state2) => state2);
4120
4188
  const variables = useAppSelector((state2) => state2.variables.variables);
4189
+ const status = useAppSelector((state2) => state2.variables.status);
4121
4190
  const sectionList = useSectionList();
4122
4191
  const titleList = selectBlockList(state).filter((block) => {
4123
4192
  return block.type === BLOCK_TYPES.TITLE && headings.includes(block.id);
4124
4193
  });
4125
4194
  const titleBlocks = Object.fromEntries(titleList.map((block) => [block.id, block]));
4126
4195
  const titleVariables = Object.fromEntries(titleList.map((block) => [block.id, variables[block.id]]));
4196
+ const titleStatus = Object.fromEntries(titleList.map((block) => [block.id, status[block.id]]));
4127
4197
  const titlesSorted = useMemo(() => {
4128
4198
  if (sectionList.isSuccess && titleBlocks) {
4129
4199
  let titleBlocksNormalized = [];
@@ -4141,10 +4211,10 @@ function useContentOutline(min = 1, max = 6, headings = []) {
4141
4211
  });
4142
4212
  return titleBlocksNormalized.filter((title) => {
4143
4213
  const currentOrder = parseInt(title.settings.order || "1", 10);
4144
- return currentOrder >= min && currentOrder <= max;
4214
+ return currentOrder >= min && currentOrder <= max && titleStatus[title.id] ? titleStatus[title.id].allowed : true;
4145
4215
  });
4146
4216
  }
4147
- }, [headings, sectionList, titleBlocks]);
4217
+ }, [headings, sectionList, titleBlocks, titleStatus]);
4148
4218
  return useMemo(() => {
4149
4219
  if (titlesSorted && titlesSorted?.length > 0) {
4150
4220
  return createOutline(titlesSorted, titleVariables);
@@ -5329,10 +5399,18 @@ function Block({ blockId, active = true }) {
5329
5399
  };
5330
5400
  fetch();
5331
5401
  }, [blockContent, variables]);
5332
- if (!block || !content || !blockStatus.allowed)
5402
+ const allowed = blockStatus.allowed || block?.type === BLOCK_TYPES.NAV;
5403
+ if (!block || !content || !allowed)
5333
5404
  return null;
5334
5405
  const Renderer = blocks_default[block.type];
5335
- return /* @__PURE__ */ jsx("div", { id: `bespoke-${block.type}-${block.id}`, className: `cms-block-wrapper cms-block-${blockId}`, children: /* @__PURE__ */ jsx(Renderer, { ...content, settings: block.settings }) });
5406
+ return /* @__PURE__ */ jsx(
5407
+ "div",
5408
+ {
5409
+ id: `bespoke-${block.type}-${block.id}`,
5410
+ className: `cms-block-wrapper bespoke-block-area cms-block-${blockId}`,
5411
+ children: /* @__PURE__ */ jsx(Renderer, { ...content, settings: block.settings })
5412
+ }
5413
+ );
5336
5414
  }
5337
5415
 
5338
5416
  // libs/settings/section.tsx
@@ -5445,19 +5523,33 @@ function CopyInput(props) {
5445
5523
  init_esm_shims();
5446
5524
  var defaultIdAccessor = "_key";
5447
5525
  function SortableTable({ data, customIdAccessor = "id" }) {
5448
- const [records, setRecords] = useState(data);
5526
+ const [records, setRecords] = useState();
5449
5527
  const [sortStatus, setSortStatus] = useState();
5450
- const keys = data && data[0] ? Object.keys(data[0]) : [];
5528
+ const keys = data && Array.isArray(data) && data[0] ? Object.keys(data[0]) : [];
5451
5529
  const idAccessor = keys.includes(customIdAccessor) ? customIdAccessor : defaultIdAccessor;
5452
5530
  const fields = keys.filter((k) => !k.startsWith("_"));
5453
5531
  const columns = fields.map((field) => ({ accessor: field, sortable: true }));
5454
5532
  const getSortedData = (sortField) => {
5455
5533
  let dataTemp = [...data];
5456
- if (idAccessor === defaultIdAccessor) {
5457
- dataTemp = dataTemp.map((item, ix) => ({ ...item, _key: `i-${ix}` }));
5458
- }
5534
+ dataTemp = dataTemp.map((item, ix) => {
5535
+ fields.forEach((f) => {
5536
+ if (typeof item[f] === "object") {
5537
+ item[f] = JSON.stringify(item[f]);
5538
+ }
5539
+ });
5540
+ if (idAccessor === defaultIdAccessor) {
5541
+ item._key = `i-${ix}`;
5542
+ }
5543
+ return item;
5544
+ });
5459
5545
  if (sortField) {
5460
- dataTemp = dataTemp.sort((a, b) => a[sortField.columnAccessor].localeCompare(b[sortField.columnAccessor]));
5546
+ dataTemp = dataTemp.sort((a, b) => {
5547
+ if (isNaN(a[sortField.columnAccessor])) {
5548
+ return a[sortField.columnAccessor].localeCompare(b[sortField.columnAccessor]);
5549
+ } else {
5550
+ return a[sortField.columnAccessor] > b[sortField.columnAccessor] ? 1 : -1;
5551
+ }
5552
+ });
5461
5553
  }
5462
5554
  return sortField && sortField.direction === "desc" ? dataTemp.reverse() : dataTemp;
5463
5555
  };
@@ -5484,6 +5576,14 @@ function SortableTable({ data, customIdAccessor = "id" }) {
5484
5576
  }
5485
5577
  );
5486
5578
  }
5579
+
5580
+ // components/options/tabs/DataTab.tsx
5581
+ init_cms();
5582
+ init_d3plusPropify();
5583
+ init_getBlockContent();
5584
+ init_hooks();
5585
+ init_varSwapRecursive();
5586
+ init_runConsumers();
5487
5587
  var formatOptions = {
5488
5588
  csv: "CSV",
5489
5589
  json: "JSON",
@@ -5491,54 +5591,149 @@ var formatOptions = {
5491
5591
  };
5492
5592
  function DataTab(props) {
5493
5593
  const { section } = props;
5594
+ const readMemberFn = useReadMemberFn();
5494
5595
  const blocksIds = section.blocks || [];
5495
- const apiBlocks = useAppSelector((state) => blocksIds.map((blockId) => state.records.entities.block[blockId]).filter((block) => block.type === "generator" && block.contentByLocale.logic.content.api).map((generator) => {
5496
- const api = state.variables.status[generator.id]?.api || "";
5497
- const data = state.variables.variables[generator.id]._data || [];
5498
- return {
5499
- ...generator,
5500
- api,
5501
- data
5502
- };
5503
- }));
5504
- const sourcesOptions = apiBlocks.map((block, ix) => ({
5505
- id: block.id,
5506
- title: `Data Source ${ix + 1}`,
5507
- path: block.api,
5508
- data: block.data
5509
- }));
5596
+ const locale = useAppSelector((state) => state.status.currentLocale);
5597
+ const PREVIEW_SIZE = 50;
5598
+ const formatterFunctions = useFormatterFunctionsForLocale(locale);
5599
+ const router = useRouter();
5600
+ const sourcesOptions = useAppSelector((state) => {
5601
+ const dataInformation = [];
5602
+ console.log("calculate api blocks");
5603
+ blocksIds.map((blockId) => state.records.entities.block[blockId]).filter((block) => [BLOCK_TYPES.GENERATOR, BLOCK_TYPES.VIZ].includes(block.type)).map((block) => {
5604
+ if (block.type === BLOCK_TYPES.GENERATOR) {
5605
+ const api = state.variables.variables[block.id]._api || state.variables.status[block.id].api;
5606
+ if (api) {
5607
+ const ix = dataInformation.length;
5608
+ dataInformation.push(
5609
+ {
5610
+ ix,
5611
+ id: block.id,
5612
+ title: `Data Source ${ix + 1}`,
5613
+ path: api
5614
+ }
5615
+ );
5616
+ }
5617
+ } else if (block.type === BLOCK_TYPES.VIZ) {
5618
+ const content = getBlockContent(block);
5619
+ const variables = useInputVariablesFlat(block.id);
5620
+ const blockContext = { variables };
5621
+ const { sectionVariables, setSectionVariables, resetSectionVariables } = useSectionVariables(block.section_id);
5622
+ const transpiledLogic = varSwapRecursive_default({ logic: content.logic }, formatterFunctions, blockContext).logic;
5623
+ const globals = {
5624
+ router,
5625
+ section: {
5626
+ variables: sectionVariables,
5627
+ setVariables: setSectionVariables,
5628
+ resetVariables: resetSectionVariables
5629
+ }
5630
+ };
5631
+ const d3Props = d3plusPropify_default(transpiledLogic, formatterFunctions, variables, locale, block.id, {}, globals);
5632
+ if (d3Props.config._api) {
5633
+ const ix = dataInformation.length;
5634
+ dataInformation.push(
5635
+ {
5636
+ ix,
5637
+ id: block.id,
5638
+ title: `Viz Data Source ${ix + 1}`,
5639
+ path: d3Props.config._api
5640
+ }
5641
+ );
5642
+ } else if (typeof d3Props.config.data === "string") {
5643
+ const ix = dataInformation.length;
5644
+ dataInformation.push(
5645
+ {
5646
+ ix,
5647
+ id: block.id,
5648
+ title: `Viz Data Source ${ix + 1}`,
5649
+ path: d3Props.config.data
5650
+ }
5651
+ );
5652
+ } else if (Array.isArray(d3Props.config.data)) {
5653
+ d3Props.config.data.forEach((dataItem) => {
5654
+ if (typeof dataItem === "string") {
5655
+ const ix = dataInformation.length;
5656
+ dataInformation.push(
5657
+ {
5658
+ ix,
5659
+ id: block.id,
5660
+ title: `Viz Data Source ${ix + 1}`,
5661
+ path: dataItem
5662
+ }
5663
+ );
5664
+ }
5665
+ });
5666
+ }
5667
+ }
5668
+ });
5669
+ return dataInformation;
5670
+ });
5510
5671
  const [selectedSource, setSelectedSource] = useState();
5511
5672
  const [fileProcessing, setFileProcessing] = useState(false);
5512
5673
  const [fileFormat, setFileFormat] = useState(formatOptions.csv);
5674
+ const [previewsSource, setPreviewsSource] = useState({});
5675
+ const [loadingPreview, setLoadingPreview] = useState(false);
5513
5676
  useEffect(() => {
5514
5677
  if (sourcesOptions[0]) {
5515
5678
  setSelectedSource(sourcesOptions[0]);
5516
5679
  }
5517
5680
  }, []);
5518
- const getFileName = (format2) => {
5519
- const sectionId = section.id;
5520
- const sourceId = selectedSource.id;
5521
- return `data_section_${sectionId}_block_${sourceId}.${format2.toLowerCase()}`;
5681
+ useEffect(() => {
5682
+ if (selectedSource && !previewsSource[selectedSource.ix]) {
5683
+ setLoadingPreview(true);
5684
+ apiFetch(selectedSource.path, {}, readMemberFn, locale).then((response) => {
5685
+ let dataToShare = [];
5686
+ if (response && response.data) {
5687
+ if (response.data && Array.isArray(response.data)) {
5688
+ dataToShare = response.data;
5689
+ } else if (response.data && response.data.data && Array.isArray(response.data.data)) {
5690
+ dataToShare = response.data.data;
5691
+ } else if (response.data && response.data.data && response.data.data.results && Array.isArray(response.data.data.results)) {
5692
+ dataToShare = response.data.data.results;
5693
+ } else if (response.data && response.data.results && Array.isArray(response.data.results)) {
5694
+ dataToShare = response.data.results;
5695
+ }
5696
+ }
5697
+ setPreviewsSource({
5698
+ ...previewsSource,
5699
+ [selectedSource.ix]: dataToShare
5700
+ });
5701
+ }).catch((e) => {
5702
+ console.error(e);
5703
+ }).finally(() => {
5704
+ setLoadingPreview(false);
5705
+ });
5706
+ }
5707
+ }, [selectedSource]);
5708
+ const getFileName = (nameformat, fileFormat2) => {
5709
+ const finalNameFormat = nameformat === fileFormat2 ? "" : `_${nameformat}`.toLowerCase();
5710
+ if (selectedSource) {
5711
+ return `data_section_${section.id}_block_${selectedSource.id}_${selectedSource.ix}${finalNameFormat}.${fileFormat2.toLowerCase()}`;
5712
+ }
5713
+ return `data_file${finalNameFormat}.${fileFormat2}`;
5714
+ };
5715
+ const getCurrentPreview = () => {
5716
+ return selectedSource && previewsSource[selectedSource.ix] ? previewsSource[selectedSource.ix] : [];
5522
5717
  };
5523
5718
  const onSaveClick = async () => {
5524
5719
  if (selectedSource) {
5525
5720
  setFileProcessing(true);
5526
5721
  const zipFile = new JSZip();
5527
- const filename = getFileName(fileFormat);
5722
+ const filename = getFileName(fileFormat, fileFormat);
5528
5723
  try {
5529
5724
  switch (fileFormat) {
5530
5725
  case formatOptions.json:
5531
- zipFile.file(filename, JSON.stringify(selectedSource.data));
5726
+ zipFile.file(filename, JSON.stringify(currentPreview));
5532
5727
  break;
5533
5728
  case formatOptions.csv:
5534
- zipFile.file(filename, csvFormat(selectedSource.data));
5729
+ zipFile.file(filename, csvFormat(currentPreview));
5535
5730
  break;
5536
5731
  case formatOptions.xlsx:
5537
5732
  const { utils, write } = await import('xlsx');
5538
5733
  const wb = utils.book_new();
5539
5734
  utils.book_append_sheet(
5540
5735
  wb,
5541
- utils.json_to_sheet(selectedSource.data),
5736
+ utils.json_to_sheet(currentPreview),
5542
5737
  filename.substring(0, 30)
5543
5738
  // Sheet name max length
5544
5739
  );
@@ -5554,7 +5749,7 @@ function DataTab(props) {
5554
5749
  compressionOptions: { level: 9 }
5555
5750
  }).then((content) => {
5556
5751
  setFileProcessing(false);
5557
- saveAs(content, getFileName("zip"));
5752
+ saveAs(content, getFileName(fileFormat, "zip"));
5558
5753
  });
5559
5754
  } catch (error) {
5560
5755
  console.error("Error generating file", error);
@@ -5562,22 +5757,24 @@ function DataTab(props) {
5562
5757
  }
5563
5758
  }
5564
5759
  };
5760
+ const currentPreview = getCurrentPreview();
5565
5761
  return /* @__PURE__ */ jsxs(Stack, { className: "cms-section-options-data", children: [
5566
5762
  /* @__PURE__ */ jsx(Space, { h: "xs" }),
5567
5763
  sourcesOptions.length === 0 && /* @__PURE__ */ jsx("p", { children: "No data sources defined." }),
5568
- sourcesOptions.length > 0 && /* @__PURE__ */ jsx(Input.Wrapper, { label: "Choose Data Source:", children: /* @__PURE__ */ jsx(Button.Group, { children: sourcesOptions.map((source, ix) => /* @__PURE__ */ jsx(
5764
+ sourcesOptions.length > 1 && /* @__PURE__ */ jsx(Input.Wrapper, { label: "Choose Data Source:", children: /* @__PURE__ */ jsx(Group, { spacing: "xs", children: sourcesOptions.map((source, ix) => /* @__PURE__ */ jsx(
5569
5765
  Button,
5570
5766
  {
5571
5767
  leftIcon: /* @__PURE__ */ jsx(IconDatabase, { size: 16 }),
5572
5768
  onClick: () => setSelectedSource(source),
5573
- variant: selectedSource?.id === source.id ? "filled" : "default",
5574
- fullWidth: true,
5769
+ variant: selectedSource?.ix === ix ? "filled" : "default",
5575
5770
  children: source.title
5576
5771
  },
5577
- `source-${source.id}`
5772
+ `source-${source.id}-${ix}`
5578
5773
  )) }) }),
5579
5774
  selectedSource && /* @__PURE__ */ jsx(CopyInput, { title: `Original ${selectedSource.title}:`, url: selectedSource.path }),
5580
- selectedSource && (!selectedSource.data || selectedSource.data.length === 0) && /* @__PURE__ */ jsx("a", { href: selectedSource.path, target: "_blank", rel: "noreferrer", children: /* @__PURE__ */ jsx(
5775
+ selectedSource && loadingPreview && /* @__PURE__ */ jsx(Fragment, { children: "Loading..." }),
5776
+ selectedSource && !loadingPreview && currentPreview.length === 0 && /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: "1rem" }), title: "Oops!", children: "Sorry. We couldn't generate the data preview. Try to open the source and check the data directly." }),
5777
+ selectedSource && !loadingPreview && currentPreview.length === 0 && /* @__PURE__ */ jsx("a", { href: selectedSource.path, target: "_blank", rel: "noreferrer", children: /* @__PURE__ */ jsx(
5581
5778
  Button,
5582
5779
  {
5583
5780
  leftIcon: /* @__PURE__ */ jsx(IconExternalLink, { size: 16 }),
@@ -5585,8 +5782,16 @@ function DataTab(props) {
5585
5782
  children: `Open ${selectedSource.title} response in a new window`
5586
5783
  }
5587
5784
  ) }),
5588
- selectedSource && selectedSource.data && selectedSource.data.length > 0 && /* @__PURE__ */ jsxs(Stack, { children: [
5589
- /* @__PURE__ */ jsx(Input.Wrapper, { label: `Formatted ${selectedSource.title}:`, style: { height: "300px" }, children: /* @__PURE__ */ jsx(SortableTable, { data: selectedSource.data }) }),
5785
+ selectedSource && !loadingPreview && currentPreview.length > 0 && /* @__PURE__ */ jsxs(Stack, { children: [
5786
+ /* @__PURE__ */ jsx(
5787
+ Input.Wrapper,
5788
+ {
5789
+ label: `Formatted ${selectedSource.title}
5790
+ ${currentPreview.length > PREVIEW_SIZE ? `(First ${PREVIEW_SIZE} rows as preview)` : ""}:`,
5791
+ style: { height: "300px" },
5792
+ children: /* @__PURE__ */ jsx(SortableTable, { data: currentPreview.slice(0, PREVIEW_SIZE) })
5793
+ }
5794
+ ),
5590
5795
  /* @__PURE__ */ jsx(Space, { h: "xs" }),
5591
5796
  /* @__PURE__ */ jsx(Input.Wrapper, { label: "Choose format:", children: /* @__PURE__ */ jsx(Button.Group, { children: Object.keys(formatOptions).map((format2) => /* @__PURE__ */ jsx(
5592
5797
  Button,
@@ -5606,7 +5811,7 @@ function DataTab(props) {
5606
5811
  loading: fileProcessing,
5607
5812
  onClick: onSaveClick,
5608
5813
  fullWidth: true,
5609
- children: /* @__PURE__ */ jsx("span", { children: fileProcessing ? "Processing file..." : `Download ${fileFormat}` })
5814
+ children: /* @__PURE__ */ jsx("span", { children: fileProcessing ? "Processing file..." : `Download full dataset in ${fileFormat} format` })
5610
5815
  }
5611
5816
  )
5612
5817
  ] })
@@ -5697,12 +5902,12 @@ function ImageTab(props) {
5697
5902
  };
5698
5903
  const getFileName = () => `${slugify_default("export-name")}`;
5699
5904
  const getSectionNode = (sectionId) => {
5700
- const sectionNode = document.getElementById(`cms-section-${sectionId}`);
5701
- return select(sectionNode).select(".cms-section-content").node();
5905
+ const sectionNode = document.getElementById(`section-${sectionId}`);
5906
+ return select(sectionNode).select(".bespoke-section-content").node();
5702
5907
  };
5703
5908
  const getVizNode = (sectionId, vizId) => {
5704
- const sectionNode = document.getElementById(`cms-section-${sectionId}`);
5705
- return select(sectionNode).select(`#cms-block-${vizId} .cms-block-preview`).node();
5909
+ const sectionNode = getSectionNode(sectionId);
5910
+ return select(sectionNode).select(`#bespoke-visualization-${vizId}.bespoke-block-area`).node();
5706
5911
  };
5707
5912
  const getSelectedNode = () => {
5708
5913
  let node;
@@ -5912,7 +6117,7 @@ function ShareTab(props) {
5912
6117
  setTitle(document.title);
5913
6118
  const { origin, pathname } = window.location;
5914
6119
  const url = `${origin}${pathname}`;
5915
- const sectionAnchor = includeSection ? `#cms-section-${section.id}` : "";
6120
+ const sectionAnchor = includeSection ? `#section-${section.id}` : "";
5916
6121
  setShareUrl(`${url}${sectionAnchor}`);
5917
6122
  }, [includeSection]);
5918
6123
  return /* @__PURE__ */ jsxs(Stack, { className: "cms-section-options-share", children: [
@@ -6012,9 +6217,9 @@ function OptionsModal(props) {
6012
6217
  keepMounted: false,
6013
6218
  children: [
6014
6219
  /* @__PURE__ */ jsxs(Tabs.List, { children: [
6015
- /* @__PURE__ */ jsx(Tabs.Tab, { value: "data", children: "Data" }),
6220
+ /* @__PURE__ */ jsx(Tabs.Tab, { value: "data", children: "Download data" }),
6016
6221
  /* @__PURE__ */ jsx(Tabs.Tab, { value: "image", children: "Save image" }),
6017
- /* @__PURE__ */ jsx(Tabs.Tab, { value: "share", children: "Share" })
6222
+ /* @__PURE__ */ jsx(Tabs.Tab, { value: "share", children: "Share link" })
6018
6223
  ] }),
6019
6224
  /* @__PURE__ */ jsx(Tabs.Panel, { value: "data", children: /* @__PURE__ */ jsx(DataTab, { section }) }),
6020
6225
  /* @__PURE__ */ jsx(Tabs.Panel, { value: "image", children: /* @__PURE__ */ jsx(ImageTab, { section }) }),
@@ -6053,7 +6258,7 @@ function Options(props) {
6053
6258
  initialMode: mode,
6054
6259
  open: opened,
6055
6260
  onEnds: onModalEnds,
6056
- title: "Section title"
6261
+ title: "Section information"
6057
6262
  }
6058
6263
  )
6059
6264
  ] });
@@ -6246,175 +6451,568 @@ var SectionMenu_default = SectionMenu;
6246
6451
 
6247
6452
  // frontend/components/report/Section.tsx
6248
6453
  init_cms();
6249
- var getStyles = (styles, settings) => (theme) => styles ? styles(theme, settings) : {};
6250
- var PositionWrapper = ({ settings, styles, children, ...props }) => {
6251
- const { position } = settings;
6252
- const defaultStyles = {
6253
- "normal": {
6254
- position: "relative",
6255
- backgroundColor: "transparent",
6256
- borderRadius: 0
6257
- },
6258
- "sticky": {
6259
- position: "sticky",
6260
- zIndex: 3,
6261
- top: 0,
6262
- borderRadius: 0,
6263
- borderTop: "none",
6264
- borderLeft: "none",
6265
- borderRight: "none"
6266
- }
6267
- };
6268
- const defaultProps = {
6269
- "normal": {
6270
- radius: 0
6271
- },
6272
- "sticky": {
6273
- radius: 0,
6274
- withBorder: true
6275
- }
6276
- };
6277
- const sx = [defaultStyles[position], getStyles(styles, settings)];
6278
- return /* @__PURE__ */ jsx(Paper, { component: "section", sx, ...defaultProps[position], ...props, children });
6279
- };
6280
- var WidthWrapper = ({ settings, styles, children, ...props }) => {
6281
- const { width: container } = settings;
6282
- const defaultStyles = {
6283
- "center": {},
6284
- "full": {}
6285
- };
6286
- const defaultProps = {
6287
- "center": { size: "md", p: "sm", fluid: false },
6288
- "full": { fluid: true, p: "md" }
6289
- };
6290
- const sx = [defaultStyles[container], getStyles(styles, settings)];
6291
- return /* @__PURE__ */ jsx(Container, { sx, ...defaultProps[container], ...props, children });
6292
- };
6293
- var StyleWrapper = ({ settings, styles, children, ...props }) => {
6294
- const { style: variant } = settings;
6295
- const defaultStyles = {
6296
- "none": {},
6297
- "card": {}
6298
- };
6299
- const defaultProps = {
6300
- "none": { bg: "transparent" },
6301
- "card": { shadow: "lg", p: "md", radius: "md" }
6302
- };
6303
- const sx = [defaultStyles[variant], getStyles(styles, settings)];
6304
- return /* @__PURE__ */ jsx(Paper, { sx, ...defaultProps[variant], ...props, children });
6454
+
6455
+ // components/sections/SectionColumns.tsx
6456
+ init_esm_shims();
6457
+
6458
+ // libs/settings/site.ts
6459
+ init_esm_shims();
6460
+ var site_default = {
6461
+ backgroundColor: "#fafafa",
6462
+ block: {
6463
+ padding: 10
6464
+ },
6465
+ column: {
6466
+ padding: 12
6467
+ },
6468
+ section: {
6469
+ backgroundColor: "white",
6470
+ borderRadius: 10,
6471
+ boxShadow: "0px 6px 10px rgba(12, 32, 50, 0.14), 0px 1px 15px rgba(12, 32, 50, 0.12), 0px 3px 5px rgba(12, 32, 50, 0.15)",
6472
+ margin: 8,
6473
+ padding: 32
6474
+ }
6305
6475
  };
6306
- function Section({ section }) {
6307
- const { id, settings } = section;
6308
- const sectionSettings2 = {
6309
- ...defaultSectionSettings,
6310
- ...settings
6311
- };
6312
- const state = useAppSelector((state2) => state2);
6313
- const status = useAppSelector((state2) => state2.variables.status);
6314
- const sectionStyles = useBespokeStyles()["Section"];
6315
- const blockRecords = selectBlockRecords(state);
6476
+
6477
+ // components/sections/SectionColumns.tsx
6478
+ init_store2();
6479
+ function SectionColumnsWrapper({
6480
+ children,
6481
+ containerProps
6482
+ }, ref) {
6316
6483
  const theme = useMantineTheme();
6317
- const smallScreen = useMediaQuery(`(max-width: ${theme.breakpoints.sm}px)`);
6318
- const sectionBlocks = Object.values(blockRecords || {}).filter((d) => d.section_id === id);
6319
- const allowedSection = sectionBlocks.some((b) => {
6320
- try {
6321
- return status[b.id].allowed && b.type !== BLOCK_TYPES.GENERATOR;
6322
- } catch (e) {
6323
- return b.settings.allowed === "always";
6324
- }
6325
- });
6326
- const columns = sectionBlocks.reduce((acc, d) => {
6327
- if (!acc[d.blockcol]) {
6328
- acc[d.blockcol] = { [d.blockrow]: d };
6329
- } else {
6330
- acc[d.blockcol][d.blockrow] = d;
6331
- }
6332
- return acc;
6333
- }, {});
6334
- const displaySection = Object.keys(blockRecords).length > 0 && !settings.hidden && allowedSection;
6335
- if (!displaySection)
6336
- return null;
6337
- return /* @__PURE__ */ jsxs(
6338
- PositionWrapper,
6484
+ const mediumScreen = useMediaQuery(`(max-width: ${theme.breakpoints.md})`);
6485
+ return /* @__PURE__ */ jsx(
6486
+ Flex,
6339
6487
  {
6340
- settings: sectionSettings2,
6341
- styles: sectionStyles?.root || void 0,
6342
- children: [
6343
- sectionSettings2.memberImageBg && /* @__PURE__ */ jsx(SectionBackground, {}),
6344
- /* @__PURE__ */ jsx(
6345
- WidthWrapper,
6346
- {
6347
- settings: sectionSettings2,
6348
- styles: sectionStyles?.container,
6349
- className: `cms-section-${id}`,
6350
- pos: "relative",
6351
- children: /* @__PURE__ */ jsx(StyleWrapper, { settings: sectionSettings2, styles: sectionStyles?.content, children: /* @__PURE__ */ jsxs(
6352
- Flex,
6353
- {
6354
- className: "cms-section-content",
6355
- align: "stretch",
6356
- direction: smallScreen ? "column" : "row",
6357
- pos: "relative",
6358
- gap: "md",
6359
- children: [
6360
- /* @__PURE__ */ jsxs("div", { style: {
6361
- position: "absolute",
6362
- right: 10,
6363
- top: 10,
6364
- zIndex: 100
6365
- }, children: [
6366
- sectionSettings2.optionsMenu && /* @__PURE__ */ jsx(Options, { sectionId: section.id }),
6367
- /* @__PURE__ */ jsx(SectionResetButton, { id: section.id })
6368
- ] }),
6369
- Object.keys(columns).sort((a, b) => orderSort(a, b, "blockcol")).map((columnIndex) => {
6370
- const column = columns[columnIndex];
6371
- const staticWidths = Object.values(column).map(({ id: id2 }) => parseFloat(blockRecords[id2]?.settings?.width || "none")).filter((d) => !Number.isNaN(d));
6372
- return /* @__PURE__ */ jsx(
6373
- Stack,
6374
- {
6375
- className: "cms-section-col",
6376
- sx: {
6377
- flex: "1 1 100%",
6378
- maxWidth: staticWidths.length ? Math.max(...staticWidths) : "none"
6379
- },
6380
- children: Object.values(column).sort((a, b) => orderSort(a, b, "blockrow")).map((item) => {
6381
- if (item.id)
6382
- return /* @__PURE__ */ jsx(Block, { blockId: item.id }, item.id);
6383
- })
6384
- },
6385
- columnIndex
6386
- );
6387
- })
6388
- ]
6389
- }
6390
- ) })
6391
- }
6392
- )
6393
- ]
6488
+ ref,
6489
+ className: "bespoke-section-content",
6490
+ pos: "relative",
6491
+ align: "stretch",
6492
+ direction: mediumScreen ? "column" : "row",
6493
+ wrap: "wrap",
6494
+ ...containerProps,
6495
+ children
6394
6496
  }
6395
6497
  );
6396
6498
  }
6397
- var Section_default = Section;
6398
- function Report() {
6399
- const sectionList = useSectionList();
6400
- return /* @__PURE__ */ jsx(Container, { p: 0, pos: "relative", fluid: true, children: sectionList.isSuccess && sectionList.data.sort(orderSort).map((section) => /* @__PURE__ */ jsx(Section_default, { section }, section.id)) });
6401
- }
6402
- var Report_default = Report;
6403
-
6404
- // frontend/components/auth/LoginButton.tsx
6405
- init_esm_shims();
6406
-
6407
- // types/auth.ts
6408
- init_esm_shims();
6409
- var CMS_ROLES = {
6410
- ADMIN: "Admin",
6411
- EDITOR: "Editor",
6412
- WRITER: "Writer"
6413
- };
6414
- function BespokeLoginBtn({
6415
- buttonProps = {},
6416
- editorMenuItemProps = {},
6417
- editorMenuItemRoute = "/cms",
6499
+ var SectionColumn = React.forwardRef(
6500
+ function SectionColumn2({ children, column, columnSettings, sx = {}, ...rest }, ref) {
6501
+ const hasInline = Object.values(column).some((item) => item.settings?.display === "inline");
6502
+ const width = columnSettings?.width;
6503
+ const theme = useMantineTheme();
6504
+ const mediumScreen = useMediaQuery(`(max-width: ${theme.breakpoints.md})`);
6505
+ return /* @__PURE__ */ jsx(
6506
+ Flex,
6507
+ {
6508
+ ref,
6509
+ className: "bespoke-section-col",
6510
+ align: "flex-start",
6511
+ direction: hasInline ? "row" : "column",
6512
+ wrap: hasInline ? "wrap" : "nowrap",
6513
+ maw: width && !mediumScreen ? `${width}px` : "none",
6514
+ miw: mediumScreen ? 300 : 400,
6515
+ p: site_default.column.padding,
6516
+ pos: "relative",
6517
+ sx: [{ flexGrow: 1, flexShrink: 1 }, ...packSx(sx)],
6518
+ ...rest,
6519
+ children
6520
+ }
6521
+ );
6522
+ }
6523
+ );
6524
+ var ResizeColumnInput = ({ sectionId, columnIndex }) => {
6525
+ const dispatch = useAppDispatch();
6526
+ const section = useSectionRef(sectionId).data;
6527
+ if (!section)
6528
+ return null;
6529
+ const { columnSettings = {} } = section.settings;
6530
+ const { width = void 0 } = columnSettings[columnIndex] ? columnSettings[columnIndex] : {};
6531
+ const handleChange = (e) => {
6532
+ if (section) {
6533
+ dispatch(actions_exports.updateEntity("section", {
6534
+ id: sectionId,
6535
+ settings: {
6536
+ ...section.settings,
6537
+ columnSettings: {
6538
+ ...columnSettings,
6539
+ [columnIndex]: {
6540
+ width: parseInt(e.target.value, 10)
6541
+ }
6542
+ }
6543
+ }
6544
+ }));
6545
+ }
6546
+ };
6547
+ const handleReset = () => {
6548
+ if (section) {
6549
+ dispatch(actions_exports.updateEntity("section", {
6550
+ id: sectionId,
6551
+ settings: {
6552
+ ...section.settings,
6553
+ columnSettings: {
6554
+ ...columnSettings,
6555
+ [columnIndex]: {
6556
+ width: void 0
6557
+ }
6558
+ }
6559
+ }
6560
+ }));
6561
+ }
6562
+ };
6563
+ return /* @__PURE__ */ jsx(
6564
+ Box,
6565
+ {
6566
+ className: "bespoke-resize-col",
6567
+ pos: "absolute",
6568
+ top: 0,
6569
+ left: "50%",
6570
+ sx: {
6571
+ transform: "translate(-50%, -50%)",
6572
+ zIndex: 2
6573
+ },
6574
+ p: "sm",
6575
+ maw: 110,
6576
+ children: /* @__PURE__ */ jsx(
6577
+ Input,
6578
+ {
6579
+ placeholder: "auto",
6580
+ w: "fit-content",
6581
+ miw: "none",
6582
+ variant: "filled",
6583
+ type: "number",
6584
+ value: width || "auto",
6585
+ onChange: handleChange,
6586
+ size: "xs",
6587
+ p: 0,
6588
+ rightSection: /* @__PURE__ */ jsx(IconX, { onClick: handleReset, size: 8 })
6589
+ }
6590
+ )
6591
+ }
6592
+ );
6593
+ };
6594
+ var ColumnsWrapper = React.forwardRef(SectionColumnsWrapper);
6595
+
6596
+ // libs/settings/block.tsx
6597
+ init_esm_shims();
6598
+ init_cms();
6599
+ var defaultSettings2 = {
6600
+ display: {
6601
+ label: "Size",
6602
+ defaultValue: "block",
6603
+ options: [
6604
+ { label: "Full Width", value: "block" },
6605
+ { label: "Inline", value: "inline" }
6606
+ ]
6607
+ },
6608
+ align: {
6609
+ label: "Alignment",
6610
+ defaultValue: "left",
6611
+ options: [
6612
+ { label: /* @__PURE__ */ jsx(IconAlignLeft, { size: 20 }), value: "left" },
6613
+ { label: /* @__PURE__ */ jsx(IconAlignCenter, { size: 20 }), value: "center" },
6614
+ { label: /* @__PURE__ */ jsx(IconAlignRight, { size: 20 }), value: "right" }
6615
+ ]
6616
+ }
6617
+ };
6618
+ var customSettings = {
6619
+ [BLOCK_TYPES.IMAGE]: { ...defaultSettings2 },
6620
+ [BLOCK_TYPES.PARAGRAPH]: { ...defaultSettings2 },
6621
+ [BLOCK_TYPES.SUBTITLE]: { ...defaultSettings2 },
6622
+ [BLOCK_TYPES.SELECTOR]: { ...defaultSettings2 },
6623
+ [BLOCK_TYPES.STAT]: { ...defaultSettings2 },
6624
+ [BLOCK_TYPES.VIZ]: { ...defaultSettings2 },
6625
+ [BLOCK_TYPES.TITLE]: {
6626
+ order: {
6627
+ label: "Importance",
6628
+ defaultValue: "1",
6629
+ options: [
6630
+ { label: "1", value: "1" },
6631
+ { label: "2", value: "2" },
6632
+ { label: "3", value: "3" },
6633
+ { label: "4", value: "4" },
6634
+ { label: "5", value: "5" },
6635
+ { label: "6", value: "6" }
6636
+ ]
6637
+ },
6638
+ search: {
6639
+ label: "Search on Click",
6640
+ defaultValue: "off",
6641
+ options: [
6642
+ { label: "Off", value: "off" },
6643
+ { label: "Inline", value: "inline" },
6644
+ { label: "Modal", value: "modal" }
6645
+ ]
6646
+ },
6647
+ ...defaultSettings2
6648
+ },
6649
+ [BLOCK_TYPES.GENERATOR]: {
6650
+ useProxy: {
6651
+ label: "Use proxy (avoid CORS)",
6652
+ defaultValue: "false",
6653
+ options: [
6654
+ { label: "No", value: "false" },
6655
+ { label: "Yes", value: "true" }
6656
+ ]
6657
+ }
6658
+ },
6659
+ [BLOCK_TYPES.NAV]: {
6660
+ variant: {
6661
+ label: "Nav variant",
6662
+ defaultValue: "inline",
6663
+ options: [
6664
+ { label: "Inline", value: "inline" },
6665
+ { label: "Fixed", value: "fixed" },
6666
+ { label: "Jump", value: "jump" }
6667
+ ]
6668
+ },
6669
+ min: {
6670
+ label: "Min Title level",
6671
+ defaultValue: "1",
6672
+ options: [
6673
+ { label: "1", value: "1" },
6674
+ { label: "2", value: "2" },
6675
+ { label: "3", value: "3" },
6676
+ { label: "4", value: "4" },
6677
+ { label: "5", value: "5" },
6678
+ { label: "6", value: "6" }
6679
+ ]
6680
+ },
6681
+ max: {
6682
+ label: "Max Title level",
6683
+ defaultValue: "6",
6684
+ options: [
6685
+ { label: "1", value: "1" },
6686
+ { label: "2", value: "2" },
6687
+ { label: "3", value: "3" },
6688
+ { label: "4", value: "4" },
6689
+ { label: "5", value: "5" },
6690
+ { label: "6", value: "6" }
6691
+ ]
6692
+ }
6693
+ }
6694
+ };
6695
+ var getBlockSettings = (blockType) => {
6696
+ const extraSettings = blockType && customSettings[blockType] ? customSettings[blockType] : defaultSettings2;
6697
+ return extraSettings;
6698
+ };
6699
+
6700
+ // cms/components/components/DesignMenu.tsx
6701
+ init_esm_shims();
6702
+ init_store2();
6703
+ var ALLOWED_UNITS = ["px", "%"];
6704
+ var formatters = {
6705
+ px: (value) => !Number.isNaN(parseFloat(value)) ? `${value}px`.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",") : "px",
6706
+ ["%"]: (value) => !Number.isNaN(parseFloat(value)) ? `${value}%`.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",") : "%"
6707
+ };
6708
+ var WidthInputProps = {
6709
+ "px": {
6710
+ defaultValue: 400,
6711
+ min: 25,
6712
+ step: 5,
6713
+ formatter: formatters["px"]
6714
+ },
6715
+ "%": {
6716
+ defaultValue: 50,
6717
+ min: 20,
6718
+ max: 100,
6719
+ step: 5,
6720
+ formatter: formatters["%"]
6721
+ }
6722
+ };
6723
+ var defaultWidthSettings = { stretch: false, unit: "px", value: "400" };
6724
+ var UnitSelector = ({ currUnit, changeUnit }) => {
6725
+ return /* @__PURE__ */ jsxs(Group, { position: "apart", children: [
6726
+ /* @__PURE__ */ jsx(Text, { size: "xs", fw: "bold", children: "Unit" }),
6727
+ /* @__PURE__ */ jsx(Group, { spacing: 3, children: ALLOWED_UNITS.map(
6728
+ (unit) => /* @__PURE__ */ jsx(
6729
+ Anchor,
6730
+ {
6731
+ component: "button",
6732
+ size: "xs",
6733
+ td: currUnit === unit ? "underline" : "none",
6734
+ onClick: () => changeUnit(unit),
6735
+ children: unit
6736
+ },
6737
+ unit
6738
+ )
6739
+ ) })
6740
+ ] });
6741
+ };
6742
+ var getWidthSettings = (block) => {
6743
+ const widthSettings = block?.settings?.width || {};
6744
+ if (widthSettings && ["stretch", "value", "unit"].every((prop) => Object.prototype.hasOwnProperty.call(widthSettings, prop)))
6745
+ return widthSettings;
6746
+ return defaultWidthSettings;
6747
+ };
6748
+ function DesignMenu({ id, display = "button", handleChange }) {
6749
+ const dispatch = useAppDispatch();
6750
+ const block = useBlockRef(id).data;
6751
+ const [opened, setOpened] = useState(false);
6752
+ const width = getWidthSettings(block);
6753
+ const handleChangeWidth = (value) => {
6754
+ if (typeof value === "boolean") {
6755
+ const result = value ? { stretch: true } : defaultWidthSettings;
6756
+ handleChangeInternal("width", { ...width, ...result });
6757
+ } else {
6758
+ handleChangeInternal("width", { ...width, value });
6759
+ }
6760
+ };
6761
+ const handleChangeInternal = (field, value) => {
6762
+ if (block) {
6763
+ if (handleChange) {
6764
+ handleChange(field, value);
6765
+ } else {
6766
+ dispatch(actions_exports.updateEntity("block", {
6767
+ id,
6768
+ settings: { ...block.settings, [field]: value }
6769
+ }));
6770
+ }
6771
+ }
6772
+ };
6773
+ if (!block)
6774
+ return null;
6775
+ const defaultSettings3 = getBlockSettings(block.type);
6776
+ const widthInputProps = WidthInputProps[width.unit];
6777
+ const changeUnit = (newUnit) => {
6778
+ const { defaultValue } = WidthInputProps[newUnit];
6779
+ handleChangeInternal("width", {
6780
+ ...width,
6781
+ value: defaultValue,
6782
+ unit: newUnit
6783
+ });
6784
+ };
6785
+ const menu = /* @__PURE__ */ jsxs(Stack, { spacing: "xs", children: [
6786
+ Object.entries(defaultSettings3).map(([key, { label, defaultValue, options }]) => /* @__PURE__ */ jsxs(Group, { spacing: "xs", position: "apart", noWrap: true, style: { width: "100%" }, children: [
6787
+ label && /* @__PURE__ */ jsx(Text, { fz: "sm", children: label }),
6788
+ /* @__PURE__ */ jsx(
6789
+ SegmentedControl,
6790
+ {
6791
+ defaultValue: String(block.settings[key] || defaultValue),
6792
+ onChange: (e) => handleChangeInternal(key, e),
6793
+ data: options,
6794
+ size: "xs"
6795
+ }
6796
+ )
6797
+ ] }, key)),
6798
+ block.type !== "generator" && /* @__PURE__ */ jsxs(Group, { spacing: "xs", children: [
6799
+ /* @__PURE__ */ jsx(Text, { fz: "sm", children: "Width" }),
6800
+ /* @__PURE__ */ jsxs(Group, { spacing: "xs", children: [
6801
+ !width.stretch && /* @__PURE__ */ jsxs("div", { children: [
6802
+ /* @__PURE__ */ jsx(UnitSelector, { currUnit: width.unit, changeUnit }),
6803
+ /* @__PURE__ */ jsx(
6804
+ NumberInput,
6805
+ {
6806
+ defaultValue: parseInt(widthInputProps.defaultValue, 10),
6807
+ disabled: width.stretch,
6808
+ onChange: (value) => handleChangeWidth(value),
6809
+ size: "xs",
6810
+ value: !Number.isNaN(width.value) ? parseInt(width.value, 10) : void 0,
6811
+ ...widthInputProps
6812
+ }
6813
+ )
6814
+ ] }),
6815
+ /* @__PURE__ */ jsx(
6816
+ Checkbox,
6817
+ {
6818
+ size: "xs",
6819
+ label: "Stretch",
6820
+ checked: width.stretch,
6821
+ onChange: (e) => handleChangeWidth(e.currentTarget.checked)
6822
+ }
6823
+ )
6824
+ ] })
6825
+ ] }, "width")
6826
+ ] });
6827
+ return display === "button" ? /* @__PURE__ */ jsxs(
6828
+ Popover,
6829
+ {
6830
+ opened,
6831
+ onClose: () => setOpened(false),
6832
+ position: "bottom-end",
6833
+ withinPortal: true,
6834
+ children: [
6835
+ /* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx(
6836
+ ActionIcon,
6837
+ {
6838
+ onClick: () => setOpened((o) => !o),
6839
+ children: /* @__PURE__ */ jsx(IconPalette, { size: 20 })
6840
+ }
6841
+ ) }),
6842
+ /* @__PURE__ */ jsx(Popover.Dropdown, { children: menu })
6843
+ ]
6844
+ }
6845
+ ) : /* @__PURE__ */ jsx(Paper, { p: "md", withBorder: true, children: menu });
6846
+ }
6847
+ var DesignMenu_default = DesignMenu;
6848
+ var getStyles = (styles, settings) => (theme) => styles ? styles(theme, settings) : {};
6849
+ var PositionWrapper = ({ settings, styles, children, ...props }) => {
6850
+ const { position } = settings;
6851
+ const defaultStyles = {
6852
+ "normal": {
6853
+ position: "relative",
6854
+ backgroundColor: "transparent",
6855
+ borderRadius: 0
6856
+ },
6857
+ "sticky": {
6858
+ position: "sticky",
6859
+ zIndex: 3,
6860
+ top: 0,
6861
+ borderRadius: 0,
6862
+ borderTop: "none",
6863
+ borderLeft: "none",
6864
+ borderRight: "none"
6865
+ }
6866
+ };
6867
+ const defaultProps = {
6868
+ "normal": {
6869
+ radius: 0
6870
+ },
6871
+ "sticky": {
6872
+ radius: 0,
6873
+ withBorder: true
6874
+ }
6875
+ };
6876
+ const sx = [defaultStyles[position], getStyles(styles, settings)];
6877
+ return /* @__PURE__ */ jsx(Paper, { component: "section", sx, ...defaultProps[position], ...props, children });
6878
+ };
6879
+ var WidthWrapper = ({ settings, styles, children, ...props }) => {
6880
+ const { width: container } = settings;
6881
+ const defaultStyles = {
6882
+ "center": {},
6883
+ "full": {}
6884
+ };
6885
+ const defaultProps = {
6886
+ "center": { size: "lg", p: "sm", fluid: false },
6887
+ "full": { fluid: true, p: "md" }
6888
+ };
6889
+ const sx = [defaultStyles[container], getStyles(styles, settings)];
6890
+ return /* @__PURE__ */ jsx(Container, { sx, ...defaultProps[container], ...props, children });
6891
+ };
6892
+ var StyleWrapper = ({ settings, styles, children, ...props }) => {
6893
+ const { style: variant } = settings;
6894
+ const defaultStyles = {
6895
+ "none": {},
6896
+ "card": {}
6897
+ };
6898
+ const defaultProps = {
6899
+ "none": { bg: "transparent" },
6900
+ "card": { shadow: "lg", p: "md", radius: "md" }
6901
+ };
6902
+ const sx = [defaultStyles[variant], getStyles(styles, settings)];
6903
+ return /* @__PURE__ */ jsx(Paper, { sx, ...defaultProps[variant], ...props, children });
6904
+ };
6905
+ function Section({ section }) {
6906
+ const { id, settings } = section;
6907
+ const sectionSettings2 = {
6908
+ ...defaultSectionSettings,
6909
+ ...settings
6910
+ };
6911
+ const state = useAppSelector((state2) => state2);
6912
+ const status = useAppSelector((state2) => state2.variables.status);
6913
+ const sectionStyles = useBespokeStyles()["Section"];
6914
+ const blockRecords = selectBlockRecords(state);
6915
+ const sectionBlocks = Object.values(blockRecords || {}).filter((d) => d.section_id === id);
6916
+ const allowedSection = sectionBlocks.some((b) => {
6917
+ try {
6918
+ return status[b.id].allowed && b.type !== BLOCK_TYPES.GENERATOR || b.type === BLOCK_TYPES.NAV;
6919
+ } catch (e) {
6920
+ return b.settings.allowed === "always";
6921
+ }
6922
+ });
6923
+ const columns = sectionBlocks.reduce((acc, d) => {
6924
+ if (!acc[d.blockcol]) {
6925
+ acc[d.blockcol] = { [d.blockrow]: d };
6926
+ } else {
6927
+ acc[d.blockcol][d.blockrow] = d;
6928
+ }
6929
+ return acc;
6930
+ }, {});
6931
+ const blockSettings = getBlockSettings();
6932
+ const displaySection = Object.keys(blockRecords).length > 0 && !settings.hidden && allowedSection;
6933
+ const colsQty = Object.keys(columns).length;
6934
+ if (!displaySection)
6935
+ return null;
6936
+ return /* @__PURE__ */ jsxs(
6937
+ PositionWrapper,
6938
+ {
6939
+ settings: sectionSettings2,
6940
+ styles: sectionStyles?.root || void 0,
6941
+ children: [
6942
+ sectionSettings2.memberImageBg && /* @__PURE__ */ jsx(SectionBackground, {}),
6943
+ /* @__PURE__ */ jsxs(
6944
+ WidthWrapper,
6945
+ {
6946
+ settings: sectionSettings2,
6947
+ styles: sectionStyles?.container,
6948
+ id: `section-${id}`,
6949
+ pos: "relative",
6950
+ children: [
6951
+ /* @__PURE__ */ jsxs("div", { style: {
6952
+ position: "absolute",
6953
+ right: 10,
6954
+ top: 10,
6955
+ zIndex: 3
6956
+ }, children: [
6957
+ sectionSettings2.optionsMenu && /* @__PURE__ */ jsx(Options, { sectionId: section.id }),
6958
+ /* @__PURE__ */ jsx(SectionResetButton, { id: section.id })
6959
+ ] }),
6960
+ /* @__PURE__ */ jsx(StyleWrapper, { className: "bespoke-section-content", settings: sectionSettings2, styles: sectionStyles?.content, children: /* @__PURE__ */ jsx(ColumnsWrapper, { children: Object.keys(columns).sort((a, b) => orderSort(a, b, "blockcol")).map((columnIndex) => {
6961
+ const column = columns[columnIndex];
6962
+ const columnSettings = settings.columnSettings ? settings.columnSettings[columnIndex] : {};
6963
+ return /* @__PURE__ */ jsx(
6964
+ SectionColumn,
6965
+ {
6966
+ column,
6967
+ columnSettings,
6968
+ sx: { flexBasis: `${100 / colsQty}%` },
6969
+ children: Object.values(column).sort((a, b) => orderSort(a, b, "blockrow")).map((item) => {
6970
+ if (!item.id)
6971
+ return null;
6972
+ const { settings: settings2, type } = blockRecords[item.id];
6973
+ const blockWidth = settings2.width && !settings2.width.stretch && settings2.width.unit ? formatters[settings2.width.unit](settings2.width.value) : settings2.display === "inline" ? "auto" : "100%";
6974
+ const blockStyles = {
6975
+ alignSelf: type === "visualization" ? "stretch" : "flex-start",
6976
+ flexGrow: 0,
6977
+ margin: "0",
6978
+ textAlign: settings2.align || blockSettings.align.defaultValue,
6979
+ width: blockWidth,
6980
+ minWidth: 300
6981
+ };
6982
+ return /* @__PURE__ */ jsx(Box, { sx: blockStyles, py: site_default.block.padding, children: /* @__PURE__ */ jsx(Block, { blockId: item.id }, item.id) }, item.id);
6983
+ })
6984
+ },
6985
+ columnIndex
6986
+ );
6987
+ }) }) })
6988
+ ]
6989
+ }
6990
+ )
6991
+ ]
6992
+ }
6993
+ );
6994
+ }
6995
+ var Section_default = Section;
6996
+ function Report() {
6997
+ const sectionList = useSectionList();
6998
+ return /* @__PURE__ */ jsx(Container, { p: 0, pos: "relative", fluid: true, children: sectionList.isSuccess && sectionList.data.sort(orderSort).map((section) => /* @__PURE__ */ jsx(Section_default, { section }, section.id)) });
6999
+ }
7000
+ var Report_default = Report;
7001
+
7002
+ // frontend/components/auth/LoginButton.tsx
7003
+ init_esm_shims();
7004
+
7005
+ // types/auth.ts
7006
+ init_esm_shims();
7007
+ var CMS_ROLES = {
7008
+ ADMIN: "Admin",
7009
+ EDITOR: "Editor",
7010
+ WRITER: "Writer"
7011
+ };
7012
+ function BespokeLoginBtn({
7013
+ buttonProps = {},
7014
+ editorMenuItemProps = {},
7015
+ editorMenuItemRoute = "/cms",
6418
7016
  logoutButtonProps = {},
6419
7017
  menuProps = {},
6420
7018
  options = "",
@@ -8075,278 +8673,76 @@ function CMSHeader(props) {
8075
8673
  variant: "outline",
8076
8674
  onClick: handlers.open,
8077
8675
  children: "Import Data"
8078
- }
8079
- )
8080
- ] })
8081
- ] }),
8082
- right: /* @__PURE__ */ jsxs(Group, { spacing: "xs", children: [
8083
- /* @__PURE__ */ jsxs(Menu, { shadow: "md", children: [
8084
- /* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(ActionIcon, { color: "blue", variant: "filled", children: /* @__PURE__ */ jsx(IconSettings, { size: 20 }) }) }),
8085
- /* @__PURE__ */ jsxs(Menu.Dropdown, { children: [
8086
- /* @__PURE__ */ jsx(Menu.Label, { children: "Revalidate" }),
8087
- /* @__PURE__ */ jsx(Menu.Item, { onClick: maybeRevalidateUrl, icon: /* @__PURE__ */ jsx(IconFileOff, { size: 20 }), children: /* @__PURE__ */ jsxs(Text, { children: [
8088
- "Revalidate ",
8089
- /* @__PURE__ */ jsx(Text, { fw: 700, children: previewName })
8090
- ] }) }),
8091
- /* @__PURE__ */ jsx(Menu.Item, { onClick: maybeRevalidateReport, icon: /* @__PURE__ */ jsx(IconFilesOff, { size: 20 }), children: /* @__PURE__ */ jsxs(Text, { children: [
8092
- "Revalidate ALL ",
8093
- /* @__PURE__ */ jsx(Text, { fw: 700, children: currentReport.name })
8094
- ] }) }),
8095
- /* @__PURE__ */ jsx(Menu.Label, { children: "Settings" }),
8096
- /* @__PURE__ */ jsx(Menu.Item, { onClick: handlers.open, icon: /* @__PURE__ */ jsx(IconSettings, { size: 20 }), children: "Report settings" }),
8097
- /* @__PURE__ */ jsx(Menu.Item, { onClick: handlersGraph.open, icon: /* @__PURE__ */ jsx(IconHierarchy3, { size: 20 }), children: "Block Graph" })
8098
- ] })
8099
- ] }),
8100
- /* @__PURE__ */ jsx(Modal, { opened: openedGraph, onClose: handlersGraph.close, title: "Block Graph", fullScreen: true, children: /* @__PURE__ */ jsx(BlockGraph, {}) }),
8101
- /* @__PURE__ */ jsx(
8102
- Drawer,
8103
- {
8104
- opened,
8105
- onClose: handlers.close,
8106
- title: /* @__PURE__ */ jsx(IconTitle, { icon: /* @__PURE__ */ jsx(IconFileAnalytics, { size: 24 }), children: `Editing Report: ${currentReport ? currentReport.name : ""}` }),
8107
- size: "50%",
8108
- padding: "xl",
8109
- position: "right",
8110
- children: /* @__PURE__ */ jsx(ReportEditor, { id, onClose: handlers.close })
8111
- }
8112
- )
8113
- ] })
8114
- }
8115
- );
8116
- }
8117
- var selectLocaleOptions = (state) => state.status.locales.map((d) => ({ value: d, label: d.toUpperCase() }));
8118
-
8119
- // components/sections/Section.tsx
8120
- init_esm_shims();
8121
-
8122
- // components/blocks/BlockElement.tsx
8123
- init_esm_shims();
8124
-
8125
- // cms/components/components/DeleteButton.tsx
8126
- init_esm_shims();
8127
- init_store2();
8128
- init_cms();
8129
- function DeleteButton({ type, id, warning = "" }) {
8130
- const PRETTY_NAME = ENTITY_PRETTY_NAMES[type] || "Entity";
8131
- const message = warning || `Delete this ${PRETTY_NAME} and all its contents? This action cannot be undone.`;
8132
- const dispatch = useDispatch();
8133
- const { newConfirmation } = useDialog();
8134
- const maybeDelete = async () => {
8135
- try {
8136
- await newConfirmation({
8137
- title: "Are you sure?",
8138
- message,
8139
- confirmText: "Yes, Delete it."
8140
- });
8141
- dispatch(actions_exports.deleteEntity(type, id));
8142
- } catch {
8143
- }
8144
- };
8145
- return /* @__PURE__ */ jsx(ActionIcon, { color: "red", onClick: maybeDelete, children: /* @__PURE__ */ jsx(IconTrash, { size: 20 }) });
8146
- }
8147
- var DeleteButton_default = DeleteButton;
8148
-
8149
- // cms/components/components/DesignMenu.tsx
8150
- init_esm_shims();
8151
-
8152
- // libs/settings/block.tsx
8153
- init_esm_shims();
8154
- init_cms();
8155
- var defaultSettings2 = {
8156
- display: {
8157
- label: "Size",
8158
- defaultValue: "block",
8159
- options: [
8160
- { label: "Full Width", value: "block" },
8161
- { label: "Inline", value: "inline" }
8162
- ]
8163
- },
8164
- align: {
8165
- label: "Alignment",
8166
- defaultValue: "left",
8167
- options: [
8168
- { label: /* @__PURE__ */ jsx(IconAlignLeft, { size: 20 }), value: "left" },
8169
- { label: /* @__PURE__ */ jsx(IconAlignCenter, { size: 20 }), value: "center" },
8170
- { label: /* @__PURE__ */ jsx(IconAlignRight, { size: 20 }), value: "right" }
8171
- ]
8172
- }
8173
- };
8174
- var customSettings = {
8175
- [BLOCK_TYPES.IMAGE]: { ...defaultSettings2 },
8176
- [BLOCK_TYPES.PARAGRAPH]: { ...defaultSettings2 },
8177
- [BLOCK_TYPES.SUBTITLE]: { ...defaultSettings2 },
8178
- [BLOCK_TYPES.SELECTOR]: { ...defaultSettings2 },
8179
- [BLOCK_TYPES.STAT]: { ...defaultSettings2 },
8180
- [BLOCK_TYPES.VIZ]: { ...defaultSettings2 },
8181
- [BLOCK_TYPES.TITLE]: {
8182
- order: {
8183
- label: "Importance",
8184
- defaultValue: "1",
8185
- options: [
8186
- { label: "1", value: "1" },
8187
- { label: "2", value: "2" },
8188
- { label: "3", value: "3" },
8189
- { label: "4", value: "4" },
8190
- { label: "5", value: "5" },
8191
- { label: "6", value: "6" }
8192
- ]
8193
- },
8194
- search: {
8195
- label: "Search on Click",
8196
- defaultValue: "off",
8197
- options: [
8198
- { label: "Off", value: "off" },
8199
- { label: "Inline", value: "inline" },
8200
- { label: "Modal", value: "modal" }
8201
- ]
8202
- },
8203
- ...defaultSettings2
8204
- },
8205
- [BLOCK_TYPES.GENERATOR]: {
8206
- useProxy: {
8207
- label: "Use proxy (avoid CORS)",
8208
- defaultValue: "false",
8209
- options: [
8210
- { label: "No", value: "false" },
8211
- { label: "Yes", value: "true" }
8212
- ]
8213
- }
8214
- },
8215
- [BLOCK_TYPES.NAV]: {
8216
- variant: {
8217
- label: "Nav variant",
8218
- defaultValue: "inline",
8219
- options: [
8220
- { label: "Inline", value: "inline" },
8221
- { label: "Fixed", value: "fixed" },
8222
- { label: "Jump", value: "jump" }
8223
- ]
8224
- },
8225
- min: {
8226
- label: "Min Title level",
8227
- defaultValue: "1",
8228
- options: [
8229
- { label: "1", value: "1" },
8230
- { label: "2", value: "2" },
8231
- { label: "3", value: "3" },
8232
- { label: "4", value: "4" },
8233
- { label: "5", value: "5" },
8234
- { label: "6", value: "6" }
8235
- ]
8236
- },
8237
- max: {
8238
- label: "Max Title level",
8239
- defaultValue: "6",
8240
- options: [
8241
- { label: "1", value: "1" },
8242
- { label: "2", value: "2" },
8243
- { label: "3", value: "3" },
8244
- { label: "4", value: "4" },
8245
- { label: "5", value: "5" },
8246
- { label: "6", value: "6" }
8247
- ]
8248
- }
8249
- }
8250
- };
8251
- var getBlockSettings = (blockType) => {
8252
- const extraSettings = blockType && customSettings[blockType] ? customSettings[blockType] : defaultSettings2;
8253
- return extraSettings;
8254
- };
8255
-
8256
- // cms/components/components/DesignMenu.tsx
8257
- init_store2();
8258
- function DesignMenu({ id, display = "button", handleChange }) {
8259
- const dispatch = useAppDispatch();
8260
- const block = useBlockRef(id).data;
8261
- const [opened, setOpened] = useState(false);
8262
- const defaultWidth = "400";
8263
- const handleChangeWidth = (value) => {
8264
- let result;
8265
- if (typeof value === "boolean") {
8266
- result = value ? "stretch" : String(defaultWidth);
8267
- } else {
8268
- result = value;
8269
- }
8270
- handleChangeInternal("width", result);
8271
- };
8272
- const handleChangeInternal = (field, value) => {
8273
- if (block) {
8274
- if (handleChange) {
8275
- handleChange(field, value);
8276
- } else {
8277
- dispatch(actions_exports.updateEntity("block", {
8278
- id,
8279
- settings: { ...block.settings, [field]: value }
8280
- }));
8281
- }
8282
- }
8283
- };
8284
- if (!block)
8285
- return null;
8286
- const defaultSettings3 = getBlockSettings(block.type);
8287
- const width = block.settings?.width ?? "stretch";
8288
- const menu = /* @__PURE__ */ jsxs(Stack, { spacing: "xs", children: [
8289
- Object.entries(defaultSettings3).map(([key, { label, defaultValue, options }]) => /* @__PURE__ */ jsxs(Group, { spacing: "xs", position: "apart", noWrap: true, style: { width: "100%" }, children: [
8290
- label && /* @__PURE__ */ jsx(Text, { fz: "sm", children: label }),
8291
- /* @__PURE__ */ jsx(
8292
- SegmentedControl,
8293
- {
8294
- defaultValue: String(block.settings[key] || defaultValue),
8295
- onChange: (e) => handleChangeInternal(key, e),
8296
- data: options,
8297
- size: "xs"
8298
- }
8299
- )
8300
- ] }, key)),
8301
- block.type !== "generator" && /* @__PURE__ */ jsxs(Group, { spacing: "xs", children: [
8302
- /* @__PURE__ */ jsx(Text, { fz: "sm", children: "Width" }),
8303
- /* @__PURE__ */ jsxs(Group, { spacing: "xs", children: [
8304
- width !== "stretch" && /* @__PURE__ */ jsx(
8305
- NumberInput,
8306
- {
8307
- defaultValue: parseInt(defaultWidth, 10),
8308
- disabled: width === "stretch",
8309
- min: 25,
8310
- onChange: (value) => handleChangeWidth(value),
8311
- placeholder: width === "stretch" ? defaultWidth : width,
8312
- step: 5,
8313
- style: { width: 80 },
8314
- value: !Number.isNaN(width) ? parseInt(width, 10) : void 0
8315
- }
8316
- ),
8676
+ }
8677
+ )
8678
+ ] })
8679
+ ] }),
8680
+ right: /* @__PURE__ */ jsxs(Group, { spacing: "xs", children: [
8681
+ /* @__PURE__ */ jsxs(Menu, { shadow: "md", children: [
8682
+ /* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(ActionIcon, { color: "blue", variant: "filled", children: /* @__PURE__ */ jsx(IconSettings, { size: 20 }) }) }),
8683
+ /* @__PURE__ */ jsxs(Menu.Dropdown, { children: [
8684
+ /* @__PURE__ */ jsx(Menu.Label, { children: "Revalidate" }),
8685
+ /* @__PURE__ */ jsx(Menu.Item, { onClick: maybeRevalidateUrl, icon: /* @__PURE__ */ jsx(IconFileOff, { size: 20 }), children: /* @__PURE__ */ jsxs(Text, { children: [
8686
+ "Revalidate ",
8687
+ /* @__PURE__ */ jsx(Text, { fw: 700, children: previewName })
8688
+ ] }) }),
8689
+ /* @__PURE__ */ jsx(Menu.Item, { onClick: maybeRevalidateReport, icon: /* @__PURE__ */ jsx(IconFilesOff, { size: 20 }), children: /* @__PURE__ */ jsxs(Text, { children: [
8690
+ "Revalidate ALL ",
8691
+ /* @__PURE__ */ jsx(Text, { fw: 700, children: currentReport.name })
8692
+ ] }) }),
8693
+ /* @__PURE__ */ jsx(Menu.Label, { children: "Settings" }),
8694
+ /* @__PURE__ */ jsx(Menu.Item, { onClick: handlers.open, icon: /* @__PURE__ */ jsx(IconSettings, { size: 20 }), children: "Report settings" }),
8695
+ /* @__PURE__ */ jsx(Menu.Item, { onClick: handlersGraph.open, icon: /* @__PURE__ */ jsx(IconHierarchy3, { size: 20 }), children: "Block Graph" })
8696
+ ] })
8697
+ ] }),
8698
+ /* @__PURE__ */ jsx(Modal, { opened: openedGraph, onClose: handlersGraph.close, title: "Block Graph", fullScreen: true, children: /* @__PURE__ */ jsx(BlockGraph, {}) }),
8317
8699
  /* @__PURE__ */ jsx(
8318
- Checkbox,
8700
+ Drawer,
8319
8701
  {
8320
- size: "xs",
8321
- label: "Stretch",
8322
- checked: width === "stretch",
8323
- onChange: (e) => handleChangeWidth(e.currentTarget.checked)
8702
+ opened,
8703
+ onClose: handlers.close,
8704
+ title: /* @__PURE__ */ jsx(IconTitle, { icon: /* @__PURE__ */ jsx(IconFileAnalytics, { size: 24 }), children: `Editing Report: ${currentReport ? currentReport.name : ""}` }),
8705
+ size: "50%",
8706
+ padding: "xl",
8707
+ position: "right",
8708
+ children: /* @__PURE__ */ jsx(ReportEditor, { id, onClose: handlers.close })
8324
8709
  }
8325
8710
  )
8326
8711
  ] })
8327
- ] }, "width")
8328
- ] });
8329
- return display === "button" ? /* @__PURE__ */ jsxs(
8330
- Popover,
8331
- {
8332
- opened,
8333
- onClose: () => setOpened(false),
8334
- position: "bottom-end",
8335
- withinPortal: true,
8336
- children: [
8337
- /* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx(
8338
- ActionIcon,
8339
- {
8340
- onClick: () => setOpened((o) => !o),
8341
- children: /* @__PURE__ */ jsx(IconPalette, { size: 20 })
8342
- }
8343
- ) }),
8344
- /* @__PURE__ */ jsx(Popover.Dropdown, { children: menu })
8345
- ]
8346
8712
  }
8347
- ) : /* @__PURE__ */ jsx(Paper, { p: "md", withBorder: true, children: menu });
8713
+ );
8348
8714
  }
8349
- var DesignMenu_default = DesignMenu;
8715
+ var selectLocaleOptions = (state) => state.status.locales.map((d) => ({ value: d, label: d.toUpperCase() }));
8716
+
8717
+ // components/sections/Section.tsx
8718
+ init_esm_shims();
8719
+
8720
+ // components/blocks/BlockElement.tsx
8721
+ init_esm_shims();
8722
+
8723
+ // cms/components/components/DeleteButton.tsx
8724
+ init_esm_shims();
8725
+ init_store2();
8726
+ init_cms();
8727
+ function DeleteButton({ type, id, warning = "" }) {
8728
+ const PRETTY_NAME = ENTITY_PRETTY_NAMES[type] || "Entity";
8729
+ const message = warning || `Delete this ${PRETTY_NAME} and all its contents? This action cannot be undone.`;
8730
+ const dispatch = useDispatch();
8731
+ const { newConfirmation } = useDialog();
8732
+ const maybeDelete = async () => {
8733
+ try {
8734
+ await newConfirmation({
8735
+ title: "Are you sure?",
8736
+ message,
8737
+ confirmText: "Yes, Delete it."
8738
+ });
8739
+ dispatch(actions_exports.deleteEntity(type, id));
8740
+ } catch {
8741
+ }
8742
+ };
8743
+ return /* @__PURE__ */ jsx(ActionIcon, { color: "red", onClick: maybeDelete, children: /* @__PURE__ */ jsx(IconTrash, { size: 20 }) });
8744
+ }
8745
+ var DeleteButton_default = DeleteButton;
8350
8746
 
8351
8747
  // components/blocks/Block.tsx
8352
8748
  init_esm_shims();
@@ -8603,9 +8999,9 @@ function BlockPreview(props) {
8603
8999
  return /* @__PURE__ */ jsxs(
8604
9000
  "div",
8605
9001
  {
8606
- id: `${block.type}-${block.id}`,
8607
- className: "cms-block-preview",
8608
- style: { width: "100%", minHeight: block.type === BLOCK_TYPES.VIZ ? 300 : "auto" },
9002
+ id: `bespoke-${block.type}-${block.id}`,
9003
+ className: "cms-block-preview bespoke-block-area",
9004
+ style: { width: "100%", minHeight: block.type === BLOCK_TYPES.VIZ ? 400 : "auto" },
8609
9005
  children: [
8610
9006
  !allowed && allowedOverlay,
8611
9007
  Renderer ? /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx(Renderer, { id: block.id, debug, ...content, settings: block.settings }) }, "renderer") : /* @__PURE__ */ jsx(Center, { style: { minHeight: 100 }, children: /* @__PURE__ */ jsx(Badge, { color: "gray", variant: "outline", children: block.type }, "type") }),
@@ -9239,6 +9635,7 @@ function BlockEditor({
9239
9635
  executeButton
9240
9636
  }
9241
9637
  );
9638
+ const isVizOrGenerator = [BLOCK_TYPES.GENERATOR, BLOCK_TYPES.VIZ].includes(blockType);
9242
9639
  return /* @__PURE__ */ jsxs(Grid, { children: [
9243
9640
  /* @__PURE__ */ jsxs(
9244
9641
  Col,
@@ -9290,7 +9687,7 @@ function BlockEditor({
9290
9687
  height: "100%"
9291
9688
  },
9292
9689
  children: [
9293
- ![BLOCK_TYPES.GENERATOR, BLOCK_TYPES.VIZ].includes(blockType) && /* @__PURE__ */ jsxs(Alert, { icon: /* @__PURE__ */ jsx(IconFlag, {}), children: [
9690
+ isVizOrGenerator && /* @__PURE__ */ jsxs(Alert, { icon: /* @__PURE__ */ jsx(IconFlag, {}), children: [
9294
9691
  "You are editing the ",
9295
9692
  /* @__PURE__ */ jsx(Code, { children: locale.toUpperCase() }),
9296
9693
  " version of the block."
@@ -9339,7 +9736,12 @@ function BlockEditor({
9339
9736
  ] }),
9340
9737
  "and ",
9341
9738
  /* @__PURE__ */ jsx(Code, { children: "router" }),
9342
- " in the scope of this generator."
9739
+ " in the scope of this generator.",
9740
+ isVizOrGenerator && /* @__PURE__ */ jsxs(Fragment, { children: [
9741
+ " Return a property called",
9742
+ /* @__PURE__ */ jsx(Code, { children: "_api" }),
9743
+ " as string, to let the user download that data and override api value."
9744
+ ] })
9343
9745
  ] }),
9344
9746
  codeEditor,
9345
9747
  /* @__PURE__ */ jsx(Divider, { my: "sm", color: "gray.8" }),
@@ -9615,27 +10017,6 @@ var Block_default = Block2;
9615
10017
 
9616
10018
  // components/blocks/BlockElement.tsx
9617
10019
  init_store2();
9618
-
9619
- // libs/settings/site.ts
9620
- init_esm_shims();
9621
- var site_default = {
9622
- backgroundColor: "#fafafa",
9623
- block: {
9624
- padding: 10
9625
- },
9626
- column: {
9627
- padding: 12
9628
- },
9629
- section: {
9630
- backgroundColor: "white",
9631
- borderRadius: 10,
9632
- boxShadow: "0px 6px 10px rgba(12, 32, 50, 0.14), 0px 1px 15px rgba(12, 32, 50, 0.12), 0px 3px 5px rgba(12, 32, 50, 0.15)",
9633
- margin: 16,
9634
- padding: 32
9635
- }
9636
- };
9637
-
9638
- // components/blocks/BlockElement.tsx
9639
10020
  init_cms();
9640
10021
  init_hooks();
9641
10022
  function BlockElement({
@@ -9643,12 +10024,12 @@ function BlockElement({
9643
10024
  setHoverBlock,
9644
10025
  isInput,
9645
10026
  isConsumer,
9646
- active,
9647
- sectionState
10027
+ active
9648
10028
  }) {
9649
10029
  const currentLocale = useAppSelector((state) => state.status.currentLocale);
9650
10030
  const block = useBlockRef(id).data;
9651
10031
  const blockStatus = useBlockStatus(id);
10032
+ const [showOptions, setShowOptions] = useState(false);
9652
10033
  const { newConfirmation } = useDialog();
9653
10034
  const [opened, setOpened] = useState(false);
9654
10035
  const [modified, setModified] = useState(false);
@@ -9706,12 +10087,29 @@ function BlockElement({
9706
10087
  Group,
9707
10088
  {
9708
10089
  id: `cms-block-${id}`,
10090
+ onMouseOver: () => setShowOptions(true),
10091
+ onMouseOut: () => setShowOptions(false),
9709
10092
  className: "cr-section-block",
10093
+ pos: "relative",
10094
+ py: site_default.block.padding,
9710
10095
  ...hoverActions,
9711
- style: {
9712
- padding: site_default.block.padding,
9713
- position: "relative"
9714
- },
10096
+ sx: (theme2) => ({
10097
+ border: "1px solid transparent",
10098
+ resize: "horizontal",
10099
+ "&:hover": {
10100
+ border: `1px solid ${theme2.colors.blue[2]}`
10101
+ },
10102
+ "&:hover::before": {
10103
+ position: "absolute",
10104
+ top: 0,
10105
+ left: 0,
10106
+ fontSize: 8,
10107
+ color: theme2.colors.blue[5],
10108
+ transform: "translateY(-100%)",
10109
+ content: `"Block ${id}"`,
10110
+ width: "fit-content"
10111
+ }
10112
+ }),
9715
10113
  children: [
9716
10114
  /* @__PURE__ */ jsx(
9717
10115
  BlockPreview_default,
@@ -9725,7 +10123,7 @@ function BlockElement({
9725
10123
  },
9726
10124
  "bp"
9727
10125
  ),
9728
- /* @__PURE__ */ jsxs(
10126
+ (showOptions || isInput || isConsumer) && /* @__PURE__ */ jsxs(
9729
10127
  Group,
9730
10128
  {
9731
10129
  spacing: 0,
@@ -9779,7 +10177,8 @@ function SectionHeader({
9779
10177
  isDragging,
9780
10178
  id,
9781
10179
  dragHandleProps,
9782
- hidden
10180
+ hidden,
10181
+ generators
9783
10182
  }) {
9784
10183
  return /* @__PURE__ */ jsxs(
9785
10184
  Group,
@@ -9793,7 +10192,17 @@ function SectionHeader({
9793
10192
  "#",
9794
10193
  id || "hello"
9795
10194
  ] }, "s1"),
9796
- /* @__PURE__ */ jsx(ActionIcon, { ...dragHandleProps, children: /* @__PURE__ */ jsx(IconMenu, { size: 16 }) }, "b1")
10195
+ /* @__PURE__ */ jsx(ActionIcon, { ...dragHandleProps, children: /* @__PURE__ */ jsx(IconMenu, { size: 16 }) }, "b1"),
10196
+ /* @__PURE__ */ jsx(
10197
+ Switch,
10198
+ {
10199
+ size: "xs",
10200
+ label: "Show generators",
10201
+ color: "green",
10202
+ checked: generators.showGenerators,
10203
+ onChange: (e) => generators.setShowGenerators(e.currentTarget.checked)
10204
+ }
10205
+ )
9797
10206
  ] }),
9798
10207
  hidden && /* @__PURE__ */ jsx(Text, { size: "xs", fw: 600, color: "dark.3", children: "Section will be hidden on the frontend" }),
9799
10208
  /* @__PURE__ */ jsx(SectionMenu_default, { sectionId: id })
@@ -9805,28 +10214,8 @@ function SectionHeader({
9805
10214
  // components/sections/Section.tsx
9806
10215
  init_cms();
9807
10216
  var blockTypes = Object.values(BLOCK_TYPES);
9808
- function SectionEditor({
9809
- for: section,
9810
- isDragging,
9811
- isActive,
9812
- onActivate,
9813
- dragHandleProps
9814
- }) {
10217
+ var CreateBlockButton = ({ columns, columnIndex, section }) => {
9815
10218
  const dispatch = useAppDispatch();
9816
- const [columns, setColumns] = useState({});
9817
- const [sectionState, setSectionState2] = useSetState({});
9818
- const blocks = useAppSelector((state) => state.records.entities.block);
9819
- const blockSettings = getBlockSettings();
9820
- const { memberImageBg, optionsMenu, hidden } = section.settings;
9821
- const [hoverBlock, setHoverBlock] = useState();
9822
- const { inputs, consumers } = useMemo(() => {
9823
- if (hoverBlock) {
9824
- const block = blocks[hoverBlock];
9825
- const { inputs: inputs2, consumers: consumers2 } = block;
9826
- return { inputs: inputs2, consumers: consumers2 };
9827
- }
9828
- return { inputs: [], consumers: [] };
9829
- }, [hoverBlock]);
9830
10219
  const addBlock = (type, targetColumn = false) => {
9831
10220
  let blockrow = FIRST_POSITION;
9832
10221
  let blockcol = FIRST_POSITION;
@@ -9845,29 +10234,130 @@ function SectionEditor({
9845
10234
  locales: locales4
9846
10235
  }));
9847
10236
  };
9848
- useEffect(() => {
9849
- const columns2 = Object.values(blocks || {}).filter((d) => d.section_id === section.id).reduce((acc, d) => {
9850
- if (!acc[d.blockcol]) {
9851
- acc[d.blockcol] = { [d.blockrow]: d };
9852
- } else {
9853
- acc[d.blockcol][d.blockrow] = d;
10237
+ return /* @__PURE__ */ jsx(Center, { w: "100%", py: "sm", children: /* @__PURE__ */ jsx(
10238
+ EntityCreateButton,
10239
+ {
10240
+ fields: [{
10241
+ type: "select",
10242
+ name: "type",
10243
+ label: "Block Type",
10244
+ options: blockTypes.map((d) => ({ label: d, value: d }))
10245
+ }],
10246
+ onSubmit: (value) => addBlock(value.type, columnIndex),
10247
+ target: /* @__PURE__ */ jsx(ActionIcon, { size: "md", radius: "lg", children: /* @__PURE__ */ jsx(IconCirclePlus, { size: 20 }) })
10248
+ }
10249
+ ) });
10250
+ };
10251
+ var FirstBlockButton = ({ columns, section, show = false }) => {
10252
+ if (!show)
10253
+ return null;
10254
+ return /* @__PURE__ */ jsx(Center, { w: "100%", children: /* @__PURE__ */ jsxs("div", { children: [
10255
+ /* @__PURE__ */ jsx(Text, { ta: "center", fw: 700, size: "sm", color: "gray.8", children: "Add your first block!" }),
10256
+ /* @__PURE__ */ jsx(CreateBlockButton, { columnIndex: false, columns, section })
10257
+ ] }) });
10258
+ };
10259
+ var CreateColumnArea = ({ active = false }) => {
10260
+ return /* @__PURE__ */ jsx(Droppable, { droppableId: "newColumn", children: (provided) => /* @__PURE__ */ jsx(
10261
+ Center,
10262
+ {
10263
+ ref: provided.innerRef,
10264
+ pos: "absolute",
10265
+ top: 16,
10266
+ right: 0,
10267
+ bottom: 16,
10268
+ w: active ? 140 : 0,
10269
+ sx: (theme) => ({
10270
+ boxSizing: "border-box",
10271
+ background: theme.colors.gray[0],
10272
+ transition: "width 0.4s",
10273
+ overflow: "hidden",
10274
+ "&:hover": {
10275
+ background: theme.colors.blue[0]
10276
+ }
10277
+ }),
10278
+ children: /* @__PURE__ */ jsxs(Stack, { p: "md", align: "center", children: [
10279
+ /* @__PURE__ */ jsx(Text, { size: "xs", ta: "center", children: "Drop here to add new column" }),
10280
+ /* @__PURE__ */ jsx(IconPlus, {})
10281
+ ] })
10282
+ }
10283
+ ) });
10284
+ };
10285
+ var ClickToEditOverlay = ({ onActivate, section, show = false }) => {
10286
+ if (!show)
10287
+ return null;
10288
+ return /* @__PURE__ */ jsx(
10289
+ Overlay,
10290
+ {
10291
+ className: "cms-section-overlay",
10292
+ onClick: () => onActivate(section.id),
10293
+ opacity: 0.4,
10294
+ style: { cursor: "pointer", zIndex: 3 },
10295
+ center: true,
10296
+ children: /* @__PURE__ */ jsx(Badge, { size: "xl", color: "blue", children: "Click to Edit" })
10297
+ }
10298
+ );
10299
+ };
10300
+ var GeneratorsPanel = ({ generators, show = false }) => {
10301
+ return /* @__PURE__ */ jsxs(Collapse, { in: show, p: "sm", children: [
10302
+ /* @__PURE__ */ jsx(Title, { order: 5, align: "center", children: "Generators" }),
10303
+ /* @__PURE__ */ jsx(
10304
+ SimpleGrid,
10305
+ {
10306
+ cols: generators.length > 3 ? 3 : generators.length,
10307
+ breakpoints: [
10308
+ { maxWidth: "md", cols: 3, spacing: "md" },
10309
+ { maxWidth: "sm", cols: 2, spacing: "sm" },
10310
+ { maxWidth: "xs", cols: 1, spacing: "sm" }
10311
+ ],
10312
+ children: generators
9854
10313
  }
9855
- return acc;
9856
- }, {});
9857
- setColumns(columns2);
9858
- }, [blocks]);
10314
+ )
10315
+ ] });
10316
+ };
10317
+ function SectionEditor({
10318
+ for: section,
10319
+ isDragging,
10320
+ isActive,
10321
+ onActivate,
10322
+ dragHandleProps
10323
+ }) {
10324
+ const dispatch = useAppDispatch();
10325
+ const [showGenerators, setShowGenerators] = useState(false);
10326
+ const [draggingBlock, setDraggingBlock] = useState(false);
10327
+ const [hoverBlock, setHoverBlock] = useState();
10328
+ const columnContainer = useRef(null);
10329
+ const blocks = useAppSelector((state) => state.records.entities.block);
10330
+ const blockSettings = getBlockSettings();
10331
+ const { memberImageBg, optionsMenu, hidden, columnSettings = {} } = section.settings;
10332
+ const { inputs, consumers } = useMemo(() => {
10333
+ if (hoverBlock) {
10334
+ const block = blocks[hoverBlock];
10335
+ const { inputs: inputs2, consumers: consumers2 } = block;
10336
+ return { inputs: inputs2, consumers: consumers2 };
10337
+ }
10338
+ return { inputs: [], consumers: [] };
10339
+ }, [hoverBlock]);
10340
+ const columns = Object.values(blocks || {}).filter((d) => d.section_id === section.id && d.type !== BLOCK_TYPES.GENERATOR).reduce((acc, d) => {
10341
+ if (!acc[d.blockcol]) {
10342
+ acc[d.blockcol] = { [d.blockrow]: d };
10343
+ } else {
10344
+ acc[d.blockcol][d.blockrow] = d;
10345
+ }
10346
+ return acc;
10347
+ }, {});
9859
10348
  const theme = useMantineTheme();
9860
- const smallScreen = useMediaQuery(`(max-width: ${theme.breakpoints.sm}px)`);
10349
+ const onDragStart = () => setDraggingBlock(true);
9861
10350
  const onDragEnd = (result) => {
10351
+ setDraggingBlock(false);
9862
10352
  if (!result.destination)
9863
10353
  return;
9864
10354
  const { source, destination } = result;
9865
10355
  if (source.droppableId === destination.droppableId && source.index === destination.index)
9866
10356
  return;
10357
+ const newColumn = destination.droppableId === "newColumn";
9867
10358
  const blockId = Number(result.draggableId);
9868
10359
  const sourceColumnIndex = source.droppableId;
9869
- const destinationColumnIndex = destination.droppableId;
9870
- const sourceRowIndex = blocks[blockId].blockrow;
10360
+ const destinationColumnIndex = newColumn ? findMaxOrdering(Object.keys(columns), true) : destination.droppableId;
9871
10361
  const payload = {
9872
10362
  id: blockId,
9873
10363
  blockrow: FIRST_POSITION,
@@ -9875,7 +10365,7 @@ function SectionEditor({
9875
10365
  };
9876
10366
  const changedColumn = sourceColumnIndex !== destinationColumnIndex;
9877
10367
  payload.blockcol = changedColumn ? destinationColumnIndex : sourceColumnIndex;
9878
- const rowItems = Object.values(columns[payload.blockcol]);
10368
+ const rowItems = Object.values(columns[payload.blockcol] || {});
9879
10369
  const entities = rowItems.reduce((acc, d) => ({ ...acc, [d.id]: d }), {});
9880
10370
  const entityIds = rowItems.sort((a, b) => orderSort(a, b, "blockrow")).map((d) => d.id);
9881
10371
  const descending = destination.index > source.index;
@@ -9887,42 +10377,24 @@ function SectionEditor({
9887
10377
  descending,
9888
10378
  "blockrow"
9889
10379
  );
9890
- const { [sourceRowIndex]: draggingBlock, ...sourceColumnPruned } = columns[sourceColumnIndex];
9891
- if (changedColumn) {
9892
- setColumns({
9893
- ...columns,
9894
- [sourceColumnIndex]: sourceColumnPruned,
9895
- [destinationColumnIndex]: {
9896
- ...columns[destinationColumnIndex],
9897
- [payload.blockrow]: { ...draggingBlock, blockrow: payload.blockrow }
9898
- }
9899
- });
9900
- } else {
9901
- setColumns({
9902
- ...columns,
9903
- [sourceColumnIndex]: {
9904
- ...sourceColumnPruned,
9905
- [payload.blockrow]: { ...draggingBlock, blockrow: payload.blockrow }
9906
- }
9907
- });
9908
- }
9909
10380
  dispatch(actions_exports.updateEntity("block", payload));
9910
10381
  };
10382
+ const generators = Object.values(blocks || {}).filter((d) => d.section_id === section.id && d.type == BLOCK_TYPES.GENERATOR);
10383
+ const orderedCols = Object.keys(columns).sort((a, b) => orderSort(a, b, "blockcol"));
9911
10384
  const columnsQty = Object.keys(columns).length;
9912
10385
  return /* @__PURE__ */ jsxs(
9913
- "div",
10386
+ Paper,
9914
10387
  {
9915
- id: `cms-section-${section.id}`,
10388
+ id: `section-${section.id}`,
9916
10389
  className: `cms-section${isDragging || isActive ? " active" : ""}`,
9917
- style: {
9918
- backgroundColor: site_default.section.backgroundColor,
9919
- borderRadius: site_default.section.borderRadius,
9920
- boxShadow: site_default.section.boxShadow,
9921
- margin: `${site_default.section.margin}px ${site_default.section.margin}px 0`,
9922
- overflow: "hidden",
9923
- width: `calc(100% - ${site_default.section.margin * 2}px)`,
9924
- position: "relative"
9925
- },
10390
+ bg: site_default.section.backgroundColor,
10391
+ m: `${site_default.section.margin}px ${site_default.section.margin}px 0`,
10392
+ w: `calc(100% - ${site_default.section.margin * 2}px)`,
10393
+ mih: 100,
10394
+ pos: "relative",
10395
+ shadow: site_default.section.boxShadow,
10396
+ radius: site_default.section.borderRadius,
10397
+ sx: { overflow: "hidden" },
9926
10398
  children: [
9927
10399
  /* @__PURE__ */ jsx(
9928
10400
  SectionHeader,
@@ -9931,166 +10403,134 @@ function SectionEditor({
9931
10403
  id: section.id,
9932
10404
  isDragging,
9933
10405
  hidden,
9934
- dragHandleProps
10406
+ dragHandleProps,
10407
+ generators: {
10408
+ showGenerators,
10409
+ setShowGenerators
10410
+ }
9935
10411
  }
9936
10412
  ),
9937
10413
  memberImageBg && /* @__PURE__ */ jsx(SectionBackground, {}),
10414
+ optionsMenu && /* @__PURE__ */ jsx(Flex, { justify: "flex-end", mx: 16, children: /* @__PURE__ */ jsx(Options, { sectionId: section.id }) }),
10415
+ /* @__PURE__ */ jsx(
10416
+ GeneratorsPanel,
10417
+ {
10418
+ show: showGenerators,
10419
+ generators: generators.map((item) => /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
10420
+ BlockElement_default,
10421
+ {
10422
+ id: Number(item.id),
10423
+ active: isActive,
10424
+ isInput: inputs.includes(Number(item.id)),
10425
+ isConsumer: consumers.includes(Number(item.id)),
10426
+ setHoverBlock
10427
+ }
10428
+ ) }, `block-${item.id}`))
10429
+ }
10430
+ ),
9938
10431
  /* @__PURE__ */ jsxs(
9939
- "div",
10432
+ ColumnsWrapper,
9940
10433
  {
9941
- className: "cms-section-content",
9942
- style: {
9943
- alignItems: "stretch",
9944
- display: "flex",
9945
- flexDirection: smallScreen ? "column" : "row",
9946
- padding: "32px 32px 32px 32px",
9947
- position: "relative",
9948
- zIndex: 0
10434
+ ref: columnContainer,
10435
+ containerProps: {
10436
+ mih: !isActive || !columnsQty ? 120 : "none",
10437
+ p: "md"
9949
10438
  },
9950
10439
  children: [
9951
- optionsMenu && /* @__PURE__ */ jsx("div", { style: {
9952
- position: "absolute",
9953
- right: 10,
9954
- top: 10,
9955
- zIndex: 100
9956
- }, children: /* @__PURE__ */ jsx(Options, { sectionId: section.id }) }),
9957
- /* @__PURE__ */ jsx(DragDropContext, { onDragEnd, children: Object.keys(columns).sort((a, b) => orderSort(a, b, "blockcol")).map((columnIndex) => {
9958
- const column = columns[columnIndex];
9959
- const staticWidths = Object.values(column).map(({ id }) => parseFloat(blocks[id]?.settings?.width)).filter((d) => !Number.isNaN(d));
9960
- return /* @__PURE__ */ jsx(
9961
- "div",
9962
- {
9963
- className: "cms-section-column",
9964
- style: {
9965
- flex: "1 1 100%",
9966
- maxWidth: staticWidths.length ? Math.max(...staticWidths) : `${100 / columnsQty}%`,
9967
- padding: site_default.column.padding
9968
- },
9969
- children: /* @__PURE__ */ jsx(Droppable, { droppableId: columnIndex, children: (provided, snapshot) => /* @__PURE__ */ jsxs(
9970
- "div",
9971
- {
9972
- ...provided.droppableProps,
9973
- ref: provided.innerRef,
9974
- style: {
9975
- alignContent: "flex-start",
9976
- background: snapshot.isDraggingOver ? theme.colors[theme.primaryColor][0] : "inherit",
9977
- display: "flex",
9978
- flexDirection: Object.values(column).find(
9979
- (item) => blocks[item.id]?.settings?.display === "inline"
9980
- ) ? "row" : "column",
9981
- flexWrap: Object.values(column).find(
9982
- (item) => blocks[item.id]?.settings?.display === "inline"
9983
- ) ? "wrap" : "nowrap",
9984
- height: "100%",
9985
- maxWidth: "100%"
10440
+ /* @__PURE__ */ jsxs(DragDropContext, { onDragEnd, onDragStart, children: [
10441
+ orderedCols.map((columnIndex) => {
10442
+ const orderedBlocks = Object.values(columns[columnIndex]).sort((a, b) => orderSort(a, b, "blockrow"));
10443
+ return /* @__PURE__ */ jsx(Droppable, { droppableId: columnIndex, children: (provided, snapshot) => /* @__PURE__ */ jsxs(
10444
+ SectionColumn,
10445
+ {
10446
+ column: columns[columnIndex],
10447
+ columnSettings: columnSettings[columnIndex],
10448
+ ref: provided.innerRef,
10449
+ sx: {
10450
+ // extra styles for columns on editor
10451
+ flexBasis: `${100 / columnsQty}%`,
10452
+ background: snapshot.isDraggingOver ? theme.colors[theme.primaryColor][0] : "inherit",
10453
+ border: "1px solid transparent",
10454
+ "& .bespoke-resize-col": {
10455
+ visibility: "hidden"
9986
10456
  },
9987
- children: [
9988
- Object.values(column).sort((a, b) => orderSort(a, b, "blockrow")).map((item, rowIndex) => {
9989
- if (!blocks[item.id])
9990
- return null;
9991
- const { settings, type } = blocks[item.id];
9992
- return /* @__PURE__ */ jsx(
9993
- Draggable,
9994
- {
9995
- draggableId: String(item.id),
9996
- index: rowIndex,
9997
- children: (provided2, snapshot2) => /* @__PURE__ */ jsx(
9998
- "div",
9999
- {
10000
- ref: provided2.innerRef,
10001
- ...provided2.draggableProps,
10002
- ...provided2.dragHandleProps,
10003
- style: {
10004
- ...provided2.draggableProps.style,
10005
- alignSelf: type === "visualization" ? "stretch" : "flex-start",
10457
+ "&:hover .bespoke-resize-col": {
10458
+ visibility: "visible"
10459
+ },
10460
+ "&:hover": {
10461
+ border: `1px solid ${theme.colors.teal[1]}`
10462
+ }
10463
+ },
10464
+ ...provided.droppableProps,
10465
+ children: [
10466
+ /* @__PURE__ */ jsx(
10467
+ ResizeColumnInput,
10468
+ {
10469
+ sectionId: section.id,
10470
+ columnIndex
10471
+ }
10472
+ ),
10473
+ orderedBlocks.map((item, rowIndex) => {
10474
+ if (!blocks[item.id])
10475
+ return null;
10476
+ const { settings, type } = blocks[item.id];
10477
+ const blockWidth = settings.width && !settings.width.stretch && settings.width.unit ? formatters[settings.width.unit](settings.width.value) : settings.display === "inline" ? "auto" : "100%";
10478
+ const blockStyles = {
10479
+ alignSelf: type === "visualization" ? "stretch" : "flex-start",
10480
+ flexGrow: 0,
10481
+ margin: "0",
10482
+ textAlign: settings.align || blockSettings.align.defaultValue,
10483
+ width: blockWidth,
10484
+ minWidth: 120
10485
+ };
10486
+ return /* @__PURE__ */ jsx(
10487
+ Draggable,
10488
+ {
10489
+ draggableId: String(item.id),
10490
+ index: rowIndex,
10491
+ children: (provided2, snapshot2) => /* @__PURE__ */ jsx(
10492
+ Box,
10493
+ {
10494
+ ref: provided2.innerRef,
10495
+ ...provided2.draggableProps,
10496
+ ...provided2.dragHandleProps,
10497
+ sx: [
10498
+ blockStyles,
10499
+ {
10006
10500
  boxShadow: snapshot2.isDragging ? theme.shadows.lg : "none",
10007
- flex: type === "visualization" ? smallScreen ? "1 1 300px" : "1 1 100%" : settings.display === "inline" ? "1 1 auto" : "0 0 auto",
10008
- margin: "0",
10009
- textAlign: settings.align || blockSettings.align.defaultValue,
10010
- width: settings.width && settings.width !== "stretch" ? parseFloat(settings.width) : settings.display === "inline" ? "auto" : "100%"
10501
+ ...provided2.draggableProps.style
10502
+ }
10503
+ ],
10504
+ children: /* @__PURE__ */ jsx(
10505
+ BlockElement_default,
10506
+ {
10507
+ id: Number(item.id),
10508
+ active: isActive,
10509
+ isInput: inputs.includes(Number(item.id)),
10510
+ isConsumer: consumers.includes(Number(item.id)),
10511
+ setHoverBlock
10011
10512
  },
10012
- children: /* @__PURE__ */ jsx(
10013
- BlockElement_default,
10014
- {
10015
- id: Number(item.id),
10016
- active: isActive,
10017
- isInput: inputs.includes(Number(item.id)),
10018
- isConsumer: consumers.includes(Number(item.id)),
10019
- sectionState: {
10020
- state: sectionState,
10021
- set: setSectionState2
10022
- },
10023
- setHoverBlock
10024
- },
10025
- `block-${item.id}`
10026
- )
10027
- }
10028
- )
10029
- },
10030
- item.id
10031
- );
10032
- }),
10033
- isActive && /* @__PURE__ */ jsx(
10034
- EntityCreateButton,
10035
- {
10036
- fields: [{
10037
- type: "select",
10038
- name: "type",
10039
- label: "Block Type",
10040
- options: blockTypes.map((d) => ({ label: d, value: d }))
10041
- }],
10042
- onSubmit: (value) => addBlock(value.type, columnIndex),
10043
- target: /* @__PURE__ */ jsx(ActionIcon, { size: "md", radius: "lg", children: /* @__PURE__ */ jsx(IconCirclePlus, { size: 20 }) })
10044
- }
10045
- ),
10046
- provided.placeholder
10047
- ]
10048
- }
10049
- ) }, columnIndex)
10050
- },
10051
- columnIndex
10052
- );
10053
- }) }),
10054
- isActive && /* @__PURE__ */ jsx(
10055
- EntityCreateButton,
10056
- {
10057
- fields: [{
10058
- type: "select",
10059
- name: "type",
10060
- label: "Block Type",
10061
- options: blockTypes.map((d) => ({ label: d, value: d }))
10062
- }],
10063
- onSubmit: (value) => addBlock(value.type),
10064
- target: /* @__PURE__ */ jsx(ActionIcon, { size: "md", radius: "lg", children: /* @__PURE__ */ jsx(IconCirclePlus, { size: 20 }) })
10065
- }
10066
- ),
10067
- !isActive && /* @__PURE__ */ jsx(
10068
- Center,
10069
- {
10070
- className: "cms-section-click-to-edit",
10071
- style: {
10072
- bottom: "0",
10073
- position: "absolute",
10074
- width: "100%",
10075
- left: "0",
10076
- top: "0"
10077
- },
10078
- children: /* @__PURE__ */ jsx(Badge, { size: "xl", variant: "outline", color: "gray", children: "Click to Edit" })
10079
- }
10080
- ),
10081
- !isActive && /* @__PURE__ */ jsx(
10082
- Overlay,
10083
- {
10084
- className: "cms-section-overlay",
10085
- onClick: () => onActivate(section.id),
10086
- color: theme.black,
10087
- opacity: 0.5,
10088
- style: { cursor: "pointer" }
10089
- }
10090
- )
10513
+ `block-${item.id}`
10514
+ )
10515
+ }
10516
+ )
10517
+ },
10518
+ item.id
10519
+ );
10520
+ }),
10521
+ isActive && /* @__PURE__ */ jsx(CreateBlockButton, { section, columnIndex, columns }),
10522
+ provided.placeholder
10523
+ ]
10524
+ }
10525
+ ) }, columnIndex);
10526
+ }),
10527
+ /* @__PURE__ */ jsx(CreateColumnArea, { active: draggingBlock && isActive })
10528
+ ] }),
10529
+ /* @__PURE__ */ jsx(FirstBlockButton, { columns, section, show: isActive && !columnsQty })
10091
10530
  ]
10092
10531
  }
10093
- )
10532
+ ),
10533
+ /* @__PURE__ */ jsx(ClickToEditOverlay, { onActivate, section, show: !isActive })
10094
10534
  ]
10095
10535
  }
10096
10536
  );
@@ -10388,9 +10828,9 @@ function FormatterForm({ formatterId, onEditEnd }) {
10388
10828
  useEffect(() => {
10389
10829
  if (!ref.isLoading && !formattersList.isLoading) {
10390
10830
  const formatterItem = !ref.isSuccess ? void 0 : ref.data;
10391
- const formatters = !formattersList.isSuccess ? [] : formattersList.data;
10831
+ const formatters2 = !formattersList.isSuccess ? [] : formattersList.data;
10392
10832
  if (formatterItem) {
10393
- const formatterNamesList = formatters.filter((f) => f.id !== formatterItem.id).map((f) => f.name);
10833
+ const formatterNamesList = formatters2.filter((f) => f.id !== formatterItem.id).map((f) => f.name);
10394
10834
  setFormatterNames(formatterNamesList);
10395
10835
  }
10396
10836
  onTest();
@@ -10593,10 +11033,10 @@ function FormattersTable({ filters, onClickEdit }) {
10593
11033
  const [sortStatus, setSortStatus] = useState();
10594
11034
  const [records, setRecords] = useState([]);
10595
11035
  const formattersList = useFormatterList();
10596
- const formatters = !formattersList.isSuccess ? [] : formattersList.data;
11036
+ const formatters2 = !formattersList.isSuccess ? [] : formattersList.data;
10597
11037
  const formatterFunctions = useFormatterFunctionsForLocale();
10598
11038
  const formattersUsageCount = useFormatterUsageCountList();
10599
- const formattersFull = useMemo(() => formatters.map((f) => {
11039
+ const formattersFull = useMemo(() => formatters2.map((f) => {
10600
11040
  const usageCount = formattersUsageCount[f.name] ? formattersUsageCount[f.name] : 0;
10601
11041
  let result = "";
10602
11042
  try {
@@ -10612,7 +11052,7 @@ function FormattersTable({ filters, onClickEdit }) {
10612
11052
  result,
10613
11053
  usageCount
10614
11054
  };
10615
- }), [formatters]);
11055
+ }), [formatters2]);
10616
11056
  const doSearch = () => {
10617
11057
  let filteredResults = formattersFull.filter(
10618
11058
  (formatter) => {
@@ -12453,6 +12893,9 @@ function UsersEditor() {
12453
12893
  editingId && /* @__PURE__ */ jsx(UserForm, { userId: editingId, onEditEnd: onEditClose, roles })
12454
12894
  ] });
12455
12895
  }
12896
+
12897
+ // views/BespokeManager.tsx
12898
+ init_ErrorBoundary();
12456
12899
  init_envvars();
12457
12900
  function BespokeManager(options) {
12458
12901
  const {
@@ -12461,7 +12904,7 @@ function BespokeManager(options) {
12461
12904
  locale = localeDefault4,
12462
12905
  profilePrefix = "/profilePathManager"
12463
12906
  } = options;
12464
- const notifications3 = {
12907
+ const notifications4 = {
12465
12908
  position: "bottom-center",
12466
12909
  ...options.notifications
12467
12910
  };
@@ -12474,8 +12917,8 @@ function BespokeManager(options) {
12474
12917
  return /* @__PURE__ */ jsxs(ResourceProvider, { pathSegment, profilePrefix, children: [
12475
12918
  /* @__PURE__ */ jsx(Head, { children: /* @__PURE__ */ jsx("title", { children: title }) }),
12476
12919
  /* @__PURE__ */ jsxs(MantineProvider, { inherit: false, children: [
12477
- /* @__PURE__ */ jsx(Notifications, { ...notifications3 }),
12478
- /* @__PURE__ */ jsx(DialogProvider, { children: /* @__PURE__ */ jsx(BespokeManagerShell, { locale }) })
12920
+ /* @__PURE__ */ jsx(Notifications, { ...notifications4 }),
12921
+ /* @__PURE__ */ jsx(DialogProvider, { children: /* @__PURE__ */ jsx(ErrorBoundary, { fallback: /* @__PURE__ */ jsx("p", { children: "Client side error in Bespoke. Check the console for details." }), children: /* @__PURE__ */ jsx(BespokeManagerShell, { locale }) }) })
12479
12922
  ] })
12480
12923
  ] });
12481
12924
  }