diff --git a/front/src/ui/composables/bytes.ts b/front/src/ui/composables/bytes.ts
index bb08cf1b8..56f015002 100644
--- a/front/src/ui/composables/bytes.ts
+++ b/front/src/ui/composables/bytes.ts
@@ -5,4 +5,3 @@ export const bytesToHumanSize = (bytes: number) => {
if (i === 0) return `${bytes} ${sizes[i]}`
return `${(bytes / 1024 ** i).toFixed(1)} ${sizes[i]}`
}
-
diff --git a/front/src/ui/composables/metadata.ts b/front/src/ui/composables/metadata.ts
index de4122c8b..94efb0dd4 100644
--- a/front/src/ui/composables/metadata.ts
+++ b/front/src/ui/composables/metadata.ts
@@ -40,7 +40,7 @@ export const getCoverUrl = async (tags: Tags): Promise
=> {
onerror: () => reject(reader.error)
})
- reader.readAsDataURL(new File([picture.data], "", { type: picture.type }))
+ reader.readAsDataURL(new File([picture.data], '', { type: picture.type }))
})
}
diff --git a/front/src/ui/pages/index.vue b/front/src/ui/pages/index.vue
index 4d250b070..57841cd0e 100644
--- a/front/src/ui/pages/index.vue
+++ b/front/src/ui/pages/index.vue
@@ -1,13 +1,13 @@
-
Upload
+
+ Upload
+
-
+
{{ bytesToHumanSize(filesystemStats.total) }} total
@@ -55,12 +60,20 @@ const tabs = computed(() => [
{{ bytesToHumanSize(filesystemStats.total - filesystemStats.used) }} available
-
-
-
+
+
{{ tab.label }}
diff --git a/front/src/ui/pages/upload/all.vue b/front/src/ui/pages/upload/all.vue
index a94aad4d3..ac47a4802 100644
--- a/front/src/ui/pages/upload/all.vue
+++ b/front/src/ui/pages/upload/all.vue
@@ -1,8 +1,8 @@
-
-
+
+
There is no file in your library
Try uploading some before coming back here!
-
-
+
{{ value }}
diff --git a/front/src/ui/pages/upload/index.vue b/front/src/ui/pages/upload/index.vue
index bda11d1ad..ef6b4e9b8 100644
--- a/front/src/ui/pages/upload/index.vue
+++ b/front/src/ui/pages/upload/index.vue
@@ -1,5 +1,5 @@
-
+
diff --git a/front/src/ui/routes/auth.ts b/front/src/ui/routes/auth.ts
new file mode 100644
index 000000000..33b64ccab
--- /dev/null
+++ b/front/src/ui/routes/auth.ts
@@ -0,0 +1,68 @@
+import type { RouteRecordRaw } from 'vue-router'
+
+import { requireLoggedOut, requireLoggedIn } from '~/router/guards'
+
+export default [
+ {
+ path: 'login',
+ name: 'login',
+ component: () => import('~/views/auth/Login.vue'),
+ props: route => ({ next: route.query.next || '/library' }),
+ beforeEnter: requireLoggedOut({ name: 'library.index' })
+ },
+ {
+ path: 'auth/password/reset',
+ name: 'auth.password-reset',
+ component: () => import('~/views/auth/PasswordReset.vue'),
+ props: route => ({ defaultEmail: route.query.email })
+ },
+ {
+ path: 'auth/callback',
+ name: 'auth.callback',
+ component: () => import('~/views/auth/Callback.vue'),
+ props: route => ({
+ code: route.query.code,
+ state: route.query.state
+ })
+ },
+ {
+ path: 'auth/email/confirm',
+ name: 'auth.email-confirm',
+ component: () => import('~/views/auth/EmailConfirm.vue'),
+ props: route => ({ defaultKey: route.query.key })
+ },
+ {
+ path: 'auth/password/reset/confirm',
+ name: 'auth.password-reset-confirm',
+ component: () => import('~/views/auth/PasswordResetConfirm.vue'),
+ props: route => ({
+ defaultUid: route.query.uid,
+ defaultToken: route.query.token
+ })
+ },
+ {
+ path: 'authorize',
+ name: 'authorize',
+ component: () => import('~/components/auth/Authorize.vue'),
+ props: route => ({
+ clientId: route.query.client_id,
+ redirectUri: route.query.redirect_uri,
+ scope: route.query.scope,
+ responseType: route.query.response_type,
+ nonce: route.query.nonce,
+ state: route.query.state
+ }),
+ beforeEnter: requireLoggedIn()
+ },
+ {
+ path: 'signup',
+ name: 'signup',
+ component: () => import('~/views/auth/Signup.vue'),
+ props: route => ({ defaultInvitation: route.query.invitation })
+ },
+ {
+ path: 'logout',
+ name: 'logout',
+ component: () => import('~/components/auth/Logout.vue')
+ }
+] as RouteRecordRaw[]
diff --git a/front/src/ui/routes/content.ts b/front/src/ui/routes/content.ts
new file mode 100644
index 000000000..da745e6de
--- /dev/null
+++ b/front/src/ui/routes/content.ts
@@ -0,0 +1,41 @@
+import type { RouteRecordRaw } from 'vue-router'
+
+export default [
+ {
+ path: 'content',
+ component: () => import('~/views/content/Base.vue'),
+ children: [{
+ path: '',
+ name: 'content.index',
+ component: () => import('~/views/content/Home.vue')
+ }]
+ },
+ {
+ path: 'content/libraries/tracks',
+ component: () => import('~/views/content/Base.vue'),
+ children: [{
+ path: '',
+ name: 'content.libraries.files',
+ component: () => import('~/views/content/libraries/Files.vue'),
+ props: route => ({ query: route.query.q })
+ }]
+ },
+ {
+ path: 'content/libraries',
+ component: () => import('~/views/content/Base.vue'),
+ children: [{
+ path: '',
+ name: 'content.libraries.index',
+ component: () => import('~/views/content/libraries/Home.vue')
+ }]
+ },
+ {
+ path: 'content/remote',
+ component: () => import('~/views/content/Base.vue'),
+ children: [{
+ path: '',
+ name: 'content.remote.index',
+ component: () => import('~/views/content/remote/Home.vue')
+ }]
+ }
+] as RouteRecordRaw[]
diff --git a/front/src/ui/routes/index.ts b/front/src/ui/routes/index.ts
new file mode 100644
index 000000000..4d210db11
--- /dev/null
+++ b/front/src/ui/routes/index.ts
@@ -0,0 +1,139 @@
+import type { RouteRecordRaw } from 'vue-router'
+
+import settings from './settings'
+import library from './library'
+import content from './content'
+import manage from './manage'
+import auth from './auth'
+import user from './user'
+import store from '~/store'
+import { requireLoggedIn } from '~/router/guards'
+
+export default [
+ {
+ path: '/',
+ name: 'root',
+ component: () => import('~/ui/layouts/constrained.vue'),
+ children: [
+ {
+ path: '/',
+ name: 'index',
+ component: () => import('~/components/Home.vue'),
+ beforeEnter (to, from, next) {
+ if (store.state.auth.authenticated) return next('/library')
+ return next()
+ }
+ },
+ {
+ path: '/index.html',
+ redirect: to => {
+ const { hash, query } = to
+ return { name: 'index', hash, query }
+ }
+ },
+ {
+ path: 'upload',
+ name: 'upload',
+ component: () => import('~/ui/pages/upload.vue'),
+ children: [
+ {
+ path: '',
+ name: 'upload.index',
+ component: () => import('~/ui/pages/upload/index.vue')
+ },
+
+ {
+ path: 'running',
+ name: 'upload.running',
+ component: () => import('~/ui/pages/upload/running.vue'),
+ beforeEnter: (_to, _from, next) => {
+ const uploads = useUploadsStore()
+ if (uploads.uploadGroups.length === 0) {
+ next('/ui/upload')
+ } else {
+ next()
+ }
+ }
+ },
+
+ {
+ path: 'history',
+ name: 'upload.history',
+ component: () => import('~/ui/pages/upload/history.vue')
+ },
+
+ {
+ path: 'all',
+ name: 'upload.all',
+ component: () => import('~/ui/pages/upload/all.vue')
+ }
+ ]
+ },
+ {
+ path: 'about',
+ name: 'about',
+ component: () => import('~/components/About.vue')
+ },
+ {
+ // TODO (wvffle): Make it a child of /about to have the active style on the sidebar link
+ path: 'about/pod',
+ name: 'about-pod',
+ component: () => import('~/components/AboutPod.vue')
+ },
+ {
+ path: 'notifications',
+ name: 'notifications',
+ component: () => import('~/views/Notifications.vue')
+ },
+ {
+ path: 'search',
+ name: 'search',
+ component: () => import('~/views/Search.vue')
+ },
+ ...auth,
+ ...settings,
+ ...user,
+ {
+ path: 'favorites',
+ name: 'favorites',
+ component: () => import('~/components/favorites/List.vue'),
+ props: route => ({
+ defaultOrdering: route.query.ordering,
+ defaultPage: route.query.page ? +route.query.page : undefined
+ }),
+ beforeEnter: requireLoggedIn()
+ },
+ ...content,
+ ...manage,
+ ...library,
+ {
+ path: 'channels/:id',
+ props: true,
+ component: () => import('~/views/channels/DetailBase.vue'),
+ children: [
+ {
+ path: '',
+ name: 'channels.detail',
+ component: () => import('~/views/channels/DetailOverview.vue')
+ },
+ {
+ path: 'episodes',
+ name: 'channels.detail.episodes',
+ component: () => import('~/views/channels/DetailEpisodes.vue')
+ }
+ ]
+ },
+ {
+ path: 'subscriptions',
+ name: 'subscriptions',
+ component: () => import('~/views/channels/SubscriptionsList.vue'),
+ props: route => ({ defaultQuery: route.query.q })
+ }
+ ]
+ },
+ {
+ path: '/:pathMatch(.*)*',
+ name: '404',
+ component: () => import('~/components/PageNotFound.vue')
+ }
+] as RouteRecordRaw[]
diff --git a/front/src/ui/routes/library.ts b/front/src/ui/routes/library.ts
new file mode 100644
index 000000000..f79d7df49
--- /dev/null
+++ b/front/src/ui/routes/library.ts
@@ -0,0 +1,238 @@
+import type { RouteRecordRaw } from 'vue-router'
+
+export default [
+ {
+ path: 'library',
+ component: () => import('~/components/library/Library.vue'),
+ children: [
+ {
+ path: '',
+ component: () => import('~/components/library/Home.vue'),
+ name: 'library.index'
+ },
+ {
+ path: 'me',
+ component: () => import('~/components/library/Home.vue'),
+ name: 'library.me',
+ props: () => ({ scope: 'me' })
+ },
+ {
+ path: 'artists/',
+ name: 'library.artists.browse',
+ component: () => import('~/components/library/Artists.vue'),
+ meta: {
+ paginateBy: 30
+ }
+ },
+ {
+ path: 'me/artists',
+ name: 'library.artists.me',
+ component: () => import('~/components/library/Artists.vue'),
+ props: { scope: 'me' },
+ meta: {
+ paginateBy: 30
+ }
+ },
+ {
+ path: 'albums/',
+ name: 'library.albums.browse',
+ component: () => import('~/components/library/Albums.vue'),
+ meta: {
+ paginateBy: 25
+ }
+ },
+ {
+ path: 'me/albums',
+ name: 'library.albums.me',
+ component: () => import('~/components/library/Albums.vue'),
+ props: { scope: 'me' },
+ meta: {
+ paginateBy: 25
+ }
+ },
+ {
+ path: 'podcasts/',
+ name: 'library.podcasts.browse',
+ component: () => import('~/components/library/Podcasts.vue'),
+ meta: {
+ paginateBy: 30
+ }
+ },
+ {
+ path: 'radios/',
+ name: 'library.radios.browse',
+ component: () => import('~/components/library/Radios.vue'),
+ meta: {
+ paginateBy: 12
+ }
+ },
+ {
+ path: 'me/radios/',
+ name: 'library.radios.me',
+ component: () => import('~/components/library/Radios.vue'),
+ props: { scope: 'me' },
+ meta: {
+ paginateBy: 12
+ }
+ },
+ {
+ path: 'radios/build',
+ name: 'library.radios.build',
+ component: () => import('~/components/library/radios/Builder.vue'),
+ props: true
+ },
+ {
+ path: 'radios/build/:id',
+ name: 'library.radios.edit',
+ component: () => import('~/components/library/radios/Builder.vue'),
+ props: true
+ },
+ {
+ path: 'radios/:id',
+ name: 'library.radios.detail',
+ component: () => import('~/views/radios/Detail.vue'),
+ props: true
+ },
+ {
+ path: 'playlists/',
+ name: 'library.playlists.browse',
+ component: () => import('~/views/playlists/List.vue'),
+ meta: {
+ paginateBy: 25
+ }
+ },
+ {
+ path: 'me/playlists/',
+ name: 'library.playlists.me',
+ component: () => import('~/views/playlists/List.vue'),
+ props: { scope: 'me' },
+ meta: {
+ paginateBy: 25
+ }
+ },
+ {
+ path: 'playlists/:id',
+ name: 'library.playlists.detail',
+ component: () => import('~/views/playlists/Detail.vue'),
+ props: route => ({
+ id: route.params.id,
+ defaultEdit: route.query.mode === 'edit'
+ })
+ },
+ {
+ path: 'tags/:id',
+ name: 'library.tags.detail',
+ component: () => import('~/components/library/TagDetail.vue'),
+ props: true
+ },
+ {
+ path: 'artists/:id',
+ component: () => import('~/components/library/ArtistBase.vue'),
+ props: true,
+ children: [
+ {
+ path: '',
+ name: 'library.artists.detail',
+ component: () => import('~/components/library/ArtistDetail.vue')
+ },
+ {
+ path: 'edit',
+ name: 'library.artists.edit',
+ component: () => import('~/components/library/ArtistEdit.vue')
+ },
+ {
+ path: 'edit/:editId',
+ name: 'library.artists.edit.detail',
+ component: () => import('~/components/library/EditDetail.vue'),
+ props: true
+ }
+ ]
+ },
+ {
+ path: 'albums/:id',
+ component: () => import('~/components/library/AlbumBase.vue'),
+ props: true,
+ children: [
+ {
+ path: '',
+ name: 'library.albums.detail',
+ component: () => import('~/components/library/AlbumDetail.vue')
+ },
+ {
+ path: 'edit',
+ name: 'library.albums.edit',
+ component: () => import('~/components/library/AlbumEdit.vue')
+ },
+ {
+ path: 'edit/:editId',
+ name: 'library.albums.edit.detail',
+ component: () => import('~/components/library/EditDetail.vue'),
+ props: true
+ }
+ ]
+ },
+ {
+ path: 'tracks/:id',
+ component: () => import('~/components/library/TrackBase.vue'),
+ props: true,
+ children: [
+ {
+ path: '',
+ name: 'library.tracks.detail',
+ component: () => import('~/components/library/TrackDetail.vue')
+ },
+ {
+ path: 'edit',
+ name: 'library.tracks.edit',
+ component: () => import('~/components/library/TrackEdit.vue')
+ },
+ {
+ path: 'edit/:editId',
+ name: 'library.tracks.edit.detail',
+ component: () => import('~/components/library/EditDetail.vue'),
+ props: true
+ }
+ ]
+ },
+ {
+ path: 'uploads/:id',
+ name: 'library.uploads.detail',
+ props: true,
+ component: () => import('~/components/library/UploadDetail.vue')
+ },
+ {
+ // browse a single library via it's uuid
+ path: ':id([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})',
+ props: true,
+ component: () => import('~/views/library/LibraryBase.vue'),
+ children: [
+ {
+ path: '',
+ name: 'library.detail',
+ component: () => import('~/views/library/DetailOverview.vue')
+ },
+ {
+ path: 'albums',
+ name: 'library.detail.albums',
+ component: () => import('~/views/library/DetailAlbums.vue')
+ },
+ {
+ path: 'tracks',
+ name: 'library.detail.tracks',
+ component: () => import('~/views/library/DetailTracks.vue')
+ },
+ {
+ path: 'edit',
+ name: 'library.detail.edit',
+ component: () => import('~/views/library/Edit.vue')
+ },
+ {
+ path: 'upload',
+ name: 'library.detail.upload',
+ redirect: () => '/upload'
+ }
+ ]
+ }
+ ]
+ }
+] as RouteRecordRaw[]
diff --git a/front/src/ui/routes/manage.ts b/front/src/ui/routes/manage.ts
new file mode 100644
index 000000000..5c8947d9c
--- /dev/null
+++ b/front/src/ui/routes/manage.ts
@@ -0,0 +1,188 @@
+import type { RouteRecordRaw } from 'vue-router'
+
+import { hasPermissions } from '~/router/guards'
+
+export default [
+ {
+ path: 'manage/settings',
+ name: 'manage.settings',
+ beforeEnter: hasPermissions('settings'),
+ component: () => import('~/views/admin/Settings.vue')
+ },
+ {
+ path: 'manage/library',
+ beforeEnter: hasPermissions('library'),
+ component: () => import('~/views/admin/library/Base.vue'),
+ children: [
+ {
+ path: 'edits',
+ name: 'manage.library.edits',
+ component: () => import('~/views/admin/library/EditsList.vue'),
+ props: route => ({ defaultQuery: route.query.q })
+ },
+ {
+ path: 'artists',
+ name: 'manage.library.artists',
+ component: () => import('~/views/admin/CommonList.vue'),
+ props: route => ({ defaultQuery: route.query.q, type: 'artists' })
+ },
+ {
+ path: 'artists/:id',
+ name: 'manage.library.artists.detail',
+ component: () => import('~/views/admin/library/ArtistDetail.vue'),
+ props: true
+ },
+ {
+ path: 'channels',
+ name: 'manage.channels',
+ component: () => import('~/views/admin/CommonList.vue'),
+ props: route => ({ defaultQuery: route.query.q, type: 'channels' })
+ },
+ {
+ path: 'channels/:id',
+ name: 'manage.channels.detail',
+ component: () => import('~/views/admin/ChannelDetail.vue'),
+ props: true
+ },
+ {
+ path: 'albums',
+ name: 'manage.library.albums',
+ component: () => import('~/views/admin/CommonList.vue'),
+ props: route => ({ defaultQuery: route.query.q, type: 'albums' })
+ },
+ {
+ path: 'albums/:id',
+ name: 'manage.library.albums.detail',
+ component: () => import('~/views/admin/library/AlbumDetail.vue'),
+ props: true
+ },
+ {
+ path: 'tracks',
+ name: 'manage.library.tracks',
+ component: () => import('~/views/admin/CommonList.vue'),
+ props: route => ({ defaultQuery: route.query.q, type: 'tracks' })
+ },
+ {
+ path: 'tracks/:id',
+ name: 'manage.library.tracks.detail',
+ component: () => import('~/views/admin/library/TrackDetail.vue'),
+ props: true
+ },
+ {
+ path: 'libraries',
+ name: 'manage.library.libraries',
+ component: () => import('~/views/admin/CommonList.vue'),
+ props: route => ({ defaultQuery: route.query.q, type: 'libraries' })
+ },
+ {
+ path: 'libraries/:id',
+ name: 'manage.library.libraries.detail',
+ component: () => import('~/views/admin/library/LibraryDetail.vue'),
+ props: true
+ },
+ {
+ path: 'uploads',
+ name: 'manage.library.uploads',
+ component: () => import('~/views/admin/CommonList.vue'),
+ props: route => ({ defaultQuery: route.query.q, type: 'uploads' })
+ },
+ {
+ path: 'uploads/:id',
+ name: 'manage.library.uploads.detail',
+ component: () => import('~/views/admin/library/UploadDetail.vue'),
+ props: true
+ },
+ {
+ path: 'tags',
+ name: 'manage.library.tags',
+ component: () => import('~/views/admin/CommonList.vue'),
+ props: route => ({ defaultQuery: route.query.q, type: 'tags' })
+ },
+ {
+ path: 'tags/:id',
+ name: 'manage.library.tags.detail',
+ component: () => import('~/views/admin/library/TagDetail.vue'),
+ props: true
+ }
+ ]
+ },
+ {
+ path: 'manage/users',
+ beforeEnter: hasPermissions('settings'),
+ component: () => import('~/views/admin/users/Base.vue'),
+ children: [
+ {
+ path: 'users',
+ name: 'manage.users.users.list',
+ component: () => import('~/views/admin/CommonList.vue'),
+ props: route => ({ type: 'users' })
+ },
+ {
+ path: 'invitations',
+ name: 'manage.users.invitations.list',
+ component: () => import('~/views/admin/CommonList.vue'),
+ props: route => ({ type: 'invitations' })
+ }
+ ]
+ },
+ {
+ path: 'manage/moderation',
+ beforeEnter: hasPermissions('moderation'),
+ component: () => import('~/views/admin/moderation/Base.vue'),
+ children: [
+ {
+ path: 'domains',
+ name: 'manage.moderation.domains.list',
+ component: () => import('~/views/admin/moderation/DomainsList.vue')
+ },
+ {
+ path: 'domains/:id',
+ name: 'manage.moderation.domains.detail',
+ component: () => import('~/views/admin/moderation/DomainsDetail.vue'),
+ props: true
+ },
+ {
+ path: 'accounts',
+ name: 'manage.moderation.accounts.list',
+ component: () => import('~/views/admin/CommonList.vue'),
+ props: route => ({ defaultQuery: route.query.q, type: 'accounts' })
+ },
+ {
+ path: 'accounts/:id',
+ name: 'manage.moderation.accounts.detail',
+ component: () => import('~/views/admin/moderation/AccountsDetail.vue'),
+ props: true
+ },
+ {
+ path: 'reports',
+ name: 'manage.moderation.reports.list',
+ component: () => import('~/views/admin/moderation/ReportsList.vue'),
+ props: route => ({ defaultQuery: route.query.q }),
+ meta: {
+ paginateBy: 25
+ }
+ },
+ {
+ path: 'reports/:id',
+ name: 'manage.moderation.reports.detail',
+ component: () => import('~/views/admin/moderation/ReportDetail.vue'),
+ props: true
+ },
+ {
+ path: 'requests',
+ name: 'manage.moderation.requests.list',
+ component: () => import('~/views/admin/moderation/RequestsList.vue'),
+ props: route => ({ defaultQuery: route.query.q }),
+ meta: {
+ paginateBy: 25
+ }
+ },
+ {
+ path: 'requests/:id',
+ name: 'manage.moderation.requests.detail',
+ component: () => import('~/views/admin/moderation/RequestDetail.vue'),
+ props: true
+ }
+ ]
+ }
+] as RouteRecordRaw[]
diff --git a/front/src/ui/routes/settings.ts b/front/src/ui/routes/settings.ts
new file mode 100644
index 000000000..61cd68d9f
--- /dev/null
+++ b/front/src/ui/routes/settings.ts
@@ -0,0 +1,30 @@
+import type { RouteRecordRaw } from 'vue-router'
+
+export default [
+ {
+ path: 'settings',
+ name: 'settings',
+ component: () => import('~/components/auth/Settings.vue')
+ },
+ {
+ path: 'settings/applications/new',
+ name: 'settings.applications.new',
+ props: route => ({
+ scopes: route.query.scopes,
+ name: route.query.name,
+ redirect_uris: route.query.redirect_uris
+ }),
+ component: () => import('~/components/auth/ApplicationNew.vue')
+ },
+ {
+ path: 'settings/plugins',
+ name: 'settings.plugins',
+ component: () => import('~/views/auth/Plugins.vue')
+ },
+ {
+ path: 'settings/applications/:id/edit',
+ name: 'settings.applications.edit',
+ component: () => import('~/components/auth/ApplicationEdit.vue'),
+ props: true
+ }
+] as RouteRecordRaw[]
diff --git a/front/src/ui/routes/ui.ts b/front/src/ui/routes/ui.ts
new file mode 100644
index 000000000..f4994b901
--- /dev/null
+++ b/front/src/ui/routes/ui.ts
@@ -0,0 +1,50 @@
+import type { RouteRecordRaw } from 'vue-router'
+import { useUploadsStore } from '~/ui/stores/upload'
+
+export default [
+ {
+ path: '/ui',
+ name: 'ui',
+ component: () => import('~/ui/layouts/constrained.vue'),
+ children: [
+ {
+ path: 'upload',
+ name: 'upload',
+ component: () => import('~/ui/pages/upload.vue'),
+ children: [
+ {
+ path: '',
+ name: 'upload.index',
+ component: () => import('~/ui/pages/upload/index.vue')
+ },
+
+ {
+ path: 'running',
+ name: 'upload.running',
+ component: () => import('~/ui/pages/upload/running.vue'),
+ beforeEnter: (_to, _from, next) => {
+ const uploads = useUploadsStore()
+ if (uploads.uploadGroups.length === 0) {
+ next('/ui/upload')
+ } else {
+ next()
+ }
+ }
+ },
+
+ {
+ path: 'history',
+ name: 'upload.history',
+ component: () => import('~/ui/pages/upload/history.vue')
+ },
+
+ {
+ path: 'all',
+ name: 'upload.all',
+ component: () => import('~/ui/pages/upload/all.vue')
+ }
+ ]
+ }
+ ]
+ }
+] as RouteRecordRaw[]
diff --git a/front/src/ui/routes/user.ts b/front/src/ui/routes/user.ts
new file mode 100644
index 000000000..381462dbb
--- /dev/null
+++ b/front/src/ui/routes/user.ts
@@ -0,0 +1,34 @@
+import type { RouteRecordRaw } from 'vue-router'
+
+import store from '~/store'
+
+export default [
+ { suffix: '.full', path: '@:username@:domain' },
+ { suffix: '', path: '@:username' }
+].map((route) => {
+ return {
+ path: route.path,
+ name: `profile${route.suffix}`,
+ component: () => import('~/views/auth/ProfileBase.vue'),
+ beforeEnter (to, from, next) {
+ if (!store.state.auth.authenticated && to.query.domain && store.getters['instance/domain'] !== to.query.domain) {
+ return next({ name: 'login', query: { next: to.fullPath } })
+ }
+
+ next()
+ },
+ props: true,
+ children: [
+ {
+ path: '',
+ name: `profile${route.suffix}.overview`,
+ component: () => import('~/views/auth/ProfileOverview.vue')
+ },
+ {
+ path: 'activity',
+ name: `profile${route.suffix}.activity`,
+ component: () => import('~/views/auth/ProfileActivity.vue')
+ }
+ ]
+ }
+}) as RouteRecordRaw[]
diff --git a/front/src/ui/stores/upload.ts b/front/src/ui/stores/upload.ts
index e11a9ae15..9d6aa8a37 100644
--- a/front/src/ui/stores/upload.ts
+++ b/front/src/ui/stores/upload.ts
@@ -1,4 +1,3 @@
-
import { defineStore, acceptHMRUpdate } from 'pinia'
import { computed, reactive, readonly, ref, markRaw, toRaw, unref, watch } from 'vue'
import { whenever, useWebWorker } from '@vueuse/core'
@@ -108,7 +107,7 @@ export class UploadGroup {
return this.queue.filter((entry) => !entry.importedAt && !entry.failReason).length
}
- queueUpload(file: File) {
+ queueUpload (file: File) {
const entry = new UploadGroupEntry(file, this)
this.queue.push(entry)
@@ -151,7 +150,7 @@ watch(currentUploadGroup, (_, from) => {
})
// Tag extraction with a Web Worker
-const { post: retrieveMetadata, data: workerMetadata} = useWebWorker(() => new FileMetadataParserWorker())
+const { post: retrieveMetadata, data: workerMetadata } = useWebWorker(() => new FileMetadataParserWorker())
whenever(workerMetadata, (reactiveData) => {
const data = toRaw(unref(reactiveData))
const entry = UploadGroup.entries[data.id]
@@ -198,7 +197,7 @@ export const useUploadsStore = defineStore('uploads', () => {
window.addEventListener('beforeunload', (event) => {
if (isUploading.value) {
event.preventDefault()
- return event.returnValue = 'The upload is still in progress. Are you sure you want to leave?'
+ return (event.returnValue = 'The upload is still in progress. Are you sure you want to leave?')
}
})
@@ -212,7 +211,7 @@ export const useUploadsStore = defineStore('uploads', () => {
currentIndex: readonly(currentIndex),
currentUpload,
queue: readonly(uploadQueue),
- uploadGroups: uploadGroups,
+ uploadGroups,
createUploadGroup,
currentUploadGroup,
progress
diff --git a/front/src/ui/workers/file-metadata-parser.ts b/front/src/ui/workers/file-metadata-parser.ts
index ca57665b1..21be995e0 100644
--- a/front/src/ui/workers/file-metadata-parser.ts
+++ b/front/src/ui/workers/file-metadata-parser.ts
@@ -17,7 +17,6 @@ export interface MetadataParsingFailure {
export type MetadataParsingResult = MetadataParsingSuccess | MetadataParsingFailure
-
const parse = async (id: string, file: File) => {
try {
console.log(`[${id}] parsing...`)