@datarecce/ui 0.1.39 → 0.1.41

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 (40) hide show
  1. package/dist/api.d.mts +1 -1
  2. package/dist/api.d.ts +1 -1
  3. package/dist/{components-DTLQ2djq.js → components-DfXnN1Hx.js} +592 -13
  4. package/dist/components-DfXnN1Hx.js.map +1 -0
  5. package/dist/{components-B6oaPB5f.mjs → components-jh6r4tQn.mjs} +593 -14
  6. package/dist/components-jh6r4tQn.mjs.map +1 -0
  7. package/dist/components.d.mts +1 -1
  8. package/dist/components.d.ts +1 -1
  9. package/dist/components.js +1 -1
  10. package/dist/components.mjs +1 -1
  11. package/dist/hooks.d.mts +1 -1
  12. package/dist/hooks.d.ts +1 -1
  13. package/dist/{index-DzBojsjY.d.mts → index-B5bpmv0i.d.mts} +70 -70
  14. package/dist/{index-DzBojsjY.d.mts.map → index-B5bpmv0i.d.mts.map} +1 -1
  15. package/dist/{index-DvKRw-cR.d.ts → index-B9lSPJTi.d.ts} +70 -70
  16. package/dist/index-B9lSPJTi.d.ts.map +1 -0
  17. package/dist/index.d.mts +1 -1
  18. package/dist/index.d.ts +1 -1
  19. package/dist/index.js +1 -1
  20. package/dist/index.mjs +1 -1
  21. package/dist/theme.d.mts +1 -1
  22. package/dist/theme.d.ts +1 -1
  23. package/dist/types.d.mts +1 -1
  24. package/dist/types.d.ts +1 -1
  25. package/package.json +1 -1
  26. package/recce-source/docs/plans/2024-12-31-csv-download-design.md +121 -0
  27. package/recce-source/docs/plans/2024-12-31-csv-download-implementation.md +930 -0
  28. package/recce-source/js/src/components/run/RunResultPane.tsx +138 -14
  29. package/recce-source/js/src/lib/csv/extractors.test.ts +456 -0
  30. package/recce-source/js/src/lib/csv/extractors.ts +468 -0
  31. package/recce-source/js/src/lib/csv/format.test.ts +211 -0
  32. package/recce-source/js/src/lib/csv/format.ts +44 -0
  33. package/recce-source/js/src/lib/csv/index.test.ts +155 -0
  34. package/recce-source/js/src/lib/csv/index.ts +109 -0
  35. package/recce-source/js/src/lib/hooks/useCSVExport.ts +136 -0
  36. package/recce-source/recce/mcp_server.py +54 -30
  37. package/recce-source/recce/models/check.py +10 -2
  38. package/dist/components-B6oaPB5f.mjs.map +0 -1
  39. package/dist/components-DTLQ2djq.js.map +0 -1
  40. package/dist/index-DvKRw-cR.d.ts.map +0 -1
package/dist/api.d.mts CHANGED
@@ -1,3 +1,3 @@
1
1
 
