diff --git a/api/worker.go b/api/worker.go index 38b8ec5..abfdf85 100644 --- a/api/worker.go +++ b/api/worker.go @@ -72,6 +72,14 @@ func (api *WebAPI) GetWorker(r *Request) { if worker != nil { + sess := api.Session.StartFasthttp(r.Ctx) + manager := sess.Get("manager") + + var secret []byte = nil + if manager != nil && manager.(*storage.Manager).WebsiteAdmin { + secret = worker.Secret + } + r.OkJson(JsonResponse{ Ok: true, Content: GetWorkerResponse{ @@ -79,6 +87,8 @@ func (api *WebAPI) GetWorker(r *Request) { Alias: worker.Alias, Id: worker.Id, Created: worker.Created, + Paused: worker.Paused, + Secret: secret, }, }, }) diff --git a/storage/worker.go b/storage/worker.go index df4977f..c4feffe 100644 --- a/storage/worker.go +++ b/storage/worker.go @@ -15,6 +15,8 @@ type Worker struct { type WorkerStats struct { Alias string `json:"alias"` ClosedTaskCount int64 `json:"closed_task_count"` + Paused bool `json:"paused"` + Id int64 `json:"id"` } type WorkerAccess struct { @@ -173,7 +175,7 @@ func (database *Database) GetAllAccesses(projectId int64) *[]WorkerAccess { db := database.getDB() - rows, err := db.Query(`SELECT id, alias, created, role_assign, role_submit, request + rows, err := db.Query(`SELECT id, alias, created, paused, role_assign, role_submit, request FROM worker_access INNER JOIN worker w on worker_access.worker = w.id WHERE project=$1 ORDER BY request, alias`, @@ -186,7 +188,7 @@ func (database *Database) GetAllAccesses(projectId int64) *[]WorkerAccess { wa := WorkerAccess{ Project: projectId, } - _ = rows.Scan(&wa.Worker.Id, &wa.Worker.Alias, &wa.Worker.Created, + _ = rows.Scan(&wa.Worker.Id, &wa.Worker.Alias, &wa.Worker.Created, &wa.Worker.Paused, &wa.Assign, &wa.Submit, &wa.Request) requests = append(requests, wa) } @@ -197,13 +199,15 @@ func (database *Database) GetAllAccesses(projectId int64) *[]WorkerAccess { func (database *Database) GetAllWorkerStats() *[]WorkerStats { db := database.getDB() - rows, err := db.Query(`SELECT alias, closed_task_count FROM worker WHERE closed_task_count>0 LIMIT 50`) + rows, err := db.Query(`SELECT alias, closed_task_count, paused, worker.id + FROM worker WHERE closed_task_count>0 LIMIT 50`) + handleErr(err) stats := make([]WorkerStats, 0) for rows.Next() { s := WorkerStats{} - _ = rows.Scan(&s.Alias, &s.ClosedTaskCount) + _ = rows.Scan(&s.Alias, &s.ClosedTaskCount, &s.Paused, &s.Id) stats = append(stats, s) } diff --git a/test/api_project_test.go b/test/api_project_test.go index 2457c26..8737d49 100644 --- a/test/api_project_test.go +++ b/test/api_project_test.go @@ -636,6 +636,10 @@ func TestTaskChainUpdateRequiresRole(t *testing.T) { } } +func TestGetAccessList(t *testing.T) { + //TODO! +} + func createProjectAsAdmin(req api.CreateProjectRequest) CreateProjectAR { return createProject(req, testAdminCtx) } diff --git a/web/angular/src/app/api.service.ts b/web/angular/src/app/api.service.ts index 0c40d08..85acbae 100755 --- a/web/angular/src/app/api.service.ts +++ b/web/angular/src/app/api.service.ts @@ -126,4 +126,13 @@ export class ApiService { return this.http.post(this.url + `/project/reclaim_assigned_tasks/${pid}`, null, this.options); } + workerSetPaused(wid: number, paused: boolean) { + return this.http.post(this.url + '/worker/set_paused', + {'worker': wid, 'paused': paused}, this.options); + } + + getWorker(wid: number) { + return this.http.get(this.url + `/worker/get/${wid}`, this.options); + } + } diff --git a/web/angular/src/app/models/worker.ts b/web/angular/src/app/models/worker.ts index ed86187..e05a231 100644 --- a/web/angular/src/app/models/worker.ts +++ b/web/angular/src/app/models/worker.ts @@ -3,4 +3,5 @@ export interface Worker { alias: string; created: number; secret: string; + paused: boolean; } diff --git a/web/angular/src/app/project-perms/project-perms.component.css b/web/angular/src/app/project-perms/project-perms.component.css index 0944ea3..a872e34 100644 --- a/web/angular/src/app/project-perms/project-perms.component.css +++ b/web/angular/src/app/project-perms/project-perms.component.css @@ -7,6 +7,10 @@ button { color: #757575; } +.paused { + color: #757575; +} + mat-checkbox { margin-right: 10px; } diff --git a/web/angular/src/app/project-perms/project-perms.component.html b/web/angular/src/app/project-perms/project-perms.component.html index c9ae6f1..5510cab 100644 --- a/web/angular/src/app/project-perms/project-perms.component.html +++ b/web/angular/src/app/project-perms/project-perms.component.html @@ -12,16 +12,24 @@

{{"perms.workers" | translate}}

- + + pause + library_add get_app -

{{wa.worker.alias}} {{wa.request ? ('perms.pending' | translate) : ''}}

+

{{wa.worker.alias}} {{wa.request ? ('perms.pending' | translate) : ''}} + {{wa.worker.paused ? ('workers.paused' | translate) : ''}}

Id={{wa.worker.id}}, {{"perms.created" | translate}} {{moment.unix(wa.worker.created).utc().format("UTC YYYY-MM-DD HH:mm:ss")}}
+ + +
+
+ diff --git a/web/angular/src/app/worker-dashboard/worker-dashboard.component.ts b/web/angular/src/app/worker-dashboard/worker-dashboard.component.ts index f6e7000..626c81c 100644 --- a/web/angular/src/app/worker-dashboard/worker-dashboard.component.ts +++ b/web/angular/src/app/worker-dashboard/worker-dashboard.component.ts @@ -2,6 +2,10 @@ import {Component, OnInit} from '@angular/core'; import {ApiService} from '../api.service'; import {Chart} from 'chart.js'; +import {AuthService} from "../auth.service"; +import {Worker} from "../models/worker"; +import {TranslateService} from "@ngx-translate/core"; +import {MessengerService} from "../messenger.service"; @Component({ selector: 'app-worker-dashboard', @@ -11,8 +15,13 @@ import {Chart} from 'chart.js'; export class WorkerDashboardComponent implements OnInit { private chart: Chart; + workers: Worker[]; + workerInfo: Worker; - constructor(private apiService: ApiService) { + constructor(private apiService: ApiService, + private translate: TranslateService, + private messenger: MessengerService, + public authService: AuthService) { } ngOnInit() { @@ -20,10 +29,36 @@ export class WorkerDashboardComponent implements OnInit { this.refresh(); } + public togglePaused(w: Worker) { + + this.workerInfo = undefined; + + this.apiService.workerSetPaused(w.id, !w.paused) + .subscribe(() => { + this.refresh(); + this.translate.get('perms.set').subscribe(t => this.messenger.show(t)); + }); + } + + public getInfo(w: Worker) { + + if (this.workerInfo && this.workerInfo.id == w.id) { + this.workerInfo = undefined; + return + } + + this.apiService.getWorker(w.id) + .subscribe(data => { + this.workerInfo = data['content']['worker']; + }); + } + public refresh() { this.apiService.getWorkerStats() .subscribe(data => { this.updateChart(data['content']['stats']); + this.workers = data['content']['stats'].sort((a, b) => + (a.alias > b.alias) ? 1 : -1); } ); } diff --git a/web/angular/src/assets/i18n/en.json b/web/angular/src/assets/i18n/en.json index 101e6cd..8493d0d 100644 --- a/web/angular/src/assets/i18n/en.json +++ b/web/angular/src/assets/i18n/en.json @@ -112,7 +112,10 @@ }, "workers": { "title": "Completed tasks per worker", - "subtitle": "Real-time data for all projects" + "subtitle": "Real-time data for all projects", + "paused": "(paused)", + "pause": "Pause", + "manage": "Manager workers" }, "perms": { "title": "Project permissions", diff --git a/web/angular/src/assets/i18n/fr.json b/web/angular/src/assets/i18n/fr.json index 6e4e264..a50f22b 100644 --- a/web/angular/src/assets/i18n/fr.json +++ b/web/angular/src/assets/i18n/fr.json @@ -109,7 +109,10 @@ }, "workers": { "title": "Tâches complétés par worker", - "subtitle": "Données en temps réél pour tous les projets" + "subtitle": "Données en temps réél pour tous les projets", + "paused": "(en pause)", + "pause": "Pauser", + "manage": "Gérer les workers" }, "perms": { "title": "Permissions du projet",