fix(fusion_plating_shopfloor): dark-mode text/background readability

Operators saw dark-on-dark (invisible) text in the workspace + "Cannot
Finish Step" dialog in Odoo dark mode.

Root cause: var(--text-secondary, #xxx) — a made-up variable that doesn't
exist in Odoo, so it always fell back to the hardcoded dark hex (invisible
on dark). Used 33× across job_workspace.scss + 5 component stylesheets.
Replaced with the real dark-aware var(--bs-secondary-color).

Also fixed paired backgrounds that would hide the now-theme-flipped text:
- finish-block action note → var(--bs-tertiary-bg) (was #f3f4f6).
- Tinted status banners (finish-block step, overtime timer, receiving
  status) → color-mix over var(--bs-body-bg) + var(--bs-body-color).
  Odoo's bootstrap lacks the BS5.3 -bg-subtle/-text-emphasis vars
  (verified against _root.scss), so color-mix is the dark-aware path.

Solid accent pills/dots (white text) and the color-coded plant-card chips
(light-bg + dark-text, readable in both) intentionally left as-is.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-06-02 01:24:25 -04:00
parent b59ad6b21e
commit 5c4a26b65f
7 changed files with 53 additions and 40 deletions

View File

@@ -1854,3 +1854,13 @@ A 50-part job can have parts at several stages at once (10 Masking, 20 Plating,
6. **Move-based scrap (`transfer_type='scrap'`) does NOT touch `job.qty_scrapped`.** At close, `button_mark_done` calls `_fp_scrapped_via_moves()` and folds it into `qty_scrapped`, then auto-fills `qty_done = qty qty_scrapped` (was: blindly `= job.qty`, which over-counted when parts were scrapped). The reconciliation gate is still the safety net.
**Verification:** the plating modules can't be installed on the local Community dev DB (missing enterprise deps — same reason `fusion_plating` shows `installed=0` in `modsdev`/`fusion-dev`). Static checks done: pyflakes (Python), lxml parse (XML), `node --check` as `.mjs` (JS — `node --check` on a `.js` errors with "Cannot use import statement outside a module"; copy to `/tmp/x.mjs` first). Dynamic tests + browser check require an installed env (entech / odoo-trial).
---
## Dark-mode SCSS gotchas — shop-floor dialogs/components (fixed 2026-06-02)
Operators reported invisible (dark-on-dark) text in the workspace + "Cannot Finish Step" dialog under Odoo dark mode. Root causes + the rules:
1. **`var(--text-secondary, #333)` is a MADE-UP variable — it does not exist in Odoo, so it ALWAYS falls back to the hardcoded dark hex → invisible on dark backgrounds.** It was used 33× across `job_workspace.scss` + 5 component stylesheets. The real, dark-aware secondary-text variable is **`var(--bs-secondary-color)`** (CLAUDE.md rule 9 lists it). Never use `--text-secondary` / `--text-primary` / `--card-bg` etc. — those aren't Odoo vars.
2. **Odoo's bootstrap does NOT define the Bootstrap 5.3 `--bs-{color}-bg-subtle` / `--bs-{color}-text-emphasis` family.** Verified by grepping `web/static/lib/bootstrap/scss/_root.scss`: `--bs-tertiary-bg` and `--bs-secondary-color` exist; `--bs-warning-bg-subtle`, `--bs-danger-bg-subtle`, `--bs-warning-text-emphasis` are MISSING. So `var(--bs-warning-bg-subtle, #fef3c7)` just yields the bright hex fallback — useless for dark mode. **For tinted status banners (warning/danger/info), use `color-mix` over the live theme bg instead:** `background-color: color-mix(in srgb, #f59e0b 14%, var(--bs-body-bg)); color: var(--bs-body-color);` — pale in light mode, dark-tinted in dark mode, readable in both, graceful-degrades to no-bg on ancient browsers. (`color-mix` works in `background-color` per the rule-8 note; keep it out of shorthands.) Solid accent elements (selected pills, priority dots) with `color: white` are fine as-is in both modes.
3. **Confirmed-present, dark-aware Odoo vars to reach for:** `--bs-body-color` (primary text), `--bs-secondary-color` (muted text), `--bs-body-bg` / `--bs-tertiary-bg` (surfaces), `--bs-border-color`. The deliberate color-coded plant-card status chips (`_plant_card.scss` `.kind-*` / `.tag-*`) are light-bg + dark-text (readable in both modes, just bright on a dark card) — intentionally left as a color-coded set.

View File

@@ -26,5 +26,5 @@ $_gate-text-hex: #b06600;
.o_fp_gate_icon { color: $_gate-border-hex; margin-top: 0.15rem; }
.o_fp_gate_body { flex: 1; }
.o_fp_gate_title { font-weight: 600; color: $_gate-text-hex; font-size: 0.85rem; }
.o_fp_gate_reason { color: var(--text-secondary, #666); font-size: 0.78rem; margin-top: 0.1rem; }
.o_fp_gate_reason { color: var(--bs-secondary-color, #666); font-size: 0.78rem; margin-top: 0.1rem; }
.o_fp_gate_jump { flex-shrink: 0; }

View File

@@ -17,5 +17,5 @@
.o_fp_hc_row label {
font-size: 0.8rem;
font-weight: 600;
color: var(--text-secondary, #666);
color: var(--bs-secondary-color, #666);
}

View File

@@ -34,18 +34,18 @@ $_kc-hover-hex: #f5f5f7;
}
.o_fp_kcard_h2 {
color: var(--text-secondary, #666);
color: var(--bs-secondary-color, #666);
font-size: 0.75rem;
margin-top: 0.15rem;
}
.o_fp_kcard_qty {
display: flex; justify-content: space-between;
font-size: 0.7rem; color: var(--text-secondary, #777);
font-size: 0.7rem; color: var(--bs-secondary-color, #777);
margin-top: 0.3rem;
}
.o_fp_kcard_due { color: var(--text-secondary, #999); }
.o_fp_kcard_due { color: var(--bs-secondary-color, #999); }
.o_fp_kcard_bar {
height: 4px; background: rgba(0,0,0,0.08);
@@ -74,7 +74,7 @@ $_kc-hover-hex: #f5f5f7;
}
.o_fp_kcard_wc {
color: var(--text-secondary, #999);
color: var(--bs-secondary-color, #999);
font-size: 0.7rem;
}

View File

@@ -38,7 +38,7 @@ $_pin-dot-fill-hex: #1d1d1f;
}
.o_fp_pin_title { font-size: 1.1rem; font-weight: 600; }
.o_fp_pin_subtitle { font-size: 0.85rem; color: var(--text-secondary, #666); text-align: center; }
.o_fp_pin_subtitle { font-size: 0.85rem; color: var(--bs-secondary-color, #666); text-align: center; }
.o_fp_pin_dots {
display: flex;
@@ -83,8 +83,8 @@ $_pin-dot-fill-hex: #1d1d1f;
&:disabled { opacity: 0.5; cursor: wait; }
}
.o_fp_pin_key_clear { font-size: 0.95rem; color: var(--text-secondary, #666); }
.o_fp_pin_key_cancel { font-size: 0.95rem; color: var(--text-secondary, #666); }
.o_fp_pin_key_clear { font-size: 0.95rem; color: var(--bs-secondary-color, #666); }
.o_fp_pin_key_cancel { font-size: 0.95rem; color: var(--bs-secondary-color, #666); }
@keyframes o_fp_pin_shake_kf {
0%, 100% { transform: translateX(0); }

View File

@@ -21,7 +21,7 @@ $_sig-canvas-border-hex: #d8dadd;
.o_fp_sig_ctx {
font-size: 0.85rem;
color: var(--text-secondary, #666);
color: var(--bs-secondary-color, #666);
}
.o_fp_sig_canvas {
@@ -36,6 +36,6 @@ $_sig-canvas-border-hex: #d8dadd;
.o_fp_sig_hint {
font-size: 0.75rem;
color: var(--text-secondary, #999);
color: var(--bs-secondary-color, #999);
text-align: center;
}

View File

@@ -29,7 +29,7 @@ $_ws-text-hex: #1d1d1f;
.o_fp_ws_loading {
margin: auto;
text-align: center;
color: var(--text-secondary, #666);
color: var(--bs-secondary-color, #666);
> div { margin-top: 0.6rem; }
}
@@ -87,8 +87,8 @@ $_ws-text-hex: #1d1d1f;
}
.o_fp_ws_wo { font-weight: 700; font-size: 1.3rem; letter-spacing: 0.01em; }
.o_fp_ws_dot { color: var(--text-secondary, #999); }
.o_fp_ws_cust, .o_fp_ws_part { color: var(--text-secondary, #555); font-size: 0.95rem; }
.o_fp_ws_dot { color: var(--bs-secondary-color, #999); }
.o_fp_ws_cust, .o_fp_ws_part { color: var(--bs-secondary-color, #555); font-size: 0.95rem; }
.o_fp_ws_pill {
background: linear-gradient(135deg, $_ws-card-hex 0%, $_ws-page-hex 100%);
@@ -97,7 +97,7 @@ $_ws-text-hex: #1d1d1f;
border-radius: 6px;
font-size: 0.9rem;
font-weight: 500;
color: var(--text-secondary, #555);
color: var(--bs-secondary-color, #555);
box-shadow: 0 1px 2px rgba(0,0,0,0.04);
}
@@ -152,7 +152,7 @@ $_ws-text-hex: #1d1d1f;
.o_fp_ws_bar_label {
font-size: 0.8rem;
font-weight: 500;
color: var(--text-secondary, #888);
color: var(--bs-secondary-color, #888);
margin-top: 0.35rem;
text-align: center;
}
@@ -237,7 +237,7 @@ $_ws-text-hex: #1d1d1f;
.o_fp_ws_empty {
text-align: center;
padding: 2rem 1rem;
color: var(--text-secondary, #999);
color: var(--bs-secondary-color, #999);
> div { margin-top: 0.5rem; }
}
@@ -270,9 +270,9 @@ $_ws-text-hex: #1d1d1f;
}
.o_fp_ws_step_icon { width: 18px; text-align: center; font-weight: 700; }
.o_fp_ws_step_num { color: var(--text-secondary, #999); font-size: 0.78rem; min-width: 50px; }
.o_fp_ws_step_num { color: var(--bs-secondary-color, #999); font-size: 0.78rem; min-width: 50px; }
.o_fp_ws_step_name { font-weight: 600; }
.o_fp_ws_step_meta { color: var(--text-secondary, #999); font-size: 0.78rem; margin-left: auto; }
.o_fp_ws_step_meta { color: var(--bs-secondary-color, #999); font-size: 0.78rem; margin-left: auto; }
.o_fp_ws_step_badge {
background: #0071e3;
@@ -295,12 +295,12 @@ $_ws-text-hex: #1d1d1f;
}
.o_fp_ws_step_chips { display: flex; gap: 0.3rem; flex-wrap: wrap; }
.o_fp_ws_step_instr { font-size: 0.78rem; color: var(--text-secondary, #555); font-style: italic; }
.o_fp_ws_step_instr { font-size: 0.78rem; color: var(--bs-secondary-color, #555); font-style: italic; }
.o_fp_ws_step_actions { display: flex; gap: 0.35rem; flex-wrap: wrap; }
.o_fp_ws_step_excluded {
font-size: 0.78rem;
color: var(--text-secondary, #888);
color: var(--bs-secondary-color, #888);
font-style: italic;
}
@@ -331,7 +331,7 @@ $_ws-text-hex: #1d1d1f;
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.04em;
color: var(--text-secondary, #777);
color: var(--bs-secondary-color, #777);
margin-bottom: 0.35rem;
}
}
@@ -362,14 +362,14 @@ $_ws-text-hex: #1d1d1f;
display: flex;
gap: 0.4rem;
font-size: 0.72rem;
color: var(--text-secondary, #777);
color: var(--bs-secondary-color, #777);
}
.o_fp_ws_note .author { font-weight: 600; }
.o_fp_ws_note .body { color: var(--text-secondary, #555); margin-top: 0.15rem; }
.o_fp_ws_note .body { color: var(--bs-secondary-color, #555); margin-top: 0.15rem; }
.o_fp_ws_empty_small {
color: var(--text-secondary, #999);
color: var(--bs-secondary-color, #999);
font-size: 0.75rem;
font-style: italic;
}
@@ -417,7 +417,7 @@ $_ws-text-hex: #1d1d1f;
align-items: center;
gap: 0.4rem;
font-size: 0.85rem;
color: var(--text-secondary, #777);
color: var(--bs-secondary-color, #777);
}
.o_fp_ws_ship_fields {
@@ -488,8 +488,8 @@ $_ws-text-hex: #1d1d1f;
.o_fp_ws_rcv_status {
padding: 0.2rem 0.6rem;
border-radius: 4px;
background: #fef3c7;
color: #78350f;
background-color: color-mix(in srgb, #f59e0b 18%, var(--bs-body-bg));
color: var(--bs-body-color);
font-weight: 600;
font-size: 0.85rem;
text-transform: uppercase;
@@ -507,7 +507,7 @@ $_ws-text-hex: #1d1d1f;
label {
font-weight: 600;
color: var(--text-secondary, #555);
color: var(--bs-secondary-color, #555);
font-size: 0.9rem;
}
}
@@ -529,7 +529,7 @@ $_ws-text-hex: #1d1d1f;
font-size: 0.8rem;
font-weight: 700;
text-transform: uppercase;
color: var(--text-secondary, #666);
color: var(--bs-secondary-color, #666);
margin-bottom: 0.5rem;
letter-spacing: 0.05em;
}
@@ -598,7 +598,7 @@ $_ws-text-hex: #1d1d1f;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-secondary, #666);
color: var(--bs-secondary-color, #666);
margin-bottom: 0.5rem;
display: flex;
align-items: center;
@@ -644,7 +644,7 @@ $_ws-text-hex: #1d1d1f;
}
.o_fp_ws_rcv_damage_photos {
color: var(--text-secondary, #666);
color: var(--bs-secondary-color, #666);
font-size: 0.85rem;
}
@@ -680,7 +680,7 @@ $_ws-text-hex: #1d1d1f;
}
.o_fp_dmg_field { display: flex; flex-direction: column; gap: 0.4rem; }
.o_fp_dmg_label { font-weight: 600; color: var(--text-secondary, #555); }
.o_fp_dmg_label { font-weight: 600; color: var(--bs-secondary-color, #555); }
.o_fp_dmg_req { color: #dc2626; }
.o_fp_dmg_pills {
@@ -784,8 +784,8 @@ $_ws-text-hex: #1d1d1f;
}
.o_fp_ws_step_timer_over {
background: #fee2e2;
color: #7f1d1d;
background-color: color-mix(in srgb, #ef4444 16%, var(--bs-body-bg));
color: var(--bs-body-color);
animation: o_fp_ws_timer_pulse 1.5s ease-in-out infinite;
}
@@ -808,15 +808,18 @@ $_ws-text-hex: #1d1d1f;
.o_fp_finish_block_step {
font-size: 1.1rem;
color: #b45309;
background: #fef3c7;
color: var(--bs-body-color);
// Amber wash over the live theme bg — pale in light mode, dark-amber
// in dark mode (the -bg-subtle/-text-emphasis BS vars aren't defined
// in Odoo's bootstrap, so color-mix is the dark-aware path).
background-color: color-mix(in srgb, #f59e0b 14%, var(--bs-body-bg));
padding: 0.7rem 1rem;
border-radius: 6px;
border-left: 4px solid #f59e0b;
}
.o_fp_finish_block_msg {
color: var(--text-secondary, #333);
color: var(--bs-secondary-color, #333);
}
.o_fp_finish_block_list {
@@ -831,9 +834,9 @@ $_ws-text-hex: #1d1d1f;
}
.o_fp_finish_block_action_note {
color: var(--text-secondary, #555);
color: var(--bs-secondary-color, #555);
font-style: italic;
padding: 0.6rem 0.8rem;
background: #f3f4f6;
background: var(--bs-tertiary-bg, #f3f4f6);
border-radius: 4px;
}