mirror of
https://github.com/odoo/runbot.git
synced 2025-03-27 13:25:47 +07:00
[IMP] mergebot, forwardbot: various UI bits
- code in the various menus added over time through the UI (queues, configuration, ...) - update / improve PR layout a tick - fix "outstanding forward ports" count on the dashboard - improve hover title / help on dashboard - add date of last modification (usually date of success / failure) - make casing more coherent (everything lowercase) - add explicit note that UTC date on staged at label is staged at datetime - rediscover yet again that the staging information is when hovering on the staging *except the staged at label* - improve `PullRequest.unstage` to always insert the PR at the start of the reason when cancelling the staging, for clarity / traceability Closes #560, closes #609
This commit is contained in:
parent
56898df93f
commit
2204c0410a
@ -8,6 +8,7 @@
|
|||||||
'data/security.xml',
|
'data/security.xml',
|
||||||
'data/crons.xml',
|
'data/crons.xml',
|
||||||
'data/views.xml',
|
'data/views.xml',
|
||||||
|
'data/queues.xml',
|
||||||
],
|
],
|
||||||
'license': 'LGPL-3',
|
'license': 'LGPL-3',
|
||||||
}
|
}
|
||||||
|
51
forwardport/data/queues.xml
Normal file
51
forwardport/data/queues.xml
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<odoo>
|
||||||
|
<record id="action_forward_port" model="ir.actions.act_window">
|
||||||
|
<field name="name">Forward port batches</field>
|
||||||
|
<field name="res_model">forwardport.batches</field>
|
||||||
|
<field name="context">{'active_test': False}</field>
|
||||||
|
</record>
|
||||||
|
<record id="tree_forward_port" model="ir.ui.view">
|
||||||
|
<field name="name">Forward port batches</field>
|
||||||
|
<field name="model">forwardport.batches</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<tree>
|
||||||
|
<field name="source"/>
|
||||||
|
<field name="batch_id"/>
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
<record id="form_forward_port" model="ir.ui.view">
|
||||||
|
<field name="name">Forward port batch</field>
|
||||||
|
<field name="model">forwardport.batches</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form>
|
||||||
|
<group>
|
||||||
|
<group><field name="source"/></group>
|
||||||
|
<group><field name="batch_id"/></group>
|
||||||
|
</group>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="action_followup_updates" model="ir.actions.act_window">
|
||||||
|
<field name="name">Followup Updates</field>
|
||||||
|
<field name="res_model">forwardport.updates</field>
|
||||||
|
</record>
|
||||||
|
<record id="tree_followup_updates" model="ir.ui.view">
|
||||||
|
<field name="name">Followup Updates</field>
|
||||||
|
<field name="model">forwardport.updates</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<tree editable="bottom">
|
||||||
|
<field name="original_root"/>
|
||||||
|
<field name="new_root"/>
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<menuitem name="Forward Port Batches" id="menu_forward_port"
|
||||||
|
parent="runbot_merge.menu_queues"
|
||||||
|
action="action_forward_port"/>
|
||||||
|
<menuitem name="Followup Updates" id="menu_followup"
|
||||||
|
parent="runbot_merge.menu_queues"
|
||||||
|
action="action_followup_updates"/>
|
||||||
|
</odoo>
|
@ -12,6 +12,7 @@
|
|||||||
<t t-set="outstanding" t-value="env['runbot_merge.pull_requests'].search_count([
|
<t t-set="outstanding" t-value="env['runbot_merge.pull_requests'].search_count([
|
||||||
('source_id', '!=', False),
|
('source_id', '!=', False),
|
||||||
('state', 'not in', ['merged', 'closed']),
|
('state', 'not in', ['merged', 'closed']),
|
||||||
|
('source_id.merge_date', '<', datetime.datetime.now() - relativedelta(days=3)),
|
||||||
])"/>
|
])"/>
|
||||||
<div t-if="outstanding != 0" class="alert col-md-12 alert-warning mb-0">
|
<div t-if="outstanding != 0" class="alert col-md-12 alert-warning mb-0">
|
||||||
<a href="/forwardport/outstanding">
|
<a href="/forwardport/outstanding">
|
||||||
@ -175,6 +176,9 @@
|
|||||||
<field name="inherit_id" ref="runbot_merge.runbot_merge_form_prs"/>
|
<field name="inherit_id" ref="runbot_merge.runbot_merge_form_prs"/>
|
||||||
<field name="model">runbot_merge.pull_requests</field>
|
<field name="model">runbot_merge.pull_requests</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//field[@name='state']" position="after">
|
||||||
|
<field name="merge_date" attrs="{'invisible': [('state', '!=', 'merged')]}"/>
|
||||||
|
</xpath>
|
||||||
<xpath expr="//sheet/group[2]" position="after">
|
<xpath expr="//sheet/group[2]" position="after">
|
||||||
<separator string="Forward Port" attrs="{'invisible': [('source_id', '=', False)]}"/>
|
<separator string="Forward Port" attrs="{'invisible': [('source_id', '=', False)]}"/>
|
||||||
<group attrs="{'invisible': [('source_id', '!=', False)]}">
|
<group attrs="{'invisible': [('source_id', '!=', False)]}">
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
'views/res_partner.xml',
|
'views/res_partner.xml',
|
||||||
'views/runbot_merge_project.xml',
|
'views/runbot_merge_project.xml',
|
||||||
'views/mergebot.xml',
|
'views/mergebot.xml',
|
||||||
|
'views/queues.xml',
|
||||||
|
'views/configuration.xml',
|
||||||
'views/templates.xml',
|
'views/templates.xml',
|
||||||
'models/project_freeze/views.xml',
|
'models/project_freeze/views.xml',
|
||||||
],
|
],
|
||||||
|
6
runbot_merge/changelog/2022-06/ui.md
Normal file
6
runbot_merge/changelog/2022-06/ui.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
IMP: various UI items
|
||||||
|
|
||||||
|
- more clearly differentiate between "pending" and "unknown" statuses on stagings
|
||||||
|
- fix "outstanding forward ports" count
|
||||||
|
- add date of staging last modification (= success / failure instant)
|
||||||
|
- correctly retrieve and include fast-forward and unstaging reasons
|
@ -171,11 +171,7 @@ def handle_pr(env, event):
|
|||||||
return "It's my understanding that closed/merged PRs don't get sync'd"
|
return "It's my understanding that closed/merged PRs don't get sync'd"
|
||||||
|
|
||||||
if pr_obj.state == 'ready':
|
if pr_obj.state == 'ready':
|
||||||
pr_obj.unstage(
|
pr_obj.unstage("updated by %s", event['sender']['login'])
|
||||||
"PR %s updated by %s",
|
|
||||||
pr_obj.display_name,
|
|
||||||
event['sender']['login']
|
|
||||||
)
|
|
||||||
|
|
||||||
_logger.info(
|
_logger.info(
|
||||||
"PR %s updated to %s by %s, resetting to 'open' and squash=%s",
|
"PR %s updated to %s by %s, resetting to 'open' and squash=%s",
|
||||||
|
@ -846,7 +846,7 @@ class PullRequests(models.Model):
|
|||||||
'pull_request': self.number,
|
'pull_request': self.number,
|
||||||
'message': "PR priority reset to 1, as pull requests with priority 0 ignore review state.",
|
'message': "PR priority reset to 1, as pull requests with priority 0 ignore review state.",
|
||||||
})
|
})
|
||||||
self.unstage("unreview (r-) by %s", author.github_login)
|
self.unstage("unreviewed (r-) by %s", author.github_login)
|
||||||
ok = True
|
ok = True
|
||||||
else:
|
else:
|
||||||
msg = "r- makes no sense in the current PR state."
|
msg = "r- makes no sense in the current PR state."
|
||||||
@ -1349,7 +1349,7 @@ class PullRequests(models.Model):
|
|||||||
# else remove this batch from the split
|
# else remove this batch from the split
|
||||||
b.split_id = False
|
b.split_id = False
|
||||||
|
|
||||||
self.staging_id.cancel(reason, *args)
|
self.staging_id.cancel('%s ' + reason, self.display_name, *args)
|
||||||
|
|
||||||
def _try_closing(self, by):
|
def _try_closing(self, by):
|
||||||
# ignore if the PR is already being updated in a separate transaction
|
# ignore if the PR is already being updated in a separate transaction
|
||||||
@ -1369,11 +1369,7 @@ class PullRequests(models.Model):
|
|||||||
''', [self.id])
|
''', [self.id])
|
||||||
self.env.cr.commit()
|
self.env.cr.commit()
|
||||||
self.modified(['state'])
|
self.modified(['state'])
|
||||||
self.unstage(
|
self.unstage("closed by %s", by)
|
||||||
"PR %s closed by %s",
|
|
||||||
self.display_name,
|
|
||||||
by
|
|
||||||
)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# state changes on reviews
|
# state changes on reviews
|
||||||
|
43
runbot_merge/views/configuration.xml
Normal file
43
runbot_merge/views/configuration.xml
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<odoo>
|
||||||
|
<record id="action_overrides" model="ir.actions.act_window">
|
||||||
|
<field name="name">CI / statuses overrides</field>
|
||||||
|
<field name="res_model">res.partner.override</field>
|
||||||
|
</record>
|
||||||
|
<record id="tree_overrides" model="ir.ui.view">
|
||||||
|
<field name="name">Overrides List</field>
|
||||||
|
<field name="model">res.partner.override</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<tree editable="bottom">
|
||||||
|
<field name="context"/>
|
||||||
|
<field name="repository_id"/>
|
||||||
|
<field name="partner_ids" widget="many2many_tags"/>
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="action_review" model="ir.actions.act_window">
|
||||||
|
<field name="name">Review Rights</field>
|
||||||
|
<field name="res_model">res.partner.review</field>
|
||||||
|
<field name="context">{'search_default_group_by_repository': True}</field>
|
||||||
|
</record>
|
||||||
|
<record id="tree_review" model="ir.ui.view">
|
||||||
|
<field name="name">Review Rights</field>
|
||||||
|
<field name="model">res.partner.review</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<tree editable="bottom">
|
||||||
|
<field name="repository_id"/>
|
||||||
|
<field name="partner_id"/>
|
||||||
|
<field name="review"/>
|
||||||
|
<field name="self_review"/>
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<menuitem name="Configuration" id="menu_configuration" parent="runbot_merge_menu"/>
|
||||||
|
<menuitem name="CI Overrides" id="menu_configuration_overrides"
|
||||||
|
parent="menu_configuration"
|
||||||
|
action="action_overrides"/>
|
||||||
|
<menuitem name="Review Rights" id="menu_configuration_review"
|
||||||
|
parent="menu_configuration"
|
||||||
|
action="action_review"/>
|
||||||
|
</odoo>
|
@ -97,10 +97,10 @@
|
|||||||
<field name="target"/>
|
<field name="target"/>
|
||||||
<field name="state"/>
|
<field name="state"/>
|
||||||
<field name="author"/>
|
<field name="author"/>
|
||||||
<field name="priority"/>
|
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="label"/>
|
<field name="label"/>
|
||||||
|
<field name="priority"/>
|
||||||
<field name="squash"/>
|
<field name="squash"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
@ -108,6 +108,8 @@
|
|||||||
<group colspan="4">
|
<group colspan="4">
|
||||||
<field name="head"/>
|
<field name="head"/>
|
||||||
<field name="statuses"/>
|
<field name="statuses"/>
|
||||||
|
</group>
|
||||||
|
<group colspan="4">
|
||||||
<field name="overrides"/>
|
<field name="overrides"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
@ -205,66 +207,33 @@
|
|||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="runbot_merge_action_fetches" model="ir.actions.act_window">
|
<record id="runbot_merge_action_commits" model="ir.actions.act_window">
|
||||||
<field name="name">PRs to fetch</field>
|
<field name="name">Commit Statuses</field>
|
||||||
<field name="res_model">runbot_merge.fetch_job</field>
|
<field name="res_model">runbot_merge.commit</field>
|
||||||
<field name="view_mode">tree</field>
|
<field name="view_mode">tree,form</field>
|
||||||
<field name="context">{'default_active': True}</field>
|
|
||||||
</record>
|
</record>
|
||||||
<record id="runbot_merge_search_fetches" model="ir.ui.view">
|
<record id="runbot_merge_commits_tree" model="ir.ui.view">
|
||||||
<field name="name">Fetches Search</field>
|
<field name="name">commits list</field>
|
||||||
<field name="model">runbot_merge.fetch_job</field>
|
<field name="model">runbot_merge.commit</field>
|
||||||
<field name="arch" type="xml">
|
|
||||||
<search>
|
|
||||||
<filter string="Active" name="active"
|
|
||||||
domain="[('active', '=', True)]"/>
|
|
||||||
<field name="repository"/>
|
|
||||||
<field name="number"/>
|
|
||||||
</search>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
<record id="runbot_merge_tree_fetches" model="ir.ui.view">
|
|
||||||
<field name="name">Fetches Tree</field>
|
|
||||||
<field name="model">runbot_merge.fetch_job</field>
|
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<tree>
|
<tree>
|
||||||
<field name="repository"/>
|
<field name="sha"/>
|
||||||
<field name="number"/>
|
<field name="statuses"/>
|
||||||
</tree>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="runbot_merge_action_overrides" model="ir.actions.act_window">
|
|
||||||
<field name="name">CI / statuses overrides</field>
|
|
||||||
<field name="res_model">res.partner.override</field>
|
|
||||||
</record>
|
|
||||||
<record id="runot_merge_tree_overrides" model="ir.ui.view">
|
|
||||||
<field name="name">Overrides List</field>
|
|
||||||
<field name="model">res.partner.override</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<tree editable="bottom">
|
|
||||||
<field name="context"/>
|
|
||||||
<field name="repository_id"/>
|
|
||||||
<field name="partner_ids" widget="many2many_tags"/>
|
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<menuitem name="Mergebot" id="runbot_merge_menu"/>
|
<menuitem name="Mergebot" id="runbot_merge_menu"/>
|
||||||
<menuitem name="Projects" id="runbot_merge_menu_project"
|
<menuitem name="Projects" id="runbot_merge_menu_project"
|
||||||
parent="runbot_merge_menu"
|
parent="runbot_merge_menu"
|
||||||
action="runbot_merge_action_projects"/>
|
action="runbot_merge_action_projects"/>
|
||||||
<menuitem name="Pull Requests" id="runbot_merge_menu_prs"
|
<menuitem name="Pull Requests" id="runbot_merge_menu_prs"
|
||||||
parent="runbot_merge_menu"
|
parent="runbot_merge_menu"
|
||||||
action="runbot_merge_action_prs"/>
|
action="runbot_merge_action_prs"/>
|
||||||
<menuitem name="Stagings" id="runbot_merge_menu_stagings"
|
<menuitem name="Stagings" id="runbot_merge_menu_stagings"
|
||||||
parent="runbot_merge_menu"
|
parent="runbot_merge_menu"
|
||||||
action="runbot_merge_action_stagings"/>
|
action="runbot_merge_action_stagings"/>
|
||||||
<menuitem name="Fetches" id="runbot_merge_menu_fetches"
|
<menuitem name="Commits" id="runbot_merge_menu_commits"
|
||||||
parent="runbot_merge_menu"
|
parent="runbot_merge_menu"
|
||||||
action="runbot_merge_action_fetches"/>
|
action="runbot_merge_action_commits"/>
|
||||||
<menuitem name="Configuration" id="runbot_merge_menu_configuration" parent="runbot_merge_menu"/>
|
|
||||||
<menuitem name="CI Overrides" id="runbot_merge_menu_configuration_overrides"
|
|
||||||
parent="runbot_merge_menu"
|
|
||||||
action="runbot_merge_action_overrides"/>
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
97
runbot_merge/views/queues.xml
Normal file
97
runbot_merge/views/queues.xml
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
<odoo>
|
||||||
|
<!--
|
||||||
|
Queues mergebot menu: contains various list views inspecting the cron tasks
|
||||||
|
(mostly)
|
||||||
|
-->
|
||||||
|
<record id="action_splits" model="ir.actions.act_window">
|
||||||
|
<field name="name">Splits</field>
|
||||||
|
<field name="res_model">runbot_merge.split</field>
|
||||||
|
</record>
|
||||||
|
<record id="tree_splits" model="ir.ui.view">
|
||||||
|
<field name="name">Splits</field>
|
||||||
|
<field name="model">runbot_merge.split</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<tree>
|
||||||
|
<field name="id"/>
|
||||||
|
<field name="target"/>
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="action_feedback" model="ir.actions.act_window">
|
||||||
|
<field name="name">Feedback</field>
|
||||||
|
<field name="res_model">runbot_merge.pull_requests.feedback</field>
|
||||||
|
</record>
|
||||||
|
<record id="tree_feedback" model="ir.ui.view">
|
||||||
|
<field name="name">Feedback</field>
|
||||||
|
<field name="model">runbot_merge.pull_requests.feedback</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<tree>
|
||||||
|
<field name="repository"/>
|
||||||
|
<field name="pull_request"/>
|
||||||
|
<field name="message"/>
|
||||||
|
<field name="close"/>
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="action_tagging" model="ir.actions.act_window">
|
||||||
|
<field name="name">Tagging</field>
|
||||||
|
<field name="res_model">runbot_merge.pull_requests.tagging</field>
|
||||||
|
</record>
|
||||||
|
<record id="tree_tagging" model="ir.ui.view">
|
||||||
|
<field name="name">Tagging</field>
|
||||||
|
<field name="model">runbot_merge.pull_requests.tagging</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<tree editable="bottom">
|
||||||
|
<field name="repository"/>
|
||||||
|
<field name="pull_request"/>
|
||||||
|
<field name="tags_add"/>
|
||||||
|
<field name="tags_remove"/>
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="action_fetches" model="ir.actions.act_window">
|
||||||
|
<field name="name">PRs to fetch</field>
|
||||||
|
<field name="res_model">runbot_merge.fetch_job</field>
|
||||||
|
<field name="view_mode">tree</field>
|
||||||
|
<field name="context">{'default_active': True}</field>
|
||||||
|
</record>
|
||||||
|
<record id="search_fetches" model="ir.ui.view">
|
||||||
|
<field name="name">Fetches Search</field>
|
||||||
|
<field name="model">runbot_merge.fetch_job</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<search>
|
||||||
|
<filter string="Active" name="active"
|
||||||
|
domain="[('active', '=', True)]"/>
|
||||||
|
<field name="repository"/>
|
||||||
|
<field name="number"/>
|
||||||
|
</search>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
<record id="tree_fetches" model="ir.ui.view">
|
||||||
|
<field name="name">Fetches Tree</field>
|
||||||
|
<field name="model">runbot_merge.fetch_job</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<tree>
|
||||||
|
<field name="repository"/>
|
||||||
|
<field name="number"/>
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<menuitem name="Queues" id="menu_queues" parent="runbot_merge_menu"/>
|
||||||
|
<menuitem name="Splits" id="menu_queues_splits"
|
||||||
|
parent="menu_queues"
|
||||||
|
action="action_splits"/>
|
||||||
|
<menuitem name="Feedback" id="menu_queues_feedback"
|
||||||
|
parent="menu_queues"
|
||||||
|
action="action_feedback"/>
|
||||||
|
<menuitem name="Tagging" id="menu_queues_tagging"
|
||||||
|
parent="menu_queues"
|
||||||
|
action="action_tagging"/>
|
||||||
|
<menuitem name="Fetches" id="menu_fetches"
|
||||||
|
parent="menu_queues"
|
||||||
|
action="action_fetches"/>
|
||||||
|
</odoo>
|
@ -135,11 +135,15 @@
|
|||||||
<t t-if="staging_index >= 4">visible-lg-block</t>
|
<t t-if="staging_index >= 4">visible-lg-block</t>
|
||||||
</t>
|
</t>
|
||||||
<t t-set="title">
|
<t t-set="title">
|
||||||
<t t-if="staging.state == 'canceled'">Cancelled: <t t-esc="staging.reason"/></t>
|
<t t-if="staging.state == 'ff_failed'">fast forward failed</t>
|
||||||
<t t-if="staging.state == 'ff_failed'">Fast Forward Failed</t>
|
<t t-if="staging.state == 'pending'">last status</t>
|
||||||
<t t-if="staging.state not in ('canceled', 'ff_failed')"><t t-esc="staging.reason"/></t>
|
<t t-if="staging.state not in ('pending', 'ff_failed')"><t t-esc="staging.reason"/></t>
|
||||||
</t>
|
</t>
|
||||||
<li t-attf-class="staging {{stateclass.strip()}} {{decorationclass.strip()}}" t-att-title="title.strip() or None">
|
<!-- separate concatenation to avoid having line-break in title as some browsers trigger it -->
|
||||||
|
<!-- write-date may have microsecond precision, strip that information -->
|
||||||
|
<!-- use write-date under assumption that a staging is last modified when it ends -->
|
||||||
|
<t t-set="title"><t t-esc="title.strip()"/> at <t t-esc="staging.write_date.replace(microsecond=0)"/>Z</t>
|
||||||
|
<li t-attf-class="staging {{stateclass.strip()}} {{decorationclass.strip()}}" t-att-title="title">
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
<li t-foreach="staging.batch_ids" t-as="batch" class="batch">
|
<li t-foreach="staging.batch_ids" t-as="batch" class="batch">
|
||||||
<t t-esc="batch.prs[:1].label"/>
|
<t t-esc="batch.prs[:1].label"/>
|
||||||
@ -152,7 +156,7 @@
|
|||||||
<t t-if="staging.heads">
|
<t t-if="staging.heads">
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
<button class="btn btn-link dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"
|
<button class="btn btn-link dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"
|
||||||
t-attf-title="{{staging.staged_at}}Z">
|
t-attf-title="Staged at {{staging.staged_at}}Z">
|
||||||
Staged <span t-field="staging.staged_at" t-options="{'widget': 'relative'}"/>
|
Staged <span t-field="staging.staged_at" t-options="{'widget': 'relative'}"/>
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</button>
|
</button>
|
||||||
|
Loading…
Reference in New Issue
Block a user