mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-03 10:26:00 +00:00
Address greptile comments
This commit is contained in:
@@ -863,13 +863,6 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
|
||||
});
|
||||
},
|
||||
handler: async () => {
|
||||
const cfg = getConfig();
|
||||
if (!cfg.LICENSE_KEY_OFFLINE) {
|
||||
throw new BadRequestError({
|
||||
message: "Offline usage reports are not enabled. LICENSE_KEY_OFFLINE must be configured."
|
||||
});
|
||||
}
|
||||
|
||||
const result = await server.services.offlineUsageReport.generateUsageReportCSV();
|
||||
|
||||
return {
|
||||
|
||||
@@ -104,17 +104,21 @@ export const offlineUsageReportDALFactory = (db: TDbClient) => {
|
||||
|
||||
// Calculate average secrets per project
|
||||
const secretsPerProject = (await db
|
||||
.from(TableName.SecretV2)
|
||||
.select("folderId")
|
||||
.count("* as count")
|
||||
.groupBy("folderId")) as Array<{ folderId: string; count: string }>;
|
||||
.from(`${TableName.SecretV2} as s`)
|
||||
.select("p.id as projectId")
|
||||
.count("s.id as count")
|
||||
.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")
|
||||
.groupBy("p.id")
|
||||
.whereNotNull("p.id")) as Array<{ projectId: string; count: string }>;
|
||||
|
||||
const averageSecretsPerProject =
|
||||
totalProjects > 0
|
||||
secretsPerProject.length > 0
|
||||
? secretsPerProject.reduce(
|
||||
(sum, row: { folderId: string; count: string }) => sum + parseInt(row.count, 10),
|
||||
(sum, row: { projectId: string; count: string }) => sum + parseInt(row.count, 10),
|
||||
0
|
||||
) / totalProjects
|
||||
) / secretsPerProject.length
|
||||
: 0;
|
||||
|
||||
return {
|
||||
|
||||
@@ -58,8 +58,6 @@ export const offlineUsageReportServiceFactory = ({
|
||||
offlineUsageReportDAL.getSecretRotationMetrics()
|
||||
]);
|
||||
|
||||
const csvLines: string[] = [];
|
||||
|
||||
const headers = [
|
||||
"Total Users",
|
||||
"Admin Users",
|
||||
@@ -89,8 +87,6 @@ export const offlineUsageReportServiceFactory = ({
|
||||
|
||||
headers.push("Signature");
|
||||
|
||||
csvLines.push(headers.slice(0, -1).join(","));
|
||||
|
||||
const dataRow: (string | number)[] = [
|
||||
userMetrics.totalUsers,
|
||||
userMetrics.adminUsers,
|
||||
@@ -114,14 +110,13 @@ export const offlineUsageReportServiceFactory = ({
|
||||
dataRow.push(projectMetrics.projectsByType[type] || 0);
|
||||
});
|
||||
|
||||
const tempCsvLines = [headers.slice(0, -1).join(","), dataRow.join(",")];
|
||||
const contentWithoutSignature = tempCsvLines.join("\n");
|
||||
const headersWithoutSignature = headers.slice(0, -1);
|
||||
const contentWithoutSignature = [headersWithoutSignature.join(","), dataRow.join(",")].join("\n");
|
||||
|
||||
const signature = signReportContent(contentWithoutSignature, licenseId);
|
||||
dataRow.push(signature);
|
||||
|
||||
const finalCsvLines = [headers.join(","), dataRow.join(",")];
|
||||
const csvContent = finalCsvLines.join("\n");
|
||||
const csvContent = [headers.join(","), dataRow.join(",")].join("\n");
|
||||
|
||||
return {
|
||||
csvContent,
|
||||
|
||||
@@ -8,7 +8,6 @@ import { adminQueryKeys, adminStandaloneKeys } from "./queries";
|
||||
import {
|
||||
RootKeyEncryptionStrategy,
|
||||
TCreateAdminUserDTO,
|
||||
TGenerateUsageReportDTO,
|
||||
TInvalidateCacheDTO,
|
||||
TServerConfig,
|
||||
TUpdateServerConfigDTO,
|
||||
@@ -197,11 +196,10 @@ export const useInvalidateCache = () => {
|
||||
};
|
||||
|
||||
export const useGenerateUsageReport = () => {
|
||||
return useMutation<TUsageReportResponse, object, TGenerateUsageReportDTO>({
|
||||
mutationFn: async (dto) => {
|
||||
return useMutation<TUsageReportResponse, object, void>({
|
||||
mutationFn: async () => {
|
||||
const { data } = await apiRequest.post<TUsageReportResponse>(
|
||||
"/api/v1/admin/usage-report/generate",
|
||||
dto
|
||||
"/api/v1/admin/usage-report/generate"
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -144,10 +144,6 @@ export interface TGetEnvOverrides {
|
||||
};
|
||||
}
|
||||
|
||||
export type TGenerateUsageReportDTO = {
|
||||
periodDays?: number;
|
||||
};
|
||||
|
||||
export type TUsageReportResponse = {
|
||||
filename: string;
|
||||
csvContent: string;
|
||||
|
||||
@@ -1,28 +1,14 @@
|
||||
import { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { faDownload, faFileAlt, faSpinner } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { Button, Card, CardTitle } from "@app/components/v2";
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
const formSchema = z.object({});
|
||||
|
||||
type TUsageReportForm = z.infer<typeof formSchema>;
|
||||
|
||||
export const UsageReportSection = () => {
|
||||
const [isGenerating, setIsGenerating] = useState(false);
|
||||
|
||||
const {
|
||||
handleSubmit,
|
||||
formState: { isSubmitting }
|
||||
} = useForm<TUsageReportForm>({
|
||||
resolver: zodResolver(formSchema)
|
||||
});
|
||||
|
||||
const downloadFile = (content: string, filename: string, mimeType: string = "text/csv") => {
|
||||
const blob = new Blob([content], { type: mimeType });
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
@@ -35,7 +21,7 @@ export const UsageReportSection = () => {
|
||||
window.URL.revokeObjectURL(url);
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
const handleGenerateReport = async () => {
|
||||
try {
|
||||
setIsGenerating(true);
|
||||
|
||||
@@ -59,8 +45,6 @@ export const UsageReportSection = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const isLoading = isSubmitting || isGenerating;
|
||||
|
||||
return (
|
||||
<Card className="p-6">
|
||||
<CardTitle className="mb-4 flex items-center gap-3">
|
||||
@@ -75,15 +59,14 @@ export const UsageReportSection = () => {
|
||||
trail.
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
|
||||
<Button
|
||||
type="submit"
|
||||
isLoading={isLoading}
|
||||
leftIcon={<FontAwesomeIcon icon={isLoading ? faSpinner : faDownload} />}
|
||||
>
|
||||
{isLoading ? "Generating..." : "Generate Report"}
|
||||
</Button>
|
||||
</form>
|
||||
<Button
|
||||
onClick={handleGenerateReport}
|
||||
className="w-fit"
|
||||
isLoading={isGenerating}
|
||||
leftIcon={<FontAwesomeIcon icon={isGenerating ? faSpinner : faDownload} />}
|
||||
>
|
||||
{isGenerating ? "Generating..." : "Generate Report"}
|
||||
</Button>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user