Add database diagnostic export
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m29s

This commit is contained in:
Cauê Faleiros
2026-07-21 13:20:48 -03:00
parent eb5cc01d56
commit 51b73ed82b
5 changed files with 243 additions and 4 deletions

View File

@@ -161,6 +161,23 @@ const authFetch = async (path: string, options: RequestInit = {}): Promise<Respo
return response;
};
export const downloadDatabaseDiagnostic = async (): Promise<void> => {
const response = await authFetch('/admin/database-diagnostic', { cache: 'no-store' });
const data = await response.json().catch(() => null);
if (!response.ok) {
throw new Error(data?.error || 'Não foi possível exportar o diagnóstico do banco.');
}
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json;charset=utf-8;' });
const url = URL.createObjectURL(blob);
const anchor = document.createElement('a');
anchor.href = url;
anchor.download = `graphs-db-diagnostic-${new Date().toISOString().slice(0, 10)}.json`;
anchor.click();
URL.revokeObjectURL(url);
};
export const fetchProductionOrders = async (
dateRange: DateRange,
filters?: { search?: string },

View File

@@ -28,7 +28,7 @@ import DateRangePicker from '../components/DateRangePicker';
import PaginationControls from '../components/PaginationControls';
import ProductTypeBadge from '../components/ProductTypeBadge';
import { classifyCutFamily } from '../analytics/cutting';
import { adjustSupplyLotInventory, approveSupplyReceipt, consumeSupplyLotForProduction, createSupplyFabricPlan, createSupplyReceipt, deleteSupplyFabricPlan, deleteSupplyReceipt, fetchCuttingSettings, fetchProductAnalytics, fetchStock, fetchSupplySummary } from '../dataService';
import { adjustSupplyLotInventory, approveSupplyReceipt, consumeSupplyLotForProduction, createSupplyFabricPlan, createSupplyReceipt, deleteSupplyFabricPlan, deleteSupplyReceipt, downloadDatabaseDiagnostic, fetchCuttingSettings, fetchProductAnalytics, fetchStock, fetchSupplySummary, isSuperAdmin } from '../dataService';
import { parseProductName } from '../productParsing';
import { resolveProductType, type ProductTypeKey } from '../productClassification';
import { getPlanningStock } from '../planningStock';
@@ -192,9 +192,44 @@ const ModuleCard = ({
);
};
const SuppliesHub = () => (
const SuppliesHub = () => {
const [isExportingDiagnostic, setIsExportingDiagnostic] = useState(false);
const [diagnosticError, setDiagnosticError] = useState('');
const canExportDiagnostic = isSuperAdmin();
const handleExportDiagnostic = async () => {
setIsExportingDiagnostic(true);
setDiagnosticError('');
try {
await downloadDatabaseDiagnostic();
} catch (error) {
setDiagnosticError(error instanceof Error ? error.message : 'Não foi possível exportar o diagnóstico do banco.');
} finally {
setIsExportingDiagnostic(false);
}
};
return (
<div className={pageClassName}>
<Header title="Suprimentos" subtitle="Corte, estoque, malha e compras em um fluxo operacional." />
<div className="flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between">
<Header title="Suprimentos" subtitle="Corte, estoque, malha e compras em um fluxo operacional." />
{canExportDiagnostic && (
<button
type="button"
onClick={handleExportDiagnostic}
disabled={isExportingDiagnostic}
className={`${buttonClassName} w-fit disabled:cursor-not-allowed disabled:opacity-60`}
>
<Download className="h-4 w-4" />
{isExportingDiagnostic ? 'Exportando...' : 'Exportar diagnóstico DB'}
</button>
)}
</div>
{diagnosticError && (
<div className="rounded-xl border border-red-500/30 bg-red-500/10 px-4 py-3 text-sm font-bold text-red-300">
{diagnosticError}
</div>
)}
<div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
<ModuleCard title="Planejamento Operacional" description="Prioridades de reposição, compra e revisão calculadas por demanda, estoque e cobertura." icon={PackageSearch} to="/supplies/current-planning" />
<ModuleCard title="Planejamento de Corte" description="Ruptura por cor e tamanho, montagem do corte e prioridade por cobertura." icon={Scissors} to="/cutting" />
@@ -204,7 +239,8 @@ const SuppliesHub = () => (
<ModuleCard title="Necessidade de Compra" description="Itens abaixo do mínimo e necessidade projetada para compra." icon={BarChart3} to="/supplies/purchase-needs" />
</div>
</div>
);
);
};
const getRangeDays = (range: DateRange) => {
const start = new Date(range.start);