Improve video upload error handling

This commit is contained in:
Chocobozzz 2018-11-16 10:05:25 +01:00
parent fe05c3acbd
commit 7373507fa8
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
14 changed files with 82 additions and 18 deletions

View File

@ -124,6 +124,10 @@ function sortBy (obj: any[], key1: string, key2?: string) {
}) })
} }
function scrollToTop () {
window.scroll(0, 0)
}
export { export {
sortBy, sortBy,
durationToString, durationToString,
@ -135,5 +139,6 @@ export {
immutableAssign, immutableAssign,
objectToFormData, objectToFormData,
lineFeedToHtml, lineFeedToHtml,
removeElementFromArray removeElementFromArray,
scrollToTop
} }

View File

@ -45,7 +45,12 @@
</div> </div>
</div> </div>
<div *ngIf="hasImportedVideo" class="alert alert-info" i18n> <div *ngIf="error" class="alert alert-danger">
<div i18n>Sorry, but something went wrong</div>
{{ error }}
</div>
<div *ngIf="hasImportedVideo && !error" class="alert alert-info" i18n>
Congratulations, the video will be imported with BitTorrent! You can already add information about this video. Congratulations, the video will be imported with BitTorrent! You can already add information about this video.
</div> </div>

View File

@ -7,6 +7,14 @@ $width-size: 190px;
@include peertube-select-container($width-size); @include peertube-select-container($width-size);
} }
.alert.alert-danger {
text-align: center;
& > div {
font-weight: $font-semibold;
}
}
.import-video-torrent { .import-video-torrent {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@ -12,6 +12,7 @@ import { VideoEdit } from '@app/shared/video/video-edit.model'
import { FormValidatorService } from '@app/shared' import { FormValidatorService } from '@app/shared'
import { VideoCaptionService } from '@app/shared/video-caption' import { VideoCaptionService } from '@app/shared/video-caption'
import { VideoImportService } from '@app/shared/video-import' import { VideoImportService } from '@app/shared/video-import'
import { scrollToTop } from '@app/shared/misc/utils'
@Component({ @Component({
selector: 'my-video-import-torrent', selector: 'my-video-import-torrent',
@ -23,9 +24,9 @@ import { VideoImportService } from '@app/shared/video-import'
}) })
export class VideoImportTorrentComponent extends VideoSend implements OnInit, CanComponentDeactivate { export class VideoImportTorrentComponent extends VideoSend implements OnInit, CanComponentDeactivate {
@Output() firstStepDone = new EventEmitter<string>() @Output() firstStepDone = new EventEmitter<string>()
@Output() firstStepError = new EventEmitter<void>()
@ViewChild('torrentfileInput') torrentfileInput: ElementRef<HTMLInputElement> @ViewChild('torrentfileInput') torrentfileInput: ElementRef<HTMLInputElement>
videoFileName: string
magnetUri = '' magnetUri = ''
isImportingVideo = false isImportingVideo = false
@ -33,6 +34,7 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Ca
isUpdatingVideo = false isUpdatingVideo = false
video: VideoEdit video: VideoEdit
error: string
protected readonly DEFAULT_VIDEO_PRIVACY = VideoPrivacy.PUBLIC protected readonly DEFAULT_VIDEO_PRIVACY = VideoPrivacy.PUBLIC
@ -104,6 +106,7 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Ca
err => { err => {
this.loadingBar.complete() this.loadingBar.complete()
this.isImportingVideo = false this.isImportingVideo = false
this.firstStepError.emit()
this.notificationsService.error(this.i18n('Error'), err.message) this.notificationsService.error(this.i18n('Error'), err.message)
} }
) )
@ -129,8 +132,8 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Ca
}, },
err => { err => {
this.isUpdatingVideo = false this.error = err.message
this.notificationsService.error(this.i18n('Error'), err.message) scrollToTop()
console.error(err) console.error(err)
} }
) )

View File

@ -37,7 +37,13 @@
</div> </div>
</div> </div>
<div *ngIf="hasImportedVideo" class="alert alert-info" i18n>
<div *ngIf="error" class="alert alert-danger">
<div i18n>Sorry, but something went wrong</div>
{{ error }}
</div>
<div *ngIf="!error && hasImportedVideo" class="alert alert-info" i18n>
Congratulations, the video behind {{ targetUrl }} will be imported! You can already add information about this video. Congratulations, the video behind {{ targetUrl }} will be imported! You can already add information about this video.
</div> </div>

View File

