]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Infinite scroll to list our subscriptions
authorChocobozzz <me@florianbigard.com>
Fri, 24 Aug 2018 08:31:56 +0000 (10:31 +0200)
committerChocobozzz <me@florianbigard.com>
Mon, 27 Aug 2018 07:41:54 +0000 (09:41 +0200)
client/src/app/+my-account/my-account-subscriptions/my-account-subscriptions.component.html
client/src/app/+my-account/my-account-subscriptions/my-account-subscriptions.component.ts
client/src/app/+my-account/my-account-video-imports/my-account-video-imports.component.html
client/src/app/search/search.component.html
client/src/app/search/search.component.ts
client/src/app/shared/user-subscription/user-subscription.service.ts
client/src/app/shared/video/infinite-scroller.directive.ts
client/src/app/videos/+video-watch/comment/video-comments.component.html
server/models/activitypub/actor-follow.ts
server/models/activitypub/actor.ts

index 4c68cd1a520e1a777cf81aebeab5c3a775ea4e7d..3752de49f662554d7a08d8533ce4db08a1878a6c 100644 (file)
@@ -1,4 +1,4 @@
-<div class="video-channels">
+<div class="video-channels" myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()">
   <div *ngFor="let videoChannel of videoChannels" class="video-channel">
     <a [routerLink]="[ '/video-channels', videoChannel.name ]">
       <img [src]="videoChannel.avatarUrl" alt="Avatar" />
index 9434b196fc3c160513d3c0bba57ef7e3780dc837..9517a37059fbc97d9f9f5ba224c529a391ea2ae6 100644 (file)
@@ -3,6 +3,7 @@ import { NotificationsService } from 'angular2-notifications'
 import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
 import { I18n } from '@ngx-translate/i18n-polyfill'
 import { UserSubscriptionService } from '@app/shared/user-subscription'
