Add ability to list redundancies
[oweals/peertube.git] / client / src / app / +admin / follows / video-redundancies-list / video-redundancies-list.component.ts
1 import { Component, OnInit } from '@angular/core'
2 import { Notifier, ServerService } from '@app/core'
3 import { SortMeta } from 'primeng/api'
4 import { ConfirmService } from '../../../core/confirm/confirm.service'
5 import { RestPagination, RestTable } from '../../../shared'
6 import { I18n } from '@ngx-translate/i18n-polyfill'
7 import { VideoRedundanciesTarget, VideoRedundancy } from '@shared/models'
8 import { peertubeLocalStorage } from '@app/shared/misc/peertube-web-storage'
9 import { VideosRedundancyStats } from '@shared/models/server'
10 import { BytesPipe } from 'ngx-pipes'
11 import { RedundancyService } from '@app/shared/video/redundancy.service'
12
13 @Component({
14   selector: 'my-video-redundancies-list',
15   templateUrl: './video-redundancies-list.component.html',
16   styleUrls: [ './video-redundancies-list.component.scss' ]
17 })
18 export class VideoRedundanciesListComponent extends RestTable implements OnInit {
19   private static LOCAL_STORAGE_DISPLAY_TYPE = 'video-redundancies-list-display-type'
20
21   videoRedundancies: VideoRedundancy[] = []
22   totalRecords = 0
23   rowsPerPage = 10
24
25   sort: SortMeta = { field: 'name', order: 1 }
26   pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
27   displayType: VideoRedundanciesTarget = 'my-videos'
28
29   redundanciesGraphsData: { stats: VideosRedundancyStats, graphData: object, options: object }[] = []
30
31   noRedundancies = false
32
33   private bytesPipe: BytesPipe
34
35   constructor (
36     private notifier: Notifier,
37     private confirmService: ConfirmService,
38     private redundancyService: RedundancyService,
39     private serverService: ServerService,
40     private i18n: I18n
41   ) {
42     super()
43
44     this.bytesPipe = new BytesPipe()
45   }
46
47   ngOnInit () {
48     this.loadSelectLocalStorage()
49
50     this.initialize()
51
52     this.serverService.getServerStats()
53         .subscribe(res => {
54           const redundancies = res.videosRedundancy
55
56           if (redundancies.length === 0) this.noRedundancies = true
57
58           for (const r of redundancies) {
59             this.buildPieData(r)
60           }
61         })
62   }
63
64   isDisplayingRemoteVideos () {
65     return this.displayType === 'remote-videos'
66   }
67
68   getTotalSize (redundancy: VideoRedundancy) {
69     return redundancy.redundancies.files.reduce((a, b) => a + b.size, 0) +
70       redundancy.redundancies.streamingPlaylists.reduce((a, b) => a + b.size, 0)
71   }
72
73   onDisplayTypeChanged () {
74     this.pagination.start = 0
75     this.saveSelectLocalStorage()
76
77     this.loadData()
78   }
79
80   getRedundancyStrategy (redundancy: VideoRedundancy) {
81     if (redundancy.redundancies.files.length !== 0) return redundancy.redundancies.files[0].strategy
82     if (redundancy.redundancies.streamingPlaylists.length !== 0) return redundancy.redundancies.streamingPlaylists[0].strategy
83
84     return ''
85   }
86
87   buildPieData (stats: VideosRedundancyStats) {
88     const totalSize = stats.totalSize
89       ? stats.totalSize - stats.totalUsed
90       : stats.totalUsed
91
92     if (totalSize === 0) return
93
94     this.redundanciesGraphsData.push({
95       stats,
96       graphData: {
97         labels: [ this.i18n('Used'), this.i18n('Available') ],
98         datasets: [
99           {
100             data: [ stats.totalUsed, totalSize ],
101             backgroundColor: [
102               '#FF6384',
103               '#36A2EB'
104             ],
105             hoverBackgroundColor: [
106               '#FF6384',
107               '#36A2EB'
108             ]
109           }
110         ]
111       },
112       options: {
113         title: {
114           display: true,
115           text: stats.strategy
116         },
117
118         tooltips: {
119           callbacks: {
120             label: (tooltipItem: any, data: any) => {
121               const dataset = data.datasets[tooltipItem.datasetIndex]
122               let label = data.labels[tooltipItem.index]
123               if (label) label += ': '
124               else label = ''
125
126               label += this.bytesPipe.transform(dataset.data[tooltipItem.index], 1)
127               return label
128             }
129           }
130         }
131       }
132     })
133   }
134
135   async removeRedundancy (redundancy: VideoRedundancy) {
136     const message = this.i18n('Do you really want to remove this video redundancy?')
137     const res = await this.confirmService.confirm(message, this.i18n('Remove redundancy'))
138     if (res === false) return
139
140     this.redundancyService.removeVideoRedundancies(redundancy)
141       .subscribe(
142         () => {
143           this.notifier.success(this.i18n('Video redundancies removed!'))
144           this.loadData()
145         },
146
147         err => this.notifier.error(err.message)
148       )
149
150   }
151
152   protected loadData () {
153     const options = {
154       pagination: this.pagination,
155       sort: this.sort,
156       target: this.displayType
157     }
158
159     this.redundancyService.listVideoRedundancies(options)
160                       .subscribe(
161                         resultList => {
162                           this.videoRedundancies = resultList.data
163                           this.totalRecords = resultList.total
164                         },
165
166                         err => this.notifier.error(err.message)
167                       )
168   }
169
170   private loadSelectLocalStorage () {
171     const displayType = peertubeLocalStorage.getItem(VideoRedundanciesListComponent.LOCAL_STORAGE_DISPLAY_TYPE)
172     if (displayType) this.displayType = displayType as VideoRedundanciesTarget
173   }
174
175   private saveSelectLocalStorage () {
176     peertubeLocalStorage.setItem(VideoRedundanciesListComponent.LOCAL_STORAGE_DISPLAY_TYPE, this.displayType)
177   }
178 }