diff options
6 files changed, 138 insertions, 33 deletions
diff --git a/client/src/app/+my-account/my-account-ownership/my-account-accept-ownership/my-account-accept-ownership.component.html b/client/src/app/+my-account/my-account-ownership/my-account-accept-ownership/my-account-accept-ownership.component.html index 222da9542..def1cbab6 100644 --- a/client/src/app/+my-account/my-account-ownership/my-account-accept-ownership/my-account-accept-ownership.component.html +++ b/client/src/app/+my-account/my-account-ownership/my-account-accept-ownership/my-account-accept-ownership.component.html | |||
@@ -7,27 +7,27 @@ | |||
7 | 7 | ||
8 | <div class="modal-body" [formGroup]="form"> | 8 | <div class="modal-body" [formGroup]="form"> |
9 | <div class="form-group"> | 9 | <div class="form-group"> |
10 | <label i18n for="channel">Select the target channel</label> | 10 | <label i18n for="channel">Select a channel to receive the video</label> |
11 | <select formControlName="channel" id="channel" class="peertube-select-container"> | 11 | <div class="peertube-select-container"> |
12 | <option></option> | 12 | <select formControlName="channel" id="channel" class="form-control"> |
13 | <option *ngFor="let channel of videoChannels" [value]="channel.id">{{ channel.displayName }} | 13 | <option i18n value="undefined" disabled>Channel that will receive the video</option> |
14 | </option> | 14 | <option *ngFor="let channel of videoChannels" [value]="channel.id">{{ channel.displayName }} |
15 | </select> | 15 | </option> |
16 | <div *ngIf="formErrors.channel" class="form-error"> | 16 | </select> |
17 | {{ formErrors.channel }} | ||
18 | </div> | 17 | </div> |
18 | <div *ngIf="formErrors.channel" class="form-error">{{ formErrors.channel }}</div> | ||
19 | </div> | 19 | </div> |
20 | </div> | 20 | </div> |
21 | 21 | ||
22 | <div class="modal-footer inputs"> | 22 | <div class="modal-footer inputs"> |
23 | <div class="form-group inputs"> | 23 | <div class="inputs"> |
24 | <input | 24 | <input |
25 | type="button" role="button" i18n-value value="Cancel" class="action-button action-button-cancel" | 25 | type="button" role="button" i18n-value value="Cancel" class="action-button action-button-cancel" |
26 | (click)="dismiss()" (key.enter)="dismiss()" | 26 | (click)="dismiss()" (key.enter)="dismiss()" |
27 | > | 27 | > |
28 | 28 | ||
29 | <input | 29 | <input |
30 | type="submit" i18n-value value="Submit" class="action-button-submit" | 30 | type="submit" i18n-value value="Accept" class="action-button-submit" |
31 | [disabled]="!form.valid" | 31 | [disabled]="!form.valid" |
32 | (click)="close()" | 32 | (click)="close()" |
33 | > | 33 | > |
diff --git a/client/src/app/+my-account/my-account-ownership/my-account-accept-ownership/my-account-accept-ownership.component.scss b/client/src/app/+my-account/my-account-ownership/my-account-accept-ownership/my-account-accept-ownership.component.scss index ad6117413..c7357f62d 100644 --- a/client/src/app/+my-account/my-account-ownership/my-account-accept-ownership/my-account-accept-ownership.component.scss +++ b/client/src/app/+my-account/my-account-ownership/my-account-accept-ownership/my-account-accept-ownership.component.scss | |||
@@ -5,6 +5,10 @@ select { | |||
5 | display: block; | 5 | display: block; |
6 | } | 6 | } |
7 | 7 | ||
8 | .peertube-select-container { | ||
9 | @include peertube-select-container(350px); | ||
10 | } | ||
11 | |||
8 | .form-group { | 12 | .form-group { |
9 | margin: 20px 0; | 13 | margin: 20px 0; |
10 | } \ No newline at end of file | 14 | } \ No newline at end of file |
diff --git a/client/src/app/+my-account/my-account-ownership/my-account-ownership.component.html b/client/src/app/+my-account/my-account-ownership/my-account-ownership.component.html index 14ae497d9..090ec7b44 100644 --- a/client/src/app/+my-account/my-account-ownership/my-account-ownership.component.html +++ b/client/src/app/+my-account/my-account-ownership/my-account-ownership.component.html | |||
@@ -11,31 +11,53 @@ | |||
11 | > | 11 | > |
12 | <ng-template pTemplate="header"> | 12 | <ng-template pTemplate="header"> |
13 | <tr> | 13 | <tr> |
14 | <th i18n>Initiator</th> | 14 | <th style="width: 35%;" i18n>Initiator</th> |
15 | <th i18n>Video</th> | 15 | <th style="width: 65%;" i18n>Video</th> |
16 | <th i18n pSortableColumn="createdAt"> | 16 | <th style="width: 150px;" i18n pSortableColumn="createdAt"> |
17 | Created | 17 | Created |
18 | <p-sortIcon field="createdAt"></p-sortIcon> | 18 | <p-sortIcon field="createdAt"></p-sortIcon> |
19 | </th> | 19 | </th> |
20 | <th i18n>Status</th> | 20 | <th style="width: 100px;" i18n>Status</th> |
21 | <th i18n>Action</th> | 21 | <th style="width: 130px;" i18n>Action</th> |
22 | </tr> | 22 | </tr> |
23 | </ng-template> | 23 | </ng-template> |
24 | 24 | ||
25 | <ng-template pTemplate="body" let-videoChangeOwnership> | 25 | <ng-template pTemplate="body" let-videoChangeOwnership> |
26 | <tr> | 26 | <tr> |
27 | <td> | 27 | <td> |
28 | <a [href]="videoChangeOwnership.initiatorAccount.url" i18n-title title="Account page" | 28 | <a [href]="videoChangeOwnership.initiatorAccount.url" i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer"> |
29 | target="_blank" rel="noopener noreferrer"> | 29 | <div class="chip two-lines"> |
30 | {{ createByString(videoChangeOwnership.initiatorAccount) }} | 30 | <img |
31 | class="avatar" | ||
32 | [src]="videoChangeOwnership.initiatorAccount.avatar?.path" | ||
33 | (error)="switchToDefaultAvatar($event)" | ||
34 | alt="Avatar" | ||
35 | > | ||
36 | <div> | ||
37 | {{ videoChangeOwnership.initiatorAccount.displayName }} | ||
38 | <span class="text-muted">{{ videoChangeOwnership.initiatorAccount.nameWithHost }}</span> | ||
39 | </div> | ||
40 | </div> | ||
31 | </a> | 41 | </a> |
32 | </td> | 42 | </td> |
43 | |||
33 | <td> | 44 | <td> |
34 | <a [href]="videoChangeOwnership.video.url" i18n-title title="Video page" target="_blank" rel="noopener noreferrer"> | 45 | <a [href]="videoChangeOwnership.video.url" class="video-table-video-link" [title]="videoChangeOwnership.video.name" target="_blank" rel="noopener noreferrer"> |
35 | {{ videoChangeOwnership.video.name }} | 46 | <div class="video-table-video"> |
47 | <div class="video-table-video-image"> | ||
48 | <img [src]="videoChangeOwnership.video.thumbnailPath"> | ||
49 | </div> | ||
50 | <div class="video-table-video-text"> | ||
51 | <div> | ||
52 | {{ videoChangeOwnership.video.name }} | ||
53 | </div> | ||
54 | <div class="text-muted">by {{ videoChangeOwnership.video.channel?.displayName }} </div> | ||
55 | </div> | ||
56 | </div> | ||
36 | </a> | 57 | </a> |
37 | </td> | 58 | </td> |
38 | <td>{{ videoChangeOwnership.createdAt }}</td> | 59 | |
60 | <td>{{ videoChangeOwnership.createdAt | date: 'short' }}</td> | ||
39 | <td i18n>{{ videoChangeOwnership.status }}</td> | 61 | <td i18n>{{ videoChangeOwnership.status }}</td> |
40 | <td class="action-cell"> | 62 | <td class="action-cell"> |
41 | <ng-container *ngIf="videoChangeOwnership.status === 'WAITING'"> | 63 | <ng-container *ngIf="videoChangeOwnership.status === 'WAITING'"> |
@@ -45,6 +67,16 @@ | |||
45 | </td> | 67 | </td> |
46 | </tr> | 68 | </tr> |
47 | </ng-template> | 69 | </ng-template> |
70 | |||
71 | <ng-template pTemplate="emptymessage"> | ||
72 | <tr> | ||
73 | <td colspan="6"> | ||
74 | <div class="no-results"> | ||
75 | <ng-container i18n>No ownership change request found.</ng-container> | ||
76 | </div> | ||
77 | </td> | ||
78 | </tr> | ||
79 | </ng-template> | ||
48 | </p-table> | 80 | </p-table> |
49 | 81 | ||
50 | <my-account-accept-ownership #myAccountAcceptOwnershipComponent (accepted)="accepted()"></my-account-accept-ownership> | 82 | <my-account-accept-ownership #myAccountAcceptOwnershipComponent (accepted)="accepted()"></my-account-accept-ownership> |
diff --git a/client/src/app/+my-account/my-account-ownership/my-account-ownership.component.scss b/client/src/app/+my-account/my-account-ownership/my-account-ownership.component.scss new file mode 100644 index 000000000..c04e26374 --- /dev/null +++ b/client/src/app/+my-account/my-account-ownership/my-account-ownership.component.scss | |||
@@ -0,0 +1,67 @@ | |||
1 | @import 'miniature'; | ||
2 | @import 'mixins'; | ||
3 | |||
4 | .chip { | ||
5 | @include chip; | ||
6 | } | ||
7 | |||
8 | .video-table-video { | ||
9 | display: inline-flex; | ||
10 | |||
11 | .video-table-video-image { | ||
12 | @include miniature-thumbnail; | ||
13 | |||
14 | $image-height: 45px; | ||
15 | |||
16 | height: $image-height; | ||
17 | width: #{(16/9) * $image-height}; | ||
18 | margin-right: 0.5rem; | ||
19 | border-radius: 2px; | ||
20 | border: none; | ||
21 | background: transparent; | ||
22 | display: inline-flex; | ||
23 | justify-content: center; | ||
24 | align-items: center; | ||
25 | position: relative; | ||
26 | |||
27 | img { | ||
28 | height: 100%; | ||
29 | width: 100%; | ||
30 | border-radius: 2px; | ||
31 | } | ||
32 | |||
33 | span { | ||
34 | color: pvar(--inputPlaceholderColor); | ||
35 | } | ||
36 | |||
37 | .video-table-video-image-label { | ||
38 | @include static-thumbnail-overlay; | ||
39 | position: absolute; | ||
40 | border-radius: 3px; | ||
41 | font-size: 10px; | ||
42 | padding: 0 3px; | ||
43 | line-height: 1.3; | ||
44 | bottom: 2px; | ||
45 | right: 2px; | ||
46 | } | ||
47 | } | ||
48 | |||
49 | .video-table-video-text { | ||
50 | display: inline-flex; | ||
51 | flex-direction: column; | ||
52 | justify-content: center; | ||
53 | font-size: 90%; | ||
54 | color: pvar(--mainForegroundColor); | ||
55 | line-height: 1rem; | ||
56 | |||
57 | div .glyphicon { | ||
58 | font-size: 80%; | ||
59 | color: gray; | ||
60 | margin-left: 0.1rem; | ||
61 | } | ||
62 | |||
63 | div + div { | ||
64 | font-size: 80%; | ||
65 | } | ||
66 | } | ||
67 | } | ||
diff --git a/client/src/app/+my-account/my-account-ownership/my-account-ownership.component.ts b/client/src/app/+my-account/my-account-ownership/my-account-ownership.component.ts index 5167732c2..98360dfb3 100644 --- a/client/src/app/+my-account/my-account-ownership/my-account-ownership.component.ts +++ b/client/src/app/+my-account/my-account-ownership/my-account-ownership.component.ts | |||
@@ -1,13 +1,15 @@ | |||
1 | import { SortMeta } from 'primeng/api' | 1 | import { SortMeta } from 'primeng/api' |
2 | import { Component, OnInit, ViewChild } from '@angular/core' | 2 | import { Component, OnInit, ViewChild } from '@angular/core' |
3 | import { Notifier, RestPagination, RestTable } from '@app/core' | 3 | import { Notifier, RestPagination, RestTable } from '@app/core' |
4 | import { Account, VideoOwnershipService } from '@app/shared/shared-main' | 4 | import { VideoOwnershipService, Actor, Video, Account } from '@app/shared/shared-main' |
5 | import { VideoChangeOwnership } from '@shared/models' | 5 | import { VideoChangeOwnership } from '@shared/models' |
6 | import { MyAccountAcceptOwnershipComponent } from './my-account-accept-ownership/my-account-accept-ownership.component' | 6 | import { MyAccountAcceptOwnershipComponent } from './my-account-accept-ownership/my-account-accept-ownership.component' |
7 | import { getAbsoluteAPIUrl } from '@app/helpers' | ||
7 | 8 | ||
8 | @Component({ | 9 | @Component({ |
9 | selector: 'my-account-ownership', | 10 | selector: 'my-account-ownership', |
10 | templateUrl: './my-account-ownership.component.html' | 11 | templateUrl: './my-account-ownership.component.html', |
12 | styleUrls: [ './my-account-ownership.component.scss' ] | ||
11 | }) | 13 | }) |
12 | export class MyAccountOwnershipComponent extends RestTable implements OnInit { | 14 | export class MyAccountOwnershipComponent extends RestTable implements OnInit { |
13 | videoChangeOwnerships: VideoChangeOwnership[] = [] | 15 | videoChangeOwnerships: VideoChangeOwnership[] = [] |
@@ -32,8 +34,8 @@ export class MyAccountOwnershipComponent extends RestTable implements OnInit { | |||
32 | return 'MyAccountOwnershipComponent' | 34 | return 'MyAccountOwnershipComponent' |
33 | } | 35 | } |
34 | 36 | ||
35 | createByString (account: Account) { | 37 | switchToDefaultAvatar ($event: Event) { |
36 | return Account.CREATE_BY_STRING(account.name, account.host) | 38 | ($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL() |
37 | } | 39 | } |
38 | 40 | ||
39 | openAcceptModal (videoChangeOwnership: VideoChangeOwnership) { | 41 | openAcceptModal (videoChangeOwnership: VideoChangeOwnership) { |
@@ -56,7 +58,11 @@ export class MyAccountOwnershipComponent extends RestTable implements OnInit { | |||
56 | return this.videoOwnershipService.getOwnershipChanges(this.pagination, this.sort) | 58 | return this.videoOwnershipService.getOwnershipChanges(this.pagination, this.sort) |
57 | .subscribe( | 59 | .subscribe( |
58 | resultList => { | 60 | resultList => { |
59 | this.videoChangeOwnerships = resultList.data | 61 | this.videoChangeOwnerships = resultList.data.map(change => ({ |
62 | ...change, | ||
63 | initiatorAccount: new Account(change.initiatorAccount), | ||
64 | nextOwnerAccount: new Account(change.nextOwnerAccount) | ||
65 | })) | ||
60 | this.totalRecords = resultList.total | 66 | this.totalRecords = resultList.total |
61 | }, | 67 | }, |
62 | 68 | ||
diff --git a/server/models/video/video-change-ownership.ts b/server/models/video/video-change-ownership.ts index aecb03c14..ac0ab7e8b 100644 --- a/server/models/video/video-change-ownership.ts +++ b/server/models/video/video-change-ownership.ts | |||
@@ -46,7 +46,8 @@ enum ScopeNames { | |||
46 | model: VideoModel.scope([ | 46 | model: VideoModel.scope([ |
47 | VideoScopeNames.WITH_THUMBNAILS, | 47 | VideoScopeNames.WITH_THUMBNAILS, |
48 | VideoScopeNames.WITH_WEBTORRENT_FILES, | 48 | VideoScopeNames.WITH_WEBTORRENT_FILES, |
49 | VideoScopeNames.WITH_STREAMING_PLAYLISTS | 49 | VideoScopeNames.WITH_STREAMING_PLAYLISTS, |
50 | VideoScopeNames.WITH_ACCOUNT_DETAILS | ||
50 | ]), | 51 | ]), |
51 | required: true | 52 | required: true |
52 | } | 53 | } |
@@ -129,12 +130,7 @@ export class VideoChangeOwnershipModel extends Model<VideoChangeOwnershipModel> | |||
129 | status: this.status, | 130 | status: this.status, |
130 | initiatorAccount: this.Initiator.toFormattedJSON(), | 131 | initiatorAccount: this.Initiator.toFormattedJSON(), |
131 | nextOwnerAccount: this.NextOwner.toFormattedJSON(), | 132 | nextOwnerAccount: this.NextOwner.toFormattedJSON(), |
132 | video: { | 133 | video: this.Video.toFormattedJSON(), |
133 | id: this.Video.id, | ||
134 | uuid: this.Video.uuid, | ||
135 | url: this.Video.url, | ||
136 | name: this.Video.name | ||
137 | }, | ||
138 | createdAt: this.createdAt | 134 | createdAt: this.createdAt |
139 | } | 135 | } |
140 | } | 136 | } |