+import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
 
 @Component({
   selector: 'my-account-subscriptions',
@@ -12,6 +13,12 @@ import { UserSubscriptionService } from '@app/shared/user-subscription'
 export class MyAccountSubscriptionsComponent implements OnInit {
   videoChannels: VideoChannel[] = []
 
+  pagination: ComponentPagination = {
+    currentPage: 1,
+    itemsPerPage: 10,
+    totalItems: null
+  }
+
   constructor (
     private userSubscriptionService: UserSubscriptionService,
     private notificationsService: NotificationsService,
@@ -19,12 +26,27 @@ export class MyAccountSubscriptionsComponent implements OnInit {
   ) {}
 
   ngOnInit () {
-    this.userSubscriptionService.listSubscriptions()
-      .subscribe(
-        res => this.videoChannels = res.data,
+    this.loadSubscriptions()
+  }
+
+  loadSubscriptions () {
+    this.userSubscriptionService.listSubscriptions(this.pagination)
+        .subscribe(
+          res => {
+            this.videoChannels = this.videoChannels.concat(res.data)
+            this.pagination.totalItems = res.total
+          },
+
+          error => this.notificationsService.error(this.i18n('Error'), error.message)
+        )
+  }
+
+  onNearOfBottom () {
+    // Last page
+    if (this.pagination.totalItems <= (this.pagination.currentPage * this.pagination.itemsPerPage)) return
 
-        error => this.notificationsService.error(this.i18n('Error'), error.message)
-      )
+    this.pagination.currentPage += 1
+    this.loadSubscriptions()
   }
 
 }
index b2b6c3d609ba58c410bfb036ec87c84c9d18dfbe..329948cb5514f8099e11c4303727a7b5d7702be6 100644 (file)
       </td>
 
       <td *ngIf="isVideoImportPending(videoImport)">
-        {{ videoImport.video.name }}
+        {{ videoImport.video?.name }}
       </td>
-      <td *ngIf="isVideoImportSuccess(videoImport)">
-        <a [href]="getVideoUrl(videoImport.video)" target="_blank" rel="noopener noreferrer">{{ videoImport.video.name }}</a>
+      <td *ngIf="isVideoImportSuccess(videoImport) && videoImport.video">
+        <a [href]="getVideoUrl(videoImport.video)" target="_blank" rel="noopener noreferrer">{{ videoImport.video?.name }}</a>
       </td>
       <td *ngIf="isVideoImportFailed(videoImport)"></td>
 
@@ -40,7 +40,7 @@
       <td>{{ videoImport.createdAt }}</td>
 
       <td class="action-cell">
-        <my-edit-button *ngIf="isVideoImportSuccess(videoImport)" [routerLink]="getEditVideoUrl(videoImport.video)"></my-edit-button>
+        <my-edit-button *ngIf="isVideoImportSuccess(videoImport) && videoImport.video" [routerLink]="getEditVideoUrl(videoImport.video)"></my-edit-button>
       </td>
     </tr>
   </ng-template>
index 128cc52f5ade5006ad51e4b0d8abeb5f7b1c7e6a..83d014987321392495796220f0d4533aaa732793 100644 (file)
@@ -1,4 +1,4 @@
-<div myInfiniteScroller [autoLoading]="true" (nearOfBottom)="onNearOfBottom()" class="search-result">
+<div myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()" class="search-result">
   <div class="results-header">
     <div class="first-line">
       <div class="results-counter" *ngIf="pagination.totalItems">
index f88df639109f91017885b806e929ad1993f85dad..ed84e24d9fbb8cf3d512d636552066b0304b7eee 100644 (file)
@@ -87,9 +87,17 @@ export class SearchComponent implements OnInit, OnDestroy {
       .subscribe(
         ([ videosResult, videoChannelsResult ]) => {
           this.videos = this.videos.concat(videosResult.videos)
-          this.pagination.totalItems = videosResult.totalVideos
+          this.pagination.totalItems = videosResult.totalVideos + videoChannelsResult.total
 
-          this.videoChannels = videoChannelsResult.data
+          this.videoChannels = this.videoChannels.concat(videoChannelsResult.data)
+
+          // Focus on channels
+          if (this.channelsPerPage !== 10 && this.videos.length < this.pagination.itemsPerPage) {
+            this.resetPagination()
+
+            this.channelsPerPage = 10
+            this.search()
+          }
         },
 
         error => {
@@ -116,8 +124,10 @@ export class SearchComponent implements OnInit, OnDestroy {
   private resetPagination () {
     this.pagination.currentPage = 1
     this.pagination.totalItems = null
+    this.channelsPerPage = 2
 
     this.videos = []
+    this.videoChannels = []
   }
 
   private updateTitle () {
index cf622019f638e9d05325340c9ece9937e44d44ea..3d05f071e6a9d42421455abe6274cb491fd1179d 100644 (file)
@@ -1,4 +1,4 @@
-import { bufferTime, catchError, filter, map, share, switchMap, tap } from 'rxjs/operators'
+import { bufferTime, catchError, filter, first, map, share, switchMap } from 'rxjs/operators'
 import { HttpClient, HttpParams } from '@angular/common/http'
 import { Injectable } from '@angular/core'
 import { ResultList } from '../../../../../shared'
@@ -8,6 +8,7 @@ import { Observable, ReplaySubject, Subject } from 'rxjs'
 import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
 import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
 import { VideoChannel as VideoChannelServer } from '../../../../../shared/models/videos'
+import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
 
 type SubscriptionExistResult = { [ uri: string ]: boolean }
 
@@ -17,7 +18,7 @@ export class UserSubscriptionService {
 
   // Use a replay subject because we "next" a value before subscribing
   private existsSubject: Subject<string> = new ReplaySubject(1)
-  private existsObservable: Observable<SubscriptionExistResult>
+  private readonly existsObservable: Observable<SubscriptionExistResult>
 
   constructor (
     private authHttp: HttpClient,
@@ -25,7 +26,6 @@ export class UserSubscriptionService {
     private restService: RestService
   ) {
     this.existsObservable = this.existsSubject.pipe(
-      tap(u => console.log(u)),
       bufferTime(500),
       filter(uris => uris.length !== 0),
       switchMap(uris => this.areSubscriptionExist(uris)),
@@ -54,10 +54,15 @@ export class UserSubscriptionService {
                )
   }
 
-  listSubscriptions (): Observable<ResultList<VideoChannel>> {
+  listSubscriptions (componentPagination: ComponentPagination): Observable<ResultList<VideoChannel>> {
     const url = UserSubscriptionService.BASE_USER_SUBSCRIPTIONS_URL
 
-    return this.authHttp.get<ResultList<VideoChannelServer>>(url)
+    const pagination = this.restService.componentPaginationToRestPagination(componentPagination)
+
+    let params = new HttpParams()
+    params = this.restService.addRestGetParams(params, pagination)
+
+    return this.authHttp.get<ResultList<VideoChannelServer>>(url, { params })
                .pipe(
                  map(res => VideoChannelService.extractVideoChannels(res)),
                  catchError(err => this.restExtractor.handleError(err))
@@ -67,11 +72,10 @@ export class UserSubscriptionService {
   isSubscriptionExists (nameWithHost: string) {
     this.existsSubject.next(nameWithHost)
 
-    return this.existsObservable
+    return this.existsObservable.pipe(first())
   }
 
   private areSubscriptionExist (uris: string[]): Observable<SubscriptionExistResult> {
-    console.log(uris)
     const url = UserSubscriptionService.BASE_USER_SUBSCRIPTIONS_URL + '/exist'
     let params = new HttpParams()
 
index 0448e2c2309942f3dc900e1eb8a191f6c0f850ae..4dc1f86e7a36817518740644ad55aed2a4027d8b 100644 (file)
@@ -11,7 +11,7 @@ export class InfiniteScrollerDirective implements OnInit, OnDestroy {
   @Input() containerHeight: number
   @Input() pageHeight: number
   @Input() percentLimit = 70
-  @Input() autoLoading = false
+  @Input() autoInit = false
 
   @Output() nearOfBottom = new EventEmitter<void>()
   @Output() nearOfTop = new EventEmitter<void>()
@@ -29,7 +29,7 @@ export class InfiniteScrollerDirective implements OnInit, OnDestroy {
   }
 
   ngOnInit () {
-    if (this.autoLoading === true) return this.initialize()
+    if (this.autoInit === true) return this.initialize()
   }
 
   ngOnDestroy () {
index 8871980e9371e5f3b0c3cf33ad9246b035b121d0..bf6706ed386053c6301ad688c9a243787a1d3939 100644 (file)
@@ -21,7 +21,7 @@
     <div
       class="comment-threads"
       myInfiniteScroller
-      [autoLoading]="true"
+      [autoInit]="true"
       (nearOfBottom)="onNearOfBottom()"
     >
       <div #commentHighlightBlock id="highlighted-comment">
index 81fcf700187fd86160116d0dc30548849b10a027..ebb2d47c263bba185c82220ef514e98de3194683 100644 (file)
@@ -169,9 +169,6 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
 
   static loadByActorAndTargetNameAndHostForAPI (actorId: number, targetName: string, targetHost: string, t?: Sequelize.Transaction) {
     const actorFollowingPartInclude: IIncludeOptions = {
-      attributes: {
-        exclude: unusedActorAttributesForAPI
-      },
       model: ActorModel,
       required: true,
       as: 'ActorFollowing',
@@ -203,7 +200,12 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
         actorId
       },
       include: [
-        actorFollowingPartInclude
+        actorFollowingPartInclude,
+        {
+          model: ActorModel,
+          required: true,
+          as: 'ActorFollower'
+        }
       ],
       transaction: t
     }
index ec0b4b2d93ac3d944a6c34ab3e43131f9750a93f..e16bd5d7943de0b36e55cba50e56c64ea58e7516 100644 (file)
@@ -49,7 +49,8 @@ export const unusedActorAttributesForAPI = [
   'outboxUrl',
   'sharedInboxUrl',
   'followersUrl',
-  'followingUrl'
+  'followingUrl',
+  'url'
 ]
 
 @DefaultScope({
@@ -322,45 +323,6 @@ export class ActorModel extends Model<ActorModel> {
     })
   }
 
-  static async getActorsFollowerSharedInboxUrls (actors: ActorModel[], t: Sequelize.Transaction) {
-    const query = {
-      // attribute: [],
-      where: {
-        id: {
-          [Sequelize.Op.in]: actors.map(a => a.id)
-        }
-      },
-      include: [
-        {
-          // attributes: [ ],
-          model: ActorFollowModel.unscoped(),
-          required: true,
-          as: 'ActorFollowers',
-          where: {
-            state: 'accepted'
-          },
-          include: [
-            {
-              attributes: [ 'sharedInboxUrl' ],
-              model: ActorModel.unscoped(),
-              as: 'ActorFollower',
-              required: true
-            }
-          ]
-        }
-      ],
-      transaction: t
-    }
-
-    const hash: { [ id: number ]: string[] } = {}
-    const res = await ActorModel.findAll(query)
-    for (const actor of res) {
-      hash[actor.id] = actor.ActorFollowers.map(follow => follow.ActorFollower.sharedInboxUrl)
-    }
-
-    return hash
-  }
-
   toFormattedJSON () {
     let avatar: Avatar = null
     if (this.Avatar) {