2
- import { $i as getLineageDiff, $r as ValueDiffDetailViewOptions, A as connectToCloud, Ai as getRun, B as submitQueryBase, Bi as getCll, C as SchemaDiffViewParams, Ci as TopKResult, D as markOnboardingCompleted, Di as SubmitRunTrackProps, E as getServerFlag, Ei as SubmitOptions, F as QueryPreviewChangeParams, Fi as waitRun, Gi as LineageDiffResult, Hi as LineageData, I as QueryResult, Ii as CllInput, Ji as NodeColumnData, Ki as ManifestMetadata, L as QueryRunParams, Li as CllNodeData, M as QueryDiffResult, Mi as searchRuns, N as QueryDiffViewOptions, Ni as submitRun, O as markRelaunchHintCompleted, Oi as aggregateRuns, P as QueryParams, Pi as submitRunFromCheck, Qi as getLineage, Qr as ValueDiffDetailResult, R as QueryViewOptions, Ri as ColumnLineageData, S as select, Si as TopKDiffResult, T as RecceServerFlags, Ti as RunsAggregated, Ui as LineageDataFromMetadata, V as submitQueryDiff, Vi as CatalogMetadata, Wi as LineageDiffData, Xi as SQLMeshInfo, Yi as NodeData, Zi as ServerInfoResult, Zr as ValueDiffDetailParams, _ as saveAs, _i as HistogramResult, _r as reorderChecks, a as User, aa as stateMetadata, ai as RowCountDiffResult, b as SelectInput, bi as ProfileDiffViewOptions, c as ImportedState, ci as submitRowCountDiff, cr as createLineageDiffCheck, d as SyncStateInput, di as RowCountDiff, dr as createCheckByRun, ea as getLineageWithError, ei as ValueDiffParams, f as SyncStateResponse, fi as fetchModelRowCount, fr as createSimpleCheck, g as rename, ga as reactQueryClient, gi as HistogramDiffResult, gr as markAsPresetCheck, h as isStateSyncing, ha as axiosClient, hi as HistogramDiffParams, hr as listChecks, i as useVersionNumber, ia as pullRequestInfo, ii as RowCountDiffParams, j as QueryDiffParams, ji as listRuns, k as ConnectToCloud, ki as cancelRun, l as SaveAsInput, li as QueryRowCountResult, lr as Check, m as importState, mi as queryRowCount, mr as getCheck, n as localStorageKeys, na as getServerInfo, ni as submitValueDiff, o as fetchGitHubAvatar, oi as RowCountParams, p as exportState, pi as queryModelRowCount, pr as deleteCheck, qi as ModelInfoResult, r as getVersion, ra as gitInfo, ri as submitValueDiffDetail, s as fetchUser, si as RowCountResult, sr as LineageDiffViewOptions, t as sessionStorageKeys, ta as getModelInfo, ti as ValueDiffResult, u as ShareStateResponse, ui as RowCount, ur as CreateCheckBody, v as shareState, vi as ProfileDiffParams, vr as updateCheck, w as createSchemaDiffCheck, wi as submitProfileDiff, x as SelectOutput, xi as TopKDiffParams, y as syncState, yi as ProfileDiffResult, yr as useChecks, z as submitQuery, zi as ImpactRadiusParams } from "./index-DzBojsjY.mjs";
2
+ import { $i as getLineageDiff, $r as ValueDiffDetailViewOptions, A as connectToCloud, Ai as getRun, B as submitQueryBase, Bi as getCll, C as SchemaDiffViewParams, Ci as TopKResult, D as markOnboardingCompleted, Di as SubmitRunTrackProps, E as getServerFlag, Ei as SubmitOptions, F as QueryPreviewChangeParams, Fi as waitRun, Gi as LineageDiffResult, Hi as LineageData, I as QueryResult, Ii as CllInput, Ji as NodeColumnData, Ki as ManifestMetadata, L as QueryRunParams, Li as CllNodeData, M as QueryDiffResult, Mi as searchRuns, N as QueryDiffViewOptions, Ni as submitRun, O as markRelaunchHintCompleted, Oi as aggregateRuns, P as QueryParams, Pi as submitRunFromCheck, Qi as getLineage, Qr as ValueDiffDetailResult, R as QueryViewOptions, Ri as ColumnLineageData, S as select, Si as TopKDiffResult, T as RecceServerFlags, Ti as RunsAggregated, Ui as LineageDataFromMetadata, V as submitQueryDiff, Vi as CatalogMetadata, Wi as LineageDiffData, Xi as SQLMeshInfo, Yi as NodeData, Zi as ServerInfoResult, Zr as ValueDiffDetailParams, _ as saveAs, _i as HistogramResult, _r as reorderChecks, a as User, aa as stateMetadata, ai as RowCountDiffResult, b as SelectInput, bi as ProfileDiffViewOptions, c as ImportedState, ci as submitRowCountDiff, cr as createLineageDiffCheck, d as SyncStateInput, di as RowCountDiff, dr as createCheckByRun, ea as getLineageWithError, ei as ValueDiffParams, f as SyncStateResponse, fi as fetchModelRowCount, fr as createSimpleCheck, g as rename, ga as reactQueryClient, gi as HistogramDiffResult, gr as markAsPresetCheck, h as isStateSyncing, ha as axiosClient, hi as HistogramDiffParams, hr as listChecks, i as useVersionNumber, ia as pullRequestInfo, ii as RowCountDiffParams, j as QueryDiffParams, ji as listRuns, k as ConnectToCloud, ki as cancelRun, l as SaveAsInput, li as QueryRowCountResult, lr as Check, m as importState, mi as queryRowCount, mr as getCheck, n as localStorageKeys, na as getServerInfo, ni as submitValueDiff, o as fetchGitHubAvatar, oi as RowCountParams, p as exportState, pi as queryModelRowCount, pr as deleteCheck, qi as ModelInfoResult, r as getVersion, ra as gitInfo, ri as submitValueDiffDetail, s as fetchUser, si as RowCountResult, sr as LineageDiffViewOptions, t as sessionStorageKeys, ta as getModelInfo, ti as ValueDiffResult, u as ShareStateResponse, ui as RowCount, ur as CreateCheckBody, v as shareState, vi as ProfileDiffParams, vr as updateCheck, w as createSchemaDiffCheck, wi as submitProfileDiff, x as SelectOutput, xi as TopKDiffParams, y as syncState, yi as ProfileDiffResult, yr as useChecks, z as submitQuery, zi as ImpactRadiusParams } from "./index-B5bpmv0i.mjs";
3
3
  export { CatalogMetadata, Check, CllInput, CllNodeData, ColumnLineageData, ConnectToCloud, CreateCheckBody, HistogramDiffParams, HistogramDiffResult, HistogramResult, ImpactRadiusParams, ImportedState, LineageData, LineageDataFromMetadata, LineageDiffData, LineageDiffResult, LineageDiffViewOptions, ManifestMetadata, ModelInfoResult, NodeColumnData, NodeData, ProfileDiffParams, ProfileDiffResult, ProfileDiffViewOptions, QueryDiffParams, QueryDiffResult, QueryDiffViewOptions, QueryParams, QueryPreviewChangeParams, QueryResult, QueryRowCountResult, QueryRunParams, QueryViewOptions, RecceServerFlags, RowCount, RowCountDiff, RowCountDiffParams, RowCountDiffResult, RowCountParams, RowCountResult, RunsAggregated, SQLMeshInfo, SaveAsInput, SchemaDiffViewParams, SelectInput, SelectOutput, ServerInfoResult, ShareStateResponse, SubmitOptions, SubmitRunTrackProps, SyncStateInput, SyncStateResponse, TopKDiffParams, TopKDiffResult, TopKResult, User, ValueDiffDetailParams, ValueDiffDetailResult, ValueDiffDetailViewOptions, ValueDiffParams, ValueDiffResult, aggregateRuns, axiosClient, cancelRun, connectToCloud, createCheckByRun, createLineageDiffCheck, createSchemaDiffCheck, createSimpleCheck, deleteCheck, exportState, fetchGitHubAvatar, fetchModelRowCount, fetchUser, getCheck, getCll, getLineage, getLineageDiff, getLineageWithError, getModelInfo, getRun, getServerFlag, getServerInfo, getVersion, gitInfo, importState, isStateSyncing, listChecks, listRuns, localStorageKeys, markAsPresetCheck, markOnboardingCompleted, markRelaunchHintCompleted, pullRequestInfo, queryModelRowCount, queryRowCount, reactQueryClient, rename, reorderChecks, saveAs, searchRuns, select, sessionStorageKeys, shareState, stateMetadata, submitProfileDiff, submitQuery, submitQueryBase, submitQueryDiff, submitRowCountDiff, submitRun, submitRunFromCheck, submitValueDiff, submitValueDiffDetail, syncState, updateCheck, useChecks, useVersionNumber, waitRun };
package/dist/api.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
 