@ -7,6 +7,14 @@ $width-size: 190px;
@include peertube-select-container($width-size); @include peertube-select-container($width-size);
} }
.alert.alert-danger {
text-align: center;
& > div {
font-weight: $font-semibold;
}
}
.import-video-url { .import-video-url {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@ -12,6 +12,7 @@ import { VideoEdit } from '@app/shared/video/video-edit.model'
import { FormValidatorService } from '@app/shared' import { FormValidatorService } from '@app/shared'
import { VideoCaptionService } from '@app/shared/video-caption' import { VideoCaptionService } from '@app/shared/video-caption'
import { VideoImportService } from '@app/shared/video-import' import { VideoImportService } from '@app/shared/video-import'
import { scrollToTop } from '@app/shared/misc/utils'
@Component({ @Component({
selector: 'my-video-import-url', selector: 'my-video-import-url',
@ -23,15 +24,16 @@ import { VideoImportService } from '@app/shared/video-import'
}) })
export class VideoImportUrlComponent extends VideoSend implements OnInit, CanComponentDeactivate { export class VideoImportUrlComponent extends VideoSend implements OnInit, CanComponentDeactivate {
@Output() firstStepDone = new EventEmitter<string>() @Output() firstStepDone = new EventEmitter<string>()
@Output() firstStepError = new EventEmitter<void>()
targetUrl = '' targetUrl = ''
videoFileName: string
isImportingVideo = false isImportingVideo = false
hasImportedVideo = false hasImportedVideo = false
isUpdatingVideo = false isUpdatingVideo = false
video: VideoEdit video: VideoEdit
error: string
protected readonly DEFAULT_VIDEO_PRIVACY = VideoPrivacy.PUBLIC protected readonly DEFAULT_VIDEO_PRIVACY = VideoPrivacy.PUBLIC
@ -96,6 +98,7 @@ export class VideoImportUrlComponent extends VideoSend implements OnInit, CanCom
err => { err => {
this.loadingBar.complete() this.loadingBar.complete()
this.isImportingVideo = false this.isImportingVideo = false
this.firstStepError.emit()
this.notificationsService.error(this.i18n('Error'), err.message) this.notificationsService.error(this.i18n('Error'), err.message)
} }
) )
@ -121,8 +124,8 @@ export class VideoImportUrlComponent extends VideoSend implements OnInit, CanCom
}, },
err => { err => {
this.isUpdatingVideo = false this.error = err.message
this.notificationsService.error(this.i18n('Error'), err.message) scrollToTop()
console.error(err) console.error(err)
} }
) )

View File

@ -21,6 +21,7 @@ export abstract class VideoSend extends FormReactive implements OnInit {
firstStepChannelId = 0 firstStepChannelId = 0
abstract firstStepDone: EventEmitter<string> abstract firstStepDone: EventEmitter<string>
abstract firstStepError: EventEmitter<void>
protected abstract readonly DEFAULT_VIDEO_PRIVACY: VideoPrivacy protected abstract readonly DEFAULT_VIDEO_PRIVACY: VideoPrivacy
protected loadingBar: LoadingBarService protected loadingBar: LoadingBarService

View File

@ -29,7 +29,7 @@
</div> </div>
</div> </div>
<div *ngIf="isUploadingVideo" class="upload-progress-cancel"> <div *ngIf="isUploadingVideo && !error" class="upload-progress-cancel">
<p-progressBar <p-progressBar
[value]="videoUploadPercents" [value]="videoUploadPercents"
[ngClass]="{ processing: videoUploadPercents === 100 && videoUploaded === false }" [ngClass]="{ processing: videoUploadPercents === 100 && videoUploaded === false }"
@ -37,6 +37,11 @@
<input *ngIf="videoUploaded === false" type="button" value="Cancel" (click)="cancelUpload()" /> <input *ngIf="videoUploaded === false" type="button" value="Cancel" (click)="cancelUpload()" />
</div> </div>
<div *ngIf="error" class="alert alert-danger">
<div i18n>Sorry, but something went wrong</div>
{{ error }}
</div>
<!-- Hidden because we want to load the component --> <!-- Hidden because we want to load the component -->
<form [hidden]="!isUploadingVideo" novalidate [formGroup]="form"> <form [hidden]="!isUploadingVideo" novalidate [formGroup]="form">
<my-video-edit <my-video-edit

View File

@ -5,6 +5,14 @@
@include peertube-select-container(190px); @include peertube-select-container(190px);
} }
.alert.alert-danger {
text-align: center;
& > div {
font-weight: $font-semibold;
}
}
.upload-video { .upload-video {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@ -14,6 +14,7 @@ import { VideoSend } from '@app/videos/+video-edit/video-add-components/video-se
import { CanComponentDeactivate } from '@app/shared/guards/can-deactivate-guard.service' import { CanComponentDeactivate } from '@app/shared/guards/can-deactivate-guard.service'
import { FormValidatorService, UserService } from '@app/shared' import { FormValidatorService, UserService } from '@app/shared'
import { VideoCaptionService } from '@app/shared/video-caption' import { VideoCaptionService } from '@app/shared/video-caption'
import { scrollToTop } from '@app/shared/misc/utils'
@Component({ @Component({
selector: 'my-video-upload', selector: 'my-video-upload',
@ -25,6 +26,7 @@ import { VideoCaptionService } from '@app/shared/video-caption'
}) })
export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy, CanComponentDeactivate { export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy, CanComponentDeactivate {
@Output() firstStepDone = new EventEmitter<string>() @Output() firstStepDone = new EventEmitter<string>()
@Output() firstStepError = new EventEmitter<void>()
@ViewChild('videofileInput') videofileInput: ElementRef<HTMLInputElement> @ViewChild('videofileInput') videofileInput: ElementRef<HTMLInputElement>
// So that it can be accessed in the template // So that it can be accessed in the template
@ -43,6 +45,8 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
uuid: '' uuid: ''
} }
error: string
protected readonly DEFAULT_VIDEO_PRIVACY = VideoPrivacy.PUBLIC protected readonly DEFAULT_VIDEO_PRIVACY = VideoPrivacy.PUBLIC
constructor ( constructor (
@ -201,6 +205,7 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
this.isUploadingVideo = false this.isUploadingVideo = false
this.videoUploadPercents = 0 this.videoUploadPercents = 0
this.videoUploadObservable = null this.videoUploadObservable = null
this.firstStepError.emit()
this.notificationsService.error(this.i18n('Error'), err.message) this.notificationsService.error(this.i18n('Error'), err.message)
} }
) )
@ -235,8 +240,8 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
}, },
err => { err => {
this.isUpdatingVideo = false this.error = err.message
this.notificationsService.error(this.i18n('Error'), err.message) scrollToTop()
console.error(err) console.error(err)
} }
) )

