Skip to content

Commit

Permalink
[IMP] t9n: list all projects in home page.
Browse files Browse the repository at this point in the history
This commit adds the project list to the home page of the translations
module with some useful info about projects.

Task-3783071
  • Loading branch information
MohammedBasioni committed May 6, 2024
1 parent 1a67332 commit b0886ec
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 5 deletions.
2 changes: 1 addition & 1 deletion addons/t9n/models/message.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from odoo import api, fields, models
from odoo import fields, models


class Message(models.Model):
Expand Down
22 changes: 21 additions & 1 deletion addons/t9n/models/project.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from odoo import fields, models, api, _
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError


Expand Down Expand Up @@ -32,3 +32,23 @@ def _check_source_and_target_languages(self):
for record in self:
if record.src_lang_id in record.target_lang_ids:
raise ValidationError(_("A project's target languages must be different from its source language."))

@api.model
def get_projects(self):
projects_records = self.search([])
return [{
"id": record.id,
"name": record.name,
"src_lang": {
"id": record.src_lang_id.id,
"name": record.src_lang_id.name if record.src_lang_id.name else "",
},
"resources": [{
"id": resource.id,
"file_name": resource.file_name,
} for resource in record.resource_ids],
"target_langs": [{
"id": lang.id,
"name": lang.name,
} for lang in record.target_lang_ids],
} for record in projects_records]
3 changes: 2 additions & 1 deletion addons/t9n/static/src/core/app.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Component } from "@odoo/owl";
import { ProjectList } from "@t9n/core/project_list";

/**
* The "root", the "homepage" of the translation application.
*/
export class App extends Component {
static components = {};
static components = { ProjectList };
static props = {};
static template = "t9n.App";
}
4 changes: 2 additions & 2 deletions addons/t9n/static/src/core/app.xml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<?xml version="1.0"?>
<templates xml:space="preserve">
<templates>

<t t-name="t9n.App">
Hello World!
<ProjectList/>
</t>

</templates>
68 changes: 68 additions & 0 deletions addons/t9n/static/src/core/project_list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Component, useState } from "@odoo/owl";

import { useService } from "@web/core/utils/hooks";

export class ProjectList extends Component {
static props = {};
static template = "t9n.ProjectList";

setup() {
this.action = useService("action");
this.state = useState({
filters: {
searchText: "",
},
sorting: {
column: "name",
order: "asc",
},
});
this.store = useState(useService("t9n.store"));
this.store.fetchProjects();
}

get projects() {
const searchTerms = this.state.filters.searchText.trim().toUpperCase();
const projects = searchTerms
? this.store.projects.filter((p) => p.name.toUpperCase().includes(searchTerms))
: [...this.store.projects];

projects.sort((p1, p2) => {
let p1Col = p1[this.state.sorting.column];
let p2Col = p2[this.state.sorting.column];

if (this.state.sorting.column !== "resource_count") {
p1Col = p1Col.toLowerCase();
p2Col = p2Col.toLowerCase();
}

if (p1Col < p2Col) {
return this.state.sorting.order === "asc" ? -1 : 1;
}
if (p1Col > p2Col) {
return this.state.sorting.order === "asc" ? 1 : -1;
}
return 0;
});
return projects;
}

onClickColumnName(column) {
if (this.state.sorting.column === column) {
this.state.sorting.order = this.state.sorting.order === "asc" ? "desc" : "asc";
} else {
this.state.sorting.column = column;
this.state.sorting.order = "asc";
}
}

onClickProject(id) {
this.action.doAction({
type: "ir.actions.act_window",
res_id: id,
res_model: "t9n.project",
views: [[false, "form"]],
target: "new",
});
}
}
37 changes: 37 additions & 0 deletions addons/t9n/static/src/core/project_list.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?xml version="1.0"?>
<templates>
<t t-name="t9n.ProjectList">
<div class="container mt-3">
<div class="input-group">
<div class="form-outline">
<input type="text" class="form-control" placeholder="Search projects" t-model="state.filters.searchText"/>
</div>
</div>
<table class="table table-hover">
<thead>
<tr>
<th t-on-click="() => this.onClickColumnName('name')">Project Name <i t-attf-class="btn btn-link fa fa-sort-{{this.state.sorting.column === 'name' and this.state.sorting.order === 'asc' ? 'up' : 'down'}}"></i>
</th>
<th>Source Language</th>
<th>Target Languages</th>
<th>Resource Count</th>
</tr>
</thead>
<tbody>
<t t-foreach="this.projects" t-as="project" t-key="project.id">
<tr>
<td>
<button class="btn btn-link " t-on-click="() => this.onClickProject(project.id)">
<t t-esc="project.name"/>
</button>
</td>
<td t-esc="project.srcLang"/>
<td t-esc="project.formattedTargetLanguages"/>
<td t-esc="project.resourceCount"/>
</tr>
</t>
</tbody>
</table>
</div>
</t>
</templates>
15 changes: 15 additions & 0 deletions addons/t9n/static/src/core/project_model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { formatList } from "@web/core/l10n/utils";

export class Project {
constructor(id, name, srcLang, targetLangs, resourceCount) {
this.id = id;
this.name = name;
this.srcLang = srcLang;
this.targetLangs = targetLangs;
this.resourceCount = resourceCount;
}

get formattedTargetLanguages() {
return formatList(this.targetLangs.map(({ name }) => name));
}
}
30 changes: 30 additions & 0 deletions addons/t9n/static/src/core/store.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { reactive } from "@odoo/owl";

import { Project } from "@t9n/core/project_model";

import { registry } from "@web/core/registry";

export class Store {
constructor(env, { orm }) {
this.env = env;
this.orm = orm;
this.projects = [];
return reactive(this);
}

async fetchProjects() {
const projects = await this.orm.call("t9n.project", "get_projects");
this.projects = projects.map((p) => {
return new Project(p.id, p.name, p.src_lang.name, p.target_langs, p.resources.length);
});
}
}

export const storeService = {
dependencies: ["orm"],
start(env, deps) {
return new Store(env, deps);
},
};

registry.category("services").add("t9n.store", storeService);

0 comments on commit b0886ec

Please sign in to comment.