arcticaurora commited on
Commit
7f52215
·
verified ·
1 Parent(s): b31a04c

Create templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +403 -0
templates/index.html ADDED
@@ -0,0 +1,403 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>File System Test App</title>
7
+
8
+ <!-- Bootstrap CSS -->
9
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet">
10
+
11
+ <!-- Font Awesome -->
12
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
13
+
14
+ <!-- TinyMCE -->
15
+ <script src="https://cdn.tiny.cloud/1/no-api-key/tinymce/6/tinymce.min.js" referrerpolicy="origin"></script>
16
+
17
+ <style>
18
+ body {
19
+ background-color: #f8f9fa;
20
+ }
21
+ .main-container {
22
+ max-width: 1200px;
23
+ margin: 0 auto;
24
+ padding: 20px;
25
+ }
26
+ .card {
27
+ margin-bottom: 20px;
28
+ border: none;
29
+ box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
30
+ }
31
+ .card-header {
32
+ background-color: #f8f9fa;
33
+ border-bottom: 1px solid #e9ecef;
34
+ }
35
+ .file-item {
36
+ display: flex;
37
+ justify-content: space-between;
38
+ align-items: center;
39
+ padding: 10px;
40
+ border-bottom: 1px solid #e9ecef;
41
+ }
42
+ .file-item:last-child {
43
+ border-bottom: none;
44
+ }
45
+ .system-info-content {
46
+ max-height: 500px;
47
+ overflow-y: auto;
48
+ font-family: monospace;
49
+ font-size: 14px;
50
+ background-color: #f8f9fa;
51
+ padding: 15px;
52
+ border-radius: 4px;
53
+ }
54
+ .test-btn {
55
+ margin: 5px;
56
+ }
57
+ </style>
58
+ </head>
59
+ <body>
60
+ <div class="main-container">
61
+ <h1 class="mb-4">File System Test App</h1>
62
+
63
+ <div class="row">
64
+ <!-- Text Editor Card -->
65
+ <div class="col-md-6">
66
+ <div class="card">
67
+ <div class="card-header">
68
+ <h5 class="card-title mb-0">Create & Save Text File</h5>
69
+ </div>
70
+ <div class="card-body">
71
+ <div class="mb-3">
72
+ <label for="filename" class="form-label">Filename</label>
73
+ <input type="text" class="form-control" id="filename" placeholder="Enter filename">
74
+ </div>
75
+ <div class="mb-3">
76
+ <label class="form-label">Content</label>
77
+ <textarea id="editor" rows="10" class="form-control"></textarea>
78
+ </div>
79
+ <button id="save-btn" class="btn btn-primary">Save File</button>
80
+ </div>
81
+ </div>
82
+
83
+ <div class="card">
84
+ <div class="card-header">
85
+ <h5 class="card-title mb-0">Upload File</h5>
86
+ </div>
87
+ <div class="card-body">
88
+ <form id="upload-form">
89
+ <div class="mb-3">
90
+ <label for="file-upload" class="form-label">Select a file</label>
91
+ <input class="form-control" type="file" id="file-upload">
92
+ </div>
93
+ <button type="submit" class="btn btn-primary">Upload</button>
94
+ </form>
95
+ </div>
96
+ </div>
97
+
98
+ <div class="card">
99
+ <div class="card-header">
100
+ <h5 class="card-title mb-0">Testing Tools</h5>
101
+ </div>
102
+ <div class="card-body">
103
+ <button id="system-info-btn" class="btn btn-info test-btn">
104
+ <i class="fas fa-info-circle"></i> System Info
105
+ </button>
106
+ <button id="binary-file-btn" class="btn btn-warning test-btn">
107
+ <i class="fas fa-file-binary"></i> Create Binary File
108
+ </button>
109
+ <button id="command-output-btn" class="btn btn-secondary test-btn">
110
+ <i class="fas fa-terminal"></i> Test Command Output
111
+ </button>
112
+ <button id="large-file-btn" class="btn btn-danger test-btn">
113
+ <i class="fas fa-file-alt"></i> Create Large File (10MB)
114
+ </button>
115
+ </div>
116
+ </div>
117
+ </div>
118
+
119
+ <!-- Files List Card -->
120
+ <div class="col-md-6">
121
+ <div class="card">
122
+ <div class="card-header d-flex justify-content-between align-items-center">
123
+ <h5 class="card-title mb-0">Files</h5>
124
+ <button id="refresh-files-btn" class="btn btn-sm btn-outline-secondary">
125
+ <i class="fas fa-sync-alt"></i> Refresh
126
+ </button>
127
+ </div>
128
+ <div class="card-body p-0">
129
+ <div id="files-list" class="list-group list-group-flush">
130
+ <div class="text-center py-4">
131
+ <i class="fas fa-spinner fa-spin"></i> Loading files...
132
+ </div>
133
+ </div>
134
+ </div>
135
+ </div>
136
+
137
+ <div class="card">
138
+ <div class="card-header">
139
+ <h5 class="card-title mb-0">System Information</h5>
140
+ </div>
141
+ <div class="card-body">
142
+ <div id="system-info" class="system-info-content">
143
+ <p>Click the "System Info" button to load system details...</p>
144
+ </div>
145
+ </div>
146
+ </div>
147
+ </div>
148
+ </div>
149
+ </div>
150
+
151
+ <!-- Toast container for notifications -->
152
+ <div class="toast-container position-fixed bottom-0 end-0 p-3">
153
+ <div id="toast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
154
+ <div class="toast-header">
155
+ <strong class="me-auto" id="toast-title">Notification</strong>
156
+ <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
157
+ </div>
158
+ <div class="toast-body" id="toast-message">
159
+ Message goes here
160
+ </div>
161
+ </div>
162
+ </div>
163
+
164
+ <!-- Bootstrap & jQuery -->
165
+ <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
166
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
167
+
168
+ <script>
169
+ // Initialize TinyMCE
170
+ tinymce.init({
171
+ selector: '#editor',
172
+ height: 300,
173
+ menubar: false,
174
+ plugins: 'lists link image table code',
175
+ toolbar: 'undo redo | formatselect | bold italic | alignleft aligncenter alignright | bullist numlist | link image | table | code',
176
+ content_style: 'body { font-family: -apple-system, BlinkMacSystemFont, San Francisco, Segoe UI, Roboto, Helvetica Neue, sans-serif; font-size: 14px; }'
177
+ });
178
+
179
+ // Show toast notification
180
+ function showToast(title, message, type = 'success') {
181
+ const toast = document.getElementById('toast');
182
+ document.getElementById('toast-title').textContent = title;
183
+ document.getElementById('toast-message').textContent = message;
184
+
185
+ // Remove previous color classes
186
+ toast.classList.remove('bg-success', 'bg-danger', 'bg-warning', 'text-white');
187
+
188
+ // Add appropriate color class
189
+ if (type === 'success') {
190
+ toast.classList.add('bg-success', 'text-white');
191
+ } else if (type === 'error') {
192
+ toast.classList.add('bg-danger', 'text-white');
193
+ } else if (type === 'warning') {
194
+ toast.classList.add('bg-warning');
195
+ }
196
+
197
+ // Show the toast
198
+ const bsToast = new bootstrap.Toast(toast);
199
+ bsToast.show();
200
+ }
201
+
202
+ // Load file list
203
+ function loadFiles() {
204
+ fetch('/list-files')
205
+ .then(response => response.json())
206
+ .then(data => {
207
+ if (data.success) {
208
+ const filesList = document.getElementById('files-list');
209
+
210
+ if (data.files.length === 0) {
211
+ filesList.innerHTML = '<div class="text-center py-4">No files found</div>';
212
+ return;
213
+ }
214
+
215
+ filesList.innerHTML = '';
216
+ data.files.forEach(file => {
217
+ const fileItem = document.createElement('div');
218
+ fileItem.className = 'file-item';
219
+ fileItem.innerHTML = `
220
+ <div>
221
+ <div><strong>${file.name}</strong></div>
222
+ <small class="text-muted">${file.size_readable} - ${file.modified}</small>
223
+ </div>
224
+ <div>
225
+ <a href="${file.url}" class="btn btn-sm btn-outline-primary" target="_blank">
226
+ <i class="fas fa-download"></i>
227
+ </a>
228
+ <button class="btn btn-sm btn-outline-danger delete-file" data-filename="${file.name}">
229
+ <i class="fas fa-trash"></i>
230
+ </button>
231
+ </div>
232
+ `;
233
+ filesList.appendChild(fileItem);
234
+ });
235
+
236
+ // Add delete event listeners
237
+ document.querySelectorAll('.delete-file').forEach(button => {
238
+ button.addEventListener('click', function() {
239
+ const filename = this.getAttribute('data-filename');
240
+ deleteFile(filename);
241
+ });
242
+ });
243
+ } else {
244
+ showToast('Error', data.message, 'error');
245
+ }
246
+ })
247
+ .catch(error => {
248
+ console.error('Error loading files:', error);
249
+ showToast('Error', 'Failed to load files', 'error');
250
+ });
251
+ }
252
+
253
+ // Delete file
254
+ function deleteFile(filename) {
255
+ if (confirm(`Are you sure you want to delete ${filename}?`)) {
256
+ fetch(`/delete-file/${filename}`, {
257
+ method: 'DELETE'
258
+ })
259
+ .then(response => response.json())
260
+ .then(data => {
261
+ if (data.success) {
262
+ showToast('Success', `File ${filename} deleted successfully`);
263
+ loadFiles();
264
+ } else {
265
+ showToast('Error', data.message, 'error');
266
+ }
267
+ })
268
+ .catch(error => {
269
+ console.error('Error deleting file:', error);
270
+ showToast('Error', 'Failed to delete file', 'error');
271
+ });
272
+ }
273
+ }
274
+
275
+ // Save file
276
+ document.getElementById('save-btn').addEventListener('click', function() {
277
+ const filename = document.getElementById('filename').value;
278
+ if (!filename) {
279
+ showToast('Error', 'Please enter a filename', 'error');
280
+ return;
281
+ }
282
+
283
+ const content = tinymce.get('editor').getContent();
284
+
285
+ const formData = new FormData();
286
+ formData.append('filename', filename);
287
+ formData.append('content', content);
288
+
289
+ fetch('/save-file', {
290
+ method: 'POST',
291
+ body: formData
292
+ })
293
+ .then(response => response.json())
294
+ .then(data => {
295
+ if (data.success) {
296
+ showToast('Success', 'File saved successfully');
297
+ loadFiles();
298
+ } else {
299
+ showToast('Error', data.message, 'error');
300
+ }
301
+ })
302
+ .catch(error => {
303
+ console.error('Error saving file:', error);
304
+ showToast('Error', 'Failed to save file', 'error');
305
+ });
306
+ });
307
+
308
+ // Upload file
309
+ document.getElementById('upload-form').addEventListener('submit', function(e) {
310
+ e.preventDefault();
311
+
312
+ const fileInput = document.getElementById('file-upload');
313
+ if (!fileInput.files[0]) {
314
+ showToast('Error', 'Please select a file to upload', 'error');
315
+ return;
316
+ }
317
+
318
+ const formData = new FormData();
319
+ formData.append('file', fileInput.files[0]);
320
+
321
+ fetch('/upload-file', {
322
+ method: 'POST',
323
+ body: formData
324
+ })
325
+ .then(response => response.json())
326
+ .then(data => {
327
+ if (data.success) {
328
+ showToast('Success', 'File uploaded successfully');
329
+ loadFiles();
330
+ fileInput.value = '';
331
+ } else {
332
+ showToast('Error', data.message, 'error');
333
+ }
334
+ })
335
+ .catch(error => {
336
+ console.error('Error uploading file:', error);
337
+ showToast('Error', 'Failed to upload file', 'error');
338
+ });
339
+ });
340
+
341
+ // Refresh files list
342
+ document.getElementById('refresh-files-btn').addEventListener('click', loadFiles);
343
+
344
+ // System info
345
+ document.getElementById('system-info-btn').addEventListener('click', function() {
346
+ fetch('/system-info')
347
+ .then(response => response.json())
348
+ .then(data => {
349
+ if (data.success) {
350
+ const systemInfo = document.getElementById('system-info');
351
+ systemInfo.innerHTML = `<pre>${JSON.stringify(data, null, 2)}</pre>`;
352
+ showToast('Success', 'System information loaded');
353
+ } else {
354
+ showToast('Error', data.message, 'error');
355
+ }
356
+ })
357
+ .catch(error => {
358
+ console.error('Error getting system info:', error);
359
+ showToast('Error', 'Failed to get system info', 'error');
360
+ });
361
+ });
362
+
363
+ // Binary file test
364
+ document.getElementById('binary-file-btn').addEventListener('click', function() {
365
+ fetch('/test-binary-file')
366
+ .then(response => response.json())
367
+ .then(data => {
368
+ if (data.success) {
369
+ showToast('Success', `Binary file created: ${data.file_size} bytes`);
370
+ loadFiles();
371
+ } else {
372
+ showToast('Error', data.message, 'error');
373
+ }
374
+ })
375
+ .catch(error => {
376
+ console.error('Error creating binary file:', error);
377
+ showToast('Error', 'Failed to create binary file', 'error');
378
+ });
379
+ });
380
+
381
+ // Command output test
382
+ document.getElementById('command-output-btn').addEventListener('click', function() {
383
+ fetch('/test-command-output')
384
+ .then(response => response.json())
385
+ .then(data => {
386
+ if (data.success) {
387
+ showToast('Success', 'Command output saved to files');
388
+ loadFiles();
389
+ } else {
390
+ showToast('Error', data.message, 'error');
391
+ }
392
+ })
393
+ .catch(error => {
394
+ console.error('Error testing command output:', error);
395
+ showToast('Error', 'Failed to test command output', 'error');
396
+ });
397
+ });
398
+
399
+ // Load files on page load
400
+ document.addEventListener('DOMContentLoaded', loadFiles);
401
+ </script>
402
+ </body>
403
+ </html>