aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/+my-library/my-ownership
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2020-11-12 15:28:54 +0100
committerChocobozzz <chocobozzz@cpy.re>2020-11-13 12:02:21 +0100
commit17119e4a546522468878cf115558b17949ab50d0 (patch)
tree3f130cfd7fdccf5aeeac9beee941750590239047 /client/src/app/+my-library/my-ownership
parentb4bc269e5517849b5b89052f0c1a2c01b6f65089 (diff)
downloadPeerTube-17119e4a546522468878cf115558b17949ab50d0.tar.gz
PeerTube-17119e4a546522468878cf115558b17949ab50d0.tar.zst
PeerTube-17119e4a546522468878cf115558b17949ab50d0.zip
Reorganize left menu and account menu
Add my-settings and my-library in left menu Move administration below my-library Split account menu: my-setting and my library
Diffstat (limited to 'client/src/app/+my-library/my-ownership')
-rw-r--r--client/src/app/+my-library/my-ownership/my-accept-ownership/my-accept-ownership.component.html36
-rw-r--r--client/src/app/+my-library/my-ownership/my-accept-ownership/my-accept-ownership.component.scss14
-rw-r--r--client/src/app/+my-library/my-ownership/my-accept-ownership/my-accept-ownership.component.ts72
-rw-r--r--client/src/app/+my-library/my-ownership/my-ownership.component.html90
-rw-r--r--client/src/app/+my-library/my-ownership/my-ownership.component.scss71
-rw-r--r--client/src/app/+my-library/my-ownership/my-ownership.component.ts81
6 files changed, 364 insertions, 0 deletions
diff --git a/client/src/app/+my-library/my-ownership/my-accept-ownership/my-accept-ownership.component.html b/client/src/app/+my-library/my-ownership/my-accept-ownership/my-accept-ownership.component.html
new file mode 100644
index 000000000..def1cbab6
--- /dev/null
+++ b/client/src/app/+my-library/my-ownership/my-accept-ownership/my-accept-ownership.component.html
@@ -0,0 +1,36 @@
1<ng-template #modal let-close="close" let-dismiss="dismiss">
2 <div class="modal-header">
3 <h1 i18n class="modal-title">Accept ownership</h1>
4
5 <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="dismiss()"></my-global-icon>
6 </div>
7
8 <div class="modal-body" [formGroup]="form">
9 <div class="form-group">
10 <label i18n for="channel">Select a channel to receive the video</label>
11 <div class="peertube-select-container">
12 <select formControlName="channel" id="channel" class="form-control">
13 <option i18n value="undefined" disabled>Channel that will receive the video</option>
14 <option *ngFor="let channel of videoChannels" [value]="channel.id">{{ channel.displayName }}
15 </option>
16 </select>
17 </div>
18 <div *ngIf="formErrors.channel" class="form-error">{{ formErrors.channel }}</div>
19 </div>
20 </div>
21
22 <div class="modal-footer inputs">
23 <div class="inputs">
24 <input
25 type="button" role="button" i18n-value value="Cancel" class="action-button action-button-cancel"
26 (click)="dismiss()" (key.enter)="dismiss()"
27 >
28
29 <input
30 type="submit" i18n-value value="Accept" class="action-button-submit"
31 [disabled]="!form.valid"
32 (click)="close()"
33 >
34 </div>
35 </div>
36</ng-template>
diff --git a/client/src/app/+my-library/my-ownership/my-accept-ownership/my-accept-ownership.component.scss b/client/src/app/+my-library/my-ownership/my-accept-ownership/my-accept-ownership.component.scss
new file mode 100644
index 000000000..c7357f62d
--- /dev/null
+++ b/client/src/app/+my-library/my-ownership/my-accept-ownership/my-accept-ownership.component.scss
@@ -0,0 +1,14 @@
1@import '_variables';
2@import '_mixins';
3
4select {
5 display: block;
6}
7
8.peertube-select-container {
9 @include peertube-select-container(350px);
10}
11
12.form-group {
13 margin: 20px 0;
14} \ No newline at end of file
diff --git a/client/src/app/+my-library/my-ownership/my-accept-ownership/my-accept-ownership.component.ts b/client/src/app/+my-library/my-ownership/my-accept-ownership/my-accept-ownership.component.ts
new file mode 100644
index 000000000..587a455f0
--- /dev/null
+++ b/client/src/app/+my-library/my-ownership/my-accept-ownership/my-accept-ownership.component.ts
@@ -0,0 +1,72 @@
1import { Component, ElementRef, EventEmitter, OnInit, Output, ViewChild } from '@angular/core'
2import { AuthService, Notifier } from '@app/core'
3import { OWNERSHIP_CHANGE_CHANNEL_VALIDATOR } from '@app/shared/form-validators/video-ownership-change-validators'
4import { FormReactive, FormValidatorService } from '@app/shared/shared-forms'
5import { VideoChannelService, VideoOwnershipService } from '@app/shared/shared-main'
6import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
7import { VideoChangeOwnership, VideoChannel } from '@shared/models'
8
9@Component({
10 selector: 'my-accept-ownership',
11 templateUrl: './my-accept-ownership.component.html',
12 styleUrls: [ './my-accept-ownership.component.scss' ]
13})
14export class MyAcceptOwnershipComponent extends FormReactive implements OnInit {
15 @Output() accepted = new EventEmitter<void>()
16
17 @ViewChild('modal', { static: true }) modal: ElementRef
18
19 videoChangeOwnership: VideoChangeOwnership | undefined = undefined
20
21 videoChannels: VideoChannel[]
22
23 error: string = null
24
25 constructor (
26 protected formValidatorService: FormValidatorService,
27 private videoOwnershipService: VideoOwnershipService,
28 private notifier: Notifier,
29 private authService: AuthService,
30 private videoChannelService: VideoChannelService,
31 private modalService: NgbModal
32 ) {
33 super()
34 }
35
36 ngOnInit () {
37 this.videoChannels = []
38
39 this.videoChannelService.listAccountVideoChannels(this.authService.getUser().account)
40 .subscribe(videoChannels => this.videoChannels = videoChannels.data)
41
42 this.buildForm({
43 channel: OWNERSHIP_CHANGE_CHANNEL_VALIDATOR
44 })
45 }
46
47 show (videoChangeOwnership: VideoChangeOwnership) {
48 this.videoChangeOwnership = videoChangeOwnership
49 this.modalService
50 .open(this.modal, { centered: true })
51 .result
52 .then(() => this.acceptOwnership())
53 .catch(() => this.videoChangeOwnership = undefined)
54 }
55
56 acceptOwnership () {
57 const channel = this.form.value['channel']
58
59 const videoChangeOwnership = this.videoChangeOwnership
60 this.videoOwnershipService
61 .acceptOwnership(videoChangeOwnership.id, { channelId: channel })
62 .subscribe(
63 () => {
64 this.notifier.success($localize`Ownership accepted`)
65 if (this.accepted) this.accepted.emit()
66 this.videoChangeOwnership = undefined
67 },
68
69 err => this.notifier.error(err.message)
70 )
71 }
72}
diff --git a/client/src/app/+my-library/my-ownership/my-ownership.component.html b/client/src/app/+my-library/my-ownership/my-ownership.component.html
new file mode 100644
index 000000000..6bf562986
--- /dev/null
+++ b/client/src/app/+my-library/my-ownership/my-ownership.component.html
@@ -0,0 +1,90 @@
1<h1>
2 <my-global-icon iconName="download" aria-hidden="true"></my-global-icon>
3 <ng-container i18n>My ownership changes</ng-container>
4</h1>
5
6<p-table
7 [value]="videoChangeOwnerships"
8 [lazy]="true"
9 [paginator]="totalRecords > 0"
10 [totalRecords]="totalRecords"
11 [rows]="rowsPerPage"
12 [sortField]="sort.field"
13 [sortOrder]="sort.order"
14 (onLazyLoad)="loadLazy($event)"
15>
16 <ng-template pTemplate="header">
17 <tr>
18 <th style="width: 150px;" i18n>Actions</th>
19 <th style="width: 35%;" i18n>Initiator</th>
20 <th style="width: 65%;" i18n>Video</th>
21 <th style="width: 150px;" i18n pSortableColumn="createdAt">
22 Created
23 <p-sortIcon field="createdAt"></p-sortIcon>
24 </th>
25 <th style="width: 100px;" i18n>Status</th>
26 </tr>
27 </ng-template>
28
29 <ng-template pTemplate="body" let-videoChangeOwnership>
30 <tr>
31 <td class="action-cell">
32 <ng-container *ngIf="videoChangeOwnership.status === 'WAITING'">
33 <my-button i18n-title title="Accept" icon="tick" (click)="openAcceptModal(videoChangeOwnership)"></my-button>
34 <my-button i18n-title title="Refuse" icon="cross" (click)="refuse(videoChangeOwnership)"></my-button>
35 </ng-container>
36 </td>
37 <td>
38 <a [href]="videoChangeOwnership.initiatorAccount.url" i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer">
39 <div class="chip two-lines">
40 <img
41 class="avatar"
42 [src]="videoChangeOwnership.initiatorAccount.avatar?.path"
43 (error)="switchToDefaultAvatar($event)"
44 alt="Avatar"
45 >
46 <div>
47 {{ videoChangeOwnership.initiatorAccount.displayName }}
48 <span class="text-muted">{{ videoChangeOwnership.initiatorAccount.nameWithHost }}</span>
49 </div>
50 </div>
51 </a>
52 </td>
53
54 <td>
55 <a [href]="videoChangeOwnership.video.url" class="video-table-video-link" [title]="videoChangeOwnership.video.name" target="_blank" rel="noopener noreferrer">
56 <div class="video-table-video">
57 <div class="video-table-video-image">
58 <img [src]="videoChangeOwnership.video.thumbnailPath">
59 </div>
60 <div class="video-table-video-text">
61 <div>
62 {{ videoChangeOwnership.video.name }}
63 </div>
64 <div class="text-muted">by {{ videoChangeOwnership.video.channel?.displayName }} </div>
65 </div>
66 </div>
67 </a>
68 </td>
69
70 <td>{{ videoChangeOwnership.createdAt | date: 'short' }}</td>
71
72 <td>
73 <span class="badge"
74 [ngClass]="getStatusClass(videoChangeOwnership.status)">{{ videoChangeOwnership.status }}</span>
75 </td>
76 </tr>
77 </ng-template>
78
79 <ng-template pTemplate="emptymessage">
80 <tr>
81 <td colspan="6">
82 <div class="no-results">
83 <ng-container i18n>No ownership change request found.</ng-container>
84 </div>
85 </td>
86 </tr>
87 </ng-template>
88</p-table>
89
90<my-accept-ownership #myAcceptOwnershipComponent (accepted)="accepted()"></my-accept-ownership>
diff --git a/client/src/app/+my-library/my-ownership/my-ownership.component.scss b/client/src/app/+my-library/my-ownership/my-ownership.component.scss
new file mode 100644
index 000000000..7cac9c9f3
--- /dev/null
+++ b/client/src/app/+my-library/my-ownership/my-ownership.component.scss
@@ -0,0 +1,71 @@
1@import 'miniature';
2@import 'mixins';
3
4.chip {
5 @include chip;
6}
7
8.badge {
9 @include table-badge;
10}
11
12.video-table-video {
13 display: inline-flex;
14
15 .video-table-video-image {
16 @include miniature-thumbnail;
17
18 $image-height: 45px;
19
20 height: $image-height;
21 width: #{(16/9) * $image-height};
22 margin-right: 0.5rem;
23 border-radius: 2px;
24 border: none;
25 background: transparent;
26 display: inline-flex;
27 justify-content: center;
28 align-items: center;
29 position: relative;
30
31 img {
32 height: 100%;
33 width: 100%;
34 border-radius: 2px;
35 }
36
37 span {
38 color: pvar(--inputPlaceholderColor);
39 }
40
41 .video-table-video-image-label {
42 @include static-thumbnail-overlay;
43 position: absolute;
44 border-radius: 3px;
45 font-size: 10px;
46 padding: 0 3px;
47 line-height: 1.3;
48 bottom: 2px;
49 right: 2px;
50 }
51 }
52
53 .video-table-video-text {
54 display: inline-flex;
55 flex-direction: column;
56 justify-content: center;
57 font-size: 90%;
58 color: pvar(--mainForegroundColor);
59 line-height: 1rem;
60
61 div .glyphicon {
62 font-size: 80%;
63 color: gray;
64 margin-left: 0.1rem;
65 }
66
67 div + div {
68 font-size: 80%;
69 }
70 }
71}
diff --git a/client/src/app/+my-library/my-ownership/my-ownership.component.ts b/client/src/app/+my-library/my-ownership/my-ownership.component.ts
new file mode 100644
index 000000000..e1aca65f6
--- /dev/null
+++ b/client/src/app/+my-library/my-ownership/my-ownership.component.ts
@@ -0,0 +1,81 @@
1import { SortMeta } from 'primeng/api'
2import { Component, OnInit, ViewChild } from '@angular/core'
3import { Notifier, RestPagination, RestTable } from '@app/core'
4import { Account, Actor, VideoOwnershipService } from '@app/shared/shared-main'
5import { VideoChangeOwnership, VideoChangeOwnershipStatus } from '@shared/models'
6import { MyAcceptOwnershipComponent } from './my-accept-ownership/my-accept-ownership.component'
7
8@Component({
9 templateUrl: './my-ownership.component.html',
10 styleUrls: [ './my-ownership.component.scss' ]
11})
12export class MyOwnershipComponent extends RestTable implements OnInit {
13 videoChangeOwnerships: VideoChangeOwnership[] = []
14 totalRecords = 0
15 sort: SortMeta = { field: 'createdAt', order: -1 }
16 pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
17
18 @ViewChild('myAcceptOwnershipComponent', { static: true }) myAccountAcceptOwnershipComponent: MyAcceptOwnershipComponent
19
20 constructor (
21 private notifier: Notifier,
22 private videoOwnershipService: VideoOwnershipService
23 ) {
24 super()
25 }
26
27 ngOnInit () {
28 this.initialize()
29 }
30
31 getIdentifier () {
32 return 'MyOwnershipComponent'
33 }
34
35 getStatusClass (status: VideoChangeOwnershipStatus) {
36 switch (status) {
37 case VideoChangeOwnershipStatus.ACCEPTED:
38 return 'badge-green'
39 case VideoChangeOwnershipStatus.REFUSED:
40 return 'badge-red'
41 default:
42 return 'badge-yellow'
43 }
44 }
45
46 switchToDefaultAvatar ($event: Event) {
47 ($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL()
48 }
49
50 openAcceptModal (videoChangeOwnership: VideoChangeOwnership) {
51 this.myAccountAcceptOwnershipComponent.show(videoChangeOwnership)
52 }
53
54 accepted () {
55 this.loadData()
56 }
57
58 refuse (videoChangeOwnership: VideoChangeOwnership) {
59 this.videoOwnershipService.refuseOwnership(videoChangeOwnership.id)
60 .subscribe(
61 () => this.loadData(),
62 err => this.notifier.error(err.message)
63 )
64 }
65
66 protected loadData () {
67 return this.videoOwnershipService.getOwnershipChanges(this.pagination, this.sort)
68 .subscribe(
69 resultList => {
70 this.videoChangeOwnerships = resultList.data.map(change => ({
71 ...change,
72 initiatorAccount: new Account(change.initiatorAccount),
73 nextOwnerAccount: new Account(change.nextOwnerAccount)
74 }))
75 this.totalRecords = resultList.total
76 },
77
78 err => this.notifier.error(err.message)
79 )
80 }
81}