-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathpage.tsx
138 lines (130 loc) · 5.99 KB
/
page.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
'use client';
import { useEffect, useState } from 'react';
import dynamic from 'next/dynamic';
import '@/styles/global.css';
import CommonLayout from '../commonLayout';
import { useSession } from '@/hooks/sessionHook';
// Dynamically import react-json-view to avoid SSR issues
const ReactJson = dynamic(() => import('react-json-view'), { ssr: false });
function App() {
const [files, setFiles] = useState([]);
const [showOverlay, setShowOverlay] = useState(false);
const [jsonContent, setJsonContent] = useState({});
const [loading, setLoading] = useState(false);
const { sessionId } = useSession();
useEffect(() => {
const fetchFiles = async () => {
try {
const response = await fetch('/api/s3list', {
headers: {
'X-Session-Id': sessionId || ''
}
});
const data = await response.json();
setFiles(data.files || []);
} catch (error) {
console.error('Error fetching files:', error);
}
};
fetchFiles();
}, []);
const handleFileClick = async (url: string) => {
try {
setLoading(true);
console.log('Fetching JSON:', url);
const response = await fetch(url);
const ndJsonData = await response.text();
const jsonData = ndJsonData
.split('\n')
.filter((line) => line.trim())
.map((line) => JSON.parse(line));
setJsonContent(jsonData);
setShowOverlay(true);
} catch (error) {
console.error('Error fetching JSON:', error);
} finally {
setLoading(false);
}
};
return (
<CommonLayout
title="Monocle Traces"
navLink={{ text: "Back to Chat", href: "/" }}
>
<div className="bg-white rounded-lg shadow-sm">
<div className="overflow-x-auto">
<table className="w-full">
<thead className="bg-gray-50">
<tr>
<th scope="col" className="w-[60%] px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
File Name
</th>
<th scope="col" className="w-[40%] px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Last Modified
</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{files.map((file: any, index) => (
<tr
key={index}
className="hover:bg-gray-50 cursor-pointer transition-colors"
>
<td
className="px-6 py-4 text-sm font-medium text-gray-900"
onClick={() => handleFileClick(file.url)}
>
{file.key}
</td>
<td className="px-6 py-4 text-sm text-gray-500">
{new Date(file.lastModified).toLocaleDateString(undefined, {
year: 'numeric',
month: 'long',
day: 'numeric'
})}
{' '}
{new Date(file.lastModified).toLocaleTimeString(undefined, {
hour: '2-digit',
minute: '2-digit'
})}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
{/* JSON Viewer Overlay */}
{showOverlay && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-6 z-50">
<div className="bg-white rounded-lg shadow-xl w-11/12 h-5/6 max-w-7xl mx-auto overflow-hidden">
<div className="p-4 border-b border-gray-200 flex justify-between items-center">
<h2 className="text-lg font-semibold text-gray-800">NDJSON Viewer</h2>
<button
onClick={() => setShowOverlay(false)}
className="p-2 hover:bg-gray-100 rounded-full transition-colors"
>
<span className="text-xl">✕</span>
</button>
</div>
<div className="p-6 h-[calc(100%-4rem)] overflow-auto">
{loading ? (
<div className="flex items-center justify-center h-full">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"></div>
</div>
) : (
<ReactJson
src={jsonContent}
style={{ backgroundColor: 'transparent' }}
enableClipboard={false}
displayDataTypes={false}
/>
)}
</div>
</div>
</div>
)}
</CommonLayout>
);
}
export default App;