git list refactor
This commit is contained in:
@@ -2,13 +2,13 @@
|
||||
<!--
|
||||
@TIER: STANDARD
|
||||
@SEMANTICS: storage, files, management
|
||||
@PURPOSE: Main page for file storage management.
|
||||
@PURPOSE: Main page for unified file storage management.
|
||||
@LAYER: UI
|
||||
@RELATION: DEPENDS_ON -> storageService
|
||||
@RELATION: CONTAINS -> FileList
|
||||
@RELATION: CONTAINS -> FileUpload
|
||||
|
||||
@INVARIANT: Always displays tabs for Backups and Repositories.
|
||||
@INVARIANT: Always displays a unified storage view without category tabs.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
@@ -25,34 +25,19 @@
|
||||
// [DEF:loadFiles:Function]
|
||||
/**
|
||||
* @purpose Fetches the list of files from the server.
|
||||
* @pre The activeTab is set to a valid category.
|
||||
* @pre currentPath is a valid storage path or empty for root.
|
||||
* @post Updates the `files` array with the latest data.
|
||||
*/
|
||||
let files = [];
|
||||
let isLoading = false;
|
||||
let activeTab = 'backups';
|
||||
let currentPath = 'backups'; // Relative to storage root
|
||||
let currentPath = '';
|
||||
let uploadCategory = 'backups';
|
||||
|
||||
async function loadFiles() {
|
||||
console.log('[STORAGE-PAGE][LOAD_START] category=%s path=%s', activeTab, currentPath);
|
||||
console.log('[STORAGE-PAGE][LOAD_START] path=%s', currentPath);
|
||||
isLoading = true;
|
||||
try {
|
||||
const category = activeTab;
|
||||
|
||||
// If we have a currentPath, we use it.
|
||||
// But if user switched tabs, we should reset currentPath to category root
|
||||
let effectivePath = currentPath;
|
||||
if (category && !currentPath.startsWith(category)) {
|
||||
effectivePath = category;
|
||||
currentPath = category;
|
||||
}
|
||||
|
||||
// API expects path relative to category root if category is provided
|
||||
const subpath = (category && effectivePath.startsWith(category))
|
||||
? effectivePath.substring(category.length).replace(/^\/+/, '')
|
||||
: effectivePath;
|
||||
|
||||
files = await listFiles(category, subpath);
|
||||
files = await listFiles(undefined, currentPath);
|
||||
console.log('[STORAGE-PAGE][LOAD_OK] count=%d', files.length);
|
||||
} catch (error) {
|
||||
console.log('[STORAGE-PAGE][LOAD_ERR] error=%s', error.message);
|
||||
@@ -104,11 +89,11 @@
|
||||
// [DEF:navigateUp:Function]
|
||||
/**
|
||||
* @purpose Navigates one level up in the directory structure.
|
||||
* @pre currentPath is set and deeper than activeTab root.
|
||||
* @pre currentPath is not root.
|
||||
* @post currentPath is moved up one directory level.
|
||||
*/
|
||||
function navigateUp() {
|
||||
if (!currentPath || currentPath === activeTab) return;
|
||||
if (!currentPath) return;
|
||||
const parts = currentPath.split('/');
|
||||
parts.pop();
|
||||
currentPath = parts.join('/') || '';
|
||||
@@ -116,49 +101,49 @@
|
||||
}
|
||||
// [/DEF:navigateUp:Function]
|
||||
|
||||
// [DEF:updateUploadCategory:Function]
|
||||
/**
|
||||
* @purpose Keeps upload category aligned with the currently viewed top-level folder.
|
||||
* @pre currentPath can be empty or a slash-delimited path.
|
||||
* @post uploadCategory is either backups or repositorys.
|
||||
*/
|
||||
function updateUploadCategory() {
|
||||
const [topLevel] = currentPath.split('/').filter(Boolean);
|
||||
uploadCategory = topLevel === 'repositorys' ? 'repositorys' : 'backups';
|
||||
}
|
||||
// [/DEF:updateUploadCategory:Function]
|
||||
|
||||
onMount(() => {
|
||||
const pathParam = $page.url.searchParams.get('path');
|
||||
if (pathParam) {
|
||||
currentPath = pathParam;
|
||||
if (pathParam.startsWith('repositorys')) {
|
||||
activeTab = 'repositorys';
|
||||
} else {
|
||||
activeTab = 'backups';
|
||||
}
|
||||
}
|
||||
updateUploadCategory();
|
||||
loadFiles();
|
||||
});
|
||||
|
||||
$: if (activeTab) {
|
||||
// Reset path when switching tabs
|
||||
if (!currentPath.startsWith(activeTab)) {
|
||||
currentPath = activeTab;
|
||||
}
|
||||
loadFiles();
|
||||
}
|
||||
$: currentPath, updateUploadCategory();
|
||||
</script>
|
||||
|
||||
<!-- [SECTION: TEMPLATE] -->
|
||||
<div class="container mx-auto p-4 max-w-6xl">
|
||||
<div class="container mx-auto w-full p-4 min-[1280px]:max-w-[1400px] min-[1536px]:max-w-[1680px]">
|
||||
<div class="mb-6">
|
||||
<h1 class="text-2xl font-bold text-gray-900">{$t.storage.management}</h1>
|
||||
{#if currentPath}
|
||||
<div class="flex items-center mt-2 text-sm text-gray-500">
|
||||
<button on:click={() => { currentPath = activeTab; loadFiles(); }} class="hover:text-indigo-600">{$t.storage.root}</button>
|
||||
{#each currentPath.split('/').slice(1) as part, i}
|
||||
<div class="flex items-center mt-2 text-sm text-gray-500">
|
||||
<button on:click={() => { currentPath = ''; loadFiles(); }} class="hover:text-indigo-600">{$t.storage.root}</button>
|
||||
{#each currentPath.split('/').filter(Boolean) as part, i}
|
||||
<span class="mx-2">/</span>
|
||||
<button
|
||||
on:click={() => {
|
||||
currentPath = currentPath.split('/').slice(0, i + 2).join('/');
|
||||
currentPath = currentPath.split('/').filter(Boolean).slice(0, i + 1).join('/');
|
||||
loadFiles();
|
||||
}}
|
||||
class="hover:text-indigo-600 capitalize"
|
||||
>
|
||||
{part}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end mb-4">
|
||||
@@ -171,29 +156,11 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
<div class="grid grid-cols-1 xl:grid-cols-[minmax(0,1fr)_360px] 2xl:grid-cols-[minmax(0,1fr)_420px] 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 = 'backups'}
|
||||
class="py-4 px-1 border-b-2 font-medium text-sm {activeTab === 'backups' ? 'border-indigo-500 text-indigo-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'}"
|
||||
>
|
||||
{$t.storage.backups}
|
||||
</button>
|
||||
<button
|
||||
on:click={() => activeTab = 'repositorys'}
|
||||
class="py-4 px-1 border-b-2 font-medium text-sm {activeTab === 'repositorys' ? 'border-indigo-500 text-indigo-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'}"
|
||||
>
|
||||
{$t.storage.repositories}
|
||||
</button>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4 min-w-0">
|
||||
<div class="flex items-center mb-2">
|
||||
{#if currentPath && currentPath !== activeTab}
|
||||
{#if currentPath}
|
||||
<button
|
||||
on:click={navigateUp}
|
||||
class="mr-4 inline-flex items-center px-3 py-1 border border-gray-300 shadow-sm text-xs font-medium rounded text-gray-700 bg-white hover:bg-gray-50"
|
||||
@@ -212,7 +179,7 @@
|
||||
<!-- Sidebar: Upload -->
|
||||
<div class="lg:col-span-1">
|
||||
<FileUpload
|
||||
category={activeTab}
|
||||
category={uploadCategory}
|
||||
path={currentPath}
|
||||
on:uploaded={loadFiles}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user