diff --git a/backend/src/services/offline-usage-report/offline-usage-report-dal.ts b/backend/src/services/offline-usage-report/offline-usage-report-dal.ts index d979887ef..109d90da8 100644 --- a/backend/src/services/offline-usage-report/offline-usage-report-dal.ts +++ b/backend/src/services/offline-usage-report/offline-usage-report-dal.ts @@ -1,5 +1,5 @@ import { TDbClient } from "@app/db"; -import { TableName } from "@app/db/schemas"; +import { ProjectType, TableName } from "@app/db/schemas"; export type TOfflineUsageReportDALFactory = ReturnType; @@ -110,6 +110,7 @@ export const offlineUsageReportDALFactory = (db: TDbClient) => { .leftJoin(`${TableName.SecretFolder} as sf`, "s.folderId", "sf.id") .leftJoin(`${TableName.Environment} as e`, "sf.envId", "e.id") .leftJoin(`${TableName.Project} as p`, "e.projectId", "p.id") + .where("p.type", ProjectType.SecretManager) .groupBy("p.id") .whereNotNull("p.id")) as Array<{ projectId: string; count: string }>; @@ -144,6 +145,7 @@ export const offlineUsageReportDALFactory = (db: TDbClient) => { .leftJoin(`${TableName.SecretFolder} as sf`, "s.folderId", "sf.id") .leftJoin(`${TableName.Environment} as e`, "sf.envId", "e.id") .leftJoin(`${TableName.Project} as p`, "e.projectId", "p.id") + .where("p.type", ProjectType.SecretManager) .groupBy("p.id", "p.name") .whereNotNull("p.id")) as Array<{ projectId: string; projectName: string; secretCount: string }>; diff --git a/frontend/src/helpers/download.ts b/frontend/src/helpers/download.ts index 50adf4fe2..d1659a956 100644 --- a/frontend/src/helpers/download.ts +++ b/frontend/src/helpers/download.ts @@ -4,3 +4,15 @@ export const downloadTxtFile = (filename: string, content: string) => { const blob = new Blob([content], { type: "text/plain;charset=utf-8" }); FileSaver.saveAs(blob, filename); }; + +export const downloadFile = (content: string, filename: string, mimeType: string = "text/csv") => { + const blob = new Blob([content], { type: mimeType }); + const url = window.URL.createObjectURL(blob); + const link = document.createElement("a"); + link.href = url; + link.download = filename; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + window.URL.revokeObjectURL(url); +}; diff --git a/frontend/src/pages/admin/GeneralPage/components/UsageReportSection.tsx b/frontend/src/pages/admin/GeneralPage/components/UsageReportSection.tsx index 21e4da557..d05800996 100644 --- a/frontend/src/pages/admin/GeneralPage/components/UsageReportSection.tsx +++ b/frontend/src/pages/admin/GeneralPage/components/UsageReportSection.tsx @@ -1,32 +1,18 @@ -import { useState } from "react"; import { faDownload, faFileAlt, faSpinner } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { createNotification } from "@app/components/notifications"; import { Button, Card, CardTitle } from "@app/components/v2"; -import { apiRequest } from "@app/config/request"; +import { downloadFile } from "@app/helpers/download"; +import { useGenerateUsageReport } from "@app/hooks/api/admin/mutation"; export const UsageReportSection = () => { - const [isGenerating, setIsGenerating] = useState(false); - - const downloadFile = (content: string, filename: string, mimeType: string = "text/csv") => { - const blob = new Blob([content], { type: mimeType }); - const url = window.URL.createObjectURL(blob); - const link = document.createElement("a"); - link.href = url; - link.download = filename; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - window.URL.revokeObjectURL(url); - }; + const generateUsageReport = useGenerateUsageReport(); const handleGenerateReport = async () => { try { - setIsGenerating(true); - - const response = await apiRequest.post("/api/v1/admin/usage-report/generate", {}); - const { csvContent, filename } = response.data; + const response = await generateUsageReport.mutateAsync(); + const { csvContent, filename } = response; downloadFile(csvContent, filename, "text/csv"); @@ -40,8 +26,6 @@ export const UsageReportSection = () => { text: "Failed to generate usage report. Please try again.", type: "error" }); - } finally { - setIsGenerating(false); } }; @@ -53,19 +37,16 @@ export const UsageReportSection = () => {
- Generate tamper-proof, cryptographically signed usage reports to ensure offline license - compliance and accurate billing verification. Reports capture user counts, machine - identities, project details, and secrets metadata, providing a secure and verifiable audit - trail. + Generate secure usage reports for offline license compliance and billing verification.
);