@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
- import { $t as trackMultiNodesAction, At as submitQuery, Bt as waitRun, Cn as getCll, Ct as cacheKeys, F as useRecceActionContext, Gt as trackColumnLevelLineage, I as useAppLocation, In as colors, It as listRuns, J as mergeKeysWithStatus, Jt as trackExploreAction, K as useClipBoardToast, Kt as trackCopyToClipboard, Ln as darkTheme, M as useLineageViewContext, Mt as submitQueryDiff, N as useLineageViewContextSafe, Pn as toaster, Pt as cancelRun, Qt as trackLineageViewRender, Rn as lightTheme, Rt as submitRun, Sn as union, Tt as ScreenshotDataGrid, Ut as EXPLORE_SOURCE, V as IconInfo, Vt as EXPLORE_ACTION, W as deltaPercentageString, Wt as LINEAGE_SELECTION_ACTION, Xt as trackHistoryAction, Zt as trackLineageSelection, _ as findByRunType, _n as isLineageGraphNode, _t as useRecceInstanceContext, an as isHistogramDiffRun, at as useModelColumns_default, bn as selectUpstream, c as createCheckByRun, cn as isQueryDiffRun, ct as useRunsAggregated, d as getCheck, dn as isRowCountRun, dt as useIdleTimeout, en as trackPreviewChange, fn as isTopKDiffRun, gn as isLineageGraphColumnNode, h as updateCheck, hn as COLUMN_HEIGHT, ht as formatDuration, it as supportsHistogramDiff, j as LineageViewContext, jt as submitQueryBase, k as createDataGridFromData, kn as axiosClient, kt as createLineageDiffCheck, ln as isQueryRun, lt as useRecceServerFlag, mn as isValueDiffRun, nn as trackShareState, on as isProfileDiffRun, p as markAsPresetCheck, pn as isValueDiffDetailRun, q as mergeKeys, qt as trackEnvironmentConfig, rn as trackSingleEnvironment, sn as isQueryBaseRun, st as useLineageGraphContext, tn as trackPreviewChangeFeedback, u as deleteCheck, un as isRowCountDiffRun, v as runTypeHasRef, vn as layout, vt as useRecceInstanceInfo, wt as EmptyRowsRenderer, xn as toReactFlow, yn as selectDownstream, zn as token, zt as submitRunFromCheck } from "./state-BySLlIE7.mjs";
2
+ import { $t as trackMultiNodesAction, At as submitQuery, Bn as lightTheme, Bt as waitRun, Cn as toReactFlow, Ct as cacheKeys, F as useRecceActionContext, Gt as trackColumnLevelLineage, H as IconSave, I as useAppLocation, In as toaster, It as listRuns, J as mergeKeysWithStatus, Jt as trackExploreAction, K as useClipBoardToast, Kt as trackCopyToClipboard, M as useLineageViewContext, Mt as submitQueryDiff, N as useLineageViewContextSafe, Pt as cancelRun, Qt as trackLineageViewRender, R as IconEdit, Rn as colors, Rt as submitRun, Sn as selectUpstream, Tn as getCll, Tt as ScreenshotDataGrid, U as IconSync, Ut as EXPLORE_SOURCE, V as IconInfo, Vn as token, Vt as EXPLORE_ACTION, W as deltaPercentageString, Wt as LINEAGE_SELECTION_ACTION, Xt as trackHistoryAction, Zt as trackLineageSelection, _ as findByRunType, _n as COLUMN_HEIGHT, _t as useRecceInstanceContext, a as saveAs$1, an as trackStateAction, at as useModelColumns_default, bn as layout, c as createCheckByRun, cn as isProfileDiffRun, ct as useRunsAggregated, d as getCheck, dn as isQueryRun, dt as useIdleTimeout, en as trackNavigation, f as listChecks, fn as isRowCountDiffRun, g as useChecks, gn as isValueDiffRun, h as updateCheck, hn as isValueDiffDetailRun, ht as formatDuration, i as rename, in as trackSingleEnvironment, it as supportsHistogramDiff, j as LineageViewContext, jn as axiosClient, jt as submitQueryBase, k as createDataGridFromData, kt as createLineageDiffCheck, ln as isQueryBaseRun, lt as useRecceServerFlag, mn as isTopKDiffRun, nn as trackPreviewChangeFeedback, p as markAsPresetCheck, pn as isRowCountRun, q as mergeKeys, qt as trackEnvironmentConfig, r as isStateSyncing, rn as trackShareState, s as syncState, sn as isHistogramDiffRun, st as useLineageGraphContext, t as exportState, tn as trackPreviewChange, u as deleteCheck, un as isQueryDiffRun, v as runTypeHasRef, vn as isLineageGraphColumnNode, vt as useRecceInstanceInfo, wn as union, wt as EmptyRowsRenderer, xn as selectDownstream, yn as isLineageGraphNode, z as IconExport, zn as darkTheme, zt as submitRunFromCheck } from "./state-BbgVwFV2.mjs";
3
3
  import { t as RECCE_SUPPORT_CALENDAR_URL } from "./urls-D7PrPolY.mjs";
4
- import { a as sessionStorageKeys, i as localStorageKeys, n as fetchUser, o as select, r as connectToCloud, s as createSchemaDiffCheck, t as fetchGitHubAvatar } from "./user-BHOgMaBf.mjs";
5
- import { i as useValueDiffAlertDialog_default, l as defaultSqlQuery, n as useRecceCheckContext, o as useRecceShareStateContext, r as useCheckToast, u as useRecceQueryContext } from "./RecceCheckContext-BETsmiD5.mjs";
4
+ import { a as localStorageKeys, c as createSchemaDiffCheck, i as connectToCloud, n as fetchGitHubAvatar, o as sessionStorageKeys, r as fetchUser, s as select, t as useVersionNumber } from "./version-C2NU3xyx.mjs";
5
+ import { i as useValueDiffAlertDialog_default, l as defaultSqlQuery, n as useRecceCheckContext, o as useRecceShareStateContext, r as useCheckToast, u as useRecceQueryContext } from "./RecceCheckContext-DIQjrvH8.mjs";
6
6
  import { t as DisableTooltipMessages } from "./tooltipMessage-CrXjOmVM.mjs";
7
7
  import CssBaseline from "@mui/material/CssBaseline";
8
8
  import { ThemeProvider, alpha, useTheme } from "@mui/material/styles";
@@ -27,27 +27,30 @@ import { IconType } from "react-icons";
27
27
  import { LuExternalLink } from "react-icons/lu";
28
28
  import { TbChecklist, TbCloudUpload, TbPlus } from "react-icons/tb";
29
29
  import _, { isEmpty } from "lodash";
30
- import { PiBookmarkSimple, PiCaretDown, PiChatText, PiCheck, PiCheckCircle, PiCircle, PiCopy, PiInfo, PiInfoFill, PiNotePencil, PiPencilSimple, PiPlusCircle, PiRepeat, PiTrashFill, PiTrashSimple, PiWarning, PiX } from "react-icons/pi";
30
+ import { PiBookmarkSimple, PiCaretDown, PiChatText, PiCheck, PiCheckCircle, PiCircle, PiCopy, PiInfo, PiInfoFill, PiMoon, PiNotePencil, PiPencilSimple, PiPlusCircle, PiRepeat, PiSun, PiTrashFill, PiTrashSimple, PiWarning, PiX } from "react-icons/pi";
31
31
  import MuiDialog from "@mui/material/Dialog";
32
32
  import DialogActions from "@mui/material/DialogActions";
33
33
  import DialogContent from "@mui/material/DialogContent";
34
34
  import DialogTitle from "@mui/material/DialogTitle";
35
35
  import IconButton from "@mui/material/IconButton";
36
36
  import { IoBookmarksOutline, IoClose, IoWarning } from "react-icons/io5";
37
+ import NextLink from "next/link";
37
38
  import Checkbox from "@mui/material/Checkbox";
38
39
  import FormControlLabel from "@mui/material/FormControlLabel";
39
40
  import TextField from "@mui/material/TextField";
40
41
  import Menu from "@mui/material/Menu";
41
42
  import MenuItem from "@mui/material/MenuItem";
42
- import { VscCircleLarge, VscDiffAdded, VscDiffModified, VscDiffRemoved, VscFeedback, VscHistory, VscKebabVertical } from "react-icons/vsc";
43
+ import { VscCircleLarge, VscDiffAdded, VscDiffModified, VscDiffRemoved, VscFeedback, VscGitPullRequest, VscHistory, VscKebabVertical } from "react-icons/vsc";
43
44
  import MuiTooltip from "@mui/material/Tooltip";
45
+ import { useCopyToClipboard, useInterval } from "usehooks-ts";
44
46
  import ListSubheader from "@mui/material/ListSubheader";
47
+ import { usePathname } from "next/navigation";
45
48
  import Link from "@mui/material/Link";
46
49
  import MuiPopover from "@mui/material/Popover";
47
50
  import { format, formatDistance, formatDistanceToNow, parseISO } from "date-fns";
48
51
  import saveAs from "file-saver";
49
52
  import { toCanvas } from "html-to-image";
50
- import { FaCamera, FaCheckCircle, FaCheckSquare, FaCube, FaDatabase, FaExpandArrowsAlt, FaRegCheckCircle, FaRegDotCircle, FaRegSquare, FaSeedling } from "react-icons/fa";
53
+ import { FaCamera, FaCheckCircle, FaCheckSquare, FaCloud, FaCube, FaDatabase, FaExpandArrowsAlt, FaGithub, FaQuestionCircle, FaRegCheckCircle, FaRegDotCircle, FaRegSquare, FaSeedling, FaSlack, FaUser } from "react-icons/fa";
51
54
  import { FaBookmark, FaChartSimple, FaCircleNodes, FaGauge, FaPlay } from "react-icons/fa6";
52
55
  import Chip from "@mui/material/Chip";
53
56
  import Skeleton from "@mui/material/Skeleton";
@@ -94,6 +97,8 @@ import Card from "@mui/material/Card";
94
97
  import CardContent from "@mui/material/CardContent";
95
98
  import CardHeader from "@mui/material/CardHeader";
96
99
  import Badge from "@mui/material/Badge";
100
+ import DisplayModeToggle from "app/(mainComponents)/DisplayModeToggle";
101
+ import RecceVersionBadge from "app/(mainComponents)/RecceVersionBadge";
97
102
 
98
103
  //#region recce-source/js/src/components/ui/mui-provider.tsx
99
104
  /**
@@ -223,7 +228,7 @@ const getHTMLElementFromRef = (refCurrent) => {
223
228
  };
224
229
  const IGNORE_SCREENSHOT_CLASS = "ignore-screenshot";
225
230
  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";
226
- function useCopyToClipboard({ renderLibrary = "html2canvas", imageType = "png", backgroundColor = null, boardEffect = true, shadowEffect = false, borderStyle = `solid 1px ${colors.neutral[300]}`, borderRadius = "10px", onSuccess, onError, ignoreElements }) {
231
+ function useCopyToClipboard$1({ renderLibrary = "html2canvas", imageType = "png", backgroundColor = null, boardEffect = true, shadowEffect = false, borderStyle = `solid 1px ${colors.neutral[300]}`, borderRadius = "10px", onSuccess, onError, ignoreElements }) {
227
232
  const [status, setStatus] = useState("idle");
228
233
  const ref = useRef(null);
229
234
  const { onOpen, setImgBlob, ImageDownloadModal } = useImageDownloadModal();
@@ -324,7 +329,7 @@ function useCopyToClipboard({ renderLibrary = "html2canvas", imageType = "png",
324
329
  }
325
330
  function useCopyToClipboardButton(options) {
326
331
  const { successToast, failToast } = useClipBoardToast();
327
- const { isLoading, copyToClipboard, ImageDownloadModal, ref } = useCopyToClipboard({
332
+ const { isLoading, copyToClipboard, ImageDownloadModal, ref } = useCopyToClipboard$1({
328
333
  imageType: "png",
329
334
  shadowEffect: true,
330
335
  backgroundColor: options?.backgroundColor ?? colors.neutral[100],
@@ -6398,7 +6403,7 @@ function PrivateLineageView({ interactive = false, ...props }, ref) {
6398
6403
  const reactFlow = useReactFlow();
6399
6404
  const refResize = useRef(null);
6400
6405
  const { successToast, failToast } = useClipBoardToast();
6401
- const { copyToClipboard, ImageDownloadModal, ref: refReactFlow } = useCopyToClipboard({
6406
+ const { copyToClipboard, ImageDownloadModal, ref: refReactFlow } = useCopyToClipboard$1({
6402
6407
  renderLibrary: "html-to-image",
6403
6408
  imageType: "png",
6404
6409
  shadowEffect: true,
@@ -10397,6 +10402,124 @@ function SummaryView() {
10397
10402
  }) });
10398
10403
  }
10399
10404
 
10405
+ //#endregion
10406
+ //#region recce-source/js/src/components/app/AvatarDropdown.tsx
10407
+ function AvatarDropdown() {
10408
+ const { data: user, isLoading, error } = useQuery({
10409
+ queryKey: cacheKeys.user(),
10410
+ queryFn: fetchUser,
10411
+ retry: false
10412
+ });
10413
+ const { data: avatarUrl } = useQuery({
10414
+ queryKey: ["github-avatar", user?.id],
10415
+ queryFn: () => user ? fetchGitHubAvatar(user.id) : Promise.resolve(null),
10416
+ enabled: !!user?.id && user.login_type === "github",
10417
+ retry: false,
10418
+ staleTime: 300 * 1e3
10419
+ });
10420
+ const [anchorEl, setAnchorEl] = useState(null);
10421
+ const open = Boolean(anchorEl);
10422
+ const handleClick = (event) => {
10423
+ setAnchorEl(event.currentTarget);
10424
+ };
10425
+ const handleClose = () => {
10426
+ setAnchorEl(null);
10427
+ };
10428
+ const showUserInfo = !isLoading && !error && user;
10429
+ const getInitials = (name) => {
10430
+ if (!name) return "U";
10431
+ return name.charAt(0).toUpperCase();
10432
+ };
10433
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [isLoading ? /* @__PURE__ */ jsx(Box, {
10434
+ onClick: handleClick,
10435
+ sx: {
10436
+ width: 32,
10437
+ height: 32,
10438
+ borderRadius: "50%",
10439
+ bgcolor: "background.paper",
10440
+ color: "primary.main",
10441
+ display: "flex",
10442
+ alignItems: "center",
10443
+ justifyContent: "center",
10444
+ cursor: "pointer"
10445
+ },
10446
+ children: /* @__PURE__ */ jsx(CircularProgress, { size: 16 })
10447
+ }) : /* @__PURE__ */ jsx(MuiAvatar, {
10448
+ onClick: handleClick,
10449
+ src: avatarUrl || void 0,
10450
+ sx: {
10451
+ width: 28,
10452
+ height: 28,
10453
+ cursor: "pointer",
10454
+ outline: "1px solid white",
10455
+ fontSize: "0.875rem"
10456
+ },
10457
+ children: getInitials(user?.login)
10458
+ }), /* @__PURE__ */ jsxs(Menu, {
10459
+ anchorEl,
10460
+ open,
10461
+ onClose: handleClose,
10462
+ slotProps: { paper: { sx: {
10463
+ bgcolor: "background.paper",
10464
+ borderColor: "divider",
10465
+ boxShadow: 3,
10466
+ minWidth: 180
10467
+ } } },
10468
+ children: [
10469
+ /* @__PURE__ */ jsxs(Box, {
10470
+ sx: {
10471
+ px: 2,
10472
+ py: 1.5
10473
+ },
10474
+ children: [
10475
+ isLoading && /* @__PURE__ */ jsxs(Box, {
10476
+ sx: {
10477
+ display: "flex",
10478
+ alignItems: "center",
10479
+ gap: 1
10480
+ },
10481
+ children: [/* @__PURE__ */ jsx(Typography, {
10482
+ variant: "body2",
10483
+ color: "text.primary",
10484
+ children: "Loading..."
10485
+ }), /* @__PURE__ */ jsx(CircularProgress, { size: 16 })]
10486
+ }),
10487
+ error && /* @__PURE__ */ jsx(Typography, {
10488
+ variant: "caption",
10489
+ color: "error",
10490
+ children: "Failed to load user information"
10491
+ }),
10492
+ showUserInfo && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Typography, {
10493
+ variant: "body2",
10494
+ fontWeight: "600",
10495
+ color: "text.primary",
10496
+ children: user.login
10497
+ }), user.email && /* @__PURE__ */ jsx(Typography, {
10498
+ variant: "caption",
10499
+ color: "text.secondary",
10500
+ children: user.email
10501
+ })] })
10502
+ ]
10503
+ }),
10504
+ /* @__PURE__ */ jsx(Divider, {}),
10505
+ /* @__PURE__ */ jsxs(MenuItem, {
10506
+ onClick: () => {
10507
+ window.open("https://cloud.datarecce.io/", "_blank");
10508
+ handleClose();
10509
+ },
10510
+ children: [/* @__PURE__ */ jsx(ListItemIcon, { children: /* @__PURE__ */ jsx(FaCloud, {}) }), /* @__PURE__ */ jsx(ListItemText, { children: "Recce Cloud" })]
10511
+ }),
10512
+ /* @__PURE__ */ jsxs(MenuItem, {
10513
+ onClick: () => {
10514
+ window.open(RECCE_SUPPORT_CALENDAR_URL, "_blank");
10515
+ handleClose();
10516
+ },
10517
+ children: [/* @__PURE__ */ jsx(ListItemIcon, { children: /* @__PURE__ */ jsx(FaUser, {}) }), /* @__PURE__ */ jsx(ListItemText, { children: "Get live support" })]
10518
+ })
10519
+ ]
10520
+ })] });
10521
+ }
10522
+
10400
10523
  //#endregion
