feat(portal): shared QWeb macros (badge, stepper, doc chip, doc group)
Macros take dict args so callers never reach into the underlying records — keeps templates testable + makes the stepper reusable on dashboard cards AND detail-page if needed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
115
fusion_plating/fusion_plating_portal/views/fp_portal_macros.xml
Normal file
115
fusion_plating/fusion_plating_portal/views/fp_portal_macros.xml
Normal file
@@ -0,0 +1,115 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2026 Nexa Systems Inc.
|
||||
License OPL-1 (Odoo Proprietary License v1.0)
|
||||
|
||||
Shared QWeb macros for the customer portal redesign.
|
||||
Every template should t-call these instead of inlining stepper/badge/doc HTML.
|
||||
-->
|
||||
<odoo>
|
||||
|
||||
<!-- ================================================================== -->
|
||||
<!-- Status badge — pass state (string) and label (string) -->
|
||||
<!-- ================================================================== -->
|
||||
<template id="fp_portal_status_badge" name="Portal: Status Badge">
|
||||
<span t-attf-class="o_fp_badge o_fp_badge_#{state}">
|
||||
<span class="o_fp_badge_dot"/>
|
||||
<t t-out="label"/>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<!-- ================================================================== -->
|
||||
<!-- Numbered horizontal stepper — pass `steps` list of dicts: -->
|
||||
<!-- {label, status: 'done'|'active'|'pending', time_label} -->
|
||||
<!-- active_state: 'normal' (teal) or 'warn' (amber) -->
|
||||
<!-- ================================================================== -->
|
||||
<template id="fp_portal_stepper" name="Portal: Numbered Stepper">
|
||||
<t t-set="active_state" t-value="active_state or 'normal'"/>
|
||||
<div class="o_fp_stepper">
|
||||
<t t-foreach="steps" t-as="step">
|
||||
<!-- circle -->
|
||||
<div t-attf-class="o_fp_step_circle #{
|
||||
'o_fp_step_done' if step['status'] == 'done' else
|
||||
(('o_fp_step_active_warn' if active_state == 'warn' else 'o_fp_step_active') if step['status'] == 'active' else '')
|
||||
}">
|
||||
<t t-if="step['status'] == 'done'">✓</t>
|
||||
<t t-elif="step['status'] in ('active', 'pending')">
|
||||
<t t-out="step_index + 1"/>
|
||||
</t>
|
||||
</div>
|
||||
<!-- connecting line (omit after last circle) -->
|
||||
<t t-if="not step_last">
|
||||
<div t-attf-class="o_fp_step_line #{
|
||||
'o_fp_step_line_done' if step['status'] == 'done' else
|
||||
('o_fp_step_line_warn' if active_state == 'warn' and step['status'] == 'active' else '')
|
||||
}"/>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
<!-- Labels under -->
|
||||
<div class="o_fp_step_labels">
|
||||
<t t-foreach="steps" t-as="step">
|
||||
<div t-attf-class="o_fp_step_label #{
|
||||
'o_fp_step_label_done' if step['status'] == 'done' else
|
||||
(('o_fp_step_label_active_warn' if active_state == 'warn' else 'o_fp_step_label_active') if step['status'] == 'active' else '')
|
||||
}">
|
||||
<div class="o_fp_step_label_title" t-out="step['label']"/>
|
||||
<div class="o_fp_step_label_time" t-out="step.get('time_label') or ''"/>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- ================================================================== -->
|
||||
<!-- Doc chip (compact) — pass doc dict {icon, label, url, pending} -->
|
||||
<!-- ================================================================== -->
|
||||
<template id="fp_portal_doc_chip" name="Portal: Doc Chip">
|
||||
<t t-if="doc.get('pending')">
|
||||
<span class="o_fp_doc_chip o_fp_doc_chip_pending">
|
||||
<t t-out="doc.get('icon') or '📑'"/>
|
||||
<span t-out="doc['label']"/> · pending
|
||||
</span>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<a t-att-href="doc['url']" class="o_fp_doc_chip">
|
||||
<t t-out="doc.get('icon') or '📄'"/>
|
||||
<span t-out="doc['label']"/>
|
||||
</a>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<!-- ================================================================== -->
|
||||
<!-- Doc group (detail page) — pass label + docs list of dicts: -->
|
||||
<!-- {label, sub, url, icon_class, pending} -->
|
||||
<!-- ================================================================== -->
|
||||
<template id="fp_portal_doc_group" name="Portal: Doc Group">
|
||||
<div class="o_fp_doc_group" style="margin-bottom: 1.1rem">
|
||||
<div class="o_fp_doc_group_label" t-out="group_label"/>
|
||||
<t t-foreach="docs" t-as="doc">
|
||||
<t t-if="doc.get('pending')">
|
||||
<div class="o_fp_doc_row o_fp_doc_row_pending">
|
||||
<span t-attf-class="o_fp_doc_icon o_fp_doc_icon_pending">📑</span>
|
||||
<div class="o_fp_doc_meta">
|
||||
<div class="o_fp_doc_name" t-out="doc['label']"/>
|
||||
<div class="o_fp_doc_sub" t-out="doc.get('sub') or ''"/>
|
||||
</div>
|
||||
<span style="color: #cbd5e1; font-size: .72rem">—</span>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<a t-att-href="doc['url']" class="o_fp_doc_row">
|
||||
<span t-attf-class="o_fp_doc_icon #{doc.get('icon_class') or 'o_fp_doc_icon_input'}">
|
||||
<t t-out="doc.get('icon') or '📄'"/>
|
||||
</span>
|
||||
<div class="o_fp_doc_meta">
|
||||
<div class="o_fp_doc_name" t-out="doc['label']"/>
|
||||
<div class="o_fp_doc_sub" t-out="doc.get('sub') or ''"/>
|
||||
</div>
|
||||
<span class="o_fp_doc_action">↓ Download</span>
|
||||
</a>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user