refactor(front): library upload pages

This commit is contained in:
ArneBo 2025-04-06 20:24:46 +02:00
parent cb9ba7d153
commit f754b397a9
5 changed files with 111 additions and 108 deletions

View File

@ -1,11 +1,23 @@
<script setup lang="ts"> <script setup lang="ts">
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { computed } from 'vue' import { computed, ref } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import Nav from '~/components/ui/Nav.vue'
import Spacer from '~/components/ui/Spacer.vue'
const { t } = useI18n() const { t } = useI18n()
const route = useRoute() const route = useRoute()
const tabs = ref([{
title: t('views.content.Base.link.libraries'),
to: { name: 'content.libraries.index'}
},
{
title: t('views.content.Base.link.tracks'),
to: { name: 'content.libraries.files' },
}])
const labels = computed(() => ({ const labels = computed(() => ({
secondaryMenu: t('views.content.Base.menu.secondary'), secondaryMenu: t('views.content.Base.menu.secondary'),
title: t('views.content.Base.title') title: t('views.content.Base.title')
@ -17,24 +29,11 @@ const labels = computed(() => ({
v-title="labels.title" v-title="labels.title"
class="main" class="main"
> >
<nav <Nav
class="ui secondary pointing menu" v-model="tabs"
role="navigation"
:aria-label="labels.secondaryMenu" :aria-label="labels.secondaryMenu"
> />
<router-link <Spacer />
class="ui item"
:to="{name: 'content.libraries.index'}"
>
{{ t('views.content.Base.link.libraries') }}
</router-link>
<router-link
class="ui item"
:to="{name: 'content.libraries.files'}"
>
{{ t('views.content.Base.link.tracks') }}
</router-link>
</nav>
<router-view :key="route.fullPath" /> <router-view :key="route.fullPath" />
</main> </main>
</template> </template>

View File

@ -9,7 +9,5 @@ defineProps<Props>()
</script> </script>
<template> <template>
<section class="ui vertical aligned stripe segment">
<library-files-table :default-query="query" /> <library-files-table :default-query="query" />
</section>
</template> </template>

View File

@ -227,6 +227,7 @@ const getImportStatusChoice = (importStatus: ImportStatus) => {
</Layout> </Layout>
</Layout> </Layout>
</Layout> </Layout>
<Spacer />
<import-status-modal <import-status-modal
v-if="detailedUpload" v-if="detailedUpload"
v-model:show="showUploadDetailModal" v-model:show="showUploadDetailModal"

View File

@ -2,20 +2,29 @@
import type { Library } from '~/types' import type { Library } from '~/types'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { ref } from 'vue' import { ref } from 'vue'
import { useStore } from '~/store'
import axios from 'axios' import axios from 'axios'
import LibraryForm from './Form.vue' import LibraryForm from './Form.vue'
import LibraryCard from './Card.vue' import LibraryCard from '~/views/content/remote/Card.vue'
import Quota from './Quota.vue' import Quota from './Quota.vue'
import useErrorHandler from '~/composables/useErrorHandler' import useErrorHandler from '~/composables/useErrorHandler'
import Loader from '~/components/ui/Loader.vue'
import Section from '~/components/ui/Section.vue'
import Alert from '~/components/ui/Alert.vue'
import Button from '~/components/ui/Button.vue'
import Spacer from '~/components/ui/Spacer.vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
const { t } = useI18n() const { t } = useI18n()
const router = useRouter() const router = useRouter()
const store = useStore()
const libraries = ref([] as Library[]) const libraries = ref([] as Library[])
const isLoading = ref(false) const isLoading = ref(false)
@ -44,61 +53,42 @@ const libraryCreated = (library: Library) => {
</script> </script>
<template> <template>
<section class="ui vertical aligned stripe segment"> <Loader v-if="isLoading" />
<!-- TODO: Modernise to new Ui --> <Section
<div
v-if="isLoading"
:class="['ui', {'active': isLoading}, 'inverted', 'dimmer']"
>
<div class="ui text loader">
{{ t('views.content.libraries.Home.loading.libraries') }}
</div>
</div>
<div
v-else v-else
class="ui text container" :h1="t('views.content.libraries.Home.header.libraries')"
page-header
> >
<h1 class="ui header"> <Alert
{{ t('views.content.libraries.Home.header.libraries') }} v-if="libraries.length == 0"
</h1> yellow
<p v-if="libraries.length == 0">
{{ t('views.content.libraries.Home.empty.noLibrary') }}
</p>
<a
:aria-expanded="!hiddenForm"
href=""
@click.prevent="hiddenForm = !hiddenForm"
> >
<i {{ t('views.content.libraries.Home.empty.noLibrary') }}
v-if="hiddenForm" <Button
class="plus icon" :aria-expanded="!hiddenForm"
/> :icon="hiddenForm ? 'bi-plus' : 'bi-minus'"
<i @click.prevent="hiddenForm = !hiddenForm"
v-else >
class="minus icon" {{ t('views.content.libraries.Home.link.createLibrary') }}
/> </Button>
{{ t('views.content.libraries.Home.link.createLibrary') }} </Alert>
</a>
<library-form <library-form
v-if="!hiddenForm" v-if="!hiddenForm"
@created="libraryCreated" @created="libraryCreated"
/> />
<div class="ui hidden divider" /> </Section>
<quota /> <quota />
<div class="ui hidden divider" /> <Spacer />
<div <Section
v-if="libraries.length > 0" v-if="libraries.length > 0"
class="ui two column grid" >
> <library-card
<div v-for="library in libraries"
v-for="library in libraries" :key="library.uuid"
:key="library.uuid" :display-scan="false"
class="column" :display-follow="store.state.auth.authenticated && library.actor.full_username != store.state.auth.fullUsername"
> :initial-library="library"
<library-card :library="library" /> :display-copy-fid="true"
</div> />
</div> </Section>
</div>
</section>
</template> </template>

View File

@ -12,6 +12,12 @@ import { useI18n } from 'vue-i18n'
import DangerousButton from '~/components/common/DangerousButton.vue' import DangerousButton from '~/components/common/DangerousButton.vue'
import Alert from '~/components/ui/Alert.vue'
import Section from '~/components/ui/Section.vue'
import Layout from '~/components/ui/Layout.vue'
import Link from '~/components/ui/Link.vue'
import Spacer from '~/components/ui/Spacer.vue'
const { t } = useI18n() const { t } = useI18n()
const quotaStatus = ref() const quotaStatus = ref()
@ -56,10 +62,9 @@ const purgeErroredFiles = () => purge('errored')
</script> </script>
<template> <template>
<div class="ui segment"> <Section
<h3 class="ui header"> :h3="t('views.content.libraries.Quota.header.currentUsage')"
{{ t('views.content.libraries.Quota.header.currentUsage') }} >
</h3>
<div <div
v-if="isLoading" v-if="isLoading"
:class="['ui', {'active': isLoading}, 'inverted', 'dimmer']" :class="['ui', {'active': isLoading}, 'inverted', 'dimmer']"
@ -68,9 +73,11 @@ const purgeErroredFiles = () => purge('errored')
{{ t('views.content.libraries.Quota.loading.currentUsage') }} {{ t('views.content.libraries.Quota.loading.currentUsage') }}
</div> </div>
</div> </div>
<div <Alert
:class="['ui', {'success': progress < 60}, {'warning': progress >= 60 && progress < 96}, {'error': progress >= 95}, 'progress']"
data-percent="progress" data-percent="progress"
:green="progress < 60"
:yellow="progress >= 60 && progress < 96"
:red="progress >= 95"
> >
<div <div
class="bar" class="bar"
@ -86,17 +93,16 @@ const purgeErroredFiles = () => purge('errored')
> >
{{ t('views.content.libraries.Quota.label.currentUsage', {max: humanSize(quotaStatus.max * 1000 * 1000), currentAmount: humanSize(quotaStatus.current * 1000 * 1000)}) }} {{ t('views.content.libraries.Quota.label.currentUsage', {max: humanSize(quotaStatus.max * 1000 * 1000), currentAmount: humanSize(quotaStatus.current * 1000 * 1000)}) }}
</div> </div>
</div> </Alert>
<div class="ui hidden divider" /> <Layout
<div
v-if="quotaStatus" v-if="quotaStatus"
class="ui stackable three column grid" flex
> >
<div <Alert
v-if="quotaStatus.pending > 0" v-if="quotaStatus.pending > 0"
class="column" yellow
> >
<div class="ui tiny warning statistic"> <div class="statistic">
<div class="value"> <div class="value">
{{ humanSize(quotaStatus.pending * 1000 * 1000) }} {{ humanSize(quotaStatus.pending * 1000 * 1000) }}
</div> </div>
@ -104,13 +110,16 @@ const purgeErroredFiles = () => purge('errored')
{{ t('views.content.libraries.Quota.label.pending') }} {{ t('views.content.libraries.Quota.label.pending') }}
</div> </div>
</div> </div>
<div> <Spacer />
<router-link <Layout flex>
class="ui basic primary tiny button" <Link
primary
solid
low-height
:to="{name: 'content.libraries.files', query: {q: compileTokens([{field: 'status', value: 'pending'}])}}" :to="{name: 'content.libraries.files', query: {q: compileTokens([{field: 'status', value: 'pending'}])}}"
> >
{{ t('views.content.libraries.Quota.link.viewFiles') }} {{ t('views.content.libraries.Quota.link.viewFiles') }}
</router-link> </Link>
<dangerous-button <dangerous-button
low-height low-height
@ -125,11 +134,11 @@ const purgeErroredFiles = () => purge('errored')
{{ t('views.content.libraries.Quota.button.purge') }} {{ t('views.content.libraries.Quota.button.purge') }}
</template> </template>
</dangerous-button> </dangerous-button>
</div> </Layout>
</div> </Alert>
<div <Alert
v-if="quotaStatus.skipped > 0" v-if="quotaStatus.skipped > 0"
class="column" yellow
> >
<div class="ui tiny statistic"> <div class="ui tiny statistic">
<div class="value"> <div class="value">
@ -139,13 +148,16 @@ const purgeErroredFiles = () => purge('errored')
{{ t('views.content.libraries.Quota.label.skipped') }} {{ t('views.content.libraries.Quota.label.skipped') }}
</div> </div>
</div> </div>
<div> <Spacer />
<router-link <Layout flex>
class="ui basic primary tiny button" <Link
primary
solid
low-height
:to="{name: 'content.libraries.files', query: {q: compileTokens([{field: 'status', value: 'skipped'}])}}" :to="{name: 'content.libraries.files', query: {q: compileTokens([{field: 'status', value: 'skipped'}])}}"
> >
{{ t('views.content.libraries.Quota.link.viewFiles') }} {{ t('views.content.libraries.Quota.link.viewFiles') }}
</router-link> </Link>
<dangerous-button <dangerous-button
low-height low-height
:action="purgeSkippedFiles" :action="purgeSkippedFiles"
@ -159,11 +171,11 @@ const purgeErroredFiles = () => purge('errored')
{{ t('views.content.libraries.Quota.button.purge') }} {{ t('views.content.libraries.Quota.button.purge') }}
</template> </template>
</dangerous-button> </dangerous-button>
</div> </Layout>
</div> </Alert>
<div <Alert
v-if="quotaStatus.errored > 0" v-if="quotaStatus.errored > 0"
class="column" red
> >
<div class="ui tiny danger statistic"> <div class="ui tiny danger statistic">
<div class="value"> <div class="value">
@ -173,13 +185,16 @@ const purgeErroredFiles = () => purge('errored')
{{ t('views.content.libraries.Quota.label.errored') }} {{ t('views.content.libraries.Quota.label.errored') }}
</div> </div>
</div> </div>
<div> <Spacer />
<router-link <Layout flex>
class="ui basic primary tiny button" <Link
primary
solid
low-height
:to="{name: 'content.libraries.files', query: {q: compileTokens([{field: 'status', value: 'errored'}])}}" :to="{name: 'content.libraries.files', query: {q: compileTokens([{field: 'status', value: 'errored'}])}}"
> >
{{ t('views.content.libraries.Quota.link.viewFiles') }} {{ t('views.content.libraries.Quota.link.viewFiles') }}
</router-link> </Link>
<dangerous-button <dangerous-button
low-height low-height
:action="purgeErroredFiles" :action="purgeErroredFiles"
@ -193,8 +208,8 @@ const purgeErroredFiles = () => purge('errored')
{{ t('views.content.libraries.Quota.button.purge') }} {{ t('views.content.libraries.Quota.button.purge') }}
</template> </template>
</dangerous-button> </dangerous-button>
</div> </Layout>
</div> </Alert>
</div> </Layout>
</div> </Section>
</template> </template>