feat(web): suggest tracks, my uploads and admin upload queue screens (M5.5)
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 3m4s
ci / ts / ts (packages + web) (push) Successful in 1m23s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 52s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m51s

- Suggest tracks: drag-and-drop of files and folders with relative
  paths, streaming SHA-256 in a Web Worker (hash-wasm), duplicate
  precheck, batch reservation and tus-js-client upload (8 MB chunks,
  4 in parallel, token refresh on 401, resume of failed files).
- My uploads: statuses, rejection reasons, withdraw, quota meter.
- Upload queue (admin): status tabs, possible-duplicate filter, batches,
  metadata and storage editing, bulk approve / reject with a reason,
  import retry, and the queue settings form.
- Sidebar section for moderators and admins; ru / en strings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mrleo1nidandClaude Opus 5.5 committed 2026-10-20 17:46:18 +03:00
1 parent ca106e8eb1
commit a3f212d253
19 files changed
+2144 -14

No files matched your search

+22
View File
@@ -11,6 +11,9 @@ import {
import { AuditPage } from '../pages/admin/AuditPage';
import { LibraryPage } from '../pages/admin/LibraryPage';
import { PatternsPage } from '../pages/admin/PatternsPage';
import { UploadQueuePage } from '../pages/admin/UploadQueuePage';
import { MyUploadsPage } from '../pages/uploads/MyUploadsPage';
import { SuggestPage } from '../pages/uploads/SuggestPage';
import { SourcesPage } from '../pages/admin/SourcesPage';
import { UsersPage } from '../pages/admin/UsersPage';
import { AlbumPage } from '../pages/AlbumPage';
@@ -205,6 +208,22 @@ const libraryRoute = createRoute({
component: LibraryPage,
});
/** Предложение треков — модераторы и админ (docs/uploads.md#1). */
const staffOnly = ({ context }: { context: { user: AuthUser } }) => {
if (context.user.role === 'user') throw redirect({ to: '/' });
};
const suggestRoute = createRoute({ getParentRoute: () => appRoute, path: '/uploads/new', beforeLoad: staffOnly, component: SuggestPage });
const myUploadsRoute = createRoute({ getParentRoute: () => appRoute, path: '/uploads/mine', beforeLoad: staffOnly, component: MyUploadsPage });
const uploadQueueRoute = createRoute({
getParentRoute: () => appRoute,
path: '/admin/uploads',
beforeLoad: adminOnly,
component: UploadQueuePage,
});
const routeTree = rootRoute.addChildren([
loginRoute,
setupAdminRoute,
@@ -223,6 +242,9 @@ const routeTree = rootRoute.addChildren([
sourcesRoute,
patternsRoute,
libraryRoute,
suggestRoute,
myUploadsRoute,
uploadQueueRoute,
]),
]);