View File

@ -6,24 +6,24 @@
<ngb-tabset class="video-add-tabset root-tabset bootstrap" [ngClass]="{ 'hide-nav': secondStepType !== undefined }"> <ngb-tabset class="video-add-tabset root-tabset bootstrap" [ngClass]="{ 'hide-nav': secondStepType !== undefined }">
<ngb-tab i18n-title title=""> <ngb-tab>
<ng-template ngbTabTitle><span i18n>Upload a file</span></ng-template> <ng-template ngbTabTitle><span i18n>Upload a file</span></ng-template>
<ng-template ngbTabContent> <ng-template ngbTabContent>
<my-video-upload #videoUpload (firstStepDone)="onFirstStepDone('upload', $event)"></my-video-upload> <my-video-upload #videoUpload (firstStepDone)="onFirstStepDone('upload', $event)" (firstStepError)="onError()"></my-video-upload>
</ng-template> </ng-template>
</ngb-tab> </ngb-tab>
<ngb-tab *ngIf="isVideoImportHttpEnabled()"> <ngb-tab *ngIf="isVideoImportHttpEnabled()">
<ng-template ngbTabTitle><span i18n>Import with URL</span></ng-template> <ng-template ngbTabTitle><span i18n>Import with URL</span></ng-template>
<ng-template ngbTabContent> <ng-template ngbTabContent>
<my-video-import-url #videoImportUrl (firstStepDone)="onFirstStepDone('import-url', $event)"></my-video-import-url> <my-video-import-url #videoImportUrl (firstStepDone)="onFirstStepDone('import-url', $event)" (firstStepError)="onError()"></my-video-import-url>
</ng-template> </ng-template>
</ngb-tab> </ngb-tab>
<ngb-tab *ngIf="isVideoImportTorrentEnabled()"> <ngb-tab *ngIf="isVideoImportTorrentEnabled()">
<ng-template ngbTabTitle><span i18n>Import with torrent</span></ng-template> <ng-template ngbTabTitle><span i18n>Import with torrent</span></ng-template>
<ng-template ngbTabContent> <ng-template ngbTabContent>
<my-video-import-torrent #videoImportTorrent (firstStepDone)="onFirstStepDone('import-torrent', $event)"></my-video-import-torrent> <my-video-import-torrent #videoImportTorrent (firstStepDone)="onFirstStepDone('import-torrent', $event)" (firstStepError)="onError()"></my-video-import-torrent>
</ng-template> </ng-template>
</ngb-tab> </ngb-tab>
</ngb-tabset> </ngb-tabset>

View File

@ -27,6 +27,11 @@ export class VideoAddComponent implements CanComponentDeactivate {
this.videoName = videoName this.videoName = videoName
} }
onError () {
this.videoName = undefined
this.secondStepType = undefined
}
canDeactivate () { canDeactivate () {
if (this.secondStepType === 'upload') return this.videoUpload.canDeactivate() if (this.secondStepType === 'upload') return this.videoUpload.canDeactivate()
if (this.secondStepType === 'import-url') return this.videoImportUrl.canDeactivate() if (this.secondStepType === 'import-url') return this.videoImportUrl.canDeactivate()

View File

@ -393,6 +393,8 @@ export {
function areErrorsInScheduleUpdate (req: express.Request, res: express.Response) { function areErrorsInScheduleUpdate (req: express.Request, res: express.Response) {
if (req.body.scheduleUpdate) { if (req.body.scheduleUpdate) {
if (!req.body.scheduleUpdate.updateAt) { if (!req.body.scheduleUpdate.updateAt) {
logger.warn('Invalid parameters: scheduleUpdate.updateAt is mandatory.')
res.status(400) res.status(400)
.json({ error: 'Schedule update at is mandatory.' }) .json({ error: 'Schedule update at is mandatory.' })