@datarecce/ui 0.1.22 → 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 (51) hide show
  1. package/dist/{RecceCheckContext-BETsmiD5.mjs → RecceCheckContext-DIQjrvH8.mjs} +2 -2
  2. package/dist/{RecceCheckContext-BETsmiD5.mjs.map → RecceCheckContext-DIQjrvH8.mjs.map} +1 -1
  3. package/dist/{RecceCheckContext-DNKi97uE.js → RecceCheckContext-_xzNlnbJ.js} +2 -2
  4. package/dist/{RecceCheckContext-DNKi97uE.js.map → RecceCheckContext-_xzNlnbJ.js.map} +1 -1
  5. package/dist/api.d.mts +1 -1
  6. package/dist/api.d.ts +1 -1
  7. package/dist/api.js +11 -37
  8. package/dist/api.mjs +3 -29
  9. package/dist/{components-C735_oqD.mjs → components-CfY72Lq2.mjs} +1259 -11
  10. package/dist/components-CfY72Lq2.mjs.map +1 -0
  11. package/dist/{components-DeA4kqxK.js → components-DXbVq9Cw.js} +1310 -35
  12. package/dist/components-DXbVq9Cw.js.map +1 -0
  13. package/dist/components.d.mts +2 -2
  14. package/dist/components.d.ts +2 -2
  15. package/dist/components.js +8 -4
  16. package/dist/components.mjs +5 -5
  17. package/dist/{hooks-D6xvNXEc.js → hooks-C4jkoryM.js} +3 -3
  18. package/dist/{hooks-D6xvNXEc.js.map → hooks-C4jkoryM.js.map} +1 -1
  19. package/dist/{hooks-Ba-AoxcK.mjs → hooks-C8pyX9m_.mjs} +3 -3
  20. package/dist/{hooks-Ba-AoxcK.mjs.map → hooks-C8pyX9m_.mjs.map} +1 -1
  21. package/dist/hooks.d.mts +1 -1
  22. package/dist/hooks.d.ts +1 -1
  23. package/dist/hooks.js +3 -3
  24. package/dist/hooks.mjs +3 -3
  25. package/dist/{index-DYduBYD8.d.ts → index-CVPmrztP.d.ts} +20 -2
  26. package/dist/index-CVPmrztP.d.ts.map +1 -0
  27. package/dist/{index-Sj_wOmNH.d.mts → index-DIHuswfP.d.mts} +85 -67
  28. package/dist/index-DIHuswfP.d.mts.map +1 -0
  29. package/dist/index.d.mts +2 -2
  30. package/dist/index.d.ts +2 -2
  31. package/dist/index.js +18 -14
  32. package/dist/index.mjs +7 -7
  33. package/dist/{state-BjKRZMwY.js → state-AeoqV9ja.js} +19 -1
  34. package/dist/{state-BjKRZMwY.js.map → state-AeoqV9ja.js.map} +1 -1
  35. package/dist/{state-BySLlIE7.mjs → state-BbgVwFV2.mjs} +8 -2
  36. package/dist/{state-BySLlIE7.mjs.map → state-BbgVwFV2.mjs.map} +1 -1
  37. package/dist/types.d.mts +1 -1
  38. package/dist/types.d.ts +1 -1
  39. package/dist/{user-BHOgMaBf.mjs → version-C2NU3xyx.mjs} +27 -3
  40. package/dist/version-C2NU3xyx.mjs.map +1 -0
  41. package/dist/{user-Dt_n5IJX.js → version-MxW9vrDY.js} +32 -2
  42. package/dist/version-MxW9vrDY.js.map +1 -0
  43. package/package.json +4 -4
  44. package/dist/api.js.map +0 -1
  45. package/dist/api.mjs.map +0 -1
  46. package/dist/components-C735_oqD.mjs.map +0 -1
  47. package/dist/components-DeA4kqxK.js.map +0 -1
  48. package/dist/index-DYduBYD8.d.ts.map +0 -1
  49. package/dist/index-Sj_wOmNH.d.mts.map +0 -1
  50. package/dist/user-BHOgMaBf.mjs.map +0 -1
  51. package/dist/user-Dt_n5IJX.js.map +0 -1
@@ -1,8 +1,8 @@
1
1
  "use client"
2
- const require_state = require('./state-BjKRZMwY.js');
2
+ const require_state = require('./state-AeoqV9ja.js');
3
3
  const require_urls = require('./urls-SazAekCZ.js');
4
- const require_user = require('./user-Dt_n5IJX.js');
5
- const require_RecceCheckContext = require('./RecceCheckContext-DNKi97uE.js');
4
+ const require_version = require('./version-MxW9vrDY.js');
5
+ const require_RecceCheckContext = require('./RecceCheckContext-_xzNlnbJ.js');
6
6
  const require_tooltipMessage = require('./tooltipMessage-Dbi1kkfi.js');
7
7
  let _mui_material_CssBaseline = require("@mui/material/CssBaseline");
8
8
  _mui_material_CssBaseline = require_state.__toESM(_mui_material_CssBaseline);
@@ -50,6 +50,8 @@ _mui_material_DialogTitle = require_state.__toESM(_mui_material_DialogTitle);
50
50
  let _mui_material_IconButton = require("@mui/material/IconButton");
51
51
  _mui_material_IconButton = require_state.__toESM(_mui_material_IconButton);
52
52
  let react_icons_io5 = require("react-icons/io5");
53
+ let next_link = require("next/link");
54
+ next_link = require_state.__toESM(next_link);
53
55
  let _mui_material_Checkbox = require("@mui/material/Checkbox");
54
56
  _mui_material_Checkbox = require_state.__toESM(_mui_material_Checkbox);
55
57
  let _mui_material_FormControlLabel = require("@mui/material/FormControlLabel");
@@ -63,8 +65,10 @@ _mui_material_MenuItem = require_state.__toESM(_mui_material_MenuItem);
63
65
  let react_icons_vsc = require("react-icons/vsc");
64
66
  let _mui_material_Tooltip = require("@mui/material/Tooltip");
65
67
  _mui_material_Tooltip = require_state.__toESM(_mui_material_Tooltip);
68
+ let usehooks_ts = require("usehooks-ts");
66
69
  let _mui_material_ListSubheader = require("@mui/material/ListSubheader");
67
70
  _mui_material_ListSubheader = require_state.__toESM(_mui_material_ListSubheader);
71
+ let next_navigation = require("next/navigation");
68
72
  let _mui_material_Link = require("@mui/material/Link");
69
73
  _mui_material_Link = require_state.__toESM(_mui_material_Link);
70
74
  let _mui_material_Popover = require("@mui/material/Popover");
@@ -149,6 +153,10 @@ let _mui_material_CardHeader = require("@mui/material/CardHeader");
149
153
  _mui_material_CardHeader = require_state.__toESM(_mui_material_CardHeader);
150
154
  let _mui_material_Badge = require("@mui/material/Badge");
151
155
  _mui_material_Badge = require_state.__toESM(_mui_material_Badge);
156
+ let app__mainComponents__DisplayModeToggle = require("app/(mainComponents)/DisplayModeToggle");
157
+ app__mainComponents__DisplayModeToggle = require_state.__toESM(app__mainComponents__DisplayModeToggle);
158
+ let app__mainComponents__RecceVersionBadge = require("app/(mainComponents)/RecceVersionBadge");
159
+ app__mainComponents__RecceVersionBadge = require_state.__toESM(app__mainComponents__RecceVersionBadge);
152
160
 
153
161
  //#region recce-source/js/src/components/ui/mui-provider.tsx
154
162
  /**
@@ -1351,9 +1359,9 @@ var require_embed_resources = /* @__PURE__ */ require_state.__commonJSMin(((expo
1351
1359
  var preferredFontFormat = _a.preferredFontFormat;
1352
1360
  return !preferredFontFormat ? str : str.replace(FONT_SRC_REGEX, function(match) {
1353
1361
  while (true) {
1354
- var _a$1 = URL_WITH_FORMAT_REGEX.exec(match) || [], src = _a$1[0], format$3 = _a$1[2];
1355
- if (!format$3) return "";
1356
- if (format$3 === preferredFontFormat) return "src: ".concat(src, ";");
1362
+ var _a$1 = URL_WITH_FORMAT_REGEX.exec(match) || [], src = _a$1[0], format$4 = _a$1[2];
1363
+ if (!format$4) return "";
1364
+ if (format$4 === preferredFontFormat) return "src: ".concat(src, ";");
1357
1365
  }
1358
1366
  });
1359
1367
  }
@@ -2288,7 +2296,7 @@ const getHTMLElementFromRef = (refCurrent) => {
2288
2296
  };
2289
2297
  const IGNORE_SCREENSHOT_CLASS = "ignore-screenshot";
2290
2298
  const highlightBoxShadow = "rgba(0, 0, 0, 0.25) 0px 54px 55px, rgba(0, 0, 0, 0.12) 0px -12px 30px, rgba(0, 0, 0, 0.12) 0px 4px 6px, rgba(0, 0, 0, 0.17) 0px 12px 13px, rgba(0, 0, 0, 0.09) 0px -3px 5px";
2291
- function useCopyToClipboard({ renderLibrary = "html2canvas", imageType = "png", backgroundColor = null, boardEffect = true, shadowEffect = false, borderStyle = `solid 1px ${require_state.colors.neutral[300]}`, borderRadius = "10px", onSuccess, onError, ignoreElements }) {
2299
+ function useCopyToClipboard$1({ renderLibrary = "html2canvas", imageType = "png", backgroundColor = null, boardEffect = true, shadowEffect = false, borderStyle = `solid 1px ${require_state.colors.neutral[300]}`, borderRadius = "10px", onSuccess, onError, ignoreElements }) {
2292
2300
  const [status, setStatus] = (0, react.useState)("idle");
2293
2301
  const ref = (0, react.useRef)(null);
2294
2302
  const { onOpen, setImgBlob, ImageDownloadModal } = useImageDownloadModal();
@@ -2389,7 +2397,7 @@ function useCopyToClipboard({ renderLibrary = "html2canvas", imageType = "png",
2389
2397
  }
2390
2398
  function useCopyToClipboardButton(options) {
2391
2399
  const { successToast, failToast } = require_state.useClipBoardToast();
2392
- const { isLoading, copyToClipboard, ImageDownloadModal, ref } = useCopyToClipboard({
2400
+ const { isLoading, copyToClipboard, ImageDownloadModal, ref } = useCopyToClipboard$1({
2393
2401
  imageType: "png",
2394
2402
  shadowEffect: true,
2395
2403
  backgroundColor: options?.backgroundColor ?? require_state.colors.neutral[100],
@@ -4452,7 +4460,7 @@ const useLineageViewContextMenu = () => {
4452
4460
  //#endregion
4453
4461
  //#region recce-source/js/src/components/lineage/LineageViewNotification.tsx
4454
4462
  function LineageViewNotification({ notification, type }) {
4455
- const notificationKey = require_user.sessionStorageKeys.lineageNotificationDismissed;
4463
+ const notificationKey = require_version.sessionStorageKeys.lineageNotificationDismissed;
4456
4464
  const [visible, setVisible] = (0, react.useState)(() => {
4457
4465
  return sessionStorage.getItem(notificationKey) !== "true";
4458
4466
  });
@@ -6394,7 +6402,7 @@ function AuthModal({ handleParentClose, parentOpen = false, ignoreCookie = false
6394
6402
  },
6395
6403
  onClick: async () => {
6396
6404
  setAuthState("authenticating");
6397
- const { connection_url } = await require_user.connectToCloud();
6405
+ const { connection_url } = await require_version.connectToCloud();
6398
6406
  window.open(connection_url, "_blank");
6399
6407
  },
6400
6408
  children: [
@@ -7286,7 +7294,7 @@ function SandboxView({ isOpen, onClose, current }) {
7286
7294
  }
7287
7295
  });
7288
7296
  const { feedbackToast, closeToast } = useFeedbackCollectionToast({
7289
- feedbackId: require_user.localStorageKeys.previewChangeFeedbackID,
7297
+ feedbackId: require_version.localStorageKeys.previewChangeFeedbackID,
7290
7298
  description: "Enjoy preview change?",
7291
7299
  onFeedbackSubmit: (feedback) => {
7292
7300
  switch (feedback) {
@@ -7315,7 +7323,7 @@ function SandboxView({ isOpen, onClose, current }) {
7315
7323
  externalLinkText: "Give us feedback"
7316
7324
  });
7317
7325
  const { guideToast: prepareEnvToast, closeGuideToast } = useGuideToast({
7318
- guideId: require_user.localStorageKeys.prepareEnvGuideID,
7326
+ guideId: require_version.localStorageKeys.prepareEnvGuideID,
7319
7327
  description: "Want to compare data changes with production data?",
7320
7328
  externalLink: "https://docs.datarecce.io/get-started/#prepare-dbt-artifacts",
7321
7329
  externalLinkText: "Learn how.",
@@ -7742,7 +7750,7 @@ function ExploreChangeMenuButton({ node, baseColumns, currentColumns, disableRea
7742
7750
  const isAddedOrRemoved = node.data.changeStatus === "added" || node.data.changeStatus === "removed";
7743
7751
  const addSchemaCheck = (0, react.useCallback)(async () => {
7744
7752
  const nodeId = node.id;
7745
- setLocation(`/checks/?id=${(await require_user.createSchemaDiffCheck({ node_id: nodeId })).check_id}`);
7753
+ setLocation(`/checks/?id=${(await require_version.createSchemaDiffCheck({ node_id: nodeId })).check_id}`);
7746
7754
  }, [node, setLocation]);
7747
7755
  const formattedColumns = formatSelectColumns(baseColumns, currentColumns);
7748
7756
  let query = `select * from {{ ref("${node.data.name}") }}`;
@@ -8391,8 +8399,8 @@ const useMultiNodesAction = (nodes, { onActionStarted, onActionNodeUpdated, onAc
8391
8399
  };
8392
8400
  const addSchemaDiffCheck = async () => {
8393
8401
  let check;
8394
- if (nodes.length === 1) check = await require_user.createSchemaDiffCheck({ node_id: nodes[0].id });
8395
- else check = await require_user.createSchemaDiffCheck({ node_id: nodes.map((node) => node.id) });
8402
+ if (nodes.length === 1) check = await require_version.createSchemaDiffCheck({ node_id: nodes[0].id });
8403
+ else check = await require_version.createSchemaDiffCheck({ node_id: nodes.map((node) => node.id) });
8396
8404
  return check;
8397
8405
  };
8398
8406
  const cancel = async () => {
@@ -8463,7 +8471,7 @@ function PrivateLineageView({ interactive = false, ...props }, ref) {
8463
8471
  const reactFlow = (0, _xyflow_react.useReactFlow)();
8464
8472
  const refResize = (0, react.useRef)(null);
8465
8473
  const { successToast, failToast } = require_state.useClipBoardToast();
8466
- const { copyToClipboard, ImageDownloadModal, ref: refReactFlow } = useCopyToClipboard({
8474
+ const { copyToClipboard, ImageDownloadModal, ref: refReactFlow } = useCopyToClipboard$1({
8467
8475
  renderLibrary: "html-to-image",
8468
8476
  imageType: "png",
8469
8477
  shadowEffect: true,
@@ -8605,7 +8613,7 @@ function PrivateLineageView({ interactive = false, ...props }, ref) {
8605
8613
  ...props.viewOptions
8606
8614
  };
8607
8615
  try {
8608
- filteredNodeIds$1 = (await require_user.select({
8616
+ filteredNodeIds$1 = (await require_version.select({
8609
8617
  select: newViewOptions.select,
8610
8618
  exclude: newViewOptions.exclude,
8611
8619
  packages: newViewOptions.packages,
@@ -8613,7 +8621,7 @@ function PrivateLineageView({ interactive = false, ...props }, ref) {
8613
8621
  })).nodes;
8614
8622
  } catch (_$1) {
8615
8623
  newViewOptions.view_mode = "all";
8616
- filteredNodeIds$1 = (await require_user.select({
8624
+ filteredNodeIds$1 = (await require_version.select({
8617
8625
  select: newViewOptions.select,
8618
8626
  exclude: newViewOptions.exclude,
8619
8627
  packages: newViewOptions.packages,
@@ -8734,7 +8742,7 @@ function PrivateLineageView({ interactive = false, ...props }, ref) {
8734
8742
  if (!lineageGraph) return;
8735
8743
  if (viewOptions.select !== newViewOptions.select || viewOptions.exclude !== newViewOptions.exclude || viewOptions.packages !== newViewOptions.packages || viewOptions.view_mode !== newViewOptions.view_mode) {
8736
8744
  try {
8737
- const result = await require_user.select({
8745
+ const result = await require_version.select({
8738
8746
  select: newViewOptions.select,
8739
8747
  exclude: newViewOptions.exclude,
8740
8748
  packages: newViewOptions.packages,
@@ -9041,13 +9049,13 @@ function PrivateLineageView({ interactive = false, ...props }, ref) {
9041
9049
  });
9042
9050
  }
9043
9051
  } else if (focusedNode) {
9044
- check = await require_user.createSchemaDiffCheck({ node_id: focusedNode.id });
9052
+ check = await require_version.createSchemaDiffCheck({ node_id: focusedNode.id });
9045
9053
  require_state.trackMultiNodesAction({
9046
9054
  type: "schema_diff",
9047
9055
  selected: "single"
9048
9056
  });
9049
9057
  } else {
9050
- check = await require_user.createSchemaDiffCheck({
9058
+ check = await require_version.createSchemaDiffCheck({
9051
9059
  select: viewOptions.select,
9052
9060
  exclude: viewOptions.exclude,
9053
9061
  packages: viewOptions.packages,
@@ -10391,7 +10399,7 @@ function UserAvatar({ event }) {
10391
10399
  const userId = actor.user_id?.toString();
10392
10400
  const { data: avatarUrl } = (0, _tanstack_react_query.useQuery)({
10393
10401
  queryKey: ["github-avatar", userId],
10394
- queryFn: () => userId ? require_user.fetchGitHubAvatar(userId) : Promise.resolve(null),
10402
+ queryFn: () => userId ? require_version.fetchGitHubAvatar(userId) : Promise.resolve(null),
10395
10403
  enabled: !!userId,
10396
10404
  retry: false,
10397
10405
  staleTime: 300 * 1e3
@@ -10740,7 +10748,7 @@ function CheckTimeline({ checkId }) {
10740
10748
  const { events, isLoading, error, createComment: createComment$1, isCreatingComment, updateComment: updateComment$1, deleteComment: deleteComment$1 } = useCheckEvents(checkId);
10741
10749
  const { data: currentUser } = (0, _tanstack_react_query.useQuery)({
10742
10750
  queryKey: require_state.cacheKeys.user(),
10743
- queryFn: require_user.fetchUser,
10751
+ queryFn: require_version.fetchUser,
10744
10752
  retry: false
10745
10753
  });
10746
10754
  const handleCreateComment = (content) => {
@@ -11129,7 +11137,7 @@ function PrivateSchemaDiffView({ check }, ref) {
11129
11137
  const params = check.params;
11130
11138
  const { isLoading, error, data } = (0, _tanstack_react_query.useQuery)({
11131
11139
  queryKey: [...require_state.cacheKeys.check(check.check_id), "select"],
11132
- queryFn: async () => require_user.select({
11140
+ queryFn: async () => require_version.select({
11133
11141
  select: params.select,
11134
11142
  exclude: params.exclude,
11135
11143
  packages: params.packages,
@@ -11821,7 +11829,7 @@ const CheckEmptyState = () => {
11821
11829
  const queryClient = (0, _tanstack_react_query.useQueryClient)();
11822
11830
  const [, setLocation] = require_state.useAppLocation();
11823
11831
  const { mutate: createSchemaCheck, isPending } = (0, _tanstack_react_query.useMutation)({
11824
- mutationFn: () => require_user.createSchemaDiffCheck({ select: "state:modified" }),
11832
+ mutationFn: () => require_version.createSchemaDiffCheck({ select: "state:modified" }),
11825
11833
  onSuccess: async (check) => {
11826
11834
  await queryClient.invalidateQueries({ queryKey: require_state.cacheKeys.checks() });
11827
11835
  setLocation(`/checks/?id=${check.check_id}`);
@@ -12471,6 +12479,124 @@ function SummaryView() {
12471
12479
  }) });
12472
12480
  }
12473
12481
 
12482
+ //#endregion
12483
+ //#region recce-source/js/src/components/app/AvatarDropdown.tsx
12484
+ function AvatarDropdown() {
12485
+ const { data: user, isLoading, error } = (0, _tanstack_react_query.useQuery)({
12486
+ queryKey: require_state.cacheKeys.user(),
12487
+ queryFn: require_version.fetchUser,
12488
+ retry: false
12489
+ });
12490
+ const { data: avatarUrl } = (0, _tanstack_react_query.useQuery)({
12491
+ queryKey: ["github-avatar", user?.id],
12492
+ queryFn: () => user ? require_version.fetchGitHubAvatar(user.id) : Promise.resolve(null),
12493
+ enabled: !!user?.id && user.login_type === "github",
12494
+ retry: false,
12495
+ staleTime: 300 * 1e3
12496
+ });
12497
+ const [anchorEl, setAnchorEl] = (0, react.useState)(null);
12498
+ const open = Boolean(anchorEl);
12499
+ const handleClick = (event) => {
12500
+ setAnchorEl(event.currentTarget);
12501
+ };
12502
+ const handleClose = () => {
12503
+ setAnchorEl(null);
12504
+ };
12505
+ const showUserInfo = !isLoading && !error && user;
12506
+ const getInitials = (name) => {
12507
+ if (!name) return "U";
12508
+ return name.charAt(0).toUpperCase();
12509
+ };
12510
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [isLoading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
12511
+ onClick: handleClick,
12512
+ sx: {
12513
+ width: 32,
12514
+ height: 32,
12515
+ borderRadius: "50%",
12516
+ bgcolor: "background.paper",
12517
+ color: "primary.main",
12518
+ display: "flex",
12519
+ alignItems: "center",
12520
+ justifyContent: "center",
12521
+ cursor: "pointer"
12522
+ },
12523
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_CircularProgress.default, { size: 16 })
12524
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Avatar.default, {
12525
+ onClick: handleClick,
12526
+ src: avatarUrl || void 0,
12527
+ sx: {
12528
+ width: 28,
12529
+ height: 28,
12530
+ cursor: "pointer",
12531
+ outline: "1px solid white",
12532
+ fontSize: "0.875rem"
12533
+ },
12534
+ children: getInitials(user?.login)
12535
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Menu.default, {
12536
+ anchorEl,
12537
+ open,
12538
+ onClose: handleClose,
12539
+ slotProps: { paper: { sx: {
12540
+ bgcolor: "background.paper",
12541
+ borderColor: "divider",
12542
+ boxShadow: 3,
12543
+ minWidth: 180
12544
+ } } },
12545
+ children: [
12546
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Box.default, {
12547
+ sx: {
12548
+ px: 2,
12549
+ py: 1.5
12550
+ },
12551
+ children: [
12552
+ isLoading && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Box.default, {
12553
+ sx: {
12554
+ display: "flex",
12555
+ alignItems: "center",
12556
+ gap: 1
12557
+ },
12558
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Typography.default, {
12559
+ variant: "body2",
12560
+ color: "text.primary",
12561
+ children: "Loading..."
12562
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_CircularProgress.default, { size: 16 })]
12563
+ }),
12564
+ error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Typography.default, {
12565
+ variant: "caption",
12566
+ color: "error",
12567
+ children: "Failed to load user information"
12568
+ }),
12569
+ showUserInfo && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Typography.default, {
12570
+ variant: "body2",
12571
+ fontWeight: "600",
12572
+ color: "text.primary",
12573
+ children: user.login
12574
+ }), user.email && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Typography.default, {
12575
+ variant: "caption",
12576
+ color: "text.secondary",
12577
+ children: user.email
12578
+ })] })
12579
+ ]
12580
+ }),
12581
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Divider.default, {}),
12582
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_MenuItem.default, {
12583
+ onClick: () => {
12584
+ window.open("https://cloud.datarecce.io/", "_blank");
12585
+ handleClose();
12586
+ },
12587
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_ListItemIcon.default, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_fa.FaCloud, {}) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_ListItemText.default, { children: "Recce Cloud" })]
12588
+ }),
12589
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_MenuItem.default, {
12590
+ onClick: () => {
12591
+ window.open(require_urls.RECCE_SUPPORT_CALENDAR_URL, "_blank");
12592
+ handleClose();
12593
+ },
12594
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_ListItemIcon.default, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_fa.FaUser, {}) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_ListItemText.default, { children: "Get live support" })]
12595
+ })
12596
+ ]
12597
+ })] });
12598
+ }
12599
+
12474
12600
  //#endregion
12475
12601
  //#region recce-source/js/src/components/timeout/IdleTimeoutBadge.tsx
12476
12602
  /**
@@ -12490,20 +12616,1145 @@ function IdleTimeoutBadge() {
12490
12616
  color: "warning",
12491
12617
  variant: "standard",
12492
12618
  sx: {
12493
- display: "flex",
12619
+ display: "flex",
12620
+ alignItems: "center",
12621
+ gap: 1,
12622
+ fontSize: "0.75rem",
12623
+ mr: 2
12624
+ },
12625
+ children: [
12626
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
12627
+ component: react_icons_io5.IoWarning,
12628
+ sx: { display: "inline-flex" }
12629
+ }),
12630
+ "Idle timeout: ",
12631
+ require_state.formatDuration(remainingSeconds, "compact")
12632
+ ]
12633
+ });
12634
+ }
12635
+
12636
+ //#endregion
12637
+ //#region recce-source/js/app/(mainComponents)/TopBar.tsx
12638
+ function LinkIcon({ icon: IconComponent, href, sx, ...props }) {
12639
+ const theme = (0, _mui_material_styles.useTheme)();
12640
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Link.default, {
12641
+ sx: {
12642
+ height: "20px",
12643
+ color: "common.white",
12644
+ ...sx
12645
+ },
12646
+ href,
12647
+ target: "_blank",
12648
+ ...props,
12649
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconComponent, { style: {
12650
+ color: theme.palette.common.white,
12651
+ width: 20,
12652
+ height: 20
12653
+ } })
12654
+ });
12655
+ }
12656
+ function TopBar() {
12657
+ const { reviewMode, isDemoSite, envInfo, cloudMode } = require_state.useLineageGraphContext();
12658
+ const { featureToggles, authed } = require_state.useRecceInstanceContext();
12659
+ const { url: prURL, id: prID } = envInfo?.pullRequest ?? {};
12660
+ const demoPrId = prURL ? prURL.split("/").pop() : null;
12661
+ const brandLink = cloudMode || authed ? "https://cloud.datarecce.io/" : "https://reccehq.com/";
12662
+ const [showModal, setShowModal] = (0, react.useState)(false);
12663
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Box.default, {
12664
+ sx: {
12665
+ display: "flex",
12666
+ gap: "10px",
12667
+ minHeight: "40px",
12668
+ alignItems: "center",
12669
+ bgcolor: require_state.colors.brand[400]
12670
+ },
12671
+ children: [
12672
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Link.default, {
12673
+ href: brandLink,
12674
+ target: "_blank",
12675
+ sx: { "&:hover": { textDecoration: "none" } },
12676
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Box.default, {
12677
+ sx: {
12678
+ display: "flex",
12679
+ gap: "10px",
12680
+ alignItems: "center"
12681
+ },
12682
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
12683
+ component: "img",
12684
+ sx: {
12685
+ width: 20,
12686
+ height: 20,
12687
+ ml: "18px"
12688
+ },
12689
+ src: "/logo/recce-logo-white.png",
12690
+ alt: "recce-logo-white"
12691
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Typography.default, {
12692
+ variant: "h4",
12693
+ sx: {
12694
+ fontFamily: "\"Montserrat\", sans-serif",
12695
+ color: "common.white",
12696
+ fontSize: "1.25rem"
12697
+ },
12698
+ children: "RECCE"
12699
+ })]
12700
+ })
12701
+ }),
12702
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(app__mainComponents__DisplayModeToggle.default, {}),
12703
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(app__mainComponents__RecceVersionBadge.default, {}),
12704
+ (featureToggles.mode ?? reviewMode) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Badge.default, {
12705
+ sx: {
12706
+ fontSize: "0.875rem",
12707
+ color: "rgba(255,255,255,0.8)",
12708
+ textTransform: "uppercase",
12709
+ borderWidth: 1,
12710
+ px: 1,
12711
+ borderRadius: .75,
12712
+ borderColor: "rgba(255,255,255,0.8)"
12713
+ },
12714
+ children: featureToggles.mode ?? "review mode"
12715
+ }),
12716
+ cloudMode && prID && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Badge.default, {
12717
+ sx: {
12718
+ fontSize: "0.875rem",
12719
+ color: "rgba(255,255,255,0.8)",
12720
+ textTransform: "uppercase",
12721
+ borderWidth: 1,
12722
+ px: 1,
12723
+ borderRadius: .75,
12724
+ borderColor: "rgba(255,255,255,0.8)"
12725
+ },
12726
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Stack.default, {
12727
+ direction: "row",
12728
+ spacing: 1,
12729
+ alignItems: "center",
12730
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, { children: "cloud mode" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
12731
+ sx: {
12732
+ borderLeft: "1px solid rgba(255,255,255,0.8)",
12733
+ pl: "8px"
12734
+ },
12735
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Link.default, {
12736
+ href: prURL,
12737
+ sx: { "&:hover": { textDecoration: "none" } },
12738
+ target: "_blank",
12739
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_vsc.VscGitPullRequest, { style: {
12740
+ color: "rgba(255,255,255,0.8)",
12741
+ width: 12,
12742
+ height: 12,
12743
+ marginRight: 2,
12744
+ display: "inline",
12745
+ verticalAlign: "middle"
12746
+ } }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Typography.default, {
12747
+ component: "span",
12748
+ sx: {
12749
+ color: "rgba(255,255,255,0.8)",
12750
+ display: "inline"
12751
+ },
12752
+ children: `#${String(prID)}`
12753
+ })]
12754
+ })
12755
+ })]
12756
+ })
12757
+ }),
12758
+ isDemoSite && prURL && demoPrId && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Badge.default, {
12759
+ sx: {
12760
+ fontSize: "0.875rem",
12761
+ color: "rgba(255,255,255,0.8)",
12762
+ textTransform: "uppercase",
12763
+ borderWidth: 1,
12764
+ px: 1,
12765
+ borderRadius: .75,
12766
+ borderColor: "rgba(255,255,255,0.8)"
12767
+ },
12768
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Stack.default, {
12769
+ direction: "row",
12770
+ spacing: 1,
12771
+ alignItems: "center",
12772
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, { children: "demo mode" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
12773
+ sx: {
12774
+ borderLeft: "1px solid rgba(255,255,255,0.8)",
12775
+ pl: "8px"
12776
+ },
12777
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Link.default, {
12778
+ href: prURL,
12779
+ sx: { "&:hover": { textDecoration: "none" } },
12780
+ target: "_blank",
12781
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_vsc.VscGitPullRequest, { style: {
12782
+ color: "rgba(255,255,255,0.8)",
12783
+ width: 12,
12784
+ height: 12,
12785
+ marginRight: 2,
12786
+ display: "inline",
12787
+ verticalAlign: "middle"
12788
+ } }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Typography.default, {
12789
+ component: "span",
12790
+ sx: {
12791
+ color: "rgba(255,255,255,0.8)",
12792
+ display: "inline"
12793
+ },
12794
+ children: `#${demoPrId}`
12795
+ })]
12796
+ })
12797
+ })]
12798
+ })
12799
+ }),
12800
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, { sx: { flex: 1 } }),
12801
+ (isDemoSite || featureToggles.mode === "read only") && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
12802
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LinkIcon, {
12803
+ icon: react_icons_fa.FaGithub,
12804
+ href: "https://github.com/DataRecce/recce"
12805
+ }),
12806
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LinkIcon, {
12807
+ icon: react_icons_fa.FaSlack,
12808
+ href: "https://getdbt.slack.com/archives/C05C28V7CPP"
12809
+ }),
12810
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LinkIcon, {
12811
+ sx: { mr: 2 },
12812
+ icon: react_icons_fa.FaQuestionCircle,
12813
+ href: "https://docs.datarecce.io"
12814
+ })
12815
+ ] }),
12816
+ !isDemoSite && featureToggles.mode !== "read only" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IdleTimeoutBadge, {}), authed || cloudMode ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
12817
+ sx: { mr: 2 },
12818
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AvatarDropdown, {})
12819
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
12820
+ component: "button",
12821
+ sx: {
12822
+ color: "common.white",
12823
+ fontSize: "0.875rem",
12824
+ fontWeight: 600,
12825
+ bgcolor: "brand.700",
12826
+ borderRadius: 1,
12827
+ px: 3,
12828
+ py: 1,
12829
+ mr: 2,
12830
+ cursor: "pointer",
12831
+ border: "none"
12832
+ },
12833
+ onClick: () => {
12834
+ setShowModal(true);
12835
+ },
12836
+ children: "Connect to Cloud"
12837
+ }), showModal && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AuthModal, {
12838
+ parentOpen: showModal,
12839
+ handleParentClose: setShowModal,
12840
+ ignoreCookie: true,
12841
+ variant: "user-profile"
12842
+ })] })] })
12843
+ ]
12844
+ });
12845
+ }
12846
+
12847
+ //#endregion
12848
+ //#region recce-source/js/src/components/app/Filename.tsx
12849
+ const useRecceToast = () => {
12850
+ const toastSuccess = (message) => {
12851
+ require_state.toaster.create({
12852
+ description: message,
12853
+ type: "success",
12854
+ duration: 5e3,
12855
+ closable: true
12856
+ });
12857
+ };
12858
+ const toastError = (message, error) => {
12859
+ let errorMessage = message;
12860
+ if (error != null) if (error instanceof axios.AxiosError) errorMessage = `${message}. ${String(error.response?.data?.detail)}`;
12861
+ else errorMessage = `${message}. ${error}`;
12862
+ require_state.toaster.create({
12863
+ description: errorMessage,
12864
+ type: "error",
12865
+ duration: 5e3,
12866
+ closable: true
12867
+ });
12868
+ };
12869
+ return {
12870
+ toastSuccess,
12871
+ toastError
12872
+ };
12873
+ };
12874
+ const useClosePrompt = (prompt) => {
12875
+ (0, react.useEffect)(() => {
12876
+ const handleBeforeUnload = (e) => {
12877
+ e.preventDefault();
12878
+ };
12879
+ if (prompt) window.addEventListener("beforeunload", handleBeforeUnload);
12880
+ return () => {
12881
+ if (prompt) window.removeEventListener("beforeunload", handleBeforeUnload);
12882
+ };
12883
+ }, [prompt]);
12884
+ };
12885
+ const Filename = () => {
12886
+ const { featureToggles } = require_state.useRecceInstanceContext();
12887
+ const { fileName, cloudMode, isDemoSite, envInfo } = require_state.useLineageGraphContext();
12888
+ const [modalOpen, setModalOpen] = (0, react.useState)(false);
12889
+ const [overwriteOpen, setOverwriteOpen] = (0, react.useState)(false);
12890
+ const isStateless = !fileName && !cloudMode && !isDemoSite;
12891
+ const { data: checks } = require_state.useChecks(isStateless);
12892
+ const hasNonPresetChecks = checks != void 0 && checks.filter((check) => !check.is_preset).length > 0;
12893
+ useClosePrompt(isStateless && hasNonPresetChecks);
12894
+ const [{ newFileName, errorMessage, modified, overwriteWithMethod, bypass }, setState] = (0, react.useState)({ newFileName: fileName ?? "recce_state.json" });
12895
+ const inputRef = (0, react.useRef)(null);
12896
+ const { toastSuccess, toastError } = useRecceToast();
12897
+ const queryClient = (0, _tanstack_react_query.useQueryClient)();
12898
+ const handleOpen = () => {
12899
+ setState({
12900
+ newFileName: fileName ?? "recce_state.json",
12901
+ modified: !fileName
12902
+ });
12903
+ setModalOpen(true);
12904
+ };
12905
+ const handleModalClose = () => setModalOpen(false);
12906
+ const handleOverwriteClose = () => setOverwriteOpen(false);
12907
+ const handleAction = async (method, overwrite) => {
12908
+ if (!newFileName) return;
12909
+ const bypassOverwrite = localStorage.getItem(require_version.localStorageKeys.bypassSaveOverwrite) === "true";
12910
+ try {
12911
+ if (method === "save") await require_state.saveAs({
12912
+ filename: newFileName,
12913
+ overwrite: overwrite ?? bypassOverwrite
12914
+ });
12915
+ else await require_state.rename({
12916
+ filename: newFileName,
12917
+ overwrite: overwrite ?? bypassOverwrite
12918
+ });
12919
+ toastSuccess(method === "save" ? "Save file successfully" : "Rename file successfully");
12920
+ await queryClient.invalidateQueries({ queryKey: require_state.cacheKeys.lineage() });
12921
+ if (bypass) localStorage.setItem(require_version.localStorageKeys.bypassSaveOverwrite, "true");
12922
+ } catch (error) {
12923
+ if (error instanceof axios.AxiosError) {
12924
+ if (error.response?.status === 409) {
12925
+ setState((s) => ({
12926
+ ...s,
12927
+ overwriteWithMethod: method
12928
+ }));
12929
+ setOverwriteOpen(true);
12930
+ return;
12931
+ }
12932
+ }
12933
+ toastError(method === "save" ? "Save file failed" : "Rename file failed", error);
12934
+ } finally {
12935
+ handleModalClose();
12936
+ }
12937
+ };
12938
+ const handleOvewriteBack = () => {
12939
+ handleOverwriteClose();
12940
+ setModalOpen(true);
12941
+ setState((s) => {
12942
+ return {
12943
+ ...s,
12944
+ overwriteWithMethod: void 0
12945
+ };
12946
+ });
12947
+ };
12948
+ if (cloudMode || isDemoSite) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, {});
12949
+ const titleNewInstance = "New Instance" + (hasNonPresetChecks ? " (unsaved)" : "");
12950
+ let titleReadOnlyState;
12951
+ if (featureToggles.disableSaveToFile && fileName) {
12952
+ const generatedAt = envInfo?.stateMetadata?.generated_at;
12953
+ const formattedDate = generatedAt ? formatRunDateTime(new Date(generatedAt)) : null;
12954
+ titleReadOnlyState = formattedDate ? `${fileName} (${formattedDate})` : null;
12955
+ }
12956
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
12957
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Stack.default, {
12958
+ direction: "row",
12959
+ alignItems: "center",
12960
+ justifyContent: "center",
12961
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
12962
+ sx: { fontWeight: 600 },
12963
+ children: titleReadOnlyState ?? fileName ?? titleNewInstance
12964
+ }), !featureToggles.disableSaveToFile && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Tooltip.default, {
12965
+ title: fileName ? "Change Filename" : "Save",
12966
+ enterDelay: 1e3,
12967
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_IconButton.default, {
12968
+ onClick: handleOpen,
12969
+ "aria-label": fileName ? "Change Filename" : "Save",
12970
+ size: "small",
12971
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
12972
+ component: fileName ? require_state.IconEdit : require_state.IconSave,
12973
+ sx: {
12974
+ fontSize: 16,
12975
+ verticalAlign: "middle"
12976
+ }
12977
+ })
12978
+ })
12979
+ })]
12980
+ }),
12981
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Dialog.default, {
12982
+ open: modalOpen,
12983
+ onClose: handleModalClose,
12984
+ children: [
12985
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_DialogTitle.default, {
12986
+ sx: {
12987
+ display: "flex",
12988
+ alignItems: "center"
12989
+ },
12990
+ children: [
12991
+ fileName ? "Change Filename" : "Save File",
12992
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, { sx: { flexGrow: 1 } }),
12993
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_IconButton.default, {
12994
+ size: "small",
12995
+ onClick: handleModalClose,
12996
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_io5.IoClose, {})
12997
+ })
12998
+ ]
12999
+ }),
13000
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_DialogContent.default, {
13001
+ onKeyDown: (e) => {
13002
+ e.stopPropagation();
13003
+ },
13004
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_TextField.default, {
13005
+ inputRef,
13006
+ value: newFileName,
13007
+ label: "File name",
13008
+ placeholder: "Enter filename",
13009
+ error: !!errorMessage,
13010
+ helperText: errorMessage,
13011
+ fullWidth: true,
13012
+ size: "small",
13013
+ sx: { mt: 1 },
13014
+ onChange: (e) => {
13015
+ const value = e.target.value;
13016
+ let newErrorMessage = void 0;
13017
+ if (!value) newErrorMessage = "Filename cannot be empty.";
13018
+ else if (!value.endsWith(".json")) newErrorMessage = "Filename must end with .json.";
13019
+ else if (!/^[a-zA-Z0-9 _-]+\.json$/.test(value)) newErrorMessage = "Invalid filename. Only alphanumeric, space, _ and - are allowed.";
13020
+ else if (fileName && value === fileName) newErrorMessage = "Filename is the same as the current one.";
13021
+ setState((s) => {
13022
+ return {
13023
+ ...s,
13024
+ modified: true,
13025
+ newFileName: value,
13026
+ errorMessage: newErrorMessage
13027
+ };
13028
+ });
13029
+ },
13030
+ onKeyDown: (e) => {
13031
+ if (e.key === "Enter") {
13032
+ if (errorMessage) return;
13033
+ if (!fileName) handleAction("save");
13034
+ else handleAction("rename");
13035
+ } else if (e.key === "Escape") handleModalClose();
13036
+ }
13037
+ })
13038
+ }),
13039
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_DialogActions.default, {
13040
+ sx: { gap: "5px" },
13041
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Button.default, {
13042
+ size: "small",
13043
+ color: fileName ? "inherit" : "iochmara",
13044
+ variant: "contained",
13045
+ onClick: async () => {
13046
+ await handleAction("save");
13047
+ },
13048
+ disabled: !newFileName || !!errorMessage || !modified,
13049
+ children: fileName ? "Save as New File" : "Confirm"
13050
+ }), fileName && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Button.default, {
13051
+ size: "small",
13052
+ color: "iochmara",
13053
+ variant: "contained",
13054
+ onClick: async () => {
13055
+ await handleAction("rename");
13056
+ },
13057
+ disabled: !newFileName || !!errorMessage || !modified,
13058
+ children: "Rename"
13059
+ })]
13060
+ })
13061
+ ]
13062
+ }),
13063
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Dialog.default, {
13064
+ open: overwriteOpen,
13065
+ onClose: handleOverwriteClose,
13066
+ children: [
13067
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_DialogTitle.default, {
13068
+ sx: {
13069
+ display: "flex",
13070
+ alignItems: "center"
13071
+ },
13072
+ children: [
13073
+ "Overwrite File?",
13074
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, { sx: { flexGrow: 1 } }),
13075
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_IconButton.default, {
13076
+ size: "small",
13077
+ onClick: handleOverwriteClose,
13078
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_io5.IoClose, {})
13079
+ })
13080
+ ]
13081
+ }),
13082
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_DialogContent.default, {
13083
+ sx: {
13084
+ borderTop: "solid 1px",
13085
+ borderBottom: "solid 1px",
13086
+ borderColor: "divider"
13087
+ },
13088
+ onKeyDown: (e) => {
13089
+ e.stopPropagation();
13090
+ },
13091
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Typography.default, {
13092
+ sx: { fontSize: "12pt" },
13093
+ children: overwriteWithMethod === "save" ? "Saving a file with this name will overwrite the existing file. Are you sure you wish to continue?" : "Renaming the file with this name will overwrite the existing file. Are you sure you wish to continue?"
13094
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_FormControlLabel.default, {
13095
+ control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Checkbox.default, {
13096
+ size: "small",
13097
+ checked: bypass,
13098
+ onChange: (e) => {
13099
+ setState((s) => ({
13100
+ ...s,
13101
+ bypass: e.target.checked
13102
+ }));
13103
+ }
13104
+ }),
13105
+ label: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Typography.default, {
13106
+ sx: {
13107
+ fontWeight: "bold",
13108
+ pt: "8px"
13109
+ },
13110
+ children: "Don't show this again"
13111
+ })
13112
+ })]
13113
+ }),
13114
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_DialogActions.default, {
13115
+ sx: { gap: "5px" },
13116
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Button.default, {
13117
+ variant: "outlined",
13118
+ onClick: handleOvewriteBack,
13119
+ size: "small",
13120
+ children: "Back"
13121
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Button.default, {
13122
+ size: "small",
13123
+ color: "iochmara",
13124
+ variant: "contained",
13125
+ onClick: () => {
13126
+ if (!overwriteWithMethod) return;
13127
+ handleAction(overwriteWithMethod, true);
13128
+ handleOverwriteClose();
13129
+ },
13130
+ children: "Overwrite"
13131
+ })]
13132
+ })
13133
+ ]
13134
+ })
13135
+ ] });
13136
+ };
13137
+
13138
+ //#endregion
13139
+ //#region recce-source/js/src/components/app/StateExporter.tsx
13140
+ function StateExporter() {
13141
+ const { featureToggles } = require_state.useRecceInstanceContext();
13142
+ const handleExport = async () => {
13143
+ try {
13144
+ const jsonData = await require_state.exportState();
13145
+ const jsonString = JSON.stringify(jsonData, null, 2);
13146
+ (0, file_saver.default)(new Blob([jsonString], { type: "application/json" }), `recce-state-${(0, date_fns.format)(/* @__PURE__ */ new Date(), "yyyy-MM-dd-HH-mm-ss")}.json`);
13147
+ } catch (error) {
13148
+ console.error("Export failed", error);
13149
+ require_state.toaster.create({
13150
+ title: "Export failed",
13151
+ description: String(error),
13152
+ type: "error",
13153
+ duration: 5e3,
13154
+ closable: true
13155
+ });
13156
+ }
13157
+ };
13158
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Tooltip.default, {
13159
+ title: "Export",
13160
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_IconButton.default, {
13161
+ size: "small",
13162
+ "aria-label": "Export state",
13163
+ onClick: async () => {
13164
+ await handleExport();
13165
+ require_state.trackStateAction({ name: "export" });
13166
+ },
13167
+ disabled: featureToggles.disableExportStateFile,
13168
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
13169
+ component: require_state.IconExport,
13170
+ sx: {
13171
+ verticalAlign: "middle",
13172
+ width: "16px",
13173
+ height: "16px"
13174
+ }
13175
+ })
13176
+ })
13177
+ });
13178
+ }
13179
+
13180
+ //#endregion
13181
+ //#region recce-source/js/src/components/app/StateSharing.tsx
13182
+ const LOADING_MESSAGES = [
13183
+ "Processing...",
13184
+ "Still processing, please wait...",
13185
+ "Almost there, thanks for your patience..."
13186
+ ];
13187
+ function TopLevelShare() {
13188
+ const { successToast, failToast } = require_state.useClipBoardToast();
13189
+ const [, copyToClipboard] = (0, usehooks_ts.useCopyToClipboard)();
13190
+ const { authed } = require_state.useRecceInstanceContext();
13191
+ const { shareUrl, isLoading, error, handleShareClick } = require_RecceCheckContext.useRecceShareStateContext();
13192
+ const [showModal, setShowModal] = (0, react.useState)(false);
13193
+ const [messageIndex, setMessageIndex] = (0, react.useState)(0);
13194
+ const [prevIsLoading, setPrevIsLoading] = (0, react.useState)(isLoading);
13195
+ if (isLoading !== prevIsLoading) {
13196
+ setPrevIsLoading(isLoading);
13197
+ if (isLoading) setMessageIndex(0);
13198
+ }
13199
+ (0, usehooks_ts.useInterval)(() => {
13200
+ setMessageIndex((prev) => Math.min(prev + 1, LOADING_MESSAGES.length - 1));
13201
+ }, isLoading ? 3e4 : null);
13202
+ (0, react.useEffect)(() => {
13203
+ if (error) failToast("Failed to share state", error);
13204
+ }, [error, failToast]);
13205
+ const handleCopy = async () => {
13206
+ try {
13207
+ await copyToClipboard(String(shareUrl));
13208
+ successToast("Copied the link to clipboard");
13209
+ } catch (error$1) {
13210
+ failToast("Failed to copy the link", error$1);
13211
+ }
13212
+ };
13213
+ if (!authed) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Stack.default, {
13214
+ direction: "row",
13215
+ sx: {
13216
+ flex: 1,
13217
+ alignItems: "center"
13218
+ },
13219
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Button.default, {
13220
+ size: "xsmall",
13221
+ color: "neutral",
13222
+ variant: "outlined",
13223
+ onClick: () => {
13224
+ setShowModal(true);
13225
+ },
13226
+ startIcon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_tb.TbCloudUpload, {}),
13227
+ children: "Share"
13228
+ }), showModal && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AuthModal, {
13229
+ parentOpen: showModal,
13230
+ handleParentClose: setShowModal,
13231
+ ignoreCookie: true,
13232
+ variant: "enable-share"
13233
+ })]
13234
+ });
13235
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Stack.default, {
13236
+ direction: "row",
13237
+ sx: {
13238
+ flex: 1,
12494
13239
  alignItems: "center",
12495
- gap: 1,
12496
- fontSize: "0.75rem",
12497
- mr: 2
13240
+ gap: "5px"
12498
13241
  },
12499
13242
  children: [
12500
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
12501
- component: react_icons_io5.IoWarning,
12502
- sx: { display: "inline-flex" }
13243
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Button.default, {
13244
+ size: "xsmall",
13245
+ variant: "outlined",
13246
+ color: "neutral",
13247
+ startIcon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_tb.TbCloudUpload, {}),
13248
+ endIcon: shareUrl ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
13249
+ component: react_icons_pi.PiCheckCircle,
13250
+ sx: { color: "success.main" }
13251
+ }) : void 0,
13252
+ onClick: async () => {
13253
+ await handleShareClick();
13254
+ require_state.trackShareState({ name: "create" });
13255
+ },
13256
+ disabled: isLoading,
13257
+ children: isLoading ? "Sharing..." : "Share"
12503
13258
  }),
12504
- "Idle timeout: ",
12505
- require_state.formatDuration(remainingSeconds, "compact")
13259
+ isLoading && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Typography.default, {
13260
+ sx: {
13261
+ fontSize: 14,
13262
+ color: "grey.500"
13263
+ },
13264
+ children: LOADING_MESSAGES[messageIndex]
13265
+ }),
13266
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Stack.default, {
13267
+ direction: "row",
13268
+ spacing: .5,
13269
+ alignItems: "center",
13270
+ children: shareUrl && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
13271
+ sx: {
13272
+ overflowX: "auto",
13273
+ whiteSpace: "nowrap",
13274
+ maxWidth: "350px"
13275
+ },
13276
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Typography.default, {
13277
+ sx: { fontSize: 14 },
13278
+ children: shareUrl
13279
+ })
13280
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_IconButton.default, {
13281
+ size: "small",
13282
+ "aria-label": "Copy the share URL",
13283
+ onClick: async () => {
13284
+ await handleCopy();
13285
+ require_state.trackShareState({ name: "copy" });
13286
+ },
13287
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_pi.PiCopy, {})
13288
+ })] })
13289
+ })
13290
+ ]
13291
+ });
13292
+ }
13293
+
13294
+ //#endregion
13295
+ //#region recce-source/js/src/components/app/StateSynchronizer.tsx
13296
+ function isCheckDetailPage(href) {
13297
+ return /^\/checks\/([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/.test(href);
13298
+ }
13299
+ function StateSpinner() {
13300
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Tooltip.default, {
13301
+ title: "Syncing",
13302
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
13303
+ sx: { mx: "10px" },
13304
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_CircularProgress.default, { size: 20 })
13305
+ })
13306
+ });
13307
+ }
13308
+ function StateSynchronizer() {
13309
+ const [isSyncing, setSyncing] = (0, react.useState)(false);
13310
+ const queryClient = (0, _tanstack_react_query.useQueryClient)();
13311
+ const [location, setLocation] = require_state.useAppLocation();
13312
+ const [open, setOpen] = (0, react.useState)(false);
13313
+ const [syncOption, setSyncOption] = (0, react.useState)("");
13314
+ const { data: instanceInfo } = require_state.useRecceInstanceInfo();
13315
+ const handleClose = () => setOpen(false);
13316
+ const handleSync = (0, react.useCallback)(async (input) => {
13317
+ setOpen(false);
13318
+ setSyncing(true);
13319
+ if ((await require_state.syncState(input)).status === "conflict") {
13320
+ setOpen(true);
13321
+ setSyncing(false);
13322
+ return;
13323
+ }
13324
+ while (await require_state.isStateSyncing()) await new Promise((resolve) => setTimeout(resolve, 1e3));
13325
+ require_state.toaster.create({
13326
+ description: "Sync Completed",
13327
+ type: "success",
13328
+ duration: 5e3,
13329
+ closable: true
13330
+ });
13331
+ setSyncing(false);
13332
+ setSyncOption("");
13333
+ await queryClient.invalidateQueries({ queryKey: require_state.cacheKeys.lineage() });
13334
+ await queryClient.invalidateQueries({ queryKey: require_state.cacheKeys.checks() });
13335
+ await queryClient.invalidateQueries({ queryKey: require_state.cacheKeys.runs() });
13336
+ if (isCheckDetailPage(location)) setLocation("/checks");
13337
+ }, [
13338
+ queryClient,
13339
+ location,
13340
+ setLocation
13341
+ ]);
13342
+ if (isSyncing) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StateSpinner, {});
13343
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Tooltip.default, {
13344
+ title: "Sync with Cloud",
13345
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_IconButton.default, {
13346
+ size: "small",
13347
+ "aria-label": "Sync state",
13348
+ onClick: () => handleSync(instanceInfo?.session_id ? { method: "merge" } : {}),
13349
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
13350
+ component: require_state.IconSync,
13351
+ sx: {
13352
+ fontSize: 16,
13353
+ verticalAlign: "middle"
13354
+ }
13355
+ })
13356
+ })
13357
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Dialog.default, {
13358
+ open,
13359
+ onClose: handleClose,
13360
+ children: [
13361
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_DialogTitle.default, {
13362
+ sx: {
13363
+ display: "flex",
13364
+ alignItems: "center",
13365
+ fontWeight: "bold"
13366
+ },
13367
+ children: [
13368
+ "Sync with Cloud",
13369
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, { sx: { flexGrow: 1 } }),
13370
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_IconButton.default, {
13371
+ size: "small",
13372
+ onClick: handleClose,
13373
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_io5.IoClose, {})
13374
+ })
13375
+ ]
13376
+ }),
13377
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_DialogContent.default, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Typography.default, { children: "New changes have been detected in the cloud. Please choose a method to sync your state" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
13378
+ sx: { mt: "5px" },
13379
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_RadioGroup.default, {
13380
+ value: syncOption,
13381
+ onChange: (e) => {
13382
+ setSyncOption(e.target.value);
13383
+ },
13384
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Stack.default, {
13385
+ direction: "column",
13386
+ children: [
13387
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_FormControlLabel.default, {
13388
+ value: "merge",
13389
+ control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Radio.default, {}),
13390
+ label: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Stack.default, {
13391
+ direction: "row",
13392
+ alignItems: "center",
13393
+ children: ["Merge", /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Tooltip.default, {
13394
+ title: "This will merge the local and remote states.",
13395
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
13396
+ component: react_icons_pi.PiInfo,
13397
+ sx: {
13398
+ ml: 2,
13399
+ cursor: "pointer"
13400
+ }
13401
+ })
13402
+ })]
13403
+ })
13404
+ }),
13405
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_FormControlLabel.default, {
13406
+ value: "overwrite",
13407
+ control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Radio.default, {}),
13408
+ label: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Stack.default, {
13409
+ direction: "row",
13410
+ alignItems: "center",
13411
+ children: ["Overwrite", /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Tooltip.default, {
13412
+ title: "This will overwrite the remote state file with the local state.",
13413
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
13414
+ component: react_icons_pi.PiInfo,
13415
+ sx: {
13416
+ ml: 2,
13417
+ cursor: "pointer"
13418
+ }
13419
+ })
13420
+ })]
13421
+ })
13422
+ }),
13423
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_FormControlLabel.default, {
13424
+ value: "revert",
13425
+ control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Radio.default, {}),
13426
+ label: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Stack.default, {
13427
+ direction: "row",
13428
+ alignItems: "center",
13429
+ children: ["Revert", /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Tooltip.default, {
13430
+ title: "This will discard local changes and revert to the cloud state.",
13431
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
13432
+ component: react_icons_pi.PiInfo,
13433
+ sx: {
13434
+ ml: 2,
13435
+ cursor: "pointer"
13436
+ }
13437
+ })
13438
+ })]
13439
+ })
13440
+ })
13441
+ ]
13442
+ })
13443
+ })
13444
+ })] }),
13445
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_DialogActions.default, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Button.default, {
13446
+ onClick: handleClose,
13447
+ sx: { mr: 1 },
13448
+ children: "Cancel"
13449
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Button.default, {
13450
+ color: "iochmara",
13451
+ variant: "contained",
13452
+ onClick: () => handleSync({ method: syncOption || void 0 }),
13453
+ disabled: !syncOption,
13454
+ children: "Sync"
13455
+ })] })
12506
13456
  ]
13457
+ })] });
13458
+ }
13459
+
13460
+ //#endregion
13461
+ //#region recce-source/js/app/(mainComponents)/NavBar.tsx
13462
+ /**
13463
+ * Route configuration for tabs
13464
+ */
13465
+ const ROUTE_CONFIG = [
13466
+ {
13467
+ path: "/lineage",
13468
+ name: "Lineage"
13469
+ },
13470
+ {
13471
+ path: "/query",
13472
+ name: "Query"
13473
+ },
13474
+ {
13475
+ path: "/checks",
13476
+ name: "Checklist"
13477
+ }
13478
+ ];
13479
+ function TabBadge({ queryKey, fetchCallback, selectCallback }) {
13480
+ const { data: count, isLoading, error } = (0, _tanstack_react_query.useQuery)({
13481
+ queryKey,
13482
+ queryFn: fetchCallback,
13483
+ select: selectCallback
13484
+ });
13485
+ if (isLoading || error || count === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, {});
13486
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
13487
+ bgcolor: "brand.main",
13488
+ display: "flex",
13489
+ justifyContent: "center",
13490
+ alignItems: "center",
13491
+ p: 1,
13492
+ borderRadius: "100%",
13493
+ color: "white",
13494
+ fontWeight: 700,
13495
+ fontSize: "0.75rem",
13496
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: count })
13497
+ });
13498
+ }
13499
+ function ChecklistBadge() {
13500
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TabBadge, {
13501
+ queryKey: require_state.cacheKeys.checks(),
13502
+ fetchCallback: require_state.listChecks,
13503
+ selectCallback: (checks) => {
13504
+ return checks.filter((check) => !check.is_checked).length;
13505
+ }
13506
+ });
13507
+ }
13508
+ function NavBar() {
13509
+ const pathname = (0, next_navigation.usePathname)();
13510
+ const { isDemoSite, isLoading, cloudMode } = require_state.useLineageGraphContext();
13511
+ const { featureToggles } = require_state.useRecceInstanceContext();
13512
+ const { data: flag, isLoading: isFlagLoading } = require_state.useRecceServerFlag();
13513
+ const prevPathnameRef = (0, react.useRef)(null);
13514
+ (0, react.useEffect)(() => {
13515
+ if (prevPathnameRef.current && prevPathnameRef.current !== pathname) require_state.trackNavigation({
13516
+ from: prevPathnameRef.current,
13517
+ to: pathname
13518
+ });
13519
+ prevPathnameRef.current = pathname;
13520
+ }, [pathname]);
13521
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
13522
+ sx: {
13523
+ borderBottom: "1px solid lightgray",
13524
+ px: "12px"
13525
+ },
13526
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Box.default, {
13527
+ sx: {
13528
+ display: "grid",
13529
+ gridTemplateColumns: "1fr auto 1fr",
13530
+ width: "100%",
13531
+ alignItems: "center"
13532
+ },
13533
+ children: [
13534
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Tabs.default, {
13535
+ value: (0, react.useMemo)(() => {
13536
+ if (pathname.startsWith("/checks")) return "/checks";
13537
+ if (pathname.startsWith("/query")) return "/query";
13538
+ if (pathname.startsWith("/runs")) return "/runs";
13539
+ return "/lineage";
13540
+ }, [pathname]),
13541
+ sx: {
13542
+ borderBottom: "none",
13543
+ minHeight: "auto"
13544
+ },
13545
+ children: ROUTE_CONFIG.map(({ path, name }) => {
13546
+ if (name === "Query" && flag?.single_env_onboarding) return null;
13547
+ if (name === "Checklist" && ChecklistBadge) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Tab.default, {
13548
+ value: path,
13549
+ disabled: isLoading || isFlagLoading,
13550
+ sx: { p: 0 },
13551
+ label: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
13552
+ sx: {
13553
+ display: "flex",
13554
+ alignItems: "center",
13555
+ gap: "4px"
13556
+ },
13557
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(next_link.default, {
13558
+ href: path,
13559
+ style: {
13560
+ textDecoration: "none",
13561
+ color: "inherit",
13562
+ padding: "0.875rem 1.1875rem",
13563
+ display: "flex",
13564
+ gap: 3,
13565
+ alignItems: "center"
13566
+ },
13567
+ children: [
13568
+ name,
13569
+ " ",
13570
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChecklistBadge, {})
13571
+ ]
13572
+ })
13573
+ })
13574
+ }, path);
13575
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Tab.default, {
13576
+ value: path,
13577
+ disabled: isLoading || isFlagLoading,
13578
+ sx: { p: 0 },
13579
+ label: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
13580
+ sx: {
13581
+ display: "flex",
13582
+ alignItems: "center",
13583
+ gap: "4px"
13584
+ },
13585
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(next_link.default, {
13586
+ href: path,
13587
+ style: {
13588
+ textDecoration: "none",
13589
+ color: "inherit",
13590
+ padding: "0.875rem 1.1875rem"
13591
+ },
13592
+ children: name
13593
+ })
13594
+ })
13595
+ }, path);
13596
+ })
13597
+ }),
13598
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Box.default, {
13599
+ sx: {
13600
+ display: "flex",
13601
+ alignItems: "center",
13602
+ gap: "12px",
13603
+ justifyContent: "center"
13604
+ },
13605
+ children: [!isLoading && !isDemoSite && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Filename, {}), !isLoading && !isDemoSite && !flag?.single_env_onboarding && !featureToggles.disableShare && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TopLevelShare, {})]
13606
+ }),
13607
+ !isLoading && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Box.default, {
13608
+ sx: {
13609
+ display: "flex",
13610
+ justifyContent: "right",
13611
+ alignItems: "center",
13612
+ mr: "8px"
13613
+ },
13614
+ children: [
13615
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EnvInfo, {}),
13616
+ cloudMode && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StateSynchronizer, {}),
13617
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StateExporter, {})
13618
+ ]
13619
+ })
13620
+ ]
13621
+ })
13622
+ });
13623
+ }
13624
+
13625
+ //#endregion
13626
+ //#region recce-source/js/app/(mainComponents)/DisplayModeToggle.tsx
13627
+ /**
13628
+ * Display Mode Toggle - switches between light and dark themes
13629
+ *
13630
+ * Uses next-themes to persist the user's preference.
13631
+ * Default is light theme, with future support for system preference.
13632
+ */
13633
+ function DisplayModeToggle() {
13634
+ const { setTheme, resolvedTheme } = (0, next_themes.useTheme)();
13635
+ const [mounted, setMounted] = (0, react.useState)(false);
13636
+ (0, react.useEffect)(() => {
13637
+ setMounted(true);
13638
+ }, []);
13639
+ const toggleTheme = () => {
13640
+ setTheme(resolvedTheme === "dark" ? "light" : "dark");
13641
+ };
13642
+ if (!mounted) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_IconButton.default, {
13643
+ size: "small",
13644
+ sx: {
13645
+ color: "rgba(255, 255, 255, 0.8)",
13646
+ "&:hover": { bgcolor: "rgba(255, 255, 255, 0.1)" }
13647
+ },
13648
+ disabled: true,
13649
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_pi.PiSun, { style: {
13650
+ width: 18,
13651
+ height: 18
13652
+ } })
13653
+ });
13654
+ const isDark = resolvedTheme === "dark";
13655
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Tooltip.default, {
13656
+ title: isDark ? "Switch to light mode" : "Switch to dark mode",
13657
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_IconButton.default, {
13658
+ size: "small",
13659
+ onClick: toggleTheme,
13660
+ sx: {
13661
+ color: "rgba(255, 255, 255, 0.8)",
13662
+ "&:hover": { bgcolor: "rgba(255, 255, 255, 0.1)" }
13663
+ },
13664
+ "aria-label": isDark ? "Switch to light mode" : "Switch to dark mode",
13665
+ children: isDark ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_pi.PiSun, { style: {
13666
+ width: 18,
13667
+ height: 18
13668
+ } }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_pi.PiMoon, { style: {
13669
+ width: 18,
13670
+ height: 18
13671
+ } })
13672
+ })
13673
+ });
13674
+ }
13675
+
13676
+ //#endregion
13677
+ //#region recce-source/js/app/(mainComponents)/RecceVersionBadge.tsx
13678
+ function RecceVersionBadge() {
13679
+ const { version, latestVersion } = require_version.useVersionNumber();
13680
+ const versionFormatRegex = (0, react.useMemo)(() => /* @__PURE__ */ new RegExp("^\\d+\\.\\d+\\.\\d+$"), []);
13681
+ (0, react.useEffect)(() => {
13682
+ if (versionFormatRegex.test(version) && version !== latestVersion) {
13683
+ const storageKey = "recce-update-toast-shown";
13684
+ if (sessionStorage.getItem(storageKey)) return;
13685
+ setTimeout(() => {
13686
+ require_state.toaster.create({
13687
+ id: "recce-update-available",
13688
+ title: "Update available",
13689
+ description: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
13690
+ "A new version of Recce (v",
13691
+ latestVersion,
13692
+ ") is available.",
13693
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("br", {}),
13694
+ "Please run",
13695
+ " ",
13696
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Box.default, {
13697
+ component: "code",
13698
+ sx: {
13699
+ bgcolor: "grey.200",
13700
+ px: .5,
13701
+ py: .25,
13702
+ borderRadius: .5,
13703
+ fontFamily: "monospace",
13704
+ fontSize: "0.875em"
13705
+ },
13706
+ children: "pip install --upgrade recce"
13707
+ }),
13708
+ " ",
13709
+ "to update Recce.",
13710
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("br", {}),
13711
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Link.default, {
13712
+ sx: {
13713
+ color: "primary.main",
13714
+ fontWeight: "bold",
13715
+ "&:hover": { textDecoration: "underline" }
13716
+ },
13717
+ href: `https://github.com/DataRecce/recce/releases/tag/v${latestVersion}`,
13718
+ target: "_blank",
13719
+ children: "Click here to view the detail of latest release"
13720
+ })
13721
+ ] }),
13722
+ duration: 60 * 1e3,
13723
+ closable: true
13724
+ });
13725
+ sessionStorage.setItem(storageKey, "true");
13726
+ }, 0);
13727
+ }
13728
+ }, [
13729
+ version,
13730
+ latestVersion,
13731
+ versionFormatRegex
13732
+ ]);
13733
+ if (!versionFormatRegex.test(version)) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Typography.default, {
13734
+ component: "span",
13735
+ sx: {
13736
+ fontSize: "sm",
13737
+ color: "rgba(255,255,255,0.8)",
13738
+ textTransform: "uppercase",
13739
+ borderWidth: 1,
13740
+ px: 1,
13741
+ borderRadius: .75
13742
+ },
13743
+ children: version
13744
+ });
13745
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Link.default, {
13746
+ href: `https://github.com/DataRecce/recce/releases/tag/v${version}`,
13747
+ sx: {
13748
+ "&:hover": { textDecoration: "none" },
13749
+ fontSize: "sm",
13750
+ color: "rgba(255,255,255,0.8)",
13751
+ textTransform: "uppercase",
13752
+ borderWidth: 1,
13753
+ px: 1,
13754
+ borderRadius: .75
13755
+ },
13756
+ target: "_blank",
13757
+ children: version
12507
13758
  });
12508
13759
  }
12509
13760
 
@@ -12556,6 +13807,12 @@ Object.defineProperty(exports, 'DiffEditor_default', {
12556
13807
  return DiffEditor_default;
12557
13808
  }
12558
13809
  });
13810
+ Object.defineProperty(exports, 'DisplayModeToggle', {
13811
+ enumerable: true,
13812
+ get: function () {
13813
+ return DisplayModeToggle;
13814
+ }
13815
+ });
12559
13816
  Object.defineProperty(exports, 'EnvInfo', {
12560
13817
  enumerable: true,
12561
13818
  get: function () {
@@ -12640,6 +13897,12 @@ Object.defineProperty(exports, 'MuiProvider', {
12640
13897
  return MuiProvider;
12641
13898
  }
12642
13899
  });
13900
+ Object.defineProperty(exports, 'NavBar', {
13901
+ enumerable: true,
13902
+ get: function () {
13903
+ return NavBar;
13904
+ }
13905
+ });
12643
13906
  Object.defineProperty(exports, 'NodeSqlView', {
12644
13907
  enumerable: true,
12645
13908
  get: function () {
@@ -12664,6 +13927,12 @@ Object.defineProperty(exports, 'QueryPage', {
12664
13927
  return QueryPage;
12665
13928
  }
12666
13929
  });
13930
+ Object.defineProperty(exports, 'RecceVersionBadge', {
13931
+ enumerable: true,
13932
+ get: function () {
13933
+ return RecceVersionBadge;
13934
+ }
13935
+ });
12667
13936
  Object.defineProperty(exports, 'ResourceTypeTag', {
12668
13937
  enumerable: true,
12669
13938
  get: function () {
@@ -12748,6 +14017,12 @@ Object.defineProperty(exports, 'SummaryView', {
12748
14017
  return SummaryView;
12749
14018
  }
12750
14019
  });
14020
+ Object.defineProperty(exports, 'TopBar', {
14021
+ enumerable: true,
14022
+ get: function () {
14023
+ return TopBar;
14024
+ }
14025
+ });
12751
14026
  Object.defineProperty(exports, 'VSplit', {
12752
14027
  enumerable: true,
12753
14028
  get: function () {
@@ -12760,4 +14035,4 @@ Object.defineProperty(exports, 'mui_provider_default', {
12760
14035
  return mui_provider_default;
12761
14036
  }
12762
14037
  });
12763
- //# sourceMappingURL=components-DeA4kqxK.js.map
14038
+ //# sourceMappingURL=components-DXbVq9Cw.js.map