Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create quota information component, add to account page #11287

Merged
merged 3 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Enhancement: Add quota information to account page

We've added a new section to the account page that displays the users current quota usage.

https://github.com/owncloud/web/pull/11287

79 changes: 79 additions & 0 deletions packages/web-runtime/src/components/Account/QuotaInformation.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<template>
<div class="quota-information oc-flex oc-flex-bottom">
<oc-icon name="hard-drive-2" size="small" fill-type="line" class="oc-mr-xs" />
<div>
<p class="oc-my-rm">
<span class="quota-information-text" v-text="personalStorageDetailsLabel" />
</p>
<oc-progress
v-if="limitedPersonalStorage"
class="quota-information-progress-bar"
:value="quotaUsagePercent"
:max="100"
size="small"
:variation="quotaProgressVariant"
/>
</div>
</div>
</template>

<script lang="ts">
import { computed, defineComponent, PropType, unref } from 'vue'
import { Quota } from '@ownclouders/web-client/graph/generated'
import { filesize } from 'filesize'
import { useGettext } from 'vue3-gettext'

export default defineComponent({
name: 'QuotaInformation',
props: {
quota: {
type: Object as PropType<Quota>,
required: true,
default: () => undefined as Quota // FIXME: hack because vue doesn't detect type
}
},
setup(props) {
const { $gettext } = useGettext()

const limitedPersonalStorage = computed(() => {
return props.quota.total !== 0
})

const quotaUsagePercent = computed(() => {
return parseFloat(((props.quota.used / props.quota.total) * 100).toFixed(2))
})

const personalStorageDetailsLabel = computed(() => {
const total = props.quota.total || 0
const used = props.quota.used || 0
return total
? $gettext('%{used} of %{total} used (%{percentage}%)', {
used: filesize(used),
total: filesize(total),
percentage: (unref(quotaUsagePercent) || 0).toString()
})
: $gettext('%{used} used', {
used: filesize(used),
total: filesize(total)
})
})

const quotaProgressVariant = computed(() => {
if ((unref(quotaUsagePercent) || 0) < 80) {
return 'primary'
}
if ((unref(quotaUsagePercent) || 0) < 90) {
return 'warning'
}
return 'danger'
})

return {
quotaUsagePercent,
personalStorageDetailsLabel,
limitedPersonalStorage,
quotaProgressVariant
}
}
})
</script>
59 changes: 8 additions & 51 deletions packages/web-runtime/src/components/Topbar/UserMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -70,24 +70,11 @@
<span class="profile-info-wrapper" :class="{ 'oc-py-xs': !user.mail }">
<span class="oc-display-block" v-text="user.displayName" />
<span v-if="user.mail" class="oc-text-small" v-text="user.mail" />
<div v-if="quotaEnabled" class="storage-wrapper oc-flex oc-flex-bottom oc-mt-xs">
<oc-icon name="hard-drive-2" size="small" fill-type="line" class="oc-mr-xs" />
<div>
<p class="oc-my-rm">
<span
class="storage-wrapper-quota oc-text-small"
v-text="personalStorageDetailsLabel"
/>
</p>
<oc-progress
v-if="limitedPersonalStorage"
:value="quotaUsagePercent"
:max="100"
size="small"
:variation="quotaProgressVariant"
/>
</div>
</div>
<quota-information
v-if="quotaEnabled"
:quota="quota"
class="oc-text-small oc-mt-xs"
/>
</span>
</li>
<li>
Expand Down Expand Up @@ -125,7 +112,6 @@
<script lang="ts">
import { storeToRefs } from 'pinia'
import { defineComponent, ComponentPublicInstance, computed, unref } from 'vue'
import { filesize } from 'filesize'
import {
useRoute,
useSpacesStore,
Expand All @@ -135,8 +121,10 @@ import {
useAuthService
} from '@ownclouders/web-pkg'
import { OcDrop } from 'design-system/src/components'
import QuotaInformation from '../Account/QuotaInformation.vue'

export default defineComponent({
components: { QuotaInformation },
setup() {
const route = useRoute()
const userStore = useUserStore()
Expand Down Expand Up @@ -182,38 +170,8 @@ export default defineComponent({
onPremisesSamAccountName() {
return this.user?.onPremisesSamAccountName
},
personalStorageDetailsLabel() {
const total = this.quota.total || 0
const used = this.quota.used || 0
return total
? this.$gettext('%{used} of %{total} used (%{percentage}%)', {
used: filesize(used),
total: filesize(total),
percentage: (this.quotaUsagePercent || 0).toString()
})
: this.$gettext('%{used} used', {
used: filesize(used),
total: filesize(total)
})
},
limitedPersonalStorage() {
return this.quota.total !== 0
},
quotaEnabled() {
return !!this.quota
},
quotaUsagePercent() {
return parseFloat(((this.quota.used / this.quota.total) * 100).toFixed(2))
},

quotaProgressVariant() {
if ((this.quotaUsagePercent || 0) < 80) {
return 'primary'
}
if ((this.quotaUsagePercent || 0) < 90) {
return 'warning'
}
return 'danger'
}
},
mounted() {
Expand Down Expand Up @@ -256,8 +214,7 @@ export default defineComponent({
}
}

&.profile-info-wrapper,
&.storage-wrapper {
&.profile-info-wrapper {
gap: var(--oc-space-medium);
min-height: 3rem;
}
Expand Down
15 changes: 14 additions & 1 deletion packages/web-runtime/src/pages/account.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@
<span v-else v-text="$gettext('No email has been set up')" />
</dd>
</div>
<div v-if="!!quota" class="account-page-info-quota oc-mb oc-width-1-2@m oc-width-1-1@s">
<dt class="oc-text-normal oc-text-muted" v-text="$gettext('Personal storage')" />
<dd data-testid="quota">
<quota-information :quota="quota" class="oc-mt-xs" />
</dd>
</div>
<div class="account-page-info-groups oc-mb oc-width-1-2@m oc-width-1-1@s">
<dt class="oc-text-normal oc-text-muted" v-text="$gettext('Group memberships')" />
<dd data-testid="group-names">
Expand Down Expand Up @@ -219,10 +225,12 @@ import { supportedLanguages } from '../defaults'
import { User } from '@ownclouders/web-client/graph/generated'
import { isEmpty } from 'lodash-es'
import { call } from '@ownclouders/web-client'
import QuotaInformation from '../components/Account/QuotaInformation.vue'

export default defineComponent({
name: 'AccountPage',
components: {
QuotaInformation,
AppLoadingSpinner,
GdprExport,
ExtensionPreference,
Expand Down Expand Up @@ -254,6 +262,10 @@ export default defineComponent({

const { user } = storeToRefs(userStore)

const quota = computed(() => {
return spacesStore.personalSpace?.spaceQuota
})

const showGdprExport = computed(() => {
return (
authStore.userContextReady &&
Expand Down Expand Up @@ -539,7 +551,8 @@ export default defineComponent({
loadAccountBundleTask,
loadGraphUserTask,
loadValuesListTask,
showEditPasswordModal
showEditPasswordModal,
quota
}
},
computed: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ exports[`User Menu component > when quota and no email is set > renders a naviga
<li data-v-08f1b1e7="" class="profile-info-wrapper oc-pl-s">
<avatar-image-stub data-v-08f1b1e7="" width="32" userid="einstein" user-name="Albert Einstein"></avatar-image-stub> <span data-v-08f1b1e7="" class="profile-info-wrapper oc-py-xs"><span data-v-08f1b1e7="" class="oc-display-block">Albert Einstein</span>
<!--v-if-->
<div data-v-08f1b1e7="" class="storage-wrapper oc-flex oc-flex-bottom oc-mt-xs">
<oc-icon-stub data-v-08f1b1e7="" name="hard-drive-2" size="small" fill-type="line" class="oc-mr-xs"></oc-icon-stub>
<div data-v-08f1b1e7="">
<p data-v-08f1b1e7="" class="oc-my-rm"><span data-v-08f1b1e7="" class="storage-wrapper-quota oc-text-small">300 B of 1 kB used (30%)</span></p>
<oc-progress-stub data-v-08f1b1e7="" max="100" size="small" variation="primary" value="30"></oc-progress-stub>
<div data-v-08f1b1e7="" class="quota-information oc-flex oc-flex-bottom oc-text-small oc-mt-xs">
<oc-icon-stub name="hard-drive-2" size="small" fill-type="line" class="oc-mr-xs"></oc-icon-stub>
<div>
<p class="oc-my-rm"><span class="quota-information-text">300 B of 1 kB used (30%)</span></p>
<oc-progress-stub class="quota-information-progress-bar" max="100" size="small" variation="primary" value="30"></oc-progress-stub>
</div>
</div></span>
</li>
Expand Down Expand Up @@ -98,11 +98,11 @@ exports[`User Menu component > when quota is above 80% and below 90% > renders a
<oc-list-stub data-v-08f1b1e7="" class="user-menu-list">
<li data-v-08f1b1e7="" class="profile-info-wrapper oc-pl-s">
<avatar-image-stub data-v-08f1b1e7="" width="32" userid="einstein" user-name="Albert Einstein"></avatar-image-stub> <span data-v-08f1b1e7="" class="profile-info-wrapper"><span data-v-08f1b1e7="" class="oc-display-block">Albert Einstein</span> <span data-v-08f1b1e7="" class="oc-text-small">test@test.de</span>
<div data-v-08f1b1e7="" class="storage-wrapper oc-flex oc-flex-bottom oc-mt-xs">
<oc-icon-stub data-v-08f1b1e7="" name="hard-drive-2" size="small" fill-type="line" class="oc-mr-xs"></oc-icon-stub>
<div data-v-08f1b1e7="">
<p data-v-08f1b1e7="" class="oc-my-rm"><span data-v-08f1b1e7="" class="storage-wrapper-quota oc-text-small">810 B of 1 kB used (81%)</span></p>
<oc-progress-stub data-v-08f1b1e7="" max="100" size="small" variation="warning" value="81"></oc-progress-stub>
<div data-v-08f1b1e7="" class="quota-information oc-flex oc-flex-bottom oc-text-small oc-mt-xs">
<oc-icon-stub name="hard-drive-2" size="small" fill-type="line" class="oc-mr-xs"></oc-icon-stub>
<div>
<p class="oc-my-rm"><span class="quota-information-text">810 B of 1 kB used (81%)</span></p>
<oc-progress-stub class="quota-information-progress-bar" max="100" size="small" variation="warning" value="81"></oc-progress-stub>
</div>
</div></span>
</li>
Expand Down Expand Up @@ -131,11 +131,11 @@ exports[`User Menu component > when quota is above 90% > renders a danger quota
<oc-list-stub data-v-08f1b1e7="" class="user-menu-list">
<li data-v-08f1b1e7="" class="profile-info-wrapper oc-pl-s">
<avatar-image-stub data-v-08f1b1e7="" width="32" userid="einstein" user-name="Albert Einstein"></avatar-image-stub> <span data-v-08f1b1e7="" class="profile-info-wrapper"><span data-v-08f1b1e7="" class="oc-display-block">Albert Einstein</span> <span data-v-08f1b1e7="" class="oc-text-small">test@test.de</span>
<div data-v-08f1b1e7="" class="storage-wrapper oc-flex oc-flex-bottom oc-mt-xs">
<oc-icon-stub data-v-08f1b1e7="" name="hard-drive-2" size="small" fill-type="line" class="oc-mr-xs"></oc-icon-stub>
<div data-v-08f1b1e7="">
<p data-v-08f1b1e7="" class="oc-my-rm"><span data-v-08f1b1e7="" class="storage-wrapper-quota oc-text-small">910 B of 1 kB used (91%)</span></p>
<oc-progress-stub data-v-08f1b1e7="" max="100" size="small" variation="danger" value="91"></oc-progress-stub>
<div data-v-08f1b1e7="" class="quota-information oc-flex oc-flex-bottom oc-text-small oc-mt-xs">
<oc-icon-stub name="hard-drive-2" size="small" fill-type="line" class="oc-mr-xs"></oc-icon-stub>
<div>
<p class="oc-my-rm"><span class="quota-information-text">910 B of 1 kB used (91%)</span></p>
<oc-progress-stub class="quota-information-progress-bar" max="100" size="small" variation="danger" value="91"></oc-progress-stub>
</div>
</div></span>
</li>
Expand Down Expand Up @@ -164,11 +164,11 @@ exports[`User Menu component > when quota is below 80% > renders a primary quota
<oc-list-stub data-v-08f1b1e7="" class="user-menu-list">
<li data-v-08f1b1e7="" class="profile-info-wrapper oc-pl-s">
<avatar-image-stub data-v-08f1b1e7="" width="32" userid="einstein" user-name="Albert Einstein"></avatar-image-stub> <span data-v-08f1b1e7="" class="profile-info-wrapper"><span data-v-08f1b1e7="" class="oc-display-block">Albert Einstein</span> <span data-v-08f1b1e7="" class="oc-text-small">test@test.de</span>
<div data-v-08f1b1e7="" class="storage-wrapper oc-flex oc-flex-bottom oc-mt-xs">
<oc-icon-stub data-v-08f1b1e7="" name="hard-drive-2" size="small" fill-type="line" class="oc-mr-xs"></oc-icon-stub>
<div data-v-08f1b1e7="">
<p data-v-08f1b1e7="" class="oc-my-rm"><span data-v-08f1b1e7="" class="storage-wrapper-quota oc-text-small">300 B of 1 kB used (30%)</span></p>
<oc-progress-stub data-v-08f1b1e7="" max="100" size="small" variation="primary" value="30"></oc-progress-stub>
<div data-v-08f1b1e7="" class="quota-information oc-flex oc-flex-bottom oc-text-small oc-mt-xs">
<oc-icon-stub name="hard-drive-2" size="small" fill-type="line" class="oc-mr-xs"></oc-icon-stub>
<div>
<p class="oc-my-rm"><span class="quota-information-text">300 B of 1 kB used (30%)</span></p>
<oc-progress-stub class="quota-information-progress-bar" max="100" size="small" variation="primary" value="30"></oc-progress-stub>
</div>
</div></span>
</li>
Expand Down Expand Up @@ -197,10 +197,10 @@ exports[`User Menu component > when quota is not defined > renders no percentag
<oc-list-stub data-v-08f1b1e7="" class="user-menu-list">
<li data-v-08f1b1e7="" class="profile-info-wrapper oc-pl-s">
<avatar-image-stub data-v-08f1b1e7="" width="32" userid="einstein" user-name="Albert Einstein"></avatar-image-stub> <span data-v-08f1b1e7="" class="profile-info-wrapper"><span data-v-08f1b1e7="" class="oc-display-block">Albert Einstein</span> <span data-v-08f1b1e7="" class="oc-text-small">test@test.de</span>
<div data-v-08f1b1e7="" class="storage-wrapper oc-flex oc-flex-bottom oc-mt-xs">
<oc-icon-stub data-v-08f1b1e7="" name="hard-drive-2" size="small" fill-type="line" class="oc-mr-xs"></oc-icon-stub>
<div data-v-08f1b1e7="">
<p data-v-08f1b1e7="" class="oc-my-rm"><span data-v-08f1b1e7="" class="storage-wrapper-quota oc-text-small">910 B used</span></p>
<div data-v-08f1b1e7="" class="quota-information oc-flex oc-flex-bottom oc-text-small oc-mt-xs">
<oc-icon-stub name="hard-drive-2" size="small" fill-type="line" class="oc-mr-xs"></oc-icon-stub>
<div>
<p class="oc-my-rm"><span class="quota-information-text">910 B used</span></p>
<!--v-if-->
</div>
</div></span>
Expand Down Expand Up @@ -230,10 +230,10 @@ exports[`User Menu component > when quota is unlimited > renders no percentag of
<oc-list-stub data-v-08f1b1e7="" class="user-menu-list">
<li data-v-08f1b1e7="" class="profile-info-wrapper oc-pl-s">
<avatar-image-stub data-v-08f1b1e7="" width="32" userid="einstein" user-name="Albert Einstein"></avatar-image-stub> <span data-v-08f1b1e7="" class="profile-info-wrapper"><span data-v-08f1b1e7="" class="oc-display-block">Albert Einstein</span> <span data-v-08f1b1e7="" class="oc-text-small">test@test.de</span>
<div data-v-08f1b1e7="" class="storage-wrapper oc-flex oc-flex-bottom oc-mt-xs">
<oc-icon-stub data-v-08f1b1e7="" name="hard-drive-2" size="small" fill-type="line" class="oc-mr-xs"></oc-icon-stub>
<div data-v-08f1b1e7="">
<p data-v-08f1b1e7="" class="oc-my-rm"><span data-v-08f1b1e7="" class="storage-wrapper-quota oc-text-small">300 B used</span></p>
<div data-v-08f1b1e7="" class="quota-information oc-flex oc-flex-bottom oc-text-small oc-mt-xs">
<oc-icon-stub name="hard-drive-2" size="small" fill-type="line" class="oc-mr-xs"></oc-icon-stub>
<div>
<p class="oc-my-rm"><span class="quota-information-text">300 B used</span></p>
<!--v-if-->
</div>
</div></span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ exports[`account page > account information section > displays basic user inform
<dt data-v-f2ac0579="" class="oc-text-normal oc-text-muted">Email</dt>
<dd data-v-f2ac0579="">some-email</dd>
</div>
<!--v-if-->
<div data-v-f2ac0579="" class="account-page-info-groups oc-mb oc-width-1-2@m oc-width-1-1@s">
<dt data-v-f2ac0579="" class="oc-text-normal oc-text-muted">Group memberships</dt>
<dd data-v-f2ac0579="" data-testid="group-names"><span data-v-f2ac0579="" data-testid="group-names-empty">You are not part of any group</span></dd>
Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/support/objects/account/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import util from 'util'
import config from '../../../config'

const accountMenuButton = '.oc-topbar-avatar'
const quotaValue = '.storage-wrapper-quota'
const quotaValue = '.quota-information-text'
const accountManageButton = '#oc-topbar-account-manage'
const infoValue = '.account-page-info-%s dd'
const requestExportButton = '[data-testid="request-export-btn"]'
Expand Down