aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/+my-library
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app/+my-library')
-rw-r--r--client/src/app/+my-library/+my-video-channels/my-video-channel-edit.component.scss3
-rw-r--r--client/src/app/+my-library/+my-video-channels/my-video-channels.component.html21
-rw-r--r--client/src/app/+my-library/+my-video-channels/my-video-channels.component.scss99
-rw-r--r--client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts46
-rw-r--r--client/src/app/+my-library/+my-video-channels/my-video-channels.module.ts4
-rw-r--r--client/src/app/+my-library/my-history/my-history.component.html32
-rw-r--r--client/src/app/+my-library/my-history/my-history.component.scss4
-rw-r--r--client/src/app/+my-library/my-history/my-history.component.ts75
-rw-r--r--client/src/app/+my-library/my-library.component.scss6
-rw-r--r--client/src/app/+my-library/my-library.module.ts4
-rw-r--r--client/src/app/+my-library/my-ownership/my-ownership.component.html2
-rw-r--r--client/src/app/+my-library/my-ownership/my-ownership.component.scss8
-rw-r--r--client/src/app/+my-library/my-ownership/my-ownership.component.ts6
-rw-r--r--client/src/app/+my-library/my-subscriptions/my-subscriptions.component.html14
-rw-r--r--client/src/app/+my-library/my-subscriptions/my-subscriptions.component.scss20
-rw-r--r--client/src/app/+my-library/my-subscriptions/my-subscriptions.component.ts35
-rw-r--r--client/src/app/+my-library/my-video-imports/my-video-imports.component.scss2
-rw-r--r--client/src/app/+my-library/my-video-imports/my-video-imports.component.ts2
-rw-r--r--client/src/app/+my-library/my-video-playlists/my-video-playlist-elements.component.scss13
-rw-r--r--client/src/app/+my-library/my-video-playlists/my-video-playlists.component.html7
-rw-r--r--client/src/app/+my-library/my-video-playlists/my-video-playlists.component.ts45
-rw-r--r--client/src/app/+my-library/my-videos/modals/video-change-ownership.component.scss2
-rw-r--r--client/src/app/+my-library/my-videos/my-videos.component.html9
-rw-r--r--client/src/app/+my-library/my-videos/my-videos.component.scss4
-rw-r--r--client/src/app/+my-library/my-videos/my-videos.component.ts35
25 files changed, 223 insertions, 275 deletions
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channel-edit.component.scss b/client/src/app/+my-library/+my-video-channels/my-video-channel-edit.component.scss
index 22de103d1..667726c22 100644
--- a/client/src/app/+my-library/+my-video-channels/my-video-channel-edit.component.scss
+++ b/client/src/app/+my-library/+my-video-channels/my-video-channel-edit.component.scss
@@ -66,7 +66,8 @@ textarea {
66 width: auto !important; 66 width: auto !important;
67 } 67 }
68 68
69 label[for=name] + div, textarea { 69 label[for=name] + div,
70 textarea {
70 width: 100%; 71 width: 100%;
71 } 72 }
72} 73}
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html
index b704a1cc6..e41cbe921 100644
--- a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html
+++ b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html
@@ -1,18 +1,11 @@
1<h1> 1<h1>
2 <span> 2 <my-global-icon iconName="channel" aria-hidden="true"></my-global-icon>
3 <my-global-icon iconName="channel" aria-hidden="true"></my-global-icon> 3 <ng-container i18n>My channels</ng-container>
4 <ng-container i18n>My channels</ng-container> 4 <span class="badge badge-secondary">{{ totalItems }}</span>
5 <span class="badge badge-secondary">{{ totalItems }}</span>
6 </span>
7</h1> 5</h1>
8 6
9<div class="video-channels-header d-flex justify-content-between"> 7<div class="video-channels-header d-flex justify-content-between">
10 <div class="has-feedback has-clear"> 8 <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter>
11 <input type="text" placeholder="Search your channels" i18n-placeholder [(ngModel)]="channelsSearch"
12 (ngModelChange)="onChannelsSearchChanged()" />
13 <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetSearch()"></a>
14 <span class="sr-only" i18n>Clear filters</span>
15 </div>
16 9
17 <a class="create-button" routerLink="create"> 10 <a class="create-button" routerLink="create">
18 <my-global-icon iconName="add" aria-hidden="true"></my-global-icon> 11 <my-global-icon iconName="add" aria-hidden="true"></my-global-icon>
@@ -20,11 +13,11 @@
20 </a> 13 </a>
21</div> 14</div>
22 15
16<div class="no-results" i18n *ngIf="totalItems === 0">No channel found.</div>
17
23<div class="video-channels"> 18<div class="video-channels">
24 <div *ngFor="let videoChannel of videoChannels; let i = index" class="video-channel"> 19 <div *ngFor="let videoChannel of videoChannels; let i = index" class="video-channel">
25 <a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]"> 20 <my-actor-avatar [channel]="videoChannel" [internalHref]="[ '/video-channels', videoChannel.nameWithHost ]"></my-actor-avatar>
26 <img [src]="videoChannel.avatarUrl" alt="Avatar" />
27 </a>
28 21
29 <div class="video-channel-info"> 22 <div class="video-channel-info">
30 <a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]" class="video-channel-names" i18n-title title="Channel page"> 23 <a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]" class="video-channel-names" i18n-title title="Channel page">
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.scss b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.scss
index 8804fa95c..191c5169d 100644
--- a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.scss
+++ b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.scss
@@ -1,6 +1,11 @@
1@import '_variables'; 1@import '_variables';
2@import '_mixins'; 2@import '_mixins';
3 3
4h1 my-global-icon {
5 position: relative;
6 top: -2px;
7}
8
4.create-button { 9.create-button {
5 @include create-button; 10 @include create-button;
6} 11}
@@ -9,10 +14,8 @@ input[type=text] {
9 @include peertube-input-text(300px); 14 @include peertube-input-text(300px);
10} 15}
11 16
12::ng-deep .action-button { 17my-edit-button {
13 &.action-button-edit { 18 margin-right: 10px;
14 margin-right: 10px;
15 }
16} 19}
17 20
18.video-channel { 21.video-channel {
@@ -20,40 +23,40 @@ input[type=text] {
20 23
21 padding-bottom: 0; 24 padding-bottom: 0;
22 25
23 img { 26 my-actor-avatar {
24 @include channel-avatar(80px); 27 @include actor-avatar-size(80px);
25 28
26 margin-right: 10px; 29 margin-right: 10px;
27 } 30 }
31}
28 32
29 .video-channel-info { 33.video-channel-info {
30 flex-grow: 1; 34 flex-grow: 1;
31 35}
32 a.video-channel-names {
33 @include disable-default-a-behaviour;
34
35 width: fit-content;
36 display: flex;
37 align-items: baseline;
38 color: pvar(--mainForegroundColor);
39
40 .video-channel-display-name {
41 font-weight: $font-semibold;
42 font-size: 18px;
43 }
44
45 .video-channel-name {
46 font-size: 14px;
47 color: $grey-actor-name;
48 margin-left: 5px;
49 }
50 }
51 }
52 36
53 .video-channel-buttons { 37.video-channel-names {
54 margin-top: 10px; 38 @include disable-default-a-behaviour;
55 min-width: 190px; 39
56 } 40 width: fit-content;
41 display: flex;
42 align-items: baseline;
43 color: pvar(--mainForegroundColor);
44}
45
46.video-channel-display-name {
47 font-weight: $font-semibold;
48 font-size: 18px;
49}
50
51.video-channel-name {
52 font-size: 14px;
53 color: $grey-actor-name;
54 margin-left: 5px;
55}
56
57.video-channel-buttons {
58 margin-top: 10px;
59 min-width: 190px;
57} 60}
58 61
59::ng-deep .chartjs-render-monitor { 62::ng-deep .chartjs-render-monitor {
@@ -73,21 +76,6 @@ input[type=text] {
73 .video-channel { 76 .video-channel {
74 padding-bottom: 10px; 77 padding-bottom: 10px;
75 78
76 .video-channel-info {
77 padding-bottom: 10px;
78 text-align: center;
79
80 .video-channel-names {
81 flex-direction: column;
82 align-items: center !important;
83 margin: auto;
84
85 .video-channel-name {
86 margin-left: 0px !important;
87 }
88 }
89 }
90
91 img { 79 img {
92 margin-right: 0; 80 margin-right: 0;
93 } 81 }
@@ -96,6 +84,21 @@ input[type=text] {
96 align-self: center; 84 align-self: center;
97 } 85 }
98 } 86 }
87
88 .video-channel-info {
89 padding-bottom: 10px;
90 text-align: center;
91 }
92
93 .video-channel-names {
94 flex-direction: column;
95 align-items: center !important;
96 margin: auto;
97 }
98
99 .video-channel-name {
100 margin-left: 0 !important;
101 }
99} 102}
100 103
101@media screen and (max-width: $mobile-view) { 104@media screen and (max-width: $mobile-view) {
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts
index f6ba50a48..9e3bf35b4 100644
--- a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts
+++ b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts
@@ -1,29 +1,26 @@
1import { ChartData } from 'chart.js' 1import { ChartData } from 'chart.js'
2import { max, maxBy, min, minBy } from 'lodash-es' 2import { max, maxBy, min, minBy } from 'lodash-es'
3import { Subject } from 'rxjs' 3import { mergeMap } from 'rxjs/operators'
4import { debounceTime, mergeMap } from 'rxjs/operators' 4import { Component } from '@angular/core'
5import { Component, OnInit } from '@angular/core' 5import { AuthService, ConfirmService, Notifier, ScreenService } from '@app/core'
6import { AuthService, ConfirmService, Notifier, ScreenService, User } from '@app/core'
7import { VideoChannel, VideoChannelService } from '@app/shared/shared-main' 6import { VideoChannel, VideoChannelService } from '@app/shared/shared-main'
8 7
9@Component({ 8@Component({
10 templateUrl: './my-video-channels.component.html', 9 templateUrl: './my-video-channels.component.html',
11 styleUrls: [ './my-video-channels.component.scss' ] 10 styleUrls: [ './my-video-channels.component.scss' ]
12}) 11})
13export class MyVideoChannelsComponent implements OnInit { 12export class MyVideoChannelsComponent {
14 totalItems: number 13 totalItems: number
15 14
16 videoChannels: VideoChannel[] = [] 15 videoChannels: VideoChannel[] = []
16
17 videoChannelsChartData: ChartData[] 17 videoChannelsChartData: ChartData[]
18 videoChannelsMinimumDailyViews = 0 18 videoChannelsMinimumDailyViews = 0
19 videoChannelsMaximumDailyViews: number 19 videoChannelsMaximumDailyViews: number
20 20
21 channelsSearch: string
22 channelsSearchChanged = new Subject<string>()
23
24 chartOptions: any 21 chartOptions: any
25 22
26 private user: User 23 search: string
27 24
28 constructor ( 25 constructor (
29 private authService: AuthService, 26 private authService: AuthService,
@@ -31,31 +28,15 @@ export class MyVideoChannelsComponent implements OnInit {
31 private confirmService: ConfirmService, 28 private confirmService: ConfirmService,
32 private videoChannelService: VideoChannelService, 29 private videoChannelService: VideoChannelService,
33 private screenService: ScreenService 30 private screenService: ScreenService
34 ) {} 31 ) {}
35
36 ngOnInit () {
37 this.user = this.authService.getUser()
38
39 this.loadVideoChannels()
40
41 this.channelsSearchChanged
42 .pipe(debounceTime(500))
43 .subscribe(() => {
44 this.loadVideoChannels()
45 })
46 }
47 32
48 get isInSmallView () { 33 get isInSmallView () {
49 return this.screenService.isInSmallView() 34 return this.screenService.isInSmallView()
50 } 35 }
51 36
52 resetSearch () { 37 onSearch (search: string) {
53 this.channelsSearch = '' 38 this.search = search
54 this.onChannelsSearchChanged() 39 this.loadVideoChannels()
55 }
56
57 onChannelsSearchChanged () {
58 this.channelsSearchChanged.next()
59 } 40 }
60 41
61 async deleteVideoChannel (videoChannel: VideoChannel) { 42 async deleteVideoChannel (videoChannel: VideoChannel) {
@@ -85,8 +66,11 @@ channel with the same name (${videoChannel.name})!`,
85 66
86 private loadVideoChannels () { 67 private loadVideoChannels () {
87 this.authService.userInformationLoaded 68 this.authService.userInformationLoaded
88 .pipe(mergeMap(() => this.videoChannelService.listAccountVideoChannels(this.user.account, null, true, this.channelsSearch))) 69 .pipe(mergeMap(() => {
89 .subscribe(res => { 70 const user = this.authService.getUser()
71
72 return this.videoChannelService.listAccountVideoChannels(user.account, null, true, this.search)
73 })).subscribe(res => {
90 this.videoChannels = res.data 74 this.videoChannels = res.data
91 this.totalItems = res.total 75 this.totalItems = res.total
92 76
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channels.module.ts b/client/src/app/+my-library/+my-video-channels/my-video-channels.module.ts
index 53557ca02..c775bfdee 100644
--- a/client/src/app/+my-library/+my-video-channels/my-video-channels.module.ts
+++ b/client/src/app/+my-library/+my-video-channels/my-video-channels.module.ts
@@ -1,6 +1,6 @@
1import { ChartModule } from 'primeng/chart' 1import { ChartModule } from 'primeng/chart'
2import { NgModule } from '@angular/core' 2import { NgModule } from '@angular/core'
3import { SharedActorImageModule } from '@app/shared/shared-actor-image' 3import { SharedActorImageEditModule } from '@app/shared/shared-actor-image-edit'
4import { SharedFormModule } from '@app/shared/shared-forms' 4import { SharedFormModule } from '@app/shared/shared-forms'
5import { SharedGlobalIconModule } from '@app/shared/shared-icons' 5import { SharedGlobalIconModule } from '@app/shared/shared-icons'
6import { SharedMainModule } from '@app/shared/shared-main' 6import { SharedMainModule } from '@app/shared/shared-main'
@@ -8,6 +8,7 @@ import { MyVideoChannelCreateComponent } from './my-video-channel-create.compone
8import { MyVideoChannelUpdateComponent } from './my-video-channel-update.component' 8import { MyVideoChannelUpdateComponent } from './my-video-channel-update.component'
9import { MyVideoChannelsRoutingModule } from './my-video-channels-routing.module' 9import { MyVideoChannelsRoutingModule } from './my-video-channels-routing.module'
10import { MyVideoChannelsComponent } from './my-video-channels.component' 10import { MyVideoChannelsComponent } from './my-video-channels.component'
11import { SharedActorImageModule } from '@app/shared/shared-actor-image/shared-actor-image.module'
11 12
12@NgModule({ 13@NgModule({
13 imports: [ 14 imports: [
@@ -18,6 +19,7 @@ import { MyVideoChannelsComponent } from './my-video-channels.component'
18 SharedMainModule, 19 SharedMainModule,
19 SharedFormModule, 20 SharedFormModule,
20 SharedGlobalIconModule, 21 SharedGlobalIconModule,
22 SharedActorImageEditModule,
21 SharedActorImageModule 23 SharedActorImageModule
22 ], 24 ],
23 25
diff --git a/client/src/app/+my-library/my-history/my-history.component.html b/client/src/app/+my-library/my-history/my-history.component.html
index 9dec64645..45ca37e0d 100644
--- a/client/src/app/+my-library/my-history/my-history.component.html
+++ b/client/src/app/+my-library/my-history/my-history.component.html
@@ -5,14 +5,7 @@
5 5
6<div class="top-buttons"> 6<div class="top-buttons">
7 <div class="search-wrapper"> 7 <div class="search-wrapper">
8 <div class="input-group has-feedback has-clear"> 8 <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter>
9 <input
10 type="text" name="history-search" id="history-search" i18n-placeholder placeholder="Search your history"
11 (keyup)="onSearch($event)"
12 >
13 <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetSearch()"></a>
14 <span class="sr-only" i18n>Clear filters</span>
15 </div>
16 </div> 9 </div>
17 10
18 <div class="history-switch"> 11 <div class="history-switch">
@@ -26,14 +19,15 @@
26 </button> 19 </button>
27</div> 20</div>
28 21
29 22<my-videos-selection
30<div class="no-history" i18n *ngIf="hasDoneFirstQuery && videos.length === 0">You don't have any video in your watch history yet.</div> 23 [pagination]="pagination"
31 24 [(videosModel)]="videos"
32<div myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true" [dataObservable]="onDataSubject.asObservable()" class="videos"> 25 [miniatureDisplayOptions]="miniatureDisplayOptions"
33 <div class="video" *ngFor="let video of videos"> 26 [titlePage]="titlePage"
34 <my-video-miniature 27 [getVideosObservableFunction]="getVideosObservableFunction"
35 [video]="video" [displayAsRow]="true" 28 [user]="user"
36 (videoRemoved)="removeVideoFromArray(video)" (videoBlocked)="removeVideoFromArray(video)" 29 [loadOnInit]="false"
37 ></my-video-miniature> 30 i18n-noResultMessage noResultMessage="You don't have any video in your watch history yet."
38 </div> 31 [enableSelection]="false"
39</div> 32 #videosSelection
33></my-videos-selection>
diff --git a/client/src/app/+my-library/my-history/my-history.component.scss b/client/src/app/+my-library/my-history/my-history.component.scss
index af4a34b4b..28b809f71 100644
--- a/client/src/app/+my-library/my-history/my-history.component.scss
+++ b/client/src/app/+my-library/my-history/my-history.component.scss
@@ -39,12 +39,12 @@
39 } 39 }
40 40
41 .delete-history { 41 .delete-history {
42 grid-column: 4;
43
44 @include peertube-button; 42 @include peertube-button;
45 @include grey-button; 43 @include grey-button;
46 @include button-with-icon; 44 @include button-with-icon;
47 45
46 grid-column: 4;
47
48 font-size: 15px; 48 font-size: 15px;
49 } 49 }
50} 50}
diff --git a/client/src/app/+my-library/my-history/my-history.component.ts b/client/src/app/+my-library/my-history/my-history.component.ts
index 1695bd7ad..ad83db7ab 100644
--- a/client/src/app/+my-library/my-history/my-history.component.ts
+++ b/client/src/app/+my-library/my-history/my-history.component.ts
@@ -1,36 +1,55 @@
1import { Component, ComponentFactoryResolver, OnDestroy, OnInit } from '@angular/core' 1import { Subject } from 'rxjs'
2import { tap } from 'rxjs/operators'
3import { Component, ComponentFactoryResolver, OnInit, ViewChild } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router' 4import { ActivatedRoute, Router } from '@angular/router'
3import { 5import {
4 AuthService, 6 AuthService,
5 ComponentPagination, 7 ComponentPagination,
6 ConfirmService, 8 ConfirmService,
9 DisableForReuseHook,
7 LocalStorageService, 10 LocalStorageService,
8 Notifier, 11 Notifier,
9 ScreenService, 12 ScreenService,
10 ServerService, 13 ServerService,
14 User,
11 UserService 15 UserService
12} from '@app/core' 16} from '@app/core'
13import { immutableAssign } from '@app/helpers' 17import { immutableAssign } from '@app/helpers'
14import { UserHistoryService } from '@app/shared/shared-main' 18import { UserHistoryService, Video } from '@app/shared/shared-main'
15import { AbstractVideoList } from '@app/shared/shared-video-miniature' 19import { MiniatureDisplayOptions, VideosSelectionComponent } from '@app/shared/shared-video-miniature'
16import { Subject } from 'rxjs'
17import { debounceTime, tap, distinctUntilChanged } from 'rxjs/operators'
18 20
19@Component({ 21@Component({
20 templateUrl: './my-history.component.html', 22 templateUrl: './my-history.component.html',
21 styleUrls: [ './my-history.component.scss' ] 23 styleUrls: [ './my-history.component.scss' ]
22}) 24})
23export class MyHistoryComponent extends AbstractVideoList implements OnInit, OnDestroy { 25export class MyHistoryComponent implements OnInit, DisableForReuseHook {
26 @ViewChild('videosSelection', { static: true }) videosSelection: VideosSelectionComponent
27
24 titlePage: string 28 titlePage: string
25 pagination: ComponentPagination = { 29 pagination: ComponentPagination = {
26 currentPage: 1, 30 currentPage: 1,
27 itemsPerPage: 5, 31 itemsPerPage: 5,
28 totalItems: null 32 totalItems: null
29 } 33 }
34
30 videosHistoryEnabled: boolean 35 videosHistoryEnabled: boolean
31 search: string
32 36
33 protected searchStream: Subject<string> 37 miniatureDisplayOptions: MiniatureDisplayOptions = {
38 date: true,
39 views: true,
40 by: true,
41 privacyLabel: false,
42 privacyText: true,
43 state: true,
44 blacklistInfo: true
45 }
46
47 getVideosObservableFunction = this.getVideosObservable.bind(this)
48
49 user: User
50
51 videos: Video[] = []
52 search: string
34 53
35 constructor ( 54 constructor (
36 protected router: Router, 55 protected router: Router,
@@ -45,45 +64,31 @@ export class MyHistoryComponent extends AbstractVideoList implements OnInit, OnD
45 private userHistoryService: UserHistoryService, 64 private userHistoryService: UserHistoryService,
46 protected cfr: ComponentFactoryResolver 65 protected cfr: ComponentFactoryResolver
47 ) { 66 ) {
48 super()
49
50 this.titlePage = $localize`My watch history` 67 this.titlePage = $localize`My watch history`
51 } 68 }
52 69
53 ngOnInit () { 70 ngOnInit () {
54 super.ngOnInit() 71 this.user = this.authService.getUser()
55 72
56 this.authService.userInformationLoaded 73 this.authService.userInformationLoaded
57 .subscribe(() => { 74 .subscribe(() => this.videosHistoryEnabled = this.user.videosHistoryEnabled)
58 this.videosHistoryEnabled = this.authService.getUser().videosHistoryEnabled 75 }
59 })
60
61 this.searchStream = new Subject()
62 76
63 this.searchStream 77 disableForReuse () {
64 .pipe( 78 this.videosSelection.disableForReuse()
65 debounceTime(400),
66 distinctUntilChanged()
67 )
68 .subscribe(search => {
69 this.search = search
70 this.reloadVideos()
71 })
72 } 79 }
73 80
74 onSearch (event: Event) { 81 enabledForReuse () {
75 const target = event.target as HTMLInputElement 82 this.videosSelection.enabledForReuse()
76 this.searchStream.next(target.value)
77 } 83 }
78 84
79 resetSearch () { 85 reloadData () {
80 const searchInput = document.getElementById('history-search') as HTMLInputElement 86 this.videosSelection.reloadVideos()
81 searchInput.value = ''
82 this.searchStream.next('')
83 } 87 }
84 88
85 ngOnDestroy () { 89 onSearch (search: string) {
86 super.ngOnDestroy() 90 this.search = search
91 this.reloadData()
87 } 92 }
88 93
89 getVideosObservable (page: number) { 94 getVideosObservable (page: number) {
@@ -129,7 +134,7 @@ export class MyHistoryComponent extends AbstractVideoList implements OnInit, OnD
129 () => { 134 () => {
130 this.notifier.success($localize`Videos history deleted`) 135 this.notifier.success($localize`Videos history deleted`)
131 136
132 this.reloadVideos() 137 this.reloadData()
133 }, 138 },
134 139
135 err => this.notifier.error(err.message) 140 err => this.notifier.error(err.message)
diff --git a/client/src/app/+my-library/my-library.component.scss b/client/src/app/+my-library/my-library.component.scss
index a5bb499b4..b32bc84e7 100644
--- a/client/src/app/+my-library/my-library.component.scss
+++ b/client/src/app/+my-library/my-library.component.scss
@@ -2,12 +2,12 @@
2@import '_mixins'; 2@import '_mixins';
3 3
4.row { 4.row {
5 @include sub-menu-h1;
6
5 flex-direction: column; 7 flex-direction: column;
6 width: 100%; 8 width: 100%;
7 9
8 & > my-top-menu-dropdown:nth-child(1) { 10 > my-top-menu-dropdown:nth-child(1) {
9 flex-grow: 1; 11 flex-grow: 1;
10 } 12 }
11
12 @include sub-menu-h1;
13} 13}
diff --git a/client/src/app/+my-library/my-library.module.ts b/client/src/app/+my-library/my-library.module.ts
index a1d706f0b..264ad03f7 100644
--- a/client/src/app/+my-library/my-library.module.ts
+++ b/client/src/app/+my-library/my-library.module.ts
@@ -26,7 +26,7 @@ import { MyVideoPlaylistUpdateComponent } from './my-video-playlists/my-video-pl
26import { MyVideoPlaylistsComponent } from './my-video-playlists/my-video-playlists.component' 26import { MyVideoPlaylistsComponent } from './my-video-playlists/my-video-playlists.component'
27import { VideoChangeOwnershipComponent } from './my-videos/modals/video-change-ownership.component' 27import { VideoChangeOwnershipComponent } from './my-videos/modals/video-change-ownership.component'
28import { MyVideosComponent } from './my-videos/my-videos.component' 28import { MyVideosComponent } from './my-videos/my-videos.component'
29import { SharedAccountAvatarModule } from '../shared/shared-account-avatar/shared-account-avatar.module' 29import { SharedActorImageModule } from '../shared/shared-actor-image/shared-actor-image.module'
30 30
31@NgModule({ 31@NgModule({
32 imports: [ 32 imports: [
@@ -47,7 +47,7 @@ import { SharedAccountAvatarModule } from '../shared/shared-account-avatar/share
47 SharedAbuseListModule, 47 SharedAbuseListModule,
48 SharedShareModal, 48 SharedShareModal,
49 SharedVideoLiveModule, 49 SharedVideoLiveModule,
50 SharedAccountAvatarModule 50 SharedActorImageModule
51 ], 51 ],
52 52
53 declarations: [ 53 declarations: [
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
index d0eff0521..4c02c78fc 100644
--- a/client/src/app/+my-library/my-ownership/my-ownership.component.html
+++ b/client/src/app/+my-library/my-ownership/my-ownership.component.html
@@ -37,7 +37,7 @@
37 <td> 37 <td>
38 <a [href]="videoChangeOwnership.initiatorAccount.url" i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer"> 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"> 39 <div class="chip two-lines">
40 <my-account-avatar [account]="videoChangeOwnership.initiatorAccount"></my-account-avatar> 40 <my-actor-avatar [account]="videoChangeOwnership.initiatorAccount"></my-actor-avatar>
41 <div> 41 <div>
42 {{ videoChangeOwnership.initiatorAccount.displayName }} 42 {{ videoChangeOwnership.initiatorAccount.displayName }}
43 <span class="text-muted">{{ videoChangeOwnership.initiatorAccount.nameWithHost }}</span> 43 <span class="text-muted">{{ videoChangeOwnership.initiatorAccount.nameWithHost }}</span>
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
index 7cac9c9f3..dfc8fc99e 100644
--- a/client/src/app/+my-library/my-ownership/my-ownership.component.scss
+++ b/client/src/app/+my-library/my-ownership/my-ownership.component.scss
@@ -13,15 +13,15 @@
13 display: inline-flex; 13 display: inline-flex;
14 14
15 .video-table-video-image { 15 .video-table-video-image {
16 @include miniature-thumbnail;
17
18 $image-height: 45px; 16 $image-height: 45px;
19 17
18 @include miniature-thumbnail;
19
20 height: $image-height; 20 height: $image-height;
21 width: #{(16/9) * $image-height}; 21 width: #{(16/9) * $image-height};
22 margin-right: 0.5rem; 22 margin-right: 0.5rem;
23 border-radius: 2px; 23 border-radius: 2px;
24 border: none; 24 border: 0;
25 background: transparent; 25 background: transparent;
26 display: inline-flex; 26 display: inline-flex;
27 justify-content: center; 27 justify-content: center;
@@ -60,7 +60,7 @@
60 60
61 div .glyphicon { 61 div .glyphicon {
62 font-size: 80%; 62 font-size: 80%;
63 color: gray; 63 color: #808080;
64 margin-left: 0.1rem; 64 margin-left: 0.1rem;
65 } 65 }
66 66
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
index a938023b4..aaf028474 100644
--- a/client/src/app/+my-library/my-ownership/my-ownership.component.ts
+++ b/client/src/app/+my-library/my-ownership/my-ownership.component.ts
@@ -48,18 +48,18 @@ export class MyOwnershipComponent extends RestTable implements OnInit {
48 } 48 }
49 49
50 accepted () { 50 accepted () {
51 this.loadData() 51 this.reloadData()
52 } 52 }
53 53
54 refuse (videoChangeOwnership: VideoChangeOwnership) { 54 refuse (videoChangeOwnership: VideoChangeOwnership) {
55 this.videoOwnershipService.refuseOwnership(videoChangeOwnership.id) 55 this.videoOwnershipService.refuseOwnership(videoChangeOwnership.id)
56 .subscribe( 56 .subscribe(
57 () => this.loadData(), 57 () => this.reloadData(),
58 err => this.notifier.error(err.message) 58 err => this.notifier.error(err.message)
59 ) 59 )
60 } 60 }
61 61
62 protected loadData () { 62 protected reloadData () {
63 return this.videoOwnershipService.getOwnershipChanges(this.pagination, this.sort) 63 return this.videoOwnershipService.getOwnershipChanges(this.pagination, this.sort)
64 .subscribe( 64 .subscribe(
65 resultList => { 65 resultList => {
diff --git a/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.html b/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.html
index ff448ad87..f91cebacf 100644
--- a/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.html
+++ b/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.html
@@ -7,21 +7,14 @@
7</h1> 7</h1>
8 8
9<div class="video-subscriptions-header"> 9<div class="video-subscriptions-header">
10 <div class="has-feedback has-clear"> 10 <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter>
11 <input type="text" placeholder="Search your subscriptions" i18n-placeholder [(ngModel)]="subscriptionsSearch"
12 (ngModelChange)="onSubscriptionsSearchChanged()" />
13 <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetSearch()"></a>
14 <span class="sr-only" i18n>Clear filters</span>
15 </div>
16</div> 11</div>
17 12
18<div class="no-results" i18n *ngIf="pagination.totalItems === 0">You don't have any subscription yet.</div> 13<div class="no-results" i18n *ngIf="pagination.totalItems === 0">You don't have any subscription yet.</div>
19 14
20<div class="video-channels" myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()" [dataObservable]="onDataSubject.asObservable()"> 15<div class="video-channels" myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()" [dataObservable]="onDataSubject.asObservable()">
21 <div *ngFor="let videoChannel of videoChannels" class="video-channel"> 16 <div *ngFor="let videoChannel of videoChannels" class="video-channel">
22 <a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]"> 17 <my-actor-avatar [channel]="videoChannel" [internalHref]="[ '/video-channels', videoChannel.nameWithHost ]"></my-actor-avatar>
23 <img [src]="videoChannel.avatarUrl" alt="Avatar" />
24 </a>
25 18
26 <div class="video-channel-info"> 19 <div class="video-channel-info">
27 <a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]" class="video-channel-names" i18n-title title="Channel page"> 20 <a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]" class="video-channel-names" i18n-title title="Channel page">
@@ -33,7 +26,8 @@
33 26
34 <a [routerLink]="[ '/accounts', videoChannel.ownerBy ]" i18n-title title="Owner account page" class="actor-owner"> 27 <a [routerLink]="[ '/accounts', videoChannel.ownerBy ]" i18n-title title="Owner account page" class="actor-owner">
35 <span i18n>Created by {{ videoChannel.ownerBy }}</span> 28 <span i18n>Created by {{ videoChannel.ownerBy }}</span>
36 <img [src]="videoChannel.ownerAvatarUrl" alt="Owner account avatar" /> 29
30 <my-actor-avatar [account]="videoChannel.ownerAccount" size="18"></my-actor-avatar>
37 </a> 31 </a>
38 </div> 32 </div>
39 33
diff --git a/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.scss b/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.scss
index 3c1a4d2ad..6c1ddf716 100644
--- a/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.scss
+++ b/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.scss
@@ -8,8 +8,8 @@ input[type=text] {
8.video-channel { 8.video-channel {
9 @include row-blocks; 9 @include row-blocks;
10 10
11 img { 11 > my-actor-avatar {
12 @include channel-avatar(80px); 12 @include actor-avatar-size(80px);
13 13
14 margin-right: 10px; 14 margin-right: 10px;
15 } 15 }
@@ -40,13 +40,25 @@ input[type=text] {
40} 40}
41 41
42.actor-owner { 42.actor-owner {
43 @include actor-owner; 43 @include disable-default-a-behaviour;
44
45 font-size: 13px;
46 color: pvar(--mainForegroundColor);
44 47
45 margin-top: 0; 48 span:hover {
49 opacity: 0.8;
50 }
51
52 my-actor-avatar {
53 margin-left: 7px;
54 display: inline-block;
55 vertical-align: top;
56 }
46} 57}
47 58
48.video-subscriptions-header { 59.video-subscriptions-header {
49 margin-bottom: 30px; 60 margin-bottom: 30px;
61 display: flex;
50} 62}
51 63
52@media screen and (max-width: $small-view) { 64@media screen and (max-width: $small-view) {
diff --git a/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.ts b/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.ts
index 3b748eccf..1f4a931a0 100644
--- a/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.ts
+++ b/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.ts
@@ -1,6 +1,5 @@
1import { Subject } from 'rxjs' 1import { Subject } from 'rxjs'
2import { debounceTime } from 'rxjs/operators' 2import { Component } from '@angular/core'
3import { Component, OnInit } from '@angular/core'
4import { ComponentPagination, Notifier } from '@app/core' 3import { ComponentPagination, Notifier } from '@app/core'
5import { VideoChannel } from '@app/shared/shared-main' 4import { VideoChannel } from '@app/shared/shared-main'
6import { UserSubscriptionService } from '@app/shared/shared-user-subscription' 5import { UserSubscriptionService } from '@app/shared/shared-user-subscription'
@@ -9,7 +8,7 @@ import { UserSubscriptionService } from '@app/shared/shared-user-subscription'
9 templateUrl: './my-subscriptions.component.html', 8 templateUrl: './my-subscriptions.component.html',
10 styleUrls: [ './my-subscriptions.component.scss' ] 9 styleUrls: [ './my-subscriptions.component.scss' ]
11}) 10})
12export class MySubscriptionsComponent implements OnInit { 11export class MySubscriptionsComponent {
13 videoChannels: VideoChannel[] = [] 12 videoChannels: VideoChannel[] = []
14 13
15 pagination: ComponentPagination = { 14 pagination: ComponentPagination = {
@@ -20,34 +19,13 @@ export class MySubscriptionsComponent implements OnInit {
20 19
21 onDataSubject = new Subject<any[]>() 20 onDataSubject = new Subject<any[]>()
22 21
23 subscriptionsSearch: string 22 search: string
24 subscriptionsSearchChanged = new Subject<string>()
25 23
26 constructor ( 24 constructor (
27 private userSubscriptionService: UserSubscriptionService, 25 private userSubscriptionService: UserSubscriptionService,
28 private notifier: Notifier 26 private notifier: Notifier
29 ) {} 27 ) {}
30 28
31 ngOnInit () {
32 this.loadSubscriptions()
33
34 this.subscriptionsSearchChanged
35 .pipe(debounceTime(500))
36 .subscribe(() => {
37 this.pagination.currentPage = 1
38 this.loadSubscriptions(false)
39 })
40 }
41
42 resetSearch () {
43 this.subscriptionsSearch = ''
44 this.onSubscriptionsSearchChanged()
45 }
46
47 onSubscriptionsSearchChanged () {
48 this.subscriptionsSearchChanged.next()
49 }
50
51 onNearOfBottom () { 29 onNearOfBottom () {
52 // Last page 30 // Last page
53 if (this.pagination.totalItems <= (this.pagination.currentPage * this.pagination.itemsPerPage)) return 31 if (this.pagination.totalItems <= (this.pagination.currentPage * this.pagination.itemsPerPage)) return
@@ -56,8 +34,13 @@ export class MySubscriptionsComponent implements OnInit {
56 this.loadSubscriptions() 34 this.loadSubscriptions()
57 } 35 }
58 36
37 onSearch (search: string) {
38 this.search = search
39 this.loadSubscriptions(false)
40 }
41
59 private loadSubscriptions (more = true) { 42 private loadSubscriptions (more = true) {
60 this.userSubscriptionService.listSubscriptions({ pagination: this.pagination, search: this.subscriptionsSearch }) 43 this.userSubscriptionService.listSubscriptions({ pagination: this.pagination, search: this.search })
61 .subscribe( 44 .subscribe(
62 res => { 45 res => {
63 this.videoChannels = more 46 this.videoChannels = more
diff --git a/client/src/app/+my-library/my-video-imports/my-video-imports.component.scss b/client/src/app/+my-library/my-video-imports/my-video-imports.component.scss
index a93c28028..c4b847c3d 100644
--- a/client/src/app/+my-library/my-video-imports/my-video-imports.component.scss
+++ b/client/src/app/+my-library/my-video-imports/my-video-imports.component.scss
@@ -6,7 +6,7 @@ pre {
6} 6}
7 7
8.video-import-error { 8.video-import-error {
9 color: red; 9 color: #ff0000;
10} 10}
11 11
12.badge { 12.badge {
diff --git a/client/src/app/+my-library/my-video-imports/my-video-imports.component.ts b/client/src/app/+my-library/my-video-imports/my-video-imports.component.ts
index d6d7d7a1b..359535526 100644
--- a/client/src/app/+my-library/my-video-imports/my-video-imports.component.ts
+++ b/client/src/app/+my-library/my-video-imports/my-video-imports.component.ts
@@ -62,7 +62,7 @@ export class MyVideoImportsComponent extends RestTable implements OnInit {
62 return '/videos/update/' + video.uuid 62 return '/videos/update/' + video.uuid
63 } 63 }
64 64
65 protected loadData () { 65 protected reloadData () {
66 this.videoImportService.getMyVideoImports(this.pagination, this.sort) 66 this.videoImportService.getMyVideoImports(this.pagination, this.sort)
67 .subscribe( 67 .subscribe(
68 resultList => { 68 resultList => {
diff --git a/client/src/app/+my-library/my-video-playlists/my-video-playlist-elements.component.scss b/client/src/app/+my-library/my-video-playlists/my-video-playlist-elements.component.scss
index 0c68dedf6..67587a58a 100644
--- a/client/src/app/+my-library/my-video-playlists/my-video-playlist-elements.component.scss
+++ b/client/src/app/+my-library/my-video-playlists/my-video-playlist-elements.component.scss
@@ -25,8 +25,8 @@
25} 25}
26 26
27.playlist-buttons { 27.playlist-buttons {
28 display:flex; 28 display: flex;
29 margin: 30px 0 10px 0; 29 margin: 30px 0 10px;
30 30
31 .share-button { 31 .share-button {
32 @include peertube-button; 32 @include peertube-button;
@@ -42,9 +42,10 @@
42.cdk-drag-preview { 42.cdk-drag-preview {
43 box-sizing: border-box; 43 box-sizing: border-box;
44 border-radius: 4px; 44 border-radius: 4px;
45 box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), 45 box-shadow:
46 0 8px 10px 1px rgba(0, 0, 0, 0.14), 46 0 5px 5px -3px rgba(0, 0, 0, 0.2),
47 0 3px 14px 2px rgba(0, 0, 0, 0.12); 47 0 8px 10px 1px rgba(0, 0, 0, 0.14),
48 0 3px 14px 2px rgba(0, 0, 0, 0.12);
48} 49}
49 50
50.cdk-drag-placeholder { 51.cdk-drag-placeholder {
@@ -56,7 +57,7 @@
56} 57}
57 58
58.video:last-child { 59.video:last-child {
59 border: none; 60 border: 0;
60} 61}
61 62
62.videos.cdk-drop-list-dragging .video:not(.cdk-drag-placeholder) { 63.videos.cdk-drop-list-dragging .video:not(.cdk-drag-placeholder) {
diff --git a/client/src/app/+my-library/my-video-playlists/my-video-playlists.component.html b/client/src/app/+my-library/my-video-playlists/my-video-playlists.component.html
index b88ea3db7..309afcf13 100644
--- a/client/src/app/+my-library/my-video-playlists/my-video-playlists.component.html
+++ b/client/src/app/+my-library/my-video-playlists/my-video-playlists.component.html
@@ -4,12 +4,7 @@
4</h1> 4</h1>
5 5
6<div class="video-playlists-header d-flex justify-content-between"> 6<div class="video-playlists-header d-flex justify-content-between">
7 <div class="has-feedback has-clear"> 7 <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter>
8 <input type="text" placeholder="Search your playlists" i18n-placeholder [(ngModel)]="videoPlaylistsSearch"
9 (ngModelChange)="onVideoPlaylistSearchChanged()" />
10 <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetSearch()"></a>
11 <span class="sr-only" i18n>Clear filters</span>
12 </div>
13 8
14 <a class="create-button" routerLink="create"> 9 <a class="create-button" routerLink="create">
15 <my-global-icon iconName="add" aria-hidden="true"></my-global-icon> 10 <my-global-icon iconName="add" aria-hidden="true"></my-global-icon>
diff --git a/client/src/app/+my-library/my-video-playlists/my-video-playlists.component.ts b/client/src/app/+my-library/my-video-playlists/my-video-playlists.component.ts
index f6d394923..d90102693 100644
--- a/client/src/app/+my-library/my-video-playlists/my-video-playlists.component.ts
+++ b/client/src/app/+my-library/my-video-playlists/my-video-playlists.component.ts
@@ -1,7 +1,7 @@
1import { Subject } from 'rxjs' 1import { Subject } from 'rxjs'
2import { debounceTime, mergeMap } from 'rxjs/operators' 2import { mergeMap } from 'rxjs/operators'
3import { Component, OnInit } from '@angular/core' 3import { Component } from '@angular/core'
4import { AuthService, ComponentPagination, ConfirmService, Notifier, User } from '@app/core' 4import { AuthService, ComponentPagination, ConfirmService, Notifier } from '@app/core'
5import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist' 5import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist'
6import { VideoPlaylistType } from '@shared/models' 6import { VideoPlaylistType } from '@shared/models'
7 7
@@ -9,10 +9,8 @@ import { VideoPlaylistType } from '@shared/models'
9 templateUrl: './my-video-playlists.component.html', 9 templateUrl: './my-video-playlists.component.html',
10 styleUrls: [ './my-video-playlists.component.scss' ] 10 styleUrls: [ './my-video-playlists.component.scss' ]
11}) 11})
12export class MyVideoPlaylistsComponent implements OnInit { 12export class MyVideoPlaylistsComponent {
13 videoPlaylistsSearch: string
14 videoPlaylists: VideoPlaylist[] = [] 13 videoPlaylists: VideoPlaylist[] = []
15 videoPlaylistSearchChanged = new Subject<string>()
16 14
17 pagination: ComponentPagination = { 15 pagination: ComponentPagination = {
18 currentPage: 1, 16 currentPage: 1,
@@ -22,27 +20,14 @@ export class MyVideoPlaylistsComponent implements OnInit {
22 20
23 onDataSubject = new Subject<any[]>() 21 onDataSubject = new Subject<any[]>()
24 22
25 private user: User 23 search: string
26 24
27 constructor ( 25 constructor (
28 private authService: AuthService, 26 private authService: AuthService,
29 private notifier: Notifier, 27 private notifier: Notifier,
30 private confirmService: ConfirmService, 28 private confirmService: ConfirmService,
31 private videoPlaylistService: VideoPlaylistService 29 private videoPlaylistService: VideoPlaylistService
32 ) {} 30 ) {}
33
34 ngOnInit () {
35 this.user = this.authService.getUser()
36
37 this.loadVideoPlaylists()
38
39 this.videoPlaylistSearchChanged
40 .pipe(
41 debounceTime(500))
42 .subscribe(() => {
43 this.loadVideoPlaylists(true)
44 })
45 }
46 31
47 async deleteVideoPlaylist (videoPlaylist: VideoPlaylist) { 32 async deleteVideoPlaylist (videoPlaylist: VideoPlaylist) {
48 const res = await this.confirmService.confirm( 33 const res = await this.confirmService.confirm(
@@ -76,22 +61,20 @@ export class MyVideoPlaylistsComponent implements OnInit {
76 this.loadVideoPlaylists() 61 this.loadVideoPlaylists()
77 } 62 }
78 63
79 resetSearch () { 64 onSearch (search: string) {
80 this.videoPlaylistsSearch = '' 65 this.search = search
81 this.onVideoPlaylistSearchChanged() 66 this.loadVideoPlaylists(true)
82 }
83
84 onVideoPlaylistSearchChanged () {
85 this.videoPlaylistSearchChanged.next()
86 } 67 }
87 68
88 private loadVideoPlaylists (reset = false) { 69 private loadVideoPlaylists (reset = false) {
89 this.authService.userInformationLoaded 70 this.authService.userInformationLoaded
90 .pipe(mergeMap(() => { 71 .pipe(mergeMap(() => {
91 return this.videoPlaylistService.listAccountPlaylists(this.user.account, this.pagination, '-updatedAt', this.videoPlaylistsSearch) 72 const user = this.authService.getUser()
92 })) 73
93 .subscribe(res => { 74 return this.videoPlaylistService.listAccountPlaylists(user.account, this.pagination, '-updatedAt', this.search)
75 })).subscribe(res => {
94 if (reset) this.videoPlaylists = [] 76 if (reset) this.videoPlaylists = []
77
95 this.videoPlaylists = this.videoPlaylists.concat(res.data) 78 this.videoPlaylists = this.videoPlaylists.concat(res.data)
96 this.pagination.totalItems = res.total 79 this.pagination.totalItems = res.total
97 80
diff --git a/client/src/app/+my-library/my-videos/modals/video-change-ownership.component.scss b/client/src/app/+my-library/my-videos/modals/video-change-ownership.component.scss
index a79fec179..16187bc4a 100644
--- a/client/src/app/+my-library/my-videos/modals/video-change-ownership.component.scss
+++ b/client/src/app/+my-library/my-videos/modals/video-change-ownership.component.scss
@@ -7,4 +7,4 @@ p-autocomplete {
7 7
8.form-group { 8.form-group {
9 margin: 20px 0; 9 margin: 20px 0;
10} \ No newline at end of file 10}
diff --git a/client/src/app/+my-library/my-videos/my-videos.component.html b/client/src/app/+my-library/my-videos/my-videos.component.html
index e9f436378..8d8b482ad 100644
--- a/client/src/app/+my-library/my-videos/my-videos.component.html
+++ b/client/src/app/+my-library/my-videos/my-videos.component.html
@@ -19,12 +19,7 @@
19</h1> 19</h1>
20 20
21<div class="videos-header d-flex justify-content-between"> 21<div class="videos-header d-flex justify-content-between">
22 <div class="has-feedback has-clear"> 22 <my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter>
23 <input type="text" placeholder="Search your videos" i18n-placeholder [(ngModel)]="videosSearch"
24 (ngModelChange)="onVideosSearchChanged()" />
25 <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetSearch()"></a>
26 <span class="sr-only" i18n>Clear filters</span>
27 </div>
28 23
29 <div class="peertube-select-container peertube-select-button"> 24 <div class="peertube-select-container peertube-select-button">
30 <select [(ngModel)]="sort" (ngModelChange)="onChangeSortColumn()" class="form-control"> 25 <select [(ngModel)]="sort" (ngModelChange)="onChangeSortColumn()" class="form-control">
@@ -46,6 +41,7 @@
46 [titlePage]="titlePage" 41 [titlePage]="titlePage"
47 [getVideosObservableFunction]="getVideosObservableFunction" 42 [getVideosObservableFunction]="getVideosObservableFunction"
48 [user]="user" 43 [user]="user"
44 [loadOnInit]="false"
49 #videosSelection 45 #videosSelection
50> 46>
51 <ng-template ptTemplate="globalButtons"> 47 <ng-template ptTemplate="globalButtons">
@@ -64,6 +60,5 @@
64 </ng-template> 60 </ng-template>
65</my-videos-selection> 61</my-videos-selection>
66 62
67
68<my-video-change-ownership #videoChangeOwnershipModal></my-video-change-ownership> 63<my-video-change-ownership #videoChangeOwnershipModal></my-video-change-ownership>
69<my-live-stream-information #liveStreamInformationModal></my-live-stream-information> 64<my-live-stream-information #liveStreamInformationModal></my-live-stream-information>
diff --git a/client/src/app/+my-library/my-videos/my-videos.component.scss b/client/src/app/+my-library/my-videos/my-videos.component.scss
index aaf21126b..57623c36f 100644
--- a/client/src/app/+my-library/my-videos/my-videos.component.scss
+++ b/client/src/app/+my-library/my-videos/my-videos.component.scss
@@ -26,12 +26,12 @@ h1 {
26} 26}
27 27
28.action-button-delete-selection { 28.action-button-delete-selection {
29 display: inline-block;
30
31 @include peertube-button; 29 @include peertube-button;
32 @include orange-button; 30 @include orange-button;
33 @include button-with-icon(21px); 31 @include button-with-icon(21px);
34 32
33 display: inline-block;
34
35 my-global-icon { 35 my-global-icon {
36 @include apply-svg-color(#fff); 36 @include apply-svg-color(#fff);
37 } 37 }
diff --git a/client/src/app/+my-library/my-videos/my-videos.component.ts b/client/src/app/+my-library/my-videos/my-videos.component.ts
index 356e158d6..1e4a4406d 100644
--- a/client/src/app/+my-library/my-videos/my-videos.component.ts
+++ b/client/src/app/+my-library/my-videos/my-videos.component.ts
@@ -1,10 +1,11 @@
1import { concat, Observable, Subject } from 'rxjs' 1import { concat, Observable } from 'rxjs'
2import { debounceTime, tap, toArray } from 'rxjs/operators' 2import { tap, toArray } from 'rxjs/operators'
3import { Component, OnInit, ViewChild } from '@angular/core' 3import { Component, OnInit, ViewChild } from '@angular/core'
4import { ActivatedRoute, Router } from '@angular/router' 4import { ActivatedRoute, Router } from '@angular/router'
5import { AuthService, ComponentPagination, ConfirmService, Notifier, ScreenService, ServerService, User } from '@app/core' 5import { AuthService, ComponentPagination, ConfirmService, Notifier, ScreenService, ServerService, User } from '@app/core'
6import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook' 6import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook'
7import { immutableAssign } from '@app/helpers' 7import { immutableAssign } from '@app/helpers'
8import { AdvancedInputFilter } from '@app/shared/shared-forms'
8import { DropdownAction, Video, VideoService } from '@app/shared/shared-main' 9import { DropdownAction, Video, VideoService } from '@app/shared/shared-main'
9import { LiveStreamInformationComponent } from '@app/shared/shared-video-live' 10import { LiveStreamInformationComponent } from '@app/shared/shared-video-live'
10import { MiniatureDisplayOptions, SelectionType, VideosSelectionComponent } from '@app/shared/shared-video-miniature' 11import { MiniatureDisplayOptions, SelectionType, VideosSelectionComponent } from '@app/shared/shared-video-miniature'
@@ -40,13 +41,21 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook {
40 videoActions: DropdownAction<{ video: Video }>[] = [] 41 videoActions: DropdownAction<{ video: Video }>[] = []
41 42
42 videos: Video[] = [] 43 videos: Video[] = []
43 videosSearch: string
44 videosSearchChanged = new Subject<string>()
45 getVideosObservableFunction = this.getVideosObservable.bind(this) 44 getVideosObservableFunction = this.getVideosObservable.bind(this)
45
46 sort: VideoSortField = '-publishedAt' 46 sort: VideoSortField = '-publishedAt'
47 47
48 user: User 48 user: User
49 49
50 inputFilters: AdvancedInputFilter[] = [
51 {
52 queryParams: { 'search': 'isLive:true' },
53 label: $localize`Only live videos`
54 }
55 ]
56
57 private search: string
58
50 constructor ( 59 constructor (
51 protected router: Router, 60 protected router: Router,
52 protected serverService: ServerService, 61 protected serverService: ServerService,
@@ -64,21 +73,15 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook {
64 this.buildActions() 73 this.buildActions()
65 74
66 this.user = this.authService.getUser() 75 this.user = this.authService.getUser()
67
68 this.videosSearchChanged
69 .pipe(debounceTime(500))
70 .subscribe(() => {
71 this.videosSelection.reloadVideos()
72 })
73 } 76 }
74 77
75 resetSearch () { 78 onSearch (search: string) {
76 this.videosSearch = '' 79 this.search = search
77 this.onVideosSearchChanged() 80 this.reloadData()
78 } 81 }
79 82
80 onVideosSearchChanged () { 83 reloadData () {
81 this.videosSearchChanged.next() 84 this.videosSelection.reloadVideos()
82 } 85 }
83 86
84 onChangeSortColumn () { 87 onChangeSortColumn () {
@@ -96,7 +99,7 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook {
96 getVideosObservable (page: number) { 99 getVideosObservable (page: number) {
97 const newPagination = immutableAssign(this.pagination, { currentPage: page }) 100 const newPagination = immutableAssign(this.pagination, { currentPage: page })
98 101
99 return this.videoService.getMyVideos(newPagination, this.sort, this.videosSearch) 102 return this.videoService.getMyVideos(newPagination, this.sort, this.search)
100 .pipe( 103 .pipe(
101 tap(res => this.pagination.totalItems = res.total) 104 tap(res => this.pagination.totalItems = res.total)
102 ) 105 )