mirror of
https://github.com/simon987/task_tracker.git
synced 2025-04-10 14:06:43 +00:00
Worker management UI for managers
This commit is contained in:
parent
72c8e18044
commit
39dd89b001
@ -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,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,4 +3,5 @@ export interface Worker {
|
||||
alias: string;
|
||||
created: number;
|
||||
secret: string;
|
||||
paused: boolean;
|
||||
}
|
||||
|
@ -7,6 +7,10 @@ button {
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
.paused {
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
mat-checkbox {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
@ -12,16 +12,24 @@
|
||||
<mat-card-content *ngIf="!(unauthorized || !auth.account)">
|
||||
<h3>{{"perms.workers" | translate}}</h3>
|
||||
<mat-list *ngIf="accesses && accesses.length>0">
|
||||
<mat-list-item *ngFor="let wa of accesses" [class.request]="wa.request">
|
||||
<mat-list-item *ngFor="let wa of accesses" [class.request]="wa.request"
|
||||
[class.paused]="wa.worker.paused">
|
||||
<mat-icon mat-list-icon *ngIf="wa.worker.paused" [title]="'workers.paused'|translate">pause
|
||||
</mat-icon>
|
||||
<mat-icon mat-list-icon *ngIf="wa.submit" [title]="'perms.submit'|translate">library_add</mat-icon>
|
||||
<mat-icon mat-list-icon *ngIf="wa.assign" [title]="'perms.assign'|translate">get_app</mat-icon>
|
||||
<h4 mat-line>{{wa.worker.alias}} {{wa.request ? ('perms.pending' | translate) : ''}}</h4>
|
||||
<h4 mat-line>{{wa.worker.alias}} {{wa.request ? ('perms.pending' | translate) : ''}}
|
||||
{{wa.worker.paused ? ('workers.paused' | translate) : ''}}</h4>
|
||||
<div mat-line>
|
||||
Id=<span class="text-mono">{{wa.worker.id}}</span>, {{"perms.created" | translate}}
|
||||
<span
|
||||
class="text-mono">{{moment.unix(wa.worker.created).utc().format("UTC YYYY-MM-DD HH:mm:ss")}}</span>
|
||||
</div>
|
||||
<span style="flex: 1 1 auto;"></span>
|
||||
<button mat-raised-button color="secondary" [title]="'workers.pause' | translate"
|
||||
(click)="togglePaused(wa.worker)">
|
||||
<mat-icon>pause</mat-icon>
|
||||
</button>
|
||||
<button mat-raised-button color="primary" [title]="'perms.grant' | translate"
|
||||
*ngIf="wa.request" (click)="acceptRequest(wa)">
|
||||
<mat-icon>check</mat-icon>
|
||||
|
@ -9,6 +9,7 @@ import {AuthService} from '../auth.service';
|
||||
import {Manager, ManagerRoleOnProject} from '../models/manager';
|
||||
import {MessengerService} from '../messenger.service';
|
||||
import {TranslateService} from '@ngx-translate/core';
|
||||
import {Worker} from "../models/worker";
|
||||
|
||||
@Component({
|
||||
selector: 'app-project-perms',
|
||||
@ -56,6 +57,14 @@ export class ProjectPermsComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
public togglePaused(w: Worker) {
|
||||
this.apiService.workerSetPaused(w.id, !w.paused)
|
||||
.subscribe(() => {
|
||||
this.getProjectAccesses();
|
||||
this.translate.get('perms.set').subscribe(t => this.messenger.show(t));
|
||||
});
|
||||
}
|
||||
|
||||
private getProject() {
|
||||
this.apiService.getProject(this.projectId).subscribe(data => {
|
||||
this.project = data['content']['project'];
|
||||
|
@ -0,0 +1,3 @@
|
||||
button {
|
||||
margin-left: 15px;
|
||||
}
|
@ -14,5 +14,32 @@
|
||||
<mat-card-content>
|
||||
<canvas id="worker-stats"></canvas>
|
||||
</mat-card-content>
|
||||
|
||||
|
||||
<mat-expansion-panel *ngIf="authService.logged" class="">
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>{{"workers.manage" | translate}}</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<mat-list>
|
||||
<mat-list-item *ngFor="let worker of workers" [class.paused]="worker.paused">
|
||||
<mat-icon mat-list-icon *ngIf="worker.paused" [title]="'workers.paused'|translate">pause</mat-icon>
|
||||
<mat-icon mat-list-icon *ngIf="!worker.paused">_blank_</mat-icon>
|
||||
<h4 mat-line>{{worker.alias}}</h4>
|
||||
<div mat-line *ngIf="workerInfo && workerInfo.id === worker.id">
|
||||
<p class="text-mono">{{workerInfo|json}}</p>
|
||||
</div>
|
||||
<span style="flex: 1 1 auto;"></span>
|
||||
<button mat-raised-button color="secondary" [title]="'workers.pause' | translate"
|
||||
(click)="togglePaused(worker)">
|
||||
<mat-icon>pause</mat-icon>
|
||||
</button>
|
||||
<button mat-raised-button color="secondary" [title]="'workers.info' | translate"
|
||||
(click)="getInfo(worker)">
|
||||
<mat-icon>info</mat-icon>
|
||||
</button>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
</mat-expansion-panel>
|
||||
</mat-card>
|
||||
</div>
|
||||
|
@ -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);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
Loading…
x
Reference in New Issue
Block a user