[IMP] runbot: add kanban view and stages to build error page

Introduce a kanban view to the runbot build error records.
Kanban cards show the most valuable field with relevant icons.

The concept of "state" was also introduced for the build error
model.
Currently there is 3 states:
 1. New: default state for any new error build
 2. Solved: when the issue should be solved
 3. Disabled: build error currently disabled (test-tags)

States are expected to be used by the user. For instance
after fixing an underteministic error the user can change the
state from new -> solved so that the user knows that he's actively
not working on it
This commit is contained in:
lse-odoo 2025-02-28 18:12:02 +01:00
parent 78964285b2
commit d846b4e382
4 changed files with 78 additions and 2 deletions

View File

@ -6,7 +6,7 @@
'author': "Odoo SA",
'website': "http://runbot.odoo.com",
'category': 'Website',
'version': '5.10',
'version': '5.11',
'application': True,
'depends': ['base', 'base_automation', 'website'],
'data': [

View File

@ -0,0 +1,15 @@
def migrate(cr, version):
# Build errors with test_tags are considered disabled
cr.execute("""
UPDATE runbot_build_error
SET state = 'disabled'
WHERE test_tags IS NOT NULL AND active IS TRUE
""")
# Archived build errors are considered solved
# Note: archived records with test-tags are considered solved too
cr.execute("""
UPDATE runbot_build_error
SET state = 'solved'
WHERE active IS FALSE
""")

View File

@ -105,6 +105,15 @@ class BuildError(models.Model):
error_count = fields.Integer("Error count", store=True, compute='_compute_count')
previous_error_id = fields.Many2one('runbot.build.error', string="Already seen error")
state = fields.Selection([
('new', 'New/Unsolved'),
('solved', 'Solved'),
('disabled', 'Disabled'),
], default='new', tracking=True, group_expand=True,
help="New: Error is new and not yet solved.\n"
"Solved: Error should be solved.\n"
"Disabled: Error is disabled (generally set with test tags).")
)
responsible = fields.Many2one('res.users', 'Assigned fixer', tracking=True)
customer = fields.Many2one('res.users', 'Customer', tracking=True)
team_id = fields.Many2one('runbot.team', 'Assigned team', tracking=True)

View File

@ -5,6 +5,9 @@
<field name="model">runbot.build.error</field>
<field name="arch" type="xml">
<form>
<header>
<field name="state" widget="statusbar" options="{'clickable': '1'}"/>
</header>
<sheet>
<div name="button_box">
<button class="oe_stat_button" type="object" icon="fa-exclamation-circle" name="action_get_build_link_record">
@ -329,6 +332,55 @@
<field name="binding_view_types">list</field>
</record>
<record id="build_error_view_kanban" model="ir.ui.view">
<field name="name">runbot.build.error.kanban</field>
<field name="model">runbot.build.error</field>
<field name="arch" type="xml">
<kanban default_group_by="state" quick_create="false" default_order="last_seen_date desc">
<templates>
<t t-name="card">
<widget name="web_ribbon" title="Test-tags" bg_color="bg-danger" invisible="not test_tags"/>
<field name="name" class="fw-bold fs-5"/>
<group>
<div class="d-flex align-items-center">
<i class="fa fa-clock-o me-2" title="Date interval from first seen to last seen"/>
<field name="first_seen_date" widget="remaining_days"/>
<i class="fa fa-long-arrow-right mx-2 oe_read_only" title="to"/>
<field name="last_seen_date" widget="remaining_days"/>
</div>
<div class="d-flex align-items-center gap-1">
<i class="fa fa-repeat" title="Number of occurence"/>
<field name="error_count"/>
</div>
<div class="d-flex align-items-center gap-1">
<i class="fa fa-bullseye" title="Triggers"/>
<field name="trigger_ids" widget="many2many_tags"/>
</div>
</group>
<footer>
<div class="d-flex align-items-center gap-1">
<field name="activity_ids" widget="kanban_activity"/>
</div>
<div class="d-flex align-items-center gap-1 ms-auto">
<i class="fa fa-random text-danger" title="inconsistant" invisible="not random"/>
<i class="fa fa-users" title="Responsible team"/>
<field name="team_id"/> <i t-if="!record.team_id.raw_value">no team</i>
<i class="fa fa-address-card" title="Investigator"/>
<field name="customer" widget="many2one_avatar_user"/>
<i class="fa fa-wrench" title="Solver"/>
<field name="responsible" widget="many2one_avatar_user"/>
<field name="fixing_pr_url" widget="url" text="PR" invisible="not fixing_pr_url"/>
</div>
</footer>
</t>
</templates>
</kanban>
</field>
</record>
<record id="build_error_view_tree" model="ir.ui.view">
<field name="name">runbot.build.error.list</field>
<field name="model">runbot.build.error</field>
@ -478,7 +530,7 @@
<field name="name">Errors</field>
<field name="res_model">runbot.build.error</field>
<field name="path">error</field>
<field name="view_mode">list,form</field>
<field name="view_mode">list,kanban,form</field>
<field name="context">{'search_default_not_fixed_errors': True, 'active_test': False}</field>
</record>