diff options
author | Chocobozzz <me@florianbigard.com> | 2019-04-10 15:26:33 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2019-04-10 16:38:32 +0200 |
commit | fd8710b897a67518d3a61c319e54b6a65ba443ef (patch) | |
tree | d9953b7e0bb4e5a119c872ab21021f4c1ab33bea /client/src/app/+admin/system | |
parent | 31b6ddf86652502e0c96d77fa10861ce4af11aa4 (diff) | |
download | PeerTube-fd8710b897a67518d3a61c319e54b6a65ba443ef.tar.gz PeerTube-fd8710b897a67518d3a61c319e54b6a65ba443ef.tar.zst PeerTube-fd8710b897a67518d3a61c319e54b6a65ba443ef.zip |
Add logs endpoint
Diffstat (limited to 'client/src/app/+admin/system')
-rw-r--r-- | client/src/app/+admin/system/jobs/index.ts | 4 | ||||
-rw-r--r-- | client/src/app/+admin/system/jobs/job.service.ts | 46 | ||||
-rw-r--r-- | client/src/app/+admin/system/jobs/jobs.component.html | 56 | ||||
-rw-r--r-- | client/src/app/+admin/system/jobs/jobs.component.scss | 14 | ||||
-rw-r--r-- | client/src/app/+admin/system/jobs/jobs.component.ts | 69 |
5 files changed, 189 insertions, 0 deletions
diff --git a/client/src/app/+admin/system/jobs/index.ts b/client/src/app/+admin/system/jobs/index.ts new file mode 100644 index 000000000..c0e0cc95d --- /dev/null +++ b/client/src/app/+admin/system/jobs/index.ts | |||
@@ -0,0 +1,4 @@ | |||
1 | export * from './shared' | ||
2 | export * from './jobs-list' | ||
3 | export * from './job.routes' | ||
4 | export * from './job.component' | ||
diff --git a/client/src/app/+admin/system/jobs/job.service.ts b/client/src/app/+admin/system/jobs/job.service.ts new file mode 100644 index 000000000..b96dc3359 --- /dev/null +++ b/client/src/app/+admin/system/jobs/job.service.ts | |||
@@ -0,0 +1,46 @@ | |||
1 | import { catchError, map } from 'rxjs/operators' | ||
2 | import { HttpClient, HttpParams } from '@angular/common/http' | ||
3 | import { Injectable } from '@angular/core' | ||
4 | import { SortMeta } from 'primeng/primeng' | ||
5 | import { Observable } from 'rxjs' | ||
6 | import { ResultList } from '../../../../../../shared' | ||
7 | import { JobState } from '../../../../../../shared/models' | ||
8 | import { Job } from '../../../../../../shared/models/server/job.model' | ||
9 | import { environment } from '../../../../environments/environment' | ||
10 | import { RestExtractor, RestPagination, RestService } from '../../../shared' | ||
11 | |||
12 | @Injectable() | ||
13 | export class JobService { | ||
14 | private static BASE_JOB_URL = environment.apiUrl + '/api/v1/jobs' | ||
15 | |||
16 | constructor ( | ||
17 | private authHttp: HttpClient, | ||
18 | private restService: RestService, | ||
19 | private restExtractor: RestExtractor | ||
20 | ) {} | ||
21 | |||
22 | getJobs (state: JobState, pagination: RestPagination, sort: SortMeta): Observable<ResultList<Job>> { | ||
23 | let params = new HttpParams() | ||
24 | params = this.restService.addRestGetParams(params, pagination, sort) | ||
25 | |||
26 | return this.authHttp.get<ResultList<Job>>(JobService.BASE_JOB_URL + '/' + state, { params }) | ||
27 | .pipe( | ||
28 | map(res => { | ||
29 | return this.restExtractor.convertResultListDateToHuman(res, [ 'createdAt', 'processedOn', 'finishedOn' ]) | ||
30 | }), | ||
31 | map(res => this.restExtractor.applyToResultListData(res, this.prettyPrintData)), | ||
32 | map(res => this.restExtractor.applyToResultListData(res, this.buildUniqId)), | ||
33 | catchError(err => this.restExtractor.handleError(err)) | ||
34 | ) | ||
35 | } | ||
36 | |||
37 | private prettyPrintData (obj: Job) { | ||
38 | const data = JSON.stringify(obj.data, null, 2) | ||
39 | |||
40 | return Object.assign(obj, { data }) | ||
41 | } | ||
42 | |||
43 | private buildUniqId (obj: Job) { | ||
44 | return Object.assign(obj, { uniqId: `${obj.id}-${obj.type}` }) | ||
45 | } | ||
46 | } | ||
diff --git a/client/src/app/+admin/system/jobs/jobs.component.html b/client/src/app/+admin/system/jobs/jobs.component.html new file mode 100644 index 000000000..7ed1888e2 --- /dev/null +++ b/client/src/app/+admin/system/jobs/jobs.component.html | |||
@@ -0,0 +1,56 @@ | |||
1 | <div class="admin-sub-header"> | ||
2 | <div i18n class="form-sub-title">Jobs list</div> | ||
3 | |||
4 | <div class="peertube-select-container"> | ||
5 | <select [(ngModel)]="jobState" (ngModelChange)="onJobStateChanged()"> | ||
6 | <option *ngFor="let state of jobStates" [value]="state">{{ state }}</option> | ||
7 | </select> | ||
8 | </div> | ||
9 | </div> | ||
10 | |||
11 | <p-table | ||
12 | [value]="jobs" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" dataKey="uniqId" | ||
13 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" [first]="pagination.start" | ||
14 | > | ||
15 | <ng-template pTemplate="header"> | ||
16 | <tr> | ||
17 | <th style="width: 27px"></th> | ||
18 | <th i18n style="width: 60px">ID</th> | ||
19 | <th i18n style="width: 210px">Type</th> | ||
20 | <th i18n style="width: 130px">State</th> | ||
21 | <th i18n style="width: 250px" pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th> | ||
22 | <th i18n style="width: 250px">Processed on</th> | ||
23 | <th i18n style="width: 250px">Finished on</th> | ||
24 | </tr> | ||
25 | </ng-template> | ||
26 | |||
27 | <ng-template pTemplate="body" let-expanded="expanded" let-job> | ||
28 | <tr> | ||
29 | <td> | ||
30 | <span class="expander" [pRowToggler]="job"> | ||
31 | <i [ngClass]="expanded ? 'glyphicon glyphicon-menu-down' : 'glyphicon glyphicon-menu-right'"></i> | ||
32 | </span> | ||
33 | </td> | ||
34 | <td>{{ job.id }}</td> | ||
35 | <td>{{ job.type }}</td> | ||
36 | <td>{{ job.state }}</td> | ||
37 | <td>{{ job.createdAt }}</td> | ||
38 | <td>{{ job.processedOn }}</td> | ||
39 | <td>{{ job.finishedOn }}</td> | ||
40 | </tr> | ||
41 | </ng-template> | ||
42 | |||
43 | <ng-template pTemplate="rowexpansion" let-job> | ||
44 | <tr> | ||
45 | <td colspan="7"> | ||
46 | <pre>{{ job.data }}</pre> | ||
47 | </td> | ||
48 | </tr> | ||
49 | <tr class="job-error" *ngIf="job.error"> | ||
50 | <td colspan="7"> | ||
51 | <pre>{{ job.error }}</pre> | ||
52 | </td> | ||
53 | </tr> | ||
54 | </ng-template> | ||
55 | </p-table> | ||
56 | |||
diff --git a/client/src/app/+admin/system/jobs/jobs.component.scss b/client/src/app/+admin/system/jobs/jobs.component.scss new file mode 100644 index 000000000..ab05f1982 --- /dev/null +++ b/client/src/app/+admin/system/jobs/jobs.component.scss | |||
@@ -0,0 +1,14 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | .peertube-select-container { | ||
5 | @include peertube-select-container(auto); | ||
6 | } | ||
7 | |||
8 | pre { | ||
9 | font-size: 11px; | ||
10 | } | ||
11 | |||
12 | .job-error { | ||
13 | color: red; | ||
14 | } | ||
diff --git a/client/src/app/+admin/system/jobs/jobs.component.ts b/client/src/app/+admin/system/jobs/jobs.component.ts new file mode 100644 index 000000000..b265e1dd6 --- /dev/null +++ b/client/src/app/+admin/system/jobs/jobs.component.ts | |||
@@ -0,0 +1,69 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | ||
2 | import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' | ||
3 | import { Notifier } from '@app/core' | ||
4 | import { SortMeta } from 'primeng/primeng' | ||
5 | import { Job } from '../../../../../../shared/index' | ||
6 | import { JobState } from '../../../../../../shared/models' | ||
7 | import { RestPagination, RestTable } from '../../../shared' | ||
8 | import { JobService } from '../shared' | ||
9 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
10 | |||
11 | @Component({ | ||
12 | selector: 'my-jobs-list', | ||
13 | templateUrl: './jobs-list.component.html', | ||
14 | styleUrls: [ './jobs-list.component.scss' ] | ||
15 | }) | ||
16 | export class JobsListComponent extends RestTable implements OnInit { | ||
17 | private static JOB_STATE_LOCAL_STORAGE_STATE = 'jobs-list-state' | ||
18 | |||
19 | jobState: JobState = 'waiting' | ||
20 | jobStates: JobState[] = [ 'active', 'completed', 'failed', 'waiting', 'delayed' ] | ||
21 | jobs: Job[] = [] | ||
22 | totalRecords: number | ||
23 | rowsPerPage = 10 | ||
24 | sort: SortMeta = { field: 'createdAt', order: -1 } | ||
25 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | ||
26 | |||
27 | constructor ( | ||
28 | private notifier: Notifier, | ||
29 | private jobsService: JobService, | ||
30 | private i18n: I18n | ||
31 | ) { | ||
32 | super() | ||
33 | } | ||
34 | |||
35 | ngOnInit () { | ||
36 | this.loadJobState() | ||
37 | this.initialize() | ||
38 | } | ||
39 | |||
40 | onJobStateChanged () { | ||
41 | this.pagination.start = 0 | ||
42 | |||
43 | this.loadData() | ||
44 | this.saveJobState() | ||
45 | } | ||
46 | |||
47 | protected loadData () { | ||
48 | this.jobsService | ||
49 | .getJobs(this.jobState, this.pagination, this.sort) | ||
50 | .subscribe( | ||
51 | resultList => { | ||
52 | this.jobs = resultList.data | ||
53 | this.totalRecords = resultList.total | ||
54 | }, | ||
55 | |||
56 | err => this.notifier.error(err.message) | ||
57 | ) | ||
58 | } | ||
59 | |||
60 | private loadJobState () { | ||
61 | const result = peertubeLocalStorage.getItem(JobsListComponent.JOB_STATE_LOCAL_STORAGE_STATE) | ||
62 | |||
63 | if (result) this.jobState = result as JobState | ||
64 | } | ||
65 | |||
66 | private saveJobState () { | ||
67 | peertubeLocalStorage.setItem(JobsListComponent.JOB_STATE_LOCAL_STORAGE_STATE, this.jobState) | ||
68 | } | ||
69 | } | ||