@datarecce/ui 0.1.22 → 0.1.24

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 (56) hide show
  1. package/dist/{RecceCheckContext-DNKi97uE.js → RecceCheckContext-Cb41gigE.js} +4 -3
  2. package/dist/RecceCheckContext-Cb41gigE.js.map +1 -0
  3. package/dist/{RecceCheckContext-BETsmiD5.mjs → RecceCheckContext-CzsuuXxT.mjs} +4 -3
  4. package/dist/RecceCheckContext-CzsuuXxT.mjs.map +1 -0
  5. package/dist/api.d.mts +2 -2
  6. package/dist/api.d.ts +2 -2
  7. package/dist/api.js +12 -37
  8. package/dist/api.mjs +3 -29
  9. package/dist/{components-C735_oqD.mjs → components-BHxcVq0D.mjs} +1353 -69
  10. package/dist/components-BHxcVq0D.mjs.map +1 -0
  11. package/dist/{components-DeA4kqxK.js → components-Bmc5X473.js} +1557 -248
  12. package/dist/components-Bmc5X473.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-Ba-AoxcK.mjs → hooks-B0XGswIh.mjs} +3 -3
  18. package/dist/{hooks-Ba-AoxcK.mjs.map → hooks-B0XGswIh.mjs.map} +1 -1
  19. package/dist/{hooks-D6xvNXEc.js → hooks-C99PZcmB.js} +3 -3
  20. package/dist/{hooks-D6xvNXEc.js.map → hooks-C99PZcmB.js.map} +1 -1
  21. package/dist/hooks.d.mts +2 -2
  22. package/dist/hooks.d.ts +2 -2
  23. package/dist/hooks.js +4 -3
  24. package/dist/hooks.mjs +4 -4
  25. package/dist/{index-Sj_wOmNH.d.mts → index-04n48ic2.d.mts} +129 -105
  26. package/dist/index-04n48ic2.d.mts.map +1 -0
  27. package/dist/{index-DYduBYD8.d.ts → index-CgyLTrll.d.ts} +129 -105
  28. package/dist/index-CgyLTrll.d.ts.map +1 -0
  29. package/dist/index.d.mts +2 -2
  30. package/dist/index.d.ts +2 -2
  31. package/dist/index.js +20 -14
  32. package/dist/index.mjs +7 -7
  33. package/dist/{state-BjKRZMwY.js → state-Ct-DP81O.js} +108 -79
  34. package/dist/state-Ct-DP81O.js.map +1 -0
  35. package/dist/{state-BySLlIE7.mjs → state-CwepO01b.mjs} +91 -80
  36. package/dist/state-CwepO01b.mjs.map +1 -0
  37. package/dist/types.d.mts +1 -1
  38. package/dist/types.d.ts +1 -1
  39. package/dist/{user-Dt_n5IJX.js → version-BgsW-hXj.js} +50 -10
  40. package/dist/version-BgsW-hXj.js.map +1 -0
  41. package/dist/version-Bz2CiMHD.mjs +93 -0
  42. package/dist/version-Bz2CiMHD.mjs.map +1 -0
  43. package/package.json +5 -4
  44. package/dist/RecceCheckContext-BETsmiD5.mjs.map +0 -1
  45. package/dist/RecceCheckContext-DNKi97uE.js.map +0 -1
  46. package/dist/api.js.map +0 -1
  47. package/dist/api.mjs.map +0 -1
  48. package/dist/components-C735_oqD.mjs.map +0 -1
  49. package/dist/components-DeA4kqxK.js.map +0 -1
  50. package/dist/index-DYduBYD8.d.ts.map +0 -1
  51. package/dist/index-Sj_wOmNH.d.mts.map +0 -1
  52. package/dist/state-BjKRZMwY.js.map +0 -1
  53. package/dist/state-BySLlIE7.mjs.map +0 -1
  54. package/dist/user-BHOgMaBf.mjs +0 -65
  55. package/dist/user-BHOgMaBf.mjs.map +0 -1
  56. 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 trackLineageViewRender, At as createLineageDiffCheck, B as IconExport, Bn as darkTheme, Bt as submitRunFromCheck, Cn as selectUpstream, En as getCll, Et as ScreenshotDataGrid, Ft as cancelRun, G as deltaPercentageString, Gt as LINEAGE_SELECTION_ACTION, H as IconInfo, Hn as token, Ht as EXPLORE_ACTION, I as useRecceActionContext, J as mergeKeys, Jt as trackEnvironmentConfig, Kt as trackColumnLevelLineage, L as useAppLocation, Ln as toaster, Lt as listRuns, M as useLineageViewContext, Mn as axiosClient, Mt as submitQueryBase, N as useLineageViewContextSafe, Nt as submitQueryDiff, Qt as trackLineageSelection, Sn as selectDownstream, St as useApiConfig, Tn as union, Tt as EmptyRowsRenderer, U as IconSave, Vn as lightTheme, Vt as waitRun, W as IconSync, Wt as EXPLORE_SOURCE, Y as mergeKeysWithStatus, Yt as trackExploreAction, Zt as trackHistoryAction, _ as findByRunType, _n as isValueDiffRun, a as saveAs$1, an as trackSingleEnvironment, at as supportsHistogramDiff, bn as isLineageGraphNode, c as createCheckByRun, cn as isHistogramDiffRun, ct as useLineageGraphContext, d as getCheck, dn as isQueryDiffRun, en as trackMultiNodesAction, f as listChecks, fn as isQueryRun, ft as useIdleTimeout, g as useChecks, gn as isValueDiffDetailRun, gt as formatDuration, h as updateCheck, hn as isTopKDiffRun, i as rename, in as trackShareState, j as LineageViewContext, jt as submitQuery, k as createDataGridFromData, ln as isProfileDiffRun, lt as useRunsAggregated, mn as isRowCountRun, nn as trackPreviewChange, on as trackStateAction, ot as useModelColumns_default, p as markAsPresetCheck, pn as isRowCountDiffRun, q as useClipBoardToast, qt as trackCopyToClipboard, r as isStateSyncing, rn as trackPreviewChangeFeedback, s as syncState, t as exportState, tn as trackNavigation, u as deleteCheck, un as isQueryBaseRun, ut as useRecceServerFlag, v as runTypeHasRef, vn as COLUMN_HEIGHT, vt as useRecceInstanceContext, wn as toReactFlow, wt as cacheKeys, xn as layout, yn as isLineageGraphColumnNode, yt as useRecceInstanceInfo, z as IconEdit, zn as colors, zt as submitRun } from "./state-CwepO01b.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 connectToCloud, c as select, i as fetchUser, l as createSchemaDiffCheck, n as useVersionNumber, o as localStorageKeys, r as fetchGitHubAvatar, s as sessionStorageKeys } from "./version-Bz2CiMHD.mjs";
5
+ import { i as useValueDiffAlertDialog_default, l as defaultSqlQuery, n as useRecceCheckContext, o as useRecceShareStateContext, r as useCheckToast, u as useRecceQueryContext } from "./RecceCheckContext-CzsuuXxT.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";
@@ -19,7 +19,7 @@ import { ErrorBoundary, FallbackRender } from "@sentry/react";
19
19
  import ReactSplit, { SplitProps } from "react-split";
20
20
  import { Background, BackgroundVariant, BaseEdge, ControlButton, Controls, EdgeProps, Handle, MiniMap, Node, NodeProps, Panel, Position, ReactFlow, ReactFlowProvider, getBezierPath, getNodesBounds, useEdgesState, useNodesState, useReactFlow, useStore } from "@xyflow/react";
21
21
  import Divider from "@mui/material/Divider";
22
- import { AxiosError, AxiosResponse } from "axios";
22
+ import { AxiosError, AxiosInstance, AxiosResponse } from "axios";
23
23
  import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
24
24
  import "@xyflow/react/dist/style.css";
25
25
  import { FiArrowRight, FiCopy, FiFrown, FiInfo, FiPackage } from "react-icons/fi";
@@ -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";
@@ -223,7 +226,7 @@ const getHTMLElementFromRef = (refCurrent) => {
223
226
  };
224
227
  const IGNORE_SCREENSHOT_CLASS = "ignore-screenshot";