2
- import { $i as getLineageDiff, $r as ValueDiffDetailViewOptions, A as connectToCloud, Ai as getRun, B as submitQueryBase, Bi as getCll, C as SchemaDiffViewParams, Ci as TopKResult, D as markOnboardingCompleted, Di as SubmitRunTrackProps, E as getServerFlag, Ei as SubmitOptions, F as QueryPreviewChangeParams, Fi as waitRun, Gi as LineageDiffResult, Hi as LineageData, I as QueryResult, Ii as CllInput, Ji as NodeColumnData, Ki as ManifestMetadata, L as QueryRunParams, Li as CllNodeData, M as QueryDiffResult, Mi as searchRuns, N as QueryDiffViewOptions, Ni as submitRun, O as markRelaunchHintCompleted, Oi as aggregateRuns, P as QueryParams, Pi as submitRunFromCheck, Qi as getLineage, Qr as ValueDiffDetailResult, R as QueryViewOptions, Ri as ColumnLineageData, S as select, Si as TopKDiffResult, T as RecceServerFlags, Ti as RunsAggregated, Ui as LineageDataFromMetadata, V as submitQueryDiff, Vi as CatalogMetadata, Wi as LineageDiffData, Xi as SQLMeshInfo, Yi as NodeData, Zi as ServerInfoResult, Zr as ValueDiffDetailParams, _ as saveAs, _i as HistogramResult, _r as reorderChecks, a as User, aa as stateMetadata, ai as RowCountDiffResult, b as SelectInput, bi as ProfileDiffViewOptions, c as ImportedState, ci as submitRowCountDiff, cr as createLineageDiffCheck, d as SyncStateInput, di as RowCountDiff, dr as createCheckByRun, ea as getLineageWithError, ei as ValueDiffParams, f as SyncStateResponse, fi as fetchModelRowCount, fr as createSimpleCheck, g as rename, ga as reactQueryClient, gi as HistogramDiffResult, gr as markAsPresetCheck, h as isStateSyncing, ha as axiosClient, hi as HistogramDiffParams, hr as listChecks, i as useVersionNumber, ia as pullRequestInfo, ii as RowCountDiffParams, j as QueryDiffParams, ji as listRuns, k as ConnectToCloud, ki as cancelRun, l as SaveAsInput, li as QueryRowCountResult, lr as Check, m as importState, mi as queryRowCount, mr as getCheck, n as localStorageKeys, na as getServerInfo, ni as submitValueDiff, o as fetchGitHubAvatar, oi as RowCountParams, p as exportState, pi as queryModelRowCount, pr as deleteCheck, qi as ModelInfoResult, r as getVersion, ra as gitInfo, ri as submitValueDiffDetail, s as fetchUser, si as RowCountResult, sr as LineageDiffViewOptions, t as sessionStorageKeys, ta as getModelInfo, ti as ValueDiffResult, u as ShareStateResponse, ui as RowCount, ur as CreateCheckBody, v as shareState, vi as ProfileDiffParams, vr as updateCheck, w as createSchemaDiffCheck, wi as submitProfileDiff, x as SelectOutput, xi as TopKDiffParams, y as syncState, yi as ProfileDiffResult, yr as useChecks, z as submitQuery, zi as ImpactRadiusParams } from "./index-DvKRw-cR.js";
2
+ import { $i as getLineageDiff, $r as ValueDiffDetailViewOptions, A as connectToCloud, Ai as getRun, B as submitQueryBase, Bi as getCll, C as SchemaDiffViewParams, Ci as TopKResult, D as markOnboardingCompleted, Di as SubmitRunTrackProps, E as getServerFlag, Ei as SubmitOptions, F as QueryPreviewChangeParams, Fi as waitRun, Gi as LineageDiffResult, Hi as LineageData, I as QueryResult, Ii as CllInput, Ji as NodeColumnData, Ki as ManifestMetadata, L as QueryRunParams, Li as CllNodeData, M as QueryDiffResult, Mi as searchRuns, N as QueryDiffViewOptions, Ni as submitRun, O as markRelaunchHintCompleted, Oi as aggregateRuns, P as QueryParams, Pi as submitRunFromCheck, Qi as getLineage, Qr as ValueDiffDetailResult, R as QueryViewOptions, Ri as ColumnLineageData, S as select, Si as TopKDiffResult, T as RecceServerFlags, Ti as RunsAggregated, Ui as LineageDataFromMetadata, V as submitQueryDiff, Vi as CatalogMetadata, Wi as LineageDiffData, Xi as SQLMeshInfo, Yi as NodeData, Zi as ServerInfoResult, Zr as ValueDiffDetailParams, _ as saveAs, _i as HistogramResult, _r as reorderChecks, a as User, aa as stateMetadata, ai as RowCountDiffResult, b as SelectInput, bi as ProfileDiffViewOptions, c as ImportedState, ci as submitRowCountDiff, cr as createLineageDiffCheck, d as SyncStateInput, di as RowCountDiff, dr as createCheckByRun, ea as getLineageWithError, ei as ValueDiffParams, f as SyncStateResponse, fi as fetchModelRowCount, fr as createSimpleCheck, g as rename, ga as reactQueryClient, gi as HistogramDiffResult, gr as markAsPresetCheck, h as isStateSyncing, ha as axiosClient, hi as HistogramDiffParams, hr as listChecks, i as useVersionNumber, ia as pullRequestInfo, ii as RowCountDiffParams, j as QueryDiffParams, ji as listRuns, k as ConnectToCloud, ki as cancelRun, l as SaveAsInput, li as QueryRowCountResult, lr as Check, m as importState, mi as queryRowCount, mr as getCheck, n as localStorageKeys, na as getServerInfo, ni as submitValueDiff, o as fetchGitHubAvatar, oi as RowCountParams, p as exportState, pi as queryModelRowCount, pr as deleteCheck, qi as ModelInfoResult, r as getVersion, ra as gitInfo, ri as submitValueDiffDetail, s as fetchUser, si as RowCountResult, sr as LineageDiffViewOptions, t as sessionStorageKeys, ta as getModelInfo, ti as ValueDiffResult, u as ShareStateResponse, ui as RowCount, ur as CreateCheckBody, v as shareState, vi as ProfileDiffParams, vr as updateCheck, w as createSchemaDiffCheck, wi as submitProfileDiff, x as SelectOutput, xi as TopKDiffParams, y as syncState, yi as ProfileDiffResult, yr as useChecks, z as submitQuery, zi as ImpactRadiusParams } from "./index-B9lSPJTi.js";
3
3
  export { CatalogMetadata, Check, CllInput, CllNodeData, ColumnLineageData, ConnectToCloud, CreateCheckBody, HistogramDiffParams, HistogramDiffResult, HistogramResult, ImpactRadiusParams, ImportedState, LineageData, LineageDataFromMetadata, LineageDiffData, LineageDiffResult, LineageDiffViewOptions, ManifestMetadata, ModelInfoResult, NodeColumnData, NodeData, ProfileDiffParams, ProfileDiffResult, ProfileDiffViewOptions, QueryDiffParams, QueryDiffResult, QueryDiffViewOptions, QueryParams, QueryPreviewChangeParams, QueryResult, QueryRowCountResult, QueryRunParams, QueryViewOptions, RecceServerFlags, RowCount, RowCountDiff, RowCountDiffParams, RowCountDiffResult, RowCountParams, RowCountResult, RunsAggregated, SQLMeshInfo, SaveAsInput, SchemaDiffViewParams, SelectInput, SelectOutput, ServerInfoResult, ShareStateResponse, SubmitOptions, SubmitRunTrackProps, SyncStateInput, SyncStateResponse, TopKDiffParams, TopKDiffResult, TopKResult, User, ValueDiffDetailParams, ValueDiffDetailResult, ValueDiffDetailViewOptions, ValueDiffParams, ValueDiffResult, aggregateRuns, axiosClient, cancelRun, connectToCloud, createCheckByRun, createLineageDiffCheck, createSchemaDiffCheck, createSimpleCheck, deleteCheck, exportState, fetchGitHubAvatar, fetchModelRowCount, fetchUser, getCheck, getCll, getLineage, getLineageDiff, getLineageWithError, getModelInfo, getRun, getServerFlag, getServerInfo, getVersion, gitInfo, importState, isStateSyncing, listChecks, listRuns, localStorageKeys, markAsPresetCheck, markOnboardingCompleted, markRelaunchHintCompleted, pullRequestInfo, queryModelRowCount, queryRowCount, reactQueryClient, rename, reorderChecks, saveAs, searchRuns, select, sessionStorageKeys, shareState, stateMetadata, submitProfileDiff, submitQuery, submitQueryBase, submitQueryDiff, submitRowCountDiff, submitRun, submitRunFromCheck, submitValueDiff, submitValueDiffDetail, syncState, updateCheck, useChecks, useVersionNumber, waitRun };
