mirror of
https://github.com/simon987/task_tracker.git
synced 2025-04-19 18:16:45 +00:00
Some work on project actions
This commit is contained in:
parent
016676e0f3
commit
d44b9924e7
@ -148,6 +148,7 @@ type UpdateProjectRequest struct {
|
||||
Public bool `json:"public"`
|
||||
Hidden bool `json:"hidden"`
|
||||
Chain int64 `json:"chain"`
|
||||
Paused bool `json:"paused"`
|
||||
}
|
||||
|
||||
func (req *UpdateProjectRequest) isValid() bool {
|
||||
@ -204,6 +205,9 @@ func (req *SubmitTaskRequest) IsValid() bool {
|
||||
if req.Hash64 != 0 && req.UniqueString != "" {
|
||||
return false
|
||||
}
|
||||
if req.Project == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
@ -158,6 +158,7 @@ func (api *WebAPI) UpdateProject(r *Request) {
|
||||
Public: updateReq.Public,
|
||||
Hidden: updateReq.Hidden,
|
||||
Chain: updateReq.Chain,
|
||||
Paused: updateReq.Paused,
|
||||
}
|
||||
sess := api.Session.StartFasthttp(r.Ctx)
|
||||
manager := sess.Get("manager")
|
||||
|
@ -2,7 +2,7 @@ server:
|
||||
address: "0.0.0.0:42901"
|
||||
|
||||
database:
|
||||
conn_str: "user=task_tracker dbname=task_tracker sslmode=disable"
|
||||
conn_str: "user=task_tracker password=task_tracker dbname=task_tracker sslmode=disable"
|
||||
# log_levels: ["debug", "error", "trace", "info", "warn"]
|
||||
log_levels: ["error", "info", "warn"]
|
||||
|
||||
@ -19,8 +19,8 @@ log:
|
||||
|
||||
session:
|
||||
cookie_name: "tt"
|
||||
expiration: "25m"
|
||||
expiration: "8h"
|
||||
|
||||
monitoring:
|
||||
snapshot_interval: "60s"
|
||||
snapshot_interval: "120s"
|
||||
history_length: "400h"
|
||||
|
@ -19,6 +19,7 @@ CREATE TABLE project
|
||||
chain INT DEFAULT NULL REFERENCES project (id),
|
||||
public boolean NOT NULL,
|
||||
hidden boolean NOT NULL,
|
||||
paused boolean NOT NULL,
|
||||
name TEXT UNIQUE NOT NULL,
|
||||
clone_url TEXT NOT NULL,
|
||||
git_repo TEXT UNIQUE NOT NULL,
|
||||
|
@ -17,6 +17,7 @@ type Project struct {
|
||||
Public bool `json:"public"`
|
||||
Hidden bool `json:"hidden"`
|
||||
Chain int64 `json:"chain"`
|
||||
Paused bool `json:"paused"`
|
||||
}
|
||||
|
||||
type AssignedTasks struct {
|
||||
@ -28,10 +29,10 @@ func (database *Database) SaveProject(project *Project) (int64, error) {
|
||||
db := database.getDB()
|
||||
|
||||
row := db.QueryRow(`INSERT INTO project (name, git_repo, clone_url, version, priority,
|
||||
motd, public, hidden, chain)
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,NULLIF($9, 0)) RETURNING id`,
|
||||
motd, public, hidden, chain, paused)
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,NULLIF($9, 0),$10) RETURNING id`,
|
||||
project.Name, project.GitRepo, project.CloneUrl, project.Version, project.Priority, project.Motd,
|
||||
project.Public, project.Hidden, project.Chain)
|
||||
project.Public, project.Hidden, project.Chain, project.Paused)
|
||||
|
||||
var id int64
|
||||
err := row.Scan(&id)
|
||||
@ -57,7 +58,7 @@ func (database *Database) GetProject(id int64) *Project {
|
||||
|
||||
db := database.getDB()
|
||||
row := db.QueryRow(`SELECT id, priority, name, clone_url, git_repo, version,
|
||||
motd, public, hidden, COALESCE(chain, 0)
|
||||
motd, public, hidden, COALESCE(chain, 0), paused
|
||||
FROM project WHERE id=$1`, id)
|
||||
|
||||
project, err := scanProject(row)
|
||||
@ -80,7 +81,7 @@ func scanProject(row *sql.Row) (*Project, error) {
|
||||
|
||||
p := &Project{}
|
||||
err := row.Scan(&p.Id, &p.Priority, &p.Name, &p.CloneUrl, &p.GitRepo, &p.Version,
|
||||
&p.Motd, &p.Public, &p.Hidden, &p.Chain)
|
||||
&p.Motd, &p.Public, &p.Hidden, &p.Chain, &p.Paused)
|
||||
|
||||
return p, err
|
||||
}
|
||||
@ -89,7 +90,7 @@ func (database *Database) GetProjectWithRepoName(repoName string) *Project {
|
||||
|
||||
db := database.getDB()
|
||||
row := db.QueryRow(`SELECT id, priority, name, clone_url, git_repo, version,
|
||||
motd, public, hidden, COALESCE(chain, 0) FROM project WHERE LOWER(git_repo)=$1`,
|
||||
motd, public, hidden, COALESCE(chain, 0), paused FROM project WHERE LOWER(git_repo)=$1`,
|
||||
strings.ToLower(repoName))
|
||||
|
||||
project, err := scanProject(row)
|
||||
@ -108,11 +109,11 @@ func (database *Database) UpdateProject(project *Project) error {
|
||||
db := database.getDB()
|
||||
|
||||
res, err := db.Exec(`UPDATE project
|
||||
SET (priority, name, clone_url, git_repo, version, motd, public, hidden, chain) =
|
||||
($1,$2,$3,$4,$5,$6,$7,$8,NULLIF($9, 0))
|
||||
WHERE id=$10`,
|
||||
SET (priority, name, clone_url, git_repo, version, motd, public, hidden, chain, paused) =
|
||||
($1,$2,$3,$4,$5,$6,$7,$8,NULLIF($9, 0), $10)
|
||||
WHERE id=$11`,
|
||||
project.Priority, project.Name, project.CloneUrl, project.GitRepo, project.Version, project.Motd,
|
||||
project.Public, project.Hidden, project.Chain, project.Id)
|
||||
project.Public, project.Hidden, project.Chain, project.Paused, project.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -135,13 +136,13 @@ func (database Database) GetAllProjects(managerId int64) *[]Project {
|
||||
var err error
|
||||
if managerId == 0 {
|
||||
rows, err = db.Query(`SELECT
|
||||
Id, priority, name, clone_url, git_repo, version, motd, public, hidden, COALESCE(chain,0)
|
||||
Id, priority, name, clone_url, git_repo, version, motd, public, hidden, COALESCE(chain,0), paused
|
||||
FROM project
|
||||
WHERE NOT hidden
|
||||
ORDER BY name`)
|
||||
} else {
|
||||
rows, err = db.Query(`SELECT
|
||||
Id, priority, name, clone_url, git_repo, version, motd, public, hidden, COALESCE(chain,0)
|
||||
Id, priority, name, clone_url, git_repo, version, motd, public, hidden, COALESCE(chain,0), paused
|
||||
FROM project
|
||||
LEFT JOIN manager_has_role_on_project mhrop ON mhrop.project = id AND mhrop.manager=$1
|
||||
WHERE NOT hidden OR mhrop.role & 1 = 1 OR (SELECT tracker_admin FROM manager WHERE id=$1)
|
||||
@ -153,7 +154,7 @@ func (database Database) GetAllProjects(managerId int64) *[]Project {
|
||||
p := Project{}
|
||||
err := rows.Scan(&p.Id, &p.Priority, &p.Name, &p.CloneUrl,
|
||||
&p.GitRepo, &p.Version, &p.Motd, &p.Public, &p.Hidden,
|
||||
&p.Chain)
|
||||
&p.Chain, &p.Paused)
|
||||
handleErr(err)
|
||||
projects = append(projects, p)
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ func (database *Database) GetTask(worker *Worker) *Task {
|
||||
FROM task
|
||||
INNER JOIN project project on task.project = project.id
|
||||
LEFT JOIN worker_verifies_task wvt on task.id = wvt.task AND wvt.worker=$1
|
||||
WHERE assignee IS NULL AND task.status=1
|
||||
WHERE NOT project.paused AND assignee IS NULL AND task.status=1
|
||||
AND (project.public OR (
|
||||
SELECT a.role_assign FROM worker_access a WHERE a.worker=$1 AND a.project=project.id
|
||||
))
|
||||
@ -186,7 +186,7 @@ func (database *Database) GetTaskFromProject(worker *Worker, projectId int64) *T
|
||||
FROM task
|
||||
INNER JOIN project project on task.project = project.id
|
||||
LEFT JOIN worker_verifies_task wvt on task.id = wvt.task AND wvt.worker=$1
|
||||
WHERE assignee IS NULL AND project.id=$2 AND status=1
|
||||
WHERE NOT project.paused AND assignee IS NULL AND project.id=$2 AND status=1
|
||||
AND (project.public OR (
|
||||
SELECT a.role_assign FROM worker_access a WHERE a.worker=$1 AND a.project=$2
|
||||
))
|
||||
|
@ -142,6 +142,7 @@ func TestUpdateProjectValid(t *testing.T) {
|
||||
Motd: "MotdB",
|
||||
Public: false,
|
||||
Hidden: true,
|
||||
Paused: true,
|
||||
}, pid, testAdminCtx)
|
||||
|
||||
if updateResp.Ok != true {
|
||||
@ -168,6 +169,9 @@ func TestUpdateProjectValid(t *testing.T) {
|
||||
if proj.Project.Hidden != true {
|
||||
t.Error()
|
||||
}
|
||||
if proj.Project.Paused != true {
|
||||
t.Error()
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateProjectInvalid(t *testing.T) {
|
||||
@ -444,6 +448,42 @@ func TestAdminShouldSeeHiddenProjectInList(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPausedProjectShouldNotDispatchTasks(t *testing.T) {
|
||||
|
||||
createTask(api.SubmitTaskRequest{
|
||||
Project: testProject,
|
||||
Recipe: "...",
|
||||
}, testWorker)
|
||||
createTask(api.SubmitTaskRequest{
|
||||
Project: testProject,
|
||||
Recipe: "...",
|
||||
}, testWorker)
|
||||
createTask(api.SubmitTaskRequest{
|
||||
Project: testProject,
|
||||
Recipe: "...",
|
||||
}, testWorker)
|
||||
|
||||
task1 := getTaskFromProject(testProject, testWorker).Content.Task
|
||||
if task1 == nil {
|
||||
t.Error()
|
||||
}
|
||||
|
||||
updateProject(api.UpdateProjectRequest{
|
||||
Paused: true,
|
||||
Name: "generictestproject",
|
||||
}, testProject, testAdminCtx)
|
||||
|
||||
task2 := getTaskFromProject(testProject, testWorker).Content.Task
|
||||
if task2 != nil {
|
||||
t.Error()
|
||||
}
|
||||
|
||||
updateProject(api.UpdateProjectRequest{
|
||||
Paused: false,
|
||||
Name: "generictestproject",
|
||||
}, testProject, testAdminCtx)
|
||||
}
|
||||
|
||||
func createProjectAsAdmin(req api.CreateProjectRequest) CreateProjectAR {
|
||||
return createProject(req, testAdminCtx)
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ server:
|
||||
address: "127.0.0.1:5001"
|
||||
|
||||
database:
|
||||
conn_str: "user=task_tracker dbname=task_tracker_test sslmode=disable"
|
||||
conn_str: "user=task_tracker password=task_tracker dbname=task_tracker sslmode=disable"
|
||||
log_levels: ["debug", "error", "trace", "info", "warn"]
|
||||
|
||||
git:
|
||||
|
@ -19,6 +19,7 @@ CREATE TABLE project
|
||||
chain INT DEFAULT NULL REFERENCES project (id),
|
||||
public boolean NOT NULL,
|
||||
hidden boolean NOT NULL,
|
||||
paused boolean NOT NULL,
|
||||
name TEXT UNIQUE NOT NULL,
|
||||
clone_url TEXT NOT NULL,
|
||||
git_repo TEXT UNIQUE NOT NULL,
|
||||
|
13
web/angular/src/app/admin-panel/admin-panel.component.html
Normal file
13
web/angular/src/app/admin-panel/admin-panel.component.html
Normal file
@ -0,0 +1,13 @@
|
||||
<div class="container">
|
||||
<mat-card class="mat-elevation-z8">
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{"admin_panel.title"|translate}}</mat-card-title>
|
||||
<mat-card-subtitle>{{"admin_panel.subtitle"|translate}}</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
|
||||
<mat-card-content>
|
||||
</mat-card-content>
|
||||
|
||||
<mat-card-actions></mat-card-actions>
|
||||
</mat-card>
|
||||
</div>
|
16
web/angular/src/app/admin-panel/admin-panel.component.ts
Normal file
16
web/angular/src/app/admin-panel/admin-panel.component.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-admin-panel',
|
||||
templateUrl: './admin-panel.component.html',
|
||||
styleUrls: ['./admin-panel.component.css']
|
||||
})
|
||||
export class AdminPanelComponent implements OnInit {
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
@ -12,6 +12,7 @@ import {
|
||||
MatButtonToggleModule,
|
||||
MatCardModule,
|
||||
MatCheckboxModule,
|
||||
MatDialogModule,
|
||||
MatDividerModule,
|
||||
MatExpansionModule,
|
||||
MatFormFieldModule,
|
||||
@ -55,6 +56,8 @@ import {ManagerSelectComponent} from './manager-select/manager-select.component'
|
||||
import {ProjectIconComponent} from './project-icon/project-icon.component';
|
||||
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';
|
||||
|
||||
|
||||
export function createTranslateLoader(http: HttpClient) {
|
||||
@ -81,6 +84,8 @@ export function createTranslateLoader(http: HttpClient) {
|
||||
ProjectIconComponent,
|
||||
IndexComponent,
|
||||
ProjectSecretComponent,
|
||||
AdminPanelComponent,
|
||||
AreYouSureComponent,
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
@ -120,7 +125,8 @@ export function createTranslateLoader(http: HttpClient) {
|
||||
MatTabsModule,
|
||||
MatListModule,
|
||||
MatButtonToggleModule,
|
||||
MatStepperModule
|
||||
MatStepperModule,
|
||||
MatDialogModule,
|
||||
|
||||
],
|
||||
exports: [],
|
||||
@ -131,6 +137,7 @@ export function createTranslateLoader(http: HttpClient) {
|
||||
],
|
||||
entryComponents: [
|
||||
SnackBarComponent,
|
||||
AreYouSureComponent
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
|
@ -0,0 +1,3 @@
|
||||
.mat-dialog-actions {
|
||||
justify-content: end;
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
<h1 mat-dialog-title>{{"dialog.confirmation"|translate}}</h1>
|
||||
<div mat-dialog-content>
|
||||
<p>{{"dialog.are_you_sure"|translate}}</p>
|
||||
</div>
|
||||
<div mat-dialog-actions>
|
||||
<button mat-button (click)="onNoClick()">{{"dialog.no"|translate}}</button>
|
||||
<button mat-button color="warn" (click)="onYesClick()">{{"dialog.ok"|translate}}</button>
|
||||
</div>
|
25
web/angular/src/app/are-you-sure/are-you-sure.component.ts
Normal file
25
web/angular/src/app/are-you-sure/are-you-sure.component.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {MatDialogRef} from "@angular/material";
|
||||
|
||||
@Component({
|
||||
selector: 'app-are-you-sure',
|
||||
templateUrl: './are-you-sure.component.html',
|
||||
styleUrls: ['./are-you-sure.component.css']
|
||||
})
|
||||
export class AreYouSureComponent implements OnInit {
|
||||
|
||||
constructor(public dialogRef: MatDialogRef<AreYouSureComponent>) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
}
|
||||
|
||||
onNoClick() {
|
||||
this.dialogRef.close(false)
|
||||
}
|
||||
|
||||
onYesClick() {
|
||||
this.dialogRef.close(true)
|
||||
}
|
||||
}
|
@ -9,4 +9,5 @@ export interface Project {
|
||||
public: boolean;
|
||||
chain: number;
|
||||
hidden: boolean;
|
||||
paused: boolean;
|
||||
}
|
||||
|
@ -38,3 +38,11 @@
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.project-actions {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.project-actions button {
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
@ -52,6 +52,28 @@
|
||||
<pre>{{project | json}}</pre>
|
||||
</mat-expansion-panel>
|
||||
|
||||
<mat-expansion-panel *ngIf="project && auth.logged" class="project-actions">
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>{{"dashboard.actions" | translate}}</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
<button mat-raised-button color="accent" (click)="resetFailedTasks()">
|
||||
<mat-icon>replay</mat-icon>
|
||||
{{"dashboard.reset_failed"|translate}}
|
||||
</button>
|
||||
<button mat-raised-button
|
||||
color="primary"
|
||||
(click)="pauseProject()"
|
||||
*ngIf="!project.paused"
|
||||
[title]="'dashboard.pause_hint'|translate">{{"dashboard.pause"|translate}}</button>
|
||||
<button mat-raised-button color="primary" (click)="pauseProject()">
|
||||
<mat-icon>pause</mat-icon>
|
||||
{{"dashboard.pause"|translate}}</button>
|
||||
<button mat-raised-button color="warn" (click)="hardReset()">
|
||||
<mat-icon>warning</mat-icon>
|
||||
{{"dashboard.hard_reset"|translate}}
|
||||
</button>
|
||||
</mat-expansion-panel>
|
||||
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button mat-raised-button [routerLink]="'/projects'">Back</button>
|
||||
|
@ -8,6 +8,8 @@ import {AssignedTasks, MonitoringSnapshot} from "../models/monitoring";
|
||||
import {TranslateService} from "@ngx-translate/core";
|
||||
import {MessengerService} from "../messenger.service";
|
||||
import {AuthService} from "../auth.service";
|
||||
import {MatDialog} from "@angular/material";
|
||||
import {AreYouSureComponent} from "../are-you-sure/are-you-sure.component";
|
||||
|
||||
|
||||
@Component({
|
||||
@ -48,6 +50,7 @@ export class ProjectDashboardComponent implements OnInit {
|
||||
private route: ActivatedRoute,
|
||||
private translate: TranslateService,
|
||||
public auth: AuthService,
|
||||
public dialog: MatDialog,
|
||||
private messenger: MessengerService) {
|
||||
}
|
||||
|
||||
@ -340,4 +343,32 @@ export class ProjectDashboardComponent implements OnInit {
|
||||
this.messenger.show(t))
|
||||
})
|
||||
}
|
||||
|
||||
resetFailedTasks() {
|
||||
this.dialog.open(AreYouSureComponent, {
|
||||
width: '250px',
|
||||
}).afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
alert("yes")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pauseProject() {
|
||||
this.dialog.open(AreYouSureComponent, {
|
||||
width: '250px',
|
||||
}).afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.project.paused = true;
|
||||
this.apiService.updateProject(this.project).subscribe(() => {
|
||||
this.translate.get("messenger.acknowledged").subscribe(t =>
|
||||
this.messenger.show(t))
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
hardReset() {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
<mat-icon *ngIf="project.public" [title]="'project.public' | translate">public</mat-icon>
|
||||
<mat-icon *ngIf="!project.public && !project.hidden" [title]="'project.private'|translate">lock</mat-icon>
|
||||
<mat-icon *ngIf="project.hidden" [title]="'project.hidden'|translate">visibility_off</mat-icon>
|
||||
<mat-icon *ngIf="project.public && !project.paused" [title]="'project.public' | translate">public</mat-icon>
|
||||
<mat-icon *ngIf="!project.public && !project.hidden && !project.paused" [title]="'project.private'|translate">lock
|
||||
</mat-icon>
|
||||
<mat-icon *ngIf="project.hidden && !project.paused" [title]="'project.hidden'|translate">visibility_off</mat-icon>
|
||||
<mat-icon *ngIf="project.paused" [title]="'project.paused'|translate">pause</mat-icon>
|
||||
|
@ -5,3 +5,11 @@ button {
|
||||
mat-panel-title > project-icon {
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.paused {
|
||||
color: #9a9a9a;
|
||||
}
|
||||
|
||||
.mat-expansion-panel-header-description {
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
@ -12,11 +12,12 @@
|
||||
<mat-accordion>
|
||||
<mat-expansion-panel *ngFor="let project of projects" style="margin-top: 1em">
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
<mat-panel-title [class.paused]="project.paused">
|
||||
<project-icon [project]="project"></project-icon>
|
||||
<span style="width: 3em">{{project.id}}</span>{{project.name}}
|
||||
<span style="width: 3em; align-self: center">{{project.id}}</span>
|
||||
<span style="align-self: center">{{project.name}}</span>
|
||||
</mat-panel-title>
|
||||
<mat-panel-description>{{project.motd}}</mat-panel-description>
|
||||
<mat-panel-description style="align-self: center">{{project.motd}}</mat-panel-description>
|
||||
</mat-expansion-panel-header>
|
||||
<pre>{{project | json}}</pre>
|
||||
<div>
|
||||
|
@ -74,7 +74,12 @@
|
||||
"title": "Dashboard for",
|
||||
"metadata": "Project metadata",
|
||||
"empty": "No tasks",
|
||||
"refresh": "Refresh"
|
||||
"refresh": "Refresh",
|
||||
"actions": "Actions",
|
||||
"reset_failed": "Reset failed tasks",
|
||||
"pause": "Pause",
|
||||
"resume": "Resume",
|
||||
"hard_reset": "Hard_reset"
|
||||
},
|
||||
"login": {
|
||||
"title": "Login",
|
||||
@ -121,7 +126,8 @@
|
||||
},
|
||||
"messenger": {
|
||||
"close": "Close",
|
||||
"unauthorized": "Unauthorized"
|
||||
"unauthorized": "Unauthorized",
|
||||
"acknowledged": "Changes saved"
|
||||
},
|
||||
"manager_list": {
|
||||
"title": "Manager list",
|
||||
@ -149,5 +155,11 @@
|
||||
"secret": "Secret",
|
||||
"update": "Update",
|
||||
"ok": "Updated"
|
||||
},
|
||||
"dialog": {
|
||||
"confirmation": "Confirmation",
|
||||
"are_you_sure": "Are you sure?",
|
||||
"no": "No",
|
||||
"ok": "Ok"
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,8 @@
|
||||
"title": "Tableau de bord pour ",
|
||||
"metadata": "Métadonnés du projet",
|
||||
"empty": "Aucune tâche",
|
||||
"refresh": "Rafraîchir"
|
||||
"refresh": "Rafraîchir",
|
||||
"actions": "Actions"
|
||||
},
|
||||
"login": {
|
||||
"title": "Ouvrir un session",
|
||||
@ -123,7 +124,8 @@
|
||||
},
|
||||
"messenger": {
|
||||
"close": "Fermer",
|
||||
"unauthorized": "Non autorisé"
|
||||
"unauthorized": "Non autorisé",
|
||||
"acknowledged": "Changements enregistrés"
|
||||
},
|
||||
"manager_list": {
|
||||
"title": "Liste ",
|
||||
|
Loading…
x
Reference in New Issue
Block a user