225
228
  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 }) {
229
+ 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
230
  const [status, setStatus] = useState("idle");
228
231
  const ref = useRef(null);
229
232
  const { onOpen, setImgBlob, ImageDownloadModal } = useImageDownloadModal();
@@ -324,7 +327,7 @@ function useCopyToClipboard({ renderLibrary = "html2canvas", imageType = "png",
324
327
  }
325
328
  function useCopyToClipboardButton(options) {
326
329
  const { successToast, failToast } = useClipBoardToast();
327
- const { isLoading, copyToClipboard, ImageDownloadModal, ref } = useCopyToClipboard({
330
+ const { isLoading, copyToClipboard, ImageDownloadModal, ref } = useCopyToClipboard$1({
328
331
  imageType: "png",
329
332
  shadowEffect: true,
330
333
  backgroundColor: options?.backgroundColor ?? colors.neutral[100],
@@ -478,13 +481,14 @@ function useImageDownloadModal() {
478
481
  //#endregion
479
482
  //#region recce-source/js/src/lib/hooks/useRun.tsx
480
483
  const useRun = (runId) => {
484
+ const { apiClient } = useApiConfig();
481
485
  const [isRunning, setIsRunning] = useState(false);
482
486
  const [aborting, setAborting] = useState(false);
483
487
  const [, refetchRunsAggregated] = useRunsAggregated();
484
488
  const { error, data: run } = useQuery({
485
489
  queryKey: cacheKeys.run(runId ?? ""),
486
490
  queryFn: async () => {
487
- return await waitRun(runId ?? "", isRunning ? 2 : 0);
491
+ return await waitRun(runId ?? "", isRunning ? 2 : 0, apiClient);
488
492
  },
489
493
  enabled: !!runId,
490
494
  refetchInterval: isRunning ? 50 : false,
@@ -508,8 +512,8 @@ const useRun = (runId) => {
508
512
  const onCancel = useCallback(async () => {
509
513
  setAborting(true);
510
514
  if (!runId) return;
511
- await cancelRun(runId);
512
- }, [runId]);
515
+ await cancelRun(runId, apiClient);
516
+ }, [runId, apiClient]);
513
517
  let RunResultView;
514
518
  if (run && runTypeHasRef(run.type)) RunResultView = findByRunType(run.type).RunResultView;
515
519
  return {
@@ -4247,6 +4251,7 @@ const QueryForm = ({ defaultPrimaryKeys, onPrimaryKeysChange, ...props }) => {
4247
4251
  //#region recce-source/js/src/components/AuthModal/AuthModal.tsx
4248
4252
  function AuthModal({ handleParentClose, parentOpen = false, ignoreCookie = false, variant = "auth" }) {
4249
4253
  const { authed } = useRecceInstanceContext();
4254
+ const { apiClient } = useApiConfig();
4250
4255
  const [open, setOpen] = useState(parentOpen || !authed);
4251
4256
  const authStateCookieValue = Cookies.get("authState") ?? "pending";
4252
4257
  const [authState, setAuthState] = useState(ignoreCookie ? "pending" : authStateCookieValue);
@@ -4329,7 +4334,7 @@ function AuthModal({ handleParentClose, parentOpen = false, ignoreCookie = false
4329
4334
  },
4330
4335
  onClick: async () => {
4331
4336
  setAuthState("authenticating");
4332
- const { connection_url } = await connectToCloud();
4337
+ const { connection_url } = await connectToCloud(apiClient);
4333
4338
  window.open(connection_url, "_blank");
4334
4339
  },
4335
4340
  children: [
@@ -5015,6 +5020,7 @@ function AddToCheckButton({ runId, viewOptions }) {
5015
5020
  const { error, run } = useRun(runId);
5016
5021
  const queryClient = useQueryClient();
5017
5022
  const [, setLocation] = useAppLocation();
5023
+ const { apiClient } = useApiConfig();
5018
5024
  const checkId = run?.check_id;
5019
5025
  const handleGoToCheck = useCallback(() => {
5020
5026
  if (!checkId) return;
@@ -5022,14 +5028,15 @@ function AddToCheckButton({ runId, viewOptions }) {
5022
5028
  }, [checkId, setLocation]);
5023
5029
  const handleAddToChecklist = useCallback(async () => {
5024
5030
  if (!runId) return;
5025
- const check = await createCheckByRun(runId, viewOptions);
5031
+ const check = await createCheckByRun(runId, viewOptions, apiClient);
5026
5032
  await queryClient.invalidateQueries({ queryKey: cacheKeys.checks() });
5027
5033
  setLocation(`/checks/?id=${check.check_id}`);
5028
5034
  }, [
5029
5035
  runId,
5030
5036
  setLocation,
5031
5037
  queryClient,
5032
- viewOptions
5038
+ viewOptions,
5039
+ apiClient
5033
5040
  ]);
5034
5041
  if (featureToggles.disableUpdateChecklist) return /* @__PURE__ */ jsx(Fragment$1, {});
5035
5042
  if (run?.check_id) return /* @__PURE__ */ jsx(Button, {
@@ -5187,15 +5194,16 @@ function SandboxView({ isOpen, onClose, current }) {
5187
5194
  const { showRunId, clearRunResult } = useRecceActionContext();
5188
5195
  const { primaryKeys, setPrimaryKeys } = useRecceQueryContext();
5189
5196
  const { data: flags, isLoading } = useRecceServerFlag();
5197
+ const { apiClient } = useApiConfig();
5190
5198
  const queryFn = async () => {
5191
5199
  const sqlTemplate = modifiedCode;
5192
5200
  const { run_id } = await submitQueryDiff({
5193
5201
  current_model: current?.name ?? "",
5194
5202
  primary_keys: primaryKeys,
5195
5203
  sql_template: sqlTemplate
5196
- }, { nowait: true });
5204
+ }, { nowait: true }, apiClient);
5197
5205
  showRunId(run_id);
5198
- return await waitRun(run_id);
5206
+ return await waitRun(run_id, void 0, apiClient);
5199
5207
  };
5200
5208
  const { mutate: runQuery, isPending } = useMutation({
5201
5209
  mutationFn: queryFn,
@@ -5673,12 +5681,17 @@ function ExploreChangeMenuButton({ node, baseColumns, currentColumns, disableRea
5673
5681
  const { envInfo, isActionAvailable } = useLineageGraphContext();
5674
5682
  const { featureToggles } = useRecceInstanceContext();
5675
5683
  const { primaryKey } = useModelColumns_default(node.data.name);
5684
+ const { apiClient } = useApiConfig();
5676
5685
  const metadataOnly = featureToggles.mode === "metadata only";
5677
5686
  const isAddedOrRemoved = node.data.changeStatus === "added" || node.data.changeStatus === "removed";
5678
5687
  const addSchemaCheck = useCallback(async () => {
5679
5688
  const nodeId = node.id;
5680
- setLocation(`/checks/?id=${(await createSchemaDiffCheck({ node_id: nodeId })).check_id}`);
5681
- }, [node, setLocation]);
5689
+ setLocation(`/checks/?id=${(await createSchemaDiffCheck({ node_id: nodeId }, apiClient)).check_id}`);
5690
+ }, [
5691
+ node,
5692
+ setLocation,
5693
+ apiClient
5694
+ ]);
5682
5695
  const formattedColumns = formatSelectColumns(baseColumns, currentColumns);
5683
5696
  let query = `select * from {{ ref("${node.data.name}") }}`;
5684
5697
  if (formattedColumns.length) query = `select \n ${formattedColumns.join("\n ")}\nfrom {{ ref("${node.data.name}") }}`;
@@ -6145,6 +6158,7 @@ const initValue = {
6145
6158
  actions: {}
6146
6159
  };
6147
6160
  const useMultiNodesAction = (nodes, { onActionStarted, onActionNodeUpdated, onActionCompleted }) => {
6161
+ const { apiClient } = useApiConfig();
6148
6162
  const actionState = useRef({ ...initValue }).current;
6149
6163
  const { showRunId } = useRecceActionContext();
6150
6164
  const submitRunForNodes = async (type, skip, getParams) => {
@@ -6174,12 +6188,12 @@ const useMultiNodesAction = (nodes, { onActionStarted, onActionNodeUpdated, onAc
6174
6188
  }
6175
6189
  const params = getParams(candidates);
6176
6190
  try {
6177
- const { run_id } = await submitRun(type, params, { nowait: true });
6191
+ const { run_id } = await submitRun(type, params, { nowait: true }, apiClient);
6178
6192
  showRunId(run_id);
6179
6193
  actionState.currentRun = { run_id };
6180
6194
  actionState.total = 1;
6181
6195
  for (;;) {
6182
- const run = await waitRun(run_id, 2);
6196
+ const run = await waitRun(run_id, 2, apiClient);
6183
6197
  actionState.currentRun = run;
6184
6198
  const status = run.error ? "failure" : run.result ? "success" : "running";
6185
6199
  for (const node of candidates) {
@@ -6228,7 +6242,7 @@ const useMultiNodesAction = (nodes, { onActionStarted, onActionNodeUpdated, onAc
6228
6242
  };
6229
6243
  onActionNodeUpdated(node);
6230
6244
  } else try {
6231
- const { run_id } = await submitRun(type, params, { nowait: true });
6245
+ const { run_id } = await submitRun(type, params, { nowait: true }, apiClient);
6232
6246
  actionState.currentRun = { run_id };
6233
6247
  actions[node.id] = {
6234
6248
  mode,
@@ -6236,7 +6250,7 @@ const useMultiNodesAction = (nodes, { onActionStarted, onActionNodeUpdated, onAc
6236
6250
  };
6237
6251
  onActionNodeUpdated(node);
6238
6252
  for (;;) {
6239
- const run = await waitRun(run_id, 2);
6253
+ const run = await waitRun(run_id, 2, apiClient);
6240
6254
  actionState.currentRun = run;
6241
6255
  const status = run.error ? "failure" : run.result ? "success" : "running";
6242
6256
  actions[node.id] = {
@@ -6322,17 +6336,17 @@ const useMultiNodesAction = (nodes, { onActionStarted, onActionNodeUpdated, onAc
6322
6336
  });
6323
6337
  };
6324
6338
  const addLineageDiffCheck = async () => {
6325
- return await createLineageDiffCheck({ node_ids: nodes.map((node) => node.id) });
6339
+ return await createLineageDiffCheck({ node_ids: nodes.map((node) => node.id) }, apiClient);
6326
6340
  };
6327
6341
  const addSchemaDiffCheck = async () => {
6328
6342
  let check;
6329
- if (nodes.length === 1) check = await createSchemaDiffCheck({ node_id: nodes[0].id });
6330
- else check = await createSchemaDiffCheck({ node_id: nodes.map((node) => node.id) });
6343
+ if (nodes.length === 1) check = await createSchemaDiffCheck({ node_id: nodes[0].id }, apiClient);
6344
+ else check = await createSchemaDiffCheck({ node_id: nodes.map((node) => node.id) }, apiClient);
6331
6345
  return check;
6332
6346
  };
6333
6347
  const cancel = async () => {
6334
6348
  actionState.status = "canceling";
6335
- if (actionState.currentRun?.run_id) await cancelRun(actionState.currentRun.run_id);
6349
+ if (actionState.currentRun?.run_id) await cancelRun(actionState.currentRun.run_id, apiClient);
6336
6350
  };
6337
6351
  const reset = () => {
6338
6352
  Object.assign(actionState, initValue);
@@ -6395,10 +6409,11 @@ const useNavToCheck = () => {
6395
6409
  };
6396
6410
  function PrivateLineageView({ interactive = false, ...props }, ref) {
6397
6411
  const { isDark } = useThemeColors();
6412
+ const { apiClient } = useApiConfig();
6398
6413
  const reactFlow = useReactFlow();
6399
6414
  const refResize = useRef(null);
6400
6415
  const { successToast, failToast } = useClipBoardToast();
6401
- const { copyToClipboard, ImageDownloadModal, ref: refReactFlow } = useCopyToClipboard({
6416
+ const { copyToClipboard, ImageDownloadModal, ref: refReactFlow } = useCopyToClipboard$1({
6402
6417
  renderLibrary: "html-to-image",
6403
6418
  imageType: "png",
6404
6419
  shadowEffect: true,
@@ -6442,7 +6457,7 @@ function PrivateLineageView({ interactive = false, ...props }, ref) {
6442
6457
  }, []);
6443
6458
  const cllHistory = useRef([]).current;
6444
6459
  const [cll, setCll] = useState(void 0);
6445
- const actionGetCll = useMutation({ mutationFn: getCll });
6460
+ const actionGetCll = useMutation({ mutationFn: (input) => getCll(input, apiClient) });
6446
6461
  const [nodeColumnSetMap, setNodeColumSetMap] = useState({});
6447
6462
  const findNodeByName = useCallback((name) => {
6448
6463
  return nodes.filter(isLineageGraphNode).find((n) => n.data.name === name);
@@ -6545,7 +6560,7 @@ function PrivateLineageView({ interactive = false, ...props }, ref) {
6545
6560
  exclude: newViewOptions.exclude,
6546
6561
  packages: newViewOptions.packages,
6547
6562
  view_mode: newViewOptions.view_mode
6548
- })).nodes;
6563
+ }, apiClient)).nodes;
6549
6564
  } catch (_$1) {
6550
6565
  newViewOptions.view_mode = "all";
6551
6566
  filteredNodeIds$1 = (await select({
@@ -6553,7 +6568,7 @@ function PrivateLineageView({ interactive = false, ...props }, ref) {
6553
6568
  exclude: newViewOptions.exclude,
6554
6569
  packages: newViewOptions.packages,
6555
6570
  view_mode: newViewOptions.view_mode
6556
- })).nodes;
6571
+ }, apiClient)).nodes;
6557
6572
  }
6558
6573
  setViewOptions(newViewOptions);
6559
6574
  }
@@ -6674,7 +6689,7 @@ function PrivateLineageView({ interactive = false, ...props }, ref) {
6674
6689
  exclude: newViewOptions.exclude,
6675
6690
  packages: newViewOptions.packages,
6676
6691
  view_mode: newViewOptions.view_mode
6677
- });
6692
+ }, apiClient);
6678
6693
  newViewOptions = {
6679
6694
  ...newViewOptions,
6680
6695
  column_level_lineage: void 0
@@ -6956,7 +6971,7 @@ function PrivateLineageView({ interactive = false, ...props }, ref) {
6956
6971
  selected: "multi"
6957
6972
  });
6958
6973
  } else if (!focusedNode) {
6959
- check = await createLineageDiffCheck(viewOptions);
6974
+ check = await createLineageDiffCheck(viewOptions, apiClient);
6960
6975
  trackMultiNodesAction({
6961
6976
  type: "lineage_diff",
6962
6977
  selected: "none"
@@ -6976,7 +6991,7 @@ function PrivateLineageView({ interactive = false, ...props }, ref) {
6976
6991
  });
6977
6992
  }
6978
6993
  } else if (focusedNode) {
6979
- check = await createSchemaDiffCheck({ node_id: focusedNode.id });
6994
+ check = await createSchemaDiffCheck({ node_id: focusedNode.id }, apiClient);
6980
6995
  trackMultiNodesAction({
6981
6996
  type: "schema_diff",
6982
6997
  selected: "single"
@@ -6987,7 +7002,7 @@ function PrivateLineageView({ interactive = false, ...props }, ref) {
6987
7002
  exclude: viewOptions.exclude,
6988
7003
  packages: viewOptions.packages,
6989
7004
  view_mode: viewOptions.view_mode
6990
- });
7005
+ }, apiClient);
6991
7006
  trackMultiNodesAction({
6992
7007
  type: "schema_diff",
6993
7008
  selected: "none"
@@ -7323,6 +7338,7 @@ const QueryPage = () => {
7323
7338
  if (envInfo?.adapterType === "sqlmesh" && _sqlQuery === defaultSqlQuery) sqlQuery = `select * from db.mymodel`;
7324
7339
  if (featureToggles.mode === "read only") sqlQuery = `--- Would like to do query here? Book a demo with us at ${RECCE_SUPPORT_CALENDAR_URL}\n${sqlQuery}`;
7325
7340
  const { showRunId } = useRecceActionContext();
7341
+ const { apiClient } = useApiConfig();
7326
7342
  const queryFn = async (type) => {
7327
7343
  function queryFactory(type$1) {
7328
7344
  switch (type$1) {
@@ -7340,9 +7356,9 @@ const QueryPage = () => {
7340
7356
  params.primary_keys = primaryKeys;
7341
7357
  if (isCustomQueries) params.base_sql_template = baseSqlQuery;
7342
7358
  }
7343
- const { run_id } = await runFn(params, options);
7359
+ const { run_id } = await runFn(params, options, apiClient);
7344
7360
  showRunId(run_id);
7345
- return await waitRun(run_id);
7361
+ return await waitRun(run_id, void 0, apiClient);
7346
7362
  };
7347
7363
  const { mutate: runQuery, isPending } = useMutation({ mutationFn: queryFn });
7348
7364
  const currentSchema = useMemo(() => {
@@ -7497,9 +7513,10 @@ const ChecklistItem = ({ check, selected, onSelect, onMarkAsApproved }) => {
7497
7513
  const isDark = useTheme().palette.mode === "dark";
7498
7514
  const { featureToggles } = useRecceInstanceContext();
7499
7515
  const queryClient = useQueryClient();
7516
+ const { apiClient } = useApiConfig();
7500
7517
  const checkId = check.check_id;
7501
7518
  const { mutate } = useMutation({
7502
- mutationFn: (check$1) => updateCheck(checkId, check$1),
7519
+ mutationFn: (check$1) => updateCheck(checkId, check$1, apiClient),
7503
7520
  onSuccess: async () => {
7504
7521
  await queryClient.invalidateQueries({ queryKey: cacheKeys.check(checkId) });
7505
7522
  await queryClient.invalidateQueries({ queryKey: cacheKeys.checks() });
@@ -7571,8 +7588,9 @@ const CheckList = ({ checks, selectedItem, onCheckSelected, onChecksReordered })
7571
7588
  const [open, setOpen] = useState(false);
7572
7589
  const [pendingApprovalCheckId, setPendingApprovalCheckId] = useState(null);
7573
7590
  const queryClient = useQueryClient();
7591
+ const { apiClient } = useApiConfig();
7574
7592
  const { mutate: markCheckedByID } = useMutation({
7575
- mutationFn: (checkId) => updateCheck(checkId, { is_checked: true }),
7593
+ mutationFn: (checkId) => updateCheck(checkId, { is_checked: true }, apiClient),
7576
7594
  onSuccess: async (_$1, checkId) => {
7577
7595
  await queryClient.invalidateQueries({ queryKey: cacheKeys.check(checkId) });
7578
7596
  await queryClient.invalidateQueries({ queryKey: cacheKeys.checks() });
@@ -7720,20 +7738,22 @@ const CheckList = ({ checks, selectedItem, onCheckSelected, onChecksReordered })
7720
7738
  * List all events for a check in chronological order.
7721
7739
  *
7722
7740
  * @param checkId - The check ID
7741
+ * @param client - Optional axios instance for API configuration
7723
7742
  * @returns Promise resolving to array of CheckEvent objects
7724
7743
  */
7725
- async function listCheckEvents(checkId) {
7726
- return (await axiosClient.get(`/api/checks/${checkId}/events`)).data;
7744
+ async function listCheckEvents(checkId, client = axiosClient) {
7745
+ return (await client.get(`/api/checks/${checkId}/events`)).data;
7727
7746
  }
7728
7747
  /**
7729
7748
  * Create a new comment on a check.
7730
7749
  *
7731
7750
  * @param checkId - The check ID
7732
7751
  * @param content - The comment content (plain text for now, markdown later)
7752
+ * @param client - Optional axios instance for API configuration
7733
7753
  * @returns Promise resolving to the created CheckEvent
7734
7754
  */
7735
- async function createComment(checkId, content) {
7736
- return (await axiosClient.post(`/api/checks/${checkId}/events`, { content })).data;
7755
+ async function createComment(checkId, content, client = axiosClient) {
7756
+ return (await client.post(`/api/checks/${checkId}/events`, { content })).data;
7737
7757
  }
7738
7758
  /**
7739
7759
  * Update an existing comment.
@@ -7742,10 +7762,11 @@ async function createComment(checkId, content) {
7742
7762
  * @param checkId - The check ID
7743
7763
  * @param eventId - The event ID of the comment to update
7744
7764
  * @param content - The new comment content
7765
+ * @param client - Optional axios instance for API configuration
7745
7766
  * @returns Promise resolving to the updated CheckEvent
7746
7767
  */
7747
- async function updateComment(checkId, eventId, content) {
7748
- return (await axiosClient.patch(`/api/checks/${checkId}/events/${eventId}`, { content })).data;
7768
+ async function updateComment(checkId, eventId, content, client = axiosClient) {
7769
+ return (await client.patch(`/api/checks/${checkId}/events/${eventId}`, { content })).data;
7749
7770
  }
7750
7771
  /**
7751
7772
  * Delete a comment (soft delete).
@@ -7753,10 +7774,11 @@ async function updateComment(checkId, eventId, content) {
7753
7774
  *
7754
7775
  * @param checkId - The check ID
7755
7776
  * @param eventId - The event ID of the comment to delete
7777
+ * @param client - Optional axios instance for API configuration
7756
7778
  * @returns Promise resolving when deletion is complete
7757
7779
  */
7758
- async function deleteComment(checkId, eventId) {
7759
- await axiosClient.delete(`/api/checks/${checkId}/events/${eventId}`);
7780
+ async function deleteComment(checkId, eventId, client = axiosClient) {
7781
+ await client.delete(`/api/checks/${checkId}/events/${eventId}`);
7760
7782
  }
7761
7783
  /**
7762
7784
  * Get the appropriate icon name for an event type.
@@ -7786,27 +7808,28 @@ const POLLING_INTERVAL = 1e4;
7786
7808
  function useCheckEvents(checkId, options = {}) {
7787
7809
  const { enabled = true } = options;
7788
7810
  const queryClient = useQueryClient();
7811
+ const { apiClient } = useApiConfig();
7789
7812
  const { data: events, isLoading, error, refetch } = useQuery({
7790
7813
  queryKey: cacheKeys.checkEvents(checkId),
7791
- queryFn: () => listCheckEvents(checkId),
7814
+ queryFn: () => listCheckEvents(checkId, apiClient),
7792
7815
  enabled,
7793
7816
  refetchInterval: POLLING_INTERVAL,
7794
7817
  refetchIntervalInBackground: false
7795
7818
  });
7796
7819
  const createCommentMutation = useMutation({
7797
- mutationFn: (content) => createComment(checkId, content),
7820
+ mutationFn: (content) => createComment(checkId, content, apiClient),
7798
7821
  onSuccess: async () => {
7799
7822
  await queryClient.invalidateQueries({ queryKey: cacheKeys.checkEvents(checkId) });
7800
7823
  }
7801
7824
  });
7802
7825
  const updateCommentMutation = useMutation({
7803
- mutationFn: ({ eventId, content }) => updateComment(checkId, eventId, content),
7826
+ mutationFn: ({ eventId, content }) => updateComment(checkId, eventId, content, apiClient),
7804
7827
  onSuccess: async () => {
7805
7828
  await queryClient.invalidateQueries({ queryKey: cacheKeys.checkEvents(checkId) });
7806
7829
  }
7807
7830
  });
7808
7831
  const deleteCommentMutation = useMutation({
7809
- mutationFn: (eventId) => deleteComment(checkId, eventId),
7832
+ mutationFn: (eventId) => deleteComment(checkId, eventId, apiClient),
7810
7833
  onSuccess: async () => {
7811
7834
  await queryClient.invalidateQueries({ queryKey: cacheKeys.checkEvents(checkId) });
7812
7835
  }
@@ -8663,10 +8686,11 @@ function TimelineEvent({ event, currentUserId, onEdit, onDelete }) {
8663
8686
  */
8664
8687
  function CheckTimeline({ checkId }) {
8665
8688
  const isDark = useTheme().palette.mode === "dark";
8689
+ const { apiClient } = useApiConfig();
8666
8690
  const { events, isLoading, error, createComment: createComment$1, isCreatingComment, updateComment: updateComment$1, deleteComment: deleteComment$1 } = useCheckEvents(checkId);
8667
8691
  const { data: currentUser } = useQuery({
8668
8692
  queryKey: cacheKeys.user(),
8669
- queryFn: fetchUser,
8693
+ queryFn: () => fetchUser(apiClient),
8670
8694
  retry: false
8671
8695
  });
8672
8696
  const handleCreateComment = (content) => {
@@ -9051,6 +9075,7 @@ const NodelistItem = ({ node, selected, onSelect, schemaChanged, isDark }) => {
9051
9075
  };
9052
9076
  function PrivateSchemaDiffView({ check }, ref) {
9053
9077
  const isDark = useTheme().palette.mode === "dark";
9078
+ const { apiClient } = useApiConfig();
9054
9079
  const { lineageGraph } = useLineageGraphContext();
9055
9080
  const params = check.params;
9056
9081
  const { isLoading, error, data } = useQuery({
@@ -9060,7 +9085,7 @@ function PrivateSchemaDiffView({ check }, ref) {
9060
9085
  exclude: params.exclude,
9061
9086
  packages: params.packages,
9062
9087
  view_mode: params.view_mode
9063
- }),
9088
+ }, apiClient),
9064
9089
  refetchOnMount: true,
9065
9090
  enabled: !params.node_id
9066
9091
  });
@@ -9172,6 +9197,7 @@ const SchemaDiffView = forwardRef(PrivateSchemaDiffView);
9172
9197
  function CheckDetail({ checkId, refreshCheckList }) {
9173
9198
  const theme = useTheme();
9174
9199
  const isDark = theme.palette.mode === "dark";
9200
+ const { apiClient } = useApiConfig();
9175
9201
  const { featureToggles, sessionId } = useRecceInstanceContext();
9176
9202
  const { setLatestSelectedCheckId } = useRecceCheckContext();
9177
9203
  const { cloudMode } = useLineageGraphContext();
@@ -9187,7 +9213,7 @@ function CheckDetail({ checkId, refreshCheckList }) {
9187
9213
  const menuOpen = Boolean(menuAnchorEl);
9188
9214
  const { isLoading, error, data: check } = useQuery({
9189
9215
  queryKey: cacheKeys.check(checkId),
9190
- queryFn: async () => getCheck(checkId),
9216
+ queryFn: async () => getCheck(checkId, apiClient),
9191
9217
  refetchOnMount: true
9192
9218
  });
9193
9219
  const trackedRunId = submittedRunId ?? check?.last_run?.run_id;
@@ -9199,14 +9225,14 @@ function CheckDetail({ checkId, refreshCheckList }) {
9199
9225
  const isPresetCheck = check?.is_preset ?? false;
9200
9226
  const lineageViewRef = useRef(null);
9201
9227
  const { mutate } = useMutation({
9202
- mutationFn: (check$1) => updateCheck(checkId, check$1),
9228
+ mutationFn: (check$1) => updateCheck(checkId, check$1, apiClient),
9203
9229
  onSuccess: async () => {
9204
9230
  await queryClient.invalidateQueries({ queryKey: cacheKeys.check(checkId) });
9205
9231
  await queryClient.invalidateQueries({ queryKey: cacheKeys.checks() });
9206
9232
  }
9207
9233
  });
9208
9234
  const { mutate: handleDelete } = useMutation({
9209
- mutationFn: () => deleteCheck(checkId),
9235
+ mutationFn: () => deleteCheck(checkId, apiClient),
9210
9236
  onSuccess: async () => {
9211
9237
  setLatestSelectedCheckId("");
9212
9238
  await queryClient.invalidateQueries({ queryKey: cacheKeys.checks() });
@@ -9216,7 +9242,7 @@ function CheckDetail({ checkId, refreshCheckList }) {
9216
9242
  const { mutate: handleMarkAsPresetCheck, isPending: isMarkingAsPreset } = useMutation({
9217
9243
  mutationFn: async () => {
9218
9244
  if (!check) throw new Error("Check not found");
9219
- return await markAsPresetCheck(checkId);
9245
+ return await markAsPresetCheck(checkId, apiClient);
9220
9246
  },
9221
9247
  onSuccess: async () => {
9222
9248
  successToast("Check marked as preset successfully");
@@ -9228,20 +9254,21 @@ function CheckDetail({ checkId, refreshCheckList }) {
9228
9254
  });
9229
9255
  const handleRerun = useCallback(async () => {
9230
9256
  if (!check?.type) return;
9231
- setSubmittedRunId((await submitRunFromCheck(checkId, { nowait: true })).run_id);
9257
+ setSubmittedRunId((await submitRunFromCheck(checkId, { nowait: true }, apiClient)).run_id);
9232
9258
  await queryClient.invalidateQueries({ queryKey: cacheKeys.check(checkId) });
9233
9259
  if (refreshCheckList) refreshCheckList();
9234
9260
  }, [
9235
9261
  check,
9236
9262
  checkId,
9237
9263
  queryClient,
9238
- refreshCheckList
9264
+ refreshCheckList,
9265
+ apiClient
9239
9266
  ]);
9240
9267
  const handleCancel = useCallback(async () => {
9241
9268
  setAborting(true);
9242
9269
  if (!trackedRunId) return;
9243
- return await cancelRun(trackedRunId);
9244
- }, [trackedRunId]);
9270
+ return await cancelRun(trackedRunId, apiClient);
9271
+ }, [trackedRunId, apiClient]);
9245
9272
  const handleCopy = async () => {
9246
9273
  if (!check) return;
9247
9274
  const markdown = buildMarkdown(check);
@@ -9746,8 +9773,9 @@ function buildBody(check) {
9746
9773
  const CheckEmptyState = () => {
9747
9774
  const queryClient = useQueryClient();
9748
9775
  const [, setLocation] = useAppLocation();
9776
+ const { apiClient } = useApiConfig();
9749
9777
  const { mutate: createSchemaCheck, isPending } = useMutation({
9750
- mutationFn: () => createSchemaDiffCheck({ select: "state:modified" }),
9778
+ mutationFn: () => createSchemaDiffCheck({ select: "state:modified" }, apiClient),
9751
9779
  onSuccess: async (check) => {
9752
9780
  await queryClient.invalidateQueries({ queryKey: cacheKeys.checks() });
9753
9781
  setLocation(`/checks/?id=${check.check_id}`);
@@ -9830,9 +9858,10 @@ const CheckEmptyState = () => {
9830
9858
  //#endregion
9831
9859
  //#region recce-source/js/src/components/run/RunPage.tsx
9832
9860
  const RunPage = ({ runId }) => {
9861
+ const { apiClient } = useApiConfig();
9833
9862
  const { error, data: run } = useQuery({
9834
9863
  queryKey: cacheKeys.run(runId),
9835
- queryFn: async () => waitRun(runId)
9864
+ queryFn: async () => waitRun(runId, void 0, apiClient)
9836
9865
  });
9837
9866
  let RunResultView;
9838
9867
  if (run && runTypeHasRef(run.type)) RunResultView = findByRunType(run.type).RunResultView;
@@ -9847,10 +9876,11 @@ const RunPage = ({ runId }) => {
9847
9876
  //#region recce-source/js/src/components/run/RunList.tsx
9848
9877
  const RunListItem = ({ run, isSelected, onSelectRun, onAddToChecklist, onGoToCheck }) => {
9849
9878
  const { featureToggles } = useRecceInstanceContext();
9879
+ const { apiClient } = useApiConfig();
9850
9880
  const { data: fetchedRun } = useQuery({
9851
9881
  queryKey: cacheKeys.run(run.run_id),
9852
9882
  queryFn: async () => {
9853
- return await waitRun(run.run_id);
9883
+ return await waitRun(run.run_id, void 0, apiClient);
9854
9884
  },
9855
9885
  enabled: run.status === "running",
9856
9886
  retry: false
@@ -9954,10 +9984,11 @@ const DateSegmentItem = ({ runAt }) => {
9954
9984
  };
9955
9985
  const RunList = () => {
9956
9986
  const { closeHistory } = useRecceActionContext();
9987
+ const { apiClient } = useApiConfig();
9957
9988
  const { data: runs, isLoading } = useQuery({
9958
9989
  queryKey: cacheKeys.runs(),
9959
9990
  queryFn: async () => {
9960
- return await listRuns();
9991
+ return await listRuns(apiClient);
9961
9992
  },
9962
9993
  retry: false
9963
9994
  });
@@ -10021,6 +10052,7 @@ const RunList = () => {
10021
10052
  function DateDividedRunHistoryItem({ run, previousDate }) {
10022
10053
  const [, setLocation] = useAppLocation();
10023
10054
  const queryClient = useQueryClient();
10055
+ const { apiClient } = useApiConfig();
10024
10056
  const { showRunId, runId } = useRecceActionContext();
10025
10057
  const currentDate = new Date(run.run_at).toDateString();
10026
10058
  const shouldRenderDateSegment = previousDate != null && previousDate !== currentDate;
@@ -10029,10 +10061,14 @@ function DateDividedRunHistoryItem({ run, previousDate }) {
10029
10061
  showRunId(runId$1, false);
10030
10062
  };
10031
10063
  const handleAddToChecklist = useCallback(async (clickedRunId) => {
10032
- const check = await createCheckByRun(clickedRunId);
10064
+ const check = await createCheckByRun(clickedRunId, void 0, apiClient);
10033
10065
  await queryClient.invalidateQueries({ queryKey: cacheKeys.checks() });
10034
10066
  setLocation(`/checks/?id=${check.check_id}`);
10035
- }, [setLocation, queryClient]);
10067
+ }, [
10068
+ setLocation,
10069
+ queryClient,
10070
+ apiClient
10071
+ ]);
10036
10072
  const handleGoToCheck = useCallback((checkId) => {
10037
10073
  trackHistoryAction({ name: "go_to_check" });
10038
10074
  setLocation(`/checks/?id=${checkId}`);
@@ -10397,6 +10433,125 @@ function SummaryView() {
10397
10433
  }) });
10398
10434
  }
10399
10435
 
10436
+ //#endregion
10437
+ //#region recce-source/js/src/components/app/AvatarDropdown.tsx
10438
+ function AvatarDropdown() {
10439
+ const { apiClient } = useApiConfig();
10440
+ const { data: user, isLoading, error } = useQuery({
10441
+ queryKey: cacheKeys.user(),
10442
+ queryFn: () => fetchUser(apiClient),
10443
+ retry: false
10444
+ });
10445
+ const { data: avatarUrl } = useQuery({
10446
+ queryKey: ["github-avatar", user?.id],
10447
+ queryFn: () => user ? fetchGitHubAvatar(user.id) : Promise.resolve(null),
10448
+ enabled: !!user?.id && user.login_type === "github",
10449
+ retry: false,
10450
+ staleTime: 300 * 1e3
10451
+ });
10452
+ const [anchorEl, setAnchorEl] = useState(null);
10453
+ const open = Boolean(anchorEl);
10454
+ const handleClick = (event) => {
10455
+ setAnchorEl(event.currentTarget);
10456
+ };
10457
+ const handleClose = () => {
10458
+ setAnchorEl(null);
10459
+ };
10460
+ const showUserInfo = !isLoading && !error && user;
10461
+ const getInitials = (name) => {
10462
+ if (!name) return "U";
10463
+ return name.charAt(0).toUpperCase();
10464
+ };
10465
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [isLoading ? /* @__PURE__ */ jsx(Box, {
10466
+ onClick: handleClick,
10467
+ sx: {
10468
+ width: 32,
10469
+ height: 32,
10470
+ borderRadius: "50%",
10471
+ bgcolor: "background.paper",
10472
+ color: "primary.main",
10473
+ display: "flex",
10474
+ alignItems: "center",
10475
+ justifyContent: "center",
10476
+ cursor: "pointer"
10477
+ },
10478
+ children: /* @__PURE__ */ jsx(CircularProgress, { size: 16 })
10479
+ }) : /* @__PURE__ */ jsx(MuiAvatar, {
10480
+ onClick: handleClick,
10481
+ src: avatarUrl || void 0,
10482
+ sx: {
10483
+ width: 28,
10484
+ height: 28,
10485
+ cursor: "pointer",
10486
+ outline: "1px solid white",
10487
+ fontSize: "0.875rem"
10488
+ },
10489
+ children: getInitials(user?.login)
10490
+ }), /* @__PURE__ */ jsxs(Menu, {
10491
+ anchorEl,
10492
+ open,
10493
+ onClose: handleClose,
10494
+ slotProps: { paper: { sx: {
10495
+ bgcolor: "background.paper",
10496
+ borderColor: "divider",
10497
+ boxShadow: 3,
10498
+ minWidth: 180
10499
+ } } },
10500
+ children: [
10501
+ /* @__PURE__ */ jsxs(Box, {
10502
+ sx: {
10503
+ px: 2,
10504
+ py: 1.5
10505
+ },
10506
+ children: [
10507
+ isLoading && /* @__PURE__ */ jsxs(Box, {
10508
+ sx: {
10509
+ display: "flex",
10510
+ alignItems: "center",
10511
+ gap: 1
10512
+ },
10513
+ children: [/* @__PURE__ */ jsx(Typography, {
10514
+ variant: "body2",
10515
+ color: "text.primary",
10516
+ children: "Loading..."
10517
+ }), /* @__PURE__ */ jsx(CircularProgress, { size: 16 })]
10518
+ }),
10519
+ error && /* @__PURE__ */ jsx(Typography, {
10520
+ variant: "caption",
10521
+ color: "error",
10522
+ children: "Failed to load user information"
10523
+ }),
10524
+ showUserInfo && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Typography, {
10525
+ variant: "body2",
10526
+ fontWeight: "600",
10527
+ color: "text.primary",
10528
+ children: user.login
10529
+ }), user.email && /* @__PURE__ */ jsx(Typography, {
10530
+ variant: "caption",
10531
+ color: "text.secondary",
10532
+ children: user.email
10533
+ })] })
10534
+ ]
10535
+ }),
10536
+ /* @__PURE__ */ jsx(Divider, {}),
10537
+ /* @__PURE__ */ jsxs(MenuItem, {
10538
+ onClick: () => {
10539
+ window.open("https://cloud.datarecce.io/", "_blank");
10540
+ handleClose();
10541
+ },
10542
+ children: [/* @__PURE__ */ jsx(ListItemIcon, { children: /* @__PURE__ */ jsx(FaCloud, {}) }), /* @__PURE__ */ jsx(ListItemText, { children: "Recce Cloud" })]
10543
+ }),
10544
+ /* @__PURE__ */ jsxs(MenuItem, {
10545
+ onClick: () => {
10546
+ window.open(RECCE_SUPPORT_CALENDAR_URL, "_blank");
10547
+ handleClose();
10548
+ },
10549
+ children: [/* @__PURE__ */ jsx(ListItemIcon, { children: /* @__PURE__ */ jsx(FaUser, {}) }), /* @__PURE__ */ jsx(ListItemText, { children: "Get live support" })]
10550
+ })
10551
+ ]
10552
+ })] });
10553
+ }
10554
+
10400
10555
  //#endregion
10401
10556
  //#region recce-source/js/src/components/timeout/IdleTimeoutBadge.tsx
10402
10557
  /**
@@ -10434,5 +10589,1134 @@ function IdleTimeoutBadge() {
10434
10589
  }
10435
10590
 
10436
10591
  //#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
10592
+ //#region recce-source/js/app/(mainComponents)/DisplayModeToggle.tsx
10593
+ /**
10594
+ * Display Mode Toggle - switches between light and dark themes
10595
+ *
10596
+ * Uses next-themes to persist the user's preference.
10597
+ * Default is light theme, with future support for system preference.
10598
+ */
10599
+ function DisplayModeToggle() {
10600
+ const { setTheme, resolvedTheme } = useTheme$1();
10601
+ const [mounted, setMounted] = useState(false);
10602
+ useEffect(() => {
10603
+ setMounted(true);
10604
+ }, []);
10605
+ const toggleTheme = () => {
10606
+ setTheme(resolvedTheme === "dark" ? "light" : "dark");
10607
+ };
10608
+ if (!mounted) return /* @__PURE__ */ jsx(IconButton, {
10609
+ size: "small",
10610
+ sx: {
10611
+ color: "rgba(255, 255, 255, 0.8)",
10612
+ "&:hover": { bgcolor: "rgba(255, 255, 255, 0.1)" }
10613
+ },
10614
+ disabled: true,
10615
+ children: /* @__PURE__ */ jsx(PiSun, { style: {
10616
+ width: 18,
10617
+ height: 18
10618
+ } })
10619
+ });
10620
+ const isDark = resolvedTheme === "dark";
10621
+ return /* @__PURE__ */ jsx(MuiTooltip, {
10622
+ title: isDark ? "Switch to light mode" : "Switch to dark mode",
10623
+ children: /* @__PURE__ */ jsx(IconButton, {
10624
+ size: "small",
10625
+ onClick: toggleTheme,
10626
+ sx: {
10627
+ color: "rgba(255, 255, 255, 0.8)",
10628
+ "&:hover": { bgcolor: "rgba(255, 255, 255, 0.1)" }
10629
+ },
10630
+ "aria-label": isDark ? "Switch to light mode" : "Switch to dark mode",
10631
+ children: isDark ? /* @__PURE__ */ jsx(PiSun, { style: {
10632
+ width: 18,
10633
+ height: 18
10634
+ } }) : /* @__PURE__ */ jsx(PiMoon, { style: {
10635
+ width: 18,
10636
+ height: 18
10637
+ } })
10638
+ })
10639
+ });
10640
+ }
10641
+
10642
+ //#endregion
10643
+ //#region recce-source/js/app/(mainComponents)/RecceVersionBadge.tsx
10644
+ function RecceVersionBadge() {
10645
+ const { version, latestVersion } = useVersionNumber();
10646
+ const versionFormatRegex = useMemo(() => /* @__PURE__ */ new RegExp("^\\d+\\.\\d+\\.\\d+$"), []);
10647
+ useEffect(() => {
10648
+ if (versionFormatRegex.test(version) && version !== latestVersion) {
10649
+ const storageKey = "recce-update-toast-shown";
10650
+ if (sessionStorage.getItem(storageKey)) return;
10651
+ setTimeout(() => {
10652
+ toaster.create({
10653
+ id: "recce-update-available",
10654
+ title: "Update available",
10655
+ description: /* @__PURE__ */ jsxs("span", { children: [
10656
+ "A new version of Recce (v",
10657
+ latestVersion,
10658
+ ") is available.",
10659
+ /* @__PURE__ */ jsx("br", {}),
10660
+ "Please run",
10661
+ " ",
10662
+ /* @__PURE__ */ jsx(Box, {
10663
+ component: "code",
10664
+ sx: {
10665
+ bgcolor: "grey.200",
10666
+ px: .5,
10667
+ py: .25,
10668
+ borderRadius: .5,
10669
+ fontFamily: "monospace",
10670
+ fontSize: "0.875em"
10671
+ },
10672
+ children: "pip install --upgrade recce"
10673
+ }),
10674
+ " ",
10675
+ "to update Recce.",
10676
+ /* @__PURE__ */ jsx("br", {}),
10677
+ /* @__PURE__ */ jsx(Link, {
10678
+ sx: {
10679
+ color: "primary.main",
10680
+ fontWeight: "bold",
10681
+ "&:hover": { textDecoration: "underline" }
10682
+ },
10683
+ href: `https://github.com/DataRecce/recce/releases/tag/v${latestVersion}`,
10684
+ target: "_blank",
10685
+ children: "Click here to view the detail of latest release"
10686
+ })
10687
+ ] }),
10688
+ duration: 60 * 1e3,
10689
+ closable: true
10690
+ });
10691
+ sessionStorage.setItem(storageKey, "true");
10692
+ }, 0);
10693
+ }
10694
+ }, [
10695
+ version,
10696
+ latestVersion,
10697
+ versionFormatRegex
10698
+ ]);
10699
+ if (!versionFormatRegex.test(version)) return /* @__PURE__ */ jsx(Typography, {
10700
+ component: "span",
10701
+ sx: {
10702
+ fontSize: "sm",
10703
+ color: "rgba(255,255,255,0.8)",
10704
+ textTransform: "uppercase",
10705
+ borderWidth: 1,
10706
+ px: 1,
10707
+ borderRadius: .75
10708
+ },
10709
+ children: version
10710
+ });
10711
+ return /* @__PURE__ */ jsx(Link, {
10712
+ href: `https://github.com/DataRecce/recce/releases/tag/v${version}`,
10713
+ sx: {
10714
+ "&:hover": { textDecoration: "none" },
10715
+ fontSize: "sm",
10716
+ color: "rgba(255,255,255,0.8)",
10717
+ textTransform: "uppercase",
10718
+ borderWidth: 1,
10719
+ px: 1,
10720
+ borderRadius: .75
10721
+ },
10722
+ target: "_blank",
10723
+ children: version
10724
+ });
10725
+ }
10726
+
10727
+ //#endregion
10728
+ //#region recce-source/js/app/(mainComponents)/TopBar.tsx
10729
+ function LinkIcon({ icon: IconComponent, href, sx, ...props }) {
10730
+ const theme = useTheme();
10731
+ return /* @__PURE__ */ jsx(Link, {
10732
+ sx: {
10733
+ height: "20px",
10734
+ color: "common.white",
10735
+ ...sx
10736
+ },
10737
+ href,
10738
+ target: "_blank",
10739
+ ...props,
10740
+ children: /* @__PURE__ */ jsx(IconComponent, { style: {
10741
+ color: theme.palette.common.white,
10742
+ width: 20,
10743
+ height: 20
10744
+ } })
10745
+ });
10746
+ }
10747
+ function TopBar() {
10748
+ const { reviewMode, isDemoSite, envInfo, cloudMode } = useLineageGraphContext();
10749
+ const { featureToggles, authed } = useRecceInstanceContext();
10750
+ const { url: prURL, id: prID } = envInfo?.pullRequest ?? {};
10751
+ const demoPrId = prURL ? prURL.split("/").pop() : null;
10752
+ const brandLink = cloudMode || authed ? "https://cloud.datarecce.io/" : "https://reccehq.com/";
10753
+ const [showModal, setShowModal] = useState(false);
10754
+ return /* @__PURE__ */ jsxs(Box, {
10755
+ sx: {
10756
+ display: "flex",
10757
+ gap: "10px",
10758
+ minHeight: "40px",
10759
+ alignItems: "center",
10760
+ bgcolor: colors.brand[400]
10761
+ },
10762
+ children: [
10763
+ /* @__PURE__ */ jsx(Link, {
10764
+ href: brandLink,
10765
+ target: "_blank",
10766
+ sx: { "&:hover": { textDecoration: "none" } },
10767
+ children: /* @__PURE__ */ jsxs(Box, {
10768
+ sx: {
10769
+ display: "flex",
10770
+ gap: "10px",
10771
+ alignItems: "center"
10772
+ },
10773
+ children: [/* @__PURE__ */ jsx(Box, {
10774
+ component: "img",
10775
+ sx: {
10776
+ width: 20,
10777
+ height: 20,
10778
+ ml: "18px"
10779
+ },
10780
+ src: "/logo/recce-logo-white.png",
10781
+ alt: "recce-logo-white"
10782
+ }), /* @__PURE__ */ jsx(Typography, {
10783
+ variant: "h4",
10784
+ sx: {
10785
+ fontFamily: "\"Montserrat\", sans-serif",
10786
+ color: "common.white",
10787
+ fontSize: "1.25rem"
10788
+ },
10789
+ children: "RECCE"
10790
+ })]
10791
+ })
10792
+ }),
10793
+ /* @__PURE__ */ jsx(DisplayModeToggle, {}),
10794
+ /* @__PURE__ */ jsx(RecceVersionBadge, {}),
10795
+ (featureToggles.mode ?? reviewMode) && /* @__PURE__ */ jsx(Badge, {
10796
+ sx: {
10797
+ fontSize: "0.875rem",
10798
+ color: "rgba(255,255,255,0.8)",
10799
+ textTransform: "uppercase",
10800
+ borderWidth: 1,
10801
+ px: 1,
10802
+ borderRadius: .75,
10803
+ borderColor: "rgba(255,255,255,0.8)"
10804
+ },
10805
+ children: featureToggles.mode ?? "review mode"
10806
+ }),
10807
+ cloudMode && prID && /* @__PURE__ */ jsx(Badge, {
10808
+ sx: {
10809
+ fontSize: "0.875rem",
10810
+ color: "rgba(255,255,255,0.8)",
10811
+ textTransform: "uppercase",
10812
+ borderWidth: 1,
10813
+ px: 1,
10814
+ borderRadius: .75,
10815
+ borderColor: "rgba(255,255,255,0.8)"
10816
+ },
10817
+ children: /* @__PURE__ */ jsxs(Stack, {
10818
+ direction: "row",
10819
+ spacing: 1,
10820
+ alignItems: "center",
10821
+ children: [/* @__PURE__ */ jsx(Box, { children: "cloud mode" }), /* @__PURE__ */ jsx(Box, {
10822
+ sx: {
10823
+ borderLeft: "1px solid rgba(255,255,255,0.8)",
10824
+ pl: "8px"
10825
+ },
10826
+ children: /* @__PURE__ */ jsxs(Link, {
10827
+ href: prURL,
10828
+ sx: { "&:hover": { textDecoration: "none" } },
10829
+ target: "_blank",
10830
+ children: [/* @__PURE__ */ jsx(VscGitPullRequest, { style: {
10831
+ color: "rgba(255,255,255,0.8)",
10832
+ width: 12,
10833
+ height: 12,
10834
+ marginRight: 2,
10835
+ display: "inline",
10836
+ verticalAlign: "middle"
10837
+ } }), /* @__PURE__ */ jsx(Typography, {
10838
+ component: "span",
10839
+ sx: {
10840
+ color: "rgba(255,255,255,0.8)",
10841
+ display: "inline"
10842
+ },
10843
+ children: `#${String(prID)}`
10844
+ })]
10845
+ })
10846
+ })]
10847
+ })
10848
+ }),
10849
+ isDemoSite && prURL && demoPrId && /* @__PURE__ */ jsx(Badge, {
10850
+ sx: {
10851
+ fontSize: "0.875rem",
10852
+ color: "rgba(255,255,255,0.8)",
10853
+ textTransform: "uppercase",
10854
+ borderWidth: 1,
10855
+ px: 1,
10856
+ borderRadius: .75,
10857
+ borderColor: "rgba(255,255,255,0.8)"
10858
+ },
10859
+ children: /* @__PURE__ */ jsxs(Stack, {
10860
+ direction: "row",
10861
+ spacing: 1,
10862
+ alignItems: "center",
10863
+ children: [/* @__PURE__ */ jsx(Box, { children: "demo mode" }), /* @__PURE__ */ jsx(Box, {
10864
+ sx: {
10865
+ borderLeft: "1px solid rgba(255,255,255,0.8)",
10866
+ pl: "8px"
10867
+ },
10868
+ children: /* @__PURE__ */ jsxs(Link, {
10869
+ href: prURL,
10870
+ sx: { "&:hover": { textDecoration: "none" } },
10871
+ target: "_blank",
10872
+ children: [/* @__PURE__ */ jsx(VscGitPullRequest, { style: {
10873
+ color: "rgba(255,255,255,0.8)",
10874
+ width: 12,
10875
+ height: 12,
10876
+ marginRight: 2,
10877
+ display: "inline",
10878
+ verticalAlign: "middle"
10879
+ } }), /* @__PURE__ */ jsx(Typography, {
10880
+ component: "span",
10881
+ sx: {
10882
+ color: "rgba(255,255,255,0.8)",
10883
+ display: "inline"
10884
+ },
10885
+ children: `#${demoPrId}`
10886
+ })]
10887
+ })
10888
+ })]
10889
+ })
10890
+ }),
10891
+ /* @__PURE__ */ jsx(Box, { sx: { flex: 1 } }),
10892
+ (isDemoSite || featureToggles.mode === "read only") && /* @__PURE__ */ jsxs(Fragment$1, { children: [
10893
+ /* @__PURE__ */ jsx(LinkIcon, {
10894
+ icon: FaGithub,
10895
+ href: "https://github.com/DataRecce/recce"
10896
+ }),
10897
+ /* @__PURE__ */ jsx(LinkIcon, {
10898
+ icon: FaSlack,
10899
+ href: "https://getdbt.slack.com/archives/C05C28V7CPP"
10900
+ }),
10901
+ /* @__PURE__ */ jsx(LinkIcon, {
10902
+ sx: { mr: 2 },
10903
+ icon: FaQuestionCircle,
10904
+ href: "https://docs.datarecce.io"
10905
+ })
10906
+ ] }),
10907
+ !isDemoSite && featureToggles.mode !== "read only" && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(IdleTimeoutBadge, {}), authed || cloudMode ? /* @__PURE__ */ jsx(Box, {
10908
+ sx: { mr: 2 },
10909
+ children: /* @__PURE__ */ jsx(AvatarDropdown, {})
10910
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Box, {
10911
+ component: "button",
10912
+ sx: {
10913
+ color: "common.white",
10914
+ fontSize: "0.875rem",
10915
+ fontWeight: 600,
10916
+ bgcolor: "brand.700",
10917
+ borderRadius: 1,
10918
+ px: 3,
10919
+ py: 1,
10920
+ mr: 2,
10921
+ cursor: "pointer",
10922
+ border: "none"
10923
+ },
10924
+ onClick: () => {
10925
+ setShowModal(true);
10926
+ },
10927
+ children: "Connect to Cloud"
10928
+ }), showModal && /* @__PURE__ */ jsx(AuthModal, {
10929
+ parentOpen: showModal,
10930
+ handleParentClose: setShowModal,
10931
+ ignoreCookie: true,
10932
+ variant: "user-profile"
10933
+ })] })] })
10934
+ ]
10935
+ });
10936
+ }
10937
+
10938
+ //#endregion
10939
+ //#region recce-source/js/src/components/app/Filename.tsx
10940
+ const useRecceToast = () => {
10941
+ const toastSuccess = (message) => {
10942
+ toaster.create({
10943
+ description: message,
10944
+ type: "success",
10945
+ duration: 5e3,
10946
+ closable: true
10947
+ });
10948
+ };
10949
+ const toastError = (message, error) => {
10950
+ let errorMessage = message;
10951
+ if (error != null) if (error instanceof AxiosError) errorMessage = `${message}. ${String(error.response?.data?.detail)}`;
10952
+ else errorMessage = `${message}. ${error}`;
10953
+ toaster.create({
10954
+ description: errorMessage,
10955
+ type: "error",
10956
+ duration: 5e3,
10957
+ closable: true
10958
+ });
10959
+ };
10960
+ return {
10961
+ toastSuccess,
10962
+ toastError
10963
+ };
10964
+ };
10965
+ const useClosePrompt = (prompt) => {
10966
+ useEffect(() => {
10967
+ const handleBeforeUnload = (e) => {
10968
+ e.preventDefault();
10969
+ };
10970
+ if (prompt) window.addEventListener("beforeunload", handleBeforeUnload);
10971
+ return () => {
10972
+ if (prompt) window.removeEventListener("beforeunload", handleBeforeUnload);
10973
+ };
10974
+ }, [prompt]);
10975
+ };
10976
+ const Filename = () => {
10977
+ const { featureToggles } = useRecceInstanceContext();
10978
+ const { fileName, cloudMode, isDemoSite, envInfo } = useLineageGraphContext();
10979
+ const { apiClient } = useApiConfig();
10980
+ const [modalOpen, setModalOpen] = useState(false);
10981
+ const [overwriteOpen, setOverwriteOpen] = useState(false);
10982
+ const isStateless = !fileName && !cloudMode && !isDemoSite;
10983
+ const { data: checks } = useChecks(isStateless);
10984
+ const hasNonPresetChecks = checks != void 0 && checks.filter((check) => !check.is_preset).length > 0;
10985
+ useClosePrompt(isStateless && hasNonPresetChecks);
10986
+ const [{ newFileName, errorMessage, modified, overwriteWithMethod, bypass }, setState] = useState({ newFileName: fileName ?? "recce_state.json" });
10987
+ const inputRef = useRef(null);
10988
+ const { toastSuccess, toastError } = useRecceToast();
10989
+ const queryClient = useQueryClient();
10990
+ const handleOpen = () => {
10991
+ setState({
10992
+ newFileName: fileName ?? "recce_state.json",
10993
+ modified: !fileName
10994
+ });
10995
+ setModalOpen(true);
10996
+ };
10997
+ const handleModalClose = () => setModalOpen(false);
10998
+ const handleOverwriteClose = () => setOverwriteOpen(false);
10999
+ const handleAction = async (method, overwrite) => {
11000
+ if (!newFileName) return;
11001
+ const bypassOverwrite = localStorage.getItem(localStorageKeys.bypassSaveOverwrite) === "true";
11002
+ try {
11003
+ if (method === "save") await saveAs$1({
11004
+ filename: newFileName,
11005
+ overwrite: overwrite ?? bypassOverwrite
11006
+ }, apiClient);
11007
+ else await rename({
11008
+ filename: newFileName,
11009
+ overwrite: overwrite ?? bypassOverwrite
11010
+ }, apiClient);
11011
+ toastSuccess(method === "save" ? "Save file successfully" : "Rename file successfully");
11012
+ await queryClient.invalidateQueries({ queryKey: cacheKeys.lineage() });
11013
+ if (bypass) localStorage.setItem(localStorageKeys.bypassSaveOverwrite, "true");
11014
+ } catch (error) {
11015
+ if (error instanceof AxiosError) {
11016
+ if (error.response?.status === 409) {
11017
+ setState((s) => ({
11018
+ ...s,
11019
+ overwriteWithMethod: method
11020
+ }));
11021
+ setOverwriteOpen(true);
11022
+ return;
11023
+ }
11024
+ }
11025
+ toastError(method === "save" ? "Save file failed" : "Rename file failed", error);
11026
+ } finally {
11027
+ handleModalClose();
11028
+ }
11029
+ };
11030
+ const handleOvewriteBack = () => {
11031
+ handleOverwriteClose();
11032
+ setModalOpen(true);
11033
+ setState((s) => {
11034
+ return {
11035
+ ...s,
11036
+ overwriteWithMethod: void 0
11037
+ };
11038
+ });
11039
+ };
11040
+ if (cloudMode || isDemoSite) return /* @__PURE__ */ jsx(Fragment$1, {});
11041
+ const titleNewInstance = "New Instance" + (hasNonPresetChecks ? " (unsaved)" : "");
11042
+ let titleReadOnlyState;
11043
+ if (featureToggles.disableSaveToFile && fileName) {
11044
+ const generatedAt = envInfo?.stateMetadata?.generated_at;
11045
+ const formattedDate = generatedAt ? formatRunDateTime(new Date(generatedAt)) : null;
11046
+ titleReadOnlyState = formattedDate ? `${fileName} (${formattedDate})` : null;
11047
+ }
11048
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
11049
+ /* @__PURE__ */ jsxs(Stack, {
11050
+ direction: "row",
11051
+ alignItems: "center",
11052
+ justifyContent: "center",
11053
+ children: [/* @__PURE__ */ jsx(Box, {
11054
+ sx: { fontWeight: 600 },
11055
+ children: titleReadOnlyState ?? fileName ?? titleNewInstance
11056
+ }), !featureToggles.disableSaveToFile && /* @__PURE__ */ jsx(MuiTooltip, {
11057
+ title: fileName ? "Change Filename" : "Save",
11058
+ enterDelay: 1e3,
11059
+ children: /* @__PURE__ */ jsx(IconButton, {
11060
+ onClick: handleOpen,
11061
+ "aria-label": fileName ? "Change Filename" : "Save",
11062
+ size: "small",
11063
+ children: /* @__PURE__ */ jsx(Box, {
11064
+ component: fileName ? IconEdit : IconSave,
11065
+ sx: {
11066
+ fontSize: 16,
11067
+ verticalAlign: "middle"
11068
+ }
11069
+ })
11070
+ })
11071
+ })]
11072
+ }),
11073
+ /* @__PURE__ */ jsxs(MuiDialog, {
11074
+ open: modalOpen,
11075
+ onClose: handleModalClose,
11076
+ children: [
11077
+ /* @__PURE__ */ jsxs(DialogTitle, {
11078
+ sx: {
11079
+ display: "flex",
11080
+ alignItems: "center"
11081
+ },
11082
+ children: [
11083
+ fileName ? "Change Filename" : "Save File",
11084
+ /* @__PURE__ */ jsx(Box, { sx: { flexGrow: 1 } }),
11085
+ /* @__PURE__ */ jsx(IconButton, {
11086
+ size: "small",
11087
+ onClick: handleModalClose,
11088
+ children: /* @__PURE__ */ jsx(IoClose, {})
11089
+ })
11090
+ ]
11091
+ }),
11092
+ /* @__PURE__ */ jsx(DialogContent, {
11093
+ onKeyDown: (e) => {
11094
+ e.stopPropagation();
11095
+ },
11096
+ children: /* @__PURE__ */ jsx(TextField, {
11097
+ inputRef,
11098
+ value: newFileName,
11099
+ label: "File name",
11100
+ placeholder: "Enter filename",
11101
+ error: !!errorMessage,
11102
+ helperText: errorMessage,
11103
+ fullWidth: true,
11104
+ size: "small",
11105
+ sx: { mt: 1 },
11106
+ onChange: (e) => {
11107
+ const value = e.target.value;
11108
+ let newErrorMessage = void 0;
11109
+ if (!value) newErrorMessage = "Filename cannot be empty.";
11110
+ else if (!value.endsWith(".json")) newErrorMessage = "Filename must end with .json.";
11111
+ else if (!/^[a-zA-Z0-9 _-]+\.json$/.test(value)) newErrorMessage = "Invalid filename. Only alphanumeric, space, _ and - are allowed.";
11112
+ else if (fileName && value === fileName) newErrorMessage = "Filename is the same as the current one.";
11113
+ setState((s) => {
11114
+ return {
11115
+ ...s,
11116
+ modified: true,
11117
+ newFileName: value,
11118
+ errorMessage: newErrorMessage
11119
+ };
11120
+ });
11121
+ },
11122
+ onKeyDown: (e) => {
11123
+ if (e.key === "Enter") {
11124
+ if (errorMessage) return;
11125
+ if (!fileName) handleAction("save");
11126
+ else handleAction("rename");
11127
+ } else if (e.key === "Escape") handleModalClose();
11128
+ }
11129
+ })
11130
+ }),
11131
+ /* @__PURE__ */ jsxs(DialogActions, {
11132
+ sx: { gap: "5px" },
11133
+ children: [/* @__PURE__ */ jsx(Button, {
11134
+ size: "small",
11135
+ color: fileName ? "inherit" : "iochmara",
11136
+ variant: "contained",
11137
+ onClick: async () => {
11138
+ await handleAction("save");
11139
+ },
11140
+ disabled: !newFileName || !!errorMessage || !modified,
11141
+ children: fileName ? "Save as New File" : "Confirm"
11142
+ }), fileName && /* @__PURE__ */ jsx(Button, {
11143
+ size: "small",
11144
+ color: "iochmara",
11145
+ variant: "contained",
11146
+ onClick: async () => {
11147
+ await handleAction("rename");
11148
+ },
11149
+ disabled: !newFileName || !!errorMessage || !modified,
11150
+ children: "Rename"
11151
+ })]
11152
+ })
11153
+ ]
11154
+ }),
11155
+ /* @__PURE__ */ jsxs(MuiDialog, {
11156
+ open: overwriteOpen,
11157
+ onClose: handleOverwriteClose,
11158
+ children: [
11159
+ /* @__PURE__ */ jsxs(DialogTitle, {
11160
+ sx: {
11161
+ display: "flex",
11162
+ alignItems: "center"
11163
+ },
11164
+ children: [
11165
+ "Overwrite File?",
11166
+ /* @__PURE__ */ jsx(Box, { sx: { flexGrow: 1 } }),
11167
+ /* @__PURE__ */ jsx(IconButton, {
11168
+ size: "small",
11169
+ onClick: handleOverwriteClose,
11170
+ children: /* @__PURE__ */ jsx(IoClose, {})
11171
+ })
11172
+ ]
11173
+ }),
11174
+ /* @__PURE__ */ jsxs(DialogContent, {
11175
+ sx: {
11176
+ borderTop: "solid 1px",
11177
+ borderBottom: "solid 1px",
11178
+ borderColor: "divider"
11179
+ },
11180
+ onKeyDown: (e) => {
11181
+ e.stopPropagation();
11182
+ },
11183
+ children: [/* @__PURE__ */ jsx(Typography, {
11184
+ sx: { fontSize: "12pt" },
11185
+ 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?"
11186
+ }), /* @__PURE__ */ jsx(FormControlLabel, {
11187
+ control: /* @__PURE__ */ jsx(Checkbox, {
11188
+ size: "small",
11189
+ checked: bypass,
11190
+ onChange: (e) => {
11191
+ setState((s) => ({
11192
+ ...s,
11193
+ bypass: e.target.checked
11194
+ }));
11195
+ }
11196
+ }),
11197
+ label: /* @__PURE__ */ jsx(Typography, {
11198
+ sx: {
11199
+ fontWeight: "bold",
11200
+ pt: "8px"
11201
+ },
11202
+ children: "Don't show this again"
11203
+ })
11204
+ })]
11205
+ }),
11206
+ /* @__PURE__ */ jsxs(DialogActions, {
11207
+ sx: { gap: "5px" },
11208
+ children: [/* @__PURE__ */ jsx(Button, {
11209
+ variant: "outlined",
11210
+ onClick: handleOvewriteBack,
11211
+ size: "small",
11212
+ children: "Back"
11213
+ }), /* @__PURE__ */ jsx(Button, {
11214
+ size: "small",
11215
+ color: "iochmara",
11216
+ variant: "contained",
11217
+ onClick: () => {
11218
+ if (!overwriteWithMethod) return;
11219
+ handleAction(overwriteWithMethod, true);
11220
+ handleOverwriteClose();
11221
+ },
11222
+ children: "Overwrite"
11223
+ })]
11224
+ })
11225
+ ]
11226
+ })
11227
+ ] });
11228
+ };
11229
+
11230
+ //#endregion
11231
+ //#region recce-source/js/src/components/app/StateExporter.tsx
11232
+ function StateExporter() {
11233
+ const { featureToggles } = useRecceInstanceContext();
11234
+ const { apiClient } = useApiConfig();
11235
+ const handleExport = async () => {
11236
+ try {
11237
+ const jsonData = await exportState(apiClient);
11238
+ const jsonString = JSON.stringify(jsonData, null, 2);
11239
+ saveAs(new Blob([jsonString], { type: "application/json" }), `recce-state-${format(/* @__PURE__ */ new Date(), "yyyy-MM-dd-HH-mm-ss")}.json`);
11240
+ } catch (error) {
11241
+ console.error("Export failed", error);
11242
+ toaster.create({
11243
+ title: "Export failed",
11244
+ description: String(error),
11245
+ type: "error",
11246
+ duration: 5e3,
11247
+ closable: true
11248
+ });
11249
+ }
11250
+ };
11251
+ return /* @__PURE__ */ jsx(MuiTooltip, {
11252
+ title: "Export",
11253
+ children: /* @__PURE__ */ jsx(IconButton, {
11254
+ size: "small",
11255
+ "aria-label": "Export state",
11256
+ onClick: async () => {
11257
+ await handleExport();
11258
+ trackStateAction({ name: "export" });
11259
+ },
11260
+ disabled: featureToggles.disableExportStateFile,
11261
+ children: /* @__PURE__ */ jsx(Box, {
11262
+ component: IconExport,
11263
+ sx: {
11264
+ verticalAlign: "middle",
11265
+ width: "16px",
11266
+ height: "16px"
11267
+ }
11268
+ })
11269
+ })
11270
+ });
11271
+ }
11272
+
11273
+ //#endregion
11274
+ //#region recce-source/js/src/components/app/StateSharing.tsx
11275
+ const LOADING_MESSAGES = [
11276
+ "Processing...",
11277
+ "Still processing, please wait...",
11278
+ "Almost there, thanks for your patience..."
11279
+ ];
11280
+ function TopLevelShare() {
11281
+ const { successToast, failToast } = useClipBoardToast();
11282
+ const [, copyToClipboard] = useCopyToClipboard();
11283
+ const { authed } = useRecceInstanceContext();
11284
+ const { shareUrl, isLoading, error, handleShareClick } = useRecceShareStateContext();
11285
+ const [showModal, setShowModal] = useState(false);
11286
+ const [messageIndex, setMessageIndex] = useState(0);
11287
+ const [prevIsLoading, setPrevIsLoading] = useState(isLoading);
11288
+ if (isLoading !== prevIsLoading) {
11289
+ setPrevIsLoading(isLoading);
11290
+ if (isLoading) setMessageIndex(0);
11291
+ }
11292
+ useInterval(() => {
11293
+ setMessageIndex((prev) => Math.min(prev + 1, LOADING_MESSAGES.length - 1));
11294
+ }, isLoading ? 3e4 : null);
11295
+ useEffect(() => {
11296
+ if (error) failToast("Failed to share state", error);
11297
+ }, [error, failToast]);
11298
+ const handleCopy = async () => {
11299
+ try {
11300
+ await copyToClipboard(String(shareUrl));
11301
+ successToast("Copied the link to clipboard");
11302
+ } catch (error$1) {
11303
+ failToast("Failed to copy the link", error$1);
11304
+ }
11305
+ };
11306
+ if (!authed) return /* @__PURE__ */ jsxs(Stack, {
11307
+ direction: "row",
11308
+ sx: {
11309
+ flex: 1,
11310
+ alignItems: "center"
11311
+ },
11312
+ children: [/* @__PURE__ */ jsx(Button, {
11313
+ size: "xsmall",
11314
+ color: "neutral",
11315
+ variant: "outlined",
11316
+ onClick: () => {
11317
+ setShowModal(true);
11318
+ },
11319
+ startIcon: /* @__PURE__ */ jsx(TbCloudUpload, {}),
11320
+ children: "Share"
11321
+ }), showModal && /* @__PURE__ */ jsx(AuthModal, {
11322
+ parentOpen: showModal,
11323
+ handleParentClose: setShowModal,
11324
+ ignoreCookie: true,
11325
+ variant: "enable-share"
11326
+ })]
11327
+ });
11328
+ return /* @__PURE__ */ jsxs(Stack, {
11329
+ direction: "row",
11330
+ sx: {
11331
+ flex: 1,
11332
+ alignItems: "center",
11333
+ gap: "5px"
11334
+ },
11335
+ children: [
11336
+ /* @__PURE__ */ jsx(Button, {
11337
+ size: "xsmall",
11338
+ variant: "outlined",
11339
+ color: "neutral",
11340
+ startIcon: /* @__PURE__ */ jsx(TbCloudUpload, {}),
11341
+ endIcon: shareUrl ? /* @__PURE__ */ jsx(Box, {
11342
+ component: PiCheckCircle,
11343
+ sx: { color: "success.main" }
11344
+ }) : void 0,
11345
+ onClick: async () => {
11346
+ await handleShareClick();
11347
+ trackShareState({ name: "create" });
11348
+ },
11349
+ disabled: isLoading,
11350
+ children: isLoading ? "Sharing..." : "Share"
11351
+ }),
11352
+ isLoading && /* @__PURE__ */ jsx(Typography, {
11353
+ sx: {
11354
+ fontSize: 14,
11355
+ color: "grey.500"
11356
+ },
11357
+ children: LOADING_MESSAGES[messageIndex]
11358
+ }),
11359
+ /* @__PURE__ */ jsx(Stack, {
11360
+ direction: "row",
11361
+ spacing: .5,
11362
+ alignItems: "center",
11363
+ children: shareUrl && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Box, {
11364
+ sx: {
11365
+ overflowX: "auto",
11366
+ whiteSpace: "nowrap",
11367
+ maxWidth: "350px"
11368
+ },
11369
+ children: /* @__PURE__ */ jsx(Typography, {
11370
+ sx: { fontSize: 14 },
11371
+ children: shareUrl
11372
+ })
11373
+ }), /* @__PURE__ */ jsx(IconButton, {
11374
+ size: "small",
11375
+ "aria-label": "Copy the share URL",
11376
+ onClick: async () => {
11377
+ await handleCopy();
11378
+ trackShareState({ name: "copy" });
11379
+ },
11380
+ children: /* @__PURE__ */ jsx(PiCopy, {})
11381
+ })] })
11382
+ })
11383
+ ]
11384
+ });
11385
+ }
11386
+
11387
+ //#endregion
11388
+ //#region recce-source/js/src/components/app/StateSynchronizer.tsx
11389
+ function isCheckDetailPage(href) {
11390
+ 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);
11391
+ }
11392
+ function StateSpinner() {
11393
+ return /* @__PURE__ */ jsx(MuiTooltip, {
11394
+ title: "Syncing",
11395
+ children: /* @__PURE__ */ jsx(Box, {
11396
+ sx: { mx: "10px" },
11397
+ children: /* @__PURE__ */ jsx(CircularProgress, { size: 20 })
11398
+ })
11399
+ });
11400
+ }
11401
+ function StateSynchronizer() {
11402
+ const [isSyncing, setSyncing] = useState(false);
11403
+ const queryClient = useQueryClient();
11404
+ const { apiClient } = useApiConfig();
11405
+ const [location, setLocation] = useAppLocation();
11406
+ const [open, setOpen] = useState(false);
11407
+ const [syncOption, setSyncOption] = useState("");
11408
+ const { data: instanceInfo } = useRecceInstanceInfo();
11409
+ const handleClose = () => setOpen(false);
11410
+ const handleSync = useCallback(async (input) => {
11411
+ setOpen(false);
11412
+ setSyncing(true);
11413
+ if ((await syncState(input, apiClient)).status === "conflict") {
11414
+ setOpen(true);
11415
+ setSyncing(false);
11416
+ return;
11417
+ }
11418
+ while (await isStateSyncing(apiClient)) await new Promise((resolve) => setTimeout(resolve, 1e3));
11419
+ toaster.create({
11420
+ description: "Sync Completed",
11421
+ type: "success",
11422
+ duration: 5e3,
11423
+ closable: true
11424
+ });
11425
+ setSyncing(false);
11426
+ setSyncOption("");
11427
+ await queryClient.invalidateQueries({ queryKey: cacheKeys.lineage() });
11428
+ await queryClient.invalidateQueries({ queryKey: cacheKeys.checks() });
11429
+ await queryClient.invalidateQueries({ queryKey: cacheKeys.runs() });
11430
+ if (isCheckDetailPage(location)) setLocation("/checks");
11431
+ }, [
11432
+ queryClient,
11433
+ location,
11434
+ setLocation,
11435
+ apiClient
11436
+ ]);
11437
+ if (isSyncing) return /* @__PURE__ */ jsx(StateSpinner, {});
11438
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(MuiTooltip, {
11439
+ title: "Sync with Cloud",
11440
+ children: /* @__PURE__ */ jsx(IconButton, {
11441
+ size: "small",
11442
+ "aria-label": "Sync state",
11443
+ onClick: () => handleSync(instanceInfo?.session_id ? { method: "merge" } : {}),
11444
+ children: /* @__PURE__ */ jsx(Box, {
11445
+ component: IconSync,
11446
+ sx: {
11447
+ fontSize: 16,
11448
+ verticalAlign: "middle"
11449
+ }
11450
+ })
11451
+ })
11452
+ }), /* @__PURE__ */ jsxs(MuiDialog, {
11453
+ open,
11454
+ onClose: handleClose,
11455
+ children: [
11456
+ /* @__PURE__ */ jsxs(DialogTitle, {
11457
+ sx: {
11458
+ display: "flex",
11459
+ alignItems: "center",
11460
+ fontWeight: "bold"
11461
+ },
11462
+ children: [
11463
+ "Sync with Cloud",
11464
+ /* @__PURE__ */ jsx(Box, { sx: { flexGrow: 1 } }),
11465
+ /* @__PURE__ */ jsx(IconButton, {
11466
+ size: "small",
11467
+ onClick: handleClose,
11468
+ children: /* @__PURE__ */ jsx(IoClose, {})
11469
+ })
11470
+ ]
11471
+ }),
11472
+ /* @__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, {
11473
+ sx: { mt: "5px" },
11474
+ children: /* @__PURE__ */ jsx(RadioGroup, {
11475
+ value: syncOption,
11476
+ onChange: (e) => {
11477
+ setSyncOption(e.target.value);
11478
+ },
11479
+ children: /* @__PURE__ */ jsxs(Stack, {
11480
+ direction: "column",
11481
+ children: [
11482
+ /* @__PURE__ */ jsx(FormControlLabel, {
11483
+ value: "merge",
11484
+ control: /* @__PURE__ */ jsx(Radio, {}),
11485
+ label: /* @__PURE__ */ jsxs(Stack, {
11486
+ direction: "row",
11487
+ alignItems: "center",
11488
+ children: ["Merge", /* @__PURE__ */ jsx(MuiTooltip, {
11489
+ title: "This will merge the local and remote states.",
11490
+ children: /* @__PURE__ */ jsx(Box, {
11491
+ component: PiInfo,
11492
+ sx: {
11493
+ ml: 2,
11494
+ cursor: "pointer"
11495
+ }
11496
+ })
11497
+ })]
11498
+ })
11499
+ }),
11500
+ /* @__PURE__ */ jsx(FormControlLabel, {
11501
+ value: "overwrite",
11502
+ control: /* @__PURE__ */ jsx(Radio, {}),
11503
+ label: /* @__PURE__ */ jsxs(Stack, {
11504
+ direction: "row",
11505
+ alignItems: "center",
11506
+ children: ["Overwrite", /* @__PURE__ */ jsx(MuiTooltip, {
11507
+ title: "This will overwrite the remote state file with the local state.",
11508
+ children: /* @__PURE__ */ jsx(Box, {
11509
+ component: PiInfo,
11510
+ sx: {
11511
+ ml: 2,
11512
+ cursor: "pointer"
11513
+ }
11514
+ })
11515
+ })]
11516
+ })
11517
+ }),
11518
+ /* @__PURE__ */ jsx(FormControlLabel, {
11519
+ value: "revert",
11520
+ control: /* @__PURE__ */ jsx(Radio, {}),
11521
+ label: /* @__PURE__ */ jsxs(Stack, {
11522
+ direction: "row",
11523
+ alignItems: "center",
11524
+ children: ["Revert", /* @__PURE__ */ jsx(MuiTooltip, {
11525
+ title: "This will discard local changes and revert to the cloud state.",
11526
+ children: /* @__PURE__ */ jsx(Box, {
11527
+ component: PiInfo,
11528
+ sx: {
11529
+ ml: 2,
11530
+ cursor: "pointer"
11531
+ }
11532
+ })
11533
+ })]
11534
+ })
11535
+ })
11536
+ ]
11537
+ })
11538
+ })
11539
+ })] }),
11540
+ /* @__PURE__ */ jsxs(DialogActions, { children: [/* @__PURE__ */ jsx(Button, {
11541
+ onClick: handleClose,
11542
+ sx: { mr: 1 },
11543
+ children: "Cancel"
11544
+ }), /* @__PURE__ */ jsx(Button, {
11545
+ color: "iochmara",
11546
+ variant: "contained",
11547
+ onClick: () => handleSync({ method: syncOption || void 0 }),
11548
+ disabled: !syncOption,
11549
+ children: "Sync"
11550
+ })] })
11551
+ ]
11552
+ })] });
11553
+ }
11554
+
11555
+ //#endregion
11556
+ //#region recce-source/js/app/(mainComponents)/NavBar.tsx
11557
+ /**
11558
+ * Route configuration for tabs
11559
+ */
11560
+ const ROUTE_CONFIG = [
11561
+ {
11562
+ path: "/lineage",
11563
+ name: "Lineage"
11564
+ },
11565
+ {
11566
+ path: "/query",
11567
+ name: "Query"
11568
+ },
11569
+ {
11570
+ path: "/checks",
11571
+ name: "Checklist"
11572
+ }
11573
+ ];
11574
+ function TabBadge({ queryKey, fetchCallback, selectCallback }) {
11575
+ const { data: count, isLoading, error } = useQuery({
11576
+ queryKey,
11577
+ queryFn: fetchCallback,
11578
+ select: selectCallback
11579
+ });
11580
+ if (isLoading || error || count === 0) return /* @__PURE__ */ jsx(Fragment$1, {});
11581
+ return /* @__PURE__ */ jsx(Box, {
11582
+ bgcolor: "brand.main",
11583
+ display: "flex",
11584
+ justifyContent: "center",
11585
+ alignItems: "center",
11586
+ p: 1,
11587
+ borderRadius: "100%",
11588
+ color: "white",
11589
+ fontWeight: 700,
11590
+ fontSize: "0.75rem",
11591
+ children: /* @__PURE__ */ jsx("span", { children: count })
11592
+ });
11593
+ }
11594
+ function ChecklistBadge() {
11595
+ return /* @__PURE__ */ jsx(TabBadge, {
11596
+ queryKey: cacheKeys.checks(),
11597
+ fetchCallback: listChecks,
11598
+ selectCallback: (checks) => {
11599
+ return checks.filter((check) => !check.is_checked).length;
11600
+ }
11601
+ });
11602
+ }
11603
+ function NavBar() {
11604
+ const pathname = usePathname();
11605
+ const { isDemoSite, isLoading, cloudMode } = useLineageGraphContext();
11606
+ const { featureToggles } = useRecceInstanceContext();
11607
+ const { data: flag, isLoading: isFlagLoading } = useRecceServerFlag();
11608
+ const prevPathnameRef = useRef(null);
11609
+ useEffect(() => {
11610
+ if (prevPathnameRef.current && prevPathnameRef.current !== pathname) trackNavigation({
11611
+ from: prevPathnameRef.current,
11612
+ to: pathname
11613
+ });
11614
+ prevPathnameRef.current = pathname;
11615
+ }, [pathname]);
11616
+ return /* @__PURE__ */ jsx(Box, {
11617
+ sx: {
11618
+ borderBottom: "1px solid lightgray",
11619
+ px: "12px"
11620
+ },
11621
+ children: /* @__PURE__ */ jsxs(Box, {
11622
+ sx: {
11623
+ display: "grid",
11624
+ gridTemplateColumns: "1fr auto 1fr",
11625
+ width: "100%",
11626
+ alignItems: "center"
11627
+ },
11628
+ children: [
11629
+ /* @__PURE__ */ jsx(Tabs, {
11630
+ value: useMemo(() => {
11631
+ if (pathname.startsWith("/checks")) return "/checks";
11632
+ if (pathname.startsWith("/query")) return "/query";
11633
+ if (pathname.startsWith("/runs")) return "/runs";
11634
+ return "/lineage";
11635
+ }, [pathname]),
11636
+ sx: {
11637
+ borderBottom: "none",
11638
+ minHeight: "auto"
11639
+ },
11640
+ children: ROUTE_CONFIG.map(({ path, name }) => {
11641
+ if (name === "Query" && flag?.single_env_onboarding) return null;
11642
+ if (name === "Checklist" && ChecklistBadge) return /* @__PURE__ */ jsx(Tab, {
11643
+ value: path,
11644
+ disabled: isLoading || isFlagLoading,
11645
+ sx: { p: 0 },
11646
+ label: /* @__PURE__ */ jsx(Box, {
11647
+ sx: {
11648
+ display: "flex",
11649
+ alignItems: "center",
11650
+ gap: "4px"
11651
+ },
11652
+ children: /* @__PURE__ */ jsxs(NextLink, {
11653
+ href: path,
11654
+ style: {
11655
+ textDecoration: "none",
11656
+ color: "inherit",
11657
+ padding: "0.875rem 1.1875rem",
11658
+ display: "flex",
11659
+ gap: 3,
11660
+ alignItems: "center"
11661
+ },
11662
+ children: [
11663
+ name,
11664
+ " ",
11665
+ /* @__PURE__ */ jsx(ChecklistBadge, {})
11666
+ ]
11667
+ })
11668
+ })
11669
+ }, path);
11670
+ return /* @__PURE__ */ jsx(Tab, {
11671
+ value: path,
11672
+ disabled: isLoading || isFlagLoading,
11673
+ sx: { p: 0 },
11674
+ label: /* @__PURE__ */ jsx(Box, {
11675
+ sx: {
11676
+ display: "flex",
11677
+ alignItems: "center",
11678
+ gap: "4px"
11679
+ },
11680
+ children: /* @__PURE__ */ jsx(NextLink, {
11681
+ href: path,
11682
+ style: {
11683
+ textDecoration: "none",
11684
+ color: "inherit",
11685
+ padding: "0.875rem 1.1875rem"
11686
+ },
11687
+ children: name
11688
+ })
11689
+ })
11690
+ }, path);
11691
+ })
11692
+ }),
11693
+ /* @__PURE__ */ jsxs(Box, {
11694
+ sx: {
11695
+ display: "flex",
11696
+ alignItems: "center",
11697
+ gap: "12px",
11698
+ justifyContent: "center"
11699
+ },
11700
+ children: [!isLoading && !isDemoSite && /* @__PURE__ */ jsx(Filename, {}), !isLoading && !isDemoSite && !flag?.single_env_onboarding && !featureToggles.disableShare && /* @__PURE__ */ jsx(TopLevelShare, {})]
11701
+ }),
11702
+ !isLoading && /* @__PURE__ */ jsxs(Box, {
11703
+ sx: {
11704
+ display: "flex",
11705
+ justifyContent: "right",
11706
+ alignItems: "center",
11707
+ mr: "8px"
11708
+ },
11709
+ children: [
11710
+ /* @__PURE__ */ jsx(EnvInfo, {}),
11711
+ cloudMode && /* @__PURE__ */ jsx(StateSynchronizer, {}),
11712
+ /* @__PURE__ */ jsx(StateExporter, {})
11713
+ ]
11714
+ })
11715
+ ]
11716
+ })
11717
+ });
11718
+ }
11719
+
11720
+ //#endregion
11721
+ 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, DisplayModeToggle as i, DiffEditor_default as j, EnvInfo as k, RunList as l, LineageDiffView as m, TopBar as n, SummaryView as o, SchemaDiffView as p, RecceVersionBadge as r, SchemaSummary as s, NavBar as t, RunPage as u, QueryPage as v, RunResultPane as w, LineageView as x, SetupConnectionGuide as y, RowCountDiffTag as z };
11722
+ //# sourceMappingURL=components-BHxcVq0D.mjs.map