@@ -6496,6 +6496,512 @@ function AuthModal({ handleParentClose, parentOpen = false, ignoreCookie = false
6496
6496
  });
6497
6497
  }
6498
6498
 
6499
+ //#endregion
6500
+ //#region recce-source/js/src/lib/csv/format.ts
6501
+ /**
6502
+ * CSV formatting utilities with Excel-friendly output
6503
+ */
6504
+ /**
6505
+ * Escape a value for CSV format
6506
+ * - Wrap in quotes if contains comma, quote, or newline
6507
+ * - Escape quotes by doubling them
6508
+ */
6509
+ function escapeCSVValue(value) {
6510
+ if (value === null || value === void 0) return "";
6511
+ const stringValue = typeof value === "object" ? JSON.stringify(value) : String(value);
6512
+ if (stringValue.includes(",") || stringValue.includes("\"") || stringValue.includes("\n") || stringValue.includes("\r")) return `"${stringValue.replace(/"/g, "\"\"")}"`;
6513
+ return stringValue;
6514
+ }
6515
+ /**
6516
+ * Convert tabular data to CSV string
6517
+ * @param columns - Column headers
6518
+ * @param rows - Row data (array of arrays)
6519
+ * @returns CSV string with UTF-8 BOM for Excel compatibility
6520
+ */
6521
+ function toCSV(columns, rows) {
6522
+ return "" + [columns.map(escapeCSVValue).join(","), ...rows.map((row) => row.map(escapeCSVValue).join(","))].join("\r\n");
6523
+ }
6524
+
6525
+ //#endregion
6526
+ //#region recce-source/js/src/lib/csv/extractors.ts
6527
+ /**
6528
+ * Format a cell value for inline diff mode
6529
+ * If base and current are the same, return the value
6530
+ * If different, return "(base_value) (current_value)"
6531
+ */
6532
+ function formatInlineDiffCell(baseValue, currentValue) {
6533
+ if ((baseValue == null ? "" : String(baseValue)) === (currentValue == null ? "" : String(currentValue))) return baseValue;
6534
+ return `${baseValue == null ? "" : `(${baseValue})`} ${currentValue == null ? "" : `(${currentValue})`}`.trim();
6535
+ }
6536
+ /**
6537
+ * Extract columns and rows from a DataFrame
6538
+ */
6539
+ function extractDataFrame(df) {
6540
+ if (!df || !df.columns || !df.data) return null;
6541
+ return {
6542
+ columns: df.columns.map((col) => col.name),
6543
+ rows: df.data.map((row) => [...row])
6544
+ };
6545
+ }
6546
+ /**
6547
+ * Extract CSV data from query result (single environment)
6548
+ */
6549
+ function extractQuery(result) {
6550
+ return extractDataFrame(result);
6551
+ }
6552
+ /**
6553
+ * Extract CSV data from query_base result
6554
+ */
6555
+ function extractQueryBase(result) {
6556
+ return extractDataFrame(result);
6557
+ }
6558
+ /**
6559
+ * Extract CSV data from query_diff result
6560
+ * Supports two result shapes:
6561
+ * 1. { diff: DataFrame } - joined diff result (QueryDiffJoinResultView)
6562
+ * 2. { base: DataFrame, current: DataFrame } - separate base/current (QueryDiffResultView)
6563
+ *
6564
+ * Display modes:
6565
+ * - "inline": Merged rows where same values shown as-is, differing values shown as "(base) (current)"
6566
+ * - "side_by_side": Single row per record with base__col, current__col columns
6567
+ *
6568
+ * Note: When base and current have different row counts (e.g., added/removed rows),
6569
+ * the merge is done positionally. Extra rows will show null for the missing environment.
6570
+ */
6571
+ function extractQueryDiff(result, options) {
6572
+ const typed = result;
6573
+ const displayMode = options?.displayMode ?? "inline";
6574
+ const primaryKeys = options?.primaryKeys ?? [];
6575
+ if (typed?.diff) return extractQueryDiffJoined(typed.diff, displayMode, primaryKeys);
6576
+ return extractQueryDiffSeparate(typed, displayMode);
6577
+ }
6578
+ /**
6579
+ * Extract CSV from joined diff DataFrame (QueryDiffJoinResultView)
6580
+ * The diff DataFrame has columns like: pk, col1, col2, in_a, in_b
6581
+ * where in_a/in_b indicate presence in base/current
6582
+ *
6583
+ * The DataFrame may have separate rows for base (in_a=true) and current (in_b=true)
6584
+ * records. This function groups them by primary key and merges into single output rows.
6585
+ *
6586
+ * Produces same layout as extractQueryDiffSeparate for consistency.
6587
+ */
6588
+ function extractQueryDiffJoined(diff, displayMode, primaryKeys) {
6589
+ if (!diff?.columns || !diff?.data) return null;
6590
+ const inAIndex = diff.columns.findIndex((col) => col.key.toLowerCase() === "in_a");
6591
+ const inBIndex = diff.columns.findIndex((col) => col.key.toLowerCase() === "in_b");
6592
+ const dataColumns = diff.columns.filter((col) => col.key.toLowerCase() !== "in_a" && col.key.toLowerCase() !== "in_b");
6593
+ const dataColumnNames = dataColumns.map((col) => col.name);
6594
+ const dataColumnIndices = dataColumns.map((col) => diff.columns.findIndex((c) => c.key === col.key));
6595
+ const pkIndices = primaryKeys.map((pk) => diff.columns.findIndex((col) => col.key === pk)).filter((idx) => idx >= 0);
6596
+ const extractRowValues = (rowData) => {
6597
+ return dataColumnIndices.map((colIndex) => rowData[colIndex]);
6598
+ };
6599
+ const getPrimaryKeyValue = (rowData) => {
6600
+ if (pkIndices.length === 0) return "";
6601
+ return pkIndices.map((idx) => String(rowData[idx] ?? "")).join("|||");
6602
+ };
6603
+ const groupedRows = /* @__PURE__ */ new Map();
6604
+ const rowOrder = [];
6605
+ diff.data.forEach((rowData, index) => {
6606
+ const inA = inAIndex >= 0 ? rowData[inAIndex] : true;
6607
+ const inB = inBIndex >= 0 ? rowData[inBIndex] : true;
6608
+ let pkValue = getPrimaryKeyValue(rowData);
6609
+ if (pkValue === "") pkValue = String(index);
6610
+ if (!groupedRows.has(pkValue)) {
6611
+ groupedRows.set(pkValue, {
6612
+ base: null,
6613
+ current: null
6614
+ });
6615
+ rowOrder.push(pkValue);
6616
+ }
6617
+ const group = groupedRows.get(pkValue);
6618
+ if (!group) return;
6619
+ const values = extractRowValues(rowData);
6620
+ if (inA) group.base = values;
6621
+ if (inB) group.current = values;
6622
+ });
6623
+ if (displayMode === "side_by_side") {
6624
+ const columns$1 = [];
6625
+ dataColumnNames.forEach((name) => {
6626
+ columns$1.push(`base__${name}`, `current__${name}`);
6627
+ });
6628
+ const rows$1 = [];
6629
+ for (const pkValue of rowOrder) {
6630
+ const group = groupedRows.get(pkValue);
6631
+ if (!group) continue;
6632
+ const baseValues = group.base;
6633
+ const currentValues = group.current;
6634
+ const row = [];
6635
+ dataColumnNames.forEach((_$1, colIndex) => {
6636
+ row.push(baseValues ? baseValues[colIndex] : null);
6637
+ row.push(currentValues ? currentValues[colIndex] : null);
6638
+ });
6639
+ rows$1.push(row);
6640
+ }
6641
+ return {
6642
+ columns: columns$1,
6643
+ rows: rows$1
6644
+ };
6645
+ }
6646
+ const columns = [...dataColumnNames];
6647
+ const rows = [];
6648
+ for (const pkValue of rowOrder) {
6649
+ const group = groupedRows.get(pkValue);
6650
+ if (!group) continue;
6651
+ const baseValues = group.base;
6652
+ const currentValues = group.current;
6653
+ const row = [];
6654
+ dataColumnNames.forEach((_$1, colIndex) => {
6655
+ const baseVal = baseValues ? baseValues[colIndex] : null;
6656
+ const currentVal = currentValues ? currentValues[colIndex] : null;
6657
+ row.push(formatInlineDiffCell(baseVal, currentVal));
6658
+ });
6659
+ rows.push(row);
6660
+ }
6661
+ return {
6662
+ columns,
6663
+ rows
6664
+ };
6665
+ }
6666
+ /**
6667
+ * Extract CSV from separate base/current DataFrames (QueryDiffResultView)
6668
+ */
6669
+ function extractQueryDiffSeparate(typed, displayMode) {
6670
+ const df = typed?.current || typed?.base;
6671
+ if (!df) return null;
6672
+ if (!typed?.base || !typed?.current) return extractDataFrame(df);
6673
+ const columnNames = typed.current.columns.map((c) => c.name);
6674
+ if (displayMode === "side_by_side") {
6675
+ const columns$1 = [];
6676
+ columnNames.forEach((name) => {
6677
+ columns$1.push(`base__${name}`, `current__${name}`);
6678
+ });
6679
+ const rows$1 = [];
6680
+ const maxRows$1 = Math.max(typed.base.data.length, typed.current.data.length);
6681
+ for (let i = 0; i < maxRows$1; i++) {
6682
+ const row = [];
6683
+ const baseRow = i < typed.base.data.length ? typed.base.data[i] : null;
6684
+ const currentRow = i < typed.current.data.length ? typed.current.data[i] : null;
6685
+ columnNames.forEach((_$1, colIndex) => {
6686
+ row.push(baseRow ? baseRow[colIndex] : null);
6687
+ row.push(currentRow ? currentRow[colIndex] : null);
6688
+ });
6689
+ rows$1.push(row);
6690
+ }
6691
+ return {
6692
+ columns: columns$1,
6693
+ rows: rows$1
6694
+ };
6695
+ }
6696
+ const columns = [...columnNames];
6697
+ const rows = [];
6698
+ const maxRows = Math.max(typed.base.data.length, typed.current.data.length);
6699
+ for (let i = 0; i < maxRows; i++) {
6700
+ const baseRow = i < typed.base.data.length ? typed.base.data[i] : null;
6701
+ const currentRow = i < typed.current.data.length ? typed.current.data[i] : null;
6702
+ const row = [];
6703
+ columnNames.forEach((_$1, colIndex) => {
6704
+ const baseVal = baseRow ? baseRow[colIndex] : null;
6705
+ const currentVal = currentRow ? currentRow[colIndex] : null;
6706
+ row.push(formatInlineDiffCell(baseVal, currentVal));
6707
+ });
6708
+ rows.push(row);
6709
+ }
6710
+ return {
6711
+ columns,
6712
+ rows
6713
+ };
6714
+ }
6715
+ /**
6716
+ * Extract CSV data from profile_diff result
6717
+ */
6718
+ function extractProfileDiff(result) {
6719
+ const typed = result;
6720
+ const df = typed?.current || typed?.base;
6721
+ if (!df) return null;
6722
+ if (typed?.base && typed?.current) {
6723
+ const columns = ["_source", ...typed.current.columns.map((c) => c.name)];
6724
+ const rows = [];
6725
+ typed.base.data.forEach((row) => {
6726
+ rows.push(["base", ...row]);
6727
+ });
6728
+ typed.current.data.forEach((row) => {
6729
+ rows.push(["current", ...row]);
6730
+ });
6731
+ return {
6732
+ columns,
6733
+ rows
6734
+ };
6735
+ }
6736
+ return extractDataFrame(df);
6737
+ }
6738
+ /**
6739
+ * Extract CSV data from row_count_diff result
6740
+ */
6741
+ function extractRowCountDiff(result) {
6742
+ const typed = result;
6743
+ if (!typed || typeof typed !== "object") return null;
6744
+ const columns = [
6745
+ "node",
6746
+ "base_count",
6747
+ "current_count",
6748
+ "diff",
6749
+ "diff_percent"
6750
+ ];
6751
+ const rows = [];
6752
+ for (const [nodeName, counts] of Object.entries(typed)) if (counts && typeof counts === "object") {
6753
+ const base = counts.base;
6754
+ const current = counts.curr;
6755
+ const diff = base != null && current != null ? current - base : null;
6756
+ const diffPercent = base && diff !== null ? (diff / base * 100).toFixed(2) + "%" : null;
6757
+ rows.push([
6758
+ nodeName,
6759
+ base,
6760
+ current,
6761
+ diff,
6762
+ diffPercent
6763
+ ]);
6764
+ }
6765
+ return {
6766
+ columns,
6767
+ rows
6768
+ };
6769
+ }
6770
+ /**
6771
+ * Extract CSV data from value_diff result
6772
+ */
6773
+ function extractValueDiff(result) {
6774
+ const typed = result;
6775
+ if (!typed?.data) return null;
6776
+ return extractDataFrame(typed.data);
6777
+ }
6778
+ /**
6779
+ * Extract CSV data from value_diff_detail result
6780
+ */
6781
+ function extractValueDiffDetail(result) {
6782
+ return extractDataFrame(result);
6783
+ }
6784
+ /**
6785
+ * Extract CSV data from top_k_diff result
6786
+ */
6787
+ function extractTopKDiff(result) {
6788
+ const typed = result;
6789
+ const hasBaseValues = !!typed?.base?.values;
6790
+ const hasCurrentValues = !!typed?.current?.values;
6791
+ if (!hasBaseValues && !hasCurrentValues) return null;
6792
+ const columns = [
6793
+ "_source",
6794
+ "value",
6795
+ "count"
6796
+ ];
6797
+ const rows = [];
6798
+ if (typed?.base?.values) typed.base.values.forEach((value, index) => {
6799
+ rows.push([
6800
+ "base",
6801
+ value,
6802
+ typed.base.counts[index]
6803
+ ]);
6804
+ });
6805
+ if (typed?.current?.values) typed.current.values.forEach((value, index) => {
6806
+ rows.push([
6807
+ "current",
6808
+ value,
6809
+ typed.current.counts[index]
6810
+ ]);
6811
+ });
6812
+ return {
6813
+ columns,
6814
+ rows
6815
+ };
6816
+ }
6817
+ /**
6818
+ * Map of run types to their extractor functions
6819
+ * Some extractors accept options (like query_diff for displayMode)
6820
+ */
6821
+ const extractors = {
6822
+ query: extractQuery,
6823
+ query_base: extractQueryBase,
6824
+ query_diff: extractQueryDiff,
6825
+ profile: extractProfileDiff,
6826
+ profile_diff: extractProfileDiff,
6827
+ row_count: extractRowCountDiff,
6828
+ row_count_diff: extractRowCountDiff,
6829
+ value_diff: extractValueDiff,
6830
+ value_diff_detail: extractValueDiffDetail,
6831
+ top_k_diff: extractTopKDiff
6832
+ };
6833
+ /**
6834
+ * Extract CSV data from a run result
6835
+ * @param runType - The type of run (query, query_diff, etc.)
6836
+ * @param result - The run result data
6837
+ * @param options - Optional export options (e.g., displayMode for query_diff)
6838
+ * @returns CSVData or null if the run type doesn't support CSV export
6839
+ */
6840
+ function extractCSVData(runType, result, options) {
6841
+ const extractor = extractors[runType];
6842
+ if (!extractor) return null;
6843
+ try {
6844
+ return extractor(result, options);
6845
+ } catch (error) {
6846
+ console.error(`Failed to extract CSV data for run type "${runType}":`, error);
6847
+ return null;
6848
+ }
6849
+ }
6850
+ /**
6851
+ * Check if a run type supports CSV export
6852
+ */
6853
+ function supportsCSVExport(runType) {
6854
+ return runType in extractors;
6855
+ }
6856
+
6857
+ //#endregion
6858
+ //#region recce-source/js/src/lib/csv/index.ts
6859
+ /**
6860
+ * CSV export utilities
6861
+ */
6862
+ /**
6863
+ * Trigger browser download of CSV file
6864
+ */
6865
+ function downloadCSV(content, filename) {
6866
+ (0, file_saver.default)(new Blob([content], { type: "text/csv;charset=utf-8" }), filename);
6867
+ }
6868
+ /**
6869
+ * Copy CSV content to clipboard
6870
+ * Uses modern Clipboard API with fallback for older browsers
6871
+ */
6872
+ async function copyCSVToClipboard(content) {
6873
+ if (typeof navigator !== "undefined" && navigator.clipboard && typeof navigator.clipboard.writeText === "function") {
6874
+ await navigator.clipboard.writeText(content);
6875
+ return;
6876
+ }
6877
+ if (typeof document === "undefined") throw new Error("Clipboard API not available in this environment");
6878
+ const textarea = document.createElement("textarea");
6879
+ textarea.value = content;
6880
+ textarea.style.position = "fixed";
6881
+ textarea.style.opacity = "0";
6882
+ textarea.setAttribute("readonly", "");
6883
+ document.body.appendChild(textarea);
6884
+ textarea.focus();
6885
+ textarea.select();
6886
+ try {
6887
+ if (!document.execCommand("copy")) throw new Error("execCommand('copy') failed");
6888
+ } finally {
6889
+ document.body.removeChild(textarea);
6890
+ }
6891
+ }
6892
+ /**
6893
+ * Generate timestamp string for filenames
6894
+ * Format: YYYYMMDD-HHmmss
6895
+ */
6896
+ function generateTimestamp() {
6897
+ const now = /* @__PURE__ */ new Date();
6898
+ return `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, "0")}${String(now.getDate()).padStart(2, "0")}-${String(now.getHours()).padStart(2, "0")}${String(now.getMinutes()).padStart(2, "0")}${String(now.getSeconds()).padStart(2, "0")}`;
6899
+ }
6900
+ /**
6901
+ * Generate context-aware CSV filename
6902
+ */
6903
+ function generateCSVFilename(runType, params) {
6904
+ const timestamp = generateTimestamp();
6905
+ const type = runType.replace(/_/g, "-");
6906
+ let nodeName;
6907
+ if (params?.node_names && Array.isArray(params.node_names) && params.node_names.length === 1) nodeName = String(params.node_names[0]);
6908
+ else if (params?.model && typeof params.model === "string") nodeName = params.model;
6909
+ if (nodeName) {
6910
+ nodeName = nodeName.replace(/[^a-zA-Z0-9_.-]/g, "-").toLowerCase();
6911
+ return `${type}-${nodeName}-${timestamp}.csv`;
6912
+ }
6913
+ return `${type}-result-${timestamp}.csv`;
6914
+ }
6915
+
6916
+ //#endregion
6917
+ //#region recce-source/js/src/lib/hooks/useCSVExport.ts
6918
+ /**
6919
+ * Hook for CSV export functionality
6920
+ */
6921
+ function useCSVExport({ run, viewOptions }) {
6922
+ const canExportCSV = (0, react.useMemo)(() => {
6923
+ if (!run?.type || !run?.result) return false;
6924
+ return supportsCSVExport(run.type);
6925
+ }, [run?.type, run?.result]);
6926
+ const getCSVContent = (0, react.useCallback)(() => {
6927
+ if (!run?.type || !run?.result) return null;
6928
+ const exportOptions = {
6929
+ displayMode: viewOptions?.display_mode,
6930
+ primaryKeys: (run?.params)?.primary_keys
6931
+ };
6932
+ const csvData = extractCSVData(run.type, run.result, exportOptions);
6933
+ if (!csvData) return null;
6934
+ return toCSV(csvData.columns, csvData.rows);
6935
+ }, [
6936
+ run?.type,
6937
+ run?.result,
6938
+ run?.params,
6939
+ viewOptions
6940
+ ]);
6941
+ return {
6942
+ canExportCSV,
6943
+ copyAsCSV: (0, react.useCallback)(async () => {
6944
+ const content = getCSVContent();
6945
+ if (!content) {
6946
+ require_RecceCheckContext.toaster.create({
6947
+ title: "Export failed",
6948
+ description: "Unable to extract data for CSV export",
6949
+ type: "error",
6950
+ duration: 3e3
6951
+ });
6952
+ return;
6953
+ }
6954
+ try {
6955
+ await copyCSVToClipboard(content);
6956
+ require_RecceCheckContext.toaster.create({
6957
+ title: "Copied to clipboard",
6958
+ description: "CSV data copied successfully",
6959
+ type: "success",
6960
+ duration: 2e3
6961
+ });
6962
+ } catch (error) {
6963
+ console.error("Failed to copy CSV to clipboard:", error);
6964
+ require_RecceCheckContext.toaster.create({
6965
+ title: "Copy failed",
6966
+ description: "Failed to copy to clipboard",
6967
+ type: "error",
6968
+ duration: 3e3
6969
+ });
6970
+ }
6971
+ }, [getCSVContent]),
6972
+ downloadAsCSV: (0, react.useCallback)(() => {
6973
+ const content = getCSVContent();
6974
+ if (!content) {
6975
+ require_RecceCheckContext.toaster.create({
6976
+ title: "Export failed",
6977
+ description: "Unable to extract data for CSV export",
6978
+ type: "error",
6979
+ duration: 3e3
6980
+ });
6981
+ return;
6982
+ }
6983
+ try {
6984
+ const filename = generateCSVFilename(run?.type ?? "", run?.params);
6985
+ downloadCSV(content, filename);
6986
+ require_RecceCheckContext.toaster.create({
6987
+ title: "Downloaded",
6988
+ description: filename,
6989
+ type: "success",
6990
+ duration: 3e3
6991
+ });
6992
+ } catch (error) {
6993
+ console.error("Failed to download CSV file:", error);
6994
+ require_RecceCheckContext.toaster.create({
6995
+ title: "Download failed",
6996
+ description: "Failed to download CSV file",
6997
+ type: "error",
6998
+ duration: 3e3
6999
+ });
7000
+ }
7001
+ }, [getCSVContent, run])
7002
+ };
7003
+ }
7004
+
6499
7005
  //#endregion
