fix(configurator): Part cell row 1 shows part# / rev separately via CSS overlay

Root cause: my @api.depends_context('fp_express_part_picker') decorator
on _compute_display_name was not honored by Odoo. Verified via odoo
shell — display_name returns the full 'PART (Rev X) — Name' regardless
of context. Reason: display_name is defined on the base Model class
and Odoo registers the field metadata (incl. _depends_context) when
the field is FIRST declared. Subclass redefinitions of the compute
method don't update _depends_context after the fact.

Workaround: don't rely on display_name context override. Instead,
overlay a custom span on top of the Many2OneField that shows JUST
the part_number_display value. CSS overlay uses:
- position: absolute / inset: 0
- background: $xpr-card (matches list row background)
- z-index: 2 over the picker
- pointer-events: none so clicks pass through to the picker

When the picker is focused (:focus-within parent), the overlay
hides so the user sees the autocomplete input value as they type.
When not focused, the overlay covers display_name with just the
part number.

Row 1 now reads 'ENG-1042  /  B' — picker on the left (showing only
part_number_display), separator, revision on the right. Matches the
mockup pixel layout the user requested.
This commit is contained in:
gsinghpal
2026-05-26 23:41:58 -04:00
parent 9c7b7c54e5
commit a7cbd1a6f7
3 changed files with 65 additions and 6 deletions

View File

@@ -34,6 +34,14 @@ export class FpExpressPartCell extends Component {
return !!this.props.record.data.part_catalog_id;
}
get partNumber() {
return this.props.record.data.part_number_display || "";
}
get partRev() {
return this.props.record.data.part_revision_display || "";
}
get partName() {
return this.props.record.data.part_name_editable || "";
}

View File

@@ -547,11 +547,20 @@
.o_fp_xpr_part_id {
font-weight: 600;
font-size: 13px;
display: flex;
align-items: baseline;
gap: 4px;
// The embedded Many2OneField input — strip its chrome so it
// looks like inline-bold text. Restore the dropdown affordance
// on hover/focus.
// The picker + overlay container
.o_fp_xpr_part_picker_wrap {
position: relative;
flex: 1;
min-width: 0;
}
// Strip Many2OneField chrome to inline-bold-text
.o_field_widget,
.o_field_widget > div,
.o_field_widget input,
.o_field_many2one input {
border: none;
@@ -559,21 +568,48 @@
padding: 1px 4px;
font-weight: 600;
font-size: 13px;
color: $xpr-text;
color: $xpr-accent;
width: 100%;
}
.o_field_widget input:focus {
background: $xpr-cell-focus;
outline: none;
}
// OVERLAY — shown when picker not focused; hides display_name
// and shows just part_number_display
.o_fp_xpr_part_num_overlay {
position: absolute;
inset: 0;
background: $xpr-card;
z-index: 2;
pointer-events: none;
padding: 1px 4px;
font-weight: 600;
font-size: 13px;
color: $xpr-accent;
display: flex;
align-items: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
// Hide overlay when picker is focused (user is typing/searching)
.o_fp_xpr_part_picker_wrap:focus-within .o_fp_xpr_part_num_overlay {
display: none;
}
.o_fp_xpr_part_sep {
color: $xpr-text-dim;
font-weight: 400;
padding: 0 2px;
flex: 0 0 auto;
}
.o_fp_xpr_part_rev {
font-weight: 600;
color: $xpr-text;
min-width: 30px;
flex: 0 0 auto;
}
.o_fp_xpr_part_rev_empty {
color: $xpr-text-dim;
@@ -581,6 +617,10 @@
font-style: italic;
}
}
// Overlay background matches the row hover state
.o_list_view tbody tr:hover & .o_fp_xpr_part_num_overlay {
background: $xpr-row-hover;
}
.o_fp_xpr_part_name {
.o_fp_xpr_part_name_input {
width: 100%;

View File

@@ -11,9 +11,20 @@
-->
<t t-name="fusion_plating_configurator.FpExpressPartCell">
<div class="o_fp_xpr_part_cell">
<!-- Row 1 — Part picker -->
<!-- Row 1 — Part picker (left, with part-number overlay) + / + Revision (right)
The overlay shows JUST the part_number_display when not focused;
on focus, the overlay hides so the user sees the autocomplete input. -->
<div class="o_fp_xpr_part_row o_fp_xpr_part_id">
<Many2OneField t-props="props"/>
<div class="o_fp_xpr_part_picker_wrap">
<Many2OneField t-props="props"/>
<span t-if="hasPart"
class="o_fp_xpr_part_num_overlay"
t-esc="partNumber"/>
</div>
<span class="o_fp_xpr_part_sep">/</span>
<span class="o_fp_xpr_part_rev"
t-att-class="{ 'o_fp_xpr_part_rev_empty': !partRev }"
t-esc="partRev or 'rev'"/>
</div>
<!-- Row 2 — Editable part description (saves to part.name) -->
<div class="o_fp_xpr_part_row o_fp_xpr_part_name">