Display user quota progress bars above upload form (#2981)
* Move user-quota to my-user-quota shared component * Add user-quota to upload form * Increase progress bar height and make it focusable * Correct syntax parenthesis * Add explicit title to user-quota bars + tooltip with quota values * Hide user-quota in second upload step * Customize focus styles on user-quota Co-authored-by: kimsible <kimsible@users.noreply.github.com>
This commit is contained in:
parent
b40a219338
commit
2e7f262724
|
@ -14,21 +14,7 @@
|
||||||
|
|
||||||
<div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
|
<div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
|
||||||
|
|
||||||
<div class="user-quota mb-3">
|
<my-user-quota [user]="user" [userInformationLoaded]="userInformationLoaded"></my-user-quota>
|
||||||
<div>
|
|
||||||
<div class="progress" i18n-title title="Total video quota">
|
|
||||||
<div class="progress-bar" role="progressbar" [style]="{ width: userVideoQuotaPercentage + '%' }" [attr.aria-valuenow]="userVideoQuotaUsed" aria-valuemin="0" [attr.aria-valuemax]="user.videoQuota">{{ userVideoQuotaUsed | bytes: 0 }}</div>
|
|
||||||
<span class="ml-auto mr-2">{{ userVideoQuota }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div *ngIf="hasDailyQuota()" class="mt-3">
|
|
||||||
<div class="progress" i18n-title title="Daily video quota">
|
|
||||||
<div class="progress-bar secondary" role="progressbar" [style]="{ width: userVideoQuotaDailyPercentage + '%' }" [attr.aria-valuenow]="userVideoQuotaUsedDaily" aria-valuemin="0" [attr.aria-valuemax]="user.videoQuotaDaily">{{ userVideoQuotaUsedDaily | bytes: 0 }}</div>
|
|
||||||
<span class="ml-auto mr-2">{{ userVideoQuotaDaily }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<my-account-profile [user]="user" [userInformationLoaded]="userInformationLoaded"></my-account-profile>
|
<my-account-profile [user]="user" [userInformationLoaded]="userInformationLoaded"></my-account-profile>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,15 +1,6 @@
|
||||||
@import '_variables';
|
@import '_variables';
|
||||||
@import '_mixins';
|
@import '_mixins';
|
||||||
|
|
||||||
.user-quota {
|
|
||||||
font-size: 15px;
|
|
||||||
margin-top: 20px;
|
|
||||||
|
|
||||||
label {
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.account-title {
|
.account-title {
|
||||||
@include settings-big-title;
|
@include settings-big-title;
|
||||||
|
|
||||||
|
@ -18,14 +9,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress {
|
.form-group {
|
||||||
@include progressbar;
|
max-width: 500px;
|
||||||
width: 500px;
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: $small-view) {
|
|
||||||
.progress {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { BytesPipe } from 'ngx-pipes'
|
|
||||||
import { ViewportScroller } from '@angular/common'
|
import { ViewportScroller } from '@angular/common'
|
||||||
import { AfterViewChecked, Component, OnInit } from '@angular/core'
|
import { AfterViewChecked, Component, OnInit } from '@angular/core'
|
||||||
import { AuthService, Notifier, User, UserService } from '@app/core'
|
import { AuthService, Notifier, User, UserService } from '@app/core'
|
||||||
|
@ -12,14 +11,6 @@ import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
export class MyAccountSettingsComponent implements OnInit, AfterViewChecked {
|
export class MyAccountSettingsComponent implements OnInit, AfterViewChecked {
|
||||||
user: User = null
|
user: User = null
|
||||||
|
|
||||||
userVideoQuota = '0'
|
|
||||||
userVideoQuotaUsed = 0
|
|
||||||
userVideoQuotaPercentage = 15
|
|
||||||
|
|
||||||
userVideoQuotaDaily = '0'
|
|
||||||
userVideoQuotaUsedDaily = 0
|
|
||||||
userVideoQuotaDailyPercentage = 15
|
|
||||||
|
|
||||||
private lastScrollHash: string
|
private lastScrollHash: string
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
|
@ -36,31 +27,6 @@ export class MyAccountSettingsComponent implements OnInit, AfterViewChecked {
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
this.user = this.authService.getUser()
|
this.user = this.authService.getUser()
|
||||||
|
|
||||||
this.authService.userInformationLoaded.subscribe(
|
|
||||||
() => {
|
|
||||||
if (this.user.videoQuota !== -1) {
|
|
||||||
this.userVideoQuota = new BytesPipe().transform(this.user.videoQuota, 0).toString()
|
|
||||||
} else {
|
|
||||||
this.userVideoQuota = this.i18n('Unlimited')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.user.videoQuotaDaily !== -1) {
|
|
||||||
this.userVideoQuotaDaily = new BytesPipe().transform(this.user.videoQuotaDaily, 0).toString()
|
|
||||||
} else {
|
|
||||||
this.userVideoQuotaDaily = this.i18n('Unlimited')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
this.userService.getMyVideoQuotaUsed()
|
|
||||||
.subscribe(data => {
|
|
||||||
this.userVideoQuotaUsed = data.videoQuotaUsed
|
|
||||||
this.userVideoQuotaPercentage = this.userVideoQuotaUsed * 100 / this.user.videoQuota
|
|
||||||
|
|
||||||
this.userVideoQuotaUsedDaily = data.videoQuotaUsedDaily
|
|
||||||
this.userVideoQuotaDailyPercentage = this.userVideoQuotaUsedDaily * 100 / this.user.videoQuotaDaily
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewChecked () {
|
ngAfterViewChecked () {
|
||||||
|
@ -83,8 +49,4 @@ export class MyAccountSettingsComponent implements OnInit, AfterViewChecked {
|
||||||
err => this.notifier.error(err.message)
|
err => this.notifier.error(err.message)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
hasDailyQuota () {
|
|
||||||
return this.user.videoQuotaDaily !== -1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
Instead, <a routerLink="/admin/users">create a dedicated account</a> to upload your videos.
|
Instead, <a routerLink="/admin/users">create a dedicated account</a> to upload your videos.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<my-user-quota *ngIf="!isInSecondStep()" [user]="user" [userInformationLoaded]="userInformationLoaded"></my-user-quota>
|
||||||
|
|
||||||
<div class="title-page title-page-single" *ngIf="isInSecondStep()">
|
<div class="title-page title-page-single" *ngIf="isInSecondStep()">
|
||||||
<ng-container *ngIf="secondStepType === 'import-url' || secondStepType === 'import-torrent'" i18n>Import {{ videoName }}</ng-container>
|
<ng-container *ngIf="secondStepType === 'import-url' || secondStepType === 'import-torrent'" i18n>Import {{ videoName }}</ng-container>
|
||||||
<ng-container *ngIf="secondStepType === 'upload'" i18n>Upload {{ videoName }}</ng-container>
|
<ng-container *ngIf="secondStepType === 'upload'" i18n>Upload {{ videoName }}</ng-container>
|
||||||
|
|
|
@ -7,7 +7,7 @@ $border-color: #EAEAEA;
|
||||||
$nav-link-height: 40px;
|
$nav-link-height: 40px;
|
||||||
|
|
||||||
.margin-content {
|
.margin-content {
|
||||||
padding-top: 50px;
|
padding-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert {
|
.alert {
|
||||||
|
@ -16,7 +16,7 @@ $nav-link-height: 40px;
|
||||||
|
|
||||||
::ng-deep .video-add-nav {
|
::ng-deep .video-add-nav {
|
||||||
border-bottom: $border-width $border-type $border-color;
|
border-bottom: $border-width $border-type $border-color;
|
||||||
margin: 50px 0 0 0 !important;
|
margin: 20px 0 0 0 !important;
|
||||||
|
|
||||||
&.hide-nav {
|
&.hide-nav {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
|
@ -64,7 +64,7 @@ $nav-link-height: 40px;
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
padding-top: 20px;
|
||||||
|
|
||||||
&.dragover {
|
&.dragover {
|
||||||
border: 3px dashed pvar(--mainColor);
|
border: 3px dashed pvar(--mainColor);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Component, HostListener, OnInit, ViewChild } from '@angular/core'
|
import { Component, HostListener, OnInit, ViewChild } from '@angular/core'
|
||||||
import { AuthService, CanComponentDeactivate, ServerService } from '@app/core'
|
import { AuthService, CanComponentDeactivate, ServerService, User } from '@app/core'
|
||||||
import { ServerConfig } from '@shared/models'
|
import { ServerConfig } from '@shared/models'
|
||||||
import { VideoImportTorrentComponent } from './video-add-components/video-import-torrent.component'
|
import { VideoImportTorrentComponent } from './video-add-components/video-import-torrent.component'
|
||||||
import { VideoImportUrlComponent } from './video-add-components/video-import-url.component'
|
import { VideoImportUrlComponent } from './video-add-components/video-import-url.component'
|
||||||
|
@ -15,6 +15,8 @@ export class VideoAddComponent implements OnInit, CanComponentDeactivate {
|
||||||
@ViewChild('videoImportUrl') videoImportUrl: VideoImportUrlComponent
|
@ViewChild('videoImportUrl') videoImportUrl: VideoImportUrlComponent
|
||||||
@ViewChild('videoImportTorrent') videoImportTorrent: VideoImportTorrentComponent
|
@ViewChild('videoImportTorrent') videoImportTorrent: VideoImportTorrentComponent
|
||||||
|
|
||||||
|
user: User = null
|
||||||
|
|
||||||
secondStepType: 'upload' | 'import-url' | 'import-torrent'
|
secondStepType: 'upload' | 'import-url' | 'import-torrent'
|
||||||
videoName: string
|
videoName: string
|
||||||
serverConfig: ServerConfig
|
serverConfig: ServerConfig
|
||||||
|
@ -24,7 +26,13 @@ export class VideoAddComponent implements OnInit, CanComponentDeactivate {
|
||||||
private serverService: ServerService
|
private serverService: ServerService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
get userInformationLoaded () {
|
||||||
|
return this.auth.userInformationLoaded
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
|
this.user = this.auth.getUser()
|
||||||
|
|
||||||
this.serverConfig = this.serverService.getTmpConfig()
|
this.serverConfig = this.serverService.getTmpConfig()
|
||||||
|
|
||||||
this.serverService.getConfig()
|
this.serverService.getConfig()
|
||||||
|
|
|
@ -26,7 +26,7 @@ import { DateToggleComponent } from './date'
|
||||||
import { FeedComponent } from './feeds'
|
import { FeedComponent } from './feeds'
|
||||||
import { LoaderComponent, SmallLoaderComponent } from './loaders'
|
import { LoaderComponent, SmallLoaderComponent } from './loaders'
|
||||||
import { HelpComponent, ListOverflowComponent, TopMenuDropdownComponent } from './misc'
|
import { HelpComponent, ListOverflowComponent, TopMenuDropdownComponent } from './misc'
|
||||||
import { UserHistoryService, UserNotificationsComponent, UserNotificationService } from './users'
|
import { UserHistoryService, UserNotificationsComponent, UserNotificationService, UserQuotaComponent } from './users'
|
||||||
import { RedundancyService, VideoImportService, VideoOwnershipService, VideoService } from './video'
|
import { RedundancyService, VideoImportService, VideoOwnershipService, VideoService } from './video'
|
||||||
import { VideoCaptionService } from './video-caption'
|
import { VideoCaptionService } from './video-caption'
|
||||||
import { VideoChannelService } from './video-channel'
|
import { VideoChannelService } from './video-channel'
|
||||||
|
@ -83,6 +83,7 @@ import { AUTH_INTERCEPTOR_PROVIDER } from './auth'
|
||||||
ListOverflowComponent,
|
ListOverflowComponent,
|
||||||
TopMenuDropdownComponent,
|
TopMenuDropdownComponent,
|
||||||
|
|
||||||
|
UserQuotaComponent,
|
||||||
UserNotificationsComponent
|
UserNotificationsComponent
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -132,6 +133,7 @@ import { AUTH_INTERCEPTOR_PROVIDER } from './auth'
|
||||||
ListOverflowComponent,
|
ListOverflowComponent,
|
||||||
TopMenuDropdownComponent,
|
TopMenuDropdownComponent,
|
||||||
|
|
||||||
|
UserQuotaComponent,
|
||||||
UserNotificationsComponent
|
UserNotificationsComponent
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
|
@ -2,3 +2,4 @@ export * from './user-history.service'
|
||||||
export * from './user-notification.model'
|
export * from './user-notification.model'
|
||||||
export * from './user-notification.service'
|
export * from './user-notification.service'
|
||||||
export * from './user-notifications.component'
|
export * from './user-notifications.component'
|
||||||
|
export * from './user-quota.component'
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
<div class="user-quota mb-3">
|
||||||
|
<div>
|
||||||
|
<strong class="user-quota-title" tabindex="0" i18n>Total video quota</strong>
|
||||||
|
<div class="progress" tabindex="0" [ngbTooltip]="titleVideoQuota()">
|
||||||
|
<div class="progress-bar" tabindex="0" role="progressbar" [style]="{ width: userVideoQuotaPercentage + '%' }"
|
||||||
|
[attr.aria-valuenow]="userVideoQuotaUsed" aria-valuemin="0" [attr.aria-valuemax]="user.videoQuota">
|
||||||
|
{{ userVideoQuotaUsed | bytes: 0 }}</div>
|
||||||
|
<span class="ml-auto mr-2">{{ userVideoQuota }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="hasDailyQuota()" class="mt-3">
|
||||||
|
<strong class="user-quota-title" tabindex="0" i18n>Daily video quota</strong>
|
||||||
|
<div class="progress" tabindex="0" [ngbTooltip]="titleVideoQuotaDaily()">
|
||||||
|
<div class="progress-bar secondary" role="progressbar" [style]="{ width: userVideoQuotaDailyPercentage + '%' }"
|
||||||
|
[attr.aria-valuenow]="userVideoQuotaUsedDaily" aria-valuemin="0" [attr.aria-valuemax]="user.videoQuotaDaily">
|
||||||
|
{{ userVideoQuotaUsedDaily | bytes: 0 }}</div>
|
||||||
|
<span class="ml-auto mr-2">{{ userVideoQuotaDaily }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,31 @@
|
||||||
|
@import '_variables';
|
||||||
|
@import '_mixins';
|
||||||
|
|
||||||
|
.user-quota {
|
||||||
|
font-size: 15px;
|
||||||
|
margin-top: 20px;
|
||||||
|
|
||||||
|
label {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&, .progress {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-quota-title, .progress {
|
||||||
|
@include disable-outline;
|
||||||
|
@include button-focus(pvar(--mainColorLightest));
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
@include progressbar;
|
||||||
|
|
||||||
|
height: 2rem;
|
||||||
|
|
||||||
|
span {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
import { Subject } from 'rxjs'
|
||||||
|
import { BytesPipe } from 'ngx-pipes'
|
||||||
|
import { Component, Input, OnInit } from '@angular/core'
|
||||||
|
import { User, UserService } from '@app/core'
|
||||||
|
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-user-quota',
|
||||||
|
templateUrl: './user-quota.component.html',
|
||||||
|
styleUrls: ['./user-quota.component.scss']
|
||||||
|
})
|
||||||
|
|
||||||
|
export class UserQuotaComponent implements OnInit {
|
||||||
|
@Input() user: User = null
|
||||||
|
@Input() userInformationLoaded: Subject<any>
|
||||||
|
|
||||||
|
userVideoQuota = '0'
|
||||||
|
userVideoQuotaUsed = 0
|
||||||
|
userVideoQuotaPercentage = 15
|
||||||
|
|
||||||
|
userVideoQuotaDaily = '0'
|
||||||
|
userVideoQuotaUsedDaily = 0
|
||||||
|
userVideoQuotaDailyPercentage = 15
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private userService: UserService,
|
||||||
|
private i18n: I18n
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit () {
|
||||||
|
this.userInformationLoaded.subscribe(
|
||||||
|
() => {
|
||||||
|
if (this.user.videoQuota !== -1) {
|
||||||
|
this.userVideoQuota = new BytesPipe().transform(this.user.videoQuota, 0).toString()
|
||||||
|
} else {
|
||||||
|
this.userVideoQuota = this.i18n('Unlimited')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.user.videoQuotaDaily !== -1) {
|
||||||
|
this.userVideoQuotaDaily = new BytesPipe().transform(this.user.videoQuotaDaily, 0).toString()
|
||||||
|
} else {
|
||||||
|
this.userVideoQuotaDaily = this.i18n('Unlimited')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
this.userService.getMyVideoQuotaUsed()
|
||||||
|
.subscribe(data => {
|
||||||
|
this.userVideoQuotaUsed = data.videoQuotaUsed
|
||||||
|
this.userVideoQuotaPercentage = this.userVideoQuotaUsed * 100 / this.user.videoQuota
|
||||||
|
|
||||||
|
this.userVideoQuotaUsedDaily = data.videoQuotaUsedDaily
|
||||||
|
this.userVideoQuotaDailyPercentage = this.userVideoQuotaUsedDaily * 100 / this.user.videoQuotaDaily
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
hasDailyQuota () {
|
||||||
|
return this.user.videoQuotaDaily !== -1
|
||||||
|
}
|
||||||
|
|
||||||
|
titleVideoQuota () {
|
||||||
|
return `${new BytesPipe().transform(this.userVideoQuotaUsed, 0).toString()} / ${this.userVideoQuota}`
|
||||||
|
}
|
||||||
|
|
||||||
|
titleVideoQuotaDaily () {
|
||||||
|
return `${new BytesPipe().transform(this.userVideoQuotaUsedDaily, 0).toString()} / ${this.userVideoQuotaDaily}`
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue