Fix frontend JSONB references

This commit is contained in:
gpt-engineer-app[bot]
2025-11-03 21:19:51 +00:00
parent a4e1be8056
commit 63d9d8890c
8 changed files with 193 additions and 61 deletions

View File

@@ -10,8 +10,8 @@ interface Breadcrumb {
timestamp: string;
category: string;
message: string;
level: string;
data?: Record<string, unknown>;
level?: string;
sequence_order?: number;
}
interface ErrorDetails {
@@ -25,7 +25,7 @@ interface ErrorDetails {
status_code: number;
duration_ms: number;
user_id?: string;
breadcrumbs?: Breadcrumb[];
request_breadcrumbs?: Breadcrumb[];
environment_context?: Record<string, unknown>;
}
@@ -146,26 +146,26 @@ ${error.error_stack ? `Stack Trace:\n${error.error_stack}` : ''}
</TabsContent>
<TabsContent value="breadcrumbs">
{error.breadcrumbs && error.breadcrumbs.length > 0 ? (
{error.request_breadcrumbs && error.request_breadcrumbs.length > 0 ? (
<div className="space-y-2">
{error.breadcrumbs.map((crumb, index) => (
<div key={index} className="border-l-2 border-primary pl-4 py-2">
<div className="flex items-center gap-2 mb-1">
<Badge variant="outline" className="text-xs">
{crumb.category}
</Badge>
<span className="text-xs text-muted-foreground">
{format(new Date(crumb.timestamp), 'HH:mm:ss.SSS')}
</span>
{error.request_breadcrumbs
.sort((a, b) => (a.sequence_order || 0) - (b.sequence_order || 0))
.map((crumb, index) => (
<div key={index} className="border-l-2 border-primary pl-4 py-2">
<div className="flex items-center gap-2 mb-1">
<Badge variant="outline" className="text-xs">
{crumb.category}
</Badge>
<Badge variant={crumb.level === 'error' ? 'destructive' : 'secondary'} className="text-xs">
{crumb.level || 'info'}
</Badge>
<span className="text-xs text-muted-foreground">
{format(new Date(crumb.timestamp), 'HH:mm:ss.SSS')}
</span>
</div>
<p className="text-sm">{crumb.message}</p>
</div>
<p className="text-sm">{crumb.message}</p>
{crumb.data && (
<pre className="text-xs text-muted-foreground mt-1">
{JSON.stringify(crumb.data, null, 2)}
</pre>
)}
</div>
))}
))}
</div>
) : (
<p className="text-muted-foreground">No breadcrumbs recorded</p>

View File

@@ -8,8 +8,18 @@ import { format } from 'date-fns';
import { handleError } from '@/lib/errorHandler';
import { AuditLogEntry } from '@/types/database';
interface ProfileChangeField {
field_name: string;
old_value: string | null;
new_value: string | null;
}
interface ProfileAuditLogWithChanges extends Omit<AuditLogEntry, 'changes'> {
profile_change_fields?: ProfileChangeField[];
}
export function ProfileAuditLog(): React.JSX.Element {
const [logs, setLogs] = useState<AuditLogEntry[]>([]);
const [logs, setLogs] = useState<ProfileAuditLogWithChanges[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
@@ -22,13 +32,18 @@ export function ProfileAuditLog(): React.JSX.Element {
.from('profile_audit_log')
.select(`
*,
profiles!user_id(username, display_name)
profiles!user_id(username, display_name),
profile_change_fields(
field_name,
old_value,
new_value
)
`)
.order('created_at', { ascending: false })
.limit(50);
if (error) throw error;
setLogs((data || []) as AuditLogEntry[]);
setLogs((data || []) as ProfileAuditLogWithChanges[]);
} catch (error: unknown) {
handleError(error, { action: 'Load audit logs' });
} finally {
@@ -71,7 +86,20 @@ export function ProfileAuditLog(): React.JSX.Element {
<Badge variant="secondary">{log.action}</Badge>
</TableCell>
<TableCell>
<pre className="text-xs">{JSON.stringify(log.changes || {}, null, 2)}</pre>
{log.profile_change_fields && log.profile_change_fields.length > 0 ? (
<div className="space-y-1">
{log.profile_change_fields.map((change, idx) => (
<div key={idx} className="text-xs">
<span className="font-medium">{change.field_name}:</span>{' '}
<span className="text-muted-foreground">{change.old_value || 'null'}</span>
{' → '}
<span className="text-foreground">{change.new_value || 'null'}</span>
</div>
))}
</div>
) : (
<span className="text-xs text-muted-foreground">No changes</span>
)}
</TableCell>
<TableCell className="text-sm text-muted-foreground">
{format(new Date(log.created_at), 'PPpp')}

View File

@@ -99,7 +99,15 @@ export function DataExportTab() {
try {
const { data, error } = await supabase
.from('profile_audit_log')
.select('id, action, changes, created_at, changed_by, ip_address_hash, user_agent')
.select(`
id,
action,
created_at,
changed_by,
ip_address_hash,
user_agent,
profile_change_fields(field_name, old_value, new_value)
`)
.eq('user_id', user.id)
.order('created_at', { ascending: false })
.limit(10);
@@ -115,15 +123,27 @@ export function DataExportTab() {
}
// Transform the data to match our type
const activityData: ActivityLogEntry[] = (data || []).map(item => ({
id: item.id,
action: item.action,
changes: item.changes as Record<string, any>,
created_at: item.created_at,
changed_by: item.changed_by,
ip_address_hash: item.ip_address_hash || undefined,
user_agent: item.user_agent || undefined
}));
const activityData: ActivityLogEntry[] = (data || []).map(item => {
const changes: Record<string, any> = {};
if (item.profile_change_fields) {
for (const field of item.profile_change_fields) {
changes[field.field_name] = {
old: field.old_value,
new: field.new_value
};
}
}
return {
id: item.id,
action: item.action,
changes,
created_at: item.created_at,
changed_by: item.changed_by,
ip_address_hash: item.ip_address_hash || undefined,
user_agent: item.user_agent || undefined
};
});
setRecentActivity(activityData);