@datawheel/bespoke 0.1.26 → 0.1.27

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 +599 -136
  2. package/dist/server.js +106 -45
  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,6 +1085,7 @@ 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;
@@ -1115,7 +1123,8 @@ async function runSingleBlock(block, formatterFunctions, blockContext, readMembe
1115
1123
  duration: null,
1116
1124
  resp: null,
1117
1125
  log: log2,
1118
- error: error2
1126
+ error: error2,
1127
+ allowed
1119
1128
  }
1120
1129
  };
1121
1130
  }
@@ -1129,7 +1138,8 @@ async function runSingleBlock(block, formatterFunctions, blockContext, readMembe
1129
1138
  duration: null,
1130
1139
  resp: null,
1131
1140
  log: [],
1132
- error: null
1141
+ error: null,
1142
+ allowed
1133
1143
  }
1134
1144
  };
1135
1145
  }
@@ -1146,7 +1156,8 @@ async function runSingleBlock(block, formatterFunctions, blockContext, readMembe
1146
1156
  log,
1147
1157
  duration,
1148
1158
  resp,
1149
- api
1159
+ api,
1160
+ allowed
1150
1161
  }
1151
1162
  };
1152
1163
  }
@@ -1159,11 +1170,12 @@ async function runSingleBlock(block, formatterFunctions, blockContext, readMembe
1159
1170
  error,
1160
1171
  duration,
1161
1172
  resp,
1162
- api
1173
+ api,
1174
+ allowed
1163
1175
  }
1164
1176
  };
1165
1177
  }
