🚀 Auto-deploy: melhoria no snap e medição AR em 22/05/2026 21:20:32
This commit is contained in:
@@ -4,6 +4,7 @@ import { Upload, Glasses, CheckCircle, XCircle, Loader2, Box, Package } from 'lu
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useModelStore } from '@/stores/useModelStore';
|
||||
import { toast } from 'sonner';
|
||||
import { supabase } from '@/integrations/supabase/client';
|
||||
import { getSupportedExtension, convertToGLB, ACCEPTED_EXTENSIONS } from '@/lib/convertToGLB';
|
||||
import { convertIFCtoGLB } from '@/lib/convertIFC';
|
||||
import { validateModelFile } from '@/lib/validateModelFile';
|
||||
@@ -23,6 +24,22 @@ const Index = () => {
|
||||
const [converting, setConverting] = useState(false);
|
||||
const { model, addModel, models, maxModels, xrSupported, setXrSupported } = useModelStore();
|
||||
|
||||
// --- Painel de Logs Remotos em Tempo Real ---
|
||||
const [debugLogs, setDebugLogs] = useState<{ level: 'info' | 'warn' | 'error'; message: string; timestamp: string; data?: any }[]>([]);
|
||||
const [showLogs, setShowLogs] = useState(() => new URLSearchParams(window.location.search).get('viewlogs') === 'true');
|
||||
|
||||
useEffect(() => {
|
||||
if (!showLogs) return;
|
||||
const logChannel = supabase.channel('global-app-logs-viewer');
|
||||
logChannel.on('broadcast', { event: 'log' }, ({ payload }) => {
|
||||
setDebugLogs(prev => [payload, ...prev].slice(0, 100));
|
||||
}).subscribe();
|
||||
|
||||
return () => {
|
||||
logChannel.unsubscribe();
|
||||
};
|
||||
}, [showLogs]);
|
||||
|
||||
const [ifcConvert, setIfcConvert] = useState(() => {
|
||||
const saved = localStorage.getItem('tsxr_ifc_convert');
|
||||
return saved !== 'false';
|
||||
@@ -312,6 +329,49 @@ const Index = () => {
|
||||
<p className="mt-16 text-center font-mono text-xs text-muted-foreground/50">
|
||||
TrackSteelXR v1.04 — Q.C. Inspection
|
||||
</p>
|
||||
|
||||
{showLogs && (
|
||||
<div className="fixed bottom-4 right-4 z-50 flex h-[400px] w-[500px] flex-col rounded-lg border border-border bg-slate-950/95 p-4 shadow-2xl backdrop-blur font-mono text-xs text-slate-200">
|
||||
<div className="flex items-center justify-between border-b border-border pb-2 mb-2">
|
||||
<span className="font-bold text-primary flex items-center gap-2">
|
||||
<span className="h-2 w-2 rounded-full bg-emerald-500 animate-ping" />
|
||||
Console de Logs Remotos (Quest 3)
|
||||
</span>
|
||||
<div className="flex gap-2">
|
||||
<Button size="sm" variant="outline" className="h-6 px-2 text-[10px]" onClick={() => setDebugLogs([])}>
|
||||
Limpar
|
||||
</Button>
|
||||
<Button size="sm" variant="outline" className="h-6 px-2 text-[10px] text-destructive" onClick={() => setShowLogs(false)}>
|
||||
Fechar
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1 overflow-y-auto space-y-2 pr-1">
|
||||
{debugLogs.length === 0 ? (
|
||||
<p className="text-slate-500 text-center mt-12">Aguardando logs do headset Quest 3...</p>
|
||||
) : (
|
||||
debugLogs.map((log, i) => (
|
||||
<div key={i} className={`p-2 rounded border ${
|
||||
log.level === 'error' ? 'bg-red-950/40 border-red-500/30 text-red-300' :
|
||||
log.level === 'warn' ? 'bg-amber-950/40 border-amber-500/30 text-amber-300' :
|
||||
'bg-slate-900/60 border-slate-700/30 text-slate-300'
|
||||
}`}>
|
||||
<div className="flex justify-between text-[9px] text-slate-400 mb-1">
|
||||
<span>{new Date(log.timestamp).toLocaleTimeString()}</span>
|
||||
<span className="uppercase font-bold">{log.level}</span>
|
||||
</div>
|
||||
<p className="break-all whitespace-pre-wrap">{log.message}</p>
|
||||
{log.data && (
|
||||
<pre className="mt-1 text-[10px] bg-black/40 p-1 rounded overflow-x-auto max-h-24 text-slate-400">
|
||||
{JSON.stringify(log.data, null, 2)}
|
||||
</pre>
|
||||
)}
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>);
|
||||
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user