Improve video upload error handling
This commit is contained in:
parent
fe05c3acbd
commit
7373507fa8
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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.' })
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue