Передаем на тест
This commit is contained in:
125
frontend/src/routes/tools/storage/+page.svelte
Normal file
125
frontend/src/routes/tools/storage/+page.svelte
Normal file
@@ -0,0 +1,125 @@
|
||||
<!-- [DEF:StoragePage:Component] -->
|
||||
<!--
|
||||
@SEMANTICS: storage, files, management
|
||||
@PURPOSE: Main page for file storage management.
|
||||
@LAYER: Feature
|
||||
@RELATION: DEPENDS_ON -> storageService
|
||||
@RELATION: CONTAINS -> FileList
|
||||
@RELATION: CONTAINS -> FileUpload
|
||||
|
||||
@INVARIANT: Always displays tabs for Backups and Repositories.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
// [SECTION: IMPORTS]
|
||||
import { onMount } from 'svelte';
|
||||
import { listFiles, deleteFile } from '../../../services/storageService';
|
||||
import { addToast } from '../../../lib/toasts';
|
||||
import FileList from '../../../components/storage/FileList.svelte';
|
||||
import FileUpload from '../../../components/storage/FileUpload.svelte';
|
||||
// [/SECTION: IMPORTS]
|
||||
|
||||
// [DEF:loadFiles:Function]
|
||||
/**
|
||||
* @purpose Fetches the list of files from the server.
|
||||
* @post Updates the `files` array with the latest data.
|
||||
*/
|
||||
let files = [];
|
||||
let isLoading = false;
|
||||
let activeTab = 'all';
|
||||
|
||||
async function loadFiles() {
|
||||
isLoading = true;
|
||||
try {
|
||||
const category = activeTab === 'all' ? null : activeTab;
|
||||
files = await listFiles(category);
|
||||
} catch (error) {
|
||||
addToast(`Failed to load files: ${error.message}`, 'error');
|
||||
} finally {
|
||||
isLoading = false;
|
||||
}
|
||||
}
|
||||
// [/DEF:loadFiles:Function]
|
||||
|
||||
// [DEF:handleDelete:Function]
|
||||
/**
|
||||
* @purpose Handles the file deletion process.
|
||||
* @param {CustomEvent} event - The delete event containing category and filename.
|
||||
*/
|
||||
async function handleDelete(event) {
|
||||
const { category, filename } = event.detail;
|
||||
if (!confirm(`Are you sure you want to delete ${filename}?`)) return;
|
||||
|
||||
try {
|
||||
await deleteFile(category, filename);
|
||||
addToast(`File ${filename} deleted.`, 'success');
|
||||
await loadFiles();
|
||||
} catch (error) {
|
||||
addToast(`Delete failed: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
// [/DEF:handleDelete:Function]
|
||||
|
||||
onMount(loadFiles);
|
||||
|
||||
$: if (activeTab) {
|
||||
loadFiles();
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- [SECTION: TEMPLATE] -->
|
||||
<div class="container mx-auto p-4 max-w-6xl">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h1 class="text-2xl font-bold text-gray-900">File Storage Management</h1>
|
||||
<button
|
||||
on:click={loadFiles}
|
||||
class="inline-flex items-center px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50"
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? 'Refreshing...' : 'Refresh'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
<!-- Main Content: File List -->
|
||||
<div class="lg:col-span-2 space-y-4">
|
||||
<!-- Tabs -->
|
||||
<div class="border-b border-gray-200">
|
||||
<nav class="-mb-px flex space-x-8">
|
||||
<button
|
||||
on:click={() => activeTab = 'all'}
|
||||
class="py-4 px-1 border-b-2 font-medium text-sm {activeTab === 'all' ? 'border-indigo-500 text-indigo-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'}"
|
||||
>
|
||||
All Files
|
||||
</button>
|
||||
<button
|
||||
on:click={() => activeTab = 'backup'}
|
||||
class="py-4 px-1 border-b-2 font-medium text-sm {activeTab === 'backup' ? 'border-indigo-500 text-indigo-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'}"
|
||||
>
|
||||
Backups
|
||||
</button>
|
||||
<button
|
||||
on:click={() => activeTab = 'repository'}
|
||||
class="py-4 px-1 border-b-2 font-medium text-sm {activeTab === 'repository' ? 'border-indigo-500 text-indigo-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'}"
|
||||
>
|
||||
Repositories
|
||||
</button>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<FileList {files} on:delete={handleDelete} />
|
||||
</div>
|
||||
|
||||
<!-- Sidebar: Upload -->
|
||||
<div class="lg:col-span-1">
|
||||
<FileUpload on:uploaded={loadFiles} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- [/SECTION: TEMPLATE] -->
|
||||
|
||||
<style>
|
||||
/* ... */
|
||||
</style>
|
||||
|
||||
<!-- [/DEF:StoragePage:Component] -->
|
||||
Reference in New Issue
Block a user