--- /dev/null
+<div class="row" myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()">
+ <div class="col-xl-6 col-md-12">
+ <div i18n class="subtitle">Followers</div>
+
+ <div i18n class="no-results" *ngIf="followersPagination.totalItems === 0">This instance does not have followers.</div>
+
+ <a *ngFor="let follower of followers" [href]="buildLink(follower)" target="_blank" rel="noopener noreferrer">
+ {{ follower }}
+ </a>
+ </div>
+
+ <div class="col-xl-6 col-md-12">
+ <div i18n class="subtitle">Followings</div>
+
+ <div i18n class="no-results" *ngIf="followingsPagination.totalItems === 0">This instance does not have followings.</div>
+
+ <a *ngFor="let following of followings" [href]="buildLink(following)" target="_blank" rel="noopener noreferrer">
+ {{ following }}
+ </a>
+ </div>
+
+</div>
--- /dev/null
+@import '_variables';
+@import '_mixins';
+
+.subtitle {
+ font-size: 18px;
+ font-weight: $font-semibold;
+ margin-bottom: 20px;
+}
+
+a {
+ display: block;
+ width: fit-content;
+ margin-top: 3px;
+}
--- /dev/null
+import { Component, OnInit } from '@angular/core'
+import { FollowService } from '@app/shared/instance/follow.service'
+import { ComponentPagination, hasMoreItems } from '@app/shared/rest/component-pagination.model'
+import { Notifier } from '@app/core'
+import { RestService } from '@app/shared'
+import { SortMeta } from 'primeng/api'
+
+@Component({
+ selector: 'my-about-follows',
+ templateUrl: './about-follows.component.html',
+ styleUrls: [ './about-follows.component.scss' ]
+})
+
+export class AboutFollowsComponent implements OnInit {
+ followers: string[] = []
+ followings: string[] = []
+
+ followersPagination: ComponentPagination = {
+ currentPage: 1,
+ itemsPerPage: 40,
+ totalItems: null
+ }
+
+ followingsPagination: ComponentPagination = {
+ currentPage: 1,
+ itemsPerPage: 40,
+ totalItems: null
+ }
+
+ sort: SortMeta = {
+ field: 'createdAt',
+ order: -1
+ }
+
+ constructor (
+ private restService: RestService,
+ private notifier: Notifier,
+ private followService: FollowService
+ ) { }
+
+ ngOnInit () {
+ this.loadMoreFollowers()
+
+ this.loadMoreFollowings()
+ }
+
+ onNearOfBottom () {
+ this.onNearOfFollowersBottom()
+
+ this.onNearOfFollowingsBottom()
+ }
+
+ onNearOfFollowersBottom () {
+ if (!hasMoreItems(this.followersPagination)) return
+
+ this.followersPagination.currentPage += 1
+ this.loadMoreFollowers()
+ }
+
+ onNearOfFollowingsBottom () {
+ if (!hasMoreItems(this.followingsPagination)) return
+
+ this.followingsPagination.currentPage += 1
+ this.loadMoreFollowings()
+ }
+
+ buildLink (host: string) {
+ return window.location.protocol + '//' + host
+ }
+
+ private loadMoreFollowers () {
+ const pagination = this.restService.componentPaginationToRestPagination(this.followersPagination)
+
+ this.followService.getFollowers(pagination, this.sort)
+ .subscribe(
+ resultList => {
+ const newFollowers = resultList.data.map(r => r.follower.host)
+ this.followers = this.followers.concat(newFollowers)
+
+ this.followersPagination.totalItems = resultList.total
+ },
+
+ err => this.notifier.error(err.message)
+ )
+ }
+
+ private loadMoreFollowings () {
+ const pagination = this.restService.componentPaginationToRestPagination(this.followingsPagination)
+
+ this.followService.getFollowing(pagination, this.sort)
+ .subscribe(
+ resultList => {
+ const newFollowings = resultList.data.map(r => r.following.host)
+ this.followings = this.followings.concat(newFollowings)
+
+ this.followingsPagination.totalItems = resultList.total
+ },
+
+ err => this.notifier.error(err.message)
+ )
+ }
+
+}
import { AboutComponent } from './about.component'
import { AboutInstanceComponent } from '@app/+about/about-instance/about-instance.component'
import { AboutPeertubeComponent } from '@app/+about/about-peertube/about-peertube.component'
+import { AboutFollowsComponent } from '@app/+about/about-follows/about-follows.component'
const aboutRoutes: Routes = [
{
title: 'About PeerTube'
}
}
+ },
+ {
+ path: 'follows',
+ component: AboutFollowsComponent,
+ data: {
+ meta: {
+ title: 'About follows'
+ }
+ }
}
]
}
<a i18n routerLink="instance" routerLinkActive="active" class="title-page">Instance</a>
<a i18n routerLink="peertube" routerLinkActive="active" class="title-page">PeerTube</a>
+
+ <a i18n routerLink="follows" routerLinkActive="active" class="title-page">Follows</a>
</div>
</div>
<div class="margin-content">
<router-outlet></router-outlet>
</div>
-</div>
\ No newline at end of file
+</div>
import { AboutInstanceComponent } from '@app/+about/about-instance/about-instance.component'
import { AboutPeertubeComponent } from '@app/+about/about-peertube/about-peertube.component'
import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-admin-modal.component'
+import { AboutFollowsComponent } from '@app/+about/about-follows/about-follows.component'
@NgModule({
imports: [
AboutComponent,
AboutInstanceComponent,
AboutPeertubeComponent,
+ AboutFollowsComponent,
ContactAdminModalComponent
],
import { SharedModule } from '../shared'
import { AdminRoutingModule } from './admin-routing.module'
import { AdminComponent } from './admin.component'
-import { FollowersListComponent, FollowingAddComponent, FollowsComponent, FollowService } from './follows'
+import { FollowersListComponent, FollowingAddComponent, FollowsComponent } from './follows'
import { FollowingListComponent } from './follows/following-list/following-list.component'
import { UserCreateComponent, UserListComponent, UserPasswordComponent, UsersComponent, UserUpdateComponent } from './users'
import {
],
providers: [
- FollowService,
RedundancyService,
JobService,
LogsService,
import { SortMeta } from 'primeng/primeng'
import { ActorFollow } from '../../../../../../shared/models/actors/follow.model'
import { RestPagination, RestTable } from '../../../shared'
-import { FollowService } from '../shared'
+import { FollowService } from '@app/shared/instance/follow.service'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({
import { Notifier } from '@app/core'
import { ConfirmService } from '../../../core'
import { validateHost } from '../../../shared'
-import { FollowService } from '../shared'
+import { FollowService } from '@app/shared/instance/follow.service'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({
import { ActorFollow } from '../../../../../../shared/models/actors/follow.model'
import { ConfirmService } from '../../../core/confirm/confirm.service'
import { RestPagination, RestTable } from '../../../shared'
-import { FollowService } from '../shared'
+import { FollowService } from '@app/shared/instance/follow.service'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({
export * from './following-add'
export * from './followers-list'
export * from './following-list'
-export * from './shared'
export * from './follows.component'
export * from './follows.routes'
+++ /dev/null
-export * from './follow.service'
import { Injectable } from '@angular/core'
import { SortMeta } from 'primeng/primeng'
import { Observable } from 'rxjs'
-import { ActorFollow, ResultList } from '../../../../../../shared'
-import { environment } from '../../../../environments/environment'
-import { RestExtractor, RestPagination, RestService } from '../../../shared'
+import { ActorFollow, ResultList } from '@shared/index'
+import { environment } from '../../../environments/environment'
+import { RestExtractor, RestPagination, RestService } from '../rest'
@Injectable()
export class FollowService {
- private static BASE_APPLICATION_URL = environment.apiUrl + '/api/v1/server'
+ private static BASE_APPLICATION_URL = 'https://peertube2.cpy.re' + '/api/v1/server'
constructor (
private authHttp: HttpClient,
import { VideoDownloadComponent } from '@app/shared/video/modals/video-download.component'
import { VideoReportComponent } from '@app/shared/video/modals/video-report.component'
import { ClipboardModule } from 'ngx-clipboard'
+import { FollowService } from '@app/shared/instance/follow.service'
@NgModule({
imports: [
UserNotificationService,
+ FollowService,
+
I18n
]
})
{{ getCurrentGroupedDateLabel(video) }}
</div>
-
<my-video-miniature
[video]="video" [user]="user" [ownerDisplayType]="ownerDisplayType"
[displayVideoActions]="displayVideoActions" [displayOptions]="displayOptions"