@datawheel/bespoke 0.1.21 → 0.1.23

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 +331 -200
  2. package/dist/server.js +137 -42
  3. package/package.json +10 -10
package/dist/index.js CHANGED
@@ -12,17 +12,17 @@ import toposort from 'toposort';
12
12
  import { schema, normalize } from 'normalizr';
13
13
  import { createSlice, configureStore } from '@reduxjs/toolkit';
14
14
  import { HYDRATE, createWrapper } from 'next-redux-wrapper';
15
- import { NotificationsProvider, showNotification } from '@mantine/notifications';
15
+ 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, Overlay, Grid, Input, Popover, Checkbox, Radio, Switch, Drawer, Tabs, Header, SimpleGrid, Image, Paper, FileInput, Accordion, CopyButton, NumberInput, Col } from '@mantine/core';
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, Overlay, Grid, Input, Popover, Checkbox, Radio, Switch, Drawer, Tabs, Header, px, SimpleGrid, Image, Paper, FileInput, Accordion, CopyButton, NumberInput, Col, rem } from '@mantine/core';
20
20
  import { dataConcat } from 'd3plus-viz';
21
21
  import * as d3plus from 'd3plus-react';
22
- import { IconInfoCircle, IconBoxMargin, IconTable, IconMathFunction, IconUsers, IconLogout, IconSearch, IconTrash, IconUserCircle, IconDatabase, IconServer, IconPencil, IconAlertCircle, IconCircleCheck, IconPlayerPlay, IconCirclePlus, IconCircleX, IconFlag, IconFileAnalytics, IconPlus, IconCamera, IconShare, IconCircleDashed, IconListSearch, IconRefreshAlert, IconSettings, IconMenu, IconRefresh, IconPolaroid, IconCircleMinus, IconEyeOff, IconAlignLeft, IconAlignCenter, IconAlignRight, IconLogin, IconWorld, IconLock, IconVariable, IconArrowRightCircle, IconExternalLink, IconDownload, IconTemplate, IconChartBar, IconCode, IconUpload, IconLink, IconClipboardCheck, IconClipboardCopy, IconPalette, IconEye, IconRss, IconGlobe } from '@tabler/icons';
23
- import { useDisclosure, useDebouncedValue, useMediaQuery, useHotkeys, getHotkeyHandler } from '@mantine/hooks';
24
- import Link from 'next/link';
25
22
  import Router, { useRouter } from 'next/router';
23
+ import { IconInfoCircle, IconBoxMargin, IconTable, IconMathFunction, IconUsers, IconLogout, IconSearch, IconTrash, IconUserCircle, IconEdit, IconDatabase, IconServer, IconPencil, IconAlertCircle, IconCircleCheck, IconPlayerPlay, IconCirclePlus, IconCircleX, IconFlag, IconFileAnalytics, IconPlus, IconCamera, IconShare, IconCircleDashed, IconListSearch, IconExternalLink, IconSettings, IconFileOff, IconFilesOff, IconMenu, IconRefresh, IconPolaroid, IconCircleMinus, IconEyeOff, IconAlignLeft, IconAlignCenter, IconAlignRight, IconLogin, IconWorld, IconLock, IconVariable, IconArrowRightCircle, IconDownload, IconTemplate, IconChartBar, IconCode, IconUpload, IconLink, IconClipboardCheck, IconClipboardCopy, IconPalette, IconEye, IconMinimize, IconMaximize, IconRss, IconGlobe } from '@tabler/icons';
24
+ import { useDisclosure, useDebouncedValue, useMediaQuery, useHotkeys, useFullscreen, getHotkeyHandler } from '@mantine/hooks';
25
+ import Link from 'next/link';
26
26
  import dynamic from 'next/dynamic';
27
27
  import { UserProvider, withPageAuthRequired, useUser } from '@auth0/nextjs-auth0/client';
28
28
  import { Prism } from '@mantine/prism';
@@ -58,8 +58,8 @@ var init_esm_shims = __esm({
58
58
  });
59
59
 
60
60
  // api/http/lib.ts
