@datawheel/bespoke 0.1.26 → 0.1.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.js +627 -137
  2. package/dist/server.js +134 -46
  3. package/package.json +3 -1
package/dist/index.js CHANGED
@@ -16,14 +16,14 @@ 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, Title, Select, SegmentedControl, MultiSelect, Box, List, Menu, Anchor, MantineProvider, Divider, Burger, Navbar, ScrollArea, Avatar, AppShell, UnstyledButton, ThemeIcon, LoadingOverlay, Skeleton, Container, TextInput, Loader, Alert, Autocomplete, Card, Space, Code, Textarea, rem, Overlay, Grid, Input, Popover, Checkbox, Radio, Switch, Drawer, Tabs, Header, px, SimpleGrid, Image, Paper, FileInput, Accordion, HoverCard, CopyButton, NumberInput, Col } from '@mantine/core';
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';
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, IconAlignLeft, IconAlignCenter, IconAlignRight, IconBoxMargin, IconTable, IconMathFunction, IconUsers, IconLogout, IconSearch, IconTrash, IconUserCircle, IconEdit, IconDatabase, IconServer, IconPencil, IconAlertCircle, IconCircleCheck, IconPlayerPlay, IconAlarmFilled, IconBox, IconLink, IconCirclePlus, IconCircleX, IconFlag, IconFileAnalytics, IconPlus, IconCamera, IconShare, IconCircleDashed, IconListSearch, IconExternalLink, IconSettings, IconFileOff, IconFilesOff, IconMenu, IconRefresh, IconPolaroid, IconCircleMinus, IconEyeOff, 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 { useDisclosure, useDebouncedValue, useSetState, useMediaQuery, useHotkeys, useFullscreen, getHotkeyHandler } from '@mantine/hooks';
25
- import Link from 'next/link';
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';
26
25
  import dynamic from 'next/dynamic';
26
+ import Link from 'next/link';
27
27
  import parse2, { Element, domToReact, Text as Text$1 } from 'html-react-parser';
28
28
  import { UserProvider, withPageAuthRequired, useUser } from '@auth0/nextjs-auth0/client';
29
29
  import { Prism } from '@mantine/prism';
@@ -37,6 +37,8 @@ import slugifyFn from 'slugify';
37
37
  import { FacebookShareButton, FacebookIcon, TwitterShareButton, TwitterIcon, TelegramShareButton, TelegramIcon, WhatsappShareButton, WhatsappIcon, LinkedinShareButton, LinkedinIcon, RedditShareButton, RedditIcon, EmailShareButton, EmailIcon } from 'react-share';
38
38
  import Head from 'next/head';
39
39
  import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd';
40
+ import * as d3 from 'd3';
41
+ import * as d3Dag from 'd3-dag';
40
42
  import Editor, { useMonaco } from '@monaco-editor/react';
41
43
  import { format } from 'pretty-format';
42
44
  import { Editor as Editor$1 } from '@tinymce/tinymce-react';
