From ddd6f4a92d3e7bf167f545f4d6246d80c4a2a650 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Wed, 25 Feb 2026 21:31:00 +0100 Subject: [PATCH 01/22] [FIX] vcp_management: bad path for icon --- vcp_management/views/menu.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vcp_management/views/menu.xml b/vcp_management/views/menu.xml index 1d785b5..1876455 100644 --- a/vcp_management/views/menu.xml +++ b/vcp_management/views/menu.xml @@ -6,7 +6,7 @@ id="vcp_main_menu" name="Virtual Control Platform" sequence="16" - web_icon="vcp,static/description/icon.png" + web_icon="vcp_management,static/description/icon.png" /> Date: Wed, 25 Feb 2026 21:41:30 +0100 Subject: [PATCH 02/22] [IMP] vcp_management: allow to delete a repository, if it has repository branch --- vcp_management/models/vcp_repository_branch.py | 1 + 1 file changed, 1 insertion(+) diff --git a/vcp_management/models/vcp_repository_branch.py b/vcp_management/models/vcp_repository_branch.py index 0305e8e..5878a06 100644 --- a/vcp_management/models/vcp_repository_branch.py +++ b/vcp_management/models/vcp_repository_branch.py @@ -22,6 +22,7 @@ class VcpRepositoryBranch(models.Model): repository_id = fields.Many2one( "vcp.repository", required=True, + ondelete="cascade", ) platform_id = fields.Many2one( related="repository_id.platform_id", From 5bd0d269df890b6534d3e70280f27f583c136c0e Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Wed, 25 Feb 2026 22:03:51 +0100 Subject: [PATCH 03/22] [IMP] vcp_*: allow to fetch only 'sources' repositories, ignoring forks --- vcp_github/models/vcp_platform.py | 3 +++ vcp_management/models/vcp_platform.py | 4 ++++ vcp_management/models/vcp_repository.py | 4 ++++ vcp_management/views/vcp_platform.xml | 1 + vcp_management/views/vcp_repository.xml | 1 + 5 files changed, 13 insertions(+) diff --git a/vcp_github/models/vcp_platform.py b/vcp_github/models/vcp_platform.py index b8534bc..9e46c29 100644 --- a/vcp_github/models/vcp_platform.py +++ b/vcp_github/models/vcp_platform.py @@ -40,6 +40,8 @@ def _update_information_github(self): self.image_1920 = base64.b64encode(response.content) repos = org.repositories() for repo in repos: + if repo.fork and not self.fetch_repository_fork: + continue self._update_github_repository(repo) self.last_update = fields.Datetime.now() @@ -55,6 +57,7 @@ def _update_github_repository(self, repo): "created_at": self._parse_github_date(repo.created_at), "stargazers_count": repo.stargazers_count, "fork_count": repo.forks_count, + "is_fork": repo.fork, "watchers_count": repo.watchers_count, "description": repo.description, } diff --git a/vcp_management/models/vcp_platform.py b/vcp_management/models/vcp_platform.py index fe58e55..ae8a174 100644 --- a/vcp_management/models/vcp_platform.py +++ b/vcp_management/models/vcp_platform.py @@ -59,6 +59,10 @@ class VcpPlatform(models.Model): ) default_update_repository_information = fields.Boolean() information_update = fields.Boolean() + fetch_repository_fork = fields.Boolean( + help="If checked, all repositories will be fetched (sources and forks)." + " Otherwise, only sources repositories will be fetched" + ) local_path = fields.Char(compute="_compute_local_path") rule_ids = fields.Many2many( "vcp.rule", diff --git a/vcp_management/models/vcp_repository.py b/vcp_management/models/vcp_repository.py index eeb44f3..c652f8e 100644 --- a/vcp_management/models/vcp_repository.py +++ b/vcp_management/models/vcp_repository.py @@ -20,6 +20,10 @@ class VcpRepository(models.Model): ) created_at = fields.Datetime(readonly=True) stargazers_count = fields.Integer(readonly=True) + is_fork = fields.Boolean( + readonly=True, + help="Specify if the repo is a Source or a Fork repository", + ) fork_count = fields.Integer(readonly=True) watchers_count = fields.Integer(readonly=True) from_date = fields.Datetime(readonly=True, required=True) diff --git a/vcp_management/views/vcp_platform.xml b/vcp_management/views/vcp_platform.xml index 7df0195..34d0673 100644 --- a/vcp_management/views/vcp_platform.xml +++ b/vcp_management/views/vcp_platform.xml @@ -28,6 +28,7 @@ + diff --git a/vcp_management/views/vcp_repository.xml b/vcp_management/views/vcp_repository.xml index 94f82b1..a492903 100644 --- a/vcp_management/views/vcp_repository.xml +++ b/vcp_management/views/vcp_repository.xml @@ -61,6 +61,7 @@ + From 331b89e656127e7a91c1222b823801c4fa716d35 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Wed, 25 Feb 2026 22:47:38 +0100 Subject: [PATCH 04/22] [IMP] vcp_*: allow to fetch only 'active' repositories, ignoring archived repositories --- vcp_github/models/vcp_platform.py | 19 +++++++++++++------ vcp_management/models/vcp_platform.py | 4 ++++ vcp_management/models/vcp_repository.py | 2 +- vcp_management/views/vcp_platform.xml | 1 + vcp_management/views/vcp_repository.xml | 13 ++++++++++++- 5 files changed, 31 insertions(+), 8 deletions(-) diff --git a/vcp_github/models/vcp_platform.py b/vcp_github/models/vcp_platform.py index 9e46c29..6f75b00 100644 --- a/vcp_github/models/vcp_platform.py +++ b/vcp_github/models/vcp_platform.py @@ -42,6 +42,8 @@ def _update_information_github(self): for repo in repos: if repo.fork and not self.fetch_repository_fork: continue + if repo.archived and not self.fetch_repository_archived: + continue self._update_github_repository(repo) self.last_update = fields.Datetime.now() @@ -58,15 +60,20 @@ def _update_github_repository(self, repo): "stargazers_count": repo.stargazers_count, "fork_count": repo.forks_count, "is_fork": repo.fork, + "active": not repo.archived, "watchers_count": repo.watchers_count, "description": repo.description, } - repository = self.env["vcp.repository"].search( - [ - ("name", "=", repo.name), - ("platform_id", "=", self.id), - ], - limit=1, + repository = ( + self.env["vcp.repository"] + .with_context(active_test=False) + .search( + [ + ("name", "=", repo.name), + ("platform_id", "=", self.id), + ], + limit=1, + ) ) if not repository: repository = ( diff --git a/vcp_management/models/vcp_platform.py b/vcp_management/models/vcp_platform.py index ae8a174..6ccb568 100644 --- a/vcp_management/models/vcp_platform.py +++ b/vcp_management/models/vcp_platform.py @@ -63,6 +63,10 @@ class VcpPlatform(models.Model): help="If checked, all repositories will be fetched (sources and forks)." " Otherwise, only sources repositories will be fetched" ) + fetch_repository_archived = fields.Boolean( + help="If checked, all repositories will be fetched (actives and archived)." + " Otherwise, only active repositories will be fetched" + ) local_path = fields.Char(compute="_compute_local_path") rule_ids = fields.Many2many( "vcp.rule", diff --git a/vcp_management/models/vcp_repository.py b/vcp_management/models/vcp_repository.py index c652f8e..3ec5e15 100644 --- a/vcp_management/models/vcp_repository.py +++ b/vcp_management/models/vcp_repository.py @@ -30,7 +30,7 @@ class VcpRepository(models.Model): request_ids = fields.One2many("vcp.request", inverse_name="repository_id") request_count = fields.Integer(compute="_compute_request_count") test_field = fields.Char() # TODO remove after testing - active = fields.Boolean(default=True) + active = fields.Boolean(default=True, readonly=True) information_update = fields.Boolean( compute="_compute_information_update", store=True, diff --git a/vcp_management/views/vcp_platform.xml b/vcp_management/views/vcp_platform.xml index 34d0673..6b7ee89 100644 --- a/vcp_management/views/vcp_platform.xml +++ b/vcp_management/views/vcp_platform.xml @@ -29,6 +29,7 @@ + diff --git a/vcp_management/views/vcp_repository.xml b/vcp_management/views/vcp_repository.xml index a492903..da889f2 100644 --- a/vcp_management/views/vcp_repository.xml +++ b/vcp_management/views/vcp_repository.xml @@ -58,6 +58,12 @@ /> + @@ -101,6 +107,11 @@ + @@ -108,7 +119,7 @@ vcp.repository - + From 6e8a995a65c7644dba26cec70df994811bb5efba Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Wed, 25 Feb 2026 22:58:13 +0100 Subject: [PATCH 05/22] [IMP] vcp_management: allow to delete a branch, if it has repository branch --- vcp_management/models/vcp_repository_branch.py | 1 + 1 file changed, 1 insertion(+) diff --git a/vcp_management/models/vcp_repository_branch.py b/vcp_management/models/vcp_repository_branch.py index 5878a06..6ff8f3f 100644 --- a/vcp_management/models/vcp_repository_branch.py +++ b/vcp_management/models/vcp_repository_branch.py @@ -18,6 +18,7 @@ class VcpRepositoryBranch(models.Model): "vcp.branch", string="Branch", required=True, + ondelete="cascade", ) repository_id = fields.Many2one( "vcp.repository", From b79d9873b3f6bb27c160b47d4af5071c97844d7c Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Wed, 25 Feb 2026 23:17:27 +0100 Subject: [PATCH 06/22] [IMP] vcp_*: add last_commit_date (in github, it related to 'PushedAt' field. (https://github.com/orgs/community/discussions/24442). It's an important field that show if the repo is active, or totally abandonned --- vcp_github/models/vcp_platform.py | 1 + vcp_management/models/vcp_repository.py | 1 + vcp_management/views/vcp_repository.xml | 2 ++ 3 files changed, 4 insertions(+) diff --git a/vcp_github/models/vcp_platform.py b/vcp_github/models/vcp_platform.py index 6f75b00..a673f38 100644 --- a/vcp_github/models/vcp_platform.py +++ b/vcp_github/models/vcp_platform.py @@ -57,6 +57,7 @@ def _parse_github_date(self, date): def _update_github_repository(self, repo): vals = { "created_at": self._parse_github_date(repo.created_at), + "last_commit_date": self._parse_github_date(repo.pushed_at), "stargazers_count": repo.stargazers_count, "fork_count": repo.forks_count, "is_fork": repo.fork, diff --git a/vcp_management/models/vcp_repository.py b/vcp_management/models/vcp_repository.py index 3ec5e15..369c65b 100644 --- a/vcp_management/models/vcp_repository.py +++ b/vcp_management/models/vcp_repository.py @@ -19,6 +19,7 @@ class VcpRepository(models.Model): required=True, ) created_at = fields.Datetime(readonly=True) + last_commit_date = fields.Datetime(readonly=True) stargazers_count = fields.Integer(readonly=True) is_fork = fields.Boolean( readonly=True, diff --git a/vcp_management/views/vcp_repository.xml b/vcp_management/views/vcp_repository.xml index da889f2..3884d97 100644 --- a/vcp_management/views/vcp_repository.xml +++ b/vcp_management/views/vcp_repository.xml @@ -67,6 +67,7 @@ + @@ -123,6 +124,7 @@ + From fcc76e23f3cc71b99b262d101d1bf98d22577c09 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Wed, 25 Feb 2026 23:36:39 +0100 Subject: [PATCH 07/22] [IMP] vcp_management: Add new smart button to go from a platform to related repositories --- vcp_management/models/vcp_platform.py | 6 ++++++ vcp_management/views/vcp_platform.xml | 16 +++++++++++++++- vcp_management/views/vcp_repository.xml | 7 +++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/vcp_management/models/vcp_platform.py b/vcp_management/models/vcp_platform.py index 6ccb568..e239e5c 100644 --- a/vcp_management/models/vcp_platform.py +++ b/vcp_management/models/vcp_platform.py @@ -57,6 +57,7 @@ class VcpPlatform(models.Model): "vcp.repository", inverse_name="platform_id", ) + repository_count = fields.Integer(compute="_compute_repository_count", store=True) default_update_repository_information = fields.Boolean() information_update = fields.Boolean() fetch_repository_fork = fields.Boolean( @@ -88,6 +89,11 @@ def _compute_local_path(self): for record in self: record.local_path = f"{source_path}/{record.id}" + @api.depends("repository_ids") + def _compute_repository_count(self): + for record in self: + record.repository_count = len(record.repository_ids) + def update_information(self): self.ensure_one() getattr(self, f"_update_information_{self.kind}")() diff --git a/vcp_management/views/vcp_platform.xml b/vcp_management/views/vcp_platform.xml index 6b7ee89..74154b5 100644 --- a/vcp_management/views/vcp_platform.xml +++ b/vcp_management/views/vcp_platform.xml @@ -15,7 +15,20 @@ /> -
+
+ +
+ diff --git a/vcp_management/views/vcp_repository.xml b/vcp_management/views/vcp_repository.xml index 3884d97..a8d96c6 100644 --- a/vcp_management/views/vcp_repository.xml +++ b/vcp_management/views/vcp_repository.xml @@ -157,6 +157,13 @@ + + Repositories + vcp.repository + list,form + [("platform_id", "=", active_id)] + + Repositories vcp-repositories From f3efe12d7aa596144b80d7960d2402f0b66acc39 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Thu, 26 Feb 2026 00:12:22 +0100 Subject: [PATCH 08/22] [FIX] vcp_github: adapt github mock to latest changes --- vcp_github/tests/test_github.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/vcp_github/tests/test_github.py b/vcp_github/tests/test_github.py index dd00238..f1d3df4 100644 --- a/vcp_github/tests/test_github.py +++ b/vcp_github/tests/test_github.py @@ -60,10 +60,16 @@ def test_update_organization_with_repository(self): mock_org.avatar_url = False mock_repo1 = MagicMock() mock_repo1.name = "server-tools" + mock_repo1.archived = False + mock_repo1.fork = False mock_repo1.created_at = "2020-01-01T00:00:00Z" + mock_repo1.pushed_at = "2020-02-01T00:00:00Z" mock_repo2 = MagicMock() mock_repo2.name = "server-brand" + mock_repo2.archived = False + mock_repo2.fork = False mock_repo2.created_at = "2021-01-01T10:00:00Z" + mock_repo2.pushed_at = "2021-02-01T00:00:00Z" mock_org.repositories.return_value = [mock_repo1, mock_repo2] mock_client.organization.return_value = mock_org mock_github3.login.return_value = mock_client @@ -102,6 +108,7 @@ def test_update_repository(self): "created_at": "2023-01-01T00:00:00Z", "updated_at": "2023-01-03T00:00:00Z", "closed_at": "2023-01-02T00:00:00Z", + "pushed_at": "2024-01-02T00:00:00Z", "commits": 3, "comments": 2, "review_comments": 1, From fb1fef9ffb397163dbd4eff7f955fbdbf2967cf8 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Thu, 26 Feb 2026 00:59:56 +0100 Subject: [PATCH 09/22] [REF] vcp_management: put vcp.platform.key model in dedicated file, applying OCA rule --- vcp_management/models/__init__.py | 1 + vcp_management/models/vcp_platform.py | 17 ---------------- vcp_management/models/vcp_platform_key.py | 24 +++++++++++++++++++++++ 3 files changed, 25 insertions(+), 17 deletions(-) create mode 100644 vcp_management/models/vcp_platform_key.py diff --git a/vcp_management/models/__init__.py b/vcp_management/models/__init__.py index aa400f5..be3a675 100644 --- a/vcp_management/models/__init__.py +++ b/vcp_management/models/__init__.py @@ -1,4 +1,5 @@ from . import vcp_platform +from . import vcp_platform_key from . import vcp_branch from . import vcp_rule from . import vcp_rule_information diff --git a/vcp_management/models/vcp_platform.py b/vcp_management/models/vcp_platform.py index e239e5c..d6461b7 100644 --- a/vcp_management/models/vcp_platform.py +++ b/vcp_management/models/vcp_platform.py @@ -366,20 +366,3 @@ def _improve_vcp_data(self, data, kind, **kwargs): values["name"] = repository.name values["url"] = repository._get_repository_url() return data - - -class VcpPlatformKey(models.Model): - _name = "vcp.platform.key" - _description = "VCP Platform API Key" # TODO - - platform_id = fields.Many2one( - comodel_name="vcp.platform", - string="Platform", - required=True, - ondelete="cascade", - ) - name = fields.Char(required=True) - - _sql_constraints = [ - ("name_uniq", "unique(name, platform_id)", "API Key must be unique.") - ] diff --git a/vcp_management/models/vcp_platform_key.py b/vcp_management/models/vcp_platform_key.py new file mode 100644 index 0000000..8e953ba --- /dev/null +++ b/vcp_management/models/vcp_platform_key.py @@ -0,0 +1,24 @@ +# Copyright 2026 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +import logging + +from odoo import fields, models + +_logger = logging.getLogger(__name__) + + +class VcpPlatformKey(models.Model): + _name = "vcp.platform.key" + _description = "VCP Platform API Key" # TODO + + platform_id = fields.Many2one( + comodel_name="vcp.platform", + string="Platform", + required=True, + ondelete="cascade", + ) + name = fields.Char(required=True) + + _sql_constraints = [ + ("name_uniq", "unique(name, platform_id)", "API Key must be unique.") + ] From 27b0f885236e699843a8cf220ce972ef132318c8 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Thu, 26 Feb 2026 01:05:43 +0100 Subject: [PATCH 10/22] [IMP] vcp_management: use new image.mixin, simplifying code base --- vcp_management/models/vcp_platform.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/vcp_management/models/vcp_platform.py b/vcp_management/models/vcp_platform.py index d6461b7..e0f2429 100644 --- a/vcp_management/models/vcp_platform.py +++ b/vcp_management/models/vcp_platform.py @@ -20,6 +20,7 @@ class VcpPlatform(models.Model): """ _name = "vcp.platform" + _inherit = ["image.mixin"] _description = "VCP Platform" name = fields.Char(required=True) @@ -28,21 +29,10 @@ class VcpPlatform(models.Model): last_update = fields.Datetime(readonly=True) active = fields.Boolean(default=True) update_interval_days = fields.Integer(default=3) - image_1920 = fields.Image() branch_ids = fields.One2many( "vcp.branch", inverse_name="platform_id", ) - image_128 = fields.Image( - max_width=128, - max_height=128, - store=True, - related="image_1920", - string="Image 128", - ) - image_64 = fields.Image( - max_width=64, max_height=64, store=True, related="image_1920", string="Image 64" - ) host_id = fields.Many2one( "vcp.host", required=True, From 5f551f7ff0f11fb1cfe5984b2dd342102c3d7e5f Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Thu, 26 Feb 2026 01:21:05 +0100 Subject: [PATCH 11/22] [IMP] vcp_odoo: use new image.mixin, simplifying code base --- vcp_odoo/models/vcp_odoo_module_version.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/vcp_odoo/models/vcp_odoo_module_version.py b/vcp_odoo/models/vcp_odoo_module_version.py index e56a884..f749ff7 100644 --- a/vcp_odoo/models/vcp_odoo_module_version.py +++ b/vcp_odoo/models/vcp_odoo_module_version.py @@ -7,7 +7,7 @@ class VcpOdooModuleVersion(models.Model): _name = "vcp.odoo.module.version" _description = "Odoo Module on an specific repository branch" - _inherit = ["vcp.rule.information.mixin"] + _inherit = ["vcp.rule.information.mixin", "image.mixin"] name = fields.Char(required=True) path = fields.Char(required=True) @@ -27,19 +27,6 @@ class VcpOdooModuleVersion(models.Model): license = fields.Char(string="License (Manifest)", readonly=True) summary = fields.Char(string="Summary (Manifest)", readonly=True) website = fields.Char(string="Website (Manifest)", readonly=True) - image_1920 = fields.Image( - max_width=1920, - max_height=1920, - readonly=True, - string="Image 1920x1920 (Manifest)", - ) - image_128 = fields.Image( - related="image_1920", - readonly=True, - max_width=128, - max_height=128, - string="Image 128x128 (Manifest)", - ) lib_python_ids = fields.Many2many( "vcp.odoo.lib.python", string="Python Libraries", From 044a7a51d0af06c193782da7ec60bffe712182fc Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Thu, 26 Feb 2026 01:28:33 +0100 Subject: [PATCH 12/22] [FIX] vcp_odoo: delete a repository branch should unlink related odoo modules. Otherwise, if we recreate after a repository branch, it will create odoo modules duplicated --- vcp_odoo/models/vcp_odoo_module_version.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vcp_odoo/models/vcp_odoo_module_version.py b/vcp_odoo/models/vcp_odoo_module_version.py index f749ff7..a04d2ba 100644 --- a/vcp_odoo/models/vcp_odoo_module_version.py +++ b/vcp_odoo/models/vcp_odoo_module_version.py @@ -19,6 +19,8 @@ class VcpOdooModuleVersion(models.Model): version = fields.Char(required=True) repository_branch_id = fields.Many2one( "vcp.repository.branch", + required=True, + ondelete="cascade", ) depends_on_module_ids = fields.Many2many( "vcp.odoo.module", From dc1df95a7452c37b22f8d0aa274812d2b524d702 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Thu, 26 Feb 2026 01:36:36 +0100 Subject: [PATCH 13/22] [IMP] vcp_odoo: Display number of versions in which the module is available. By default, set a filter to hide modules without versions --- vcp_odoo/models/vcp_odoo_module.py | 12 +++++++++++- vcp_odoo/views/vcp_odoo_module.xml | 8 +++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/vcp_odoo/models/vcp_odoo_module.py b/vcp_odoo/models/vcp_odoo_module.py index b5f2e16..05c4d85 100644 --- a/vcp_odoo/models/vcp_odoo_module.py +++ b/vcp_odoo/models/vcp_odoo_module.py @@ -1,7 +1,7 @@ # Copyright 2026 Dixmit # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from odoo import fields, models, tools +from odoo import api, fields, models, tools class VcpOdooModule(models.Model): @@ -10,11 +10,21 @@ class VcpOdooModule(models.Model): name = fields.Char(required=True) version_ids = fields.One2many("vcp.odoo.module.version", inverse_name="module_id") + version_count = fields.Integer( + compute="_compute_version_count", + help="number of versions in which the module is available", + store=True, + ) _sql_constraints = [ ("name_uniq", "unique(name)", "The module name must be unique"), ] + @api.depends("version_ids") + def _compute_version_count(self): + for record in self: + record.version_count = len(record.version_ids) + @tools.ormcache("name") def _get_odoo_module(self, name): """ diff --git a/vcp_odoo/views/vcp_odoo_module.xml b/vcp_odoo/views/vcp_odoo_module.xml index 57b2d67..5a2f85d 100644 --- a/vcp_odoo/views/vcp_odoo_module.xml +++ b/vcp_odoo/views/vcp_odoo_module.xml @@ -26,6 +26,11 @@ + @@ -35,6 +40,7 @@ + @@ -44,7 +50,7 @@ vcp.odoo.module list,form [] - {} + {'search_default_filter_with_version': 1} From c07c24942b89e46018e7f787ea36879d62dcab49 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Thu, 26 Feb 2026 01:53:25 +0100 Subject: [PATCH 14/22] [IMP] vcp_management: add branch count on repo level --- vcp_management/models/vcp_repository.py | 6 ++++++ vcp_management/views/vcp_repository.xml | 1 + 2 files changed, 7 insertions(+) diff --git a/vcp_management/models/vcp_repository.py b/vcp_management/models/vcp_repository.py index 369c65b..0c75604 100644 --- a/vcp_management/models/vcp_repository.py +++ b/vcp_management/models/vcp_repository.py @@ -51,6 +51,7 @@ class VcpRepository(models.Model): "vcp.repository.branch", inverse_name="repository_id", ) + branch_count = fields.Integer(compute="_compute_branch_count", store=True) def _get_rules(self): rules = self.rule_ids @@ -79,6 +80,11 @@ def _compute_request_count(self): for record in self: record.request_count = len(record.request_ids) + @api.depends("branch_ids") + def _compute_branch_count(self): + for record in self: + record.branch_count = len(record.branch_ids) + def update_branches(self): self.ensure_one() now = fields.Datetime.now() diff --git a/vcp_management/views/vcp_repository.xml b/vcp_management/views/vcp_repository.xml index a8d96c6..ab9b7f9 100644 --- a/vcp_management/views/vcp_repository.xml +++ b/vcp_management/views/vcp_repository.xml @@ -126,6 +126,7 @@ + From dfc1ca86650a6adc6d7de495deb662ddb4d2022e Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Thu, 26 Feb 2026 02:13:58 +0100 Subject: [PATCH 15/22] [IMP] vcp_odoo: display all the versionsw where the module is available --- vcp_management/models/vcp_repository_branch.py | 7 +++++++ vcp_odoo/models/vcp_odoo_module.py | 10 ++++++++++ vcp_odoo/views/vcp_odoo_module.xml | 5 +++++ 3 files changed, 22 insertions(+) diff --git a/vcp_management/models/vcp_repository_branch.py b/vcp_management/models/vcp_repository_branch.py index 6ff8f3f..88f5407 100644 --- a/vcp_management/models/vcp_repository_branch.py +++ b/vcp_management/models/vcp_repository_branch.py @@ -98,3 +98,10 @@ def _download_code(self): depth=1, ) return result + + def _compute_display_name(self): + if not self._context.get("display_only_branch_name"): + return super()._compute_display_name() + + for record in self: + record.display_name = record.branch_id.name diff --git a/vcp_odoo/models/vcp_odoo_module.py b/vcp_odoo/models/vcp_odoo_module.py index 05c4d85..479107e 100644 --- a/vcp_odoo/models/vcp_odoo_module.py +++ b/vcp_odoo/models/vcp_odoo_module.py @@ -15,6 +15,9 @@ class VcpOdooModule(models.Model): help="number of versions in which the module is available", store=True, ) + repository_branch_ids = fields.Many2many( + "vcp.repository.branch", compute="_compute_repository_branch_ids" + ) _sql_constraints = [ ("name_uniq", "unique(name)", "The module name must be unique"), @@ -25,6 +28,13 @@ def _compute_version_count(self): for record in self: record.version_count = len(record.version_ids) + @api.depends("version_ids.repository_branch_id") + def _compute_repository_branch_ids(self): + for record in self: + record.repository_branch_ids = record.mapped( + "version_ids.repository_branch_id" + ).sorted(lambda x: x.branch_id.name) + @tools.ormcache("name") def _get_odoo_module(self, name): """ diff --git a/vcp_odoo/views/vcp_odoo_module.xml b/vcp_odoo/views/vcp_odoo_module.xml index 5a2f85d..105d54a 100644 --- a/vcp_odoo/views/vcp_odoo_module.xml +++ b/vcp_odoo/views/vcp_odoo_module.xml @@ -40,6 +40,11 @@ + From 7a24dd651b233155b1eb8b73d1d29a95c6768101 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Thu, 26 Feb 2026 14:23:34 +0100 Subject: [PATCH 16/22] [ADD] vcp_github: demo data --- vcp_github/__manifest__.py | 4 +++- vcp_github/demo/demo_vcp_platform.xml | 7 +++++++ vcp_portal/tests/test_portal.py | 4 ++-- 3 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 vcp_github/demo/demo_vcp_platform.xml diff --git a/vcp_github/__manifest__.py b/vcp_github/__manifest__.py index 668f42d..5dfc3b5 100644 --- a/vcp_github/__manifest__.py +++ b/vcp_github/__manifest__.py @@ -17,5 +17,7 @@ "data": [ "data/data.xml", ], - "demo": [], + "demo": [ + "demo/demo_vcp_platform.xml", + ], } diff --git a/vcp_github/demo/demo_vcp_platform.xml b/vcp_github/demo/demo_vcp_platform.xml new file mode 100644 index 0000000..1bb895f --- /dev/null +++ b/vcp_github/demo/demo_vcp_platform.xml @@ -0,0 +1,7 @@ + + + + OCA + + + diff --git a/vcp_portal/tests/test_portal.py b/vcp_portal/tests/test_portal.py index 901fbe2..bdf5b42 100644 --- a/vcp_portal/tests/test_portal.py +++ b/vcp_portal/tests/test_portal.py @@ -41,7 +41,7 @@ def setUpClass(cls): ) platform = cls.env["vcp.platform"].create( { - "name": "oca", + "name": "oca-dev", "short_description": "OCA", "description": "OCA", "host_id": cls.host.id, @@ -50,7 +50,7 @@ def setUpClass(cls): repository = cls.env["vcp.repository"].create( { "name": "contributors-module", - "description": "OCA/contributors-module", + "description": "OCA-dev/contributors-module", "platform_id": platform.id, "from_date": date, } From 6e215266b35f6f7d753d1dee6fbd080c1a1f8ef9 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Thu, 26 Feb 2026 14:56:07 +0100 Subject: [PATCH 17/22] [IMP] vcp_*: Add branch pattern, to fetch only branches whose names are matching a given pattern. It allows to ignore ocabot branches, in case of fetching OCA repositories --- vcp_github/demo/demo_vcp_platform.xml | 1 + vcp_github/models/vcp_repository.py | 8 ++++++++ vcp_management/models/vcp_platform.py | 5 +++++ vcp_management/models/vcp_repository.py | 4 ++++ vcp_management/views/vcp_platform.xml | 1 + vcp_management/views/vcp_repository.xml | 1 + 6 files changed, 20 insertions(+) diff --git a/vcp_github/demo/demo_vcp_platform.xml b/vcp_github/demo/demo_vcp_platform.xml index 1bb895f..a039cd5 100644 --- a/vcp_github/demo/demo_vcp_platform.xml +++ b/vcp_github/demo/demo_vcp_platform.xml @@ -3,5 +3,6 @@ OCA + ^\d+\.\d+$ diff --git a/vcp_github/models/vcp_repository.py b/vcp_github/models/vcp_repository.py index cadc3e6..666c33e 100644 --- a/vcp_github/models/vcp_repository.py +++ b/vcp_github/models/vcp_repository.py @@ -1,6 +1,7 @@ # Copyright 2026 Dixmit # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). import logging +import re from datetime import datetime, timedelta import github3 @@ -25,6 +26,13 @@ def _update_branches_github(self): existing_branches = {b.branch_id.name: b for b in self.branch_ids} found_branches = self.env["vcp.repository.branch"] for branch in repo.branches(): + branch_pattern = ( + self.fetch_branch_pattern + or self.platform_id.fetch_repository_branch_pattern + or False + ) + if branch_pattern and not re.match(branch_pattern, branch.name): + continue if branch.name in existing_branches: existing_branches[branch.name].sudo().write( {"last_commit": branch.commit.sha} diff --git a/vcp_management/models/vcp_platform.py b/vcp_management/models/vcp_platform.py index e0f2429..77c6e6d 100644 --- a/vcp_management/models/vcp_platform.py +++ b/vcp_management/models/vcp_platform.py @@ -58,6 +58,11 @@ class VcpPlatform(models.Model): help="If checked, all repositories will be fetched (actives and archived)." " Otherwise, only active repositories will be fetched" ) + fetch_repository_branch_pattern = fields.Char( + help="Regular Expression. If set, only branches whose names are matching" + " the pattern will be fetched, when fetching branches of the repositories" + " of the platform." + ) local_path = fields.Char(compute="_compute_local_path") rule_ids = fields.Many2many( "vcp.rule", diff --git a/vcp_management/models/vcp_repository.py b/vcp_management/models/vcp_repository.py index 0c75604..665ef56 100644 --- a/vcp_management/models/vcp_repository.py +++ b/vcp_management/models/vcp_repository.py @@ -20,6 +20,10 @@ class VcpRepository(models.Model): ) created_at = fields.Datetime(readonly=True) last_commit_date = fields.Datetime(readonly=True) + fetch_branch_pattern = fields.Char( + help="Regular Expression. If set, only branches whose names are matching" + " the pattern will be fetched. You can define that value at platform level." + ) stargazers_count = fields.Integer(readonly=True) is_fork = fields.Boolean( readonly=True, diff --git a/vcp_management/views/vcp_platform.xml b/vcp_management/views/vcp_platform.xml index 74154b5..7015edb 100644 --- a/vcp_management/views/vcp_platform.xml +++ b/vcp_management/views/vcp_platform.xml @@ -43,6 +43,7 @@ + diff --git a/vcp_management/views/vcp_repository.xml b/vcp_management/views/vcp_repository.xml index ab9b7f9..8598815 100644 --- a/vcp_management/views/vcp_repository.xml +++ b/vcp_management/views/vcp_repository.xml @@ -67,6 +67,7 @@ + From 75f38b0d8d62efba06b66a71f339f0bbab2bf764 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Thu, 26 Feb 2026 15:04:55 +0100 Subject: [PATCH 18/22] [REF] vcp_odoo: create a python file per model, following OCA convention --- vcp_odoo/models/__init__.py | 2 ++ vcp_odoo/models/vcp_odoo_bin_package.py | 18 +++++++++++++ vcp_odoo/models/vcp_odoo_lib_python.py | 18 +++++++++++++ vcp_odoo/models/vcp_odoo_module_version.py | 30 +--------------------- 4 files changed, 39 insertions(+), 29 deletions(-) create mode 100644 vcp_odoo/models/vcp_odoo_bin_package.py create mode 100644 vcp_odoo/models/vcp_odoo_lib_python.py diff --git a/vcp_odoo/models/__init__.py b/vcp_odoo/models/__init__.py index 7e48d76..be6d37f 100644 --- a/vcp_odoo/models/__init__.py +++ b/vcp_odoo/models/__init__.py @@ -1,3 +1,5 @@ from . import vcp_rule from . import vcp_odoo_module from . import vcp_odoo_module_version +from . import vcp_odoo_bin_package +from . import vcp_odoo_lib_python diff --git a/vcp_odoo/models/vcp_odoo_bin_package.py b/vcp_odoo/models/vcp_odoo_bin_package.py new file mode 100644 index 0000000..2625e28 --- /dev/null +++ b/vcp_odoo/models/vcp_odoo_bin_package.py @@ -0,0 +1,18 @@ +# Copyright 2026 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models, tools + + +class VcpOdooBinPackage(models.Model): + _name = "vcp.odoo.bin.package" + _description = "Binary Package required by an Odoo Module" + + name = fields.Char(required=True) + + @tools.ormcache("name") + def _get_bin(self, name): + bin_src = self.search([("name", "=", name)], limit=1) + if not bin_src: + bin_src = self.create({"name": name}) + return bin_src.id diff --git a/vcp_odoo/models/vcp_odoo_lib_python.py b/vcp_odoo/models/vcp_odoo_lib_python.py new file mode 100644 index 0000000..2759f3c --- /dev/null +++ b/vcp_odoo/models/vcp_odoo_lib_python.py @@ -0,0 +1,18 @@ +# Copyright 2026 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models, tools + + +class VcpOdooLibPython(models.Model): + _name = "vcp.odoo.lib.python" + _description = "Python Library required by an Odoo Module" + + name = fields.Char(required=True) + + @tools.ormcache("name") + def _get_lib_python(self, name): + lib = self.search([("name", "=", name)], limit=1) + if not lib: + lib = self.create({"name": name}) + return lib.id diff --git a/vcp_odoo/models/vcp_odoo_module_version.py b/vcp_odoo/models/vcp_odoo_module_version.py index a04d2ba..363f860 100644 --- a/vcp_odoo/models/vcp_odoo_module_version.py +++ b/vcp_odoo/models/vcp_odoo_module_version.py @@ -1,7 +1,7 @@ # Copyright 2026 Dixmit # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from odoo import fields, models, tools +from odoo import fields, models class VcpOdooModuleVersion(models.Model): @@ -40,31 +40,3 @@ class VcpOdooModuleVersion(models.Model): def _get_local_path(self): return f"{self.repository_branch_id.local_path}/{self.path}" - - -class VcpOdooLibPython(models.Model): - _name = "vcp.odoo.lib.python" - _description = "Python Library required by an Odoo Module" - - name = fields.Char(required=True) - - @tools.ormcache("name") - def _get_lib_python(self, name): - lib = self.search([("name", "=", name)], limit=1) - if not lib: - lib = self.create({"name": name}) - return lib.id - - -class VcpOdooBinPackage(models.Model): - _name = "vcp.odoo.bin.package" - _description = "Binary Package required by an Odoo Module" - - name = fields.Char(required=True) - - @tools.ormcache("name") - def _get_bin(self, name): - bin_src = self.search([("name", "=", name)], limit=1) - if not bin_src: - bin_src = self.create({"name": name}) - return bin_src.id From fca47850a53ea6f3b66e502005fd1609d5abd8d1 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Thu, 26 Feb 2026 15:32:39 +0100 Subject: [PATCH 19/22] [REF] vcp_management: use new menu items nested system --- vcp_management/__manifest__.py | 2 +- vcp_management/views/menu.xml | 59 ++++++++++++++++++++--- vcp_management/views/vcp_host.xml | 7 --- vcp_management/views/vcp_organization.xml | 7 --- vcp_management/views/vcp_platform.xml | 7 --- vcp_management/views/vcp_repository.xml | 7 --- vcp_management/views/vcp_request.xml | 7 --- vcp_management/views/vcp_rule.xml | 7 --- vcp_management/views/vcp_user.xml | 7 --- 9 files changed, 53 insertions(+), 57 deletions(-) diff --git a/vcp_management/__manifest__.py b/vcp_management/__manifest__.py index 24fe0d4..ea5f64d 100644 --- a/vcp_management/__manifest__.py +++ b/vcp_management/__manifest__.py @@ -14,7 +14,6 @@ "security/ir.model.access.csv", "data/ir_cron.xml", "templates/templates.xml", - "views/menu.xml", "views/vcp_comment.xml", "views/vcp_review.xml", "views/vcp_request.xml", @@ -26,6 +25,7 @@ "views/vcp_host.xml", "views/vcp_rule.xml", "views/vcp_rule_information.xml", + "views/menu.xml", ], "demo": [], "external_dependencies": { diff --git a/vcp_management/views/menu.xml b/vcp_management/views/menu.xml index 1876455..9c16a8d 100644 --- a/vcp_management/views/menu.xml +++ b/vcp_management/views/menu.xml @@ -7,11 +7,56 @@ name="Virtual Control Platform" sequence="16" web_icon="vcp_management,static/description/icon.png" - /> - + > + + + + + + + + + + + + + + + + diff --git a/vcp_management/views/vcp_host.xml b/vcp_management/views/vcp_host.xml index d82675e..a231261 100644 --- a/vcp_management/views/vcp_host.xml +++ b/vcp_management/views/vcp_host.xml @@ -46,11 +46,4 @@ [] {} - - - Platform Types - - - - diff --git a/vcp_management/views/vcp_organization.xml b/vcp_management/views/vcp_organization.xml index e27b22e..142a44a 100644 --- a/vcp_management/views/vcp_organization.xml +++ b/vcp_management/views/vcp_organization.xml @@ -44,11 +44,4 @@ [] {} - - - Organizations - - - - diff --git a/vcp_management/views/vcp_platform.xml b/vcp_management/views/vcp_platform.xml index 7015edb..f3e8189 100644 --- a/vcp_management/views/vcp_platform.xml +++ b/vcp_management/views/vcp_platform.xml @@ -93,11 +93,4 @@ [] {} - - - Platforms - - - - diff --git a/vcp_management/views/vcp_repository.xml b/vcp_management/views/vcp_repository.xml index 8598815..75ba13f 100644 --- a/vcp_management/views/vcp_repository.xml +++ b/vcp_management/views/vcp_repository.xml @@ -174,11 +174,4 @@ [] {} - - - Repositories - - - - diff --git a/vcp_management/views/vcp_request.xml b/vcp_management/views/vcp_request.xml index fd7b5ee..d2a203a 100644 --- a/vcp_management/views/vcp_request.xml +++ b/vcp_management/views/vcp_request.xml @@ -82,11 +82,4 @@ [("repository_id", "=", active_id)] {} - - - Requests - - - - diff --git a/vcp_management/views/vcp_rule.xml b/vcp_management/views/vcp_rule.xml index ab5ca77..e621272 100644 --- a/vcp_management/views/vcp_rule.xml +++ b/vcp_management/views/vcp_rule.xml @@ -49,11 +49,4 @@ [] {} - - - Processing Rules - - - - diff --git a/vcp_management/views/vcp_user.xml b/vcp_management/views/vcp_user.xml index 7cff525..18e17f9 100644 --- a/vcp_management/views/vcp_user.xml +++ b/vcp_management/views/vcp_user.xml @@ -47,11 +47,4 @@ [] {} - - - Users - - - - From b256b9eeb31a8a1b471a682896a2c46d5c1fdb96 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Thu, 26 Feb 2026 15:50:18 +0100 Subject: [PATCH 20/22] [IMP] vcp_management: Add vcp.branch menuitem, and improve display --- vcp_management/models/vcp_branch.py | 1 + vcp_management/views/menu.xml | 9 +++++++++ vcp_management/views/vcp_branch.xml | 13 ++++++++++++- vcp_management/views/vcp_platform.xml | 6 +++++- 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/vcp_management/models/vcp_branch.py b/vcp_management/models/vcp_branch.py index 1ac5390..3c47744 100644 --- a/vcp_management/models/vcp_branch.py +++ b/vcp_management/models/vcp_branch.py @@ -17,6 +17,7 @@ class VcpBranch(models.Model): comodel_name="vcp.platform", string="Platform", required=True, + readonly=True, ) _sql_constraints = [ ("name_uniq", "unique(name, platform_id)", "Branch name must be unique.") diff --git a/vcp_management/views/menu.xml b/vcp_management/views/menu.xml index 9c16a8d..86ff139 100644 --- a/vcp_management/views/menu.xml +++ b/vcp_management/views/menu.xml @@ -29,6 +29,15 @@ sequence="20" /> + + + + - + + @@ -21,7 +22,17 @@ + + + + Branches + vcp.branch + vcp-branch + list,form + [] + {} + diff --git a/vcp_management/views/vcp_platform.xml b/vcp_management/views/vcp_platform.xml index f3e8189..4798e72 100644 --- a/vcp_management/views/vcp_platform.xml +++ b/vcp_management/views/vcp_platform.xml @@ -50,7 +50,11 @@ - + + + + + From 6cbc808777b0f618b7cea5db9b258e10ccde4c6b Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Sat, 28 Feb 2026 00:22:44 +0100 Subject: [PATCH 21/22] [IMP+FIX] vcp_comment: Add vcp.branch menuitem, and improve display. Fix body storage. (convert markdown into html) --- requirements.txt | 1 + vcp_github/__manifest__.py | 2 +- vcp_github/models/vcp_platform.py | 4 ++++ vcp_github/models/vcp_repository.py | 4 ++-- vcp_management/views/menu.xml | 6 ++++++ vcp_management/views/vcp_comment.xml | 20 ++++++++++++++++++++ 6 files changed, 34 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index e67d950..06fba4a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ # generated from manifests external_dependencies GitPython github3.py +markdown pathspec diff --git a/vcp_github/__manifest__.py b/vcp_github/__manifest__.py index 5dfc3b5..d10048f 100644 --- a/vcp_github/__manifest__.py +++ b/vcp_github/__manifest__.py @@ -12,7 +12,7 @@ "vcp_management", ], "external_dependencies": { - "python": ["github3.py"], + "python": ["github3.py", "markdown"], }, "data": [ "data/data.xml", diff --git a/vcp_github/models/vcp_platform.py b/vcp_github/models/vcp_platform.py index a673f38..aba8a07 100644 --- a/vcp_github/models/vcp_platform.py +++ b/vcp_github/models/vcp_platform.py @@ -5,6 +5,7 @@ from datetime import datetime import github3 +import markdown import requests from pytz import UTC @@ -54,6 +55,9 @@ def _parse_github_date(self, date): datetime.fromisoformat(date.replace("Z", "+00:00")) ).replace(tzinfo=None) + def _parse_github_markdown(self, text): + return markdown.markdown(text) + def _update_github_repository(self, repo): vals = { "created_at": self._parse_github_date(repo.created_at), diff --git a/vcp_github/models/vcp_repository.py b/vcp_github/models/vcp_repository.py index 666c33e..a44dc09 100644 --- a/vcp_github/models/vcp_repository.py +++ b/vcp_github/models/vcp_repository.py @@ -113,7 +113,7 @@ def _parse_github_pr(self, pr, client): "id": str(c["id"]), "user_id": c.get("user") and self.platform_id.host_id._get_user(c["user"].get("login")), - "body": c["body"], + "body": self.platform_id._parse_github_markdown(c["body"]), "created_at": self.platform_id._parse_github_date(c["created_at"]), "updated_at": self.platform_id._parse_github_date(c["updated_at"]), } @@ -124,7 +124,7 @@ def _parse_github_pr(self, pr, client): "id": str(r["id"]), "user_id": r.get("user") and self.platform_id.host_id._get_user(r["user"].get("login")), - "body": r["body"], + "body": self.platform_id._parse_github_markdown(r["body"]), "submitted_at": self.platform_id._parse_github_date( r.get("submitted_at") ), diff --git a/vcp_management/views/menu.xml b/vcp_management/views/menu.xml index 86ff139..2166395 100644 --- a/vcp_management/views/menu.xml +++ b/vcp_management/views/menu.xml @@ -36,6 +36,12 @@ action="vcp_branch_act_window" sequence="10" /> + diff --git a/vcp_management/views/vcp_comment.xml b/vcp_management/views/vcp_comment.xml index c43cec9..a81b1c4 100644 --- a/vcp_management/views/vcp_comment.xml +++ b/vcp_management/views/vcp_comment.xml @@ -9,7 +9,16 @@
+ + + + + + + + + @@ -20,7 +29,18 @@ + + + + + + + Comments + vcp.comment + vcp-comment + list,form + From 32e0be34b0338ed12aa31b4421c06daec182f7bc Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Sat, 28 Feb 2026 00:39:59 +0100 Subject: [PATCH 22/22] [IMP] vcp_management: Add vcp.review menuitem, and improve display --- vcp_management/views/menu.xml | 6 ++++++ vcp_management/views/vcp_review.xml | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/vcp_management/views/menu.xml b/vcp_management/views/menu.xml index 2166395..91d7b02 100644 --- a/vcp_management/views/menu.xml +++ b/vcp_management/views/menu.xml @@ -42,6 +42,12 @@ action="vcp_comment_act_window" sequence="30" /> + diff --git a/vcp_management/views/vcp_review.xml b/vcp_management/views/vcp_review.xml index 6c20335..b30c8fd 100644 --- a/vcp_management/views/vcp_review.xml +++ b/vcp_management/views/vcp_review.xml @@ -10,6 +10,11 @@ + + + + + @@ -21,7 +26,18 @@ + + + + + + + Reviews + vcp.review + vcp-review + list,form +