61
- function http(axios7, config) {
62
- return axios7.request(config).then((response) => {
61
+ function http(axios6, config) {
62
+ return axios6.request(config).then((response) => {
63
63
  const { status, data } = response;
64
64
  return "error" in data ? { ok: false, status, error: data.error } : { ok: true, status, data: data.data };
65
65
  }, (err) => {
@@ -70,25 +70,25 @@ function http(axios7, config) {
70
70
  return { ok: false, status: 500, error: err.message };
71
71
  });
72
72
  }
73
- function httpGET(axios7, request, transformParams) {
73
+ function httpGET(axios6, request, transformParams) {
74
74
  const config = typeof request === "string" ? { url: request } : request;
75
- return (params) => http(axios7, {
75
+ return (params) => http(axios6, {
76
76
  ...config,
77
77
  method: "GET",
78
78
  params: transformParams ? transformParams(params) : params
79
79
  });
80
80
  }
81
- function httpPOST(axios7, request, transformPayload) {
81
+ function httpPOST(axios6, request, transformPayload) {
82
82
  const config = typeof request === "string" ? { url: request } : request;
83
- return (payload) => http(axios7, {
83
+ return (payload) => http(axios6, {
84
84
  ...config,
85
85
  method: "POST",
86
86
  data: transformPayload ? transformPayload(payload) : payload
87
87
  });
88
88
  }
89
- function httpDELETE(axios7, request, transformPayload) {
89
+ function httpDELETE(axios6, request, transformPayload) {
90
90
  const config = typeof request === "string" ? { url: request } : request;
91
- return (payload) => http(axios7, {
91
+ return (payload) => http(axios6, {
92
92
  ...config,
93
93
  method: "DELETE",
94
94
  data: transformPayload ? transformPayload(payload) : payload
@@ -101,8 +101,8 @@ var init_lib = __esm({
101
101
  });
102
102
 
103
103
  // api/http/image/imageSave.ts
104
- function httpImageSaveFactory(axios7, provider) {
105
- return (params) => http(axios7, {
104
+ function httpImageSaveFactory(axios6, provider) {
105
+ return (params) => http(axios6, {
106
106
  method: "GET",
107
107
  url: `search/images/${provider}`,
108
108
  params: { prompt: params.prompt, provider }
@@ -116,8 +116,8 @@ var init_imageSave = __esm({
116
116
  });
117
117
 
118
118
  // api/http/image/imageSearch.ts
119
- function httpImageSearchFactory(axios7, provider) {
120
- return (params) => http(axios7, {
119
+ function httpImageSearchFactory(axios6, provider) {
120
+ return (params) => http(axios6, {
121
121
  method: "GET",
122
122
  url: `search/images/${provider}`,
123
123
  params: { prompt: params.prompt, provider }
@@ -130,58 +130,59 @@ var init_imageSearch = __esm({
130
130
  }
131
131
  });
132
132
  function apiFactory(baseURL) {
133
- const axios7 = axios.create({ baseURL });
133
+ const axios6 = axios.create({ baseURL });
134
134
  return {
135
- createBlock: httpPOST(axios7, "create/block"),
136
- createDimension: httpPOST(axios7, "create/dimension"),
137
- createFormatter: httpPOST(axios7, "create/formatter"),
138
- createReport: httpPOST(axios7, "create/report"),
139
- createSection: httpPOST(axios7, "create/section"),
140
- createVariant: httpPOST(axios7, "create/variant"),
141
- deleteBlock: httpDELETE(axios7, "delete/block", transformDeletePayload),
142
- deleteDimension: httpDELETE(axios7, "delete/dimension", transformDeletePayload),
143
- deleteFormatter: httpDELETE(axios7, "delete/formatter", transformDeletePayload),
144
- deleteReport: httpDELETE(axios7, "delete/report", transformDeletePayload),
145
- deleteSection: httpDELETE(axios7, "delete/section", transformDeletePayload),
146
- deleteVariant: httpDELETE(axios7, "delete/variant", transformDeletePayload),
147
- readBlock: httpGET(axios7, "read/block"),
148
- readDimension: httpGET(axios7, "read/dimension"),
149
- readFormatter: httpGET(axios7, "read/formatter"),
150
- readReport: httpGET(axios7, "read/report"),
151
- readSection: httpGET(axios7, "read/section"),
152
- readVariant: httpGET(axios7, "read/variant"),
153
- updateBlock: httpPOST(axios7, "update/block"),
154
- updateDimension: httpPOST(axios7, "update/dimension"),
155
- updateFormatter: httpPOST(axios7, "update/formatter"),
156
- updateReport: httpPOST(axios7, "update/report"),
157
- updateSection: httpPOST(axios7, "update/section"),
158
- updateVariant: httpPOST(axios7, "update/variant"),
159
- searchReport: httpGET(axios7, "search/reports"),
160
- validateVariantSlug: httpGET(axios7, "validate/variant"),
161
- readMember: httpGET(axios7, "read/members", transformReadMembers),
162
- readMemberImage: httpGET(axios7, {
135
+ createBlock: httpPOST(axios6, "create/block"),
136
+ createDimension: httpPOST(axios6, "create/dimension"),
137
+ createFormatter: httpPOST(axios6, "create/formatter"),
138
+ createReport: httpPOST(axios6, "create/report"),
139
+ createSection: httpPOST(axios6, "create/section"),
140
+ createVariant: httpPOST(axios6, "create/variant"),
141
+ deleteBlock: httpDELETE(axios6, "delete/block", transformDeletePayload),
142
+ deleteDimension: httpDELETE(axios6, "delete/dimension", transformDeletePayload),
143
+ deleteFormatter: httpDELETE(axios6, "delete/formatter", transformDeletePayload),
144
+ deleteReport: httpDELETE(axios6, "delete/report", transformDeletePayload),
145
+ deleteSection: httpDELETE(axios6, "delete/section", transformDeletePayload),
146
+ deleteVariant: httpDELETE(axios6, "delete/variant", transformDeletePayload),
147
+ readBlock: httpGET(axios6, "read/block"),
148
+ readDimension: httpGET(axios6, "read/dimension"),
149
+ readFormatter: httpGET(axios6, "read/formatter"),
150
+ readReport: httpGET(axios6, "read/report"),
151
+ readSection: httpGET(axios6, "read/section"),
152
+ readVariant: httpGET(axios6, "read/variant"),
153
+ updateBlock: httpPOST(axios6, "update/block"),
154
+ updateDimension: httpPOST(axios6, "update/dimension"),
155
+ updateFormatter: httpPOST(axios6, "update/formatter"),
156
+ updateReport: httpPOST(axios6, "update/report"),
157
+ updateSection: httpPOST(axios6, "update/section"),
158
+ updateVariant: httpPOST(axios6, "update/variant"),
159
+ searchReport: httpGET(axios6, "search/reports"),
160
+ validateVariantSlug: httpGET(axios6, "validate/variant"),
161
+ readMember: httpGET(axios6, "read/members", transformReadMembers),
162
+ readMemberImage: httpGET(axios6, {
163
163
  url: "member/image.png",
164
164
  responseType: "blob"
165
165
  }),
166
- searchMember: httpGET(axios7, "search/members"),
167
- updateMember: httpGET(axios7, "update/members"),
168
- imageLocalSearch: httpImageSearchFactory(axios7, "local"),
169
- imageLocalSave: httpImageSaveFactory(axios7, "local"),
170
- imageFlickrSearch: httpImageSearchFactory(axios7, "flickr"),
171
- imageFlickrSave: httpImageSaveFactory(axios7, "flickr"),
172
- imageUnsplashSearch: httpImageSearchFactory(axios7, "unsplash"),
173
- imageUnsplashSave: httpImageSaveFactory(axios7, "unsplash"),
174
- imageUploadSave: httpImageSaveFactory(axios7, "upload"),
175
- readMetadata: httpGET(axios7, "read/metadata"),
176
- regenerateSearch: httpPOST(axios7, "search/regenerate"),
177
- urlProxy: httpGET(axios7, "url/proxy"),
178
- searchRole: httpGET(axios7, "auth/search/roles"),
179
- searchUser: httpGET(axios7, "auth/search/users"),
180
- readUser: httpGET(axios7, "auth/read/user"),
181
- updateUser: httpPOST(axios7, "auth/update/user"),
182
- addNewReportToCurrentUser: httpPOST(axios7, "auth/update/me"),
183
- revalidate: httpGET(axios7, "revalidate/report"),
184
- readPrivateBlocks: httpPOST(axios7, "read/blocks/private")
166
+ searchMember: httpGET(axios6, "search/members"),
167
+ updateMember: httpGET(axios6, "update/members"),
168
+ imageLocalSearch: httpImageSearchFactory(axios6, "local"),
169
+ imageLocalSave: httpImageSaveFactory(axios6, "local"),
170
+ imageFlickrSearch: httpImageSearchFactory(axios6, "flickr"),
171
+ imageFlickrSave: httpImageSaveFactory(axios6, "flickr"),
172
+ imageUnsplashSearch: httpImageSearchFactory(axios6, "unsplash"),
173
+ imageUnsplashSave: httpImageSaveFactory(axios6, "unsplash"),
174
+ imageUploadSave: httpImageSaveFactory(axios6, "upload"),
175
+ readMetadata: httpGET(axios6, "read/metadata"),
176
+ regenerateSearch: httpPOST(axios6, "search/regenerate"),
177
+ urlProxy: httpGET(axios6, "url/proxy"),
178
+ searchRole: httpGET(axios6, "auth/search/roles"),
179
+ searchUser: httpGET(axios6, "auth/search/users"),
180
+ readUser: httpGET(axios6, "auth/read/user"),
181
+ updateUser: httpPOST(axios6, "auth/update/user"),
182
+ addNewReportToCurrentUser: httpPOST(axios6, "auth/update/me"),
183
+ revalidateReport: httpGET(axios6, "revalidate/report"),
184
+ revalidateUrl: httpGET(axios6, "revalidate/url"),
185
+ readPrivateBlocks: httpPOST(axios6, "read/blocks/private")
185
186
  };
186
187
  }
187
188
  var transformDeletePayload, transformReadMembers;
@@ -1111,9 +1112,9 @@ var init_runConsumers = __esm({
1111
1112
  if (rootBlock.consumers.length && crawlDown) {
1112
1113
  rootBlock.consumers.forEach((cid) => {
1113
1114
  const rel = `${bid}-${cid}`;
1114
- if (!acc.includes(rel))
1115
+ if (!acc.includes(rel) && blocks[cid].section_id === blocks[bid].section_id)
1115
1116
  acc.push(rel);
1116
- rootBlock.consumers.forEach((cid2) => getDependencies(cid2, blocks, acc, crawlUp, crawlDown));
1117
+ rootBlock.consumers.filter((cid2) => blocks[cid2].section_id === blocks[bid].section_id).forEach((cid2) => getDependencies(cid2, blocks, acc, crawlUp, crawlDown));
1117
1118
  });
1118
1119
  }
1119
1120
  return acc;
@@ -1310,13 +1311,14 @@ var init_FUNC = __esm({
1310
1311
  "libs/FUNC.js"() {
1311
1312
  init_esm_shims();
1312
1313
  init_libs();
1313
- parse = (config, formatters = {}, locale = "en", actions = {}) => {
1314
+ parse = (config, formatters = {}, locale = "en", actions = {}, extraGlobals = {}) => {
1314
1315
  const globals = {
1315
1316
  setVariables: actions.onSetVariables ? actions.onSetVariables : (d) => d,
1316
1317
  openModal: actions.onOpenModal ? actions.onOpenModal : (d) => d,
1317
1318
  formatters,
1318
1319
  libs: libraries,
1319
- locale
1320
+ locale,
1321
+ ...extraGlobals
1320
1322
  };
1321
1323
  function parseFunction(obj) {
1322
1324
  return Function("globals", ...obj.vars, `with (globals) { ${obj.logic} }`).bind(globals, globals);
@@ -1848,7 +1850,7 @@ function rpcAnnounce(entity, key) {
1848
1850
  function rpcFailure(entity, key, code, message) {
1849
1851
  return (dispatch) => {
1850
1852
  if (typeof window === "object") {
1851
- showNotification({
1853
+ notifications.show({
1852
1854
  autoClose: 3e3,
1853
1855
  color: "red",
1854
1856
  id: key,
@@ -2035,6 +2037,8 @@ __export(actions_exports, {
2035
2037
  recalculateVariables: () => recalculateVariables,
2036
2038
  removeBlocksFromState: () => removeBlocksFromState,
2037
2039
  reportSearch: () => reportSearch,
2040
+ revalidateReport: () => revalidateReport,
2041
+ revalidateUrl: () => revalidateUrl,
2038
2042
  searchMember: () => searchMember,
2039
2043
  searchRegenerate: () => searchRegenerate,
2040
2044
  searchRole: () => searchRole,
@@ -2130,6 +2134,7 @@ function recalculateVariables(resource, params) {
2130
2134
  locale: currentLocale
2131
2135
  };
2132
2136
  const section = state.records.entities.section[sid];
2137
+ console.log(section?.blocks);
2133
2138
  const data = await runConsumersV2(
2134
2139
  blocks,
2135
2140
  section && [section],
@@ -2225,6 +2230,26 @@ function readPrivateBlocks(params) {
2225
2230
  return result.data;
2226
2231
  };
2227
2232
  }
2233
+ function revalidateUrl(params) {
2234
+ return async (_, __, api) => {
2235
+ const result = await api.revalidateUrl({ target: params.target });
2236
+ if ("error" in result) {
2237
+ throw new Error(result.error);
2238
+ }
2239
+ return result.data;
2240
+ };
2241
+ }
2242
+ function revalidateReport(params) {
2243
+ return async (_, __, api) => {
2244
+ const result = await api.revalidateReport(
2245
+ { reportId: params.reportId, profilePrefix: params.profilePrefix }
2246
+ );
2247
+ if ("error" in result) {
2248
+ throw new Error(result.error);
2249
+ }
2250
+ return result.data;
2251
+ };
2252
+ }
2228
2253
  var setStatus, setPreviews;
2229
2254
  var init_actions = __esm({
2230
2255
  "store/actions.ts"() {
@@ -2311,7 +2336,7 @@ function entityRefHookFactory(entity) {
2311
2336
  }, [key]);
2312
2337
  const value = useAppSelector(selector);
2313
2338
  useEffect(() => {
2314
- if (value.isUninitialized) {
2339
+ if (value.isUninitialized && id !== null) {
2315
2340
  dispatch(readEntity(entity, { id, include: true }));
2316
2341
  }
2317
2342
  return () => {
@@ -2381,6 +2406,7 @@ var init_hooks = __esm({
2381
2406
  return result;
2382
2407
  };
2383
2408
  useInputVariablesHash = (id) => {
2409
+ console.log("useInputVariablesHash", id);
2384
2410
  const block = useBlockRef(id).data;
2385
2411
  const variables = useAppSelector((state) => state.variables.variables);
2386
2412
  const attributes = useAppSelector((state) => state.variables.attributes);
@@ -2510,7 +2536,7 @@ var init_sanitizeBlockContent = __esm({
2510
2536
  sanitizeBlockContent_default = sanitizeBlockContent;
2511
2537
  }
2512
2538
  });
2513
- var localeDefault7, frontEndMessage, errorStub, d3plusPropify_default;
2539
+ var localeDefault7, frontEndMessage, errorStub, propify, d3plusPropify_default;
2514
2540
  var init_d3plusPropify = __esm({
2515
2541
  "libs/d3plusPropify.ts"() {
2516
2542
  init_esm_shims();
@@ -2525,10 +2551,10 @@ var init_d3plusPropify = __esm({
2525
2551
  <strong>${frontEndMessage}</strong>
2526
2552
  </p>`
2527
2553
  };
2528
- d3plusPropify_default = (logic, formatters, variables = {}, locale = localeDefault7, id = null, actions = {}) => {
2554
+ propify = (logic, formatters, variables = {}, locale = localeDefault7, id = null, actions = {}, globals = {}) => {
2529
2555
  let config;
2530
2556
  try {
2531
- config = parse({ vars: ["variables"], logic }, formatters, locale, actions)(variables);
2557
+ config = parse({ vars: ["variables"], logic }, formatters, locale, actions, globals)(variables);
2532
2558
  } catch (e) {
2533
2559
  console.error(`Parsing Error in propify (ID: ${id})`);
2534
2560
  console.error(`Error message: ${e.message}`);
@@ -2563,6 +2589,7 @@ var init_d3plusPropify = __esm({
2563
2589
  topojsonFormat
2564
2590
  };
2565
2591
  };
2592
+ d3plusPropify_default = propify;
2566
2593
  }
2567
2594
  });
2568
2595
 
@@ -2608,11 +2635,12 @@ function Viz(config) {
2608
2635
  const content = getBlockContent(block);
2609
2636
  const formatterFunctions = useFormatterFunctionsForLocale(locale);
2610
2637
  const blockContext = { variables };
2638
+ const router = useRouter();
2611
2639
  const vizProps = useMemo(() => {
2612
2640
  if (!content?.logic)
2613
2641
  return { error: "Add a Configuration" };
2614
2642
  const transpiledLogic = varSwapRecursive_default({ logic: content.logic }, formatterFunctions, blockContext).logic;
2615
- return d3plusPropify_default(transpiledLogic, formatterFunctions, variables, locale, block.id, {});
2643
+ return d3plusPropify_default(transpiledLogic, formatterFunctions, variables, locale, block.id, {}, { router });
2616
2644
  }, [block, active, variables]);
2617
2645
  const { type } = vizProps.config || {};
2618
2646
  const fallbackType = type && vizTypes[type] ? type : "Treemap";
@@ -2818,13 +2846,14 @@ function Viz2({
2818
2846
  const content = getBlockContent(block);
2819
2847
  const formatterFunctions = useFormatterFunctionsForLocale(locale);
2820
2848
  const blockContext = { variables };
2849
+ const router = useRouter();
2821
2850
  const vizProps = useMemo(() => {
2822
2851
  if (!active)
2823
2852
  return { error: "Activate to View" };
2824
2853
  if (!content?.logic)
2825
2854
  return { error: "Add a Configuration" };
2826
2855
  const transpiledLogic = varSwapRecursive_default({ logic: content.logic }, formatterFunctions, blockContext).logic;
2827
- return d3plusPropify_default(transpiledLogic, formatterFunctions, variables, locale, block.id, {});
2856
+ return d3plusPropify_default(transpiledLogic, formatterFunctions, variables, locale, block.id, {}, { router });
2828
2857
  }, [block, active, variables]);
2829
2858
  useMemo(() => {
2830
2859
  if (!active || !content?.logic)
@@ -3767,16 +3796,16 @@ function NavView({ headings, settings }) {
3767
3796
  if (!nodes || !nodes?.length) {
3768
3797
  return null;
3769
3798
  }
3770
- return /* @__PURE__ */ jsx(Fragment, { children: nodes.map((node) => /* @__PURE__ */ jsxs(Fragment, { children: [
3799
+ return /* @__PURE__ */ jsx(Fragment, { children: nodes.map((node) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
3771
3800
  /* @__PURE__ */ jsx(Menu.Item, { children: /* @__PURE__ */ jsx(
3772
3801
  Anchor,
3773
3802
  {
3774
3803
  href: `#bespoke-title-${node.id}`,
3775
- children: node.label
3804
+ dangerouslySetInnerHTML: { __html: node.label }
3776
3805
  }
3777
- ) }, node.id),
3806
+ ) }),
3778
3807
  /* @__PURE__ */ jsx(Box, { pl: "xs", children: renderMenu(node.children) })
3779
- ] })) });
3808
+ ] }, node.id)) });
3780
3809
  };
3781
3810
  return /* @__PURE__ */ jsx(Box, { component: "nav", children: /* @__PURE__ */ jsx(
3782
3811
  List,
@@ -3789,7 +3818,7 @@ function NavView({ headings, settings }) {
3789
3818
  }),
3790
3819
  children: contentOutline?.map(
3791
3820
  (node) => /* @__PURE__ */ jsx(List.Item, { children: /* @__PURE__ */ jsxs(Menu, { trigger: "hover", openDelay: 100, closeDelay: 400, children: [
3792
- /* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(Anchor, { href: `#bespoke-title-${node.id}`, children: node.label }) }),
3821
+ /* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(Anchor, { href: `#bespoke-title-${node.id}`, dangerouslySetInnerHTML: { __html: node.label } }) }),
3793
3822
  node?.children?.length ? /* @__PURE__ */ jsx(Menu.Dropdown, { children: renderMenu(node.children) }) : null
3794
3823
  ] }) }, node.id)
3795
3824
  )
@@ -4587,7 +4616,7 @@ function NavPreview({ headings, settings }) {
4587
4616
  if (!nodes || !nodes?.length) {
4588
4617
  return null;
4589
4618
  }
4590
- return /* @__PURE__ */ jsx(Fragment, { children: nodes.map((node) => /* @__PURE__ */ jsxs(Fragment, { children: [
4619
+ return /* @__PURE__ */ jsx(Fragment, { children: nodes.map((node) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
4591
4620
  /* @__PURE__ */ jsx(Menu.Item, { children: /* @__PURE__ */ jsxs(
4592
4621
  Anchor,
4593
4622
  {
@@ -4599,7 +4628,7 @@ function NavPreview({ headings, settings }) {
4599
4628
  }
4600
4629
  ) }, node.id),
4601
4630
  /* @__PURE__ */ jsx(Box, { pl: "xs", children: renderMenu(node.children) })
4602
- ] })) });
4631
+ ] }, node.id)) });
4603
4632
  };
4604
4633
  return /* @__PURE__ */ jsxs(Box, { pos: "relative", children: [
4605
4634
  /* @__PURE__ */ jsx(Tooltip, { label: `
@@ -4803,7 +4832,6 @@ function Block({ blockId, active = true }) {
4803
4832
  return;
4804
4833
  }
4805
4834
  if (block.type === BLOCK_TYPES.NAV) {
4806
- console.log("nav block", block);
4807
4835
  setContent({
4808
4836
  id: block.id,
4809
4837
  headings: block.inputs,
@@ -4828,8 +4856,6 @@ function Block({ blockId, active = true }) {
4828
4856
  }, [blockContent, variables]);
4829
4857
  if (!block || !content || !allowed)
4830
4858
  return null;
4831
- if (block.type === "nav")
4832
- console.log("nav", content);
4833
4859
  const Renderer = blocks_default[block.type];
4834
4860
  return /* @__PURE__ */ jsx("div", { id: `bespoke-${block.type}-${block.id}`, className: `cms-block-wrapper cms-block-${blockId}`, children: /* @__PURE__ */ jsx(Renderer, { ...content }) });
4835
4861
  }
@@ -5687,30 +5713,68 @@ var Report_default = Report;
5687
5713
 
5688
5714
  // frontend/components/auth/LoginButton.tsx
5689
5715
  init_esm_shims();
5716
+
5717
+ // types/auth.ts
5718
+ init_esm_shims();
5719
+ var CMS_ROLES = {
5720
+ ADMIN: "Admin",
5721
+ EDITOR: "Editor",
5722
+ WRITER: "Writer"
5723
+ };
5690
5724
  function BespokeLoginBtn({
5691
- options = "",
5692
5725
  buttonProps = {},
5693
- menuProps = {}
5726
+ editorMenuItemProps = {},
5727
+ editorMenuItemRoute = "/cms",
5728
+ logoutButtonProps = {},
5729
+ menuProps = {},
5730
+ options = "",
5731
+ optionsPosition = "bottom",
5732
+ translations = {},
5733
+ withEditorMenuItem = true,
5734
+ withSession = true
5694
5735
  }) {
5695
5736
  const { user, error, isLoading } = useUser();
5737
+ const userRoles = useMemo(() => user?.bespoke_roles || [], [user]);
5738
+ const isCMSUser = useMemo(() => CMS_ROLES && Object.keys(CMS_ROLES).length > 0 && Object.keys(CMS_ROLES).some((role) => userRoles.includes(CMS_ROLES[role])), [userRoles]);
5696
5739
  const buttonConfig = {
5697
5740
  leftIcon: /* @__PURE__ */ jsx(IconUserCircle, {}),
5698
5741
  ...buttonProps
5699
5742
  };
5700
5743
  if (user && !error && !isLoading) {
5744
+ const editorMenuItemConfig = {
5745
+ ...editorMenuItemProps
5746
+ };
5747
+ const logoutButtonConfig = {
5748
+ color: "red",
5749
+ fullWidth: true,
5750
+ leftIcon: /* @__PURE__ */ jsx(IconLogout, { size: 14 }),
5751
+ size: "xs",
5752
+ variant: "subtle",
5753
+ ...logoutButtonProps
5754
+ };
5701
5755
  const menuConfig = {
5702
5756
  shadow: "md",
5703
5757
  width: "auto",
5704
5758
  position: "bottom",
5705
5759
  ...menuProps
5706
5760
  };
5761
+ const cmsButton = /* @__PURE__ */ jsx(Link, { href: editorMenuItemRoute, passHref: true, children: /* @__PURE__ */ jsx(
5762
+ Menu.Item,
5763
+ {
5764
+ icon: /* @__PURE__ */ jsx(IconEdit, { size: 14 }),
5765
+ ...editorMenuItemConfig,
5766
+ children: translations["Go to editor"] || "Go to editor"
5767
+ }
5768
+ ) });
5707
5769
  return /* @__PURE__ */ jsxs(Menu, { ...menuConfig, children: [
5708
- /* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(Button, { ...buttonConfig, children: `Hi, ${user.name || user.email}!` }) }),
5770
+ /* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(Button, { ...buttonConfig, children: `${translations["Welcome message"] || `Hi, ${user.name || user.email}`}` }) }),
5709
5771
  /* @__PURE__ */ jsxs(Menu.Dropdown, { children: [
5710
- options,
5711
- options && /* @__PURE__ */ jsx(Menu.Divider, {}),
5712
- /* @__PURE__ */ jsx(Menu.Label, { children: "Session" }),
5713
- /* @__PURE__ */ jsxs(
5772
+ optionsPosition === "top" && /* @__PURE__ */ jsxs(Fragment, { children: [
5773
+ withEditorMenuItem && isCMSUser && cmsButton,
5774
+ options,
5775
+ (options || withEditorMenuItem && isCMSUser) && /* @__PURE__ */ jsx(Menu.Divider, {})
5776
+ ] }),
5777
+ withSession && /* @__PURE__ */ jsxs(
5714
5778
  Menu.Item,
5715
5779
  {
5716
5780
  component: "span",
@@ -5723,14 +5787,19 @@ function BespokeLoginBtn({
5723
5787
  }
5724
5788
  ),
5725
5789
  /* @__PURE__ */ jsx(
5726
- Menu.Item,
5790
+ Button,
5727
5791
  {
5728
5792
  component: "a",
5729
5793
  href: "/api/auth/logout",
5730
- icon: /* @__PURE__ */ jsx(IconLogout, { size: 14 }),
5731
- children: "Disconnect"
5794
+ ...logoutButtonConfig,
5795
+ children: translations["Disconnect"] || "Disconnect"
5732
5796
  }
5733
- )
5797
+ ),
5798
+ optionsPosition === "bottom" && /* @__PURE__ */ jsxs(Fragment, { children: [
5799
+ (options || withEditorMenuItem && isCMSUser) && /* @__PURE__ */ jsx(Menu.Divider, {}),
5800
+ withEditorMenuItem && isCMSUser && cmsButton,
5801
+ options
5802
+ ] })
5734
5803
  ] })
5735
5804
  ] });
5736
5805
  }
@@ -5741,7 +5810,7 @@ function BespokeLoginBtn({
5741
5810
  href: "/api/auth/login",
5742
5811
  loading: isLoading,
5743
5812
  ...buttonConfig,
5744
- children: isLoading ? "Signing in..." : "Sign in"
5813
+ children: isLoading ? translations["Signing in"] || "Signing in..." : translations["Sign in"] || "Sign in"
5745
5814
  }
5746
5815
  );
5747
5816
  }
@@ -5881,14 +5950,6 @@ function normalizeList(value) {
5881
5950
  return value.toString().split(",");
5882
5951
  }
5883
5952
 
5884
- // types/auth.ts
5885
- init_esm_shims();
5886
- var CMS_ROLES = {
5887
- ADMIN: "Admin",
5888
- EDITOR: "Editor",
5889
- WRITER: "Writer"
5890
- };
5891
-
5892
5953
  // api/endpoints/member.ts
5893
5954
  var { localeDefault: localeDefault8 } = getLocales_default();
5894
5955
  function parseReadMemberParams(query) {
@@ -7073,21 +7134,15 @@ function CMSHeader(props) {
7073
7134
  const { report: currentReport, profilePrefix } = props;
7074
7135
  const { id } = currentReport;
7075
7136
  const { newConfirmation } = useDialog();
7076
- const location = useManagerLocation();
7077
7137
  const dispatch = useAppDispatch();
7078
7138
  const resource = useContext(ResourceContext);
7079
7139
  const currentLocale = useAppSelector((state) => state.status.currentLocale);
7080
7140
  const localeDefault9 = useAppSelector((state) => state.status.localeDefault);
7081
7141
  const localeOptions = useAppSelector(selectLocaleOptions);
7082
- const reportList = useReportList();
7142
+ const previewsFromState = useAppSelector((state) => state.status.previews);
7083
7143
  const [opened, handlers] = useDisclosure(false);
7084
7144
  const { user } = useUser();
7085
7145
  const castedUser = user;
7086
- const reportOptions = useMemo(() => {
7087
- if (!reportList.isSuccess)
7088
- return [];
7089
- return reportList.data.map((d) => ({ value: `${d.id}`, label: d.name }));
7090
- }, [reportList.status]);
7091
7146
  const dimensions = useMemo(() => {
7092
7147
  return currentReport && currentReport.dimensions ? currentReport.dimensions : [];
7093
7148
  }, [currentReport]);
@@ -7096,9 +7151,14 @@ function CMSHeader(props) {
7096
7151
  }, [dimensions]);
7097
7152
  const [previewMembers, setPreviewMembers] = useState([]);
7098
7153
  const [initialFavorites, setInitialFavorites] = useState([]);
7099
- const onChangeReport = useCallback((value) => {
7100
- location.push(`/reports/${value}`);
7101
- }, [location]);
7154
+ const previewPath = previewsFromState.reduce((acc, member) => {
7155
+ return acc.concat([member.variant_slug, member.slug]);
7156
+ }, []);
7157
+ const previewName = previewsFromState.reduce((acc, member) => {
7158
+ return acc.concat([member.name]);
7159
+ }, []).join(" / ");
7160
+ const localePrefix = currentLocale === localeDefault9 ? "" : `/${currentLocale}`;
7161
+ const realPath = `${localePrefix}${profilePrefix}/${previewPath.join("/")}`;
7102
7162
  const onSelectPreview = (previewMember) => {
7103
7163
  const newPreviews = currentReport.dimensions.map((dId) => {
7104
7164
  let member;
@@ -7116,18 +7176,48 @@ function CMSHeader(props) {
7116
7176
  });
7117
7177
  setPreviewMembers(newPreviews);
7118
7178
  };
7119
- const maybeRevalidate = useCallback(async () => {
7179
+ const maybeRevalidateUrl = useCallback(async () => {
7180
+ try {
7181
+ await newConfirmation({
7182
+ title: "Are you sure?",
7183
+ message: `Revalidate action will force to regenerate page: ${realPath}.`,
7184
+ confirmText: "Revalidate now!"
7185
+ });
7186
+ await dispatch(actions_exports.revalidateUrl({ target: realPath })).then((response) => {
7187
+ const message = `Revalidated page ${response.target} you will see the changes in the following minutes.`;
7188
+ notifications.show({
7189
+ autoClose: false,
7190
+ color: "green",
7191
+ id: "revalidate-results",
7192
+ message,
7193
+ title: "Revalidate Results"
7194
+ });
7195
+ }).catch((error) => {
7196
+ notifications.show({
7197
+ autoClose: false,
7198
+ color: "red",
7199
+ id: "revalidate-error",
7200
+ message: error.message,
7201
+ title: "Revalidate Error"
7202
+ });
7203
+ });
7204
+ } catch {
7205
+ console.debug("Revalidate error.");
7206
+ }
7207
+ }, [realPath]);
7208
+ const maybeRevalidateReport = useCallback(async () => {
7120
7209
  try {
7121
7210
  await newConfirmation({
7122
7211
  title: "Are you sure?",
7123
- message: "Revalidate action will force to regenerate all the cached instances of this report type.",
7212
+ message: `Revalidate action will force to regenerate all the cached instances of '${currentReport.name}' report type.`,
7124
7213
  confirmText: "Revalidate now!"
7125
7214
  });
7126
- const revalidateUrl = `/api/cms/revalidate/report?profilePrefix=${profilePrefix}&reportId=${id}`;
7127
- await axios.get(revalidateUrl).then((response) => {
7128
- const resp = response.data.data.data;
7129
- const message = `Revalidated ${resp.revalidated} pages of report ID ${resp.reportId}, like ${resp.samples.join(", ")}.`;
7130
- showNotification({
7215
+ await dispatch(actions_exports.revalidateReport({
7216
+ profilePrefix,
7217
+ reportId: id
7218
+ })).then((response) => {
7219
+ const message = `Revalidated ${response.revalidated} pages of report ${currentReport.name}(ID ${response.reportId}), you will see the changes in the following minutes. Examples: ${response.samples.join(", ")}.`;
7220
+ notifications.show({
7131
7221
  autoClose: false,
7132
7222
  color: "green",
7133
7223
  id: "revalidate-results",
@@ -7135,7 +7225,7 @@ function CMSHeader(props) {
7135
7225
  title: "Revalidate Results"
7136
7226
  });
7137
7227
  }).catch((error) => {
7138
- showNotification({
7228
+ notifications.show({
7139
7229
  autoClose: false,
7140
7230
  color: "red",
7141
7231
  id: "revalidate-error",
@@ -7146,10 +7236,15 @@ function CMSHeader(props) {
7146
7236
  } catch {
7147
7237
  console.debug("Revalidate edition.");
7148
7238
  }
7149
- }, []);
7239
+ }, [id]);
7150
7240
  useEffect(() => {
7151
7241
  setPreviewMembers([]);
7152
7242
  }, [dimensions]);
7243
+ useEffect(() => {
7244
+ if (previewsFromState && previewsFromState.length > 0) {
7245
+ setInitialFavorites(previewsFromState.map((ps) => ({ variantId: ps.variant_id, contentId: ps.content_id })));
7246
+ }
7247
+ }, [previewsFromState]);
7153
7248
  useEffect(() => {
7154
7249
  if (previewMembers.length > 0) {
7155
7250
  dispatch(actions_exports.recalculateVariables(resource, {
@@ -7181,17 +7276,8 @@ function CMSHeader(props) {
7181
7276
  onChange: (value) => dispatch(statusActions.setStatus({ currentLocale: value || localeDefault9 }))
7182
7277
  }
7183
7278
  ),
7184
- /* @__PURE__ */ jsx(
7185
- Select,
7186
- {
7187
- style: { width: 100 },
7188
- size: "xs",
7189
- data: reportOptions,
7190
- value: String(id),
7191
- onChange: onChangeReport
7192
- }
7193
- ),
7194
- showPreviewSelector && dimensions.map((dId, ix) => /* @__PURE__ */ jsx(
7279
+ /* @__PURE__ */ jsx(Divider, { orientation: "vertical" }),
7280
+ showPreviewSelector && dimensions.map((dId, ix) => /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
7195
7281
  DimensionAutocomplete,
7196
7282
  {
7197
7283
  id: dId,
@@ -7200,34 +7286,53 @@ function CMSHeader(props) {
7200
7286
  locale: currentLocale
7201
7287
  },
7202
7288
  dId
7203
- )),
7204
- !showPreviewSelector && /* @__PURE__ */ jsx(
7205
- Button,
7206
- {
7207
- size: "xs",
7208
- variant: "outline",
7209
- onClick: handlers.open,
7210
- children: "Import Data"
7211
- }
7212
- )
7213
- ] }),
7214
- right: /* @__PURE__ */ jsxs(Group, { children: [
7215
- /* @__PURE__ */ jsx(ActionIcon, { onClick: maybeRevalidate, color: "blue", variant: "filled", children: /* @__PURE__ */ jsx(IconRefreshAlert, { size: 20 }) }),
7216
- /* @__PURE__ */ jsxs(ActionIcon, { color: "blue", variant: "filled", children: [
7217
- /* @__PURE__ */ jsx(IconSettings, { onClick: handlers.open, size: 20 }),
7289
+ ) })),
7290
+ previewsFromState.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
7291
+ /* @__PURE__ */ jsx(Divider, { orientation: "vertical" }),
7292
+ /* @__PURE__ */ jsx(ActionIcon, { component: "a", href: realPath, target: "_blank", variant: "subtle", title: "Open report in new tab", children: /* @__PURE__ */ jsx(IconExternalLink, { size: 20 }) })
7293
+ ] }),
7294
+ !showPreviewSelector && /* @__PURE__ */ jsxs(Fragment, { children: [
7295
+ /* @__PURE__ */ jsx(Divider, { orientation: "vertical" }),
7218
7296
  /* @__PURE__ */ jsx(
7219
- Drawer,
7297
+ Button,
7220
7298
  {
7221
- opened,
7222
- onClose: handlers.close,
7223
- title: /* @__PURE__ */ jsx(IconTitle, { icon: /* @__PURE__ */ jsx(IconFileAnalytics, { size: 24 }), children: `Editing Report: ${currentReport ? currentReport.name : ""}` }),
7224
- size: "50%",
7225
- padding: "xl",
7226
- position: "right",
7227
- children: /* @__PURE__ */ jsx(ReportEditor, { id, onClose: handlers.close })
7299
+ size: "xs",
7300
+ variant: "outline",
7301
+ onClick: handlers.open,
7302
+ children: "Import Data"
7228
7303
  }
7229
7304
  )
7230
7305
  ] })
7306
+ ] }),
7307
+ right: /* @__PURE__ */ jsxs(Group, { spacing: "xs", children: [
7308
+ /* @__PURE__ */ jsxs(Menu, { shadow: "md", children: [
7309
+ /* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(ActionIcon, { color: "blue", variant: "filled", children: /* @__PURE__ */ jsx(IconSettings, { size: 20 }) }) }),
7310
+ /* @__PURE__ */ jsxs(Menu.Dropdown, { children: [
7311
+ /* @__PURE__ */ jsx(Menu.Label, { children: "Revalidate" }),
7312
+ /* @__PURE__ */ jsx(Menu.Item, { onClick: maybeRevalidateUrl, icon: /* @__PURE__ */ jsx(IconFileOff, { size: 20 }), children: /* @__PURE__ */ jsxs(Text, { children: [
7313
+ "Revalidate ",
7314
+ /* @__PURE__ */ jsx(Text, { fw: 700, children: previewName })
7315
+ ] }) }),
7316
+ /* @__PURE__ */ jsx(Menu.Item, { onClick: maybeRevalidateReport, icon: /* @__PURE__ */ jsx(IconFilesOff, { size: 20 }), children: /* @__PURE__ */ jsxs(Text, { children: [
7317
+ "Revalidate ALL ",
7318
+ /* @__PURE__ */ jsx(Text, { fw: 700, children: currentReport.name })
7319
+ ] }) }),
7320
+ /* @__PURE__ */ jsx(Menu.Label, { children: "Settings" }),
7321
+ /* @__PURE__ */ jsx(Menu.Item, { onClick: handlers.open, icon: /* @__PURE__ */ jsx(IconSettings, { size: 20 }), children: "Report settings" })
7322
+ ] })
7323
+ ] }),
7324
+ /* @__PURE__ */ jsx(
7325
+ Drawer,
7326
+ {
7327
+ opened,
7328
+ onClose: handlers.close,
7329
+ title: /* @__PURE__ */ jsx(IconTitle, { icon: /* @__PURE__ */ jsx(IconFileAnalytics, { size: 24 }), children: `Editing Report: ${currentReport ? currentReport.name : ""}` }),
7330
+ size: "50%",
7331
+ padding: "xl",
7332
+ position: "right",
7333
+ children: /* @__PURE__ */ jsx(ReportEditor, { id, onClose: handlers.close })
7334
+ }
7335
+ )
7231
7336
  ] })
7232
7337
  }
7233
7338
  );
@@ -7549,13 +7654,13 @@ function MonacoWrapper({ monacoOptions, variables = {} }) {
7549
7654
  }
7550
7655
  }, [monaco]);
7551
7656
  return /* @__PURE__ */ jsx(
7552
- "div",
7657
+ Box,
7553
7658
  {
7554
7659
  className: "cr-monaco-container",
7660
+ w: "100%",
7555
7661
  children: /* @__PURE__ */ jsx(
7556
7662
  Editor,
7557
7663
  {
7558
- height: "50vh",
7559
7664
  defaultLanguage: "javascript",
7560
7665
  theme: "Monokai",
7561
7666
  ...monacoOptions
@@ -7584,6 +7689,7 @@ var emptyStatus = {
7584
7689
  };
7585
7690
  function BlockPreview(props) {
7586
7691
  const {
7692
+ id,
7587
7693
  active,
7588
7694
  allowed,
7589
7695
  blockStateContent,
@@ -7670,10 +7776,10 @@ function BlockPreview(props) {
7670
7776
  {
7671
7777
  id: `${block.type}-${block.id}`,
7672
7778
  className: "cms-block-preview",
7673
- style: { width: "100%", minHeight: block.type === BLOCK_TYPES.VIZ && 300 },
7779
+ style: { width: "100%", minHeight: block.type === BLOCK_TYPES.VIZ ? 300 : "auto" },
7674
7780
  children: [
7675
7781
  !allowed && allowedOverlay,
7676
- Renderer ? /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx(Renderer, { debug, ...content }) }, "renderer") : /* @__PURE__ */ jsx(Center, { style: { minHeight: 100 }, children: /* @__PURE__ */ jsx(Badge, { color: "gray", variant: "outline", children: block.type }, "type") }),
7782
+ Renderer ? /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx(Renderer, { id: block.id, debug, ...content }) }, "renderer") : /* @__PURE__ */ jsx(Center, { style: { minHeight: 100 }, children: /* @__PURE__ */ jsx(Badge, { color: "gray", variant: "outline", children: block.type }, "type") }),
7677
7783
  debug && textLog && /* @__PURE__ */ jsx(
7678
7784
  Textarea,
7679
7785
  {
@@ -8130,7 +8236,7 @@ function VariableList({ id, setInlineId }) {
8130
8236
  disabled: !isGenerator,
8131
8237
  label: "Edit this Generator",
8132
8238
  style: { position: "absolute", right: 0, top: 0 },
8133
- transition: "pop",
8239
+ transitionProps: { transition: "pop" },
8134
8240
  withArrow: true,
8135
8241
  children: /* @__PURE__ */ jsx(ActionIcon, { size: "xs", onClick: () => setInlineId(vid), variant: "filled", children: /* @__PURE__ */ jsx(IconSettings, {}) })
8136
8242
  }
@@ -8160,6 +8266,7 @@ function BlockEditor({
8160
8266
  const status = useBlockStatus(id);
8161
8267
  const resp = status?.resp;
8162
8268
  const variables = useInputVariablesFlat(id);
8269
+ const { ref, toggle, fullscreen } = useFullscreen();
8163
8270
  const onChangeCode = (logic, locale2) => setBlockContent({ logic }, locale2);
8164
8271
  const onChangeAPI = (api) => setBlockContent({ api });
8165
8272
  const blockPreview = /* @__PURE__ */ jsx(
@@ -8179,7 +8286,9 @@ function BlockEditor({
8179
8286
  {
8180
8287
  monacoOptions: {
8181
8288
  onChange: (logic) => onChangeCode(logic, locale),
8182
- value: blockContent?.logic || ""
8289
+ value: blockContent?.logic || "",
8290
+ height: fullscreen ? "90vh" : "58vh",
8291
+ width: "100%"
8183
8292
  },
8184
8293
  variables
8185
8294
  },
@@ -8229,7 +8338,7 @@ function BlockEditor({
8229
8338
  maxHeight: 200,
8230
8339
  overflowY: "scroll"
8231
8340
  },
8232
- children: /* @__PURE__ */ jsx(InputMenuItem_default, { variables: resp })
8341
+ children: /* @__PURE__ */ jsx(InputMenuItem_default, { id, variables: resp })
8233
8342
  }
8234
8343
  )
8235
8344
  ] })
@@ -8257,35 +8366,52 @@ function BlockEditor({
8257
8366
  {
8258
8367
  value: tab,
8259
8368
  onTabChange: setTab,
8260
- styles: {
8261
- root: {
8262
- display: "flex",
8263
- flex: 1,
8264
- flexDirection: "column",
8265
- width: "100%",
8266
- body: {
8267
- display: "flex",
8268
- flex: "1 1 100%"
8269
- }
8270
- }
8271
- },
8272
- variant: "pills",
8273
8369
  children: [
8274
- /* @__PURE__ */ jsxs(Tabs.List, { position: "center", children: [
8275
- /* @__PURE__ */ jsx(Tabs.Tab, { value: "Content", icon: /* @__PURE__ */ jsx(IconEye, {}) }),
8276
- /* @__PURE__ */ jsx(Tabs.Tab, { value: "Settings", icon: /* @__PURE__ */ jsx(IconSettings, {}) })
8370
+ /* @__PURE__ */ jsxs(Tabs.List, { position: "left", children: [
8371
+ /* @__PURE__ */ jsx(Tabs.Tab, { value: "Content", icon: /* @__PURE__ */ jsx(IconEye, {}), children: "Edit" }),
8372
+ /* @__PURE__ */ jsx(Tabs.Tab, { value: "Settings", icon: /* @__PURE__ */ jsx(IconSettings, {}), children: "Settings" })
8277
8373
  ] }),
8278
- /* @__PURE__ */ jsx(Tabs.Panel, { value: "Content", children: /* @__PURE__ */ jsxs(Grid, { className: "cr-block-output", style: { flex: 1, width: "100%" }, children: [
8279
- /* @__PURE__ */ jsxs(Col, { span: 9, className: `cr-block-output-editor ${currentMode}`, children: [
8280
- currentMode === "code" && /* @__PURE__ */ jsxs(Fragment, { children: [
8281
- codeEditor,
8282
- executeButton
8283
- ] }),
8284
- currentMode !== "code" && uiEditor
8285
- ] }, "content-col"),
8286
- /* @__PURE__ */ jsx(Col, { span: 3, style: { display: "flex", flexDirection: "column" }, children: blockPreview })
8287
- ] }) }),
8288
- /* @__PURE__ */ jsx(Tabs.Panel, { value: "Settings", children: /* @__PURE__ */ jsx(
8374
+ /* @__PURE__ */ jsx(Tabs.Panel, { value: "Content", pt: "xs", children: /* @__PURE__ */ jsx(Box, { ref, pos: "relative", bg: "white", children: /* @__PURE__ */ jsxs(
8375
+ Grid,
8376
+ {
8377
+ className: "cr-block-output",
8378
+ style: { flex: 1, width: "100%", height: fullscreen ? "100vh" : "auto", margin: 0 },
8379
+ children: [
8380
+ /* @__PURE__ */ jsxs(Col, { span: 9, bg: "#272822", className: `cr-block-output-editor ${currentMode}`, children: [
8381
+ currentMode === "code" && /* @__PURE__ */ jsxs(Fragment, { children: [
8382
+ /* @__PURE__ */ jsxs(Alert, { p: "xs", mb: "xs", icon: /* @__PURE__ */ jsx(IconInfoCircle, {}), color: "gray", children: [
8383
+ "You can access ",
8384
+ /* @__PURE__ */ jsx(Code, { children: "variables" }),
8385
+ ",",
8386
+ /* @__PURE__ */ jsx(Code, { children: "resp" }),
8387
+ ", and ",
8388
+ /* @__PURE__ */ jsx(Code, { children: "router" }),
8389
+ " in the scope of this generator."
8390
+ ] }),
8391
+ codeEditor,
8392
+ /* @__PURE__ */ jsx(Divider, { my: "sm", color: "gray.8" }),
8393
+ /* @__PURE__ */ jsxs(Group, { px: "xs", h: "fit-content", position: "right", children: [
8394
+ /* @__PURE__ */ jsx(
8395
+ Button,
8396
+ {
8397
+ variant: "light",
8398
+ color: "grey",
8399
+ onClick: toggle,
8400
+ leftIcon: fullscreen ? /* @__PURE__ */ jsx(IconMinimize, { size: rem(12) }) : /* @__PURE__ */ jsx(IconMaximize, { size: rem(12) }),
8401
+ compact: true,
8402
+ children: fullscreen ? "Minimize" : "Maximize"
8403
+ }
8404
+ ),
8405
+ executeButton
8406
+ ] })
8407
+ ] }),
8408
+ currentMode !== "code" && uiEditor
8409
+ ] }, "content-col"),
8410
+ /* @__PURE__ */ jsx(Col, { span: 3, style: { display: "flex", flexDirection: "column" }, children: blockPreview })
8411
+ ]
8412
+ }
8413
+ ) }) }),
8414
+ /* @__PURE__ */ jsx(Tabs.Panel, { value: "Settings", pt: "xs", children: /* @__PURE__ */ jsx(
8289
8415
  BlockSettings_default,
8290
8416
  {
8291
8417
  id,
@@ -8314,7 +8440,7 @@ function ConsumerMenu({ id }) {
8314
8440
  Menu,
8315
8441
  {
8316
8442
  position: "top",
8317
- transition: "pop",
8443
+ transitionProps: { transition: "pop" },
8318
8444
  trigger: "hover",
8319
8445
  zIndex: 1001,
8320
8446
  children: [
@@ -8447,9 +8573,10 @@ function Block2({
8447
8573
  const executeButton = /* @__PURE__ */ jsx(
8448
8574
  Button,
8449
8575
  {
8450
- style: { minHeight: 40 },
8451
8576
  disabled: !isValid,
8452
8577
  onClick: () => onSave(true),
8578
+ size: "sm",
8579
+ compact: true,
8453
8580
  children: "Save & Execute"
8454
8581
  }
8455
8582
  );
@@ -8590,7 +8717,7 @@ function BlockElement({
8590
8717
  onClose: maybeCloseWithoutSaving,
8591
8718
  overflow: "inside",
8592
8719
  padding: theme.spacing.sm,
8593
- size: "90%"
8720
+ size: "95%"
8594
8721
  };
8595
8722
  const hoverActions = {
8596
8723
  onMouseEnter: () => setHoverBlock(id),
@@ -8633,8 +8760,8 @@ function BlockElement({
8633
8760
  className: "cr-block-controls export-hidden",
8634
8761
  style: {
8635
8762
  position: "absolute",
8636
- right: theme.spacing.xs / 2,
8637
- top: theme.spacing.xs / 2,
8763
+ right: px(theme.spacing.xs) / 2,
8764
+ top: px(theme.spacing.xs) / 2,
8638
8765
  backgroundColor: theme.colors.gray[2],
8639
8766
  borderRadius: theme.radius.sm
8640
8767
  },
@@ -9130,6 +9257,7 @@ function InteractiveReport(props) {
9130
9257
  }
9131
9258
  }, [report.dimensions, previews]);
9132
9259
  const onDragEnd = useCallback((result) => {
9260
+ console.log("----onDragEnd", result);
9133
9261
  if (!result.destination || result.source.index === result.destination.index)
9134
9262
  return;
9135
9263
  const id = Number.parseInt(result.draggableId, 10);
@@ -11434,7 +11562,7 @@ function BespokeManager(options) {
11434
11562
  locale = localeDefault4,
11435
11563
  profilePrefix
11436
11564
  } = options;
11437
- const notifications = {
11565
+ const notifications3 = {
11438
11566
  position: "bottom-center",
11439
11567
  ...options.notifications
11440
11568
  };
@@ -11446,7 +11574,10 @@ function BespokeManager(options) {
11446
11574
  function BespokeManagerPage() {
11447
11575
  return /* @__PURE__ */ jsxs(ResourceProvider, { pathSegment, children: [
11448
11576
  /* @__PURE__ */ jsx(Head, { children: /* @__PURE__ */ jsx("title", { children: title }) }),
11449
- /* @__PURE__ */ jsx(MantineProvider, { inherit: false, children: /* @__PURE__ */ jsx(NotificationsProvider, { ...notifications, children: /* @__PURE__ */ jsx(DialogProvider, { children: /* @__PURE__ */ jsx(BespokeManagerShell, { locale, profilePrefix }) }) }) })
11577
+ /* @__PURE__ */ jsxs(MantineProvider, { inherit: false, children: [
11578
+ /* @__PURE__ */ jsx(Notifications, { ...notifications3 }),
11579
+ /* @__PURE__ */ jsx(DialogProvider, { children: /* @__PURE__ */ jsx(BespokeManagerShell, { locale, profilePrefix }) })
11580
+ ] })
11450
11581
  ] });
11451
11582
  }
11452
11583
  }
package/dist/server.js CHANGED
@@ -22,12 +22,11 @@ import fs from 'fs';
22
22
  import auth0 from 'auth0';
23
23
  import NextCors from 'nextjs-cors';
24
24
  import formidable from 'formidable';
25
- import glob from 'fast-glob';
26
25
  import toposort from 'toposort';
27
26
  import { schema, normalize } from 'normalizr';
28
27
  import { createSlice, configureStore } from '@reduxjs/toolkit';
29
28
  import { HYDRATE, createWrapper } from 'next-redux-wrapper';
30
- import { showNotification } from '@mantine/notifications';
29
+ import { notifications } from '@mantine/notifications';
31
30
  import { createContext } from 'react';
32
31
  import 'react-redux';
33
32
  import 'react/jsx-runtime';
@@ -3488,19 +3487,45 @@ function dbUrlProxyFactory() {
3488
3487
  };
3489
3488
  }
3490
3489
 
3491
- // api/db/revalidate.ts
3492
- function dbRevalidateFactory(db) {
3490
+ // api/db/revalidateReport.ts
3491
+ function dbRevalidateReportFactory(db) {
3493
3492
  return async (request) => {
3494
- const { reportId, qty, samples } = request;
3495
3493
  try {
3496
- return {
3497
- ok: true,
3498
- status: 200,
3499
- data: {
3500
- reportId,
3501
- revalidated: qty,
3502
- samples
3494
+ const { variantPaths } = request;
3495
+ const paths = [];
3496
+ if (variantPaths) {
3497
+ for (let index = 0; index < variantPaths.length; index++) {
3498
+ const variant = variantPaths[index];
3499
+ const members = await db.search.findAll({
3500
+ attributes: ["slug"],
3501
+ where: {
3502
+ variant_id: variant.variantId
3503
+ }
3504
+ });
3505
+ members.forEach((m) => {
3506
+ paths.push(`/${variant.prefix}/${variant.variantSlug}/${m.slug}`);
3507
+ });
3503
3508
  }
3509
+ }
3510
+ return {
3511
+ ...request,
3512
+ paths,
3513
+ revalidated: 0,
3514
+ samples: []
3515
+ };
3516
+ } catch (err) {
3517
+ throw new BackendError(err.response?.status || 500, err.message);
3518
+ }
3519
+ };
3520
+ }
3521
+
3522
+ // api/db/revalidateUrl.ts
3523
+ function dbRevalidateUrlFactory() {
3524
+ return async (request) => {
3525
+ try {
3526
+ const { target } = request;
3527
+ return {
3528
+ target
3504
3529
  };
3505
3530
  } catch (err) {
3506
3531
  throw new BackendError(err.response?.status || 500, err.message);
@@ -3737,7 +3762,8 @@ function apiFactory(dbModels) {
3737
3762
  readUser: resultWrapper(dbReadUser()),
3738
3763
  updateUser: resultWrapper(dbUpdateUser()),
3739
3764
  addNewReportToCurrentUser: resultWrapper(dbAddNewReportToCurrentUser()),
3740
- revalidate: resultWrapper(dbRevalidateFactory()),
3765
+ revalidateReport: resultWrapper(dbRevalidateReportFactory(dbModels)),
3766
+ revalidateUrl: resultWrapper(dbRevalidateUrlFactory()),
3741
3767
  readPrivateBlocks: resultWrapper(dbReadPrivateBlocksFactory(dbModels))
3742
3768
  };
3743
3769
  }
@@ -3869,8 +3895,10 @@ function endpointUrlProxyFactory(operations) {
3869
3895
  });
3870
3896
  });
3871
3897
  }
3872
- function endpointRevalidateFactory(operations) {
3873
- const { readMetadata: readMetadata2, revalidate } = operations;
3898
+
3899
+ // api/endpoints/revalidateReport.ts
3900
+ function endpointRevalidateReportFactory(operations) {
3901
+ const { readMetadata: readMetadata2, revalidateReport: revalidateReport2 } = operations;
3874
3902
  return endpoint("GET", "revalidate/report", async (req, res) => {
3875
3903
  const { reportId, profilePrefix } = req.query;
3876
3904
  if (!reportId || !profilePrefix) {
@@ -3879,32 +3907,50 @@ function endpointRevalidateFactory(operations) {
3879
3907
  try {
3880
3908
  const reportIdInt = parseInt(`${reportId}`, 10);
3881
3909
  const profilePrefixClean = `${profilePrefix}`.split("/").filter((p) => p !== "").join("/");
3882
- const initialPathSelector = [
3883
- ".next",
3884
- "server",
3885
- "pages"
3886
- ];
3887
- const pathSelector = [
3888
- ...initialPathSelector,
3889
- profilePrefixClean
3890
- ];
3891
- const paths = [];
3910
+ const variantPaths = [];
3892
3911
  const report = await readMetadata2({}).then((metadata) => metadata.ok ? metadata.data.data.find((r) => r.id === reportIdInt) : []);
3893
3912
  if (report && report.mode === REPORT_MODES.UNILATERAL) {
3894
3913
  report.dimensions.forEach((d) => {
3895
3914
  d.variants.forEach((v) => {
3896
- paths.push([
3897
- ...pathSelector,
3898
- v.slug,
3899
- "*.html"
3900
- ].join("/"));
3915
+ variantPaths.push({
3916
+ prefix: profilePrefixClean,
3917
+ variantId: v.id,
3918
+ variantSlug: v.slug
3919
+ });
3901
3920
  });
3902
3921
  });
3903
3922
  }
3904
- const files = await glob(paths);
3905
- const urls = files.map((file) => `${file.replace(initialPathSelector.join("/"), "").replace(".html", "")}`);
3906
- await Promise.all(urls.map((path) => res.revalidate(path)));
3907
- return revalidate({ reportId: reportIdInt, qty: urls.length, samples: urls.slice(0, 5) });
3923
+ const urlsToRevalidate = await revalidateReport2(
3924
+ {
3925
+ profilePrefix: profilePrefixClean,
3926
+ reportId: reportIdInt,
3927
+ variantPaths
3928
+ }
3929
+ );
3930
+ let samples = [];
3931
+ let qty = 0;
3932
+ if (urlsToRevalidate.ok) {
3933
+ qty = urlsToRevalidate.data.paths.length;
3934
+ samples = urlsToRevalidate.data.paths.slice(0, 5);
3935
+ Promise.all(urlsToRevalidate.data.paths.map((path) => {
3936
+ let rev;
3937
+ try {
3938
+ rev = res.revalidate(path, { unstable_onlyGenerated: true });
3939
+ } catch (error) {
3940
+ console.log("error", path, error);
3941
+ }
3942
+ return rev;
3943
+ }));
3944
+ }
3945
+ return {
3946
+ ok: true,
3947
+ status: 200,
3948
+ data: {
3949
+ reportId,
3950
+ revalidated: qty,
3951
+ samples
3952
+ }
3953
+ };
3908
3954
  } catch (err) {
3909
3955
  console.log(err);
3910
3956
  throw new BackendError(500, "Error revalidating");
@@ -3912,6 +3958,30 @@ function endpointRevalidateFactory(operations) {
3912
3958
  }, [CMS_ROLES.EDITOR]);
3913
3959
  }
3914
3960
 
3961
+ // api/endpoints/revalidateUrl.ts
3962
+ function endpointRevalidateUrlFactory() {
3963
+ return endpoint("GET", "revalidate/url", async (req, res) => {
3964
+ const { target } = req.query;
3965
+ if (!target) {
3966
+ throw new BackendError(400, "Missing target parameter in revalidate factory");
3967
+ } else {
3968
+ try {
3969
+ res.revalidate(target, { unstable_onlyGenerated: true });
3970
+ return {
3971
+ ok: true,
3972
+ status: 200,
3973
+ data: {
3974
+ target
3975
+ }
3976
+ };
3977
+ } catch (err) {
3978
+ console.log(err);
3979
+ throw new BackendError(500, "Error revalidating");
3980
+ }
3981
+ }
3982
+ }, [CMS_ROLES.ADMIN, CMS_ROLES.EDITOR, CMS_ROLES.WRITER]);
3983
+ }
3984
+
3915
3985
  // api/endpoints/readPrivateBlocks.ts
3916
3986
  var { localeDefault: localeDefault5 } = getLocales_default();
3917
3987
  function endpointReadPrivateBlocksFactory(operations) {
@@ -4049,7 +4119,8 @@ function getEndpointMap(db) {
4049
4119
  endpointGetUserDataFactory(api),
4050
4120
  endpointUpdateUserDataFactory(api),
4051
4121
  endpointAddNewReportToCurrentUserFactory(api),
4052
- endpointRevalidateFactory(api),
4122
+ endpointRevalidateReportFactory(api),
4123
+ endpointRevalidateUrlFactory(),
4053
4124
  endpointReadPrivateBlocksFactory(api)
4054
4125
  ].map(({ handler, method, path, roleRequired }) => [endpointKey(method, path), { handler, roleRequired }]));
4055
4126
  }
@@ -4133,6 +4204,8 @@ __export(actions_exports, {
4133
4204
  recalculateVariables: () => recalculateVariables,
4134
4205
  removeBlocksFromState: () => removeBlocksFromState,
4135
4206
  reportSearch: () => reportSearch,
4207
+ revalidateReport: () => revalidateReport,
4208
+ revalidateUrl: () => revalidateUrl,
4136
4209
  searchMember: () => searchMember,
4137
4210
  searchRegenerate: () => searchRegenerate,
4138
4211
  searchRole: () => searchRole,
@@ -4254,7 +4327,8 @@ function apiFactory2(baseURL) {
4254
4327
  readUser: httpGET(axios6, "auth/read/user"),
4255
4328
  updateUser: httpPOST(axios6, "auth/update/user"),
4256
4329
  addNewReportToCurrentUser: httpPOST(axios6, "auth/update/me"),
4257
- revalidate: httpGET(axios6, "revalidate/report"),
4330
+ revalidateReport: httpGET(axios6, "revalidate/report"),
4331
+ revalidateUrl: httpGET(axios6, "revalidate/url"),
4258
4332
  readPrivateBlocks: httpPOST(axios6, "read/blocks/private")
4259
4333
  };
4260
4334
  }
@@ -4615,9 +4689,9 @@ var getDependencies = (bid, blocks, acc = [], crawlUp = true, crawlDown2 = true)
4615
4689
  if (rootBlock.consumers.length && crawlDown2) {
4616
4690
  rootBlock.consumers.forEach((cid) => {
4617
4691
  const rel = `${bid}-${cid}`;
4618
- if (!acc.includes(rel))
4692
+ if (!acc.includes(rel) && blocks[cid].section_id === blocks[bid].section_id)
4619
4693
  acc.push(rel);
4620
- rootBlock.consumers.forEach((cid2) => getDependencies(cid2, blocks, acc, crawlUp, crawlDown2));
4694
+ rootBlock.consumers.filter((cid2) => blocks[cid2].section_id === blocks[bid].section_id).forEach((cid2) => getDependencies(cid2, blocks, acc, crawlUp, crawlDown2));
4621
4695
  });
4622
4696
  }
4623
4697
  return acc;
@@ -4685,13 +4759,14 @@ function comparePositions(firstPos, secondPos) {
4685
4759
  function orderSort(a, b, accessor = "ordering") {
4686
4760
  return comparePositions(b[accessor], a[accessor]);
4687
4761
  }
4688
- var parse = (config, formatters = {}, locale = "en", actions = {}) => {
4762
+ var parse = (config, formatters = {}, locale = "en", actions = {}, extraGlobals = {}) => {
4689
4763
  const globals = {
4690
4764
  setVariables: actions.onSetVariables ? actions.onSetVariables : (d) => d,
4691
4765
  openModal: actions.onOpenModal ? actions.onOpenModal : (d) => d,
4692
4766
  formatters,
4693
4767
  libs: libraries,
4694
- locale
4768
+ locale,
4769
+ ...extraGlobals
4695
4770
  };
4696
4771
  function parseFunction(obj) {
4697
4772
  return Function("globals", ...obj.vars, `with (globals) { ${obj.logic} }`).bind(globals, globals);
@@ -5192,7 +5267,7 @@ function rpcAnnounce(entity, key) {
5192
5267
  function rpcFailure(entity, key, code, message) {
5193
5268
  return (dispatch) => {
5194
5269
  if (typeof window === "object") {
5195
- showNotification({
5270
+ notifications.show({
5196
5271
  autoClose: 3e3,
5197
5272
  color: "red",
5198
5273
  id: key,
@@ -5401,6 +5476,7 @@ function recalculateVariables(resource, params) {
5401
5476
  locale: currentLocale
5402
5477
  };
5403
5478
  const section = state.records.entities.section[sid];
5479
+ console.log(section?.blocks);
5404
5480
  const data = await runConsumersV2(
5405
5481
  blocks,
5406
5482
  section && [section],
@@ -5496,6 +5572,26 @@ function readPrivateBlocks(params) {
5496
5572
  return result.data;
5497
5573
  };
5498
5574
  }
5575
+ function revalidateUrl(params) {
5576
+ return async (_, __, api) => {
5577
+ const result = await api.revalidateUrl({ target: params.target });
5578
+ if ("error" in result) {
5579
+ throw new Error(result.error);
5580
+ }
5581
+ return result.data;
5582
+ };
5583
+ }
5584
+ function revalidateReport(params) {
5585
+ return async (_, __, api) => {
5586
+ const result = await api.revalidateReport(
5587
+ { reportId: params.reportId, profilePrefix: params.profilePrefix }
5588
+ );
5589
+ if ("error" in result) {
5590
+ throw new Error(result.error);
5591
+ }
5592
+ return result.data;
5593
+ };
5594
+ }
5499
5595
  var storeFactory = (_context) => configureStore({
5500
5596
  reducer: {
5501
5597
  [recordsSlice.name]: recordsSlice.reducer,
@@ -5660,7 +5756,6 @@ function BespokeRendererStaticProps(options) {
5660
5756
  const publicBlockRecords = { ...blockRecords };
5661
5757
  let privateBlockIds = Object.values(blockRecords).reduce((acc, block) => {
5662
5758
  if ("access" in block.settings && !["public", "guest"].some((grant) => !block.settings.access || block.settings.access.includes(grant))) {
5663
- console.log("is Private", block.id);
5664
5759
  acc.push(block.id);
5665
5760
  }
5666
5761
  return acc;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datawheel/bespoke",
3
- "version": "0.1.21",
3
+ "version": "0.1.23",
4
4
  "description": "Content management system for creating automated data reports",
5
5
  "exports": {
6
6
  ".": {
@@ -42,14 +42,14 @@
42
42
  "@auth0/nextjs-auth0": "^2.0.1",
43
43
  "@emotion/react": "^11.10.4",
44
44
  "@hello-pangea/dnd": "^16.2.0",
45
- "@mantine/core": "^5.6.3",
46
- "@mantine/dates": "^5.6.3",
47
- "@mantine/dropzone": "^5.6.3",
48
- "@mantine/form": "^5.6.3",
49
- "@mantine/hooks": "^5.6.3",
50
- "@mantine/next": "^6.0.1",
51
- "@mantine/notifications": "^5.6.3",
52
- "@mantine/prism": "^5.6.3",
45
+ "@mantine/core": "^6.0.6",
46
+ "@mantine/dates": "^6.0.6",
47
+ "@mantine/dropzone": "^6.0.6",
48
+ "@mantine/form": "^6.0.6",
49
+ "@mantine/hooks": "^6.0.6",
50
+ "@mantine/next": "^6.0.6",
51
+ "@mantine/notifications": "^6.0.6",
52
+ "@mantine/prism": "^6.0.6",
53
53
  "@monaco-editor/react": "^4.4.5",
54
54
  "@reduxjs/toolkit": "^1.8.4",
55
55
  "@tabler/icons": "^1.106.0",
@@ -81,7 +81,7 @@
81
81
  "jszip": "^3.10.1",
82
82
  "lunr": "^2.3.9",
83
83
  "lunr-languages": "^1.9.0",
84
- "mantine-datatable": "^1.7.9",
84
+ "mantine-datatable": "^2.3.3",
85
85
  "monaco-themes": "^0.4.2",
86
86
  "next-redux-wrapper": "^7.0.0",
87
87
  "nextjs-cors": "^2.1.1",