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 @@
+
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"
}
}