From c2124392e80f1e86990ab57e024b6dcffb11e1a8 Mon Sep 17 00:00:00 2001 From: Don Kendall Date: Tue, 19 May 2026 20:42:05 -0400 Subject: [PATCH 1/4] feat(farm_onboarding): systray bell + post_init hook autostart MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First UX-refinement slice. Surfaces the onboarding wizard the moment a farm user signs in instead of waiting for them to find the menu item. What's wired: - `farm_pack` gains a `post_init_hook` that seeds one `farm.onboarding.session` per (internal-farm-user, company) on install. Existing installs upgrade and immediately surface the bell; new users created later pick up a session lazily via `get_or_create_for_current_user`. - `farm_onboarding` ships its first OWL component: `FarmOnboardingSystray`. A leaf icon + red badge dot appears in the navbar when the current user has a pending session; clicking it opens the wizard via the existing `action_open_for_current_user` server action. Hidden entirely when no session is pending — non- farm users see nothing. - `farm.onboarding.session.count_pending_for_current_user` is a new read-only RPC endpoint the bell calls on mount. Kept separate from `get_or_create_for_current_user` so the systray mount path cannot accidentally create session rows on every page load. Step 1 of the UX-refinement plan. Step 2 (the design pass that gives this bell + the wizard their distinctive look) builds on the assets pipeline this PR sets up. Versions bumped: farm_pack 19.0.1.0.0 → 19.0.1.1.0, farm_onboarding 19.0.1.0.0 → 19.0.1.1.0. --- farm_onboarding/__manifest__.py | 8 ++- .../models/farm_onboarding_session.py | 19 ++++++ .../static/src/js/onboarding_systray.esm.js | 56 +++++++++++++++++ .../static/src/xml/onboarding_systray.xml | 28 +++++++++ .../tests/test_farm_onboarding_session.py | 17 ++++++ farm_pack/__init__.py | 1 + farm_pack/__manifest__.py | 5 +- farm_pack/hooks.py | 47 ++++++++++++++ farm_pack/tests/__init__.py | 1 + farm_pack/tests/test_post_init_hook.py | 61 +++++++++++++++++++ 10 files changed, 241 insertions(+), 2 deletions(-) create mode 100644 farm_onboarding/static/src/js/onboarding_systray.esm.js create mode 100644 farm_onboarding/static/src/xml/onboarding_systray.xml create mode 100644 farm_pack/hooks.py create mode 100644 farm_pack/tests/__init__.py create mode 100644 farm_pack/tests/test_post_init_hook.py diff --git a/farm_onboarding/__manifest__.py b/farm_onboarding/__manifest__.py index eeb5990..a3884d4 100644 --- a/farm_onboarding/__manifest__.py +++ b/farm_onboarding/__manifest__.py @@ -1,7 +1,7 @@ { "name": "Farm Onboarding", "summary": "60-second first-run wizard for new farm-pack installs", - "version": "19.0.1.0.0", + "version": "19.0.1.1.0", "license": "AGPL-3", "author": "Ledo Enterprises, Odoo Community Association (OCA)", "website": "https://github.com/ledoent/farm-pack", @@ -16,6 +16,12 @@ "views/farm_enterprise_type_views.xml", "views/farm_onboarding_menu.xml", ], + "assets": { + "web.assets_backend": [ + "farm_onboarding/static/src/js/onboarding_systray.esm.js", + "farm_onboarding/static/src/xml/onboarding_systray.xml", + ], + }, "demo": [], "installable": True, "application": False, diff --git a/farm_onboarding/models/farm_onboarding_session.py b/farm_onboarding/models/farm_onboarding_session.py index 49100fa..f58b431 100644 --- a/farm_onboarding/models/farm_onboarding_session.py +++ b/farm_onboarding/models/farm_onboarding_session.py @@ -131,6 +131,25 @@ def get_or_create_for_current_user(self): ) return session + @api.model + def count_pending_for_current_user(self): + """Lightweight RPC endpoint for the systray bell. + + Returns the number of unfinished onboarding sessions for the + current (user, company). The bell uses this to decide whether + to render the pulsing dot. Kept separate from + `get_or_create_for_current_user` so the systray's mount path + is read-only — we do NOT want every page load creating session + rows. + """ + return self.search_count( + [ + ("company_id", "=", self.env.company.id), + ("user_id", "=", self.env.user.id), + ("state", "!=", "done"), + ] + ) + def action_open_for_current_user(self): session = self.get_or_create_for_current_user() return { diff --git a/farm_onboarding/static/src/js/onboarding_systray.esm.js b/farm_onboarding/static/src/js/onboarding_systray.esm.js new file mode 100644 index 0000000..d04314f --- /dev/null +++ b/farm_onboarding/static/src/js/onboarding_systray.esm.js @@ -0,0 +1,56 @@ +/** @odoo-module **/ + +import {Component, onWillStart, useState} from "@odoo/owl"; +import {registry} from "@web/core/registry"; +import {useService} from "@web/core/utils/hooks"; + +/** + * Systray bell that surfaces unfinished farm-onboarding sessions. + * + * Hidden when the current user has no pending session (count == 0), + * so non-farm users see nothing. When pending, a pulsing dot draws + * the eye; click opens the wizard via the existing + * `action_open_for_current_user` server action. + * + * Deliberately lightweight — one `search_count` RPC on mount, no + * polling. The bell hides immediately on click (optimistic); if the + * user backs out of the wizard without finishing, the next page + * reload will surface it again. + */ +export class FarmOnboardingSystray extends Component { + static template = "farm_onboarding.SystrayBell"; + static props = {}; + + setup() { + this.orm = useService("orm"); + this.action = useService("action"); + this.state = useState({pending: 0, loaded: false}); + + onWillStart(async () => { + this.state.pending = await this.orm.call( + "farm.onboarding.session", + "count_pending_for_current_user", + [] + ); + this.state.loaded = true; + }); + } + + async openWizard() { + const action = await this.orm.call( + "farm.onboarding.session", + "action_open_for_current_user", + [] + ); + await this.action.doAction(action); + this.state.pending = 0; + } +} + +registry + .category("systray") + .add( + "farm_onboarding.SystrayBell", + {Component: FarmOnboardingSystray}, + {sequence: 100} + ); diff --git a/farm_onboarding/static/src/xml/onboarding_systray.xml b/farm_onboarding/static/src/xml/onboarding_systray.xml new file mode 100644 index 0000000..a8685d7 --- /dev/null +++ b/farm_onboarding/static/src/xml/onboarding_systray.xml @@ -0,0 +1,28 @@ + + + + +
+