fix(jobs): Record Inputs v3 wizard — visual bug fixes (v19.0.8.16.1)

Four visible bugs reported by user after deploy:

1. Type + Unit pills overlapped at top-right of every card.
   Root cause: both <field>s carried the same .o_fp_iw_meta class
   AND both mapped to grid-area: meta. CSS Grid stacked them on
   top of each other so the labels rendered as overlap garbage
   (e.g. "eachnber", "Time(secs)Time(seconds)").
   Fix: distinct classes (.o_fp_iw_meta_type / .o_fp_iw_meta_unit)
   each in its own grid column. Grid is now 4 columns wide:
     "prompt | type | unit | trash"

2. Input borders barely visible in dark mode (#343942 on #22262d).
   Operators couldn't tell where to click.
   Fix: brighter border using $fp-iw-ink-faint instead of $fp-iw-border.
   Hover bumps to $fp-iw-ink-mute. Focus uses brand purple. Also
   added a slight surface tint ($fp-iw-page) so empty inputs read
   as obviously-interactive instead of blending into the card.

3. Photo widget rendered enormous (full card width).
   Root cause: max-width applied only to the preview image, not
   to the .o_field_image container itself.
   Fix: max-width 240px on .o_field_image AND its inner controls.

4. Numeric values floated centered in empty space.
   Root cause: input width wasn't stretching to its grid cell;
   default Odoo numeric-cell text-align: right plus our missing
   width: 100% left tiny inputs centered in the value area.
   Fix: explicit width: 100%, text-align: left, and 420px
   max-width on the .o_field_widget container.

Bonus polish:
  * Trash icon hidden by default (opacity: 0), reveals to 0.6 on
    row hover, full opacity on direct hover. Reduces visual noise
    for the common case where operator just types and saves.
  * Boolean toggle scale bumped from 1.4 to 1.5 + adds left margin
    so the switch sits properly inside the value cell.
  * Mobile (<900px) grid collapses to: prompt|trash / type|unit /
    value / extras — keeps the type+unit pair on one row but lets
    them flow naturally below the prompt.

No model changes. SCSS + XML view only. v2 view still in place
for instant rollback.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-05-03 21:38:06 -04:00
parent 9794a98de9
commit efef7859cd
3 changed files with 116 additions and 68 deletions

View File

@@ -3,7 +3,7 @@
# License OPL-1 (Odoo Proprietary License v1.0)
{
'name': 'Fusion Plating — Native Jobs',
'version': '19.0.8.16.0',
'version': '19.0.8.16.1',
'category': 'Manufacturing/Plating',
'summary': 'Native plating job model — replaces mrp.production / mrp.workorder bridge.',
'author': 'Nexa Systems Inc.',

View File

@@ -154,15 +154,17 @@ $fp-iw-pill-bg : var(--fp-pill-bg, #{$_fp-iw-pill-bg-hex});
gap: 12px;
}
// Each row becomes a card
// Each row becomes a card. Five-column grid so the meta cells
// (input_type pill, target_unit pill) each land in their own
// column instead of stacking on top of each other.
tr.o_data_row {
display: grid;
grid-template-columns: 1fr auto;
grid-template-columns: 1fr auto auto auto;
grid-template-areas:
"prompt meta"
"value value"
"extras extras";
gap: 8px 16px;
"prompt type unit trash"
"value value value value"
"extras extras extras extras";
gap: 10px 12px;
align-items: start;
padding: 16px 20px;
background-color: $fp-iw-card;
@@ -229,13 +231,15 @@ $fp-iw-pill-bg : var(--fp-pill-bg, #{$_fp-iw-pill-bg-hex});
// XML view via a span sibling (.o_fp_iw_required_marker).
}
// ---------- Meta — type + unit pill, target range ----------
// ---------- Meta pills — type + unit each in its OWN column ----
// Both fields carry the .o_fp_iw_meta class for shared
// pill styling, plus a distinct class (_type / _unit) so
// CSS Grid can put each in its own area.
td.o_fp_iw_meta_type { grid-area: type; }
td.o_fp_iw_meta_unit { grid-area: unit; }
td.o_fp_iw_meta {
grid-area: meta;
display: flex;
gap: 8px;
align-items: center;
justify-content: flex-end;
align-self: center;
font-size: 0.75rem;
color: $fp-iw-ink-mute;
@@ -243,8 +247,13 @@ $fp-iw-pill-bg : var(--fp-pill-bg, #{$_fp-iw-pill-bg-hex});
width: auto;
}
// Type/unit selection looks like a pill
select, input {
// The pill itself — applied to whatever input/select
// Odoo renders for the field type (Selection → select).
select,
input,
.o_input,
.o_field_widget > span {
display: inline-block;
font-size: 0.75rem;
padding: 4px 10px !important;
background-color: $fp-iw-pill-bg !important;
@@ -254,36 +263,55 @@ $fp-iw-pill-bg : var(--fp-pill-bg, #{$_fp-iw-pill-bg-hex});
line-height: 1.2 !important;
height: auto !important;
min-height: 0 !important;
box-shadow: none !important;
width: auto !important;
}
}
// ---------- Value — the live widget for this row's type ----------
// ---------- Value — the live widget for this row's type --------
td.o_fp_iw_value {
grid-area: value;
max-width: 360px;
// Numeric / text / date inputs — large + comfortable
// Make the value widget container fill the available
// grid area, no centering, no shrinking.
.o_field_widget {
display: block;
width: 100%;
max-width: 420px;
}
// Inputs — number/text/date/etc. all share the same
// chrome. Brighter border + slight surface tint so
// empty inputs are obviously interactive in dark mode.
input[type="text"],
input[type="number"],
input[type="datetime-local"],
input.o_input,
input:not([type]) {
width: 100% !important;
text-align: left !important;
font-size: 1.125rem;
font-weight: 500;
padding: 10px 14px;
padding: 10px 14px !important;
min-height: 48px;
background-color: $fp-iw-card;
color: $fp-iw-ink;
border: 1px solid $fp-iw-border;
border-radius: 8px;
box-shadow: none;
background-color: $fp-iw-page !important;
color: $fp-iw-ink !important;
border: 1px solid $fp-iw-ink-faint !important;
border-radius: 8px !important;
box-shadow: none !important;
transition: border-color 120ms ease,
box-shadow 120ms ease;
box-shadow 120ms ease,
background-color 120ms ease;
&:hover {
border-color: $fp-iw-ink-mute !important;
}
&:focus {
border-color: $fp-iw-border-focus;
border-color: $fp-iw-border-focus !important;
background-color: $fp-iw-card !important;
box-shadow: 0 0 0 3px
color-mix(in srgb,
#{$fp-iw-border-focus} 25%, transparent);
#{$fp-iw-border-focus} 25%, transparent) !important;
outline: none;
}
@@ -293,16 +321,24 @@ $fp-iw-pill-bg : var(--fp-pill-bg, #{$_fp-iw-pill-bg-hex});
}
}
// Boolean toggle — make the pill bigger, easier to tap
.o_boolean_toggle {
transform: scale(1.4);
// Boolean toggle — bigger pill for fat fingers
.o_boolean_toggle,
.form-switch {
transform: scale(1.5);
transform-origin: left center;
margin: 8px 0;
margin: 12px 0 12px 16px;
}
// Image / photo widget
// Image / photo widget — constrain the WHOLE field
// (upload area + preview) so it doesn't blow up to
// fill the whole card width.
.o_field_image {
img, .o_image, .o_form_uri {
max-width: 240px;
img,
.o_image,
.o_form_uri,
.o_form_image_controls {
max-width: 240px;
max-height: 180px;
border-radius: 8px;
@@ -311,46 +347,51 @@ $fp-iw-pill-bg : var(--fp-pill-bg, #{$_fp-iw-pill-bg-hex});
}
}
// ---------- Extras — composite types (multi-point, panel) ----------
// ---------- Extras — composite types (multi-point, panel) ----
td.o_fp_iw_extra {
grid-area: extras;
display: inline-flex;
gap: 8px;
align-items: baseline;
margin-right: 8px;
gap: 6px;
align-items: center;
margin-right: 12px;
// Compact label-above-input grouping
// Compact label-before-input grouping
&::before {
content: attr(data-label);
display: block;
display: inline-block;
font-size: 0.75rem;
color: $fp-iw-ink-mute;
margin-right: 4px;
}
input {
input,
input.o_input {
width: 80px !important;
text-align: left !important;
font-size: 1rem;
padding: 6px 10px;
padding: 6px 10px !important;
min-height: 38px;
background-color: $fp-iw-card;
color: $fp-iw-ink;
border: 1px solid $fp-iw-border;
border-radius: 6px;
background-color: $fp-iw-page !important;
color: $fp-iw-ink !important;
border: 1px solid $fp-iw-ink-faint !important;
border-radius: 6px !important;
box-shadow: none !important;
}
}
// Trash button column — small, right-aligned, low contrast
// Trash button — hidden by default to declutter the card.
// Operators rarely need to delete authored prompts; ad-hoc
// rows can still be removed via the row's context menu.
// Show on row hover for power users.
td.o_list_record_remove {
grid-area: meta;
align-self: start;
grid-area: trash;
align-self: center;
justify-self: end;
opacity: 0.4;
&:hover { opacity: 1; }
opacity: 0;
transition: opacity 120ms ease;
button {
color: $fp-iw-ink-mute;
color: $fp-iw-ink-faint;
background: transparent !important;
border: none !important;
padding: 4px;
@@ -360,6 +401,14 @@ $fp-iw-pill-bg : var(--fp-pill-bg, #{$_fp-iw-pill-bg-hex});
}
}
}
&:hover td.o_list_record_remove,
&:focus-within td.o_list_record_remove {
opacity: 0.6;
}
td.o_list_record_remove:hover {
opacity: 1 !important;
}
}
// "Add a line" footer — make it a tasteful CTA card
@@ -398,25 +447,21 @@ $fp-iw-pill-bg : var(--fp-pill-bg, #{$_fp-iw-pill-bg-hex});
@media (max-width: 900px) {
.o_fp_input_card_list .o_list_table tr.o_data_row {
grid-template-columns: 1fr;
grid-template-columns: 1fr auto;
grid-template-areas:
"prompt"
"meta"
"value"
"extras";
"prompt trash"
"type unit"
"value value"
"extras extras";
td.o_fp_iw_meta {
justify-content: flex-start;
td.o_fp_iw_meta_type,
td.o_fp_iw_meta_unit {
justify-self: start;
}
td.o_fp_iw_value {
max-width: 100%;
.o_field_widget { max-width: 100%; }
input { min-height: 56px; }
}
td.o_list_record_remove {
justify-self: end;
}
}
}

View File

@@ -151,15 +151,18 @@
placeholder="e.g. Oven Temp, Bath Reading, Operator Initials"
class="o_fp_iw_prompt"/>
<!-- Meta — type + unit rendered as pills (top-right) -->
<!-- Meta — type + unit rendered as pills (top-right).
Distinct classes so each pill lands in its own
grid column (otherwise they stack on top of
each other and the labels overlap). -->
<field name="input_type"
string="Type"
readonly="is_authored"
class="o_fp_iw_meta"/>
class="o_fp_iw_meta o_fp_iw_meta_type"/>
<field name="target_unit"
string="Unit"
readonly="is_authored"
class="o_fp_iw_meta"
class="o_fp_iw_meta o_fp_iw_meta_unit"
optional="show"/>
<!-- Hidden by default — operator can opt in via the cog menu