1166
- var verbose2, ORIGIN, swapAPI, urlProxy, getDependencies, runConsumersV2, getDurationColor, getSizeColor;
1178
+ var verbose2, ORIGIN, swapAPI, urlProxy, getDependencies, isBlockAllowed, runConsumersV2, getDurationColor, getSizeColor;
1167
1179
  var init_runConsumers = __esm({
1168
1180
  "libs/blocks/runConsumers.ts"() {
1169
1181
  init_esm_shims();
@@ -1195,27 +1207,51 @@ var init_runConsumers = __esm({
1195
1207
  return url;
1196
1208
  };
1197
1209
  ({ urlProxy } = apiFactory("/api/cms"));
1198
- getDependencies = (bid, blocks, acc = [], crawlUp = true, crawlDown = true) => {
1210
+ getDependencies = (bid, blocks, acc = [], crawlUp = true, crawlDown = true, withinSection = true, visited = []) => {
1211
+ if (visited.includes(bid))
1212
+ return [];
1213
+ visited.push(bid);
1199
1214
  const rootBlock = blocks[bid];
1200
1215
  if (rootBlock.inputs.length && crawlUp) {
1201
1216
  rootBlock.inputs.forEach((iid) => {
1202
1217
  const rel = `${iid}-${bid}`;
1203
1218
  if (!acc.includes(rel))
1204
1219
  acc.push(rel);
1205
- rootBlock.inputs.forEach((iid2) => getDependencies(iid2, blocks, acc, crawlUp, false));
1220
+ rootBlock.inputs.forEach((iid2) => getDependencies(iid2, blocks, acc, crawlUp, false, withinSection, visited));
1206
1221
  });
1207
1222
  }
1208
1223
  if (rootBlock.consumers.length && crawlDown) {
1209
1224
  rootBlock.consumers.forEach((cid) => {
1210
1225
  const rel = `${bid}-${cid}`;
1211
- if (!acc.includes(rel) && blocks[cid].section_id === blocks[bid].section_id)
1226
+ if (!acc.includes(rel) && (blocks[cid].section_id === blocks[bid].section_id || !withinSection))
1212
1227
  acc.push(rel);
1213
- rootBlock.consumers.filter((cid2) => blocks[cid2].section_id === blocks[bid].section_id).forEach((cid2) => getDependencies(cid2, blocks, acc, crawlUp, crawlDown));
1228
+ rootBlock.consumers.filter((cid2) => blocks[cid2].section_id === blocks[bid].section_id || !withinSection).forEach((cid2) => getDependencies(cid2, blocks, acc, crawlUp, crawlDown, withinSection, visited));
1214
1229
  });
1215
1230
  }
1216
1231
  return acc;
1217
1232
  };
1218
- runConsumersV2 = async (blocks, sections, bid, formatterFunctions, blockContext, initialVariables = {}, readMemberFn) => {
1233
+ isBlockAllowed = (block, blockContext, variables, formatterFunctions) => {
1234
+ let allowed = true;
1235
+ if (block && "allowed" in block.settings && block.settings.allowed !== "always") {
1236
+ if (block.settings.allowed === "never") {
1237
+ allowed = false;
1238
+ } else {
1239
+ const parsedBlockContext = parseBlockContext(blockContext);
1240
+ const { vars, error, output } = mortarEval_default(
1241
+ "variables",
1242
+ variables,
1243
+ block.settings.allowedLogic || "return false;",
1244
+ formatterFunctions,
1245
+ void 0,
1246
+ parsedBlockContext
1247
+ );
1248
+ if (!error)
1249
+ allowed = Boolean(output);
1250
+ }
1251
+ }
1252
+ return allowed;
1253
+ };
1254
+ runConsumersV2 = async (blocks, sections, bid, formatterFunctions, blockContext, initialVariables = {}, readMemberFn, mode = "section") => {
1219
1255
  if (!bid && !sections)
1220
1256
  return { variables: { ...initialVariables } };
1221
1257
  const variablesById = { ...initialVariables };
@@ -1223,8 +1259,9 @@ var init_runConsumers = __esm({
1223
1259
  const parsedBlockContext = parseBlockContext(blockContext);
1224
1260
  const attributes = parsedBlockContext.variables;
1225
1261
  const rootBlocks = bid ? { [bid]: blocks[bid] } : sections.reduce((rootBlocks2, { id }) => ({ ...rootBlocks2, ...getRootBlocksForSection_default(id, blocks) }), {});
1262
+ const withinSection = mode === "section";
1226
1263
  const blockDeps = Object.keys(rootBlocks).reduce((deps, id) => {
1227
- const dependencies = getDependencies(Number(id), blocks, [], !bid).map((rel) => rel.split("-"));
1264
+ const dependencies = getDependencies(Number(id), blocks, [], !bid, true, withinSection).map((rel) => rel.split("-"));
1228
1265
  return [...deps, ...dependencies];
1229
1266
  }, []);
1230
1267
  const orderedDAG = Object.keys(rootBlocks).reduce(
@@ -2401,15 +2438,16 @@ var init_actions = __esm({
2401
2438
  }
2402
2439
  });
2403
2440
  function ResourceProvider(props) {
2404
- const { pathSegment } = props;
2441
+ const { pathSegment, profilePrefix } = props;
2405
2442
  const formatters = useFormatterList();
2406
2443
  const value = useMemo(() => ({
2444
+ profilePrefix,
2407
2445
  pathSegment,
2408
2446
  formatterFunctions: locales3.reduce((acc, locale) => ({
2409
2447
  ...acc,
2410
2448
  [locale]: formatters.data ? funcifyFormattersByLocale(formatters.data, locale) : {}
2411
2449
  }), {})
2412
- }), [formatters, pathSegment]);
2450
+ }), [formatters, pathSegment, profilePrefix]);
2413
2451
  return /* @__PURE__ */ jsx(ResourceContext.Provider, { value, children: props.children });
2414
2452
  }
2415
2453
  function useBespoke() {
@@ -2429,7 +2467,8 @@ var init_ResourceProvider = __esm({
2429
2467
  ({ locales: locales3 } = getLocales_default());
2430
2468
  initialContext = {
2431
2469
  pathSegment: "path",
2432
- formatterFunctions: locales3.reduce((acc, d) => ({ ...acc, [d]: {} }), {})
2470
+ formatterFunctions: locales3.reduce((acc, d) => ({ ...acc, [d]: {} }), {}),
2471
+ profilePrefix: "path"
2433
2472
  };
2434
2473
  ResourceContext = createContext(initialContext);
2435
2474
  }
@@ -2517,7 +2556,7 @@ function processResult(data, req) {
2517
2556
  }
2518
2557
  return { ...result, data };
2519
2558
  }
2520
- var localeDefault5, useAppDispatch, useAppSelector, useReportList, useVariantList, useSectionList, useFormatterList, useReportRef, useSectionRef, useBlockRef, useDimensionRef, useVariantRef, useFormatterRef, useInputVariablesFlat, useInputVariablesHash, useBlockStatus, useFormatterFunctionsForLocale, useBlockContext, getFormatterUsageCount, useFormatterUsageCount, useFormatterUsageCountList;
2559
+ 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
2560
  var init_hooks = __esm({
2522
2561
  "store/hooks.ts"() {
2523
2562
  init_esm_shims();
@@ -2532,6 +2571,7 @@ var init_hooks = __esm({
2532
2571
  useReportList = entityListHookFactory("report");
2533
2572
  useVariantList = entityListHookFactory("variant");
2534
2573
  useSectionList = entityListHookFactory("section");
2574
+ useBlockList = entityListHookFactory("block");
2535
2575
  useFormatterList = entityListHookFactory("formatter");
2536
2576
  useReportRef = entityRefHookFactory("report");
2537
2577
  useSectionRef = entityRefHookFactory("section");
@@ -2573,6 +2613,10 @@ var init_hooks = __esm({
2573
2613
  const resource = useContext(ResourceContext);
2574
2614
  return resource.formatterFunctions[locale];
2575
2615
  };
2616
+ useProfilePrefix = () => {
2617
+ const resource = useContext(ResourceContext);
2618
+ return resource.profilePrefix;
2619
+ };
2576
2620
  useBlockContext = (id = void 0, locale = void 0) => {
2577
2621
  useAppSelector((state2) => state2);
2578
2622
  const localeDefault9 = useAppSelector((state2) => state2.status.localeDefault);
@@ -2626,6 +2670,7 @@ var init_store = __esm({
2626
2670
  return getDefaultMiddleware({
2627
2671
  thunk: {
2628
2672
  extraArgument: apiFactory("/api/cms/")
2673
+ // serializableCheck: false,
2629
2674
  }
2630
2675
  });
2631
2676
  }
@@ -2633,7 +2678,7 @@ var init_store = __esm({
2633
2678
  storeWrapper = createWrapper(storeFactory);
2634
2679
  }
2635
2680
  });
2636
- function withFetcher(Component, useRef6) {
2681
+ function withFetcher(Component, useRef7) {
2637
2682
  const ComponentWithFetcher = (props) => {
2638
2683
  const {
2639
2684
  id,
@@ -2641,7 +2686,7 @@ function withFetcher(Component, useRef6) {
2641
2686
  skelWidth,
2642
2687
  ...otherProps
2643
2688
  } = props;
2644
- const ref = useRef6(id);
2689
+ const ref = useRef7(id);
2645
2690
  if (ref.isUninitialized || ref.isFetching) {
2646
2691
  return /* @__PURE__ */ jsx(Skeleton, { width: skelWidth, height: skelHeight });
2647
2692
  }
@@ -3285,8 +3330,13 @@ init_esm_shims();
3285
3330
 
3286
3331
  // frontend/components/explore/ExploreTile.tsx
3287
3332
  init_esm_shims();
3288
- function ExploreTile({ profile, profilePrefix }) {
3289
- const url = `${profilePrefix}${profile.path}`;
3333
+ init_store2();
3334
+ function ExploreTile({ profile, profilePrefix, onSelect }) {
3335
+ const currentLocale = useAppSelector((state) => state.status.currentLocale);
3336
+ const localeDefault9 = useAppSelector((state) => state.status.localeDefault);
3337
+ const localePrefix = currentLocale === localeDefault9 ? "" : `/${currentLocale}`;
3338
+ const url = `${localePrefix}${profilePrefix}${profile.path}`;
3339
+ const router = useRouter();
3290
3340
  const images = profile.members.map((m) => /* @__PURE__ */ jsx(
3291
3341
  Image,
3292
3342
  {
@@ -3301,21 +3351,37 @@ function ExploreTile({ profile, profilePrefix }) {
3301
3351
  /* @__PURE__ */ jsx(Text, { weight: 500, children: m.name }),
3302
3352
  /* @__PURE__ */ jsx(Badge, { color: "green", variant: "light", children: m.metadata.variant.name })
3303
3353
  ] }, m.id));
3354
+ const onItemSubmit = (innerUrl) => {
3355
+ router.push(`${innerUrl}`);
3356
+ if (onSelect)
3357
+ onSelect();
3358
+ };
3304
3359
  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
3360
  /* @__PURE__ */ jsx(Card.Section, { children: /* @__PURE__ */ jsx(Group, { grow: true, spacing: 0, children: images }) }),
3306
3361
  /* @__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` }) })
3362
+ /* @__PURE__ */ jsx(
3363
+ "a",
3364
+ {
3365
+ href: url,
3366
+ onClick: (evt) => {
3367
+ evt.preventDefault();
3368
+ onItemSubmit(url);
3369
+ },
3370
+ children: /* @__PURE__ */ jsx(Button, { variant: "light", color: "blue", fullWidth: true, mt: "md", radius: "md", children: `See ${profile.report.name} Report` })
3371
+ }
3372
+ )
3308
3373
  ] }) }, profile.id);
3309
3374
  }
3310
3375
  var ExploreTile_default = ExploreTile;
3311
- function ExploreResults({ results = [], profilePrefix }) {
3376
+ function ExploreResults({ results = [], profilePrefix, onSelect = () => {
3377
+ } }) {
3312
3378
  const [scrollSize, setScrollSize] = useState(500);
3313
3379
  useEffect(() => {
3314
3380
  const { innerHeight } = window;
3315
3381
  setScrollSize(innerHeight - 200);
3316
3382
  }, []);
3317
3383
  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)
3384
+ (item) => /* @__PURE__ */ jsx(ExploreTile_default, { profile: item, profilePrefix, onSelect }, item.id)
3319
3385
  ) }) });
3320
3386
  }
3321
3387
  var ExploreResults_default = ExploreResults;
@@ -3326,10 +3392,12 @@ function BespokeExplore({
3326
3392
  locale,
3327
3393
  profilePrefix,
3328
3394
  initialReportId,
3329
- initialVariantId
3395
+ initialVariantId,
3396
+ onSelect
3330
3397
  }) {
3331
3398
  const dispatch = useAppDispatch();
3332
3399
  const defaultFilters = {
3400
+ // initial reportIds should go here to avoid multiple unnecesary requests
3333
3401
  profile: void 0,
3334
3402
  variant: void 0
3335
3403
  };
@@ -3348,6 +3416,7 @@ function BespokeExplore({
3348
3416
  });
3349
3417
  }, []);
3350
3418
  useEffect(() => {
3419
+ let cancelled = false;
3351
3420
  if (metadata) {
3352
3421
  setLoading(true);
3353
3422
  const filterProfile = filters.profile && !Number.isNaN(filters.profile) ? filters.profile : [];
@@ -3366,7 +3435,7 @@ function BespokeExplore({
3366
3435
  all: false
3367
3436
  };
3368
3437
  dispatch(actions_exports.reportSearch(params)).then((resp) => {
3369
- if (resp && resp.results) {
3438
+ if (resp && resp.results && !cancelled) {
3370
3439
  setResults(resp.results);
3371
3440
  }
3372
3441
  setLoading(false);
@@ -3376,6 +3445,9 @@ function BespokeExplore({
3376
3445
  setLoading(false);
3377
3446
  });
3378
3447
  }
3448
+ return () => {
3449
+ cancelled = false;
3450
+ };
3379
3451
  }, [debouncedQuery, filters, metadata]);
3380
3452
  const onFilterChange = (newFilters) => {
3381
3453
  setFilters(newFilters);
@@ -3418,7 +3490,7 @@ function BespokeExplore({
3418
3490
  ),
3419
3491
  /* @__PURE__ */ jsx(LoadingOverlay, { visible: loading }),
3420
3492
  !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 })
3493
+ !loading && /* @__PURE__ */ jsx(ExploreResults_default, { results, profilePrefix, onSelect })
3422
3494
  ] });
3423
3495
  }
3424
3496
  var Explore_default = BespokeExplore;
@@ -3429,13 +3501,14 @@ init_getLocales();
3429
3501
  var { localeDefault: localeDefault6 } = getLocales_default();
3430
3502
  function BespokeExploreModal({
3431
3503
  exploreProps = { profilePrefix: "/", locale: localeDefault6 },
3432
- icon = /* @__PURE__ */ jsx(IconSearch, {}),
3504
+ icon = /* @__PURE__ */ jsx(IconSearch, { size: 20 }),
3433
3505
  actionIconProps = {},
3434
- modalProps = {}
3506
+ modalProps = {},
3507
+ children
3435
3508
  }) {
3436
3509
  const [opened, setOpened] = useState(false);
3437
3510
  const btnConfig = {
3438
- variant: "subtle",
3511
+ variant: "light",
3439
3512
  size: "md",
3440
3513
  radius: "md",
3441
3514
  ...actionIconProps
@@ -3444,10 +3517,22 @@ function BespokeExploreModal({
3444
3517
  fullScreen: true,
3445
3518
  opened,
3446
3519
  onClose: () => setOpened(false)
3520
+ //...modalProps,
3447
3521
  };
3522
+ const actionIcon = /* @__PURE__ */ jsx(ActionIcon, { ...btnConfig, onClick: () => setOpened(true), children: icon });
3448
3523
  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 })
3524
+ /* @__PURE__ */ jsx(Modal, { ...modalProps, ...mdlConfig, children: /* @__PURE__ */ jsx(Explore_default, { ...exploreProps, onSelect: () => setOpened(false) }) }),
3525
+ /* @__PURE__ */ jsx("div", { onClick: () => setOpened(true), children: children ? /* @__PURE__ */ jsx(Tooltip, { label: "Click to search", children: /* @__PURE__ */ jsxs(
3526
+ Group,
3527
+ {
3528
+ spacing: "sm",
3529
+ style: { cursor: "pointer" },
3530
+ children: [
3531
+ children,
3532
+ actionIcon
3533
+ ]
3534
+ }
3535
+ ) }) : /* @__PURE__ */ jsx(Fragment, { children: actionIcon }) })
3451
3536
  ] });
3452
3537
  }
3453
3538
  var ExploreModal_default = BespokeExploreModal;
@@ -3472,8 +3557,10 @@ var SearchItem = forwardRef(
3472
3557
  }
3473
3558
  );
3474
3559
  var SearchItem_default = SearchItem;
3475
- function BespokeSearch({ locale, profilePrefix, autocompleteProps = {} }) {
3560
+ function BespokeSearch({ locale, profilePrefix, autocompleteProps = {}, children }) {
3476
3561
  const dispatch = useAppDispatch();
3562
+ const currentLocale = useAppSelector((state) => state.status.currentLocale);
3563
+ const localeDefault9 = useAppSelector((state) => state.status.localeDefault);
3477
3564
  const router = useRouter();
3478
3565
  const [query, setQuery] = useState("");
3479
3566
  const [debouncedQuery, cancel] = useDebouncedValue(query, 500);
@@ -3481,6 +3568,7 @@ function BespokeSearch({ locale, profilePrefix, autocompleteProps = {} }) {
3481
3568
  const [loading, setLoading] = useState(false);
3482
3569
  const [redirecting, setRedirecting] = useState(false);
3483
3570
  const [initialized, setInitialized] = useState(false);
3571
+ const [visible, setVisible] = useState(children ? false : true);
3484
3572
  const inputRef = useRef();
3485
3573
  const doSearch = () => {
3486
3574
  setLoading(true);
@@ -3500,7 +3588,7 @@ function BespokeSearch({ locale, profilePrefix, autocompleteProps = {} }) {
3500
3588
  dispatch(actions_exports.reportSearch(params)).then((value) => {
3501
3589
  if (value && value.results) {
3502
3590
  setResults(value.results.map((r) => {
3503
- r.value = `VALUE: ${r.name}...`;
3591
+ r.value = `VALUE: ${r.id}`;
3504
3592
  return r;
3505
3593
  }));
3506
3594
  }
@@ -3518,10 +3606,16 @@ function BespokeSearch({ locale, profilePrefix, autocompleteProps = {} }) {
3518
3606
  }, [debouncedQuery]);
3519
3607
  useEffect(() => {
3520
3608
  cancel();
3521
- if (inputRef.current) {
3609
+ if (inputRef.current && visible) {
3522
3610
  setInitialized(true);
3523
3611
  }
3524
3612
  }, []);
3613
+ useEffect(() => {
3614
+ cancel();
3615
+ if (inputRef.current && visible) {
3616
+ setInitialized(true);
3617
+ }
3618
+ }, [visible]);
3525
3619
  const acConfig = {
3526
3620
  placeholder: "Search",
3527
3621
  size: "md",
@@ -3531,14 +3625,24 @@ function BespokeSearch({ locale, profilePrefix, autocompleteProps = {} }) {
3531
3625
  };
3532
3626
  const onItemSubmit = (item) => {
3533
3627
  setRedirecting(true);
3534
- router.push(`${profilePrefix}${item.path}`);
3628
+ setVisible(false);
3629
+ const localePrefix = currentLocale === localeDefault9 ? "" : `/${currentLocale}`;
3630
+ const url = `${localePrefix}${profilePrefix}${item.path}`;
3631
+ router.push(url);
3535
3632
  };
3536
3633
  const onChange = (searchTerm) => {
3537
3634
  if (!searchTerm.includes("VALUE:")) {
3538
3635
  setQuery(searchTerm);
3539
3636
  }
3540
3637
  };
3541
- return /* @__PURE__ */ jsx(
3638
+ const doClose = () => {
3639
+ setVisible(false);
3640
+ };
3641
+ const doOpen = () => {
3642
+ setVisible(true);
3643
+ doSearch();
3644
+ };
3645
+ const autocompleteElement = /* @__PURE__ */ jsx(
3542
3646
  Autocomplete,
3543
3647
  {
3544
3648
  value: query,
@@ -3549,11 +3653,26 @@ function BespokeSearch({ locale, profilePrefix, autocompleteProps = {} }) {
3549
3653
  disabled: (loading || redirecting) && !initialized,
3550
3654
  limit: 10,
3551
3655
  maxDropdownHeight: 250,
3552
- rightSection: loading ? /* @__PURE__ */ jsx(Loader, { size: 20 }) : "",
3656
+ rightSection: /* @__PURE__ */ jsx(Group, { spacing: 0, position: "right", children: loading ? /* @__PURE__ */ jsx(Loader, { size: 20 }) : /* @__PURE__ */ jsx(Fragment, {}) }),
3657
+ rightSectionWidth: 50,
3553
3658
  ref: inputRef,
3554
3659
  ...acConfig
3555
3660
  }
3556
3661
  );
3662
+ const finalElement = children ? /* @__PURE__ */ jsx(Tooltip, { label: "Click to search", disabled: visible, children: /* @__PURE__ */ jsxs(
3663
+ Group,
3664
+ {
3665
+ spacing: "sm",
3666
+ align: "center",
3667
+ style: { cursor: "pointer" },
3668
+ children: [
3669
+ !visible && /* @__PURE__ */ jsx("div", { onClick: () => setVisible(true), children }),
3670
+ visible && /* @__PURE__ */ jsx(Fragment, { children: autocompleteElement }),
3671
+ 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 }) })
3672
+ ]
3673
+ }
3674
+ ) }) : autocompleteElement;
3675
+ return finalElement;
3557
3676
  }
3558
3677
  var Search_default = BespokeSearch;
3559
3678
 
@@ -3626,7 +3745,7 @@ function ParagraphView({ paragraph, tooltip, size = "md" }) {
3626
3745
  // frontend/components/report/blocks/Stat.tsx
3627
3746
  init_esm_shims();
3628
3747
  init_sanitizeBlockContent();
3629
- function Stat({ subtitle, title, value, tooltip = "stat tooltip" }) {
3748
+ function Stat({ subtitle, title, value, tooltip }) {
3630
3749
  const titleHTML = sanitizeBlockContent_default(title);
3631
3750
  const valueHTML = sanitizeBlockContent_default(value);
3632
3751
  const subtitleHTML = sanitizeBlockContent_default(subtitle);
@@ -3658,21 +3777,62 @@ function SubtitleView({ subtitle, tooltip }) {
3658
3777
  // frontend/components/report/blocks/Title.tsx
3659
3778
  init_esm_shims();
3660
3779
  init_sanitizeBlockContent();
3780
+ init_hooks();
3661
3781
  function TitleView({ title, tooltip, slug, settings }) {
3662
3782
  const titleHTML = sanitizeBlockContent_default(title) || "<span class='cr-block-placeholder'>Title</span>";
3663
3783
  const tooltipHTML = sanitizeBlockContent_default(tooltip);
3664
3784
  const intOrder = settings && settings.order ? parseInt(settings.order, 10) : 1;
3665
3785
  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
- ] });
3786
+ const searchOnClick = settings && settings.search ? settings.search : "off";
3787
+ const currentLocale = useAppSelector((state) => state.status.currentLocale);
3788
+ const profilePrefix = useProfilePrefix();
3789
+ const initialIds = useAppSelector(
3790
+ (state) => ({
3791
+ reportId: state.variables.attributes.report_id,
3792
+ variantId: state.variables.attributes.variant_id1
3793
+ })
3794
+ );
3795
+ const titleElement = /* @__PURE__ */ jsx(
3796
+ Title,
3797
+ {
3798
+ order,
3799
+ dangerouslySetInnerHTML: { __html: titleHTML }
3800
+ }
3801
+ );
3802
+ const locale = currentLocale;
3803
+ const finalElement = useMemo(() => {
3804
+ let component = /* @__PURE__ */ jsx(Fragment, {});
3805
+ if (searchOnClick === "modal") {
3806
+ component = /* @__PURE__ */ jsx(ExploreModal_default, { exploreProps: {
3807
+ locale,
3808
+ profilePrefix,
3809
+ initialReportId: initialIds.reportId,
3810
+ initialVariantId: initialIds.variantId
3811
+ }, children: titleElement });
3812
+ } else if (searchOnClick === "inline") {
3813
+ component = /* @__PURE__ */ jsx(
3814
+ Search_default,
3815
+ {
3816
+ locale,
3817
+ profilePrefix,
3818
+ children: titleElement
3819
+ }
3820
+ );
3821
+ } else {
3822
+ component = titleElement;
3823
+ }
3824
+ return component;
3825
+ }, [searchOnClick, titleElement]);
3826
+ return /* @__PURE__ */ jsxs(
3827
+ Group,
3828
+ {
3829
+ spacing: "sm",
3830
+ children: [
3831
+ tooltip && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Tooltip, { label: tooltipHTML, withArrow: true, withinPortal: true, children: /* @__PURE__ */ jsx(ActionIcon, { children: /* @__PURE__ */ jsx(IconInfoCircle, {}) }) }) }, "tooltip"),
3832
+ /* @__PURE__ */ jsx("div", { children: finalElement })
3833
+ ]
3834
+ }
3835
+ );
3676
3836
  }
3677
3837
 
3678
3838
  // frontend/components/report/blocks/Selector.tsx
@@ -3726,12 +3886,13 @@ function useOnChangeSelector(blockId, section, selectorIdentifier) {
3726
3886
  formatters,
3727
3887
  blockContext,
3728
3888
  initialVariables,
3729
- readMemberFn
3889
+ readMemberFn,
3890
+ "report"
3730
3891
  ).then((data) => {
3731
3892
  dispatch(variablesActions.setVariableChange({
3732
3893
  attributes,
3733
3894
  variables: data.variables,
3734
- status: {}
3895
+ status: data.status
3735
3896
  }));
3736
3897
  });
3737
3898
  },
@@ -3757,7 +3918,7 @@ var parseMultiValue = (selectorValue, defaultValue) => {
3757
3918
  return defaultValue;
3758
3919
  };
3759
3920
  function Selector(config) {
3760
- const { name, options, id, defaultValue, section } = config;
3921
+ const { name, options, id, defaultValue, section, component } = config;
3761
3922
  const selectorIdentifier = getSelectorIdentifier(id);
3762
3923
  const router = useRouter();
3763
3924
  const callback = useOnChangeSelector(id, section, selectorIdentifier);
@@ -3768,22 +3929,22 @@ function Selector(config) {
3768
3929
  (d) => ({ value: d.id, label: d.label })
3769
3930
  ), [optDependency]);
3770
3931
  return {
3771
- [SELECTOR_TYPES.SINGLE]: data.length > 3 ? /* @__PURE__ */ jsx(
3772
- Select,
3932
+ [SELECTOR_TYPES.SINGLE]: component === SELECTOR_COMPONENTS.SEGMENTED_CONTROL ? /* @__PURE__ */ jsx(
3933
+ SegmentedControl,
3773
3934
  {
3774
- label: name,
3775
3935
  data,
3776
3936
  value,
3777
- onChange: (value2) => callback(value2)
3937
+ onChange: (value2) => callback(value2),
3938
+ name,
3939
+ fullWidth: true
3778
3940
  }
3779
3941
  ) : /* @__PURE__ */ jsx(
3780
- SegmentedControl,
3942
+ Select,
3781
3943
  {
3944
+ label: name,
3782
3945
  data,
3783
3946
  value,
3784
- onChange: (value2) => callback(value2),
3785
- name,
3786
- fullWidth: true
3947
+ onChange: (value2) => callback(value2)
3787
3948
  }
3788
3949
  ),
3789
3950
  [SELECTOR_TYPES.MULTI]: /* @__PURE__ */ jsx(
@@ -3887,7 +4048,8 @@ function useInitialState(pathSegmentsKey) {
3887
4048
  formatters,
3888
4049
  blockContext,
3889
4050
  variables,
3890
- readMemberFn
4051
+ readMemberFn,
4052
+ "report"
3891
4053
  ).then((data) => {
3892
4054
  return dispatch(variablesActions.setVariableChange({ ...data, attributes }));
3893
4055
  });
@@ -3924,7 +4086,7 @@ function createOutline(elements, variables) {
3924
4086
  const node = {
3925
4087
  id,
3926
4088
  order,
3927
- label: variables[id] ? variables[id][`title${id}title`] : "-Not calculated yet-",
4089
+ label: variables[id] ? variables[id][`title${id}title`] : `Title ${id}`,
3928
4090
  children: []
3929
4091
  };
3930
4092
  nodes[id] = node;
@@ -3986,12 +4148,12 @@ function useContentOutline(min = 1, max = 6, headings = []) {
3986
4148
  return useMemo(() => {
3987
4149
  if (titlesSorted && titlesSorted?.length > 0) {
3988
4150
  return createOutline(titlesSorted, titleVariables);
4151
+ } else {
4152
+ return [];
3989
4153
  }
3990
4154
  }, [titlesSorted, titleVariables]);
3991
4155
  }
3992
- function NavView({ headings, settings }) {
3993
- const { type, min, max } = settings;
3994
- const contentOutline = useContentOutline(parseInt(min, 10), parseInt(max, 10), headings);
4156
+ var DesktopNav = ({ contentOutline }) => {
3995
4157
  const renderMenu = (nodes) => {
3996
4158
  if (!nodes || !nodes?.length) {
3997
4159
  return null;
@@ -4024,6 +4186,80 @@ function NavView({ headings, settings }) {
4024
4186
  )
4025
4187
  }
4026
4188
  ) });
4189
+ };
4190
+ var MobileAccordion = ({ contentOutline, closeNav }) => {
4191
+ const [value, setValue] = useState(null);
4192
+ return /* @__PURE__ */ jsx(Stack, { children: contentOutline.map(
4193
+ (node) => node.children.length ? /* @__PURE__ */ jsxs(Fragment, { children: [
4194
+ /* @__PURE__ */ jsxs(Group, { spacing: 0, noWrap: true, children: [
4195
+ /* @__PURE__ */ jsx(
4196
+ UnstyledButton,
4197
+ {
4198
+ w: "100%",
4199
+ component: "a",
4200
+ onClick: closeNav,
4201
+ href: `#bespoke-title-${node.id}`,
4202
+ children: /* @__PURE__ */ jsx(Text, { pl: "sm", dangerouslySetInnerHTML: { __html: node.label } })
4203
+ },
4204
+ node.id
4205
+ ),
4206
+ /* @__PURE__ */ jsx(
4207
+ ActionIcon,
4208
+ {
4209
+ component: "a",
4210
+ size: "lg",
4211
+ onClick: () => setValue((value2) => value2 === node.id ? null : node.id),
4212
+ children: /* @__PURE__ */ jsx(
4213
+ IconChevronDown,
4214
+ {
4215
+ style: {
4216
+ transition: "transform 0.2s",
4217
+ transform: value === node.id ? "rotate(-180deg)" : "none"
4218
+ },
4219
+ stroke: 1
4220
+ }
4221
+ )
4222
+ }
4223
+ )
4224
+ ] }, node.id),
4225
+ /* @__PURE__ */ jsx(
4226
+ Collapse,
4227
+ {
4228
+ in: value === node.id,
4229
+ pl: "sm",
4230
+ transitionTimingFunction: "linear",
4231
+ transitionDuration: 200,
4232
+ children: /* @__PURE__ */ jsx(MobileAccordion, { contentOutline: node.children, closeNav })
4233
+ }
4234
+ )
4235
+ ] }) : /* @__PURE__ */ jsx(Group, { noWrap: true, children: /* @__PURE__ */ jsx(
4236
+ UnstyledButton,
4237
+ {
4238
+ display: "flex",
4239
+ w: "100%",
4240
+ component: "a",
4241
+ href: `#bespoke-title-${node.id}`,
4242
+ children: /* @__PURE__ */ jsx(Text, { pl: "sm", dangerouslySetInnerHTML: { __html: node.label } })
4243
+ },
4244
+ node.id
4245
+ ) }, node.id)
4246
+ ) });
4247
+ };
4248
+ var MobileNav = ({ contentOutline }) => {
4249
+ const [opened, { toggle }] = useDisclosure(false);
4250
+ const label = opened ? "Close content outline" : "Open content outline";
4251
+ return /* @__PURE__ */ jsxs(Box, { component: "nav", children: [
4252
+ /* @__PURE__ */ jsx(Group, { children: /* @__PURE__ */ jsx(Burger, { opened, onClick: toggle, "aria-label": label, size: "md" }) }),
4253
+ /* @__PURE__ */ jsx(Collapse, { in: opened, mt: "md", children: /* @__PURE__ */ jsx(MobileAccordion, { contentOutline, closeNav: toggle }) })
4254
+ ] });
4255
+ };
4256
+ function NavView({ headings, settings }) {
4257
+ const { type, min, max } = settings;
4258
+ const contentOutline = useContentOutline(parseInt(min, 10), parseInt(max, 10), headings);
4259
+ const theme = useMantineTheme();
4260
+ const mq = `(max-width: ${theme.breakpoints.md})`;
4261
+ const smallerThanMd = useMediaQuery(mq);
4262
+ return smallerThanMd ? /* @__PURE__ */ jsx(MobileNav, { contentOutline }) : /* @__PURE__ */ jsx(DesktopNav, { contentOutline });
4027
4263
  }
4028
4264
 
4029
4265
  // frontend/components/report/blocks/index.tsx
@@ -4062,8 +4298,9 @@ var validateOptionsArray = (options) => {
4062
4298
  return options.map((d) => typeof d === "string" ? { id: d, label: d } : d);
4063
4299
  };
4064
4300
  var maybeFixForMulti = (defaultValue, type) => type === SELECTOR_TYPES.MULTI && !Array.isArray(defaultValue) ? [defaultValue] : defaultValue;
4065
- var Selector_default = (vars, id) => {
4301
+ var selectorAdapter = (vars, id) => {
4066
4302
  const type = vars.type || SELECTOR_TYPES.SINGLE;
4303
+ const component = vars.component || "Selector";
4067
4304
  const name = vars.name || "Unlabeled Selector";
4068
4305
  const options = validateOptionsArray(vars.options || []);
4069
4306
  let defaultValue;
@@ -4081,9 +4318,11 @@ var Selector_default = (vars, id) => {
4081
4318
  name,
4082
4319
  type,
4083
4320
  options,
4321
+ component,
4084
4322
  defaultValue
4085
4323
  };
4086
4324
  };
4325
+ var Selector_default = selectorAdapter;
4087
4326
 
4088
4327
  // components/blocks/types/adapters/index.js
4089
4328
  var adapters_default = {
@@ -4126,6 +4365,10 @@ var SELECTOR_TYPE = {
4126
4365
  SINGLE: "single",
4127
4366
  MULTI: "multi"
4128
4367
  };
4368
+ var SELECTOR_COMPONENT = {
4369
+ SEGMENTED_CONTROL: "segmented control",
4370
+ SELECTOR: "selector"
4371
+ };
4129
4372
  var OPTION_TYPE = {
4130
4373
  STATIC: "static",
4131
4374
  DYNAMIC: "dynamic"
@@ -4347,14 +4590,16 @@ function SelectorUI(props) {
4347
4590
  } = props;
4348
4591
  const [selectorIdentifier, setSelectorIdentifier] = useState("");
4349
4592
  const [selectorType, setSelectorType] = useState(SELECTOR_TYPE.SINGLE);
4593
+ const [selectorComponent, setSelectorComponent] = useState(SELECTOR_COMPONENT.SELECTOR);
4350
4594
  const [options, setOptions] = useState({ static: [], dynamic: {} });
4351
4595
  const [optionsType, setOptionsType] = useState(OPTION_TYPE.STATIC);
4352
- const stateFields = [selectorIdentifier, selectorType, options, optionsType];
4596
+ const stateFields = [selectorIdentifier, selectorType, selectorComponent, options, optionsType];
4353
4597
  useEffect(() => {
4354
4598
  if (!simpleState)
4355
4599
  return;
4356
4600
  setSelectorIdentifier(simpleState.name || "");
4357
4601
  setSelectorType(simpleState.type);
4602
+ setSelectorComponent(simpleState.component);
4358
4603
  if (simpleState.options?.hasOwnProperty("dynamic") && simpleState.options?.hasOwnProperty("static")) {
4359
4604
  setOptions(simpleState.options);
4360
4605
  }
@@ -4364,6 +4609,7 @@ function SelectorUI(props) {
4364
4609
  () => {
4365
4610
  const logicObj = {
4366
4611
  name: selectorIdentifier,
4612
+ component: selectorComponent,
4367
4613
  type: selectorType
4368
4614
  };
4369
4615
  let defaultValue;
@@ -4390,6 +4636,7 @@ function SelectorUI(props) {
4390
4636
  const simpleState2 = {
4391
4637
  name: selectorIdentifier,
4392
4638
  type: selectorType,
4639
+ component: selectorComponent,
4393
4640
  optionsType,
4394
4641
  options
4395
4642
  };
@@ -4418,6 +4665,15 @@ function SelectorUI(props) {
4418
4665
  data: Object.values(SELECTOR_TYPE)
4419
4666
  }
4420
4667
  ),
4668
+ selectorType === SELECTOR_TYPE.SINGLE && /* @__PURE__ */ jsx(
4669
+ Select,
4670
+ {
4671
+ label: "Selector Component",
4672
+ value: selectorComponent,
4673
+ onChange: setSelectorComponent,
4674
+ data: Object.values(SELECTOR_COMPONENT)
4675
+ }
4676
+ ),
4421
4677
  /* @__PURE__ */ jsx(
4422
4678
  Select,
4423
4679
  {
@@ -4518,7 +4774,9 @@ function TitlePreview({ title, tooltip, slug, settings }) {
4518
4774
  const tooltipHTML = sanitizeBlockContent_default(tooltip);
4519
4775
  const intOrder = settings && settings.order ? parseInt(settings.order, 10) : 1;
4520
4776
  const order = intOrder <= 6 ? intOrder : 1;
4521
- return /* @__PURE__ */ jsxs("div", { children: [
4777
+ const searchOnClick = settings && settings.search && settings.search !== "off" ? true : false;
4778
+ const searchType = settings && settings.search ? settings.search : "";
4779
+ return /* @__PURE__ */ jsxs(Group, { spacing: "sm", children: [
4522
4780
  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
4781
  /* @__PURE__ */ jsx(
4524
4782
  Title,
@@ -4526,7 +4784,8 @@ function TitlePreview({ title, tooltip, slug, settings }) {
4526
4784
  order,
4527
4785
  dangerouslySetInnerHTML: { __html: titleHTML }
4528
4786
  }
4529
- )
4787
+ ),
4788
+ searchOnClick && /* @__PURE__ */ jsx(Tooltip, { label: `Click will open '${searchType}' report search`, children: /* @__PURE__ */ jsx(ActionIcon, { variant: "light", children: /* @__PURE__ */ jsx(IconSearch, { size: 20 }) }) })
4530
4789
  ] });
4531
4790
  }
4532
4791
 
@@ -4579,7 +4838,18 @@ function SelectorPreview(config) {
4579
4838
  };
4580
4839
  const { name } = config;
4581
4840
  return {
4582
- [SELECTOR_TYPES.SINGLE]: /* @__PURE__ */ jsx(
4841
+ [SELECTOR_TYPES.SINGLE]: config.component === SELECTOR_COMPONENTS.SEGMENTED_CONTROL ? /* @__PURE__ */ jsxs("div", { children: [
4842
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: name }),
4843
+ /* @__PURE__ */ jsx(
4844
+ SegmentedControl,
4845
+ {
4846
+ data,
4847
+ value,
4848
+ onChange: onChangeSingle,
4849
+ fullWidth: true
4850
+ }
4851
+ )
4852
+ ] }) : /* @__PURE__ */ jsx(
4583
4853
  Select,
4584
4854
  {
4585
4855
  label: name,
@@ -4971,7 +5241,6 @@ init_varSwap();
4971
5241
  init_mortarEval();
4972
5242
  init_envvars();
4973
5243
  init_runSelector();
4974
- init_block();
4975
5244
  function Block({ blockId, active = true }) {
4976
5245
  const { query, locale = localeDefault4 } = useRouter();
4977
5246
  const block = useBlockRef(blockId).data;
@@ -4984,8 +5253,9 @@ function Block({ blockId, active = true }) {
4984
5253
  locale
4985
5254
  };
4986
5255
  const generatorVariables = useAppSelector((state) => state.variables.variables[block.id] || {});
5256
+ const blockStatus = useAppSelector((state) => state.variables.status[block.id] || {});
4987
5257
  const [content, setContent] = useState(() => {
4988
- if (![BLOCK_TYPES.GENERATOR, BLOCK_TYPES.VIZ, BLOCK_TYPES.NAV].includes(block?.type)) {
5258
+ if (![BLOCK_TYPES.GENERATOR, BLOCK_TYPES.VIZ, BLOCK_TYPES.NAV].includes(block.type)) {
4989
5259
  if (block?.type === BLOCK_TYPES.SELECTOR) {
4990
5260
  const blockContent2 = getBlockContent(block, locale);
4991
5261
  const { config: renderVariables } = runSelector_default(blockContent2?.logic, formatterFunctions, blockContext);
@@ -5005,24 +5275,6 @@ function Block({ blockId, active = true }) {
5005
5275
  }
5006
5276
  return null;
5007
5277
  });
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
5278
  useEffect(() => {
5027
5279
  const fetch = async () => {
5028
5280
  if (!block || block.type === BLOCK_TYPES.GENERATOR)
@@ -5077,7 +5329,7 @@ function Block({ blockId, active = true }) {
5077
5329
  };
5078
5330
  fetch();
5079
5331
  }, [blockContent, variables]);
5080
- if (!block || !content || !allowed)
5332
+ if (!block || !content || !blockStatus.allowed)
5081
5333
  return null;
5082
5334
  const Renderer = blocks_default[block.type];
5083
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 }) });
@@ -5906,7 +6158,8 @@ function DesignSectionMenu({ sectionId }) {
5906
6158
  return null;
5907
6159
  const {
5908
6160
  memberImageBg,
5909
- optionsMenu
6161
+ optionsMenu,
6162
+ hidden
5910
6163
  } = section.settings;
5911
6164
  return /* @__PURE__ */ jsxs(
5912
6165
  Popover,
@@ -5942,6 +6195,15 @@ function DesignSectionMenu({ sectionId }) {
5942
6195
  onChange: (e) => handleChange("optionsMenu", e.currentTarget.checked)
5943
6196
  }
5944
6197
  ),
6198
+ /* @__PURE__ */ jsx(
6199
+ Checkbox,
6200
+ {
6201
+ size: "xs",
6202
+ label: "Hide section",
6203
+ checked: hidden,
6204
+ onChange: (e) => handleChange("hidden", e.currentTarget.checked)
6205
+ }
6206
+ ),
5945
6207
  Object.entries(sectionSettings).map(([key, { label, defaultValue, options }]) => /* @__PURE__ */ jsxs(Group, { spacing: "xs", position: "apart", noWrap: true, style: { width: "100%" }, children: [
5946
6208
  label && /* @__PURE__ */ jsx(Text, { fz: "sm", children: label }),
5947
6209
  /* @__PURE__ */ jsx(
@@ -5981,6 +6243,9 @@ function SectionMenu({ sectionId }) {
5981
6243
  ] });
5982
6244
  }
5983
6245
  var SectionMenu_default = SectionMenu;
6246
+
6247
+ // frontend/components/report/Section.tsx
6248
+ init_cms();
5984
6249
  var getStyles = (styles, settings) => (theme) => styles ? styles(theme, settings) : {};
5985
6250
  var PositionWrapper = ({ settings, styles, children, ...props }) => {
5986
6251
  const { position } = settings;
@@ -6045,11 +6310,20 @@ function Section({ section }) {
6045
6310
  ...settings
6046
6311
  };
6047
6312
  const state = useAppSelector((state2) => state2);
6313
+ const status = useAppSelector((state2) => state2.variables.status);
6048
6314
  const sectionStyles = useBespokeStyles()["Section"];
6049
6315
  const blockRecords = selectBlockRecords(state);
6050
6316
  const theme = useMantineTheme();
6051
6317
  const smallScreen = useMediaQuery(`(max-width: ${theme.breakpoints.sm}px)`);
6052
- const columns = Object.values(blockRecords || {}).filter((d) => d.section_id === id).reduce((acc, d) => {
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) => {
6053
6327
  if (!acc[d.blockcol]) {
6054
6328
  acc[d.blockcol] = { [d.blockrow]: d };
6055
6329
  } else {
@@ -6057,6 +6331,9 @@ function Section({ section }) {
6057
6331
  }
6058
6332
  return acc;
6059
6333
  }, {});
6334
+ const displaySection = Object.keys(blockRecords).length > 0 && !settings.hidden && allowedSection;
6335
+ if (!displaySection)
6336
+ return null;
6060
6337
  return /* @__PURE__ */ jsxs(
6061
6338
  PositionWrapper,
6062
6339
  {
@@ -6295,8 +6572,14 @@ init_esm_shims();
6295
6572
 
6296
6573
  // components/builder/JumpTo.tsx
6297
6574
  init_esm_shims();
6575
+ init_store2();
6298
6576
  function JumpTo() {
6299
- const contentOutline = useContentOutline();
6577
+ const blocks = useBlockList();
6578
+ const titleBlocks = useMemo(
6579
+ () => blocks.data ? blocks.data.filter((d) => d.type === "title").map((d) => d.id) : [],
6580
+ [blocks.data]
6581
+ );
6582
+ const contentOutline = useContentOutline(1, 6, titleBlocks);
6300
6583
  const handleClick = (blockId) => {
6301
6584
  const section = document.getElementById(`title-${blockId}`);
6302
6585
  if (section) {
@@ -6308,7 +6591,7 @@ function JumpTo() {
6308
6591
  if (!nodes) {
6309
6592
  return null;
6310
6593
  }
6311
- return /* @__PURE__ */ jsx(Fragment, { children: nodes.map((node) => /* @__PURE__ */ jsxs(Fragment, { children: [
6594
+ return /* @__PURE__ */ jsx(Fragment, { children: nodes.map((node) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
6312
6595
  /* @__PURE__ */ jsx(
6313
6596
  Menu.Item,
6314
6597
  {
@@ -6316,11 +6599,10 @@ function JumpTo() {
6316
6599
  onClick: () => handleClick(node.id),
6317
6600
  pl: 10 * node.order,
6318
6601
  children: node.label
6319
- },
6320
- `jump-key-${node.id}`
6602
+ }
6321
6603
  ),
6322
6604
  renderOutline(node.children)
6323
- ] })) });
6605
+ ] }, `jump-key-${node.id}`)) });
6324
6606
  };
6325
6607
  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
6608
  /* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(ActionIcon, { variant: "filled", color: "blue", children: /* @__PURE__ */ jsx(IconListSearch, {}) }) }),
@@ -7141,12 +7423,13 @@ function VariantEditor({ for: variant, onClose: closeHandler }) {
7141
7423
  ),
7142
7424
  variantConfig.config[selectedLocale] && /* @__PURE__ */ jsxs(Fragment, { children: [
7143
7425
  /* @__PURE__ */ jsx(Space, { h: "lg" }),
7144
- /* @__PURE__ */ jsxs(Group, { grow: true, children: [
7426
+ /* @__PURE__ */ jsxs(Group, { grow: true, align: "flex-end", children: [
7145
7427
  /* @__PURE__ */ jsx(
7146
7428
  TextInput,
7147
7429
  {
7148
7430
  onChange: (e) => onChangeConfig("path", e.target.value),
7149
- placeholder: "Enter a source API",
7431
+ title: "Api endpoint",
7432
+ description: "Enter the url to retrieve a member list to ingest. (JSON) and click Fetch.",
7150
7433
  value: variantConfig.config[selectedLocale].path
7151
7434
  }
7152
7435
  ),
@@ -7167,19 +7450,24 @@ function VariantEditor({ for: variant, onClose: closeHandler }) {
7167
7450
  Select,
7168
7451
  {
7169
7452
  value: variantConfig.config[selectedLocale].accessor,
7170
- label: "Accessor property (array)",
7453
+ label: "Elements",
7454
+ description: "Choose the key that returns the array of elements that \n are going to be ingested as members.",
7171
7455
  data: accessorSelectData,
7456
+ disabled: accessorSelectData.length === 0,
7457
+ placeholder: accessorSelectData.length === 0 ? "Root is an array" : "",
7172
7458
  onChange: (e) => onChangeAccessor(e)
7173
7459
  }
7174
7460
  ),
7175
7461
  /* @__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] }),
7462
+ payload[variantConfig.config[selectedLocale].accessor] && !Array.isArray(payload) && /* @__PURE__ */ jsx(InputMenuItem_default, { variables: payload[variantConfig.config[selectedLocale].accessor][0] }),
7463
+ Array.isArray(payload) && payload[0] && /* @__PURE__ */ jsx(InputMenuItem_default, { variables: payload[0] }),
7177
7464
  /* @__PURE__ */ jsx(Space, { h: "md" }),
7178
7465
  /* @__PURE__ */ jsx(
7179
7466
  Select,
7180
7467
  {
7181
7468
  value: variantConfig.config[selectedLocale].idKey,
7182
- label: "Key property",
7469
+ label: "Unique identificator",
7470
+ description: "Choose the field that is a unique identification for a single member.",
7183
7471
  data: keys,
7184
7472
  onChange: (e) => onChangeConfig("idKey", e)
7185
7473
  }
@@ -7189,13 +7477,29 @@ function VariantEditor({ for: variant, onClose: closeHandler }) {
7189
7477
  Select,
7190
7478
  {
7191
7479
  value: variantConfig.config[selectedLocale].labelKey,
7192
- label: "Label property",
7480
+ label: "Members' name",
7481
+ description: "Choose the field that contains the members name.",
7193
7482
  data: keys,
7194
7483
  onChange: (e) => onChangeConfig("labelKey", e)
7195
7484
  }
7196
7485
  ),
7197
7486
  /* @__PURE__ */ jsx(Space, { h: "md" }),
7487
+ /* @__PURE__ */ jsx(
7488
+ Select,
7489
+ {
7490
+ value: variantConfig.config[selectedLocale].zValueKey || "",
7491
+ label: "Member's relevance (optional)",
7492
+ description: "Choose a field that will be converted to a number and \n normalized from 0 to 1 to determine the member's relevance.",
7493
+ data: [
7494
+ { value: "null", label: "None" },
7495
+ ...keys
7496
+ ],
7497
+ onChange: (e) => onChangeConfig("zValueKey", e)
7498
+ }
7499
+ ),
7500
+ /* @__PURE__ */ jsx(Space, { h: "md" }),
7198
7501
  /* @__PURE__ */ jsx(Title, { order: 3, size: "h5", children: "Attributes" }),
7502
+ /* @__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
7503
  /* @__PURE__ */ jsx(Space, { h: "xs" }),
7200
7504
  variantConfig.config[selectedLocale].attributes && variantConfig.config[selectedLocale].attributes.map((attr, ix) => /* @__PURE__ */ jsxs(Group, { align: "end", grow: true, children: [
7201
7505
  /* @__PURE__ */ jsx(
@@ -7292,7 +7596,7 @@ function VariantEditor({ for: variant, onClose: closeHandler }) {
7292
7596
  }
7293
7597
  )
7294
7598
  ] }),
7295
- size: 145
7599
+ size: 165
7296
7600
  }
7297
7601
  );
7298
7602
  }
@@ -7371,7 +7675,7 @@ function DimensionEditor({ id, onClose: closeHandler }) {
7371
7675
  /* @__PURE__ */ jsx(Button, { variant: "outline", disabled: loading, loading, onClick: closeHandler, children: "Cancel" }),
7372
7676
  /* @__PURE__ */ jsx(Button, { disabled: loading, loading, onClick: submitHandler, children: "Save Dimension" })
7373
7677
  ] }),
7374
- size: 145
7678
+ size: 165
7375
7679
  }
7376
7680
  );
7377
7681
  }
@@ -7442,7 +7746,7 @@ function ReportEditor({ id, onClose: closeHandler }) {
7442
7746
  /* @__PURE__ */ jsx(Button, { variant: "outline", disabled: loading, loading, onClick: closeHandler, children: "Cancel" }),
7443
7747
  /* @__PURE__ */ jsx(Button, { disabled: loading, loading, onClick: submitHandler, children: "Save Report" })
7444
7748
  ] }),
7445
- size: 145
7749
+ size: 165
7446
7750
  }
7447
7751
  );
7448
7752
  }
@@ -7463,17 +7767,155 @@ function HeaderLayout(props) {
7463
7767
 
7464
7768
  // components/builder/CMSHeader.tsx
7465
7769
  init_statusSlice();
7770
+ init_hooks();
7771
+
7772
+ // components/builder/BlockGraph.tsx
7773
+ init_esm_shims();
7774
+ init_store2();
7775
+ function BlockGraph() {
7776
+ const [screenWidth, setScreenWidth] = useState(window.innerWidth - 40);
7777
+ const [screenHeight, setScreenHeight] = useState(window.innerHeight - 150);
7778
+ useEffect(() => {
7779
+ const handleResize = () => {
7780
+ setScreenWidth(window.innerWidth - 40);
7781
+ setScreenHeight(window.innerHeight - 120);
7782
+ };
7783
+ window.addEventListener("resize", handleResize);
7784
+ return () => {
7785
+ window.removeEventListener("resize", handleResize);
7786
+ };
7787
+ }, []);
7788
+ const blocks = useBlockList();
7789
+ const sections = useSectionList();
7790
+ const [sectionSelected, setSectionSelected] = useState(null);
7791
+ const sectionList = useMemo(() => {
7792
+ if (sections.isSuccess) {
7793
+ const sectionsOptions = sections.data.map((n) => ({
7794
+ value: `${n.id}`,
7795
+ label: `Section ${n.id}`
7796
+ }));
7797
+ setSectionSelected(sectionsOptions[0].value);
7798
+ return sectionsOptions;
7799
+ } else {
7800
+ return [];
7801
+ }
7802
+ }, [sections.isLoading]);
7803
+ const data = useMemo(() => {
7804
+ if (blocks.isSuccess && sectionSelected) {
7805
+ const rootNode = { id: "root", label: "section", size: 40, parentIds: [] };
7806
+ const globalNode = { id: "wide", label: "report", size: 40, parentIds: [] };
7807
+ const sectionBlocks = blocks.data.filter((n) => `${n.section_id}` === `${sectionSelected}`);
7808
+ const sectionBlocksIds = sectionBlocks.map((n) => n.id);
7809
+ return [
7810
+ rootNode,
7811
+ globalNode,
7812
+ ...sectionBlocks.map((n) => {
7813
+ const projectedSize = n.consumers.length > 0 ? n.consumers.length * 20 : 40;
7814
+ const parentIds = n.inputs.length > 0 ? n.inputs.map((i) => sectionBlocksIds.includes(i) ? `${i}` : `${globalNode.id}`) : [`${rootNode.id}`];
7815
+ return {
7816
+ id: `${n.id}`,
7817
+ label: `${n.type}`,
7818
+ size: projectedSize > 50 ? 50 : projectedSize,
7819
+ parentIds: [...Array.from(new Set(parentIds))]
7820
+ };
7821
+ })
7822
+ ];
7823
+ } else {
7824
+ return [];
7825
+ }
7826
+ }, [blocks.isLoading, sectionSelected]);
7827
+ const svgRef = useRef(null);
7828
+ useEffect(() => {
7829
+ const dag = d3Dag.dagStratify()(data);
7830
+ const nodeRadius = 40;
7831
+ const layout = d3Dag.sugiyama().nodeSize((node) => {
7832
+ const data2 = node ? node.data : null;
7833
+ const internalRadius = data2 ? data2.size : nodeRadius;
7834
+ return [(node ? 3.6 : 0.25) * internalRadius, 3 * internalRadius];
7835
+ });
7836
+ const { width, height } = layout(dag);
7837
+ const svgSelection = d3.select(svgRef.current);
7838
+ svgSelection.selectAll("*").remove();
7839
+ svgSelection.attr("viewBox", [0, 0, width, height].join(" "));
7840
+ const defs = svgSelection.append("defs");
7841
+ const steps = dag.size();
7842
+ const interp = d3.interpolateRainbow;
7843
+ const colorMap = /* @__PURE__ */ new Map();
7844
+ data.forEach((node, i) => {
7845
+ colorMap.set(node.id, interp(i / steps));
7846
+ });
7847
+ const line2 = d3.line().curve(d3.curveCatmullRom).x((d) => d.x).y((d) => d.y);
7848
+ const paths = svgSelection.append("g").selectAll("g").data(dag.links()).enter().append("g");
7849
+ paths.append("path").attr("class", "curve").attr("d", ({ points }) => line2(points)).attr("fill", "none").attr("stroke-width", 3).attr("stroke", ({ source, target }) => {
7850
+ const gradId = encodeURIComponent(`${source.data.id}--${target.data.id}`);
7851
+ 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);
7852
+ grad.append("stop").attr("offset", "0%").attr("stop-color", colorMap.get(source.data.id));
7853
+ grad.append("stop").attr("offset", "100%").attr("stop-color", colorMap.get(target.data.id));
7854
+ return `url(#${gradId})`;
7855
+ });
7856
+ const nodes = svgSelection.append("g").selectAll("g").data(dag.descendants()).enter().append("g").attr("transform", ({ x, y }) => `translate(${x}, ${y})`);
7857
+ nodes.append("circle").attr("r", (n) => n.data.size).attr("fill", (n) => colorMap.get(n.data.id));
7858
+ const arrows = svgSelection.append("g").selectAll("g").data(dag.links()).enter().append("g");
7859
+ const arrow = d3.symbol().type(d3.symbolTriangle).size(nodeRadius * 1.5);
7860
+ arrows.append("path").attr("class", "arrow").attr("d", arrow).attr("transform", (link) => {
7861
+ const { points, target } = link;
7862
+ const [end, start] = points.reverse();
7863
+ const dx = start.x - end.x;
7864
+ const dy = start.y - end.y;
7865
+ const scale = target.data.size * 1 / Math.sqrt(dx * dx + dy * dy);
7866
+ const angle = Math.atan2(-dy, -dx) * 180 / Math.PI + 90;
7867
+ return `translate(${end.x + dx * scale}, ${end.y + dy * scale}) rotate(${angle})`;
7868
+ }).attr("fill", ({ target }) => colorMap.get(target.data.id)).attr("stroke", "white");
7869
+ const texts = svgSelection.append("g").selectAll("g").data(dag.descendants()).enter().append("g").attr("transform", ({ x, y }) => `translate(${x}, ${y})`);
7870
+ 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");
7871
+ 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");
7872
+ }, [data]);
7873
+ const handlePrev = () => {
7874
+ const currentIndex = sectionList.findIndex((item) => item.value === sectionSelected);
7875
+ if (currentIndex > 0) {
7876
+ setSectionSelected(sectionList[currentIndex - 1].value);
7877
+ }
7878
+ };
7879
+ const handleNext = () => {
7880
+ const currentIndex = sectionList.findIndex((item) => item.value === sectionSelected);
7881
+ if (currentIndex < sectionList.length - 1) {
7882
+ setSectionSelected(sectionList[currentIndex + 1].value);
7883
+ }
7884
+ };
7885
+ return /* @__PURE__ */ jsxs(Stack, { spacing: 0, children: [
7886
+ /* @__PURE__ */ jsxs(Group, { align: "flex-end", w: "100%", position: "apart", children: [
7887
+ /* @__PURE__ */ jsx(
7888
+ Select,
7889
+ {
7890
+ label: "Chooose a section",
7891
+ placeholder: "Pick one",
7892
+ value: sectionSelected,
7893
+ onChange: setSectionSelected,
7894
+ data: sectionList,
7895
+ width: "80%"
7896
+ }
7897
+ ),
7898
+ /* @__PURE__ */ jsxs(Group, { grow: true, maw: 100, children: [
7899
+ /* @__PURE__ */ jsx(ActionIcon, { onClick: handlePrev, variant: "outline", children: /* @__PURE__ */ jsx(IconChevronLeft, { size: "1.125rem" }) }),
7900
+ /* @__PURE__ */ jsx(ActionIcon, { onClick: handleNext, variant: "outline", children: /* @__PURE__ */ jsx(IconChevronRight, { size: "1.125rem" }) })
7901
+ ] })
7902
+ ] }),
7903
+ /* @__PURE__ */ jsx("svg", { ref: svgRef, width: screenWidth, height: screenHeight })
7904
+ ] });
7905
+ }
7466
7906
  function CMSHeader(props) {
7467
- const { report: currentReport, profilePrefix } = props;
7907
+ const { report: currentReport } = props;
7468
7908
  const { id } = currentReport;
7469
7909
  const { newConfirmation } = useDialog();
7470
7910
  const dispatch = useAppDispatch();
7471
7911
  const resource = useContext(ResourceContext);
7912
+ const profilePrefix = useProfilePrefix();
7472
7913
  const currentLocale = useAppSelector((state) => state.status.currentLocale);
7473
7914
  const localeDefault9 = useAppSelector((state) => state.status.localeDefault);
7474
7915
  const localeOptions = useAppSelector(selectLocaleOptions);
7475
7916
  const previewsFromState = useAppSelector((state) => state.status.previews);
7476
7917
  const [opened, handlers] = useDisclosure(false);
7918
+ const [openedGraph, handlersGraph] = useDisclosure(false);
7477
7919
  const { user } = useUser();
7478
7920
  const castedUser = user;
7479
7921
  const dimensions = useMemo(() => {
@@ -7651,9 +8093,11 @@ function CMSHeader(props) {
7651
8093
  /* @__PURE__ */ jsx(Text, { fw: 700, children: currentReport.name })
7652
8094
  ] }) }),
7653
8095
  /* @__PURE__ */ jsx(Menu.Label, { children: "Settings" }),
7654
- /* @__PURE__ */ jsx(Menu.Item, { onClick: handlers.open, icon: /* @__PURE__ */ jsx(IconSettings, { size: 20 }), children: "Report 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" })
7655
8098
  ] })
7656
8099
  ] }),
8100
+ /* @__PURE__ */ jsx(Modal, { opened: openedGraph, onClose: handlersGraph.close, title: "Block Graph", fullScreen: true, children: /* @__PURE__ */ jsx(BlockGraph, {}) }),
7657
8101
  /* @__PURE__ */ jsx(
7658
8102
  Drawer,
7659
8103
  {
@@ -7747,6 +8191,15 @@ var customSettings = {
7747
8191
  { label: "6", value: "6" }
7748
8192
  ]
7749
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
+ },
7750
8203
  ...defaultSettings2
7751
8204
  },
7752
8205
  [BLOCK_TYPES.GENERATOR]: {
@@ -7760,8 +8213,8 @@ var customSettings = {
7760
8213
  }
7761
8214
  },
7762
8215
  [BLOCK_TYPES.NAV]: {
7763
- type: {
7764
- label: "Nav type",
8216
+ variant: {
8217
+ label: "Nav variant",
7765
8218
  defaultValue: "inline",
7766
8219
  options: [
7767
8220
  { label: "Inline", value: "inline" },
@@ -8039,7 +8492,8 @@ var emptyStatus = {
8039
8492
  duration: null,
8040
8493
  error: null,
8041
8494
  log: [],
8042
- resp: null
8495
+ resp: null,
8496
+ allowed: true
8043
8497
  };
8044
8498
  function BlockPreview(props) {
8045
8499
  const {
@@ -9324,13 +9778,15 @@ function SectionHeader({
9324
9778
  active,
9325
9779
  isDragging,
9326
9780
  id,
9327
- dragHandleProps
9781
+ dragHandleProps,
9782
+ hidden
9328
9783
  }) {
9329
9784
  return /* @__PURE__ */ jsxs(
9330
9785
  Group,
9331
9786
  {
9332
9787
  className: `cms-section-header${active || isDragging ? " active" : ""}`,
9333
9788
  position: "apart",
9789
+ bg: hidden ? "red.1" : "none",
9334
9790
  children: [
9335
9791
  /* @__PURE__ */ jsxs(Group, { className: "cms-section-header-editor", spacing: 0, children: [
9336
9792
  /* @__PURE__ */ jsxs(Code, { style: { backgroundColor: "transparent" }, children: [
@@ -9339,6 +9795,7 @@ function SectionHeader({
9339
9795
  ] }, "s1"),
9340
9796
  /* @__PURE__ */ jsx(ActionIcon, { ...dragHandleProps, children: /* @__PURE__ */ jsx(IconMenu, { size: 16 }) }, "b1")
9341
9797
  ] }),
9798
+ hidden && /* @__PURE__ */ jsx(Text, { size: "xs", fw: 600, color: "dark.3", children: "Section will be hidden on the frontend" }),
9342
9799
  /* @__PURE__ */ jsx(SectionMenu_default, { sectionId: id })
9343
9800
  ]
9344
9801
  }
@@ -9360,7 +9817,7 @@ function SectionEditor({
9360
9817
  const [sectionState, setSectionState2] = useSetState({});
9361
9818
  const blocks = useAppSelector((state) => state.records.entities.block);
9362
9819
  const blockSettings = getBlockSettings();
9363
- const { memberImageBg, optionsMenu } = section.settings;
9820
+ const { memberImageBg, optionsMenu, hidden } = section.settings;
9364
9821
  const [hoverBlock, setHoverBlock] = useState();
9365
9822
  const { inputs, consumers } = useMemo(() => {
9366
9823
  if (hoverBlock) {
@@ -9473,6 +9930,7 @@ function SectionEditor({
9473
9930
  active: isActive,
9474
9931
  id: section.id,
9475
9932
  isDragging,
9933
+ hidden,
9476
9934
  dragHandleProps
9477
9935
  }
9478
9936
  ),
@@ -9645,7 +10103,7 @@ init_ordering();
9645
10103
  init_store2();
9646
10104
  init_actions();
9647
10105
  function BuilderEditor(props) {
9648
- const { profilePrefix, id } = props;
10106
+ const { id } = props;
9649
10107
  const reportRef = useReportRef(id);
9650
10108
  return useMemo(() => {
9651
10109
  if (reportRef.isError) {
@@ -9659,14 +10117,13 @@ function BuilderEditor(props) {
9659
10117
  {
9660
10118
  report: reportRef.data,
9661
10119
  locale: props.locale,
9662
- isLoading: reportRef.isFetching,
9663
- profilePrefix
10120
+ isLoading: reportRef.isFetching
9664
10121
  }
9665
10122
  );
9666
10123
  }, [reportRef.status, reportRef.data?.sections]);
9667
10124
  }
9668
10125
  function InteractiveReport(props) {
9669
- const { report, isLoading, profilePrefix } = props;
10126
+ const { report, isLoading } = props;
9670
10127
  const theme = useMantineTheme();
9671
10128
  const dispatch = useAppDispatch();
9672
10129
  const resource = useContext(ResourceContext);
@@ -9744,7 +10201,7 @@ function InteractiveReport(props) {
9744
10201
  }
9745
10202
  ), [sectionOrder, activeSection, maybeActivate]);
9746
10203
  return /* @__PURE__ */ jsxs(Stack, { styles: { backgroundColor: theme.colors.gray[2] }, spacing: 0, children: [
9747
- /* @__PURE__ */ jsx(CMSHeader, { report, profilePrefix }),
10204
+ /* @__PURE__ */ jsx(CMSHeader, { report }),
9748
10205
  /* @__PURE__ */ jsxs(Alert, { icon: /* @__PURE__ */ jsx(IconFlag, {}), children: [
9749
10206
  "You are editing the ",
9750
10207
  /* @__PURE__ */ jsx(Code, { children: currentLocale.toUpperCase() }),
@@ -10112,7 +10569,7 @@ function FormatterForm({ formatterId, onEditEnd }) {
10112
10569
  }
10113
10570
  )
10114
10571
  ] }),
10115
- size: 145
10572
+ size: 165
10116
10573
  }
10117
10574
  )
10118
10575
  }
@@ -11054,7 +11511,7 @@ function MemberForm({ memberId, onEditEnd }) {
11054
11511
  }
11055
11512
  )
11056
11513
  ] }),
11057
- size: 145
11514
+ size: 165
11058
11515
  }
11059
11516
  )
11060
11517
  }
@@ -11106,6 +11563,11 @@ function MembersTable({ members, onClickEdit, onSort }) {
11106
11563
  title: "Variant",
11107
11564
  accessor: "variant.name"
11108
11565
  },
11566
+ {
11567
+ title: "Relevance",
11568
+ sortable: true,
11569
+ accessor: "zvalue"
11570
+ },
11109
11571
  {
11110
11572
  title: "Slug",
11111
11573
  accessor: "slug",
@@ -11217,8 +11679,8 @@ function MetadataEditor() {
11217
11679
  ...getParams,
11218
11680
  locale: "all",
11219
11681
  includes: true,
11220
- sort: internalSort ? internalSort.columnAccessor : "id",
11221
- direction: internalSort ? internalSort.direction : "asc"
11682
+ sort: internalSort ? internalSort.columnAccessor : "zvalue",
11683
+ direction: internalSort ? internalSort.direction : "desc"
11222
11684
  }
11223
11685
  }
11224
11686
  ).then((response) => response.data && response.data.data && response.data.data.results ? response.data.data.results : []);
@@ -11807,7 +12269,7 @@ function UserForm({ userId, onEditEnd, roles }) {
11807
12269
  }
11808
12270
  )
11809
12271
  ] }),
11810
- size: 145
12272
+ size: 165
11811
12273
  }
11812
12274
  )
11813
12275
  }
@@ -11997,7 +12459,7 @@ function BespokeManager(options) {
11997
12459
  title = "Bespoke CMS",
11998
12460
  pathSegment = "bespoke",
11999
12461
  locale = localeDefault4,
12000
- profilePrefix
12462
+ profilePrefix = "/profilePathManager"
12001
12463
  } = options;
12002
12464
  const notifications3 = {
12003
12465
  position: "bottom-center",
@@ -12009,17 +12471,17 @@ function BespokeManager(options) {
12009
12471
  FailureComponent: UnauthorizeView
12010
12472
  });
12011
12473
  function BespokeManagerPage() {
12012
- return /* @__PURE__ */ jsxs(ResourceProvider, { pathSegment, children: [
12474
+ return /* @__PURE__ */ jsxs(ResourceProvider, { pathSegment, profilePrefix, children: [
12013
12475
  /* @__PURE__ */ jsx(Head, { children: /* @__PURE__ */ jsx("title", { children: title }) }),
12014
12476
  /* @__PURE__ */ jsxs(MantineProvider, { inherit: false, children: [
12015
12477
  /* @__PURE__ */ jsx(Notifications, { ...notifications3 }),
12016
- /* @__PURE__ */ jsx(DialogProvider, { children: /* @__PURE__ */ jsx(BespokeManagerShell, { locale, profilePrefix }) })
12478
+ /* @__PURE__ */ jsx(DialogProvider, { children: /* @__PURE__ */ jsx(BespokeManagerShell, { locale }) })
12017
12479
  ] })
12018
12480
  ] });
12019
12481
  }
12020
12482
  }
12021
12483
  function BespokeManagerShell(props) {
12022
- const { locale, profilePrefix } = props;
12484
+ const { locale } = props;
12023
12485
  const [opened, { toggle: toggleOpened }] = useDisclosure(true);
12024
12486
  const { user, error, isLoading } = useUser();
12025
12487
  const location = useManagerLocation();
@@ -12145,7 +12607,7 @@ function BespokeManagerShell(props) {
12145
12607
  if (location.page === "reports") {
12146
12608
  if (location.params.length > 0) {
12147
12609
  const reportId = Number.parseInt(location.params[0]);
12148
- return /* @__PURE__ */ jsx(BuilderEditor, { id: reportId, locale, profilePrefix });
12610
+ return /* @__PURE__ */ jsx(BuilderEditor, { id: reportId, locale });
12149
12611
  }
12150
12612
  return /* @__PURE__ */ jsx(ReportPicker, {});
12151
12613
  }
@@ -12196,12 +12658,13 @@ init_ResourceProvider();
12196
12658
  function BespokeRenderer({
12197
12659
  pathSegmentsKey = "bespoke",
12198
12660
  bespokeStyles,
12199
- buildTime
12661
+ buildTime,
12662
+ profilePrefix = "/defaultPath"
12200
12663
  }) {
12201
12664
  const loading = useInitialState(pathSegmentsKey);
12202
12665
  if (loading)
12203
12666
  return /* @__PURE__ */ jsx(LoadingOverlay, { visible: true });
12204
- return /* @__PURE__ */ jsx(MantineProvider, { theme: { other: { bespokeStyles } }, inherit: true, children: /* @__PURE__ */ jsxs(ResourceProvider, { pathSegment: "bespoke", children: [
12667
+ return /* @__PURE__ */ jsx(MantineProvider, { theme: { other: { bespokeStyles } }, inherit: true, children: /* @__PURE__ */ jsxs(ResourceProvider, { pathSegment: "bespoke", profilePrefix, children: [
12205
12668
  /* @__PURE__ */ jsx(Report_default, {}),
12206
12669
  /* @__PURE__ */ jsx("small", { children: buildTime })
12207
12670
  ] }) });