6500
7006
  //#region recce-source/js/src/components/query/SqlEditor.tsx
6501
7007
  function SqlEditor({ value, onChange, onRun, onRunBase, onRunDiff, label, CustomEditor, options = {}, manifestData, schemas, ...props }) {
@@ -6890,12 +7396,71 @@ const SingleEnvironmentSetupNotification = ({ runType }) => {
6890
7396
  default: return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, {});
6891
7397
  }
6892
7398
  };
6893
- const RunResultShareMenu = ({ disableCopyToClipboard, onCopyToClipboard, onMouseEnter, onMouseLeave }) => {
7399
+ const RunResultExportMenu = ({ run, viewOptions, disableExport, onCopyAsImage, onMouseEnter, onMouseLeave }) => {
7400
+ const [anchorEl, setAnchorEl] = (0, react.useState)(null);
7401
+ const open = Boolean(anchorEl);
7402
+ const { canExportCSV, copyAsCSV, downloadAsCSV } = useCSVExport({
7403
+ run,
7404
+ viewOptions
7405
+ });
7406
+ const handleClick = (event) => {
7407
+ setAnchorEl(event.currentTarget);
7408
+ };
7409
+ const handleClose = () => {
7410
+ setAnchorEl(null);
7411
+ };
7412
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Button.default, {
7413
+ size: "small",
7414
+ variant: "outlined",
7415
+ color: "neutral",
7416
+ onClick: handleClick,
7417
+ endIcon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_pi.PiCaretDown, {}),
7418
+ sx: { textTransform: "none" },
7419
+ children: "Export"
7420
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Menu.default, {
7421
+ anchorEl,
7422
+ open,
7423
+ onClose: handleClose,
7424
+ children: [
7425
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_MenuItem.default, {
7426
+ onClick: async () => {
7427
+ await onCopyAsImage();
7428
+ handleClose();
7429
+ },
7430
+ onMouseEnter,
7431
+ onMouseLeave,
7432
+ disabled: disableExport,
7433
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_ListItemIcon.default, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_pi.PiImage, {}) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_ListItemText.default, { children: "Copy as Image" })]
7434
+ }),
7435
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_MenuItem.default, {
7436
+ onClick: async () => {
7437
+ await copyAsCSV();
7438
+ handleClose();
7439
+ },
7440
+ disabled: disableExport || !canExportCSV,
7441
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_ListItemIcon.default, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_pi.PiTable, {}) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_ListItemText.default, { children: "Copy as CSV" })]
7442
+ }),
7443
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_MenuItem.default, {
7444
+ onClick: () => {
7445
+ downloadAsCSV();
7446
+ handleClose();
7447
+ },
7448
+ disabled: disableExport || !canExportCSV,
7449
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_ListItemIcon.default, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_pi.PiDownloadSimple, {}) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_ListItemText.default, { children: "Download as CSV" })]
7450
+ })
7451
+ ]
7452
+ })] });
7453
+ };
7454
+ const RunResultShareMenu = ({ run, viewOptions, disableCopyToClipboard, onCopyToClipboard, onMouseEnter, onMouseLeave }) => {
6894
7455
  const { authed } = require_RecceCheckContext.useRecceInstanceContext();
6895
7456
  const { handleShareClick } = require_RecceCheckContext.useRecceShareStateContext();
6896
7457
  const [showModal, setShowModal] = (0, react.useState)(false);
6897
7458
  const [anchorEl, setAnchorEl] = (0, react.useState)(null);
6898
7459
  const open = Boolean(anchorEl);
7460
+ const { canExportCSV, copyAsCSV, downloadAsCSV } = useCSVExport({
7461
+ run,
7462
+ viewOptions
7463
+ });
6899
7464
  const handleClick = (event) => {
6900
7465
  setAnchorEl(event.currentTarget);
6901
7466
  };
@@ -6925,7 +7490,23 @@ const RunResultShareMenu = ({ disableCopyToClipboard, onCopyToClipboard, onMouse
6925
7490
  onMouseEnter,
6926
7491
  onMouseLeave,
6927
7492
  disabled: disableCopyToClipboard,
6928
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_ListItemIcon.default, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_pi.PiCopy, {}) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_ListItemText.default, { children: "Copy to Clipboard" })]
7493
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_ListItemIcon.default, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_pi.PiImage, {}) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_ListItemText.default, { children: "Copy as Image" })]
7494
+ }),
7495
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_MenuItem.default, {
7496
+ onClick: async () => {
7497
+ await copyAsCSV();
7498
+ handleClose();
7499
+ },
7500
+ disabled: disableCopyToClipboard || !canExportCSV,
7501
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_ListItemIcon.default, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_pi.PiTable, {}) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_ListItemText.default, { children: "Copy as CSV" })]
7502
+ }),
7503
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_MenuItem.default, {
7504
+ onClick: () => {
7505
+ downloadAsCSV();
7506
+ handleClose();
7507
+ },
7508
+ disabled: disableCopyToClipboard || !canExportCSV,
7509
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_ListItemIcon.default, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_pi.PiDownloadSimple, {}) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_ListItemText.default, { children: "Download as CSV" })]
6929
7510
  }),
