diff --git a/storage/worker.go b/storage/worker.go index f6410c0..edd62d8 100644 --- a/storage/worker.go +++ b/storage/worker.go @@ -178,7 +178,7 @@ func (database *Database) GetAllWorkerStats() *[]WorkerStats { db := database.getDB() rows, err := db.Query(`SELECT alias, closed_task_count, paused, worker.id - FROM worker WHERE closed_task_count>0 LIMIT 50`) + FROM worker`) handleErr(err) if err != nil { diff --git a/web/angular/src/app/api.service.ts b/web/angular/src/app/api.service.ts index 05b5f1e..bbc257c 100644 --- a/web/angular/src/app/api.service.ts +++ b/web/angular/src/app/api.service.ts @@ -1,7 +1,9 @@ import {Injectable} from '@angular/core'; -import {HttpClient} from '@angular/common/http'; +import {HttpClient, HttpHeaders} from '@angular/common/http'; import {Project} from './models/project'; +import {Worker} from './models/worker'; import {Credentials} from './models/credentials'; +import {SubmitTaskOptions} from './models/console'; @Injectable() export class ApiService { @@ -17,6 +19,13 @@ export class ApiService { ) { } + private static getWorkerHeaders(w: Worker): HttpHeaders { + return new HttpHeaders({ + 'X-Worker-ID': w.id.toString(), + 'X-Secret': w.secret, + }); + } + getLogs(level: number) { return this.http.post(this.url + '/logs', {level: level, since: 1}, this.options); } @@ -135,4 +144,19 @@ export class ApiService { return this.http.get(this.url + `/worker/get/${wid}`, this.options); } + workerSubmitTask(taskOptions: SubmitTaskOptions) { + return this.http.post(this.url + `/task/submit`, { + project: taskOptions.project.id, + max_retries: taskOptions.maxRetries, + recipe: taskOptions.recipe, + priority: taskOptions.priority, + max_assign_time: taskOptions.maxAssignTime, + hash64: 0, + unique_string: taskOptions.uniqueStr, + verification_count: taskOptions.verificationCount + }, { + headers: ApiService.getWorkerHeaders(taskOptions.worker), + responseType: 'json' + }); + } } diff --git a/web/angular/src/app/app-routing.module.ts b/web/angular/src/app/app-routing.module.ts index af504a7..e7f2131 100644 --- a/web/angular/src/app/app-routing.module.ts +++ b/web/angular/src/app/app-routing.module.ts @@ -15,6 +15,7 @@ import {ProjectPermsComponent} from './project-perms/project-perms.component'; import {ManagerListComponent} from './manager-list/manager-list.component'; import {IndexComponent} from './index/index.component'; import {ProjectSecretComponent} from './project-secret/project-secret.component'; +import {ConsoleComponent} from './console/console.component'; const routes: Routes = [ {path: '', component: IndexComponent}, @@ -22,6 +23,7 @@ const routes: Routes = [ {path: 'login', component: LoginComponent}, {path: 'account', component: AccountDetailsComponent}, {path: 'projects', component: ProjectListComponent}, + {path: 'console', component: ConsoleComponent}, {path: 'project/:id', component: ProjectDashboardComponent}, {path: 'project/:id/update', component: UpdateProjectComponent}, {path: 'project/:id/perms', component: ProjectPermsComponent}, diff --git a/web/angular/src/app/app.component.html b/web/angular/src/app/app.component.html index c7fce61..3ac81c0 100644 --- a/web/angular/src/app/app.component.html +++ b/web/angular/src/app/app.component.html @@ -15,6 +15,9 @@ [routerLink]="'manager_list'" *ngIf="authService.logged && authService.account.tracker_admin" >{{"nav.manager_list" | translate}} +
+
diff --git a/web/angular/src/app/app.module.ts b/web/angular/src/app/app.module.ts index c634f25..a4acaf7 100644 --- a/web/angular/src/app/app.module.ts +++ b/web/angular/src/app/app.module.ts @@ -58,6 +58,9 @@ import {IndexComponent} from './index/index.component'; import {ProjectSecretComponent} from './project-secret/project-secret.component'; import {AdminPanelComponent} from './admin-panel/admin-panel.component'; import {AreYouSureComponent} from './are-you-sure/are-you-sure.component'; +import {WorkerSelectComponent} from "./worker-select/worker-select.component"; +import { ConsoleComponent } from './console/console.component'; +import { ConsoleTaskSubmitComponent } from './console-task-submit/console-task-submit.component'; export function createTranslateLoader(http: HttpClient) { @@ -86,6 +89,9 @@ export function createTranslateLoader(http: HttpClient) { ProjectSecretComponent, AdminPanelComponent, AreYouSureComponent, + WorkerSelectComponent, + ConsoleComponent, + ConsoleTaskSubmitComponent ], imports: [ BrowserModule, diff --git a/web/angular/src/app/console-task-submit/console-task-submit.component.css b/web/angular/src/app/console-task-submit/console-task-submit.component.css new file mode 100644 index 0000000..ef0ee71 --- /dev/null +++ b/web/angular/src/app/console-task-submit/console-task-submit.component.css @@ -0,0 +1,3 @@ +.mat-form-field { + width: 100%; +} diff --git a/web/angular/src/app/console-task-submit/console-task-submit.component.html b/web/angular/src/app/console-task-submit/console-task-submit.component.html new file mode 100644 index 0000000..64e3629 --- /dev/null +++ b/web/angular/src/app/console-task-submit/console-task-submit.component.html @@ -0,0 +1,46 @@ +
+ + + + + + + {{"console.max_assign_time"|translate}} + + + + + {{"console.verification_count"|translate}} + + + + + {{"console.max_retries"|translate}} + + + + + {{"console.priority"|translate}} + + + + + {{"console.recipe" | translate}} + + + + + {{"console.unique_str" | translate}} + + + + + + +
diff --git a/web/angular/src/app/console-task-submit/console-task-submit.component.ts b/web/angular/src/app/console-task-submit/console-task-submit.component.ts new file mode 100644 index 0000000..aeae192 --- /dev/null +++ b/web/angular/src/app/console-task-submit/console-task-submit.component.ts @@ -0,0 +1,32 @@ +import {Component, EventEmitter, OnInit, Output} from '@angular/core'; +import {SubmitTaskOptions} from '../models/console'; +import {ApiService} from '../api.service'; + +@Component({ + selector: 'app-console-task-submit', + templateUrl: './console-task-submit.component.html', + styleUrls: ['./console-task-submit.component.css'] +}) +export class ConsoleTaskSubmitComponent implements OnInit { + + public submitOptions = new SubmitTaskOptions(); + + @Output() submitTask = new EventEmitter(); + + constructor(private apiService: ApiService) { + } + + ngOnInit() { + } + + onSubmit() { + this.apiService.getWorker(this.submitOptions.worker.id).subscribe(data => { + this.submitOptions.worker.secret = data['content']['worker']['secret']; + this.submitTask.emit(this.submitOptions); + }); + } + + public buttonDisabled(): boolean { + return this.submitOptions.project === undefined || this.submitOptions.worker === undefined; + } +} diff --git a/web/angular/src/app/console/console.component.css b/web/angular/src/app/console/console.component.css new file mode 100644 index 0000000..e69de29 diff --git a/web/angular/src/app/console/console.component.html b/web/angular/src/app/console/console.component.html new file mode 100644 index 0000000..d28a471 --- /dev/null +++ b/web/angular/src/app/console/console.component.html @@ -0,0 +1,18 @@ +
+ + + {{"console.title" | translate}} + {{"console.subtitle" | translate}} + + + + + + {{"console.submit" | translate}} + + + + + + +
diff --git a/web/angular/src/app/console/console.component.ts b/web/angular/src/app/console/console.component.ts new file mode 100644 index 0000000..1d75ea2 --- /dev/null +++ b/web/angular/src/app/console/console.component.ts @@ -0,0 +1,29 @@ +import {Component, OnInit} from '@angular/core'; +import {SubmitTaskOptions} from '../models/console'; +import {ApiService} from '../api.service'; +import {MessengerService} from '../messenger.service'; +import {TranslateService} from '@ngx-translate/core'; + +@Component({ + selector: 'app-console', + templateUrl: './console.component.html', + styleUrls: ['./console.component.css'] +}) +export class ConsoleComponent implements OnInit { + + constructor(private apiService: ApiService, + private messenger: MessengerService, + private translate: TranslateService) { + } + + ngOnInit() { + } + + onTaskSubmit(options: SubmitTaskOptions) { + this.apiService.workerSubmitTask(options).subscribe(data => { + this.translate.get('console.submit_ok').subscribe(t => this.messenger.show(t)); + }, error => { + this.messenger.show(error.error.message); + }); + } +} diff --git a/web/angular/src/app/create-project/create-project.component.html b/web/angular/src/app/create-project/create-project.component.html index 8500417..782f3af 100644 --- a/web/angular/src/app/create-project/create-project.component.html +++ b/web/angular/src/app/create-project/create-project.component.html @@ -29,7 +29,7 @@ {{"project.git_repo_hint" | translate}} - + - {{"project.manager_select" | translate}} + {{"console.worker_select" | translate}} - - {{"project_select.loading" | translate}} + + {{"worker_select.loading" | translate}} - - supervisor_account + person {{m.username}} diff --git a/web/angular/src/app/manager-select/manager-select.component.ts b/web/angular/src/app/manager-select/manager-select.component.ts index 43e1cf5..0330d68 100644 --- a/web/angular/src/app/manager-select/manager-select.component.ts +++ b/web/angular/src/app/manager-select/manager-select.component.ts @@ -25,6 +25,4 @@ export class ManagerSelectComponent implements OnInit { this.apiService.getManagerList() .subscribe(data => this.managerList = data['content']['managers']); } - - } diff --git a/web/angular/src/app/models/console.ts b/web/angular/src/app/models/console.ts new file mode 100644 index 0000000..b62fab2 --- /dev/null +++ b/web/angular/src/app/models/console.ts @@ -0,0 +1,13 @@ +import {Worker} from './worker'; +import {Project} from './project'; + +export class SubmitTaskOptions { + public worker: Worker; + public project: Project; + public recipe: string; + public uniqueStr: string; + public maxAssignTime = 3600; + public verificationCount = 0; + public maxRetries = 3; + public priority = 1; +} 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 5510cab..62e3e93 100644 --- a/web/angular/src/app/project-perms/project-perms.component.html +++ b/web/angular/src/app/project-perms/project-perms.component.html @@ -41,7 +41,7 @@ -

{{"perms.no_workers"|translate}}

+

{{"perms.no_workers"|translate}}

{{"perms.managers" | translate}}

diff --git a/web/angular/src/app/project-perms/project-perms.component.ts b/web/angular/src/app/project-perms/project-perms.component.ts index ac64bf6..b149e25 100644 --- a/web/angular/src/app/project-perms/project-perms.component.ts +++ b/web/angular/src/app/project-perms/project-perms.component.ts @@ -28,7 +28,7 @@ export class ProjectPermsComponent implements OnInit { project: Project; private projectId: number; accesses: WorkerAccess[]; - managerRoles: ManagerRoleOnProject; + managerRoles: ManagerRoleOnProject[]; unauthorized = false; moment = moment; diff --git a/web/angular/src/app/project-select/project-select.component.html b/web/angular/src/app/project-select/project-select.component.html index 570adbe..b5c8feb 100644 --- a/web/angular/src/app/project-select/project-select.component.html +++ b/web/angular/src/app/project-select/project-select.component.html @@ -1,7 +1,7 @@ - {{"project.chain" | translate}} + {{placeholder}} {{project?.name}} diff --git a/web/angular/src/app/project-select/project-select.component.ts b/web/angular/src/app/project-select/project-select.component.ts index 7a773a6..2134ad4 100644 --- a/web/angular/src/app/project-select/project-select.component.ts +++ b/web/angular/src/app/project-select/project-select.component.ts @@ -12,6 +12,7 @@ export class ProjectSelectComponent implements OnInit { projectList: Project[]; @Input() project: Project; + @Input() placeholder: string; @Output() projectChange = new EventEmitter(); constructor(private apiService: ApiService) { diff --git a/web/angular/src/app/update-project/update-project.component.html b/web/angular/src/app/update-project/update-project.component.html index 04abf23..70d0362 100644 --- a/web/angular/src/app/update-project/update-project.component.html +++ b/web/angular/src/app/update-project/update-project.component.html @@ -37,7 +37,7 @@ > {{'project.git_repo_hint'|translate}} - + {{"project.assign_rate"|translate}} diff --git a/web/angular/src/app/worker-select/worker-select.component.css b/web/angular/src/app/worker-select/worker-select.component.css new file mode 100644 index 0000000..ef0ee71 --- /dev/null +++ b/web/angular/src/app/worker-select/worker-select.component.css @@ -0,0 +1,3 @@ +.mat-form-field { + width: 100%; +} diff --git a/web/angular/src/app/worker-select/worker-select.component.html b/web/angular/src/app/worker-select/worker-select.component.html new file mode 100644 index 0000000..f22547a --- /dev/null +++ b/web/angular/src/app/worker-select/worker-select.component.html @@ -0,0 +1,15 @@ + + {{"console.worker_select" | translate}} + + {{worker?.alias}} + + {{"worker_select.loading" | translate}} + + + {{w.id}} + {{w.alias}} + + + diff --git a/web/angular/src/app/worker-select/worker-select.component.ts b/web/angular/src/app/worker-select/worker-select.component.ts new file mode 100644 index 0000000..1c365aa --- /dev/null +++ b/web/angular/src/app/worker-select/worker-select.component.ts @@ -0,0 +1,32 @@ +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import {ApiService} from '../api.service'; +import {Manager} from '../models/manager'; +import {Worker} from '../models/worker'; + +@Component({ + selector: 'worker-select', + templateUrl: './worker-select.component.html', + styleUrls: ['./worker-select.component.css'] +}) +export class WorkerSelectComponent implements OnInit { + + @Input() worker: Worker; + workerList: Worker[]; + + @Output() + workerChange = new EventEmitter(); + + constructor(private apiService: ApiService) { + } + + ngOnInit() { + } + + loadWorkerList() { + this.apiService.getWorkerStats() + .subscribe(data => { + this.workerList = 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 bf226b4..b883428 100644 --- a/web/angular/src/assets/i18n/en.json +++ b/web/angular/src/assets/i18n/en.json @@ -9,7 +9,8 @@ "worker_dashboard": "Workers", "account": "Account", "manager_list": "Managers", - "back": "Back" + "back": "Back", + "console": "Console" }, "logs": { "title": "Logs", @@ -48,7 +49,8 @@ "new_account": "Create account", "account": "Account details", "workers": "Workers", - "manager_list": "Managers" + "manager_list": "Managers", + "console": "Console" }, "project": { "name": "Project name", @@ -156,9 +158,12 @@ "register_time": "Register date" }, "project_select": { - "list_loading": "Loading project list...", + "loading": "Loading project list...", "none": "None" }, + "worker_select": { + "loading": "Loading worker list..." + }, "index": { "version": "Latest commit hash here", "alias": "Relevent alias" @@ -178,5 +183,19 @@ "are_you_sure": "Are you sure?", "no": "No", "ok": "Ok" + }, + "console": { + "title": "Console", + "subtitle": "Misc debugging operations", + "submit": "Manual task submit", + "worker_select": "Select worker", + "max_assign_time": "Maximum assign time (in seconds)", + "recipe": "Task recipe", + "unique_str": "Unique string (optionnal)", + "task_submit": "Submit task", + "verification_count": "Verification count", + "max_retries": "Maximum retries", + "priority": "Priority", + "submit_ok": "Task submitted" } } diff --git a/web/angular/src/assets/i18n/fr.json b/web/angular/src/assets/i18n/fr.json index 8146f13..696256d 100644 --- a/web/angular/src/assets/i18n/fr.json +++ b/web/angular/src/assets/i18n/fr.json @@ -9,7 +9,8 @@ "worker_dashboard": "Workers", "account": "Compte", "manager_list": "Managers", - "back": "Retour" + "back": "Retour", + "console": "Console" }, "logs": { "title": "Journaux", @@ -49,7 +50,8 @@ "new_account": "Création de compte", "account": "Compte", "workers": "Workers", - "manager_list": "Managers" + "manager_list": "Managers", + "console": "Console" }, "project": { "name": "Nom du projet", @@ -153,9 +155,12 @@ "register_time": "Date d'inscription" }, "project_select": { - "list_loading": "Chargement de la liste de projets...", + "loading": "Chargement de la liste de projets...", "none": "Aucun" }, + "worker_select": { + "loading": "Chargement de la liste de worker..." + }, "index": { "version": "Le dernier hash de commit", "alias": "Alias pertinent" @@ -169,6 +174,20 @@ "secret": "Secret", "update": "Mettre à jour", "ok": "Mis à jour" + }, + "console": { + "title": "Console", + "subtitle": "Opération diverses", + "submit": "Soumission de tâches manuelle", + "worker_select": "Selectionner un Worker", + "max_assign_time": "Temps maximum d'execution", + "recipe": "Contenu de la tâcheu", + "unique_str": "Chaine de charactères unique", + "task_submit": "Soumettre", + "verification_count": "Nombre de vérification", + "max_retries": "Nombre maximal d'essai", + "priority": "Priorité", + "submit_ok": "Tâche soummise" } }