@datarecce/ui 0.1.0

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.
package/dist/hooks.js ADDED
@@ -0,0 +1,199 @@
1
+ 'use strict';
2
+
3
+ var reactQuery = require('@tanstack/react-query');
4
+ var axios = require('axios');
5
+ var react = require('@chakra-ui/react');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+ var react$1 = require('react');
8
+ var unified = require('@amplitude/unified');
9
+
10
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
+
12
+ var axios__default = /*#__PURE__*/_interopDefault(axios);
13
+
14
+ // recce-source/js/src/lib/api/cacheKeys.ts
15
+ var cacheKeys = {
16
+ rowCount: (model) => ["row_count", model],
17
+ lineage: () => ["lineage"],
18
+ checks: () => ["checks", "list"],
19
+ check: (checkId) => ["checks", checkId],
20
+ checkEvents: (checkId) => ["checks", checkId, "events"],
21
+ runs: () => ["runs"],
22
+ run: (runId) => ["runs", runId],
23
+ runsAggregated: () => ["runs_aggregated"],
24
+ flag: () => ["flag"],
25
+ instanceInfo: () => ["instance_info"],
26
+ user: () => ["user"]
27
+ };
28
+
29
+ // recce-source/js/src/lib/const.ts
30
+ var apiUrl = process.env.NEXT_PUBLIC_API_URL;
31
+ apiUrl ??= typeof window !== "undefined" ? window.location.origin : "";
32
+ var PUBLIC_API_URL = apiUrl;
33
+ process.env.NEXT_PUBLIC_CLOUD_WEB_URL;
34
+
35
+ // recce-source/js/src/lib/api/axiosClient.ts
36
+ var axiosClient = axios__default.default.create({
37
+ baseURL: PUBLIC_API_URL
38
+ });
39
+ new reactQuery.QueryClient();
40
+
41
+ // recce-source/js/src/lib/api/instanceInfo.ts
42
+ async function getRecceInstanceInfo() {
43
+ return (await axiosClient.get(
44
+ "/api/instance-info"
45
+ )).data;
46
+ }
47
+
48
+ // recce-source/js/src/lib/hooks/useRecceInstanceInfo.tsx
49
+ var useRecceInstanceInfo = () => {
50
+ return reactQuery.useQuery({
51
+ queryKey: cacheKeys.instanceInfo(),
52
+ queryFn: getRecceInstanceInfo
53
+ });
54
+ };
55
+ var toaster = react.createToaster({
56
+ placement: "bottom-end",
57
+ pauseOnPageIdle: true
58
+ });
59
+
60
+ // recce-source/js/src/lib/hooks/useCheckToast.tsx
61
+ function useCheckToast() {
62
+ function markedAsApprovedToast() {
63
+ toaster.create({
64
+ title: "Marked as approved",
65
+ type: "success",
66
+ duration: 2e3
67
+ });
68
+ }
69
+ return {
70
+ markedAsApprovedToast
71
+ };
72
+ }
73
+
74
+ // recce-source/js/src/lib/hooks/useClipBoardToast.tsx
75
+ function useClipBoardToast() {
76
+ function successToast(message) {
77
+ toaster.create({
78
+ description: message,
79
+ type: "info",
80
+ duration: 5e3,
81
+ closable: true
82
+ });
83
+ }
84
+ function failToast(title, error) {
85
+ toaster.create({
86
+ title,
87
+ description: String(error),
88
+ type: "error",
89
+ duration: 5e3,
90
+ closable: true
91
+ });
92
+ }
93
+ return {
94
+ successToast,
95
+ failToast
96
+ };
97
+ }
98
+ var LineageViewContext = react$1.createContext(void 0);
99
+ var useLineageViewContext = () => {
100
+ return react$1.useContext(LineageViewContext);
101
+ };
102
+ function track(eventInput, eventProperties, eventOptions) {
103
+ {
104
+ console.log("[Tracking]", eventInput, eventProperties, eventOptions);
105
+ }
106
+ return unified.track(eventInput, eventProperties, eventOptions);
107
+ }
108
+ var EXPLORE_ACTION = {
109
+ VALUE_DIFF: "value_diff"};
110
+ var EXPLORE_FORM_EVENT = {
111
+ EXECUTE: "execute",
112
+ CANCEL: "cancel"
113
+ };
114
+ function trackExploreActionForm(props) {
115
+ track("[Web] explore_action_form", props);
116
+ }
117
+ function useValueDiffAlertDialog() {
118
+ const { open, onOpen, onClose } = react.useDisclosure();
119
+ const [nodeCount, setNodeCount] = react$1.useState(0);
120
+ const [resolvePromise, setResolvePromise] = react$1.useState();
121
+ const cancelRef = react$1.useRef(null);
122
+ const confirm = react$1.useCallback(
123
+ (nodeCount2) => {
124
+ setNodeCount(nodeCount2);
125
+ return new Promise((resolve) => {
126
+ setResolvePromise(() => resolve);
127
+ onOpen();
128
+ });
129
+ },
130
+ [onOpen]
131
+ );
132
+ const handleConfirm = () => {
133
+ trackExploreActionForm({
134
+ action: EXPLORE_ACTION.VALUE_DIFF,
135
+ event: EXPLORE_FORM_EVENT.EXECUTE
136
+ });
137
+ resolvePromise?.(true);
138
+ onClose();
139
+ };
140
+ const handleCancel = () => {
141
+ trackExploreActionForm({
142
+ action: EXPLORE_ACTION.VALUE_DIFF,
143
+ event: EXPLORE_FORM_EVENT.CANCEL
144
+ });
145
+ resolvePromise?.(false);
146
+ onClose();
147
+ };
148
+ const ValueDiffAlertDialog = /* @__PURE__ */ jsxRuntime.jsx(
149
+ react.Dialog.Root,
150
+ {
151
+ size: "xl",
152
+ open,
153
+ role: "alertdialog",
154
+ initialFocusEl: () => {
155
+ return cancelRef.current;
156
+ },
157
+ onOpenChange: handleCancel,
158
+ children: /* @__PURE__ */ jsxRuntime.jsxs(react.Portal, { children: [
159
+ /* @__PURE__ */ jsxRuntime.jsx(react.Dialog.Backdrop, {}),
160
+ /* @__PURE__ */ jsxRuntime.jsx(react.Dialog.Positioner, { children: /* @__PURE__ */ jsxRuntime.jsxs(react.Dialog.Content, { children: [
161
+ /* @__PURE__ */ jsxRuntime.jsx(react.Dialog.Header, { fontSize: "lg", fontWeight: "bold", children: /* @__PURE__ */ jsxRuntime.jsxs(react.Dialog.Title, { children: [
162
+ "Value Diff on ",
163
+ nodeCount,
164
+ " nodes"
165
+ ] }) }),
166
+ /* @__PURE__ */ jsxRuntime.jsx(react.Dialog.Body, { gap: "20px", as: react.Flex, direction: "column", children: /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { children: [
167
+ "Value diff will be executed on ",
168
+ nodeCount,
169
+ " nodes in the Lineage, which can add extra costs to your bill."
170
+ ] }) }),
171
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Dialog.Footer, { gap: 1, children: [
172
+ /* @__PURE__ */ jsxRuntime.jsx(
173
+ react.Button,
174
+ {
175
+ ref: cancelRef,
176
+ onClick: handleCancel,
177
+ variant: "outline",
178
+ colorPalette: "gray",
179
+ children: "Cancel"
180
+ }
181
+ ),
182
+ /* @__PURE__ */ jsxRuntime.jsx(react.Button, { colorPalette: "iochmara", onClick: handleConfirm, ml: 3, children: "Execute" })
183
+ ] }),
184
+ /* @__PURE__ */ jsxRuntime.jsx(react.Dialog.CloseTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(react.CloseButton, { size: "sm" }) })
185
+ ] }) })
186
+ ] })
187
+ }
188
+ );
189
+ return { confirm, AlertDialog: ValueDiffAlertDialog };
190
+ }
191
+ var useValueDiffAlertDialog_default = useValueDiffAlertDialog;
192
+
193
+ exports.useCheckToast = useCheckToast;
194
+ exports.useClipBoardToast = useClipBoardToast;
195
+ exports.useLineageViewContext = useLineageViewContext;
196
+ exports.useRecceInstanceInfo = useRecceInstanceInfo;
197
+ exports.useValueDiffAlertDialog = useValueDiffAlertDialog_default;
198
+ //# sourceMappingURL=hooks.js.map
199
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../recce-source/js/src/lib/api/cacheKeys.ts","../recce-source/js/src/lib/const.ts","../recce-source/js/src/lib/api/axiosClient.ts","../recce-source/js/src/lib/api/instanceInfo.ts","../recce-source/js/src/lib/hooks/useRecceInstanceInfo.tsx","../recce-source/js/src/components/ui/toaster.tsx","../recce-source/js/src/lib/hooks/useCheckToast.tsx","../recce-source/js/src/lib/hooks/useClipBoardToast.tsx","../recce-source/js/src/components/lineage/LineageViewContext.tsx","../recce-source/js/src/lib/api/track.ts","../recce-source/js/src/components/lineage/useValueDiffAlertDialog.tsx"],"names":["axios","QueryClient","useQuery","createToaster","createContext","useContext","trk","useDisclosure","useState","useRef","useCallback","nodeCount","jsx","Dialog","jsxs","Portal","Flex","Box","Button","CloseButton"],"mappings":"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","file":"hooks.js","sourcesContent":["export const cacheKeys = {\n rowCount: (model: string) => [\"row_count\", model],\n lineage: () => [\"lineage\"],\n checks: () => [\"checks\", \"list\"],\n check: (checkId: string) => [\"checks\", checkId],\n checkEvents: (checkId: string) => [\"checks\", checkId, \"events\"],\n runs: () => [\"runs\"],\n run: (runId: string) => [\"runs\", runId],\n runsAggregated: () => [\"runs_aggregated\"],\n flag: () => [\"flag\"],\n instanceInfo: () => [\"instance_info\"],\n user: () => [\"user\"],\n};\n","let apiUrl = process.env.NEXT_PUBLIC_API_URL;\napiUrl ??= typeof window !== \"undefined\" ? window.location.origin : \"\";\n\nexport const PUBLIC_API_URL = apiUrl;\n\nlet cloudWebUrl = process.env.NEXT_PUBLIC_CLOUD_WEB_URL;\ncloudWebUrl ??= \"https://cloud.datarecce.io\";\n\nexport const PUBLIC_CLOUD_WEB_URL = cloudWebUrl;\n","import { QueryClient } from \"@tanstack/react-query\";\nimport axios from \"axios\";\nimport { PUBLIC_API_URL } from \"@/lib/const\";\n\nexport const axiosClient = axios.create({\n baseURL: PUBLIC_API_URL,\n});\n\nexport const reactQueryClient = new QueryClient();\n","import { AxiosResponse } from \"axios\";\nimport { axiosClient } from \"./axiosClient\";\n\nexport interface RecceInstanceInfo {\n server_mode: \"server\" | \"preview\" | \"read-only\";\n single_env: boolean;\n authed: boolean;\n cloud_instance: boolean;\n lifetime_expired_at?: Date;\n idle_timeout?: number;\n share_url?: string;\n session_id?: string;\n organization_name?: string;\n web_url?: string;\n}\n\nexport async function getRecceInstanceInfo(): Promise<RecceInstanceInfo> {\n return (\n await axiosClient.get<never, AxiosResponse<RecceInstanceInfo>>(\n \"/api/instance-info\",\n )\n ).data;\n}\n","import { useQuery } from \"@tanstack/react-query\";\nimport { cacheKeys } from \"../api/cacheKeys\";\nimport { getRecceInstanceInfo, RecceInstanceInfo } from \"../api/instanceInfo\";\n\nexport const useRecceInstanceInfo = () => {\n return useQuery<RecceInstanceInfo>({\n queryKey: cacheKeys.instanceInfo(),\n queryFn: getRecceInstanceInfo,\n });\n};\n","\"use client\";\n\nimport type { CreateToasterReturn } from \"@chakra-ui/react\";\nimport {\n Toaster as ChakraToaster,\n createToaster,\n Portal,\n Spinner,\n Stack,\n Toast,\n} from \"@chakra-ui/react\";\n\nexport const toaster: CreateToasterReturn = createToaster({\n placement: \"bottom-end\",\n pauseOnPageIdle: true,\n});\n\nexport const Toaster = () => {\n return (\n <Portal>\n <ChakraToaster toaster={toaster} insetInline={{ mdDown: \"4\" }}>\n {(toast) => (\n <Toast.Root width={{ md: \"sm\" }}>\n {toast.type === \"loading\" ? (\n <Spinner size=\"sm\" color=\"blue.solid\" />\n ) : (\n <Toast.Indicator />\n )}\n <Stack gap=\"1\" flex=\"1\" maxWidth=\"100%\">\n {toast.title && <Toast.Title>{toast.title}</Toast.Title>}\n {toast.description && (\n <Toast.Description>{toast.description}</Toast.Description>\n )}\n </Stack>\n {toast.action && (\n <Toast.ActionTrigger>{toast.action.label}</Toast.ActionTrigger>\n )}\n {toast.closable && <Toast.CloseTrigger />}\n </Toast.Root>\n )}\n </ChakraToaster>\n </Portal>\n );\n};\n","import { toaster } from \"@/components/ui/toaster\";\n\nexport function useCheckToast() {\n function markedAsApprovedToast() {\n toaster.create({\n title: \"Marked as approved\",\n type: \"success\",\n duration: 2000,\n });\n }\n return {\n markedAsApprovedToast,\n };\n}\n","import { toaster } from \"@/components/ui/toaster\";\n\nexport function useClipBoardToast() {\n function successToast(message: string) {\n toaster.create({\n description: message,\n type: \"info\",\n duration: 5000,\n closable: true,\n });\n }\n\n function failToast(title: string, error: unknown) {\n toaster.create({\n title: title,\n description: String(error),\n type: \"error\",\n duration: 5000,\n closable: true,\n });\n }\n\n return {\n successToast,\n failToast,\n };\n}\n","import React, { createContext, useContext } from \"react\";\nimport { CllInput, ColumnLineageData } from \"@/lib/api/cll\";\nimport { LineageDiffViewOptions } from \"@/lib/api/lineagecheck\";\nimport { Run } from \"@/lib/api/types\";\nimport { LineageGraphNode, LineageGraphNodes } from \"./lineage\";\n\ntype NewType = LineageDiffViewOptions;\ntype ActionMode = \"per_node\" | \"multi_nodes\";\n\ninterface NodeAction {\n mode: ActionMode;\n status?: \"pending\" | \"running\" | \"success\" | \"failure\" | \"skipped\";\n skipReason?: string;\n run?: Run;\n}\n\nexport interface ActionState {\n mode: ActionMode;\n status: \"pending\" | \"running\" | \"canceling\" | \"canceled\" | \"completed\";\n currentRun?: Partial<Run>;\n completed: number;\n total: number;\n actions: Record<string, NodeAction>;\n}\n\nexport interface LineageViewContextType {\n interactive: boolean;\n nodes: LineageGraphNodes[];\n focusedNode?: LineageGraphNode;\n selectedNodes: LineageGraphNode[];\n cll: ColumnLineageData | undefined;\n\n // context menu\n showContextMenu: (event: React.MouseEvent, node: LineageGraphNodes) => void;\n\n // filter\n viewOptions: LineageDiffViewOptions;\n onViewOptionsChanged: (options: NewType) => void;\n\n // Multi nodes selection\n selectMode: \"selecting\" | \"action_result\" | undefined;\n selectNode: (nodeId: string) => void;\n selectParentNodes: (nodeId: string, degree?: number) => void;\n selectChildNodes: (nodeId: string, degree?: number) => void;\n deselect: () => void;\n\n // node state\n isNodeHighlighted: (nodeId: string) => boolean;\n isNodeSelected: (nodeId: string) => boolean;\n isEdgeHighlighted: (source: string, target: string) => boolean;\n getNodeAction: (nodeId: string) => NodeAction;\n getNodeColumnSet: (nodeId: string) => Set<string>;\n isNodeShowingChangeAnalysis: (nodeId: string) => boolean;\n\n //actions\n runRowCount: () => Promise<void>;\n runRowCountDiff: () => Promise<void>;\n runValueDiff: () => Promise<void>;\n addLineageDiffCheck: (viewMode?: string) => void;\n addSchemaDiffCheck: () => void;\n cancel: () => void;\n actionState: ActionState;\n\n // Column Level Lineage\n centerNode: (nodeId: string) => void;\n showColumnLevelLineage: (cll?: CllInput) => Promise<void>;\n resetColumnLevelLineage: (previous?: boolean) => Promise<void>;\n}\n\nexport const LineageViewContext = createContext<\n LineageViewContextType | undefined\n>(undefined);\n\nexport const useLineageViewContextSafe = (): LineageViewContextType => {\n const context = useContext(LineageViewContext);\n if (!context) {\n throw new Error(\n \"useLineageViewContext must be used within a LineageViewProvider\",\n );\n }\n return context;\n};\n\nexport const useLineageViewContext = (): LineageViewContextType | undefined => {\n return useContext(LineageViewContext);\n};\n","import {\n AmplitudeReturn,\n BaseEvent,\n EventOptions,\n Result,\n} from \"@amplitude/analytics-core\";\nimport { initAll, track as trk } from \"@amplitude/unified\";\n\nfunction track(\n eventInput: string | BaseEvent,\n // biome-ignore lint/suspicious/noExplicitAny: Amplitude library uses any for event properties\n eventProperties?: Record<string, any> | undefined,\n eventOptions?: EventOptions | undefined,\n): AmplitudeReturn<Result> {\n // If Amplitude isn't initialized, log to console instead\n if (!amplitudeInitialized) {\n console.log(\"[Tracking]\", eventInput, eventProperties, eventOptions);\n }\n return trk(eventInput, eventProperties, eventOptions);\n}\n\nlet amplitudeInitialized = false;\n\nexport function trackInit() {\n function getCookie(key: string) {\n const b = document.cookie.match(\"(^|;)\\\\s*\" + key + \"\\\\s*=\\\\s*([^;]+)\");\n return b ? b.pop() : \"\";\n }\n\n const userId =\n process.env.NODE_ENV === \"development\"\n ? \"web_dev\"\n : getCookie(\"recce_user_id\");\n const apiKey = process.env.AMPLITUDE_API_KEY;\n if (userId && apiKey) {\n try {\n void initAll(apiKey, {\n analytics: {\n userId,\n autocapture: true,\n },\n sessionReplay: {\n sampleRate: 1,\n },\n });\n amplitudeInitialized = true;\n } catch (e) {\n console.error(e);\n }\n }\n\n // Log when Amplitude is not initialized (for development/debugging)\n if (!amplitudeInitialized) {\n console.log(\n \"[Tracking] Amplitude not initialized (missing API key or user ID). Events will be logged to console instead.\",\n );\n }\n}\n\ninterface MultiNodeActionProps {\n type:\n | \"row_count\"\n | \"row_count_diff\"\n | \"value_diff\"\n | \"schema_diff\"\n | \"lineage_diff\";\n selected: \"single\" | \"multi\" | \"none\";\n}\n\nexport function trackMultiNodesAction(props: MultiNodeActionProps) {\n track(\"[Web] multi_nodes_action\", props);\n}\n\ninterface HistoryActionProps {\n name: \"show\" | \"hide\" | \"click_run\" | \"add_to_checklist\" | \"go_to_check\";\n}\n\nexport function trackHistoryAction(props: HistoryActionProps) {\n track(\"[Web] history_action\", props);\n}\n\ninterface PreviewChangeProps {\n action: \"explore\" | \"run\" | \"close\";\n node?: string;\n status?: \"success\" | \"failure\";\n}\n\nexport function trackPreviewChange(props: PreviewChangeProps) {\n track(\"[Experiment] preview_change\", props);\n}\n\ninterface PreviewChangeFeedbackProps {\n feedback: \"like\" | \"dislike\" | \"form\";\n node?: string;\n}\n\nexport function trackPreviewChangeFeedback(props: PreviewChangeFeedbackProps) {\n track(\"[Experiment] preview_change\", props);\n}\n\ninterface SingleEnvironmentProps {\n action:\n | \"onboarding\"\n | \"external_link\"\n | \"preview_changes\"\n | `target_base_added`;\n from?: \"onboarding\" | \"preview_changes\";\n node?: string;\n}\n\nexport function trackSingleEnvironment(props: SingleEnvironmentProps) {\n track(\"[Experiment] single_environment\", props);\n}\n\nexport function getExperimentTrackingBreakingChangeEnabled() {\n return false;\n}\n\ninterface ColumnLevelLineageProps {\n action: \"view\";\n source: \"schema_column\" | \"changed_column\" | \"cll_column\";\n}\n\nexport function trackColumnLevelLineage(props: ColumnLevelLineageProps) {\n track(\"[Web] column_level_lineage\", props);\n}\n\ninterface ShareStateProps {\n name: \"enable\" | \"create\" | \"copy\";\n}\n\nexport function trackShareState(props: ShareStateProps) {\n track(\"[Web] share_state\", props);\n}\n\ninterface StateActionProps {\n name: \"import\" | \"export\";\n}\n\nexport function trackStateAction(props: StateActionProps) {\n track(\"[Web] state_action\", props);\n}\n\ninterface CopyToClipboardProps {\n from: \"run\" | \"check\" | \"lineage_view\";\n type: string;\n}\n\nexport function trackCopyToClipboard(props: CopyToClipboardProps) {\n track(\"[Click] copy_to_clipboard\", props);\n}\n\ninterface TrackNavProps {\n from: string;\n to: string;\n}\n\nexport function trackNavigation(props: TrackNavProps) {\n track(\"[Web] navigation_change\", props);\n}\n\nexport interface LineageViewRenderProps {\n node_count: number;\n view_mode: string;\n impact_radius_enabled: boolean;\n cll_column_active?: boolean;\n right_sidebar_open: boolean;\n [status: string]: number | string | boolean | undefined;\n}\n\nexport function trackLineageViewRender(props: LineageViewRenderProps) {\n track(\"[Web] lineage_view_render\", props);\n}\n\nexport interface EnvironmentConfigProps {\n review_mode: boolean;\n adapter_type: string | null;\n has_git_info: boolean;\n has_pr_info: boolean;\n // Adapter-specific (shape varies by adapter_type)\n base?: {\n schema_count?: number;\n dbt_version?: string | null;\n timestamp?: string | null;\n has_env?: boolean;\n };\n current?: {\n schema_count?: number;\n dbt_version?: string | null;\n timestamp?: string | null;\n has_env?: boolean;\n };\n schemas_match?: boolean;\n}\n\nexport function trackEnvironmentConfig(props: EnvironmentConfigProps) {\n track(\"[Web] environment_config\", props);\n}\n\n// Explore action types\nexport const EXPLORE_ACTION = {\n ROW_COUNT: \"row_count\",\n ROW_COUNT_DIFF: \"row_count_diff\",\n PROFILE: \"profile\",\n PROFILE_DIFF: \"profile_diff\",\n VALUE_DIFF: \"value_diff\",\n SCHEMA_DIFF: \"schema_diff\",\n LINEAGE_DIFF: \"lineage_diff\",\n QUERY: \"query\",\n HISTOGRAM_DIFF: \"histogram_diff\",\n TOP_K_DIFF: \"top_k_diff\",\n} as const;\n\n// Explore action sources\nexport const EXPLORE_SOURCE = {\n LINEAGE_VIEW_TOP_BAR: \"lineage_view_top_bar\",\n LINEAGE_VIEW_CONTEXT_MENU: \"lineage_view_context_menu\",\n NODE_KEBAB_MENU: \"node_kebab_menu\",\n NODE_SIDEBAR_SINGLE_ENV: \"node_sidebar_single_env\",\n NODE_SIDEBAR_MULTI_ENV: \"node_sidebar_multi_env\",\n SCHEMA_ROW_COUNT_BUTTON: \"schema_row_count_button\",\n SCHEMA_COLUMN_MENU: \"schema_column_menu\",\n} as const;\n\nexport type ExploreActionType =\n (typeof EXPLORE_ACTION)[keyof typeof EXPLORE_ACTION];\nexport type ExploreSourceType =\n (typeof EXPLORE_SOURCE)[keyof typeof EXPLORE_SOURCE];\n\ninterface ExploreActionProps {\n action: ExploreActionType;\n source: ExploreSourceType;\n node_count?: number;\n}\n\nexport function trackExploreAction(props: ExploreActionProps) {\n track(\"[Web] explore_action\", props);\n}\n\n// Explore action form events\nexport const EXPLORE_FORM_EVENT = {\n EXECUTE: \"execute\",\n CANCEL: \"cancel\",\n} as const;\n\nexport type ExploreFormEventType =\n (typeof EXPLORE_FORM_EVENT)[keyof typeof EXPLORE_FORM_EVENT];\n\ninterface ExploreActionFormProps {\n action: ExploreActionType;\n event: ExploreFormEventType;\n}\n\nexport function trackExploreActionForm(props: ExploreActionFormProps) {\n track(\"[Web] explore_action_form\", props);\n}\n\n// Helper to check if a run type is an explore action\nexport function isExploreAction(type: string): type is ExploreActionType {\n return Object.values(EXPLORE_ACTION).includes(type as ExploreActionType);\n}\n\n// Lineage selection action types\nexport const LINEAGE_SELECTION_ACTION = {\n SELECT_PARENT_NODES: \"select_parent_nodes\",\n SELECT_CHILD_NODES: \"select_child_nodes\",\n SELECT_ALL_UPSTREAM: \"select_all_upstream\",\n SELECT_ALL_DOWNSTREAM: \"select_all_downstream\",\n} as const;\n\nexport type LineageSelectionActionType =\n (typeof LINEAGE_SELECTION_ACTION)[keyof typeof LINEAGE_SELECTION_ACTION];\n\ninterface LineageSelectionProps {\n action: LineageSelectionActionType;\n node_count?: number;\n}\n\nexport function trackLineageSelection(props: LineageSelectionProps) {\n track(\"[Web] lineage_selection\", props);\n}\n","import {\n Box,\n Button,\n CloseButton,\n Dialog,\n Flex,\n Portal,\n useDisclosure,\n} from \"@chakra-ui/react\";\nimport React, { useCallback, useRef, useState } from \"react\";\nimport {\n EXPLORE_ACTION,\n EXPLORE_FORM_EVENT,\n trackExploreActionForm,\n} from \"@/lib/api/track\";\n\nfunction useValueDiffAlertDialog() {\n const { open, onOpen, onClose } = useDisclosure();\n const [nodeCount, setNodeCount] = useState(0);\n const [resolvePromise, setResolvePromise] =\n useState<(value: boolean) => void>();\n const cancelRef = useRef<HTMLButtonElement>(null);\n\n const confirm = useCallback(\n (nodeCount: number) => {\n setNodeCount(nodeCount);\n return new Promise<boolean>((resolve) => {\n setResolvePromise(() => resolve);\n onOpen();\n });\n },\n [onOpen],\n );\n\n const handleConfirm = () => {\n trackExploreActionForm({\n action: EXPLORE_ACTION.VALUE_DIFF,\n event: EXPLORE_FORM_EVENT.EXECUTE,\n });\n resolvePromise?.(true);\n onClose();\n };\n\n const handleCancel = () => {\n trackExploreActionForm({\n action: EXPLORE_ACTION.VALUE_DIFF,\n event: EXPLORE_FORM_EVENT.CANCEL,\n });\n resolvePromise?.(false);\n onClose();\n };\n\n const ValueDiffAlertDialog = (\n <Dialog.Root\n size={\"xl\"}\n open={open}\n role=\"alertdialog\"\n initialFocusEl={() => {\n return cancelRef.current;\n }}\n onOpenChange={handleCancel}\n >\n <Portal>\n <Dialog.Backdrop />\n <Dialog.Positioner>\n <Dialog.Content>\n <Dialog.Header fontSize=\"lg\" fontWeight=\"bold\">\n <Dialog.Title>Value Diff on {nodeCount} nodes</Dialog.Title>\n </Dialog.Header>\n\n <Dialog.Body gap=\"20px\" as={Flex} direction=\"column\">\n <Box>\n Value diff will be executed on {nodeCount} nodes in the Lineage,\n which can add extra costs to your bill.\n </Box>\n </Dialog.Body>\n\n <Dialog.Footer gap={1}>\n <Button\n ref={cancelRef}\n onClick={handleCancel}\n variant=\"outline\"\n colorPalette=\"gray\"\n >\n Cancel\n </Button>\n <Button colorPalette=\"iochmara\" onClick={handleConfirm} ml={3}>\n Execute\n </Button>\n </Dialog.Footer>\n <Dialog.CloseTrigger asChild>\n <CloseButton size=\"sm\" />\n </Dialog.CloseTrigger>\n </Dialog.Content>\n </Dialog.Positioner>\n </Portal>\n </Dialog.Root>\n );\n\n return { confirm, AlertDialog: ValueDiffAlertDialog };\n}\n\nexport default useValueDiffAlertDialog;\n"]}
package/dist/hooks.mjs ADDED
@@ -0,0 +1,189 @@
1
+ import { QueryClient, useQuery } from '@tanstack/react-query';
2
+ import axios from 'axios';
3
+ import { createToaster, useDisclosure, Dialog, Portal, Flex, Box, Button, CloseButton } from '@chakra-ui/react';
4
+ import { jsx, jsxs } from 'react/jsx-runtime';
5
+ import { createContext, useContext, useState, useRef, useCallback } from 'react';
6
+ import { track as track$1 } from '@amplitude/unified';
7
+
8
+ // recce-source/js/src/lib/api/cacheKeys.ts
9
+ var cacheKeys = {
10
+ rowCount: (model) => ["row_count", model],
11
+ lineage: () => ["lineage"],
12
+ checks: () => ["checks", "list"],
13
+ check: (checkId) => ["checks", checkId],
14
+ checkEvents: (checkId) => ["checks", checkId, "events"],
15
+ runs: () => ["runs"],
16
+ run: (runId) => ["runs", runId],
17
+ runsAggregated: () => ["runs_aggregated"],
18
+ flag: () => ["flag"],
19
+ instanceInfo: () => ["instance_info"],
20
+ user: () => ["user"]
21
+ };
22
+
23
+ // recce-source/js/src/lib/const.ts
24
+ var apiUrl = process.env.NEXT_PUBLIC_API_URL;
25
+ apiUrl ??= typeof window !== "undefined" ? window.location.origin : "";
26
+ var PUBLIC_API_URL = apiUrl;
27
+ process.env.NEXT_PUBLIC_CLOUD_WEB_URL;
28
+
29
+ // recce-source/js/src/lib/api/axiosClient.ts
30
+ var axiosClient = axios.create({
31
+ baseURL: PUBLIC_API_URL
32
+ });
33
+ new QueryClient();
34
+
35
+ // recce-source/js/src/lib/api/instanceInfo.ts
36
+ async function getRecceInstanceInfo() {
37
+ return (await axiosClient.get(
38
+ "/api/instance-info"
39
+ )).data;
40
+ }
41
+
42
+ // recce-source/js/src/lib/hooks/useRecceInstanceInfo.tsx
43
+ var useRecceInstanceInfo = () => {
44
+ return useQuery({
45
+ queryKey: cacheKeys.instanceInfo(),
46
+ queryFn: getRecceInstanceInfo
47
+ });
48
+ };
49
+ var toaster = createToaster({
50
+ placement: "bottom-end",
51
+ pauseOnPageIdle: true
52
+ });
53
+
54
+ // recce-source/js/src/lib/hooks/useCheckToast.tsx
55
+ function useCheckToast() {
56
+ function markedAsApprovedToast() {
57
+ toaster.create({
58
+ title: "Marked as approved",
59
+ type: "success",
60
+ duration: 2e3
61
+ });
62
+ }
63
+ return {
64
+ markedAsApprovedToast
65
+ };
66
+ }
67
+
68
+ // recce-source/js/src/lib/hooks/useClipBoardToast.tsx
69
+ function useClipBoardToast() {
70
+ function successToast(message) {
71
+ toaster.create({
72
+ description: message,
73
+ type: "info",
74
+ duration: 5e3,
75
+ closable: true
76
+ });
77
+ }
78
+ function failToast(title, error) {
79
+ toaster.create({
80
+ title,
81
+ description: String(error),
82
+ type: "error",
83
+ duration: 5e3,
84
+ closable: true
85
+ });
86
+ }
87
+ return {
88
+ successToast,
89
+ failToast
90
+ };
91
+ }
92
+ var LineageViewContext = createContext(void 0);
93
+ var useLineageViewContext = () => {
94
+ return useContext(LineageViewContext);
95
+ };
96
+ function track(eventInput, eventProperties, eventOptions) {
97
+ {
98
+ console.log("[Tracking]", eventInput, eventProperties, eventOptions);
99
+ }
100
+ return track$1(eventInput, eventProperties, eventOptions);
101
+ }
102
+ var EXPLORE_ACTION = {
103
+ VALUE_DIFF: "value_diff"};
104
+ var EXPLORE_FORM_EVENT = {
105
+ EXECUTE: "execute",
106
+ CANCEL: "cancel"
107
+ };
108
+ function trackExploreActionForm(props) {
109
+ track("[Web] explore_action_form", props);
110
+ }
111
+ function useValueDiffAlertDialog() {
112
+ const { open, onOpen, onClose } = useDisclosure();
113
+ const [nodeCount, setNodeCount] = useState(0);
114
+ const [resolvePromise, setResolvePromise] = useState();
115
+ const cancelRef = useRef(null);
116
+ const confirm = useCallback(
117
+ (nodeCount2) => {
118
+ setNodeCount(nodeCount2);
119
+ return new Promise((resolve) => {
120
+ setResolvePromise(() => resolve);
121
+ onOpen();
122
+ });
123
+ },
124
+ [onOpen]
125
+ );
126
+ const handleConfirm = () => {
127
+ trackExploreActionForm({
128
+ action: EXPLORE_ACTION.VALUE_DIFF,
129
+ event: EXPLORE_FORM_EVENT.EXECUTE
130
+ });
131
+ resolvePromise?.(true);
132
+ onClose();
133
+ };
134
+ const handleCancel = () => {
135
+ trackExploreActionForm({
136
+ action: EXPLORE_ACTION.VALUE_DIFF,
137
+ event: EXPLORE_FORM_EVENT.CANCEL
138
+ });
139
+ resolvePromise?.(false);
140
+ onClose();
141
+ };
142
+ const ValueDiffAlertDialog = /* @__PURE__ */ jsx(
143
+ Dialog.Root,
144
+ {
145
+ size: "xl",
146
+ open,
147
+ role: "alertdialog",
148
+ initialFocusEl: () => {
149
+ return cancelRef.current;
150
+ },
151
+ onOpenChange: handleCancel,
152
+ children: /* @__PURE__ */ jsxs(Portal, { children: [
153
+ /* @__PURE__ */ jsx(Dialog.Backdrop, {}),
154
+ /* @__PURE__ */ jsx(Dialog.Positioner, { children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
155
+ /* @__PURE__ */ jsx(Dialog.Header, { fontSize: "lg", fontWeight: "bold", children: /* @__PURE__ */ jsxs(Dialog.Title, { children: [
156
+ "Value Diff on ",
157
+ nodeCount,
158
+ " nodes"
159
+ ] }) }),
160
+ /* @__PURE__ */ jsx(Dialog.Body, { gap: "20px", as: Flex, direction: "column", children: /* @__PURE__ */ jsxs(Box, { children: [
161
+ "Value diff will be executed on ",
162
+ nodeCount,
163
+ " nodes in the Lineage, which can add extra costs to your bill."
164
+ ] }) }),
165
+ /* @__PURE__ */ jsxs(Dialog.Footer, { gap: 1, children: [
166
+ /* @__PURE__ */ jsx(
167
+ Button,
168
+ {
169
+ ref: cancelRef,
170
+ onClick: handleCancel,
171
+ variant: "outline",
172
+ colorPalette: "gray",
173
+ children: "Cancel"
174
+ }
175
+ ),
176
+ /* @__PURE__ */ jsx(Button, { colorPalette: "iochmara", onClick: handleConfirm, ml: 3, children: "Execute" })
177
+ ] }),
178
+ /* @__PURE__ */ jsx(Dialog.CloseTrigger, { asChild: true, children: /* @__PURE__ */ jsx(CloseButton, { size: "sm" }) })
179
+ ] }) })
180
+ ] })
181
+ }
182
+ );
183
+ return { confirm, AlertDialog: ValueDiffAlertDialog };
184
+ }
185
+ var useValueDiffAlertDialog_default = useValueDiffAlertDialog;
186
+
187
+ export { useCheckToast, useClipBoardToast, useLineageViewContext, useRecceInstanceInfo, useValueDiffAlertDialog_default as useValueDiffAlertDialog };
188
+ //# sourceMappingURL=hooks.mjs.map
189
+ //# sourceMappingURL=hooks.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../recce-source/js/src/lib/api/cacheKeys.ts","../recce-source/js/src/lib/const.ts","../recce-source/js/src/lib/api/axiosClient.ts","../recce-source/js/src/lib/api/instanceInfo.ts","../recce-source/js/src/lib/hooks/useRecceInstanceInfo.tsx","../recce-source/js/src/components/ui/toaster.tsx","../recce-source/js/src/lib/hooks/useCheckToast.tsx","../recce-source/js/src/lib/hooks/useClipBoardToast.tsx","../recce-source/js/src/components/lineage/LineageViewContext.tsx","../recce-source/js/src/lib/api/track.ts","../recce-source/js/src/components/lineage/useValueDiffAlertDialog.tsx"],"names":["trk","nodeCount","jsx","jsxs","Portal"],"mappings":"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","file":"hooks.mjs","sourcesContent":["export const cacheKeys = {\n rowCount: (model: string) => [\"row_count\", model],\n lineage: () => [\"lineage\"],\n checks: () => [\"checks\", \"list\"],\n check: (checkId: string) => [\"checks\", checkId],\n checkEvents: (checkId: string) => [\"checks\", checkId, \"events\"],\n runs: () => [\"runs\"],\n run: (runId: string) => [\"runs\", runId],\n runsAggregated: () => [\"runs_aggregated\"],\n flag: () => [\"flag\"],\n instanceInfo: () => [\"instance_info\"],\n user: () => [\"user\"],\n};\n","let apiUrl = process.env.NEXT_PUBLIC_API_URL;\napiUrl ??= typeof window !== \"undefined\" ? window.location.origin : \"\";\n\nexport const PUBLIC_API_URL = apiUrl;\n\nlet cloudWebUrl = process.env.NEXT_PUBLIC_CLOUD_WEB_URL;\ncloudWebUrl ??= \"https://cloud.datarecce.io\";\n\nexport const PUBLIC_CLOUD_WEB_URL = cloudWebUrl;\n","import { QueryClient } from \"@tanstack/react-query\";\nimport axios from \"axios\";\nimport { PUBLIC_API_URL } from \"@/lib/const\";\n\nexport const axiosClient = axios.create({\n baseURL: PUBLIC_API_URL,\n});\n\nexport const reactQueryClient = new QueryClient();\n","import { AxiosResponse } from \"axios\";\nimport { axiosClient } from \"./axiosClient\";\n\nexport interface RecceInstanceInfo {\n server_mode: \"server\" | \"preview\" | \"read-only\";\n single_env: boolean;\n authed: boolean;\n cloud_instance: boolean;\n lifetime_expired_at?: Date;\n idle_timeout?: number;\n share_url?: string;\n session_id?: string;\n organization_name?: string;\n web_url?: string;\n}\n\nexport async function getRecceInstanceInfo(): Promise<RecceInstanceInfo> {\n return (\n await axiosClient.get<never, AxiosResponse<RecceInstanceInfo>>(\n \"/api/instance-info\",\n )\n ).data;\n}\n","import { useQuery } from \"@tanstack/react-query\";\nimport { cacheKeys } from \"../api/cacheKeys\";\nimport { getRecceInstanceInfo, RecceInstanceInfo } from \"../api/instanceInfo\";\n\nexport const useRecceInstanceInfo = () => {\n return useQuery<RecceInstanceInfo>({\n queryKey: cacheKeys.instanceInfo(),\n queryFn: getRecceInstanceInfo,\n });\n};\n","\"use client\";\n\nimport type { CreateToasterReturn } from \"@chakra-ui/react\";\nimport {\n Toaster as ChakraToaster,\n createToaster,\n Portal,\n Spinner,\n Stack,\n Toast,\n} from \"@chakra-ui/react\";\n\nexport const toaster: CreateToasterReturn = createToaster({\n placement: \"bottom-end\",\n pauseOnPageIdle: true,\n});\n\nexport const Toaster = () => {\n return (\n <Portal>\n <ChakraToaster toaster={toaster} insetInline={{ mdDown: \"4\" }}>\n {(toast) => (\n <Toast.Root width={{ md: \"sm\" }}>\n {toast.type === \"loading\" ? (\n <Spinner size=\"sm\" color=\"blue.solid\" />\n ) : (\n <Toast.Indicator />\n )}\n <Stack gap=\"1\" flex=\"1\" maxWidth=\"100%\">\n {toast.title && <Toast.Title>{toast.title}</Toast.Title>}\n {toast.description && (\n <Toast.Description>{toast.description}</Toast.Description>\n )}\n </Stack>\n {toast.action && (\n <Toast.ActionTrigger>{toast.action.label}</Toast.ActionTrigger>\n )}\n {toast.closable && <Toast.CloseTrigger />}\n </Toast.Root>\n )}\n </ChakraToaster>\n </Portal>\n );\n};\n","import { toaster } from \"@/components/ui/toaster\";\n\nexport function useCheckToast() {\n function markedAsApprovedToast() {\n toaster.create({\n title: \"Marked as approved\",\n type: \"success\",\n duration: 2000,\n });\n }\n return {\n markedAsApprovedToast,\n };\n}\n","import { toaster } from \"@/components/ui/toaster\";\n\nexport function useClipBoardToast() {\n function successToast(message: string) {\n toaster.create({\n description: message,\n type: \"info\",\n duration: 5000,\n closable: true,\n });\n }\n\n function failToast(title: string, error: unknown) {\n toaster.create({\n title: title,\n description: String(error),\n type: \"error\",\n duration: 5000,\n closable: true,\n });\n }\n\n return {\n successToast,\n failToast,\n };\n}\n","import React, { createContext, useContext } from \"react\";\nimport { CllInput, ColumnLineageData } from \"@/lib/api/cll\";\nimport { LineageDiffViewOptions } from \"@/lib/api/lineagecheck\";\nimport { Run } from \"@/lib/api/types\";\nimport { LineageGraphNode, LineageGraphNodes } from \"./lineage\";\n\ntype NewType = LineageDiffViewOptions;\ntype ActionMode = \"per_node\" | \"multi_nodes\";\n\ninterface NodeAction {\n mode: ActionMode;\n status?: \"pending\" | \"running\" | \"success\" | \"failure\" | \"skipped\";\n skipReason?: string;\n run?: Run;\n}\n\nexport interface ActionState {\n mode: ActionMode;\n status: \"pending\" | \"running\" | \"canceling\" | \"canceled\" | \"completed\";\n currentRun?: Partial<Run>;\n completed: number;\n total: number;\n actions: Record<string, NodeAction>;\n}\n\nexport interface LineageViewContextType {\n interactive: boolean;\n nodes: LineageGraphNodes[];\n focusedNode?: LineageGraphNode;\n selectedNodes: LineageGraphNode[];\n cll: ColumnLineageData | undefined;\n\n // context menu\n showContextMenu: (event: React.MouseEvent, node: LineageGraphNodes) => void;\n\n // filter\n viewOptions: LineageDiffViewOptions;\n onViewOptionsChanged: (options: NewType) => void;\n\n // Multi nodes selection\n selectMode: \"selecting\" | \"action_result\" | undefined;\n selectNode: (nodeId: string) => void;\n selectParentNodes: (nodeId: string, degree?: number) => void;\n selectChildNodes: (nodeId: string, degree?: number) => void;\n deselect: () => void;\n\n // node state\n isNodeHighlighted: (nodeId: string) => boolean;\n isNodeSelected: (nodeId: string) => boolean;\n isEdgeHighlighted: (source: string, target: string) => boolean;\n getNodeAction: (nodeId: string) => NodeAction;\n getNodeColumnSet: (nodeId: string) => Set<string>;\n isNodeShowingChangeAnalysis: (nodeId: string) => boolean;\n\n //actions\n runRowCount: () => Promise<void>;\n runRowCountDiff: () => Promise<void>;\n runValueDiff: () => Promise<void>;\n addLineageDiffCheck: (viewMode?: string) => void;\n addSchemaDiffCheck: () => void;\n cancel: () => void;\n actionState: ActionState;\n\n // Column Level Lineage\n centerNode: (nodeId: string) => void;\n showColumnLevelLineage: (cll?: CllInput) => Promise<void>;\n resetColumnLevelLineage: (previous?: boolean) => Promise<void>;\n}\n\nexport const LineageViewContext = createContext<\n LineageViewContextType | undefined\n>(undefined);\n\nexport const useLineageViewContextSafe = (): LineageViewContextType => {\n const context = useContext(LineageViewContext);\n if (!context) {\n throw new Error(\n \"useLineageViewContext must be used within a LineageViewProvider\",\n );\n }\n return context;\n};\n\nexport const useLineageViewContext = (): LineageViewContextType | undefined => {\n return useContext(LineageViewContext);\n};\n","import {\n AmplitudeReturn,\n BaseEvent,\n EventOptions,\n Result,\n} from \"@amplitude/analytics-core\";\nimport { initAll, track as trk } from \"@amplitude/unified\";\n\nfunction track(\n eventInput: string | BaseEvent,\n // biome-ignore lint/suspicious/noExplicitAny: Amplitude library uses any for event properties\n eventProperties?: Record<string, any> | undefined,\n eventOptions?: EventOptions | undefined,\n): AmplitudeReturn<Result> {\n // If Amplitude isn't initialized, log to console instead\n if (!amplitudeInitialized) {\n console.log(\"[Tracking]\", eventInput, eventProperties, eventOptions);\n }\n return trk(eventInput, eventProperties, eventOptions);\n}\n\nlet amplitudeInitialized = false;\n\nexport function trackInit() {\n function getCookie(key: string) {\n const b = document.cookie.match(\"(^|;)\\\\s*\" + key + \"\\\\s*=\\\\s*([^;]+)\");\n return b ? b.pop() : \"\";\n }\n\n const userId =\n process.env.NODE_ENV === \"development\"\n ? \"web_dev\"\n : getCookie(\"recce_user_id\");\n const apiKey = process.env.AMPLITUDE_API_KEY;\n if (userId && apiKey) {\n try {\n void initAll(apiKey, {\n analytics: {\n userId,\n autocapture: true,\n },\n sessionReplay: {\n sampleRate: 1,\n },\n });\n amplitudeInitialized = true;\n } catch (e) {\n console.error(e);\n }\n }\n\n // Log when Amplitude is not initialized (for development/debugging)\n if (!amplitudeInitialized) {\n console.log(\n \"[Tracking] Amplitude not initialized (missing API key or user ID). Events will be logged to console instead.\",\n );\n }\n}\n\ninterface MultiNodeActionProps {\n type:\n | \"row_count\"\n | \"row_count_diff\"\n | \"value_diff\"\n | \"schema_diff\"\n | \"lineage_diff\";\n selected: \"single\" | \"multi\" | \"none\";\n}\n\nexport function trackMultiNodesAction(props: MultiNodeActionProps) {\n track(\"[Web] multi_nodes_action\", props);\n}\n\ninterface HistoryActionProps {\n name: \"show\" | \"hide\" | \"click_run\" | \"add_to_checklist\" | \"go_to_check\";\n}\n\nexport function trackHistoryAction(props: HistoryActionProps) {\n track(\"[Web] history_action\", props);\n}\n\ninterface PreviewChangeProps {\n action: \"explore\" | \"run\" | \"close\";\n node?: string;\n status?: \"success\" | \"failure\";\n}\n\nexport function trackPreviewChange(props: PreviewChangeProps) {\n track(\"[Experiment] preview_change\", props);\n}\n\ninterface PreviewChangeFeedbackProps {\n feedback: \"like\" | \"dislike\" | \"form\";\n node?: string;\n}\n\nexport function trackPreviewChangeFeedback(props: PreviewChangeFeedbackProps) {\n track(\"[Experiment] preview_change\", props);\n}\n\ninterface SingleEnvironmentProps {\n action:\n | \"onboarding\"\n | \"external_link\"\n | \"preview_changes\"\n | `target_base_added`;\n from?: \"onboarding\" | \"preview_changes\";\n node?: string;\n}\n\nexport function trackSingleEnvironment(props: SingleEnvironmentProps) {\n track(\"[Experiment] single_environment\", props);\n}\n\nexport function getExperimentTrackingBreakingChangeEnabled() {\n return false;\n}\n\ninterface ColumnLevelLineageProps {\n action: \"view\";\n source: \"schema_column\" | \"changed_column\" | \"cll_column\";\n}\n\nexport function trackColumnLevelLineage(props: ColumnLevelLineageProps) {\n track(\"[Web] column_level_lineage\", props);\n}\n\ninterface ShareStateProps {\n name: \"enable\" | \"create\" | \"copy\";\n}\n\nexport function trackShareState(props: ShareStateProps) {\n track(\"[Web] share_state\", props);\n}\n\ninterface StateActionProps {\n name: \"import\" | \"export\";\n}\n\nexport function trackStateAction(props: StateActionProps) {\n track(\"[Web] state_action\", props);\n}\n\ninterface CopyToClipboardProps {\n from: \"run\" | \"check\" | \"lineage_view\";\n type: string;\n}\n\nexport function trackCopyToClipboard(props: CopyToClipboardProps) {\n track(\"[Click] copy_to_clipboard\", props);\n}\n\ninterface TrackNavProps {\n from: string;\n to: string;\n}\n\nexport function trackNavigation(props: TrackNavProps) {\n track(\"[Web] navigation_change\", props);\n}\n\nexport interface LineageViewRenderProps {\n node_count: number;\n view_mode: string;\n impact_radius_enabled: boolean;\n cll_column_active?: boolean;\n right_sidebar_open: boolean;\n [status: string]: number | string | boolean | undefined;\n}\n\nexport function trackLineageViewRender(props: LineageViewRenderProps) {\n track(\"[Web] lineage_view_render\", props);\n}\n\nexport interface EnvironmentConfigProps {\n review_mode: boolean;\n adapter_type: string | null;\n has_git_info: boolean;\n has_pr_info: boolean;\n // Adapter-specific (shape varies by adapter_type)\n base?: {\n schema_count?: number;\n dbt_version?: string | null;\n timestamp?: string | null;\n has_env?: boolean;\n };\n current?: {\n schema_count?: number;\n dbt_version?: string | null;\n timestamp?: string | null;\n has_env?: boolean;\n };\n schemas_match?: boolean;\n}\n\nexport function trackEnvironmentConfig(props: EnvironmentConfigProps) {\n track(\"[Web] environment_config\", props);\n}\n\n// Explore action types\nexport const EXPLORE_ACTION = {\n ROW_COUNT: \"row_count\",\n ROW_COUNT_DIFF: \"row_count_diff\",\n PROFILE: \"profile\",\n PROFILE_DIFF: \"profile_diff\",\n VALUE_DIFF: \"value_diff\",\n SCHEMA_DIFF: \"schema_diff\",\n LINEAGE_DIFF: \"lineage_diff\",\n QUERY: \"query\",\n HISTOGRAM_DIFF: \"histogram_diff\",\n TOP_K_DIFF: \"top_k_diff\",\n} as const;\n\n// Explore action sources\nexport const EXPLORE_SOURCE = {\n LINEAGE_VIEW_TOP_BAR: \"lineage_view_top_bar\",\n LINEAGE_VIEW_CONTEXT_MENU: \"lineage_view_context_menu\",\n NODE_KEBAB_MENU: \"node_kebab_menu\",\n NODE_SIDEBAR_SINGLE_ENV: \"node_sidebar_single_env\",\n NODE_SIDEBAR_MULTI_ENV: \"node_sidebar_multi_env\",\n SCHEMA_ROW_COUNT_BUTTON: \"schema_row_count_button\",\n SCHEMA_COLUMN_MENU: \"schema_column_menu\",\n} as const;\n\nexport type ExploreActionType =\n (typeof EXPLORE_ACTION)[keyof typeof EXPLORE_ACTION];\nexport type ExploreSourceType =\n (typeof EXPLORE_SOURCE)[keyof typeof EXPLORE_SOURCE];\n\ninterface ExploreActionProps {\n action: ExploreActionType;\n source: ExploreSourceType;\n node_count?: number;\n}\n\nexport function trackExploreAction(props: ExploreActionProps) {\n track(\"[Web] explore_action\", props);\n}\n\n// Explore action form events\nexport const EXPLORE_FORM_EVENT = {\n EXECUTE: \"execute\",\n CANCEL: \"cancel\",\n} as const;\n\nexport type ExploreFormEventType =\n (typeof EXPLORE_FORM_EVENT)[keyof typeof EXPLORE_FORM_EVENT];\n\ninterface ExploreActionFormProps {\n action: ExploreActionType;\n event: ExploreFormEventType;\n}\n\nexport function trackExploreActionForm(props: ExploreActionFormProps) {\n track(\"[Web] explore_action_form\", props);\n}\n\n// Helper to check if a run type is an explore action\nexport function isExploreAction(type: string): type is ExploreActionType {\n return Object.values(EXPLORE_ACTION).includes(type as ExploreActionType);\n}\n\n// Lineage selection action types\nexport const LINEAGE_SELECTION_ACTION = {\n SELECT_PARENT_NODES: \"select_parent_nodes\",\n SELECT_CHILD_NODES: \"select_child_nodes\",\n SELECT_ALL_UPSTREAM: \"select_all_upstream\",\n SELECT_ALL_DOWNSTREAM: \"select_all_downstream\",\n} as const;\n\nexport type LineageSelectionActionType =\n (typeof LINEAGE_SELECTION_ACTION)[keyof typeof LINEAGE_SELECTION_ACTION];\n\ninterface LineageSelectionProps {\n action: LineageSelectionActionType;\n node_count?: number;\n}\n\nexport function trackLineageSelection(props: LineageSelectionProps) {\n track(\"[Web] lineage_selection\", props);\n}\n","import {\n Box,\n Button,\n CloseButton,\n Dialog,\n Flex,\n Portal,\n useDisclosure,\n} from \"@chakra-ui/react\";\nimport React, { useCallback, useRef, useState } from \"react\";\nimport {\n EXPLORE_ACTION,\n EXPLORE_FORM_EVENT,\n trackExploreActionForm,\n} from \"@/lib/api/track\";\n\nfunction useValueDiffAlertDialog() {\n const { open, onOpen, onClose } = useDisclosure();\n const [nodeCount, setNodeCount] = useState(0);\n const [resolvePromise, setResolvePromise] =\n useState<(value: boolean) => void>();\n const cancelRef = useRef<HTMLButtonElement>(null);\n\n const confirm = useCallback(\n (nodeCount: number) => {\n setNodeCount(nodeCount);\n return new Promise<boolean>((resolve) => {\n setResolvePromise(() => resolve);\n onOpen();\n });\n },\n [onOpen],\n );\n\n const handleConfirm = () => {\n trackExploreActionForm({\n action: EXPLORE_ACTION.VALUE_DIFF,\n event: EXPLORE_FORM_EVENT.EXECUTE,\n });\n resolvePromise?.(true);\n onClose();\n };\n\n const handleCancel = () => {\n trackExploreActionForm({\n action: EXPLORE_ACTION.VALUE_DIFF,\n event: EXPLORE_FORM_EVENT.CANCEL,\n });\n resolvePromise?.(false);\n onClose();\n };\n\n const ValueDiffAlertDialog = (\n <Dialog.Root\n size={\"xl\"}\n open={open}\n role=\"alertdialog\"\n initialFocusEl={() => {\n return cancelRef.current;\n }}\n onOpenChange={handleCancel}\n >\n <Portal>\n <Dialog.Backdrop />\n <Dialog.Positioner>\n <Dialog.Content>\n <Dialog.Header fontSize=\"lg\" fontWeight=\"bold\">\n <Dialog.Title>Value Diff on {nodeCount} nodes</Dialog.Title>\n </Dialog.Header>\n\n <Dialog.Body gap=\"20px\" as={Flex} direction=\"column\">\n <Box>\n Value diff will be executed on {nodeCount} nodes in the Lineage,\n which can add extra costs to your bill.\n </Box>\n </Dialog.Body>\n\n <Dialog.Footer gap={1}>\n <Button\n ref={cancelRef}\n onClick={handleCancel}\n variant=\"outline\"\n colorPalette=\"gray\"\n >\n Cancel\n </Button>\n <Button colorPalette=\"iochmara\" onClick={handleConfirm} ml={3}>\n Execute\n </Button>\n </Dialog.Footer>\n <Dialog.CloseTrigger asChild>\n <CloseButton size=\"sm\" />\n </Dialog.CloseTrigger>\n </Dialog.Content>\n </Dialog.Positioner>\n </Portal>\n </Dialog.Root>\n );\n\n return { confirm, AlertDialog: ValueDiffAlertDialog };\n}\n\nexport default useValueDiffAlertDialog;\n"]}