From caeba27846dc41f829d3a2e99b08274fc795f68e Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Mon, 25 May 2026 10:58:11 -0400 Subject: [PATCH] feat(plant_kanban): polish KPI strip + chips + toolbar buttons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User feedback after first deploy: 7 KPI tiles wrapped to second line (grid was repeat(5, 1fr) but I had added 2 new ones), and the controls felt cramped. Layout fix: - .kpi-strip grid: repeat(5, 1fr) → repeat(8, 1fr) so the row stays one line and there's room for the new Awaiting QC tile. Missing KPI added: - Awaiting QC — fp.job.card_state='awaiting_qc' count. Operators couldn't see when QC was blocking job close from the KPI strip (only visible inside the column). Server-side count + filter clause + matching filter chip. Visual polish (all light + dark via existing token system): - KPI tiles: padding 6→10px, value font 20→26px, label font 9→10px, subtle 135deg linear-gradient bg per kind (urgent/warn/good/qc), hover lifts the tile with translateY + shadow. - Filter chips: padding 4/12→7/16px, font 11→13px, gradient bg, active state has gradient blue + shadow. - Search input: padding 5/10→9/14px, font 12→14px, focus ring. - Toolbar buttons (Station/All Plant/Manager/Scan QR/Hand Off): padding 5/10→8/14px, font 12→14px, gradients, hover lift. Dark mode handled automatically — all gradients reference $plant-* tokens which already have @if $o-webclient-color-scheme == dark global overrides in _plant_tokens.scss. Version bump fusion_plating_shopfloor 19.0.34.0.0 → 19.0.34.1.0. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../fusion_plating_shopfloor/__manifest__.py | 2 +- .../controllers/plant_kanban.py | 5 ++ .../src/scss/components/_filter_chip.scss | 19 ++++-- .../static/src/scss/components/_kpi_tile.scss | 56 ++++++++++++---- .../static/src/scss/plant_kanban.scss | 66 ++++++++++++------- .../static/src/xml/plant_kanban.xml | 8 +++ 6 files changed, 114 insertions(+), 42 deletions(-) diff --git a/fusion_plating/fusion_plating_shopfloor/__manifest__.py b/fusion_plating/fusion_plating_shopfloor/__manifest__.py index f3e17f1b..4185cb1b 100644 --- a/fusion_plating/fusion_plating_shopfloor/__manifest__.py +++ b/fusion_plating/fusion_plating_shopfloor/__manifest__.py @@ -5,7 +5,7 @@ { 'name': 'Fusion Plating — Shop Floor', - 'version': '19.0.34.0.0', + 'version': '19.0.34.1.0', 'category': 'Manufacturing/Plating', 'summary': 'Shop-floor tablet stations, QR scanning, bake window enforcer.', 'description': """ diff --git a/fusion_plating/fusion_plating_shopfloor/controllers/plant_kanban.py b/fusion_plating/fusion_plating_shopfloor/controllers/plant_kanban.py index c1f9b70d..79535d6e 100644 --- a/fusion_plating/fusion_plating_shopfloor/controllers/plant_kanban.py +++ b/fusion_plating/fusion_plating_shopfloor/controllers/plant_kanban.py @@ -95,6 +95,8 @@ class PlantKanbanController(http.Controller): ))) if filters.get('mine'): domain.append(('card_state', 'in', ('ready_mine', 'running_mine'))) + if filters.get('awaiting_qc'): + domain.append(('card_state', '=', 'awaiting_qc')) # Spec 2026-05-25 — post-shop state filter chips if filters.get('awaiting_cert'): domain.append(('state', '=', 'awaiting_cert')) @@ -145,6 +147,9 @@ class PlantKanbanController(http.Controller): 'on_hold': sum( 1 for j in jobs if j.card_state == 'on_hold' ), + 'awaiting_qc': sum( + 1 for j in jobs if j.card_state == 'awaiting_qc' + ), # Spec 2026-05-25 — post-shop state KPIs 'awaiting_cert': sum( 1 for j in jobs if j.state == 'awaiting_cert' diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_filter_chip.scss b/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_filter_chip.scss index b0f73aa7..3b9c713a 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_filter_chip.scss +++ b/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_filter_chip.scss @@ -1,20 +1,27 @@ // _filter_chip.scss — depends on _plant_tokens.scss +// 2026-05-25: bigger touch target + gradient bg. .o_fp_filter_chip { - padding: 4px 12px; - font-size: 11px; - background: $plant-card-bg; + padding: 7px 16px; + font-size: 13px; + font-weight: 500; + background: linear-gradient(135deg, $plant-card-bg 0%, $plant-bg 100%); border: 1px solid $plant-card-border; - border-radius: 14px; + border-radius: 18px; color: $plant-muted; cursor: pointer; font-family: inherit; + transition: transform 0.1s ease, box-shadow 0.1s ease; &.active { - background: #1d4ed8; + background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%); border-color: #1d4ed8; color: #fff; font-weight: 600; + box-shadow: 0 2px 4px rgba(29, 78, 216, 0.25); + } + &:hover:not(.active) { + transform: translateY(-1px); + box-shadow: 0 2px 4px rgba(0,0,0,0.06); } - &:hover:not(.active) { background: $plant-bg; } } diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_kpi_tile.scss b/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_kpi_tile.scss index 275d9d67..ac918901 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_kpi_tile.scss +++ b/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_kpi_tile.scss @@ -1,34 +1,66 @@ // _kpi_tile.scss — depends on _plant_tokens.scss +// +// 2026-05-25: redesigned for the 8-tile row. Narrower individual width +// (grid handles that), more vertical presence via padding + larger +// typography, subtle 135deg gradients per kind that work in both light +// and dark modes (gradient stops use $plant-* tokens — dark variants +// flip automatically via the @if $o-webclient-color-scheme branch). .o_fp_kpi_tile { - padding: 6px 10px; - background: $plant-card-bg; - border-radius: 6px; + padding: 10px 12px; + background: linear-gradient(135deg, $plant-card-bg 0%, $plant-bg 100%); + border-radius: 8px; border: 1px solid $plant-card-border; - display: flex; flex-direction: column; gap: 1px; + display: flex; flex-direction: column; gap: 3px; cursor: pointer; - transition: background 0.1s; + transition: transform 0.1s ease, box-shadow 0.1s ease, border-color 0.1s ease; text-align: left; color: $plant-text; font-family: inherit; + box-shadow: 0 1px 2px rgba(0,0,0,0.04); + min-width: 0; // grid-track minmax handles sizing; let label truncate - &:hover { background: $plant-bg; } + &:hover { + transform: translateY(-1px); + box-shadow: 0 2px 6px rgba(0,0,0,0.08); + } &.active { border-color: $plant-mine-border; - background: $plant-mine-bg; + background: linear-gradient(135deg, $plant-mine-bg 0%, $plant-card-bg 100%); + box-shadow: 0 2px 6px rgba(0,0,0,0.10); + } + + // Kind-specific subtle gradients. Each pulls from existing tokens + // so dark mode auto-flips via the @if $o-webclient-color-scheme + // == dark global override in _plant_tokens.scss. + &.urgent { + background: linear-gradient(135deg, $plant-card-bg 0%, $plant-hold-bg 100%); + .kpi-val { color: $plant-hold-border; } + } + &.warn { + background: linear-gradient(135deg, $plant-card-bg 0%, $plant-bake-bg 100%); + .kpi-val { color: $plant-idle-border; } + } + &.good { + background: linear-gradient(135deg, $plant-card-bg 0%, $plant-done-bg 100%); + .kpi-val { color: $plant-done-border; } + } + &.qc { + background: linear-gradient(135deg, $plant-card-bg 0%, $plant-qc-bg 100%); + .kpi-val { color: $plant-qc-border; } } - &.urgent .kpi-val { color: $plant-hold-border; } - &.warn .kpi-val { color: $plant-idle-border; } - &.good .kpi-val { color: $plant-done-border; } .kpi-val { - font-size: 20px; font-weight: 700; + font-size: 26px; font-weight: 700; color: $plant-text; line-height: 1; font-variant-numeric: tabular-nums; } .kpi-lbl { - font-size: 9px; font-weight: 600; + font-size: 10px; font-weight: 600; color: $plant-muted; text-transform: uppercase; letter-spacing: 0.04em; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } } diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/scss/plant_kanban.scss b/fusion_plating/fusion_plating_shopfloor/static/src/scss/plant_kanban.scss index f5ba6f88..d50797f4 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/scss/plant_kanban.scss +++ b/fusion_plating/fusion_plating_shopfloor/static/src/scss/plant_kanban.scss @@ -34,67 +34,87 @@ .floor-title { font-size: 16px; font-weight: 700; } .floor-controls { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; } + // 2026-05-25 — toolbar buttons bigger + gradients for visual weight .station-picker { - padding: 5px 10px; - background: $plant-mine-bg; + padding: 8px 14px; + background: linear-gradient(135deg, $plant-mine-bg 0%, $plant-card-bg 100%); border: 1px solid $plant-mine-border; - border-radius: 6px; - font-size: 12px; + border-radius: 7px; + font-size: 14px; font-weight: 600; - color: #856404; + color: $plant-text; cursor: pointer; font-family: inherit; + box-shadow: 0 1px 2px rgba(0,0,0,0.05); } .mode-toggle { display: inline-flex; border: 1px solid $plant-card-border; - border-radius: 6px; + border-radius: 7px; overflow: hidden; + box-shadow: 0 1px 2px rgba(0,0,0,0.05); .mode-btn { - padding: 5px 12px; - font-size: 12px; + padding: 8px 16px; + font-size: 14px; font-weight: 600; - background: $plant-card-bg; + background: linear-gradient(135deg, $plant-card-bg 0%, $plant-bg 100%); color: $plant-muted; border: 0; cursor: pointer; border-right: 1px solid $plant-card-border; font-family: inherit; &:last-child { border-right: 0; } - &.active { background: #1d4ed8; color: #fff; } + &.active { + background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%); + color: #fff; + } &:hover:not(.active) { background: $plant-bg; } } } .toolbar-btn { - padding: 5px 10px; - font-size: 12px; - background: $plant-card-bg; + padding: 8px 14px; + font-size: 14px; + font-weight: 500; + background: linear-gradient(135deg, $plant-card-bg 0%, $plant-bg 100%); border: 1px solid $plant-card-border; - border-radius: 6px; + border-radius: 7px; cursor: pointer; color: $plant-text; font-family: inherit; - &:hover { background: $plant-bg; } + box-shadow: 0 1px 2px rgba(0,0,0,0.05); + transition: transform 0.1s ease, box-shadow 0.1s ease; + &:hover { + transform: translateY(-1px); + box-shadow: 0 2px 4px rgba(0,0,0,0.08); + } &.handoff { - background: #ffc107; + background: linear-gradient(135deg, #ffd966 0%, #ffc107 100%); border-color: #d39e00; - color: #856404; + color: #5e4400; font-weight: 700; } } - .kpi-strip { display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; } + // 8 tiles — Work Orders, At My Station, Bakes Due, On Hold, + // Awaiting QC, Awaiting CoC, Ready to Ship, Overdue. + .kpi-strip { display: grid; grid-template-columns: repeat(8, 1fr); gap: 8px; } - .search-row { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; } + .search-row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; } .search-input { - flex: 1; min-width: 200px; - padding: 5px 10px; + flex: 1; min-width: 220px; + padding: 9px 14px; border: 1px solid $plant-card-border; - border-radius: 6px; + border-radius: 8px; background: $plant-card-bg; color: $plant-text; - font-size: 12px; + font-size: 14px; font-family: inherit; + box-shadow: 0 1px 2px rgba(0,0,0,0.04) inset; + &:focus { + outline: none; + border-color: #1d4ed8; + box-shadow: 0 0 0 3px rgba(29, 78, 216, 0.15); + } } // Board: fixed-width columns with horizontal scroll on smaller diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/xml/plant_kanban.xml b/fusion_plating/fusion_plating_shopfloor/static/src/xml/plant_kanban.xml index 501f67ee..321d7e3b 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/xml/plant_kanban.xml +++ b/fusion_plating/fusion_plating_shopfloor/static/src/xml/plant_kanban.xml @@ -47,6 +47,11 @@ kind="'urgent'" active="!!state.filters.on_hold" onClick="() => this.toggleFilter('on_hold')"/> + +