Compare commits

...

1 Commits

Author SHA1 Message Date
Fraser
64fb24e355 Split api/analytics.ts into search telemetry and the export mutation
The file bundled two unrelated concerns. Search tracking now lives in
api/analytics/search.ts next to its only caller, and the export
mutation in api/analytics/export.ts. The analytics/ directory satisfies
the no-analytics-import-outside-analytics-files rule that pinned the
old filename.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 15:23:08 +12:00
5 changed files with 54 additions and 51 deletions

View File

@@ -0,0 +1,48 @@
import { openSaveDialog } from "metabase/utils/dom";
import { Api } from "../api";
export interface ExportAnalyticsResponse {
filename: string;
}
export const analyticsApi = Api.injectEndpoints({
endpoints: (builder) => ({
exportAnalytics: builder.mutation<ExportAnalyticsResponse, void>({
async queryFn(_arg, { signal }) {
try {
const response = await fetch(
"/api/ee/audit-app/analytics-dev/export",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
credentials: "include",
signal,
},
);
if (!response.ok) {
return { error: new Error("Export failed") };
}
const contentDisposition = response.headers.get(
"Content-Disposition",
);
const filenameMatch = contentDisposition?.match(/filename="(.+)"/);
const filename = filenameMatch?.[1] || "analytics-export.tar.gz";
const fileContent = await response.blob();
openSaveDialog(filename, fileContent);
return { data: { filename } };
} catch (error) {
return { error };
}
},
}),
}),
});
export const { useExportAnalyticsMutation } = analyticsApi;

View File

@@ -5,60 +5,12 @@ import {
shouldReportSearchTerm,
trackSchemaEvent,
} from "metabase/analytics";
import { openSaveDialog } from "metabase/utils/dom";
import {
toSnowplowContentTypes,
toSnowplowContext,
} from "metabase-types/analytics";
import type { SearchRequest, SearchResponse } from "metabase-types/api";
import { Api } from "./api";
export interface ExportAnalyticsResponse {
filename: string;
}
export const analyticsApi = Api.injectEndpoints({
endpoints: (builder) => ({
exportAnalytics: builder.mutation<ExportAnalyticsResponse, void>({
async queryFn(_arg, { signal }) {
try {
const response = await fetch(
"/api/ee/audit-app/analytics-dev/export",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
credentials: "include",
signal,
},
);
if (!response.ok) {
return { error: new Error("Export failed") };
}
const contentDisposition = response.headers.get(
"Content-Disposition",
);
const filenameMatch = contentDisposition?.match(/filename="(.+)"/);
const filename = filenameMatch?.[1] || "analytics-export.tar.gz";
const fileContent = await response.blob();
openSaveDialog(filename, fileContent);
return { data: { filename } };
} catch (error) {
return { error };
}
},
}),
}),
});
export const { useExportAnalyticsMutation } = analyticsApi;
type SearchRequestFilter = Pick<
SearchRequest,
| "created_by"

View File

@@ -1,7 +1,7 @@
import type { SearchRequest, SearchResponse } from "metabase-types/api";
import { createMockSearchResults } from "metabase-types/api/mocks";
import { registerSearchStarted, trackFulfilledSearch } from "./analytics";
import { registerSearchStarted, trackFulfilledSearch } from "./search";
// hashSearchTerm/shouldReportSearchTerm are stubbed to avoid crypto.subtle / Settings in the hashing
// path; we only care about the tracking lifecycle here.

View File

@@ -1,7 +1,7 @@
export * from "./action";
export * from "./activity";
export * from "./ai-entity-analysis";
export * from "./analytics";
export * from "./analytics/export";
export * from "./api";
export * from "./api-key";
export * from "./automagic-dashboards";

View File

@@ -1,6 +1,9 @@
import type { SearchRequest, SearchResponse } from "metabase-types/api";
import { registerSearchStarted, trackFulfilledSearch } from "./analytics";
import {
registerSearchStarted,
trackFulfilledSearch,
} from "./analytics/search";
import { Api } from "./api";
import { provideSearchItemListTags } from "./tags";
import { handleQueryFulfilled } from "./utils/lifecycle";