@@ -194,7 +196,6 @@ var init_http = __esm({
194
196
  init_imageSearch();
195
197
  init_lib();
196
198
  transformDeletePayload = (id) => {
197
- console.log("transformDeletePayload", id);
198
199
  return { id };
199
200
  };
200
201
  transformReadMembers = (params) => {
@@ -274,7 +275,7 @@ var init_block = __esm({
274
275
  });
275
276
 
276
277
  // types/cms.ts
277
- var ENTITY_TYPES, ENTITY_PRETTY_NAMES, REPORT_TYPES, SELECTOR_TYPES, REPORT_FIELDS, ALLOWED, ACCESS, BLOCK_CONTENT_TYPES, BLOCK_LOGIC_TYPES, BLOCK_LOGIC_LOCALE, BLOCK_TYPES, BLOCK_FIELDS, BLOCK_MAP, BLOCK_SETTINGS, FORMATTER_TYPES, FORMATTER_TYPES_NAMES, FORMATTER_INPUT_TYPES, FORMATTER_INPUT_TYPES_NAMES;
278
+ var ENTITY_TYPES, ENTITY_PRETTY_NAMES, REPORT_TYPES, SELECTOR_TYPES, SELECTOR_COMPONENTS, REPORT_FIELDS, ALLOWED, ACCESS, BLOCK_CONTENT_TYPES, BLOCK_LOGIC_TYPES, BLOCK_LOGIC_LOCALE, BLOCK_TYPES, BLOCK_FIELDS, BLOCK_MAP, BLOCK_SETTINGS, FORMATTER_TYPES, FORMATTER_TYPES_NAMES, FORMATTER_INPUT_TYPES, FORMATTER_INPUT_TYPES_NAMES;
278
279
  var init_cms = __esm({
279
280
  "types/cms.ts"() {
280
281
  init_esm_shims();
@@ -314,6 +315,10 @@ var init_cms = __esm({
314
315
  SINGLE: "single",
315
316
  MULTI: "multi"
316
317
  };
318
+ SELECTOR_COMPONENTS = {
319
+ SEGMENTED_CONTROL: "segmented control",
320
+ SELECTOR: "selector"
321
+ };
317
322
  REPORT_FIELDS = {
318
323
  TITLE: "title",
319
324
  SUBTITLE: "subtitle",
@@ -882,6 +887,7 @@ var init_runSelector = __esm({
882
887
  const evalResult = mortarEval_default("variables", variables, transpiledLogic, formatterFunctions, void 0, blockContext);
883
888
  const { vars, log, error } = evalResult;
884
889
  const type = vars.type || SELECTOR_TYPES.SINGLE;
890
+ const component = vars.component || "Selector";
885
891
  const name = vars.name || "Unlabeled Selector";
886
892
  const options = scaffoldDynamic_default(vars.options || []);
887
893
  const maybeFixForMulti2 = (defaultValue2) => type === SELECTOR_TYPES.MULTI && !Array.isArray(defaultValue2) ? [defaultValue2] : defaultValue2;
@@ -900,7 +906,8 @@ var init_runSelector = __esm({
900
906
  name,
901
907
  type,
902
908
  options,
903
- defaultValue
909
+ defaultValue,
910
+ component
904
911
  };
905
912
  return { config, log, error };
906
913
  };
@@ -1078,11 +1085,26 @@ async function apiFetch(url, settings, readMemberFn, locale = "en") {
1078
1085
  }
1079
1086
  async function runSingleBlock(block, formatterFunctions, blockContext, readMemberFn) {
1080
1087
  const { locale, variables, query } = parseBlockContext(blockContext);
1088
+ const allowed = isBlockAllowed(block, blockContext, variables, formatterFunctions);
1081
1089
  let resp = null;
1082
1090
  const unswappedAPI = block.contentByLocale?.logic?.content?.api;
1083
1091
  let apiResponse;
1084
1092
  let duration = null;
1085
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
+ }
1086
1108
  if (unswappedAPI) {
1087
1109
  api = swapAPI(unswappedAPI, formatterFunctions, blockContext);
1088
1110
  const isAbsolute = new RegExp("^(?:[a-z+]+:)?//", "i");
@@ -1095,7 +1117,7 @@ async function runSingleBlock(block, formatterFunctions, blockContext, readMembe
1095
1117
  return result;
1096
1118
  }, (e) => {
1097
1119
  if (verbose2)
1098
- console.error(`Error fetching ${api}: ${e.message}`);
1120
+ console.error(`Error fetching ${api} block ${block.id}: ${e.message}`);
1099
1121
  return { data: {}, requestDuration: 0 };
1100
1122
  });
1101
1123
  resp = apiResponse.data;
@@ -1115,7 +1137,8 @@ async function runSingleBlock(block, formatterFunctions, blockContext, readMembe
1115
1137
  duration: null,
1116
1138
  resp: null,
1117
1139
  log: log2,
1118
- error: error2
1140
+ error: error2,
1141
+ allowed
1119
1142
  }
1120
1143
  };
1121
1144
  }
@@ -1129,7 +1152,8 @@ async function runSingleBlock(block, formatterFunctions, blockContext, readMembe
1129
1152
  duration: null,
1130
1153
  resp: null,
1131
1154
  log: [],
1132
- error: null
1155
+ error: null,
1156
+ allowed
1133
1157
  }
1134
1158
  };
1135
1159
  }
@@ -1146,7 +1170,8 @@ async function runSingleBlock(block, formatterFunctions, blockContext, readMembe
1146
1170
  log,
1147
1171
  duration,
1148
1172
  resp,
1149
- api
1173
+ api,
1174
+ allowed
1150
1175
  }
1151
1176
  };
1152
1177
  }
@@ -1159,11 +1184,12 @@ async function runSingleBlock(block, formatterFunctions, blockContext, readMembe
1159
1184
  error,
1160
1185
  duration,
1161
1186
  resp,
1162
- api
1187
+ api,
1188
+ allowed
1163
1189
  }
1164
1190
  };
1165
1191
  }
1166
- var verbose2, ORIGIN, swapAPI, urlProxy, getDependencies, runConsumersV2, getDurationColor, getSizeColor;
1192
+ var verbose2, ORIGIN, swapAPI, urlProxy, getDependencies, isBlockAllowed, runConsumersV2, getDurationColor, getSizeColor;
1167
1193
  var init_runConsumers = __esm({
1168
1194
  "libs/blocks/runConsumers.ts"() {
1169
1195
  init_esm_shims();
@@ -1195,27 +1221,51 @@ var init_runConsumers = __esm({
1195
1221
  return url;
1196
1222
  };
1197
1223
  ({ urlProxy } = apiFactory("/api/cms"));
1198
- getDependencies = (bid, blocks, acc = [], crawlUp = true, crawlDown = true) => {
1224
+ getDependencies = (bid, blocks, acc = [], crawlUp = true, crawlDown = true, withinSection = true, visited = []) => {
1225
+ if (visited.includes(bid))
1226
+ return [];
1227
+ visited.push(bid);
1199
1228
  const rootBlock = blocks[bid];
1200
1229
  if (rootBlock.inputs.length && crawlUp) {
1201
1230
  rootBlock.inputs.forEach((iid) => {
1202
1231
  const rel = `${iid}-${bid}`;
1203
1232
  if (!acc.includes(rel))
1204
1233
  acc.push(rel);
1205
- rootBlock.inputs.forEach((iid2) => getDependencies(iid2, blocks, acc, crawlUp, false));
1234
+ rootBlock.inputs.forEach((iid2) => getDependencies(iid2, blocks, acc, crawlUp, false, withinSection, visited));
1206
1235
  });
1207
1236
  }
1208
1237
  if (rootBlock.consumers.length && crawlDown) {
1209
1238
  rootBlock.consumers.forEach((cid) => {
1210
1239
  const rel = `${bid}-${cid}`;
1211
- if (!acc.includes(rel) && blocks[cid].section_id === blocks[bid].section_id)
1240
+ if (!acc.includes(rel) && (blocks[cid].section_id === blocks[bid].section_id || !withinSection))
1212
1241
  acc.push(rel);
1213
- rootBlock.consumers.filter((cid2) => blocks[cid2].section_id === blocks[bid].section_id).forEach((cid2) => getDependencies(cid2, blocks, acc, crawlUp, crawlDown));
1242
+ rootBlock.consumers.filter((cid2) => blocks[cid2].section_id === blocks[bid].section_id || !withinSection).forEach((cid2) => getDependencies(cid2, blocks, acc, crawlUp, crawlDown, withinSection, visited));
1214
1243
  });
1215
1244
  }
1216
1245
  return acc;
1217
1246
  };
1218
- runConsumersV2 = async (blocks, sections, bid, formatterFunctions, blockContext, initialVariables = {}, readMemberFn) => {
1247
+ isBlockAllowed = (block, blockContext, variables, formatterFunctions) => {
1248
+ let allowed = true;
1249
+ if (block && "allowed" in block.settings && block.settings.allowed !== "always") {
1250
+ if (block.settings.allowed === "never") {
1251
+ allowed = false;
1252
+ } else {
1253
+ const parsedBlockContext = parseBlockContext(blockContext);
1254
+ const { error, output } = mortarEval_default(
1255
+ "variables",
1256
+ variables,
1257
+ block.settings.allowedLogic || "return false;",
1258
+ formatterFunctions,
1259
+ void 0,
1260
+ parsedBlockContext
1261
+ );
1262
+ if (!error)
1263
+ allowed = Boolean(output);
1264
+ }
1265
+ }
1266
+ return allowed;
1267
+ };
1268
+ runConsumersV2 = async (blocks, sections, bid, formatterFunctions, blockContext, initialVariables = {}, readMemberFn, mode = "section") => {
1219
1269
  if (!bid && !sections)
1220
1270
  return { variables: { ...initialVariables } };
1221
1271
  const variablesById = { ...initialVariables };
@@ -1223,8 +1273,9 @@ var init_runConsumers = __esm({
1223
1273
  const parsedBlockContext = parseBlockContext(blockContext);
1224
1274
  const attributes = parsedBlockContext.variables;
1225
1275
  const rootBlocks = bid ? { [bid]: blocks[bid] } : sections.reduce((rootBlocks2, { id }) => ({ ...rootBlocks2, ...getRootBlocksForSection_default(id, blocks) }), {});
1276
+ const withinSection = mode === "section";
1226
1277
  const blockDeps = Object.keys(rootBlocks).reduce((deps, id) => {
1227
- const dependencies = getDependencies(Number(id), blocks, [], !bid).map((rel) => rel.split("-"));
1278
+ const dependencies = getDependencies(Number(id), blocks, [], !bid, true, withinSection).map((rel) => rel.split("-"));
1228
1279
  return [...deps, ...dependencies];
1229
1280
  }, []);
1230
1281
  const orderedDAG = Object.keys(rootBlocks).reduce(
@@ -1240,6 +1291,19 @@ var init_runConsumers = __esm({
1240
1291
  );
1241
1292
  const runningTask = dependenciesDone.then(() => {
1242
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
+ }
1243
1307
  return runSingleBlock(
1244
1308
  block,
1245
1309
  formatterFunctions,
@@ -2401,15 +2465,16 @@ var init_actions = __esm({
2401
2465
  }
2402
2466
  });
2403
2467
  function ResourceProvider(props) {
2404
- const { pathSegment } = props;
2468
+ const { pathSegment, profilePrefix } = props;
2405
2469
  const formatters = useFormatterList();
2406
2470
  const value = useMemo(() => ({
2471
+ profilePrefix,
2407
2472
  pathSegment,
2408
2473
  formatterFunctions: locales3.reduce((acc, locale) => ({
2409
2474
  ...acc,
2410
2475
  [locale]: formatters.data ? funcifyFormattersByLocale(formatters.data, locale) : {}
2411
2476
  }), {})
2412
- }), [formatters, pathSegment]);
2477
+ }), [formatters, pathSegment, profilePrefix]);
2413
2478
  return /* @__PURE__ */ jsx(ResourceContext.Provider, { value, children: props.children });
2414
2479
  }
2415
2480
  function useBespoke() {
@@ -2429,7 +2494,8 @@ var init_ResourceProvider = __esm({
2429
2494
  ({ locales: locales3 } = getLocales_default());
2430
2495
  initialContext = {
2431
2496
  pathSegment: "path",
2432
- formatterFunctions: locales3.reduce((acc, d) => ({ ...acc, [d]: {} }), {})
2497
+ formatterFunctions: locales3.reduce((acc, d) => ({ ...acc, [d]: {} }), {}),
2498
+ profilePrefix: "path"
2433
2499
  };
2434
2500
  ResourceContext = createContext(initialContext);
2435
2501
  }
@@ -2517,7 +2583,7 @@ function processResult(data, req) {
2517
2583
  }
2518
2584
  return { ...result, data };
2519
2585
  }
2520
- var localeDefault5, useAppDispatch, useAppSelector, useReportList, useVariantList, useSectionList, useFormatterList, useReportRef, useSectionRef, useBlockRef, useDimensionRef, useVariantRef, useFormatterRef, useInputVariablesFlat, useInputVariablesHash, useBlockStatus, useFormatterFunctionsForLocale, useBlockContext, getFormatterUsageCount, useFormatterUsageCount, useFormatterUsageCountList;
2586
+ var localeDefault5, useAppDispatch, useAppSelector, useReportList, useVariantList, useSectionList, useBlockList, useFormatterList, useReportRef, useSectionRef, useBlockRef, useDimensionRef, useVariantRef, useFormatterRef, useInputVariablesFlat, useInputVariablesHash, useBlockStatus, useFormatterFunctionsForLocale, useProfilePrefix, useBlockContext, getFormatterUsageCount, useFormatterUsageCount, useFormatterUsageCountList;
2521
2587
  var init_hooks = __esm({
2522
2588
  "store/hooks.ts"() {
2523
2589
  init_esm_shims();
@@ -2532,6 +2598,7 @@ var init_hooks = __esm({
2532
2598
  useReportList = entityListHookFactory("report");
2533
2599
  useVariantList = entityListHookFactory("variant");
2534
2600
  useSectionList = entityListHookFactory("section");
2601
+ useBlockList = entityListHookFactory("block");
2535
2602
  useFormatterList = entityListHookFactory("formatter");
2536
2603
  useReportRef = entityRefHookFactory("report");
2537
2604
  useSectionRef = entityRefHookFactory("section");
@@ -2573,6 +2640,10 @@ var init_hooks = __esm({
2573
2640
  const resource = useContext(ResourceContext);
2574
2641
  return resource.formatterFunctions[locale];
2575
2642
  };
2643
+ useProfilePrefix = () => {
2644
+ const resource = useContext(ResourceContext);
2645
+ return resource.profilePrefix;
2646
+ };
2576
2647
  useBlockContext = (id = void 0, locale = void 0) => {
2577
2648
  useAppSelector((state2) => state2);
2578
2649
  const localeDefault9 = useAppSelector((state2) => state2.status.localeDefault);
@@ -2626,6 +2697,7 @@ var init_store = __esm({
2626
2697
  return getDefaultMiddleware({
2627
2698
  thunk: {
2628
2699
  extraArgument: apiFactory("/api/cms/")
2700
+ // serializableCheck: false,
2629
2701
  }
2630
2702
  });
2631
2703
  }
@@ -2633,7 +2705,7 @@ var init_store = __esm({
2633
2705
  storeWrapper = createWrapper(storeFactory);
2634
2706
  }
2635
2707
  });
2636
- function withFetcher(Component, useRef6) {
2708
+ function withFetcher(Component, useRef7) {
2637
2709
  const ComponentWithFetcher = (props) => {
2638
2710
  const {
2639
2711
  id,
@@ -2641,7 +2713,7 @@ function withFetcher(Component, useRef6) {
2641
2713
  skelWidth,
2642
2714
  ...otherProps
2643
2715
  } = props;
2644
- const ref = useRef6(id);
2716
+ const ref = useRef7(id);
2645
2717
  if (ref.isUninitialized || ref.isFetching) {
2646
2718
  return /* @__PURE__ */ jsx(Skeleton, { width: skelWidth, height: skelHeight });
2647
2719
  }
@@ -3285,8 +3357,13 @@ init_esm_shims();
3285
3357
 
3286
3358
  // frontend/components/explore/ExploreTile.tsx
3287
3359
  init_esm_shims();
3288
- function ExploreTile({ profile, profilePrefix }) {
3289
- const url = `${profilePrefix}${profile.path}`;
3360
+ init_store2();
3361
+ function ExploreTile({ profile, profilePrefix, onSelect }) {
3362
+ const currentLocale = useAppSelector((state) => state.status.currentLocale);
3363
+ const localeDefault9 = useAppSelector((state) => state.status.localeDefault);
3364
+ const localePrefix = currentLocale === localeDefault9 ? "" : `/${currentLocale}`;
3365
+ const url = `${localePrefix}${profilePrefix}${profile.path}`;
3366
+ const router = useRouter();
3290
3367
  const images = profile.members.map((m) => /* @__PURE__ */ jsx(
3291
3368
  Image,
3292
3369
  {
@@ -3301,21 +3378,37 @@ function ExploreTile({ profile, profilePrefix }) {
3301
3378
  /* @__PURE__ */ jsx(Text, { weight: 500, children: m.name }),
3302
3379
  /* @__PURE__ */ jsx(Badge, { color: "green", variant: "light", children: m.metadata.variant.name })
3303
3380
  ] }, m.id));
3381
+ const onItemSubmit = (innerUrl) => {
3382
+ router.push(`${innerUrl}`);
3383
+ if (onSelect)
3384
+ onSelect();
3385
+ };
3304
3386
  return /* @__PURE__ */ jsx(Grid.Col, { xs: 12, sm: 6, md: 4, lg: 4, xl: 3, children: /* @__PURE__ */ jsxs(Card, { shadow: "sm", p: "lg", radius: "md", withBorder: true, children: [
3305
3387
  /* @__PURE__ */ jsx(Card.Section, { children: /* @__PURE__ */ jsx(Group, { grow: true, spacing: 0, children: images }) }),
3306
3388
  /* @__PURE__ */ jsx(Group, { position: "apart", mt: "md", mb: "xs", children: names }),
3307
- /* @__PURE__ */ jsx(Link, { href: url, passHref: true, prefetch: false, children: /* @__PURE__ */ jsx(Button, { variant: "light", color: "blue", fullWidth: true, mt: "md", radius: "md", children: `See ${profile.report.name} Report` }) })
3389
+ /* @__PURE__ */ jsx(
3390
+ "a",
3391
+ {
3392
+ href: url,
3393
+ onClick: (evt) => {
3394
+ evt.preventDefault();
3395
+ onItemSubmit(url);
3396
+ },
3397
+ children: /* @__PURE__ */ jsx(Button, { variant: "light", color: "blue", fullWidth: true, mt: "md", radius: "md", children: `See ${profile.report.name} Report` })
3398
+ }
3399
+ )
3308
3400
  ] }) }, profile.id);
3309
3401
  }
3310
3402
  var ExploreTile_default = ExploreTile;
3311
- function ExploreResults({ results = [], profilePrefix }) {
3403
+ function ExploreResults({ results = [], profilePrefix, onSelect = () => {
3404
+ } }) {
3312
3405
  const [scrollSize, setScrollSize] = useState(500);
3313
3406
  useEffect(() => {
3314
3407
  const { innerHeight } = window;
3315
3408
  setScrollSize(innerHeight - 200);
3316
3409
  }, []);
3317
3410
  return /* @__PURE__ */ jsx(ScrollArea, { offsetScrollbars: true, type: "always", style: { height: scrollSize }, children: /* @__PURE__ */ jsx(Grid, { align: "stretch", children: results.map(
3318
- (item) => /* @__PURE__ */ jsx(ExploreTile_default, { profile: item, profilePrefix }, item.id)
3411
+ (item) => /* @__PURE__ */ jsx(ExploreTile_default, { profile: item, profilePrefix, onSelect }, item.id)
3319
3412
  ) }) });
3320
3413
  }
3321
3414
  var ExploreResults_default = ExploreResults;
@@ -3326,10 +3419,12 @@ function BespokeExplore({
3326
3419
  locale,
3327
3420
  profilePrefix,
3328
3421
  initialReportId,
3329
- initialVariantId
3422
+ initialVariantId,
3423
+ onSelect
3330
3424
  }) {
3331
3425
  const dispatch = useAppDispatch();
3332
3426
  const defaultFilters = {
3427
+ // initial reportIds should go here to avoid multiple unnecesary requests
3333
3428
  profile: void 0,
3334
3429
  variant: void 0
3335
3430
  };
@@ -3348,6 +3443,7 @@ function BespokeExplore({
3348
3443
  });
3349
3444
  }, []);
3350
3445
  useEffect(() => {
3446
+ let cancelled = false;
3351
3447
  if (metadata) {
3352
3448
  setLoading(true);
3353
3449
  const filterProfile = filters.profile && !Number.isNaN(filters.profile) ? filters.profile : [];
@@ -3366,7 +3462,7 @@ function BespokeExplore({
3366
3462
  all: false
3367
3463
  };
3368
3464
  dispatch(actions_exports.reportSearch(params)).then((resp) => {
3369
- if (resp && resp.results) {
3465
+ if (resp && resp.results && !cancelled) {
3370
3466
  setResults(resp.results);
3371
3467
  }
3372
3468
  setLoading(false);
@@ -3376,6 +3472,9 @@ function BespokeExplore({
3376
3472
  setLoading(false);
3377
3473
  });
3378
3474
  }
3475
+ return () => {
3476
+ cancelled = false;
3477
+ };
3379
3478
  }, [debouncedQuery, filters, metadata]);
3380
3479
  const onFilterChange = (newFilters) => {
3381
3480
  setFilters(newFilters);
@@ -3418,7 +3517,7 @@ function BespokeExplore({
3418
3517
  ),
3419
3518
  /* @__PURE__ */ jsx(LoadingOverlay, { visible: loading }),
3420
3519
  !loading && results.length === 0 && /* @__PURE__ */ jsx(Alert, { title: "No results", color: "blue", children: "Try another search or filter." }),
3421
- !loading && /* @__PURE__ */ jsx(ExploreResults_default, { results, profilePrefix })
3520
+ !loading && /* @__PURE__ */ jsx(ExploreResults_default, { results, profilePrefix, onSelect })
3422
3521
  ] });
3423
3522
  }
3424
3523
  var Explore_default = BespokeExplore;
@@ -3429,13 +3528,14 @@ init_getLocales();
3429
3528
  var { localeDefault: localeDefault6 } = getLocales_default();
3430
3529
  function BespokeExploreModal({
3431
3530
  exploreProps = { profilePrefix: "/", locale: localeDefault6 },
3432
- icon = /* @__PURE__ */ jsx(IconSearch, {}),
3531
+ icon = /* @__PURE__ */ jsx(IconSearch, { size: 20 }),
3433
3532
  actionIconProps = {},
3434
- modalProps = {}
3533
+ modalProps = {},
3534
+ children
3435
3535
  }) {
3436
3536
  const [opened, setOpened] = useState(false);
3437
3537
  const btnConfig = {
3438
- variant: "subtle",
3538
+ variant: "light",
3439
3539
  size: "md",
3440
3540
  radius: "md",
3441
3541
  ...actionIconProps
@@ -3444,10 +3544,22 @@ function BespokeExploreModal({
3444
3544
  fullScreen: true,
3445
3545
  opened,
3446
3546
  onClose: () => setOpened(false)
3547
+ //...modalProps,
3447
3548
  };
3549
+ const actionIcon = /* @__PURE__ */ jsx(ActionIcon, { ...btnConfig, onClick: () => setOpened(true), children: icon });
3448
3550
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3449
- /* @__PURE__ */ jsx(Modal, { ...modalProps, ...mdlConfig, children: /* @__PURE__ */ jsx(Explore_default, { ...exploreProps }) }),
3450
- /* @__PURE__ */ jsx(ActionIcon, { ...btnConfig, onClick: () => setOpened(true), children: icon })
3551
+ /* @__PURE__ */ jsx(Modal, { ...modalProps, ...mdlConfig, children: /* @__PURE__ */ jsx(Explore_default, { ...exploreProps, onSelect: () => setOpened(false) }) }),
3552
+ /* @__PURE__ */ jsx("div", { onClick: () => setOpened(true), children: children ? /* @__PURE__ */ jsx(Tooltip, { label: "Click to search", children: /* @__PURE__ */ jsxs(
3553
+ Group,
3554
+ {
3555
+ spacing: "sm",
3556
+ style: { cursor: "pointer" },
3557
+ children: [
3558
+ children,
3559
+ actionIcon
3560
+ ]
3561
+ }
3562
+ ) }) : /* @__PURE__ */ jsx(Fragment, { children: actionIcon }) })
3451
3563
  ] });
3452
3564
  }
3453
3565
  var ExploreModal_default = BespokeExploreModal;
@@ -3472,8 +3584,10 @@ var SearchItem = forwardRef(
3472
3584
  }
3473
3585
  );
3474
3586
  var SearchItem_default = SearchItem;
3475
- function BespokeSearch({ locale, profilePrefix, autocompleteProps = {} }) {
3587
+ function BespokeSearch({ locale, profilePrefix, autocompleteProps = {}, children }) {
3476
3588
  const dispatch = useAppDispatch();
3589
+ const currentLocale = useAppSelector((state) => state.status.currentLocale);
3590
+ const localeDefault9 = useAppSelector((state) => state.status.localeDefault);
3477
3591
  const router = useRouter();
3478
3592
  const [query, setQuery] = useState("");
3479
3593
  const [debouncedQuery, cancel] = useDebouncedValue(query, 500);
@@ -3481,6 +3595,7 @@ function BespokeSearch({ locale, profilePrefix, autocompleteProps = {} }) {
3481
3595
  const [loading, setLoading] = useState(false);
3482
3596
  const [redirecting, setRedirecting] = useState(false);
3483
3597
  const [initialized, setInitialized] = useState(false);
3598
+ const [visible, setVisible] = useState(children ? false : true);
3484
3599
  const inputRef = useRef();
3485
3600
  const doSearch = () => {
3486
3601
  setLoading(true);
@@ -3500,7 +3615,7 @@ function BespokeSearch({ locale, profilePrefix, autocompleteProps = {} }) {
3500
3615
  dispatch(actions_exports.reportSearch(params)).then((value) => {
3501
3616
  if (value && value.results) {
3502
3617
  setResults(value.results.map((r) => {
3503
- r.value = `VALUE: ${r.name}...`;
3618
+ r.value = `VALUE: ${r.id}`;
3504
3619
  return r;
3505
3620
  }));
3506
3621
  }
@@ -3518,10 +3633,16 @@ function BespokeSearch({ locale, profilePrefix, autocompleteProps = {} }) {
3518
3633
  }, [debouncedQuery]);
3519
3634
  useEffect(() => {
3520
3635
  cancel();
3521
- if (inputRef.current) {
3636
+ if (inputRef.current && visible) {
3522
3637
  setInitialized(true);
3523
3638
  }
3524
3639
  }, []);
3640
+ useEffect(() => {
3641
+ cancel();
3642
+ if (inputRef.current && visible) {
3643
+ setInitialized(true);
3644
+ }
3645
+ }, [visible]);
3525
3646
  const acConfig = {
3526
3647
  placeholder: "Search",
3527
3648
  size: "md",
@@ -3531,14 +3652,24 @@ function BespokeSearch({ locale, profilePrefix, autocompleteProps = {} }) {
3531
3652
  };
3532
3653
  const onItemSubmit = (item) => {
3533
3654
  setRedirecting(true);
3534
- router.push(`${profilePrefix}${item.path}`);
3655
+ setVisible(false);
3656
+ const localePrefix = currentLocale === localeDefault9 ? "" : `/${currentLocale}`;
3657
+ const url = `${localePrefix}${profilePrefix}${item.path}`;
3658
+ router.push(url);
3535
3659
  };
3536
3660
  const onChange = (searchTerm) => {
3537
3661
  if (!searchTerm.includes("VALUE:")) {
3538
3662
  setQuery(searchTerm);
3539
3663
  }
3540
3664
  };
3541
- return /* @__PURE__ */ jsx(
3665
+ const doClose = () => {
3666
+ setVisible(false);
3667
+ };
3668
+ const doOpen = () => {
3669
+ setVisible(true);
3670
+ doSearch();
3671
+ };
3672
+ const autocompleteElement = /* @__PURE__ */ jsx(
3542
3673
  Autocomplete,
3543
3674
  {
3544
3675
  value: query,
@@ -3549,11 +3680,26 @@ function BespokeSearch({ locale, profilePrefix, autocompleteProps = {} }) {
3549
3680
  disabled: (loading || redirecting) && !initialized,
3550
3681
  limit: 10,
3551
3682
  maxDropdownHeight: 250,
3552
- rightSection: loading ? /* @__PURE__ */ jsx(Loader, { size: 20 }) : "",
3683
+ rightSection: /* @__PURE__ */ jsx(Group, { spacing: 0, position: "right", children: loading ? /* @__PURE__ */ jsx(Loader, { size: 20 }) : /* @__PURE__ */ jsx(Fragment, {}) }),
3684
+ rightSectionWidth: 50,
3553
3685
  ref: inputRef,
3554
3686
  ...acConfig
3555
3687
  }
3556
3688
  );
3689
+ const finalElement = children ? /* @__PURE__ */ jsx(Tooltip, { label: "Click to search", disabled: visible, children: /* @__PURE__ */ jsxs(
3690
+ Group,
3691
+ {
3692
+ spacing: "sm",
3693
+ align: "center",
3694
+ style: { cursor: "pointer" },
3695
+ children: [
3696
+ !visible && /* @__PURE__ */ jsx("div", { onClick: () => setVisible(true), children }),
3697
+ visible && /* @__PURE__ */ jsx(Fragment, { children: autocompleteElement }),
3698
+ visible ? /* @__PURE__ */ jsx(ActionIcon, { variant: "light", onClick: doClose, children: /* @__PURE__ */ jsx(IconX, { size: 20 }) }) : /* @__PURE__ */ jsx(ActionIcon, { variant: "light", onClick: doOpen, children: /* @__PURE__ */ jsx(IconSearch, { size: 20 }) })
3699
+ ]
3700
+ }
3701
+ ) }) : autocompleteElement;
3702
+ return finalElement;
3557
3703
  }
3558
3704
  var Search_default = BespokeSearch;
3559
3705
 
@@ -3626,7 +3772,7 @@ function ParagraphView({ paragraph, tooltip, size = "md" }) {
3626
3772
  // frontend/components/report/blocks/Stat.tsx
3627
3773
  init_esm_shims();
3628
3774
  init_sanitizeBlockContent();
3629
- function Stat({ subtitle, title, value, tooltip = "stat tooltip" }) {
3775
+ function Stat({ subtitle, title, value, tooltip }) {
3630
3776
  const titleHTML = sanitizeBlockContent_default(title);
3631
3777
  const valueHTML = sanitizeBlockContent_default(value);
3632
3778
  const subtitleHTML = sanitizeBlockContent_default(subtitle);
@@ -3658,21 +3804,62 @@ function SubtitleView({ subtitle, tooltip }) {
3658
3804
  // frontend/components/report/blocks/Title.tsx
3659
3805
  init_esm_shims();
3660
3806
  init_sanitizeBlockContent();
3807
+ init_hooks();
3661
3808
  function TitleView({ title, tooltip, slug, settings }) {
3662
3809
  const titleHTML = sanitizeBlockContent_default(title) || "<span class='cr-block-placeholder'>Title</span>";
3663
3810
  const tooltipHTML = sanitizeBlockContent_default(tooltip);
3664
3811
  const intOrder = settings && settings.order ? parseInt(settings.order, 10) : 1;
3665
3812
  const order = intOrder <= 6 ? intOrder : 1;
3666
- return /* @__PURE__ */ jsxs(Group, { spacing: "xs", children: [
3667
- tooltip && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Tooltip, { label: tooltipHTML, withArrow: true, withinPortal: true, children: /* @__PURE__ */ jsx(ActionIcon, { children: /* @__PURE__ */ jsx(IconInfoCircle, {}) }) }) }, "tooltip"),
3668
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
3669
- Title,
3670
- {
3671
- order,
3672
- dangerouslySetInnerHTML: { __html: titleHTML }
3673
- }
3674
- ) })
3675
- ] });
3813
+ const searchOnClick = settings && settings.search ? settings.search : "off";
3814
+ const currentLocale = useAppSelector((state) => state.status.currentLocale);
3815
+ const profilePrefix = useProfilePrefix();
3816
+ const initialIds = useAppSelector(
3817
+ (state) => ({
3818
+ reportId: state.variables.attributes.report_id,
3819
+ variantId: state.variables.attributes.variant_id1
3820
+ })
3821
+ );
3822
+ const titleElement = /* @__PURE__ */ jsx(
3823
+ Title,
3824
+ {
3825
+ order,
3826
+ dangerouslySetInnerHTML: { __html: titleHTML }
3827
+ }
3828
+ );
3829
+ const locale = currentLocale;
3830
+ const finalElement = useMemo(() => {
3831
+ let component = /* @__PURE__ */ jsx(Fragment, {});
3832
+ if (searchOnClick === "modal") {
3833
+ component = /* @__PURE__ */ jsx(ExploreModal_default, { exploreProps: {
3834
+ locale,
3835
+ profilePrefix,
3836
+ initialReportId: initialIds.reportId,
3837
+ initialVariantId: initialIds.variantId
3838
+ }, children: titleElement });
3839
+ } else if (searchOnClick === "inline") {
3840
+ component = /* @__PURE__ */ jsx(
3841
+ Search_default,
3842
+ {
3843
+ locale,
3844
+ profilePrefix,
3845
+ children: titleElement
3846
+ }
3847
+ );
3848
+ } else {
3849
+ component = titleElement;
3850
+ }
3851
+ return component;
3852
+ }, [searchOnClick, titleElement]);
3853
+ return /* @__PURE__ */ jsxs(
3854
+ Group,
3855
+ {
3856
+ spacing: "sm",
3857
+ children: [
3858
+ tooltip && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Tooltip, { label: tooltipHTML, withArrow: true, withinPortal: true, children: /* @__PURE__ */ jsx(ActionIcon, { children: /* @__PURE__ */ jsx(IconInfoCircle, {}) }) }) }, "tooltip"),
3859
+ /* @__PURE__ */ jsx("div", { children: finalElement })
3860
+ ]
3861
+ }
3862
+ );
3676
3863
  }
3677
3864
 
3678
3865
  // frontend/components/report/blocks/Selector.tsx
@@ -3726,12 +3913,13 @@ function useOnChangeSelector(blockId, section, selectorIdentifier) {
3726
3913
  formatters,
3727
3914
  blockContext,
3728
3915
  initialVariables,
3729
- readMemberFn
3916
+ readMemberFn,
3917
+ "report"
3730
3918
  ).then((data) => {
3731
3919
  dispatch(variablesActions.setVariableChange({
3732
3920
  attributes,
3733
3921
  variables: data.variables,
3734
- status: {}
3922
+ status: data.status
3735
3923
  }));
3736
3924
  });
3737
3925
  },
@@ -3757,7 +3945,7 @@ var parseMultiValue = (selectorValue, defaultValue) => {
3757
3945
  return defaultValue;
3758
3946
  };
3759
3947
  function Selector(config) {
3760
- const { name, options, id, defaultValue, section } = config;
3948
+ const { name, options, id, defaultValue, section, component } = config;
3761
3949
  const selectorIdentifier = getSelectorIdentifier(id);
3762
3950
  const router = useRouter();
3763
3951
  const callback = useOnChangeSelector(id, section, selectorIdentifier);
@@ -3768,22 +3956,22 @@ function Selector(config) {
3768
3956
  (d) => ({ value: d.id, label: d.label })
3769
3957
  ), [optDependency]);
3770
3958
  return {
3771
- [SELECTOR_TYPES.SINGLE]: data.length > 3 ? /* @__PURE__ */ jsx(
3772
- Select,
3959
+ [SELECTOR_TYPES.SINGLE]: component === SELECTOR_COMPONENTS.SEGMENTED_CONTROL ? /* @__PURE__ */ jsx(
3960
+ SegmentedControl,
3773
3961
  {
3774
- label: name,
3775
3962
  data,
3776
3963
  value,
3777
- onChange: (value2) => callback(value2)
3964
+ onChange: (value2) => callback(value2),
3965
+ name,
3966
+ fullWidth: true
3778
3967
  }
3779
3968
  ) : /* @__PURE__ */ jsx(
3780
- SegmentedControl,
3969
+ Select,
3781
3970
  {
3971
+ label: name,
3782
3972
  data,
3783
3973
  value,
3784
- onChange: (value2) => callback(value2),
3785
- name,
3786
- fullWidth: true
3974
+ onChange: (value2) => callback(value2)
3787
3975
  }
3788
3976
  ),
3789
3977
  [SELECTOR_TYPES.MULTI]: /* @__PURE__ */ jsx(
@@ -3887,7 +4075,8 @@ function useInitialState(pathSegmentsKey) {
3887
4075
  formatters,
3888
4076
  blockContext,
3889
4077
  variables,
3890
- readMemberFn
4078
+ readMemberFn,
4079
+ "report"
3891
4080
  ).then((data) => {
3892
4081
  return dispatch(variablesActions.setVariableChange({ ...data, attributes }));
3893
4082
  });
@@ -3924,7 +4113,7 @@ function createOutline(elements, variables) {
3924
4113
  const node = {
3925
4114
  id,
3926
4115
  order,
3927
- label: variables[id] ? variables[id][`title${id}title`] : "-Not calculated yet-",
4116
+ label: variables[id] ? variables[id][`title${id}title`] : `Title ${id}`,
3928
4117
  children: []
3929
4118
  };
3930
4119
  nodes[id] = node;
@@ -3986,12 +4175,12 @@ function useContentOutline(min = 1, max = 6, headings = []) {
3986
4175
  return useMemo(() => {
3987
4176
  if (titlesSorted && titlesSorted?.length > 0) {
3988
4177
  return createOutline(titlesSorted, titleVariables);
4178
+ } else {
4179
+ return [];
3989
4180
  }
3990
4181
  }, [titlesSorted, titleVariables]);
3991
4182
  }
3992
- function NavView({ headings, settings }) {
3993
- const { type, min, max } = settings;
3994
- const contentOutline = useContentOutline(parseInt(min, 10), parseInt(max, 10), headings);
4183
+ var DesktopNav = ({ contentOutline }) => {
3995
4184
  const renderMenu = (nodes) => {
3996
4185
  if (!nodes || !nodes?.length) {
3997
4186
  return null;
@@ -4024,6 +4213,80 @@ function NavView({ headings, settings }) {
4024
4213
  )
4025
4214
  }
4026
4215
  ) });
4216
+ };
4217
+ var MobileAccordion = ({ contentOutline, closeNav }) => {
4218
+ const [value, setValue] = useState(null);
4219
+ return /* @__PURE__ */ jsx(Stack, { children: contentOutline.map(
4220
+ (node) => node.children.length ? /* @__PURE__ */ jsxs(Fragment, { children: [
4221
+ /* @__PURE__ */ jsxs(Group, { spacing: 0, noWrap: true, children: [
4222
+ /* @__PURE__ */ jsx(
4223
+ UnstyledButton,
4224
+ {
4225
+ w: "100%",
4226
+ component: "a",
4227
+ onClick: closeNav,
4228
+ href: `#bespoke-title-${node.id}`,
4229
+ children: /* @__PURE__ */ jsx(Text, { pl: "sm", dangerouslySetInnerHTML: { __html: node.label } })
4230
+ },
4231
+ node.id
4232
+ ),
4233
+ /* @__PURE__ */ jsx(
4234
+ ActionIcon,
4235
+ {
4236
+ component: "a",
4237
+ size: "lg",
4238
+ onClick: () => setValue((value2) => value2 === node.id ? null : node.id),
4239
+ children: /* @__PURE__ */ jsx(
4240
+ IconChevronDown,
4241
+ {
4242
+ style: {
4243
+ transition: "transform 0.2s",
4244
+ transform: value === node.id ? "rotate(-180deg)" : "none"
4245
+ },
4246
+ stroke: 1
4247
+ }
4248
+ )
4249
+ }
4250
+ )
4251
+ ] }, node.id),
4252
+ /* @__PURE__ */ jsx(
4253
+ Collapse,
4254
+ {
4255
+ in: value === node.id,
4256
+ pl: "sm",
4257
+ transitionTimingFunction: "linear",
4258
+ transitionDuration: 200,
4259
+ children: /* @__PURE__ */ jsx(MobileAccordion, { contentOutline: node.children, closeNav })
4260
+ }
4261
+ )
4262
+ ] }) : /* @__PURE__ */ jsx(Group, { noWrap: true, children: /* @__PURE__ */ jsx(
4263
+ UnstyledButton,
4264
+ {
4265
+ display: "flex",
4266
+ w: "100%",
4267
+ component: "a",
4268
+ href: `#bespoke-title-${node.id}`,
4269
+ children: /* @__PURE__ */ jsx(Text, { pl: "sm", dangerouslySetInnerHTML: { __html: node.label } })
4270
+ },
4271
+ node.id
4272
+ ) }, node.id)
4273
+ ) });
4274
+ };
4275
+ var MobileNav = ({ contentOutline }) => {
4276
+ const [opened, { toggle }] = useDisclosure(false);
4277
+ const label = opened ? "Close content outline" : "Open content outline";
4278
+ return /* @__PURE__ */ jsxs(Box, { component: "nav", children: [
4279
+ /* @__PURE__ */ jsx(Group, { children: /* @__PURE__ */ jsx(Burger, { opened, onClick: toggle, "aria-label": label, size: "md" }) }),
4280
+ /* @__PURE__ */ jsx(Collapse, { in: opened, mt: "md", children: /* @__PURE__ */ jsx(MobileAccordion, { contentOutline, closeNav: toggle }) })
4281
+ ] });
4282
+ };
4283
+ function NavView({ headings, settings }) {
4284
+ const { type, min, max } = settings;
4285
+ const contentOutline = useContentOutline(parseInt(min, 10), parseInt(max, 10), headings);
4286
+ const theme = useMantineTheme();
4287
+ const mq = `(max-width: ${theme.breakpoints.md})`;
4288
+ const smallerThanMd = useMediaQuery(mq);
4289
+ return smallerThanMd ? /* @__PURE__ */ jsx(MobileNav, { contentOutline }) : /* @__PURE__ */ jsx(DesktopNav, { contentOutline });
4027
4290
  }
4028
4291
 
4029
4292
  // frontend/components/report/blocks/index.tsx
@@ -4062,8 +4325,9 @@ var validateOptionsArray = (options) => {
4062
4325
  return options.map((d) => typeof d === "string" ? { id: d, label: d } : d);
4063
4326
  };
4064
4327
  var maybeFixForMulti = (defaultValue, type) => type === SELECTOR_TYPES.MULTI && !Array.isArray(defaultValue) ? [defaultValue] : defaultValue;
4065
- var Selector_default = (vars, id) => {
4328
+ var selectorAdapter = (vars, id) => {
4066
4329
  const type = vars.type || SELECTOR_TYPES.SINGLE;
4330
+ const component = vars.component || "Selector";
4067
4331
  const name = vars.name || "Unlabeled Selector";
4068
4332
  const options = validateOptionsArray(vars.options || []);
4069
4333
  let defaultValue;
@@ -4081,9 +4345,11 @@ var Selector_default = (vars, id) => {
4081
4345
  name,
4082
4346
  type,
4083
4347
  options,
4348
+ component,
4084
4349
  defaultValue
4085
4350
  };
4086
4351
  };
4352
+ var Selector_default = selectorAdapter;
4087
4353
 
4088
4354
  // components/blocks/types/adapters/index.js
4089
4355
  var adapters_default = {
@@ -4126,6 +4392,10 @@ var SELECTOR_TYPE = {
4126
4392
  SINGLE: "single",
4127
4393
  MULTI: "multi"
4128
4394
  };
4395
+ var SELECTOR_COMPONENT = {
4396
+ SEGMENTED_CONTROL: "segmented control",
4397
+ SELECTOR: "selector"
4398
+ };
4129
4399
  var OPTION_TYPE = {
4130
4400
  STATIC: "static",
4131
4401
  DYNAMIC: "dynamic"
@@ -4347,14 +4617,16 @@ function SelectorUI(props) {
4347
4617
  } = props;
4348
4618
  const [selectorIdentifier, setSelectorIdentifier] = useState("");
4349
4619
  const [selectorType, setSelectorType] = useState(SELECTOR_TYPE.SINGLE);
4620
+ const [selectorComponent, setSelectorComponent] = useState(SELECTOR_COMPONENT.SELECTOR);
4350
4621
  const [options, setOptions] = useState({ static: [], dynamic: {} });
4351
4622
  const [optionsType, setOptionsType] = useState(OPTION_TYPE.STATIC);
4352
- const stateFields = [selectorIdentifier, selectorType, options, optionsType];
4623
+ const stateFields = [selectorIdentifier, selectorType, selectorComponent, options, optionsType];
4353
4624
  useEffect(() => {
4354
4625
  if (!simpleState)
4355
4626
  return;
4356
4627
  setSelectorIdentifier(simpleState.name || "");
4357
4628
  setSelectorType(simpleState.type);
4629
+ setSelectorComponent(simpleState.component);
4358
4630
  if (simpleState.options?.hasOwnProperty("dynamic") && simpleState.options?.hasOwnProperty("static")) {
4359
4631
  setOptions(simpleState.options);
4360
4632
  }
@@ -4364,6 +4636,7 @@ function SelectorUI(props) {
4364
4636
  () => {
4365
4637
  const logicObj = {
4366
4638
  name: selectorIdentifier,
4639
+ component: selectorComponent,
4367
4640
  type: selectorType
4368
4641
  };
4369
4642
  let defaultValue;
@@ -4390,6 +4663,7 @@ function SelectorUI(props) {
4390
4663
  const simpleState2 = {
4391
4664
  name: selectorIdentifier,
4392
4665
  type: selectorType,
4666
+ component: selectorComponent,
4393
4667
  optionsType,
4394
4668
  options
4395
4669
  };
@@ -4418,6 +4692,15 @@ function SelectorUI(props) {
4418
4692
  data: Object.values(SELECTOR_TYPE)
4419
4693
  }
4420
4694
  ),
4695
+ selectorType === SELECTOR_TYPE.SINGLE && /* @__PURE__ */ jsx(
4696
+ Select,
4697
+ {
4698
+ label: "Selector Component",
4699
+ value: selectorComponent,
4700
+ onChange: setSelectorComponent,
4701
+ data: Object.values(SELECTOR_COMPONENT)
4702
+ }
4703
+ ),
4421
4704
  /* @__PURE__ */ jsx(
4422
4705
  Select,
4423
4706
  {
@@ -4518,7 +4801,9 @@ function TitlePreview({ title, tooltip, slug, settings }) {
4518
4801
  const tooltipHTML = sanitizeBlockContent_default(tooltip);
4519
4802
  const intOrder = settings && settings.order ? parseInt(settings.order, 10) : 1;
4520
4803
  const order = intOrder <= 6 ? intOrder : 1;
4521
- return /* @__PURE__ */ jsxs("div", { children: [
4804
+ const searchOnClick = settings && settings.search && settings.search !== "off" ? true : false;
4805
+ const searchType = settings && settings.search ? settings.search : "";
4806
+ return /* @__PURE__ */ jsxs(Group, { spacing: "sm", children: [
4522
4807
  tooltip && /* @__PURE__ */ jsx("div", { style: { position: "absolute", right: "50px" }, children: /* @__PURE__ */ jsx(Tooltip, { label: tooltipHTML, withArrow: true, withinPortal: true, children: /* @__PURE__ */ jsx(ActionIcon, { children: /* @__PURE__ */ jsx(IconInfoCircle, {}) }) }) }, "tooltip"),
4523
4808
  /* @__PURE__ */ jsx(
4524
4809
  Title,
@@ -4526,7 +4811,8 @@ function TitlePreview({ title, tooltip, slug, settings }) {
4526
4811
  order,
4527
4812
  dangerouslySetInnerHTML: { __html: titleHTML }
4528
4813
  }
4529
- )
4814
+ ),
4815
+ searchOnClick && /* @__PURE__ */ jsx(Tooltip, { label: `Click will open '${searchType}' report search`, children: /* @__PURE__ */ jsx(ActionIcon, { variant: "light", children: /* @__PURE__ */ jsx(IconSearch, { size: 20 }) }) })
4530
4816
  ] });
4531
4817
  }
4532
4818
 
@@ -4579,7 +4865,18 @@ function SelectorPreview(config) {
4579
4865
  };
4580
4866
  const { name } = config;
4581
4867
  return {
4582
- [SELECTOR_TYPES.SINGLE]: /* @__PURE__ */ jsx(
4868
+ [SELECTOR_TYPES.SINGLE]: config.component === SELECTOR_COMPONENTS.SEGMENTED_CONTROL ? /* @__PURE__ */ jsxs("div", { children: [
4869
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: name }),
4870
+ /* @__PURE__ */ jsx(
4871
+ SegmentedControl,
4872
+ {
4873
+ data,
4874
+ value,
4875
+ onChange: onChangeSingle,
4876
+ fullWidth: true
4877
+ }
4878
+ )
4879
+ ] }) : /* @__PURE__ */ jsx(
4583
4880
  Select,
4584
4881
  {
4585
4882
  label: name,
@@ -4971,7 +5268,6 @@ init_varSwap();
4971
5268
  init_mortarEval();
4972
5269
  init_envvars();
4973
5270
  init_runSelector();
4974
- init_block();
4975
5271
  function Block({ blockId, active = true }) {
4976
5272
  const { query, locale = localeDefault4 } = useRouter();
4977
5273
  const block = useBlockRef(blockId).data;
@@ -4984,8 +5280,9 @@ function Block({ blockId, active = true }) {
4984
5280
  locale
4985
5281
  };
4986
5282
  const generatorVariables = useAppSelector((state) => state.variables.variables[block.id] || {});
5283
+ const blockStatus = useAppSelector((state) => state.variables.status[block.id] || {});
4987
5284
  const [content, setContent] = useState(() => {
4988
- if (![BLOCK_TYPES.GENERATOR, BLOCK_TYPES.VIZ, BLOCK_TYPES.NAV].includes(block?.type)) {
5285
+ if (![BLOCK_TYPES.GENERATOR, BLOCK_TYPES.VIZ, BLOCK_TYPES.NAV].includes(block.type)) {
4989
5286
  if (block?.type === BLOCK_TYPES.SELECTOR) {
4990
5287
  const blockContent2 = getBlockContent(block, locale);
4991
5288
  const { config: renderVariables } = runSelector_default(blockContent2?.logic, formatterFunctions, blockContext);
@@ -5005,24 +5302,6 @@ function Block({ blockId, active = true }) {
5005
5302
  }
5006
5303
  return null;
5007
5304
  });
5008
- let allowed = true;
5009
- if (block && "allowed" in block.settings && block.settings.allowed !== "always") {
5010
- if (block.settings.allowed === "never") {
5011
- allowed = false;
5012
- } else {
5013
- const parsedBlockContext = parseBlockContext(blockContext);
5014
- const { vars, error, output } = mortarEval_default(
5015
- "variables",
5016
- variables,
5017
- block.settings.allowedLogic || "return false;",
5018
- formatterFunctions,
5019
- void 0,
5020
- parsedBlockContext
5021
- );
5022
- if (!error)
5023
- allowed = Boolean(output);
5024
- }
5025
- }
5026
5305
  useEffect(() => {
5027
5306
  const fetch = async () => {
5028
5307
  if (!block || block.type === BLOCK_TYPES.GENERATOR)
@@ -5077,7 +5356,7 @@ function Block({ blockId, active = true }) {
5077
5356
  };
5078
5357
  fetch();
5079
5358
  }, [blockContent, variables]);
5080
- if (!block || !content || !allowed)
5359
+ if (!block || !content || !blockStatus.allowed)
5081
5360
  return null;
5082
5361
  const Renderer = blocks_default[block.type];
5083
5362
  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 }) });
@@ -5906,7 +6185,8 @@ function DesignSectionMenu({ sectionId }) {
5906
6185
  return null;
5907
6186
  const {
5908
6187
  memberImageBg,
5909
- optionsMenu
6188
+ optionsMenu,
6189
+ hidden
5910
6190
  } = section.settings;
5911
6191
  return /* @__PURE__ */ jsxs(
5912
6192
  Popover,
@@ -5942,6 +6222,15 @@ function DesignSectionMenu({ sectionId }) {
5942
6222
  onChange: (e) => handleChange("optionsMenu", e.currentTarget.checked)
5943
6223
  }
5944
6224
  ),
6225
+ /* @__PURE__ */ jsx(
6226
+ Checkbox,
6227
+ {
6228
+ size: "xs",
6229
+ label: "Hide section",
6230
+ checked: hidden,
6231
+ onChange: (e) => handleChange("hidden", e.currentTarget.checked)
6232
+ }
6233
+ ),
5945
6234
  Object.entries(sectionSettings).map(([key, { label, defaultValue, options }]) => /* @__PURE__ */ jsxs(Group, { spacing: "xs", position: "apart", noWrap: true, style: { width: "100%" }, children: [
5946
6235
  label && /* @__PURE__ */ jsx(Text, { fz: "sm", children: label }),
5947
6236
  /* @__PURE__ */ jsx(
@@ -5981,6 +6270,9 @@ function SectionMenu({ sectionId }) {
5981
6270
  ] });
5982
6271
  }
5983
6272
  var SectionMenu_default = SectionMenu;
6273
+
6274
+ // frontend/components/report/Section.tsx
6275
+ init_cms();
5984
6276
  var getStyles = (styles, settings) => (theme) => styles ? styles(theme, settings) : {};
5985
6277
  var PositionWrapper = ({ settings, styles, children, ...props }) => {
5986
6278
  const { position } = settings;
@@ -6045,11 +6337,20 @@ function Section({ section }) {
6045
6337
  ...settings
6046
6338
  };
6047
6339
  const state = useAppSelector((state2) => state2);
6340
+ const status = useAppSelector((state2) => state2.variables.status);
6048
6341
  const sectionStyles = useBespokeStyles()["Section"];
6049
6342
  const blockRecords = selectBlockRecords(state);
6050
6343
  const theme = useMantineTheme();
6051
6344
  const smallScreen = useMediaQuery(`(max-width: ${theme.breakpoints.sm}px)`);
6052
- const columns = Object.values(blockRecords || {}).filter((d) => d.section_id === id).reduce((acc, d) => {
6345
+ const sectionBlocks = Object.values(blockRecords || {}).filter((d) => d.section_id === id);
6346
+ const allowedSection = sectionBlocks.some((b) => {
6347
+ try {
6348
+ return status[b.id].allowed && b.type !== BLOCK_TYPES.GENERATOR;
6349
+ } catch (e) {
6350
+ return b.settings.allowed === "always";
6351
+ }
6352
+ });
6353
+ const columns = sectionBlocks.reduce((acc, d) => {
6053
6354
  if (!acc[d.blockcol]) {
6054
6355
  acc[d.blockcol] = { [d.blockrow]: d };
6055
6356
  } else {
@@ -6057,6 +6358,9 @@ function Section({ section }) {
6057
6358
  }
6058
6359
  return acc;
6059
6360
  }, {});
6361
+ const displaySection = Object.keys(blockRecords).length > 0 && !settings.hidden && allowedSection;
6362
+ if (!displaySection)
6363
+ return null;
6060
6364
  return /* @__PURE__ */ jsxs(
6061
6365
  PositionWrapper,
6062
6366
  {
@@ -6295,8 +6599,14 @@ init_esm_shims();
6295
6599
 
6296
6600
  // components/builder/JumpTo.tsx
6297
6601
  init_esm_shims();
6602
+ init_store2();
6298
6603
  function JumpTo() {
6299
- const contentOutline = useContentOutline();
6604
+ const blocks = useBlockList();
6605
+ const titleBlocks = useMemo(
6606
+ () => blocks.data ? blocks.data.filter((d) => d.type === "title").map((d) => d.id) : [],
6607
+ [blocks.data]
6608
+ );
6609
+ const contentOutline = useContentOutline(1, 6, titleBlocks);
6300
6610
  const handleClick = (blockId) => {
6301
6611
  const section = document.getElementById(`title-${blockId}`);
6302
6612
  if (section) {
@@ -6308,7 +6618,7 @@ function JumpTo() {
6308
6618
  if (!nodes) {
6309
6619
  return null;
6310
6620
  }
6311
- return /* @__PURE__ */ jsx(Fragment, { children: nodes.map((node) => /* @__PURE__ */ jsxs(Fragment, { children: [
6621
+ return /* @__PURE__ */ jsx(Fragment, { children: nodes.map((node) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
6312
6622
  /* @__PURE__ */ jsx(
6313
6623
  Menu.Item,
6314
6624
  {
@@ -6316,11 +6626,10 @@ function JumpTo() {
6316
6626
  onClick: () => handleClick(node.id),
6317
6627
  pl: 10 * node.order,
6318
6628
  children: node.label
6319
- },
6320
- `jump-key-${node.id}`
6629
+ }
6321
6630
  ),
6322
6631
  renderOutline(node.children)
6323
- ] })) });
6632
+ ] }, `jump-key-${node.id}`)) });
6324
6633
  };
6325
6634
  return /* @__PURE__ */ jsx("div", { style: { position: "fixed", bottom: 10, right: 10, zIndex: 10 }, children: /* @__PURE__ */ jsxs(Menu, { shadow: "md", position: "top-end", offset: 0, children: [
6326
6635
  /* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(ActionIcon, { variant: "filled", color: "blue", children: /* @__PURE__ */ jsx(IconListSearch, {}) }) }),
@@ -7141,12 +7450,13 @@ function VariantEditor({ for: variant, onClose: closeHandler }) {
7141
7450
  ),
7142
7451
  variantConfig.config[selectedLocale] && /* @__PURE__ */ jsxs(Fragment, { children: [
7143
7452
  /* @__PURE__ */ jsx(Space, { h: "lg" }),
7144
- /* @__PURE__ */ jsxs(Group, { grow: true, children: [
7453
+ /* @__PURE__ */ jsxs(Group, { grow: true, align: "flex-end", children: [
7145
7454
  /* @__PURE__ */ jsx(
7146
7455
  TextInput,
7147
7456
  {
7148
7457
  onChange: (e) => onChangeConfig("path", e.target.value),
7149
- placeholder: "Enter a source API",
7458
+ title: "Api endpoint",
7459
+ description: "Enter the url to retrieve a member list to ingest. (JSON) and click Fetch.",
7150
7460
  value: variantConfig.config[selectedLocale].path
7151
7461
  }
7152
7462
  ),
@@ -7167,19 +7477,24 @@ function VariantEditor({ for: variant, onClose: closeHandler }) {
7167
7477
  Select,
7168
7478
  {
7169
7479
  value: variantConfig.config[selectedLocale].accessor,
7170
- label: "Accessor property (array)",
7480
+ label: "Elements",
7481
+ description: "Choose the key that returns the array of elements that \n are going to be ingested as members.",
7171
7482
  data: accessorSelectData,
7483
+ disabled: accessorSelectData.length === 0,
7484
+ placeholder: accessorSelectData.length === 0 ? "Root is an array" : "",
7172
7485
  onChange: (e) => onChangeAccessor(e)
7173
7486
  }
7174
7487
  ),
7175
7488
  /* @__PURE__ */ jsx(Divider, { label: "First element preview", labelPosition: "center" }),
7176
- payload[variantConfig.config[selectedLocale].accessor] && /* @__PURE__ */ jsx(InputMenuItem_default, { variables: payload[variantConfig.config[selectedLocale].accessor][0] }),
7489
+ payload[variantConfig.config[selectedLocale].accessor] && !Array.isArray(payload) && /* @__PURE__ */ jsx(InputMenuItem_default, { variables: payload[variantConfig.config[selectedLocale].accessor][0] }),
7490
+ Array.isArray(payload) && payload[0] && /* @__PURE__ */ jsx(InputMenuItem_default, { variables: payload[0] }),
7177
7491
  /* @__PURE__ */ jsx(Space, { h: "md" }),
7178
7492
  /* @__PURE__ */ jsx(
7179
7493
  Select,
7180
7494
  {
7181
7495
  value: variantConfig.config[selectedLocale].idKey,
7182
- label: "Key property",
7496
+ label: "Unique identificator",
7497
+ description: "Choose the field that is a unique identification for a single member.",
7183
7498
  data: keys,
7184
7499
  onChange: (e) => onChangeConfig("idKey", e)
7185
7500
  }
@@ -7189,13 +7504,29 @@ function VariantEditor({ for: variant, onClose: closeHandler }) {
7189
7504
  Select,
7190
7505
  {
7191
7506
  value: variantConfig.config[selectedLocale].labelKey,
7192
- label: "Label property",
7507
+ label: "Members' name",
7508
+ description: "Choose the field that contains the members name.",
7193
7509
  data: keys,
7194
7510
  onChange: (e) => onChangeConfig("labelKey", e)
7195
7511
  }
7196
7512
  ),
7197
7513
  /* @__PURE__ */ jsx(Space, { h: "md" }),
7514
+ /* @__PURE__ */ jsx(
7515
+ Select,
7516
+ {
7517
+ value: variantConfig.config[selectedLocale].zValueKey || "",
7518
+ label: "Member's relevance (optional)",
7519
+ description: "Choose a field that will be converted to a number and \n normalized from 0 to 1 to determine the member's relevance.",
7520
+ data: [
7521
+ { value: "null", label: "None" },
7522
+ ...keys
7523
+ ],
7524
+ onChange: (e) => onChangeConfig("zValueKey", e)
7525
+ }
7526
+ ),
7527
+ /* @__PURE__ */ jsx(Space, { h: "md" }),
7198
7528
  /* @__PURE__ */ jsx(Title, { order: 3, size: "h5", children: "Attributes" }),
7529
+ /* @__PURE__ */ jsx(Text, { size: "sm", children: "Attributes are properties to be ingested as metadata with the member element. Could be constants (same value for every member) or dynamic (based on a property of the data)" }),
7199
7530
  /* @__PURE__ */ jsx(Space, { h: "xs" }),
7200
7531
  variantConfig.config[selectedLocale].attributes && variantConfig.config[selectedLocale].attributes.map((attr, ix) => /* @__PURE__ */ jsxs(Group, { align: "end", grow: true, children: [
7201
7532
  /* @__PURE__ */ jsx(
@@ -7292,7 +7623,7 @@ function VariantEditor({ for: variant, onClose: closeHandler }) {
7292
7623
  }
7293
7624
  )
7294
7625
  ] }),
7295
- size: 145
7626
+ size: 165
7296
7627
  }
7297
7628
  );
7298
7629
  }
@@ -7371,7 +7702,7 @@ function DimensionEditor({ id, onClose: closeHandler }) {
7371
7702
  /* @__PURE__ */ jsx(Button, { variant: "outline", disabled: loading, loading, onClick: closeHandler, children: "Cancel" }),
7372
7703
  /* @__PURE__ */ jsx(Button, { disabled: loading, loading, onClick: submitHandler, children: "Save Dimension" })
7373
7704
  ] }),
7374
- size: 145
7705
+ size: 165
7375
7706
  }
7376
7707
  );
7377
7708
  }
@@ -7442,7 +7773,7 @@ function ReportEditor({ id, onClose: closeHandler }) {
7442
7773
  /* @__PURE__ */ jsx(Button, { variant: "outline", disabled: loading, loading, onClick: closeHandler, children: "Cancel" }),
7443
7774
  /* @__PURE__ */ jsx(Button, { disabled: loading, loading, onClick: submitHandler, children: "Save Report" })
7444
7775
  ] }),
7445
- size: 145
7776
+ size: 165
7446
7777
  }
7447
7778
  );
7448
7779
  }
@@ -7463,17 +7794,155 @@ function HeaderLayout(props) {
7463
7794
 
7464
7795
  // components/builder/CMSHeader.tsx
7465
7796
  init_statusSlice();
7797
+ init_hooks();
7798
+
7799
+ // components/builder/BlockGraph.tsx
7800
+ init_esm_shims();
7801
+ init_store2();
7802
+ function BlockGraph() {
7803
+ const [screenWidth, setScreenWidth] = useState(window.innerWidth - 40);
7804
+ const [screenHeight, setScreenHeight] = useState(window.innerHeight - 150);
7805
+ useEffect(() => {
7806
+ const handleResize = () => {
7807
+ setScreenWidth(window.innerWidth - 40);
7808
+ setScreenHeight(window.innerHeight - 120);
7809
+ };
7810
+ window.addEventListener("resize", handleResize);
7811
+ return () => {
7812
+ window.removeEventListener("resize", handleResize);
7813
+ };
7814
+ }, []);
7815
+ const blocks = useBlockList();
7816
+ const sections = useSectionList();
7817
+ const [sectionSelected, setSectionSelected] = useState(null);
7818
+ const sectionList = useMemo(() => {
7819
+ if (sections.isSuccess) {
7820
+ const sectionsOptions = sections.data.map((n) => ({
7821
+ value: `${n.id}`,
7822
+ label: `Section ${n.id}`
7823
+ }));
7824
+ setSectionSelected(sectionsOptions[0].value);
7825
+ return sectionsOptions;
7826
+ } else {
7827
+ return [];
7828
+ }
7829
+ }, [sections.isLoading]);
7830
+ const data = useMemo(() => {
7831
+ if (blocks.isSuccess && sectionSelected) {
7832
+ const rootNode = { id: "root", label: "section", size: 40, parentIds: [] };
7833
+ const globalNode = { id: "wide", label: "report", size: 40, parentIds: [] };
7834
+ const sectionBlocks = blocks.data.filter((n) => `${n.section_id}` === `${sectionSelected}`);
7835
+ const sectionBlocksIds = sectionBlocks.map((n) => n.id);
7836
+ return [
7837
+ rootNode,
7838
+ globalNode,
7839
+ ...sectionBlocks.map((n) => {
7840
+ const projectedSize = n.consumers.length > 0 ? n.consumers.length * 20 : 40;
7841
+ const parentIds = n.inputs.length > 0 ? n.inputs.map((i) => sectionBlocksIds.includes(i) ? `${i}` : `${globalNode.id}`) : [`${rootNode.id}`];
7842
+ return {
7843
+ id: `${n.id}`,
7844
+ label: `${n.type}`,
7845
+ size: projectedSize > 50 ? 50 : projectedSize,
7846
+ parentIds: [...Array.from(new Set(parentIds))]
7847
+ };
7848
+ })
7849
+ ];
7850
+ } else {
7851
+ return [];
7852
+ }
7853
+ }, [blocks.isLoading, sectionSelected]);
7854
+ const svgRef = useRef(null);
7855
+ useEffect(() => {
7856
+ const dag = d3Dag.dagStratify()(data);
7857
+ const nodeRadius = 40;
7858
+ const layout = d3Dag.sugiyama().nodeSize((node) => {
7859
+ const data2 = node ? node.data : null;
7860
+ const internalRadius = data2 ? data2.size : nodeRadius;
7861
+ return [(node ? 3.6 : 0.25) * internalRadius, 3 * internalRadius];
7862
+ });
7863
+ const { width, height } = layout(dag);
7864
+ const svgSelection = d3.select(svgRef.current);
7865
+ svgSelection.selectAll("*").remove();
7866
+ svgSelection.attr("viewBox", [0, 0, width, height].join(" "));
7867
+ const defs = svgSelection.append("defs");
7868
+ const steps = dag.size();
7869
+ const interp = d3.interpolateRainbow;
7870
+ const colorMap = /* @__PURE__ */ new Map();
7871
+ data.forEach((node, i) => {
7872
+ colorMap.set(node.id, interp(i / steps));
7873
+ });
7874
+ const line2 = d3.line().curve(d3.curveCatmullRom).x((d) => d.x).y((d) => d.y);
7875
+ const paths = svgSelection.append("g").selectAll("g").data(dag.links()).enter().append("g");
7876
+ paths.append("path").attr("class", "curve").attr("d", ({ points }) => line2(points)).attr("fill", "none").attr("stroke-width", 3).attr("stroke", ({ source, target }) => {
7877
+ const gradId = encodeURIComponent(`${source.data.id}--${target.data.id}`);
7878
+ const grad = defs.append("linearGradient").attr("id", gradId).attr("gradientUnits", "userSpaceOnUse").attr("x1", source.x).attr("x2", target.x).attr("y1", source.y).attr("y2", target.y);
7879
+ grad.append("stop").attr("offset", "0%").attr("stop-color", colorMap.get(source.data.id));
7880
+ grad.append("stop").attr("offset", "100%").attr("stop-color", colorMap.get(target.data.id));
7881
+ return `url(#${gradId})`;
7882
+ });
7883
+ const nodes = svgSelection.append("g").selectAll("g").data(dag.descendants()).enter().append("g").attr("transform", ({ x, y }) => `translate(${x}, ${y})`);
7884
+ nodes.append("circle").attr("r", (n) => n.data.size).attr("fill", (n) => colorMap.get(n.data.id));
7885
+ const arrows = svgSelection.append("g").selectAll("g").data(dag.links()).enter().append("g");
7886
+ const arrow = d3.symbol().type(d3.symbolTriangle).size(nodeRadius * 1.5);
7887
+ arrows.append("path").attr("class", "arrow").attr("d", arrow).attr("transform", (link) => {
7888
+ const { points, target } = link;
7889
+ const [end, start] = points.reverse();
7890
+ const dx = start.x - end.x;
7891
+ const dy = start.y - end.y;
7892
+ const scale = target.data.size * 1 / Math.sqrt(dx * dx + dy * dy);
7893
+ const angle = Math.atan2(-dy, -dx) * 180 / Math.PI + 90;
7894
+ return `translate(${end.x + dx * scale}, ${end.y + dy * scale}) rotate(${angle})`;
7895
+ }).attr("fill", ({ target }) => colorMap.get(target.data.id)).attr("stroke", "white");
7896
+ const texts = svgSelection.append("g").selectAll("g").data(dag.descendants()).enter().append("g").attr("transform", ({ x, y }) => `translate(${x}, ${y})`);
7897
+ texts.append("text").text((d) => d.data.id).attr("font-weight", "bold").attr("font-family", "sans-serif").attr("text-anchor", "middle").attr("font-size", "10px").style("transform", "translate(0px,10px)").attr("alignment-baseline", "middle").attr("fill", "black");
7898
+ texts.append("text").text((d) => d.data.label).attr("font-weight", "bold").attr("font-family", "sans-serif").attr("font-size", "15px").style("transform", "translate(0px,-5px)").attr("text-anchor", "middle").attr("alignment-baseline", "middle").attr("fill", "black");
7899
+ }, [data]);
7900
+ const handlePrev = () => {
7901
+ const currentIndex = sectionList.findIndex((item) => item.value === sectionSelected);
7902
+ if (currentIndex > 0) {
7903
+ setSectionSelected(sectionList[currentIndex - 1].value);
7904
+ }
7905
+ };
7906
+ const handleNext = () => {
7907
+ const currentIndex = sectionList.findIndex((item) => item.value === sectionSelected);
7908
+ if (currentIndex < sectionList.length - 1) {
7909
+ setSectionSelected(sectionList[currentIndex + 1].value);
7910
+ }
7911
+ };
7912
+ return /* @__PURE__ */ jsxs(Stack, { spacing: 0, children: [
7913
+ /* @__PURE__ */ jsxs(Group, { align: "flex-end", w: "100%", position: "apart", children: [
7914
+ /* @__PURE__ */ jsx(
7915
+ Select,
7916
+ {
7917
+ label: "Chooose a section",
7918
+ placeholder: "Pick one",
7919
+ value: sectionSelected,
7920
+ onChange: setSectionSelected,
7921
+ data: sectionList,
7922
+ width: "80%"
7923
+ }
7924
+ ),
7925
+ /* @__PURE__ */ jsxs(Group, { grow: true, maw: 100, children: [
7926
+ /* @__PURE__ */ jsx(ActionIcon, { onClick: handlePrev, variant: "outline", children: /* @__PURE__ */ jsx(IconChevronLeft, { size: "1.125rem" }) }),
7927
+ /* @__PURE__ */ jsx(ActionIcon, { onClick: handleNext, variant: "outline", children: /* @__PURE__ */ jsx(IconChevronRight, { size: "1.125rem" }) })
7928
+ ] })
7929
+ ] }),
7930
+ /* @__PURE__ */ jsx("svg", { ref: svgRef, width: screenWidth, height: screenHeight })
7931
+ ] });
7932
+ }
7466
7933
  function CMSHeader(props) {
7467
- const { report: currentReport, profilePrefix } = props;
7934
+ const { report: currentReport } = props;
7468
7935
  const { id } = currentReport;
7469
7936
  const { newConfirmation } = useDialog();
7470
7937
  const dispatch = useAppDispatch();
7471
7938
  const resource = useContext(ResourceContext);
7939
+ const profilePrefix = useProfilePrefix();
7472
7940
  const currentLocale = useAppSelector((state) => state.status.currentLocale);
7473
7941
  const localeDefault9 = useAppSelector((state) => state.status.localeDefault);
7474
7942
  const localeOptions = useAppSelector(selectLocaleOptions);
7475
7943
  const previewsFromState = useAppSelector((state) => state.status.previews);
7476
7944
  const [opened, handlers] = useDisclosure(false);
7945
+ const [openedGraph, handlersGraph] = useDisclosure(false);
7477
7946
  const { user } = useUser();
7478
7947
  const castedUser = user;
7479
7948
  const dimensions = useMemo(() => {
@@ -7651,9 +8120,11 @@ function CMSHeader(props) {
7651
8120
  /* @__PURE__ */ jsx(Text, { fw: 700, children: currentReport.name })
7652
8121
  ] }) }),
7653
8122
  /* @__PURE__ */ jsx(Menu.Label, { children: "Settings" }),
7654
- /* @__PURE__ */ jsx(Menu.Item, { onClick: handlers.open, icon: /* @__PURE__ */ jsx(IconSettings, { size: 20 }), children: "Report settings" })
8123
+ /* @__PURE__ */ jsx(Menu.Item, { onClick: handlers.open, icon: /* @__PURE__ */ jsx(IconSettings, { size: 20 }), children: "Report settings" }),
8124
+ /* @__PURE__ */ jsx(Menu.Item, { onClick: handlersGraph.open, icon: /* @__PURE__ */ jsx(IconHierarchy3, { size: 20 }), children: "Block Graph" })
7655
8125
  ] })
7656
8126
  ] }),
8127
+ /* @__PURE__ */ jsx(Modal, { opened: openedGraph, onClose: handlersGraph.close, title: "Block Graph", fullScreen: true, children: /* @__PURE__ */ jsx(BlockGraph, {}) }),
7657
8128
  /* @__PURE__ */ jsx(
7658
8129
  Drawer,
7659
8130
  {
@@ -7747,6 +8218,15 @@ var customSettings = {
7747
8218
  { label: "6", value: "6" }
7748
8219
  ]
7749
8220
  },
8221
+ search: {
8222
+ label: "Search on Click",
8223
+ defaultValue: "off",
8224
+ options: [
8225
+ { label: "Off", value: "off" },
8226
+ { label: "Inline", value: "inline" },
8227
+ { label: "Modal", value: "modal" }
8228
+ ]
8229
+ },
7750
8230
  ...defaultSettings2
7751
8231
  },
7752
8232
  [BLOCK_TYPES.GENERATOR]: {
@@ -7760,8 +8240,8 @@ var customSettings = {
7760
8240
  }
7761
8241
  },
7762
8242
  [BLOCK_TYPES.NAV]: {
7763
- type: {
7764
- label: "Nav type",
8243
+ variant: {
8244
+ label: "Nav variant",
7765
8245
  defaultValue: "inline",
7766
8246
  options: [
7767
8247
  { label: "Inline", value: "inline" },
@@ -8039,7 +8519,8 @@ var emptyStatus = {
8039
8519
  duration: null,
8040
8520
  error: null,
8041
8521
  log: [],
8042
- resp: null
8522
+ resp: null,
8523
+ allowed: true
8043
8524
  };
8044
8525
  function BlockPreview(props) {
8045
8526
  const {
@@ -9324,13 +9805,15 @@ function SectionHeader({
9324
9805
  active,
9325
9806
  isDragging,
9326
9807
  id,
9327
- dragHandleProps
9808
+ dragHandleProps,
9809
+ hidden
9328
9810
  }) {
9329
9811
  return /* @__PURE__ */ jsxs(
9330
9812
  Group,
9331
9813
  {
9332
9814
  className: `cms-section-header${active || isDragging ? " active" : ""}`,
9333
9815
  position: "apart",
9816
+ bg: hidden ? "red.1" : "none",
9334
9817
  children: [
9335
9818
  /* @__PURE__ */ jsxs(Group, { className: "cms-section-header-editor", spacing: 0, children: [
9336
9819
  /* @__PURE__ */ jsxs(Code, { style: { backgroundColor: "transparent" }, children: [
@@ -9339,6 +9822,7 @@ function SectionHeader({
9339
9822
  ] }, "s1"),
9340
9823
  /* @__PURE__ */ jsx(ActionIcon, { ...dragHandleProps, children: /* @__PURE__ */ jsx(IconMenu, { size: 16 }) }, "b1")
9341
9824
  ] }),
9825
+ hidden && /* @__PURE__ */ jsx(Text, { size: "xs", fw: 600, color: "dark.3", children: "Section will be hidden on the frontend" }),
9342
9826
  /* @__PURE__ */ jsx(SectionMenu_default, { sectionId: id })
9343
9827
  ]
9344
9828
  }
@@ -9360,7 +9844,7 @@ function SectionEditor({
9360
9844
  const [sectionState, setSectionState2] = useSetState({});
9361
9845
  const blocks = useAppSelector((state) => state.records.entities.block);
9362
9846
  const blockSettings = getBlockSettings();
9363
- const { memberImageBg, optionsMenu } = section.settings;
9847
+ const { memberImageBg, optionsMenu, hidden } = section.settings;
9364
9848
  const [hoverBlock, setHoverBlock] = useState();
9365
9849
  const { inputs, consumers } = useMemo(() => {
9366
9850
  if (hoverBlock) {
@@ -9473,6 +9957,7 @@ function SectionEditor({
9473
9957
  active: isActive,
9474
9958
  id: section.id,
9475
9959
  isDragging,
9960
+ hidden,
9476
9961
  dragHandleProps
9477
9962
  }
9478
9963
  ),
@@ -9645,7 +10130,7 @@ init_ordering();
9645
10130
  init_store2();
9646
10131
  init_actions();
9647
10132
  function BuilderEditor(props) {
9648
- const { profilePrefix, id } = props;
10133
+ const { id } = props;
9649
10134
  const reportRef = useReportRef(id);
9650
10135
  return useMemo(() => {
9651
10136
  if (reportRef.isError) {
@@ -9659,14 +10144,13 @@ function BuilderEditor(props) {
9659
10144
  {
9660
10145
  report: reportRef.data,
9661
10146
  locale: props.locale,
9662
- isLoading: reportRef.isFetching,
9663
- profilePrefix
10147
+ isLoading: reportRef.isFetching
9664
10148
  }
9665
10149
  );
9666
10150
  }, [reportRef.status, reportRef.data?.sections]);
9667
10151
  }
9668
10152
  function InteractiveReport(props) {
9669
- const { report, isLoading, profilePrefix } = props;
10153
+ const { report, isLoading } = props;
9670
10154
  const theme = useMantineTheme();
9671
10155
  const dispatch = useAppDispatch();
9672
10156
  const resource = useContext(ResourceContext);
@@ -9744,7 +10228,7 @@ function InteractiveReport(props) {
9744
10228
  }
9745
10229
  ), [sectionOrder, activeSection, maybeActivate]);
9746
10230
  return /* @__PURE__ */ jsxs(Stack, { styles: { backgroundColor: theme.colors.gray[2] }, spacing: 0, children: [
9747
- /* @__PURE__ */ jsx(CMSHeader, { report, profilePrefix }),
10231
+ /* @__PURE__ */ jsx(CMSHeader, { report }),
9748
10232
  /* @__PURE__ */ jsxs(Alert, { icon: /* @__PURE__ */ jsx(IconFlag, {}), children: [
9749
10233
  "You are editing the ",
9750
10234
  /* @__PURE__ */ jsx(Code, { children: currentLocale.toUpperCase() }),
@@ -10112,7 +10596,7 @@ function FormatterForm({ formatterId, onEditEnd }) {
10112
10596
  }
10113
10597
  )
10114
10598
  ] }),
10115
- size: 145
10599
+ size: 165
10116
10600
  }
10117
10601
  )
10118
10602
  }
@@ -11054,7 +11538,7 @@ function MemberForm({ memberId, onEditEnd }) {
11054
11538
  }
11055
11539
  )
11056
11540
  ] }),
11057
- size: 145
11541
+ size: 165
11058
11542
  }
11059
11543
  )
11060
11544
  }
@@ -11106,6 +11590,11 @@ function MembersTable({ members, onClickEdit, onSort }) {
11106
11590
  title: "Variant",
11107
11591
  accessor: "variant.name"
11108
11592
  },
11593
+ {
11594
+ title: "Relevance",
11595
+ sortable: true,
11596
+ accessor: "zvalue"
11597
+ },
11109
11598
  {
11110
11599
  title: "Slug",
11111
11600
  accessor: "slug",
@@ -11217,8 +11706,8 @@ function MetadataEditor() {
11217
11706
  ...getParams,
11218
11707
  locale: "all",
11219
11708
  includes: true,
11220
- sort: internalSort ? internalSort.columnAccessor : "id",
11221
- direction: internalSort ? internalSort.direction : "asc"
11709
+ sort: internalSort ? internalSort.columnAccessor : "zvalue",
11710
+ direction: internalSort ? internalSort.direction : "desc"
11222
11711
  }
11223
11712
  }
11224
11713
  ).then((response) => response.data && response.data.data && response.data.data.results ? response.data.data.results : []);
@@ -11807,7 +12296,7 @@ function UserForm({ userId, onEditEnd, roles }) {
11807
12296
  }
11808
12297
  )
11809
12298
  ] }),
11810
- size: 145
12299
+ size: 165
11811
12300
  }
11812
12301
  )
11813
12302
  }
@@ -11997,7 +12486,7 @@ function BespokeManager(options) {
11997
12486
  title = "Bespoke CMS",
11998
12487
  pathSegment = "bespoke",
11999
12488
  locale = localeDefault4,
12000
- profilePrefix
12489
+ profilePrefix = "/profilePathManager"
12001
12490
  } = options;
12002
12491
  const notifications3 = {
12003
12492
  position: "bottom-center",
@@ -12009,17 +12498,17 @@ function BespokeManager(options) {
12009
12498
  FailureComponent: UnauthorizeView
12010
12499
  });
12011
12500
  function BespokeManagerPage() {
12012
- return /* @__PURE__ */ jsxs(ResourceProvider, { pathSegment, children: [
12501
+ return /* @__PURE__ */ jsxs(ResourceProvider, { pathSegment, profilePrefix, children: [
12013
12502
  /* @__PURE__ */ jsx(Head, { children: /* @__PURE__ */ jsx("title", { children: title }) }),
12014
12503
  /* @__PURE__ */ jsxs(MantineProvider, { inherit: false, children: [
12015
12504
  /* @__PURE__ */ jsx(Notifications, { ...notifications3 }),
12016
- /* @__PURE__ */ jsx(DialogProvider, { children: /* @__PURE__ */ jsx(BespokeManagerShell, { locale, profilePrefix }) })
12505
+ /* @__PURE__ */ jsx(DialogProvider, { children: /* @__PURE__ */ jsx(BespokeManagerShell, { locale }) })
12017
12506
  ] })
12018
12507
  ] });
12019
12508
  }
12020
12509
  }
12021
12510
  function BespokeManagerShell(props) {
12022
- const { locale, profilePrefix } = props;
12511
+ const { locale } = props;
12023
12512
  const [opened, { toggle: toggleOpened }] = useDisclosure(true);
12024
12513
  const { user, error, isLoading } = useUser();
12025
12514
  const location = useManagerLocation();
@@ -12145,7 +12634,7 @@ function BespokeManagerShell(props) {
12145
12634
  if (location.page === "reports") {
12146
12635
  if (location.params.length > 0) {
12147
12636
  const reportId = Number.parseInt(location.params[0]);
12148
- return /* @__PURE__ */ jsx(BuilderEditor, { id: reportId, locale, profilePrefix });
12637
+ return /* @__PURE__ */ jsx(BuilderEditor, { id: reportId, locale });
12149
12638
  }
12150
12639
  return /* @__PURE__ */ jsx(ReportPicker, {});
12151
12640
  }
@@ -12196,12 +12685,13 @@ init_ResourceProvider();
12196
12685
  function BespokeRenderer({
12197
12686
  pathSegmentsKey = "bespoke",
12198
12687
  bespokeStyles,
12199
- buildTime
12688
+ buildTime,
12689
+ profilePrefix = "/defaultPath"
12200
12690
  }) {
12201
12691
  const loading = useInitialState(pathSegmentsKey);
12202
12692
  if (loading)
12203
12693
  return /* @__PURE__ */ jsx(LoadingOverlay, { visible: true });
12204
- return /* @__PURE__ */ jsx(MantineProvider, { theme: { other: { bespokeStyles } }, inherit: true, children: /* @__PURE__ */ jsxs(ResourceProvider, { pathSegment: "bespoke", children: [
12694
+ return /* @__PURE__ */ jsx(MantineProvider, { theme: { other: { bespokeStyles } }, inherit: true, children: /* @__PURE__ */ jsxs(ResourceProvider, { pathSegment: "bespoke", profilePrefix, children: [
12205
12695
  /* @__PURE__ */ jsx(Report_default, {}),
12206
12696
  /* @__PURE__ */ jsx("small", { children: buildTime })
12207
12697
  ] }) });