10401
10524
  //#region recce-source/js/src/components/timeout/IdleTimeoutBadge.tsx
10402
10525
  /**
@@ -10434,5 +10557,1130 @@ function IdleTimeoutBadge() {
10434
10557
  }
10435
10558
 
10436
10559
  //#endregion
10437
- export { LineageViewTopBar as A, ErrorBoundary$1 as B, SqlEditor_default as C, DiffEditor_default as D, NodeSqlView as E, RowCountDiffTag as F, mui_provider_default as H, GraphEdge as I, GraphColumnNode as L, GraphNode as M, ModelRowCount as N, CodeEditor_default as O, ResourceTypeTag as P, HSplit as R, RunStatusAndDate as S, EnvInfo as T, MuiProvider as V, LineageView as _, RunList as a, RunResultPane as b, CheckDetail as c, CheckDescription as d, CheckBreadcrumb as f, LineagePage as g, SetupConnectionGuide as h, ChangeSummary as i, HistoryToggle as j, SchemaView as k, SchemaDiffView as l, QueryPage as m, SummaryView as n, RunPage as o, CheckList as p, SchemaSummary as r, CheckEmptyState as s, IdleTimeoutBadge as t, LineageDiffView as u, SetupConnectionBanner as v, QueryForm as w, RunView as x, NodeView as y, VSplit as z };
10438
- //# sourceMappingURL=components-C735_oqD.mjs.map
10560
+ //#region recce-source/js/app/(mainComponents)/TopBar.tsx
10561
+ function LinkIcon({ icon: IconComponent, href, sx, ...props }) {
10562
+ const theme = useTheme();
10563
+ return /* @__PURE__ */ jsx(Link, {
10564
+ sx: {
10565
+ height: "20px",
10566
+ color: "common.white",
10567
+ ...sx
10568
+ },
10569
+ href,
10570
+ target: "_blank",
10571
+ ...props,
10572
+ children: /* @__PURE__ */ jsx(IconComponent, { style: {
10573
+ color: theme.palette.common.white,
10574
+ width: 20,
10575
+ height: 20
10576
+ } })
10577
+ });
10578
+ }
10579
+ function TopBar() {
10580
+ const { reviewMode, isDemoSite, envInfo, cloudMode } = useLineageGraphContext();
10581
+ const { featureToggles, authed } = useRecceInstanceContext();
10582
+ const { url: prURL, id: prID } = envInfo?.pullRequest ?? {};
10583
+ const demoPrId = prURL ? prURL.split("/").pop() : null;
10584
+ const brandLink = cloudMode || authed ? "https://cloud.datarecce.io/" : "https://reccehq.com/";
10585
+ const [showModal, setShowModal] = useState(false);
10586
+ return /* @__PURE__ */ jsxs(Box, {
10587
+ sx: {
10588
+ display: "flex",
10589
+ gap: "10px",
10590
+ minHeight: "40px",
10591
+ alignItems: "center",
10592
+ bgcolor: colors.brand[400]
10593
+ },
10594
+ children: [
10595
+ /* @__PURE__ */ jsx(Link, {
10596
+ href: brandLink,
10597
+ target: "_blank",
10598
+ sx: { "&:hover": { textDecoration: "none" } },
10599
+ children: /* @__PURE__ */ jsxs(Box, {
10600
+ sx: {
10601
+ display: "flex",
10602
+ gap: "10px",
10603
+ alignItems: "center"
10604
+ },
10605
+ children: [/* @__PURE__ */ jsx(Box, {
10606
+ component: "img",
10607
+ sx: {
10608
+ width: 20,
10609
+ height: 20,
10610
+ ml: "18px"
10611
+ },
10612
+ src: "/logo/recce-logo-white.png",
10613
+ alt: "recce-logo-white"
10614
+ }), /* @__PURE__ */ jsx(Typography, {
10615
+ variant: "h4",
10616
+ sx: {
10617
+ fontFamily: "\"Montserrat\", sans-serif",
10618
+ color: "common.white",
10619
+ fontSize: "1.25rem"
10620
+ },
10621
+ children: "RECCE"
10622
+ })]
10623
+ })
10624
+ }),
10625
+ /* @__PURE__ */ jsx(DisplayModeToggle, {}),
10626
+ /* @__PURE__ */ jsx(RecceVersionBadge, {}),
10627
+ (featureToggles.mode ?? reviewMode) && /* @__PURE__ */ jsx(Badge, {
10628
+ sx: {
10629
+ fontSize: "0.875rem",
10630
+ color: "rgba(255,255,255,0.8)",
10631
+ textTransform: "uppercase",
10632
+ borderWidth: 1,
10633
+ px: 1,
10634
+ borderRadius: .75,
10635
+ borderColor: "rgba(255,255,255,0.8)"
10636
+ },
10637
+ children: featureToggles.mode ?? "review mode"
10638
+ }),
10639
+ cloudMode && prID && /* @__PURE__ */ jsx(Badge, {
10640
+ sx: {
10641
+ fontSize: "0.875rem",
10642
+ color: "rgba(255,255,255,0.8)",
10643
+ textTransform: "uppercase",
10644
+ borderWidth: 1,
10645
+ px: 1,
10646
+ borderRadius: .75,
10647
+ borderColor: "rgba(255,255,255,0.8)"
10648
+ },
10649
+ children: /* @__PURE__ */ jsxs(Stack, {
10650
+ direction: "row",
10651
+ spacing: 1,
10652
+ alignItems: "center",
10653
+ children: [/* @__PURE__ */ jsx(Box, { children: "cloud mode" }), /* @__PURE__ */ jsx(Box, {
10654
+ sx: {
10655
+ borderLeft: "1px solid rgba(255,255,255,0.8)",
10656
+ pl: "8px"
10657
+ },
10658
+ children: /* @__PURE__ */ jsxs(Link, {
10659
+ href: prURL,
10660
+ sx: { "&:hover": { textDecoration: "none" } },
10661
+ target: "_blank",
10662
+ children: [/* @__PURE__ */ jsx(VscGitPullRequest, { style: {
10663
+ color: "rgba(255,255,255,0.8)",
10664
+ width: 12,
10665
+ height: 12,
10666
+ marginRight: 2,
10667
+ display: "inline",
10668
+ verticalAlign: "middle"
10669
+ } }), /* @__PURE__ */ jsx(Typography, {
10670
+ component: "span",
10671
+ sx: {
10672
+ color: "rgba(255,255,255,0.8)",
10673
+ display: "inline"
10674
+ },
10675
+ children: `#${String(prID)}`
10676
+ })]
10677
+ })
10678
+ })]
10679
+ })
10680
+ }),
10681
+ isDemoSite && prURL && demoPrId && /* @__PURE__ */ jsx(Badge, {
10682
+ sx: {
10683
+ fontSize: "0.875rem",
10684
+ color: "rgba(255,255,255,0.8)",
10685
+ textTransform: "uppercase",
10686
+ borderWidth: 1,
10687
+ px: 1,
10688
+ borderRadius: .75,
10689
+ borderColor: "rgba(255,255,255,0.8)"
10690
+ },
10691
+ children: /* @__PURE__ */ jsxs(Stack, {
10692
+ direction: "row",
10693
+ spacing: 1,
10694
+ alignItems: "center",
10695
+ children: [/* @__PURE__ */ jsx(Box, { children: "demo mode" }), /* @__PURE__ */ jsx(Box, {
10696
+ sx: {
10697
+ borderLeft: "1px solid rgba(255,255,255,0.8)",
10698
+ pl: "8px"
10699
+ },
10700
+ children: /* @__PURE__ */ jsxs(Link, {
10701
+ href: prURL,
10702
+ sx: { "&:hover": { textDecoration: "none" } },
10703
+ target: "_blank",
10704
+ children: [/* @__PURE__ */ jsx(VscGitPullRequest, { style: {
10705
+ color: "rgba(255,255,255,0.8)",
10706
+ width: 12,
10707
+ height: 12,
10708
+ marginRight: 2,
10709
+ display: "inline",
10710
+ verticalAlign: "middle"
10711
+ } }), /* @__PURE__ */ jsx(Typography, {
10712
+ component: "span",
10713
+ sx: {
10714
+ color: "rgba(255,255,255,0.8)",
10715
+ display: "inline"
10716
+ },
10717
+ children: `#${demoPrId}`
10718
+ })]
10719
+ })
10720
+ })]
10721
+ })
10722
+ }),
10723
+ /* @__PURE__ */ jsx(Box, { sx: { flex: 1 } }),
10724
+ (isDemoSite || featureToggles.mode === "read only") && /* @__PURE__ */ jsxs(Fragment$1, { children: [
10725
+ /* @__PURE__ */ jsx(LinkIcon, {
10726
+ icon: FaGithub,
10727
+ href: "https://github.com/DataRecce/recce"
10728
+ }),
10729
+ /* @__PURE__ */ jsx(LinkIcon, {
10730
+ icon: FaSlack,
10731
+ href: "https://getdbt.slack.com/archives/C05C28V7CPP"
10732
+ }),
10733
+ /* @__PURE__ */ jsx(LinkIcon, {
10734
+ sx: { mr: 2 },
10735
+ icon: FaQuestionCircle,
10736
+ href: "https://docs.datarecce.io"
10737
+ })
10738
+ ] }),
10739
+ !isDemoSite && featureToggles.mode !== "read only" && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(IdleTimeoutBadge, {}), authed || cloudMode ? /* @__PURE__ */ jsx(Box, {
10740
+ sx: { mr: 2 },
10741
+ children: /* @__PURE__ */ jsx(AvatarDropdown, {})
10742
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Box, {
10743
+ component: "button",
10744
+ sx: {
10745
+ color: "common.white",
10746
+ fontSize: "0.875rem",
10747
+ fontWeight: 600,
10748
+ bgcolor: "brand.700",
10749
+ borderRadius: 1,
10750
+ px: 3,
10751
+ py: 1,
10752
+ mr: 2,
10753
+ cursor: "pointer",
10754
+ border: "none"
10755
+ },
10756
+ onClick: () => {
10757
+ setShowModal(true);
10758
+ },
10759
+ children: "Connect to Cloud"
10760
+ }), showModal && /* @__PURE__ */ jsx(AuthModal, {
10761
+ parentOpen: showModal,
10762
+ handleParentClose: setShowModal,
10763
+ ignoreCookie: true,
10764
+ variant: "user-profile"
10765
+ })] })] })
10766
+ ]
10767
+ });
10768
+ }
10769
+
10770
+ //#endregion
10771
+ //#region recce-source/js/src/components/app/Filename.tsx
10772
+ const useRecceToast = () => {
10773
+ const toastSuccess = (message) => {
10774
+ toaster.create({
10775
+ description: message,
10776
+ type: "success",
10777
+ duration: 5e3,
10778
+ closable: true
10779
+ });
10780
+ };
10781
+ const toastError = (message, error) => {
10782
+ let errorMessage = message;
10783
+ if (error != null) if (error instanceof AxiosError) errorMessage = `${message}. ${String(error.response?.data?.detail)}`;
10784
+ else errorMessage = `${message}. ${error}`;
10785
+ toaster.create({
10786
+ description: errorMessage,
10787
+ type: "error",
10788
+ duration: 5e3,
10789
+ closable: true
10790
+ });
10791
+ };
10792
+ return {
10793
+ toastSuccess,
10794
+ toastError
10795
+ };
10796
+ };
10797
+ const useClosePrompt = (prompt) => {
10798
+ useEffect(() => {
10799
+ const handleBeforeUnload = (e) => {
10800
+ e.preventDefault();
10801
+ };
10802
+ if (prompt) window.addEventListener("beforeunload", handleBeforeUnload);
10803
+ return () => {
10804
+ if (prompt) window.removeEventListener("beforeunload", handleBeforeUnload);
10805
+ };
10806
+ }, [prompt]);
10807
+ };
10808
+ const Filename = () => {
10809
+ const { featureToggles } = useRecceInstanceContext();
10810
+ const { fileName, cloudMode, isDemoSite, envInfo } = useLineageGraphContext();
10811
+ const [modalOpen, setModalOpen] = useState(false);
10812
+ const [overwriteOpen, setOverwriteOpen] = useState(false);
10813
+ const isStateless = !fileName && !cloudMode && !isDemoSite;
10814
+ const { data: checks } = useChecks(isStateless);
10815
+ const hasNonPresetChecks = checks != void 0 && checks.filter((check) => !check.is_preset).length > 0;
10816
+ useClosePrompt(isStateless && hasNonPresetChecks);
10817
+ const [{ newFileName, errorMessage, modified, overwriteWithMethod, bypass }, setState] = useState({ newFileName: fileName ?? "recce_state.json" });
10818
+ const inputRef = useRef(null);
10819
+ const { toastSuccess, toastError } = useRecceToast();
10820
+ const queryClient = useQueryClient();
10821
+ const handleOpen = () => {
10822
+ setState({
10823
+ newFileName: fileName ?? "recce_state.json",
10824
+ modified: !fileName
10825
+ });
10826
+ setModalOpen(true);
10827
+ };
10828
+ const handleModalClose = () => setModalOpen(false);
10829
+ const handleOverwriteClose = () => setOverwriteOpen(false);
10830
+ const handleAction = async (method, overwrite) => {
10831
+ if (!newFileName) return;
10832
+ const bypassOverwrite = localStorage.getItem(localStorageKeys.bypassSaveOverwrite) === "true";
10833
+ try {
10834
+ if (method === "save") await saveAs$1({
10835
+ filename: newFileName,
10836
+ overwrite: overwrite ?? bypassOverwrite
10837
+ });
10838
+ else await rename({
10839
+ filename: newFileName,
10840
+ overwrite: overwrite ?? bypassOverwrite
10841
+ });
10842
+ toastSuccess(method === "save" ? "Save file successfully" : "Rename file successfully");
10843
+ await queryClient.invalidateQueries({ queryKey: cacheKeys.lineage() });
10844
+ if (bypass) localStorage.setItem(localStorageKeys.bypassSaveOverwrite, "true");
10845
+ } catch (error) {
10846
+ if (error instanceof AxiosError) {
10847
+ if (error.response?.status === 409) {
10848
+ setState((s) => ({
10849
+ ...s,
10850
+ overwriteWithMethod: method
10851
+ }));
10852
+ setOverwriteOpen(true);
10853
+ return;
10854
+ }
10855
+ }
10856
+ toastError(method === "save" ? "Save file failed" : "Rename file failed", error);
10857
+ } finally {
10858
+ handleModalClose();
10859
+ }
10860
+ };
10861
+ const handleOvewriteBack = () => {
10862
+ handleOverwriteClose();
10863
+ setModalOpen(true);
10864
+ setState((s) => {
10865
+ return {
10866
+ ...s,
10867
+ overwriteWithMethod: void 0
10868
+ };
10869
+ });
10870
+ };
10871
+ if (cloudMode || isDemoSite) return /* @__PURE__ */ jsx(Fragment$1, {});
10872
+ const titleNewInstance = "New Instance" + (hasNonPresetChecks ? " (unsaved)" : "");
10873
+ let titleReadOnlyState;
10874
+ if (featureToggles.disableSaveToFile && fileName) {
10875
+ const generatedAt = envInfo?.stateMetadata?.generated_at;
10876
+ const formattedDate = generatedAt ? formatRunDateTime(new Date(generatedAt)) : null;
10877
+ titleReadOnlyState = formattedDate ? `${fileName} (${formattedDate})` : null;
10878
+ }
10879
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
10880
+ /* @__PURE__ */ jsxs(Stack, {
10881
+ direction: "row",
10882
+ alignItems: "center",
10883
+ justifyContent: "center",
10884
+ children: [/* @__PURE__ */ jsx(Box, {
10885
+ sx: { fontWeight: 600 },
10886
+ children: titleReadOnlyState ?? fileName ?? titleNewInstance
10887
+ }), !featureToggles.disableSaveToFile && /* @__PURE__ */ jsx(MuiTooltip, {
10888
+ title: fileName ? "Change Filename" : "Save",
10889
+ enterDelay: 1e3,
10890
+ children: /* @__PURE__ */ jsx(IconButton, {
10891
+ onClick: handleOpen,
10892
+ "aria-label": fileName ? "Change Filename" : "Save",
10893
+ size: "small",
10894
+ children: /* @__PURE__ */ jsx(Box, {
10895
+ component: fileName ? IconEdit : IconSave,
10896
+ sx: {
10897
+ fontSize: 16,
10898
+ verticalAlign: "middle"
10899
+ }
10900
+ })
10901
+ })
10902
+ })]
10903
+ }),
10904
+ /* @__PURE__ */ jsxs(MuiDialog, {
10905
+ open: modalOpen,
10906
+ onClose: handleModalClose,
10907
+ children: [
10908
+ /* @__PURE__ */ jsxs(DialogTitle, {
10909
+ sx: {
10910
+ display: "flex",
10911
+ alignItems: "center"
10912
+ },
10913
+ children: [
10914
+ fileName ? "Change Filename" : "Save File",
10915
+ /* @__PURE__ */ jsx(Box, { sx: { flexGrow: 1 } }),
10916
+ /* @__PURE__ */ jsx(IconButton, {
10917
+ size: "small",
10918
+ onClick: handleModalClose,
10919
+ children: /* @__PURE__ */ jsx(IoClose, {})
10920
+ })
10921
+ ]
10922
+ }),
10923
+ /* @__PURE__ */ jsx(DialogContent, {
10924
+ onKeyDown: (e) => {
10925
+ e.stopPropagation();
10926
+ },
10927
+ children: /* @__PURE__ */ jsx(TextField, {
10928
+ inputRef,
10929
+ value: newFileName,
10930
+ label: "File name",
10931
+ placeholder: "Enter filename",
10932
+ error: !!errorMessage,
10933
+ helperText: errorMessage,
10934
+ fullWidth: true,
10935
+ size: "small",
10936
+ sx: { mt: 1 },
10937
+ onChange: (e) => {
10938
+ const value = e.target.value;
10939
+ let newErrorMessage = void 0;
10940
+ if (!value) newErrorMessage = "Filename cannot be empty.";
10941
+ else if (!value.endsWith(".json")) newErrorMessage = "Filename must end with .json.";
10942
+ else if (!/^[a-zA-Z0-9 _-]+\.json$/.test(value)) newErrorMessage = "Invalid filename. Only alphanumeric, space, _ and - are allowed.";
10943
+ else if (fileName && value === fileName) newErrorMessage = "Filename is the same as the current one.";
10944
+ setState((s) => {
10945
+ return {
10946
+ ...s,
10947
+ modified: true,
10948
+ newFileName: value,
10949
+ errorMessage: newErrorMessage
10950
+ };
10951
+ });
10952
+ },
10953
+ onKeyDown: (e) => {
10954
+ if (e.key === "Enter") {
10955
+ if (errorMessage) return;
10956
+ if (!fileName) handleAction("save");
10957
+ else handleAction("rename");
10958
+ } else if (e.key === "Escape") handleModalClose();
10959
+ }
10960
+ })
10961
+ }),
10962
+ /* @__PURE__ */ jsxs(DialogActions, {
10963
+ sx: { gap: "5px" },
10964
+ children: [/* @__PURE__ */ jsx(Button, {
10965
+ size: "small",
10966
+ color: fileName ? "inherit" : "iochmara",
10967
+ variant: "contained",
10968
+ onClick: async () => {
10969
+ await handleAction("save");
10970
+ },
10971
+ disabled: !newFileName || !!errorMessage || !modified,
10972
+ children: fileName ? "Save as New File" : "Confirm"
10973
+ }), fileName && /* @__PURE__ */ jsx(Button, {
10974
+ size: "small",
10975
+ color: "iochmara",
10976
+ variant: "contained",
10977
+ onClick: async () => {
10978
+ await handleAction("rename");
10979
+ },
10980
+ disabled: !newFileName || !!errorMessage || !modified,
10981
+ children: "Rename"
10982
+ })]
10983
+ })
10984
+ ]
10985
+ }),
10986
+ /* @__PURE__ */ jsxs(MuiDialog, {
10987
+ open: overwriteOpen,
10988
+ onClose: handleOverwriteClose,
10989
+ children: [
10990
+ /* @__PURE__ */ jsxs(DialogTitle, {
10991
+ sx: {
10992
+ display: "flex",
10993
+ alignItems: "center"
10994
+ },
10995
+ children: [
10996
+ "Overwrite File?",
10997
+ /* @__PURE__ */ jsx(Box, { sx: { flexGrow: 1 } }),
10998
+ /* @__PURE__ */ jsx(IconButton, {
10999
+ size: "small",
11000
+ onClick: handleOverwriteClose,
11001
+ children: /* @__PURE__ */ jsx(IoClose, {})
11002
+ })
11003
+ ]
11004
+ }),
11005
+ /* @__PURE__ */ jsxs(DialogContent, {
11006
+ sx: {
11007
+ borderTop: "solid 1px",
11008
+ borderBottom: "solid 1px",
11009
+ borderColor: "divider"
11010
+ },
11011
+ onKeyDown: (e) => {
11012
+ e.stopPropagation();
11013
+ },
11014
+ children: [/* @__PURE__ */ jsx(Typography, {
11015
+ sx: { fontSize: "12pt" },
11016
+ 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?"
11017
+ }), /* @__PURE__ */ jsx(FormControlLabel, {
11018
+ control: /* @__PURE__ */ jsx(Checkbox, {
11019
+ size: "small",
11020
+ checked: bypass,
11021
+ onChange: (e) => {
11022
+ setState((s) => ({
11023
+ ...s,
11024
+ bypass: e.target.checked
11025
+ }));
11026
+ }
11027
+ }),
11028
+ label: /* @__PURE__ */ jsx(Typography, {
11029
+ sx: {
11030
+ fontWeight: "bold",
11031
+ pt: "8px"
11032
+ },
11033
+ children: "Don't show this again"
11034
+ })
11035
+ })]
11036
+ }),
11037
+ /* @__PURE__ */ jsxs(DialogActions, {
11038
+ sx: { gap: "5px" },
11039
+ children: [/* @__PURE__ */ jsx(Button, {
11040
+ variant: "outlined",
11041
+ onClick: handleOvewriteBack,
11042
+ size: "small",
11043
+ children: "Back"
11044
+ }), /* @__PURE__ */ jsx(Button, {
11045
+ size: "small",
11046
+ color: "iochmara",
11047
+ variant: "contained",
11048
+ onClick: () => {
11049
+ if (!overwriteWithMethod) return;
11050
+ handleAction(overwriteWithMethod, true);
11051
+ handleOverwriteClose();
11052
+ },
11053
+ children: "Overwrite"
11054
+ })]
11055
+ })
11056
+ ]
11057
+ })
11058
+ ] });
11059
+ };
11060
+
11061
+ //#endregion
11062
+ //#region recce-source/js/src/components/app/StateExporter.tsx
11063
+ function StateExporter() {
11064
+ const { featureToggles } = useRecceInstanceContext();
11065
+ const handleExport = async () => {
11066
+ try {
11067
+ const jsonData = await exportState();
11068
+ const jsonString = JSON.stringify(jsonData, null, 2);
11069
+ saveAs(new Blob([jsonString], { type: "application/json" }), `recce-state-${format(/* @__PURE__ */ new Date(), "yyyy-MM-dd-HH-mm-ss")}.json`);
11070
+ } catch (error) {
11071
+ console.error("Export failed", error);
11072
+ toaster.create({
11073
+ title: "Export failed",
11074
+ description: String(error),
11075
+ type: "error",
11076
+ duration: 5e3,
11077
+ closable: true
11078
+ });
11079
+ }
11080
+ };
11081
+ return /* @__PURE__ */ jsx(MuiTooltip, {
11082
+ title: "Export",
11083
+ children: /* @__PURE__ */ jsx(IconButton, {
11084
+ size: "small",
11085
+ "aria-label": "Export state",
11086
+ onClick: async () => {
11087
+ await handleExport();
11088
+ trackStateAction({ name: "export" });
11089
+ },
11090
+ disabled: featureToggles.disableExportStateFile,
11091
+ children: /* @__PURE__ */ jsx(Box, {
11092
+ component: IconExport,
11093
+ sx: {
11094
+ verticalAlign: "middle",
11095
+ width: "16px",
11096
+ height: "16px"
11097
+ }
11098
+ })
11099
+ })
11100
+ });
11101
+ }
11102
+
11103
+ //#endregion
11104
+ //#region recce-source/js/src/components/app/StateSharing.tsx
11105
+ const LOADING_MESSAGES = [
11106
+ "Processing...",
11107
+ "Still processing, please wait...",
11108
+ "Almost there, thanks for your patience..."
11109
+ ];
11110
+ function TopLevelShare() {
11111
+ const { successToast, failToast } = useClipBoardToast();
11112
+ const [, copyToClipboard] = useCopyToClipboard();
11113
+ const { authed } = useRecceInstanceContext();
11114
+ const { shareUrl, isLoading, error, handleShareClick } = useRecceShareStateContext();
11115
+ const [showModal, setShowModal] = useState(false);
11116
+ const [messageIndex, setMessageIndex] = useState(0);
11117
+ const [prevIsLoading, setPrevIsLoading] = useState(isLoading);
11118
+ if (isLoading !== prevIsLoading) {
11119
+ setPrevIsLoading(isLoading);
11120
+ if (isLoading) setMessageIndex(0);
11121
+ }
11122
+ useInterval(() => {
11123
+ setMessageIndex((prev) => Math.min(prev + 1, LOADING_MESSAGES.length - 1));
11124
+ }, isLoading ? 3e4 : null);
11125
+ useEffect(() => {
11126
+ if (error) failToast("Failed to share state", error);
11127
+ }, [error, failToast]);
11128
+ const handleCopy = async () => {
11129
+ try {
11130
+ await copyToClipboard(String(shareUrl));
11131
+ successToast("Copied the link to clipboard");
11132
+ } catch (error$1) {
11133
+ failToast("Failed to copy the link", error$1);
11134
+ }
11135
+ };
11136
+ if (!authed) return /* @__PURE__ */ jsxs(Stack, {
11137
+ direction: "row",
11138
+ sx: {
11139
+ flex: 1,
11140
+ alignItems: "center"
11141
+ },
11142
+ children: [/* @__PURE__ */ jsx(Button, {
11143
+ size: "xsmall",
11144
+ color: "neutral",
11145
+ variant: "outlined",
11146
+ onClick: () => {
11147
+ setShowModal(true);
11148
+ },
11149
+ startIcon: /* @__PURE__ */ jsx(TbCloudUpload, {}),
11150
+ children: "Share"
11151
+ }), showModal && /* @__PURE__ */ jsx(AuthModal, {
11152
+ parentOpen: showModal,
11153
+ handleParentClose: setShowModal,
11154
+ ignoreCookie: true,
11155
+ variant: "enable-share"
11156
+ })]
11157
+ });
11158
+ return /* @__PURE__ */ jsxs(Stack, {
11159
+ direction: "row",
11160
+ sx: {
11161
+ flex: 1,
11162
+ alignItems: "center",
11163
+ gap: "5px"
11164
+ },
11165
+ children: [
11166
+ /* @__PURE__ */ jsx(Button, {
11167
+ size: "xsmall",
11168
+ variant: "outlined",
11169
+ color: "neutral",
11170
+ startIcon: /* @__PURE__ */ jsx(TbCloudUpload, {}),
11171
+ endIcon: shareUrl ? /* @__PURE__ */ jsx(Box, {
11172
+ component: PiCheckCircle,
11173
+ sx: { color: "success.main" }
11174
+ }) : void 0,
11175
+ onClick: async () => {
11176
+ await handleShareClick();
11177
+ trackShareState({ name: "create" });
11178
+ },
11179
+ disabled: isLoading,
11180
+ children: isLoading ? "Sharing..." : "Share"
11181
+ }),
11182
+ isLoading && /* @__PURE__ */ jsx(Typography, {
11183
+ sx: {
11184
+ fontSize: 14,
11185
+ color: "grey.500"
11186
+ },
11187
+ children: LOADING_MESSAGES[messageIndex]
11188
+ }),
11189
+ /* @__PURE__ */ jsx(Stack, {
11190
+ direction: "row",
11191
+ spacing: .5,
11192
+ alignItems: "center",
11193
+ children: shareUrl && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Box, {
11194
+ sx: {
11195
+ overflowX: "auto",
11196
+ whiteSpace: "nowrap",
11197
+ maxWidth: "350px"
11198
+ },
11199
+ children: /* @__PURE__ */ jsx(Typography, {
11200
+ sx: { fontSize: 14 },
11201
+ children: shareUrl
11202
+ })
11203
+ }), /* @__PURE__ */ jsx(IconButton, {
11204
+ size: "small",
11205
+ "aria-label": "Copy the share URL",
11206
+ onClick: async () => {
11207
+ await handleCopy();
11208
+ trackShareState({ name: "copy" });
11209
+ },
11210
+ children: /* @__PURE__ */ jsx(PiCopy, {})
11211
+ })] })
11212
+ })
11213
+ ]
11214
+ });
11215
+ }
11216
+
11217
+ //#endregion
11218
+ //#region recce-source/js/src/components/app/StateSynchronizer.tsx
11219
+ function isCheckDetailPage(href) {
11220
+ 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);
11221
+ }
11222
+ function StateSpinner() {
11223
+ return /* @__PURE__ */ jsx(MuiTooltip, {
11224
+ title: "Syncing",
11225
+ children: /* @__PURE__ */ jsx(Box, {
11226
+ sx: { mx: "10px" },
11227
+ children: /* @__PURE__ */ jsx(CircularProgress, { size: 20 })
11228
+ })
11229
+ });
11230
+ }
11231
+ function StateSynchronizer() {
11232
+ const [isSyncing, setSyncing] = useState(false);
11233
+ const queryClient = useQueryClient();
11234
+ const [location, setLocation] = useAppLocation();
11235
+ const [open, setOpen] = useState(false);
11236
+ const [syncOption, setSyncOption] = useState("");
11237
+ const { data: instanceInfo } = useRecceInstanceInfo();
11238
+ const handleClose = () => setOpen(false);
11239
+ const handleSync = useCallback(async (input) => {
11240
+ setOpen(false);
11241
+ setSyncing(true);
11242
+ if ((await syncState(input)).status === "conflict") {
11243
+ setOpen(true);
11244
+ setSyncing(false);
11245
+ return;
11246
+ }
11247
+ while (await isStateSyncing()) await new Promise((resolve) => setTimeout(resolve, 1e3));
11248
+ toaster.create({
11249
+ description: "Sync Completed",
11250
+ type: "success",
11251
+ duration: 5e3,
11252
+ closable: true
11253
+ });
11254
+ setSyncing(false);
11255
+ setSyncOption("");
11256
+ await queryClient.invalidateQueries({ queryKey: cacheKeys.lineage() });
11257
+ await queryClient.invalidateQueries({ queryKey: cacheKeys.checks() });
11258
+ await queryClient.invalidateQueries({ queryKey: cacheKeys.runs() });
11259
+ if (isCheckDetailPage(location)) setLocation("/checks");
11260
+ }, [
11261
+ queryClient,
11262
+ location,
11263
+ setLocation
11264
+ ]);
11265
+ if (isSyncing) return /* @__PURE__ */ jsx(StateSpinner, {});
11266
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(MuiTooltip, {
11267
+ title: "Sync with Cloud",
11268
+ children: /* @__PURE__ */ jsx(IconButton, {
11269
+ size: "small",
11270
+ "aria-label": "Sync state",
11271
+ onClick: () => handleSync(instanceInfo?.session_id ? { method: "merge" } : {}),
11272
+ children: /* @__PURE__ */ jsx(Box, {
11273
+ component: IconSync,
11274
+ sx: {
11275
+ fontSize: 16,
11276
+ verticalAlign: "middle"
11277
+ }
11278
+ })
11279
+ })
11280
+ }), /* @__PURE__ */ jsxs(MuiDialog, {
11281
+ open,
11282
+ onClose: handleClose,
11283
+ children: [
11284
+ /* @__PURE__ */ jsxs(DialogTitle, {
11285
+ sx: {
11286
+ display: "flex",
11287
+ alignItems: "center",
11288
+ fontWeight: "bold"
11289
+ },
11290
+ children: [
11291
+ "Sync with Cloud",
11292
+ /* @__PURE__ */ jsx(Box, { sx: { flexGrow: 1 } }),
11293
+ /* @__PURE__ */ jsx(IconButton, {
11294
+ size: "small",
11295
+ onClick: handleClose,
11296
+ children: /* @__PURE__ */ jsx(IoClose, {})
11297
+ })
11298
+ ]
11299
+ }),
11300
+ /* @__PURE__ */ jsxs(DialogContent, { children: [/* @__PURE__ */ jsx(Typography, { children: "New changes have been detected in the cloud. Please choose a method to sync your state" }), /* @__PURE__ */ jsx(Box, {
11301
+ sx: { mt: "5px" },
11302
+ children: /* @__PURE__ */ jsx(RadioGroup, {
11303
+ value: syncOption,
11304
+ onChange: (e) => {
11305
+ setSyncOption(e.target.value);
11306
+ },
11307
+ children: /* @__PURE__ */ jsxs(Stack, {
11308
+ direction: "column",
11309
+ children: [
11310
+ /* @__PURE__ */ jsx(FormControlLabel, {
11311
+ value: "merge",
11312
+ control: /* @__PURE__ */ jsx(Radio, {}),
11313
+ label: /* @__PURE__ */ jsxs(Stack, {
11314
+ direction: "row",
11315
+ alignItems: "center",
11316
+ children: ["Merge", /* @__PURE__ */ jsx(MuiTooltip, {
11317
+ title: "This will merge the local and remote states.",
11318
+ children: /* @__PURE__ */ jsx(Box, {
11319
+ component: PiInfo,
11320
+ sx: {
11321
+ ml: 2,
11322
+ cursor: "pointer"
11323
+ }
11324
+ })
11325
+ })]
11326
+ })
11327
+ }),
11328
+ /* @__PURE__ */ jsx(FormControlLabel, {
11329
+ value: "overwrite",
11330
+ control: /* @__PURE__ */ jsx(Radio, {}),
11331
+ label: /* @__PURE__ */ jsxs(Stack, {
11332
+ direction: "row",
11333
+ alignItems: "center",
11334
+ children: ["Overwrite", /* @__PURE__ */ jsx(MuiTooltip, {
11335
+ title: "This will overwrite the remote state file with the local state.",
11336
+ children: /* @__PURE__ */ jsx(Box, {
11337
+ component: PiInfo,
11338
+ sx: {
11339
+ ml: 2,
11340
+ cursor: "pointer"
11341
+ }
11342
+ })
11343
+ })]
11344
+ })
11345
+ }),
11346
+ /* @__PURE__ */ jsx(FormControlLabel, {
11347
+ value: "revert",
11348
+ control: /* @__PURE__ */ jsx(Radio, {}),
11349
+ label: /* @__PURE__ */ jsxs(Stack, {
11350
+ direction: "row",
11351
+ alignItems: "center",
11352
+ children: ["Revert", /* @__PURE__ */ jsx(MuiTooltip, {
11353
+ title: "This will discard local changes and revert to the cloud state.",
11354
+ children: /* @__PURE__ */ jsx(Box, {
11355
+ component: PiInfo,
11356
+ sx: {
11357
+ ml: 2,
11358
+ cursor: "pointer"
11359
+ }
11360
+ })
11361
+ })]
11362
+ })
11363
+ })
11364
+ ]
11365
+ })
11366
+ })
11367
+ })] }),
11368
+ /* @__PURE__ */ jsxs(DialogActions, { children: [/* @__PURE__ */ jsx(Button, {
11369
+ onClick: handleClose,
11370
+ sx: { mr: 1 },
11371
+ children: "Cancel"
11372
+ }), /* @__PURE__ */ jsx(Button, {
11373
+ color: "iochmara",
11374
+ variant: "contained",
11375
+ onClick: () => handleSync({ method: syncOption || void 0 }),
11376
+ disabled: !syncOption,
11377
+ children: "Sync"
11378
+ })] })
11379
+ ]
11380
+ })] });
11381
+ }
11382
+
11383
+ //#endregion
11384
+ //#region recce-source/js/app/(mainComponents)/NavBar.tsx
11385
+ /**
11386
+ * Route configuration for tabs
11387
+ */
11388
+ const ROUTE_CONFIG = [
11389
+ {
11390
+ path: "/lineage",
11391
+ name: "Lineage"
11392
+ },
11393
+ {
11394
+ path: "/query",
11395
+ name: "Query"
11396
+ },
11397
+ {
11398
+ path: "/checks",
11399
+ name: "Checklist"
11400
+ }
11401
+ ];
11402
+ function TabBadge({ queryKey, fetchCallback, selectCallback }) {
11403
+ const { data: count, isLoading, error } = useQuery({
11404
+ queryKey,
11405
+ queryFn: fetchCallback,
11406
+ select: selectCallback
11407
+ });
11408
+ if (isLoading || error || count === 0) return /* @__PURE__ */ jsx(Fragment$1, {});
11409
+ return /* @__PURE__ */ jsx(Box, {
11410
+ bgcolor: "brand.main",
11411
+ display: "flex",
11412
+ justifyContent: "center",
11413
+ alignItems: "center",
11414
+ p: 1,
11415
+ borderRadius: "100%",
11416
+ color: "white",
11417
+ fontWeight: 700,
11418
+ fontSize: "0.75rem",
11419
+ children: /* @__PURE__ */ jsx("span", { children: count })
11420
+ });
11421
+ }
11422
+ function ChecklistBadge() {
11423
+ return /* @__PURE__ */ jsx(TabBadge, {
11424
+ queryKey: cacheKeys.checks(),
11425
+ fetchCallback: listChecks,
11426
+ selectCallback: (checks) => {
11427
+ return checks.filter((check) => !check.is_checked).length;
11428
+ }
11429
+ });
11430
+ }
11431
+ function NavBar() {
11432
+ const pathname = usePathname();
11433
+ const { isDemoSite, isLoading, cloudMode } = useLineageGraphContext();
11434
+ const { featureToggles } = useRecceInstanceContext();
11435
+ const { data: flag, isLoading: isFlagLoading } = useRecceServerFlag();
11436
+ const prevPathnameRef = useRef(null);
11437
+ useEffect(() => {
11438
+ if (prevPathnameRef.current && prevPathnameRef.current !== pathname) trackNavigation({
11439
+ from: prevPathnameRef.current,
11440
+ to: pathname
11441
+ });
11442
+ prevPathnameRef.current = pathname;
11443
+ }, [pathname]);
11444
+ return /* @__PURE__ */ jsx(Box, {
11445
+ sx: {
11446
+ borderBottom: "1px solid lightgray",
11447
+ px: "12px"
11448
+ },
11449
+ children: /* @__PURE__ */ jsxs(Box, {
11450
+ sx: {
11451
+ display: "grid",
11452
+ gridTemplateColumns: "1fr auto 1fr",
11453
+ width: "100%",
11454
+ alignItems: "center"
11455
+ },
11456
+ children: [
11457
+ /* @__PURE__ */ jsx(Tabs, {
11458
+ value: useMemo(() => {
11459
+ if (pathname.startsWith("/checks")) return "/checks";
11460
+ if (pathname.startsWith("/query")) return "/query";
11461
+ if (pathname.startsWith("/runs")) return "/runs";
11462
+ return "/lineage";
11463
+ }, [pathname]),
11464
+ sx: {
11465
+ borderBottom: "none",
11466
+ minHeight: "auto"
11467
+ },
11468
+ children: ROUTE_CONFIG.map(({ path, name }) => {
11469
+ if (name === "Query" && flag?.single_env_onboarding) return null;
11470
+ if (name === "Checklist" && ChecklistBadge) return /* @__PURE__ */ jsx(Tab, {
11471
+ value: path,
11472
+ disabled: isLoading || isFlagLoading,
11473
+ sx: { p: 0 },
11474
+ label: /* @__PURE__ */ jsx(Box, {
11475
+ sx: {
11476
+ display: "flex",
11477
+ alignItems: "center",
11478
+ gap: "4px"
11479
+ },
11480
+ children: /* @__PURE__ */ jsxs(NextLink, {
11481
+ href: path,
11482
+ style: {
11483
+ textDecoration: "none",
11484
+ color: "inherit",
11485
+ padding: "0.875rem 1.1875rem",
11486
+ display: "flex",
11487
+ gap: 3,
11488
+ alignItems: "center"
11489
+ },
11490
+ children: [
11491
+ name,
11492
+ " ",
11493
+ /* @__PURE__ */ jsx(ChecklistBadge, {})
11494
+ ]
11495
+ })
11496
+ })
11497
+ }, path);
11498
+ return /* @__PURE__ */ jsx(Tab, {
11499
+ value: path,
11500
+ disabled: isLoading || isFlagLoading,
11501
+ sx: { p: 0 },
11502
+ label: /* @__PURE__ */ jsx(Box, {
11503
+ sx: {
11504
+ display: "flex",
11505
+ alignItems: "center",
11506
+ gap: "4px"
11507
+ },
11508
+ children: /* @__PURE__ */ jsx(NextLink, {
11509
+ href: path,
11510
+ style: {
11511
+ textDecoration: "none",
11512
+ color: "inherit",
11513
+ padding: "0.875rem 1.1875rem"
11514
+ },
11515
+ children: name
11516
+ })
11517
+ })
11518
+ }, path);
11519
+ })
11520
+ }),
11521
+ /* @__PURE__ */ jsxs(Box, {
11522
+ sx: {
11523
+ display: "flex",
11524
+ alignItems: "center",
11525
+ gap: "12px",
11526
+ justifyContent: "center"
11527
+ },
11528
+ children: [!isLoading && !isDemoSite && /* @__PURE__ */ jsx(Filename, {}), !isLoading && !isDemoSite && !flag?.single_env_onboarding && !featureToggles.disableShare && /* @__PURE__ */ jsx(TopLevelShare, {})]
11529
+ }),
11530
+ !isLoading && /* @__PURE__ */ jsxs(Box, {
11531
+ sx: {
11532
+ display: "flex",
11533
+ justifyContent: "right",
11534
+ alignItems: "center",
11535
+ mr: "8px"
11536
+ },
11537
+ children: [
11538
+ /* @__PURE__ */ jsx(EnvInfo, {}),
11539
+ cloudMode && /* @__PURE__ */ jsx(StateSynchronizer, {}),
11540
+ /* @__PURE__ */ jsx(StateExporter, {})
11541
+ ]
11542
+ })
11543
+ ]
11544
+ })
11545
+ });
11546
+ }
11547
+
11548
+ //#endregion
11549
+ //#region recce-source/js/app/(mainComponents)/DisplayModeToggle.tsx
11550
+ /**
11551
+ * Display Mode Toggle - switches between light and dark themes
11552
+ *
11553
+ * Uses next-themes to persist the user's preference.
11554
+ * Default is light theme, with future support for system preference.
11555
+ */
11556
+ function DisplayModeToggle$1() {
11557
+ const { setTheme, resolvedTheme } = useTheme$1();
11558
+ const [mounted, setMounted] = useState(false);
11559
+ useEffect(() => {
11560
+ setMounted(true);
11561
+ }, []);
11562
+ const toggleTheme = () => {
11563
+ setTheme(resolvedTheme === "dark" ? "light" : "dark");
11564
+ };
11565
+ if (!mounted) return /* @__PURE__ */ jsx(IconButton, {
11566
+ size: "small",
11567
+ sx: {
11568
+ color: "rgba(255, 255, 255, 0.8)",
11569
+ "&:hover": { bgcolor: "rgba(255, 255, 255, 0.1)" }
11570
+ },
11571
+ disabled: true,
11572
+ children: /* @__PURE__ */ jsx(PiSun, { style: {
11573
+ width: 18,
11574
+ height: 18
11575
+ } })
11576
+ });
11577
+ const isDark = resolvedTheme === "dark";
11578
+ return /* @__PURE__ */ jsx(MuiTooltip, {
11579
+ title: isDark ? "Switch to light mode" : "Switch to dark mode",
11580
+ children: /* @__PURE__ */ jsx(IconButton, {
11581
+ size: "small",
11582
+ onClick: toggleTheme,
11583
+ sx: {
11584
+ color: "rgba(255, 255, 255, 0.8)",
11585
+ "&:hover": { bgcolor: "rgba(255, 255, 255, 0.1)" }
11586
+ },
11587
+ "aria-label": isDark ? "Switch to light mode" : "Switch to dark mode",
11588
+ children: isDark ? /* @__PURE__ */ jsx(PiSun, { style: {
11589
+ width: 18,
11590
+ height: 18
11591
+ } }) : /* @__PURE__ */ jsx(PiMoon, { style: {
11592
+ width: 18,
11593
+ height: 18
11594
+ } })
11595
+ })
11596
+ });
11597
+ }
11598
+
11599
+ //#endregion
11600
+ //#region recce-source/js/app/(mainComponents)/RecceVersionBadge.tsx
11601
+ function RecceVersionBadge$1() {
11602
+ const { version, latestVersion } = useVersionNumber();
11603
+ const versionFormatRegex = useMemo(() => /* @__PURE__ */ new RegExp("^\\d+\\.\\d+\\.\\d+$"), []);
11604
+ useEffect(() => {
11605
+ if (versionFormatRegex.test(version) && version !== latestVersion) {
11606
+ const storageKey = "recce-update-toast-shown";
11607
+ if (sessionStorage.getItem(storageKey)) return;
11608
+ setTimeout(() => {
11609
+ toaster.create({
11610
+ id: "recce-update-available",
11611
+ title: "Update available",
11612
+ description: /* @__PURE__ */ jsxs("span", { children: [
11613
+ "A new version of Recce (v",
11614
+ latestVersion,
11615
+ ") is available.",
11616
+ /* @__PURE__ */ jsx("br", {}),
11617
+ "Please run",
11618
+ " ",
11619
+ /* @__PURE__ */ jsx(Box, {
11620
+ component: "code",
11621
+ sx: {
11622
+ bgcolor: "grey.200",
11623
+ px: .5,
11624
+ py: .25,
11625
+ borderRadius: .5,
11626
+ fontFamily: "monospace",
11627
+ fontSize: "0.875em"
11628
+ },
11629
+ children: "pip install --upgrade recce"
11630
+ }),
11631
+ " ",
11632
+ "to update Recce.",
11633
+ /* @__PURE__ */ jsx("br", {}),
11634
+ /* @__PURE__ */ jsx(Link, {
11635
+ sx: {
11636
+ color: "primary.main",
11637
+ fontWeight: "bold",
11638
+ "&:hover": { textDecoration: "underline" }
11639
+ },
11640
+ href: `https://github.com/DataRecce/recce/releases/tag/v${latestVersion}`,
11641
+ target: "_blank",
11642
+ children: "Click here to view the detail of latest release"
11643
+ })
11644
+ ] }),
11645
+ duration: 60 * 1e3,
11646
+ closable: true
11647
+ });
11648
+ sessionStorage.setItem(storageKey, "true");
11649
+ }, 0);
11650
+ }
11651
+ }, [
11652
+ version,
11653
+ latestVersion,
11654
+ versionFormatRegex
11655
+ ]);
11656
+ if (!versionFormatRegex.test(version)) return /* @__PURE__ */ jsx(Typography, {
11657
+ component: "span",
11658
+ sx: {
11659
+ fontSize: "sm",
11660
+ color: "rgba(255,255,255,0.8)",
11661
+ textTransform: "uppercase",
11662
+ borderWidth: 1,
11663
+ px: 1,
11664
+ borderRadius: .75
11665
+ },
11666
+ children: version
11667
+ });
11668
+ return /* @__PURE__ */ jsx(Link, {
11669
+ href: `https://github.com/DataRecce/recce/releases/tag/v${version}`,
11670
+ sx: {
11671
+ "&:hover": { textDecoration: "none" },
11672
+ fontSize: "sm",
11673
+ color: "rgba(255,255,255,0.8)",
11674
+ textTransform: "uppercase",
11675
+ borderWidth: 1,
11676
+ px: 1,
11677
+ borderRadius: .75
11678
+ },
11679
+ target: "_blank",
11680
+ children: version
11681
+ });
11682
+ }
11683
+
11684
+ //#endregion
11685
+ export { NodeSqlView as A, GraphEdge as B, NodeView as C, SqlEditor_default as D, RunStatusAndDate as E, HistoryToggle as F, MuiProvider as G, HSplit as H, GraphNode as I, mui_provider_default as K, ModelRowCount as L, CodeEditor_default as M, SchemaView as N, QueryForm as O, LineageViewTopBar as P, ResourceTypeTag as R, SetupConnectionBanner as S, RunView as T, VSplit as U, GraphColumnNode as V, ErrorBoundary$1 as W, CheckList as _, IdleTimeoutBadge as a, LineagePage as b, ChangeSummary as c, CheckEmptyState as d, CheckDetail as f, CheckBreadcrumb as g, CheckDescription as h, TopBar as i, DiffEditor_default as j, EnvInfo as k, RunList as l, LineageDiffView as m, DisplayModeToggle$1 as n, SummaryView as o, SchemaDiffView as p, NavBar as r, SchemaSummary as s, RecceVersionBadge$1 as t, RunPage as u, QueryPage as v, RunResultPane as w, LineageView as x, SetupConnectionGuide as y, RowCountDiffTag as z };
11686
+ //# sourceMappingURL=components-CfY72Lq2.mjs.map