6930
7511
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Divider.default, {}),
6931
7512
  authed ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_MenuItem.default, {
@@ -7023,18 +7604,16 @@ const PrivateLoadableRunView = ({ runId, onClose, isSingleEnvironment }) => {
7023
7604
  sx: { textTransform: "none" },
7024
7605
  children: "Rerun"
7025
7606
  }),
7026
- featureToggles.disableShare ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Button.default, {
7027
- variant: "outlined",
7028
- color: "neutral",
7029
- disabled: !runId || !run?.result || !!error || tabValue !== "result",
7607
+ featureToggles.disableShare ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RunResultExportMenu, {
7608
+ run,
7609
+ viewOptions,
7610
+ disableExport: !runId || !run?.result || !!error || tabValue !== "result",
7611
+ onCopyAsImage: onCopyToClipboard,
7030
7612
  onMouseEnter,
7031
- onMouseLeave,
7032
- size: "small",
7033
- onClick: onCopyToClipboard,
7034
- startIcon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_pi.PiCopy, {}),
7035
- sx: { textTransform: "none" },
7036
- children: "Copy to Clipboard"
7613
+ onMouseLeave
7037
7614
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RunResultShareMenu, {
7615
+ run,
7616
+ viewOptions,
7038
7617
  disableCopyToClipboard,
7039
7618
  onCopyToClipboard: async () => {
7040
7619
  await onCopyToClipboard();
@@ -14107,4 +14686,4 @@ Object.defineProperty(exports, 'mui_provider_default', {
14107
14686
  return mui_provider_default;
14108
14687
  }
14109
14688
  });
14110
- //# sourceMappingURL=components-DTLQ2djq.js.map
14689
+ //# sourceMappingURL=components-DfXnN1Hx.js.map