import * as React from "react"; import { Box, Container, Paper, Typography, Button, IconButton, CircularProgress, Alert, Snackbar, Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, Chip, } from "@mui/material"; import DeleteIcon from "@mui/icons-material/Delete"; import AddCircleIcon from "@mui/icons-material/AddCircle"; import RefreshIcon from "@mui/icons-material/Refresh"; import ContentCopyIcon from "@mui/icons-material/ContentCopy"; import { useResourceByName, useConfig, defaultFieldComponents } from "../react-openapi"; import type { ResourceField } from "../react-openapi"; interface ReportSnapshotQuery { accounts?: string[]; ignore_self?: boolean; start_date?: string; end_date?: string; } interface ReportSnapshot { id: string; snapshot_id: string; created_at: string; query?: ReportSnapshotQuery; } function formatDate(iso: string) { const d = new Date(iso); return d.toLocaleString(); } export default function ReportSnapshots() { const [ignoreSelf, setIgnoreSelf] = React.useState(true); const [startDate, setStartDate] = React.useState(""); const [endDate, setEndDate] = React.useState(""); const [minAmount, setMinAmount] = React.useState(""); const [maxAmount, setMaxAmount] = React.useState(""); const [snackbar, setSnackbar] = React.useState<{ message: string; severity: "success" | "error" } | null>(null); const [deleteTarget, setDeleteTarget] = React.useState(null); const [createdSnapshotId, setCreatedSnapshotId] = React.useState(null); const { useList, useCreate, useDelete, components } = useResourceByName("reports", { fieldComponents: defaultFieldComponents }); const { data: listData, isLoading, isFetching, refetch } = useList(); const createMutation = useCreate(); const deleteMutation = useDelete(); const config = useConfig(); const reportsRes = config?.resources.find((r: any) => r.name === "reports"); const ignoreSelfField: ResourceField | undefined = reportsRes?.fields?.ignore_self; const startDateField: ResourceField | undefined = reportsRes?.fields?.start_date; const endDateField: ResourceField | undefined = reportsRes?.fields?.end_date; const minAmountField: ResourceField | undefined = reportsRes?.fields?.min_amount; const maxAmountField: ResourceField | undefined = reportsRes?.fields?.max_amount; const snapshots: ReportSnapshot[] = listData?.data ?? []; const handleCreate = async () => { try { const payload: Record = {}; if (ignoreSelf) payload.ignore_self = true; if (startDate) payload.start_date = new Date(startDate).toISOString(); if (endDate) payload.end_date = new Date(endDate).toISOString(); if (minAmount) payload.min_amount = parseFloat(minAmount); if (maxAmount) payload.max_amount = parseFloat(maxAmount); const result = await createMutation.mutateAsync(payload); const snapshotId = (result as any)?.snapshot_id; if (snapshotId) { setCreatedSnapshotId(snapshotId); setSnackbar({ message: `Snapshot created: ${snapshotId}`, severity: "success" }); } else { setSnackbar({ message: "Snapshot created", severity: "success" }); } resetForm(); } catch (err: any) { setSnackbar({ message: err?.response?.data?.detail || "Failed to create snapshot", severity: "error" }); } }; const resetForm = () => { setIgnoreSelf(true); setStartDate(""); setEndDate(""); setMinAmount(""); setMaxAmount(""); }; const handleDelete = async () => { if (!deleteTarget) return; try { await deleteMutation.mutateAsync(deleteTarget.snapshot_id); setSnackbar({ message: "Snapshot deleted", severity: "success" }); } catch { setSnackbar({ message: "Failed to delete snapshot", severity: "error" }); } setDeleteTarget(null); }; return ( Report Snapshots Generate New Snapshot {ignoreSelfField && components?.FormField && ( setIgnoreSelf(val)} /> )} {startDateField && components?.datetime && ( setStartDate(val)} /> )} {endDateField && components?.datetime && ( setEndDate(val)} /> )} {minAmountField && components?.FormField && ( setMinAmount(val)} /> )} {maxAmountField && components?.FormField && ( setMaxAmount(val)} /> )} {createdSnapshotId && ( setCreatedSnapshotId(null)}> Snapshot created: {createdSnapshotId}. Use it in the Dashboard snapshot selector. )} Existing Snapshots refetch()} disabled={isFetching}> {isLoading ? ( ) : snapshots.length === 0 ? ( No snapshots yet ) : ( {["Snapshot ID", "Created", "Query", "Actions"].map((h) => ( {h} ))} {snapshots.map((snap: ReportSnapshot) => ( {snap.snapshot_id} { navigator.clipboard.writeText(snap.snapshot_id); setSnackbar({ message: "Copied!", severity: "success" }); }} sx={{ opacity: 0.5, '&:hover': { opacity: 1 } }} > {formatDate(snap.created_at)} {snap.query ? ( {snap.query.accounts && } {snap.query.ignore_self && } {snap.query.start_date && } {snap.query.end_date && } ) : ( \u2014 )} setDeleteTarget(snap)}> ))} )} setSnackbar(null)} anchorOrigin={{ vertical: "bottom", horizontal: "center" }} > {snackbar ? setSnackbar(null)}>{snackbar.message} : undefined} setDeleteTarget(null)}> Delete Snapshot? This will permanently delete the report snapshot. ); }