diff --git a/.hgignore b/.hgignore
index ff39af1a9d50ba1f598f807932876aa939d58849_LmhnaWdub3Jl..f13b4b6ca20c6f4d6faa688f5a5d4e258e189ab9_LmhnaWdub3Jl 100644
--- a/.hgignore
+++ b/.hgignore
@@ -1,24 +1,3 @@
 syntax: glob
-**/*.pyc
-*.pyc
-*.pyo
-*.swp
-.tmp*
-*~
-*.egg-info
-dist/*
-build/*
-lib/*
-output/*
-*.orig
-*.log
-.settings/*
-storage/*
-.project
-.idea
-.pydevproject
-*.db
-.ropeproject/*
-.mob
 ./doc/_build
 ./doc/autotodo
@@ -23,5 +2,2 @@
 ./doc/_build
 ./doc/autotodo
-./doc/manifest
-pyproject.toml
-.isort.cfg
diff --git a/__manifest__.py b/__manifest__.py
index ff39af1a9d50ba1f598f807932876aa939d58849_X19tYW5pZmVzdF9fLnB5..f13b4b6ca20c6f4d6faa688f5a5d4e258e189ab9_X19tYW5pZmVzdF9fLnB5 100644
--- a/__manifest__.py
+++ b/__manifest__.py
@@ -19,9 +19,12 @@
 ##############################################################################
 {
     "name": "Board alerts",
-    "summary": "Send emails at regular intervals to summarize the contents of a dashboard.",
+    "summary": """
+        Send emails at regular intervals"
+        to summarize the contents of a dashboard.
+    """,
     "license": "AGPL-3",
     "version": "16.0.1.0.0",
     "category": "Tools",
     "author": "XCG Consulting",
     "website": "https://orbeet.io/",
@@ -23,7 +26,7 @@
     "license": "AGPL-3",
     "version": "16.0.1.0.0",
     "category": "Tools",
     "author": "XCG Consulting",
     "website": "https://orbeet.io/",
-    "depends": ["board", "mail", "web"],
+    "depends": ["web", "board", "mail", "spreadsheet_dashboard"],
     "data": [
@@ -29,4 +32,5 @@
     "data": [
+        "security/ir.model.access.csv",
         "data/alert_board.xml",
         "data/board_alerts_email_template.xml",
         "data/board_alerts_cron_task.xml",
@@ -30,6 +34,5 @@
         "data/alert_board.xml",
         "data/board_alerts_email_template.xml",
         "data/board_alerts_cron_task.xml",
-        "views/board_alerts_assets.xml",
         "wizard/board_alerts_dlg.xml",
     ],
@@ -34,5 +37,11 @@
         "wizard/board_alerts_dlg.xml",
     ],
-    "qweb": ["static/src/xml/alert_board.xml"],
+    "assets": {
+        "web.assets_backend": [
+            "/board_alerts/static/src/xml/alert_board.xml",
+            # "/board_alerts/static/src/scss/alert_board.scss",
+            "/board_alerts/static/src/js/alert_board.js",
+        ],
+    },
     "installable": True,
 }
diff --git a/controllers/add_to_alert_dashboard.py b/controllers/add_to_alert_dashboard.py
index ff39af1a9d50ba1f598f807932876aa939d58849_Y29udHJvbGxlcnMvYWRkX3RvX2FsZXJ0X2Rhc2hib2FyZC5weQ==..f13b4b6ca20c6f4d6faa688f5a5d4e258e189ab9_Y29udHJvbGxlcnMvYWRkX3RvX2FsZXJ0X2Rhc2hib2FyZC5weQ== 100644
--- a/controllers/add_to_alert_dashboard.py
+++ b/controllers/add_to_alert_dashboard.py
@@ -13,11 +13,8 @@
     """
 
     @route(route="/board/add_to_alert_dashboard", type="json", auth="user")
-    def add_to_dashboard(
-        self, action_id, context_to_save, domain, view_mode, name=""
-    ):
-        """Called when adding to the alert dashboard from the Odoo web client.
-        """
+    def add_to_dashboard(self, action_id, context_to_save, domain, view_mode, name=""):
+        """Called when adding to the alert dashboard from the Odoo web client."""
 
         action = request.env.ref("board_alerts.action_alert_board")
         if (
@@ -28,7 +25,7 @@
         ):
             # Maybe should check the content instead of model board.board ?
             view_id = action["views"][0][0]
-            board = request.env["board.board"].fields_view_get(view_id, "form")
+            board = request.env["board.board"].get_view(view_id, "form")
             if board and "arch" in board:
                 xml = ElementTree.fromstring(board["arch"])
                 column = xml.find("./board/column")
diff --git a/data/alert_board.xml b/data/alert_board.xml
index ff39af1a9d50ba1f598f807932876aa939d58849_ZGF0YS9hbGVydF9ib2FyZC54bWw=..f13b4b6ca20c6f4d6faa688f5a5d4e258e189ab9_ZGF0YS9hbGVydF9ib2FyZC54bWw= 100644
--- a/data/alert_board.xml
+++ b/data/alert_board.xml
@@ -1,3 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8" ?>
 <odoo>
     <data noupdate="1">
@@ -2,6 +2,5 @@
 <odoo>
     <data noupdate="1">
-
         <!-- Define the board the user can drag views into that will be used to send
             emails. Imitated from the definition of the "My Dashboard" board in odoo/addons/board/views/board_views.xml. -->
 
@@ -25,8 +24,11 @@
             <field name="view_id" ref="alert_board" />
         </record>
 
-        <menuitem id="menu_alert_board" parent="base.menu_board_root"
-            action="action_alert_board" sequence="6" />
-
+        <menuitem
+            id="menu_alert_board"
+            parent="spreadsheet_dashboard.spreadsheet_dashboard_menu_root"
+            action="action_alert_board"
+            sequence="126"
+        />
     </data>
 </odoo>
diff --git a/data/board_alerts_cron_task.xml b/data/board_alerts_cron_task.xml
index ff39af1a9d50ba1f598f807932876aa939d58849_ZGF0YS9ib2FyZF9hbGVydHNfY3Jvbl90YXNrLnhtbA==..f13b4b6ca20c6f4d6faa688f5a5d4e258e189ab9_ZGF0YS9ib2FyZF9hbGVydHNfY3Jvbl90YXNrLnhtbA== 100644
--- a/data/board_alerts_cron_task.xml
+++ b/data/board_alerts_cron_task.xml
@@ -1,3 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8" ?>
 <odoo>
     <data noupdate="1">
@@ -2,6 +2,5 @@
 <odoo>
     <data noupdate="1">
-
         <!-- Cron task to send board alert emails every morning at 07H00. -->
 
         <record id="board_alerts_cron_task" model="ir.cron">
@@ -10,5 +9,5 @@
             <field name="code">model.send_board_alerts()</field>
             <field name="interval_number">1</field>
             <field name="interval_type">days</field>
-            <field name="model_id" ref="model_res_users"/>
+            <field name="model_id" ref="model_res_users" />
             <field name="name">Board alerts - Daily emails</field>
@@ -14,5 +13,4 @@
             <field name="name">Board alerts - Daily emails</field>
-            <field name="nextcall"
-                eval="time.strftime('%Y-%m-%d 07:00:00', time.localtime(time.time() + 24 * 3600))" />
+            <field name="nextcall" eval="time.strftime('%Y-%m-%d 07:00:00')" />
             <field name="numbercall">-1</field>
         </record>
@@ -17,5 +15,4 @@
             <field name="numbercall">-1</field>
         </record>
-
     </data>
 </odoo>
diff --git a/data/board_alerts_email_template.xml b/data/board_alerts_email_template.xml
index ff39af1a9d50ba1f598f807932876aa939d58849_ZGF0YS9ib2FyZF9hbGVydHNfZW1haWxfdGVtcGxhdGUueG1s..f13b4b6ca20c6f4d6faa688f5a5d4e258e189ab9_ZGF0YS9ib2FyZF9hbGVydHNfZW1haWxfdGVtcGxhdGUueG1s 100644
--- a/data/board_alerts_email_template.xml
+++ b/data/board_alerts_email_template.xml
@@ -1,3 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8" ?>
 <odoo>
     <data noupdate="1">
@@ -2,6 +2,5 @@
 <odoo>
     <data noupdate="1">
-
         <!-- Default email template for board alert emails. -->
 
         <record id="board_alerts_mail_template" model="mail.template">
@@ -5,8 +4,10 @@
         <!-- Default email template for board alert emails. -->
 
         <record id="board_alerts_mail_template" model="mail.template">
-            <field name="body_html"><![CDATA[
+            <field
+                name="body_html"
+            ><![CDATA[
                 <p>Hello ${ object.name },</p>
                 <p>Here follow your alerts for today.</p>
                 <div>${ object.get_board_alert_contents() | safe }</div>
             ]]></field>
@@ -9,8 +10,10 @@
                 <p>Hello ${ object.name },</p>
                 <p>Here follow your alerts for today.</p>
                 <div>${ object.get_board_alert_contents() | safe }</div>
             ]]></field>
-            <field name="email_from">${ object.company_id.name or '' } &lt;${ object.company_id.email or '' }&gt;</field>
+            <field
+                name="email_from"
+            >${ object.company_id.name or '' } &lt;${ object.company_id.email or '' }&gt;</field>
             <field name="partner_to">${ object.partner_id.id }</field>
             <field name="email_to">${ object.email }</field>
             <field name="lang">${object.partner_id.lang}</field>
@@ -18,6 +21,5 @@
             <field name="name">Board alert email</field>
             <field name="subject">Today's alerts</field>
         </record>
-
     </data>
 </odoo>
diff --git a/i18n/fr.po b/i18n/fr.po
index ff39af1a9d50ba1f598f807932876aa939d58849_aTE4bi9mci5wbw==..f13b4b6ca20c6f4d6faa688f5a5d4e258e189ab9_aTE4bi9mci5wbw== 100644
--- a/i18n/fr.po
+++ b/i18n/fr.po
@@ -6,8 +6,8 @@
 msgstr ""
 "Project-Id-Version: Odoo Server 13.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-06-12 07:40+0000\n"
-"PO-Revision-Date: 2020-06-12 09:42+0200\n"
+"POT-Creation-Date: 2024-01-04 09:09+0000\n"
+"PO-Revision-Date: 2024-01-04 09:16+0000\n"
 "Last-Translator: Houzéfa Abbasbhay <houzefa.abba@xcg-consulting.fr>\n"
 "Language-Team: XCG Consulting\n"
 "Language: fr\n"
@@ -15,7 +15,7 @@
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
-"X-Generator: Poedit 2.0.6\n"
+"X-Generator: Poedit 3.4.2\n"
 
 #. module: board_alerts
 #: model:mail.template,body_html:board_alerts.board_alerts_mail_template
@@ -34,5 +34,5 @@
 "            "
 
 #. module: board_alerts
-#. openerp-web
+#. odoo-javascript
 #: code:addons/board_alerts/static/src/js/alert_board.js:0
@@ -38,6 +38,7 @@
 #: code:addons/board_alerts/static/src/js/alert_board.js:0
-#, python-format
-msgid "'%s' added to alert dashboard"
+#, fuzzy, python-format
+#| msgid "'%s' added to alert dashboard"
+msgid "\"%s\" added to alert dashboard"
 msgstr "'%s' ajouté au tableau de bord des alertes"
 
 #. module: board_alerts
@@ -41,10 +42,10 @@
 msgstr "'%s' ajouté au tableau de bord des alertes"
 
 #. module: board_alerts
-#. openerp-web
+#. odoo-javascript
 #: code:addons/board_alerts/static/src/xml/alert_board.xml:0
 #, python-format
 msgid "Add"
 msgstr "Ajouter"
 
 #. module: board_alerts
@@ -45,13 +46,13 @@
 #: code:addons/board_alerts/static/src/xml/alert_board.xml:0
 #, python-format
 msgid "Add"
 msgstr "Ajouter"
 
 #. module: board_alerts
-#. openerp-web
+#. odoo-javascript
 #: code:addons/board_alerts/static/src/xml/alert_board.xml:0
 #, python-format
 msgid "Add to my alert dashboard"
 msgstr "Ajouter à mon tableau d'alertes"
 
 #. module: board_alerts
@@ -52,9 +53,14 @@
 #: code:addons/board_alerts/static/src/xml/alert_board.xml:0
 #, python-format
 msgid "Add to my alert dashboard"
 msgstr "Ajouter à mon tableau d'alertes"
 
 #. module: board_alerts
+#: model:mail.template,name:board_alerts.board_alerts_mail_template
+msgid "Board alert email"
+msgstr "E-mail d'alerte du tableau de bord"
+
+#. module: board_alerts
 #: model:ir.model,name:board_alerts.model_board_alerts_dlg
 msgid "Board alert sender dialog box"
 msgstr "Boîte de dialogue d'envoi d'alertes de tableau de bord"
@@ -62,7 +68,6 @@
 #. module: board_alerts
 #: model:ir.actions.server,name:board_alerts.board_alerts_cron_task_ir_actions_server
 #: model:ir.cron,cron_name:board_alerts.board_alerts_cron_task
-#: model:ir.cron,name:board_alerts.board_alerts_cron_task
 msgid "Board alerts - Daily emails"
 msgstr "Tableau de bord d'alertes - Emails quotidiens"
 
@@ -72,7 +77,7 @@
 msgstr "Annuler"
 
 #. module: board_alerts
-#. openerp-web
+#. odoo-javascript
 #: code:addons/board_alerts/static/src/js/alert_board.js:0
 #, python-format
 msgid "Could not add filter to alert dashboard"
@@ -99,6 +104,7 @@
 msgstr "ID"
 
 #. module: board_alerts
+#. odoo-python
 #: code:addons/board_alerts/models/board_alerts.py:0
 #, python-format
 msgid "Lang %s not found"
@@ -120,6 +126,7 @@
 msgstr "Modifié le"
 
 #. module: board_alerts
+#. odoo-python
 #: code:addons/board_alerts/models/board_alerts.py:0
 #: model:ir.actions.act_window,name:board_alerts.action_alert_board
 #: model:ir.ui.menu,name:board_alerts.menu_alert_board
@@ -129,9 +136,10 @@
 msgstr "Mes alertes"
 
 #. module: board_alerts
+#. odoo-python
 #: code:addons/board_alerts/models/board_alerts.py:0
 #, python-format
 msgid "No"
 msgstr "Non"
 
 #. module: board_alerts
@@ -132,10 +140,10 @@
 #: code:addons/board_alerts/models/board_alerts.py:0
 #, python-format
 msgid "No"
 msgstr "Non"
 
 #. module: board_alerts
-#. openerp-web
+#. odoo-javascript
 #: code:addons/board_alerts/static/src/js/alert_board.js:0
 #, python-format
 msgid "Please refresh your browser for the changes to take effect."
@@ -155,8 +163,8 @@
 
 #. module: board_alerts
 #: model:ir.model,name:board_alerts.model_res_users
-msgid "Users"
-msgstr "Utilisateurs"
+msgid "User"
+msgstr "Utilisateur"
 
 #. module: board_alerts
 #: model_terms:ir.ui.view,arch_db:board_alerts.board_alerts_dlg
@@ -168,6 +176,7 @@
 "les alertes des tableaux\"."
 
 #. module: board_alerts
+#. odoo-python
 #: code:addons/board_alerts/models/board_alerts.py:0
 #, python-format
 msgid "Yes"
diff --git a/models/board_alerts.py b/models/board_alerts.py
index ff39af1a9d50ba1f598f807932876aa939d58849_bW9kZWxzL2JvYXJkX2FsZXJ0cy5weQ==..f13b4b6ca20c6f4d6faa688f5a5d4e258e189ab9_bW9kZWxzL2JvYXJkX2FsZXJ0cy5weQ== 100644
--- a/models/board_alerts.py
+++ b/models/board_alerts.py
@@ -32,7 +32,6 @@
 
     @api.model
     def send_board_alerts(self):
-        """Find users and send them their board alerts.
-        """
+        """Find users and send them their board alerts."""
 
         # Get our email template, referenced by its XML ID.
@@ -37,8 +36,6 @@
 
         # Get our email template, referenced by its XML ID.
-        email_template = self.sudo().env.ref(
-            "board_alerts.board_alerts_mail_template"
-        )
+        email_template = self.sudo().env.ref("board_alerts.board_alerts_mail_template")
 
         # Loop through all users; send them an email.
         for user in self.sudo().search([]):
@@ -50,9 +47,9 @@
 
             # Fill the context to avoid computing contents twice.
             (
-                email_template.with_context(
-                    board_alert_contents=contents
-                ).send_mail(user.id)
+                email_template.with_context(board_alert_contents=contents).send_mail(
+                    user.id
+                )
             )
 
     def get_board_alert_contents(self):
@@ -83,9 +80,7 @@
         board_view = self.env.ref("board_alerts.alert_board")
 
         # Set up the link that will be inserted in emails.
-        board_link = (
-            self.env["ir.config_parameter"].sudo().get_param("web.base.url")
-        )
+        board_link = self.env["ir.config_parameter"].sudo().get_param("web.base.url")
         if board_link:
             board_link += "/?db=%s#action=%s" % (
                 self.env.cr.dbname,
@@ -93,7 +88,7 @@
             )
 
         # Get the "custom view" representing the board.
-        board = self.env["board.board"].fields_view_get(view_id=board_view.id)
+        board = self.env["board.board"].get_view(view_id=board_view.id)
 
         to_send = []
 
@@ -132,7 +127,7 @@
                 )
                 .id
             )
-            act_view = act_model.with_context(act_context).fields_view_get(
+            act_view = act_model.with_context(act_context).get_view(
                 view_id=act_view_id, view_type=view_type
             )
 
@@ -194,12 +189,10 @@
         for data_title, data in data_list:
             frame = etree.SubElement(root, "div")
             frame.attrib["style"] = (
-                "border: 1px solid LightGray;"
-                "margin-top: 8px;"
-                "padding: 8px;"
+                "border: 1px solid LightGray;" "margin-top: 8px;" "padding: 8px;"
             )
 
             title = etree.SubElement(frame, "h3")
             title.text = data_title or ""
 
             table = etree.SubElement(frame, "table")
@@ -200,12 +193,10 @@
             )
 
             title = etree.SubElement(frame, "h3")
             title.text = data_title or ""
 
             table = etree.SubElement(frame, "table")
-            table.attrib["style"] = (
-                "border-collapse: collapse;" "border-spacing: 2px;"
-            )
+            table.attrib["style"] = "border-collapse: collapse;" "border-spacing: 2px;"
 
             first_record = True
 
@@ -236,11 +227,7 @@
 
         # The user object only has a "lang" selection key; find the actual
         # language object.
-        lang = (
-            self.sudo()
-            .env["res.lang"]
-            .search([("code", "=", self.lang)], limit=1)
-        )
+        lang = self.sudo().env["res.lang"].search([("code", "=", self.lang)], limit=1)
         if not lang:
             raise exceptions.UserError(_("Lang %s not found") % self.lang)
 
@@ -251,8 +238,7 @@
                 "allowed_company_ids": self.company_ids.ids,
                 # ---
                 "date_format": lang.date_format,
-                "datetime_format": "%s %s"
-                % (lang.date_format, lang.time_format),
+                "datetime_format": "%s %s" % (lang.date_format, lang.time_format),
                 "lang": self.lang,
                 "tz": self.tz,
                 "uid": self.id,
@@ -337,8 +323,7 @@
         return content or ""
 
     def _get_object_name(self, content):
-        """Call the "name_get" function of the specified Odoo record set.
-        """
+        """Call the "name_get" function of the specified Odoo record set."""
 
         # 0: first element of the returned list.
         # 1: second element of the (ID, name) tuple.
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000000000000000000000000000000000000..f13b4b6ca20c6f4d6faa688f5a5d4e258e189ab9_cHlwcm9qZWN0LnRvbWw=
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,78 @@
+[project]
+name = "odoo-addon-board_alerts"
+dynamic = ["version"]
+readme = "README.rst"
+requires-python = "~=3.10"
+license = { file = "LICENSE", name = "GNU Affero General Public License v3" }
+keywords = ["odoo"]
+authors = [{ name = "XCG Consulting" }]
+classifiers = [
+  "Programming Language :: Python",
+  "Programming Language :: Python :: 3",
+  "Programming Language :: Python :: 3.10",
+  "Framework :: Odoo",
+  "Framework :: Odoo :: 16.0",
+  "License :: OSI Approved :: GNU Affero General Public License v3"
+]
+dependencies = ["odoo==16.0.*"]
+
+[project.optional-dependencies]
+doc = ["sphinx", "sphinx-odoo-autodoc", "odoo-scripts"]
+test = []
+
+[project.urls]
+repository = "https://orus.io/xcg/odoo-modules/board_alerts"
+changelog = "https://orus.io/xcg/odoo-module/board_alerts/-/blob/branch/16.0/NEWS.rst"
+
+[build-system]
+requires = ["hatchling >=1.19", "hatch-vcs"]
+build-backend = "hatchling.build"
+
+[tool.hatch.build]
+exclude = [
+  "/doc/",
+  "/.editorconfig",
+  "/.eslintrc.yml",
+  "/.flake8",
+  "/.gitlab-ci.yml",
+  "/.hgignore",
+  "/.hgtags",
+  "/.prettierrc.yml",
+  "/.yamllint.yaml"
+]
+
+[tool.hatch.build.targets.wheel]
+include = [
+  "*.csv",
+  "/i18n/",
+  "/static/",
+  "README.rst",
+  "*.xml",
+  "*.py",
+  "*.svg",
+  "*.png"
+]
+
+[tool.hatch.build.targets.wheel.sources]
+"" = "odoo/addons/board_alerts"
+
+[tool.hatch.version]
+source = "vcs"
+
+[tool.black]
+target = 3.10
+
+[tool.isort]
+py_version = 310
+profile = "black"
+known_odoo = ['odoo']
+known_odoo_addons = ['odoo.addons']
+sections = [
+  'FUTURE',
+  'STDLIB',
+  'THIRDPARTY',
+  'ODOO',
+  'ODOO_ADDONS',
+  'FIRSTPARTY',
+  'LOCALFOLDER'
+]
diff --git a/security/ir.model.access.csv b/security/ir.model.access.csv
new file mode 100644
index 0000000000000000000000000000000000000000..f13b4b6ca20c6f4d6faa688f5a5d4e258e189ab9_c2VjdXJpdHkvaXIubW9kZWwuYWNjZXNzLmNzdg==
--- /dev/null
+++ b/security/ir.model.access.csv
@@ -0,0 +1,2 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_board_alerts_dlg,board_alerts_dlg,model_board_alerts_dlg,base.group_user,1,1,1,1
diff --git a/static/src/js/alert_board.js b/static/src/js/alert_board.js
index ff39af1a9d50ba1f598f807932876aa939d58849_c3RhdGljL3NyYy9qcy9hbGVydF9ib2FyZC5qcw==..f13b4b6ca20c6f4d6faa688f5a5d4e258e189ab9_c3RhdGljL3NyYy9qcy9hbGVydF9ib2FyZC5qcw== 100644
--- a/static/src/js/alert_board.js
+++ b/static/src/js/alert_board.js
@@ -1,3 +1,13 @@
+/** @odoo-module **/
+
+import {Dropdown} from "@web/core/dropdown/dropdown";
+import {registry} from "@web/core/registry";
+import {useAutofocus, useService} from "@web/core/utils/hooks";
+import {sprintf} from "@web/core/utils/strings";
+
+const {Component, useState} = owl;
+const favoriteMenuRegistry = registry.category("favoriteMenu");
+
 /* Alert board. */
 
 /* Taken from the default "My board" dashboard.
@@ -6,17 +16,9 @@
  * Adapted to add an "Add to my alert board" menu command.
  */
 
-odoo.define('board_alerts.AddToAlertBoardMenu', function(require) {
-    "use strict";
-
-    var ActionManager = require('web.ActionManager');
-    var Context = require('web.Context');
-    var core = require('web.core');
-    var Domain = require('web.Domain');
-    var favorites_submenus_registry = require('web.favorites_submenus_registry');
-    var pyUtils = require('web.py_utils');
-    var Widget = require('web.Widget');
-
-    var _t = core._t;
-    var QWeb = core.qweb;
+export class AddToAlertBoard extends Component {
+    setup() {
+        this.notification = useService("notification");
+        this.rpc = useService("rpc");
+        this.state = useState({name: this.env.config.getDisplayName()});
 
@@ -22,28 +24,4 @@
 
-    var AddToAlertBoardMenu = Widget.extend({
-    events: _.extend({}, Widget.prototype.events, {
-    'click .o_add_to_alert_board.o_menu_header': '_onAlertMenuHeaderClick',
-    'click .o_add_to_alert_board_confirm_button': '_onAddToAlertBoardConfirmButtonClick',
-    'click .o_add_to_alert_board_input': '_onAddToAlertBoardInputClick',
-    'keyup .o_add_to_alert_board_input': '_onAlertKeyUp',
-    }),
-    /**
-     * @override
-     * @param {Object} params
-     * @param {Object} params.action an ir.actions description
-     */
-    init: function(parent, params) {
-        this._super(parent);
-        this.action = params.action;
-        this.isOpen = false;
-    },
-    /**
-     * @override
-     */
-    start: function() {
-        if (this.action.id && this.action.type === 'ir.actions.act_window') {
-            this._render();
-        }
-        return this._super.apply(this, arguments);
-    },
+        useAutofocus();
+    }
 
@@ -49,5 +27,5 @@
 
-    //--------------------------------------------------------------------------
-    // Public
-    //--------------------------------------------------------------------------
+    //---------------------------------------------------------------------
+    // Protected
+    //---------------------------------------------------------------------
 
@@ -53,14 +31,14 @@
 
-    /**
-     * Closes the menu and render it.
-     * 
-     */
-    closeMenu: function() {
-        this.isOpen = false;
-        this._render();
-    },
-
-    //--------------------------------------------------------------------------
-    // Private
-    //--------------------------------------------------------------------------
+    async addToAlertBoard() {
+        const {domain, globalContext} = this.env.searchModel;
+        const {comparison, context, groupBys, orderBy} =
+            this.env.searchModel.getPreFavoriteValues();
+        const contextToSave = {
+            ...globalContext,
+            ...context,
+            comparison,
+            orderedBy: orderBy,
+            group_by: groupBys,
+            dashboard_merge_domains_contexts: false,
+        };
 
@@ -66,42 +44,9 @@
 
-    /**
-     * This is the main function for actually saving the dashboard. This method is supposed to call
-     * the route /board/add_to_alert_dashboard with proper information.
-     * 
-     * @private
-     * @returns {Promise}
-     */
-    _addToAlertBoard: function() {
-        var self = this;
-        var searchQuery;
-        // TO DO: for now the domains in query are evaluated.
-        // This should be changed I think.
-        this.trigger_up('get_search_query', {
-            callback: function(query) {
-                searchQuery = query;
-            }
-        });
-        // TO DO: replace direct reference to action manager, controller, and currentAction in code below
-
-        // AAB: trigger_up an event that will be intercepted by the controller,
-        // as soon as the controller is the parent of the control panel
-        var actionManager = this.findAncestor(function(ancestor) {
-            return ancestor instanceof ActionManager;
-        });
-        var controller = actionManager.getCurrentController();
-
-        var context = new Context(this.action.context);
-        context.add(searchQuery.context);
-        context.add({
-        group_by: searchQuery.groupBy,
-        orderedBy: searchQuery.orderedBy,
-        });
-
-        this.trigger_up('get_controller_query_params', {
-            callback: function(controllerQueryParams) {
-                var queryContext = controllerQueryParams.context;
-                var allContext = _.extend(_.omit(controllerQueryParams, ['context']), queryContext);
-                context.add(allContext);
-            }
+        const result = await this.rpc("/board/add_to_alert_dashboard", {
+            action_id: this.env.config.actionId || false,
+            context_to_save: contextToSave,
+            domain,
+            name: this.state.name,
+            view_mode: this.env.config.viewType,
         });
 
@@ -106,11 +51,24 @@
         });
 
-        var domain = new Domain(this.action.domain || []);
-        domain = Domain.prototype.normalizeArray(domain.toArray().concat(searchQuery.domain));
-
-        var evalutatedContext = pyUtils.eval('context', context);
-        for ( var key in evalutatedContext) {
-            if (evalutatedContext.hasOwnProperty(key) && /^search_default_/.test(key)) {
-                delete evalutatedContext[key];
-            }
+        if (result) {
+            this.notification.add(
+                this.env._t(
+                    "Please refresh your browser for the changes to take effect."
+                ),
+                {
+                    title: sprintf(
+                        this.env._t(`"%s" added to alert dashboard`),
+                        this.state.name
+                    ),
+                    type: "warning",
+                }
+            );
+            this.state.name = this.env.config.getDisplayName();
+        } else {
+            this.notification.add(
+                this.env._t("Could not add filter to alert dashboard"),
+                {
+                    type: "danger",
+                }
+            );
         }
@@ -116,7 +74,3 @@
         }
-        evalutatedContext.dashboard_merge_domains_contexts = false;
-
-        var name = this.$input.val();
-
-        this.closeMenu();
+    }
 
@@ -122,46 +76,3 @@
 
-        return self._rpc({
-        route: '/board/add_to_alert_dashboard',
-        params: {
-        action_id: self.action.id || false,
-        context_to_save: evalutatedContext,
-        domain: domain,
-        view_mode: controller.viewType,
-        name: name,
-        },
-        }).then(function(r) {
-            if (r) {
-                self.do_notify(_.str.sprintf(_t("'%s' added to alert dashboard"), name), _t('Please refresh your browser for the changes to take effect.'));
-            } else {
-                self.do_warn(_t("Could not add filter to alert dashboard"));
-            }
-        });
-    },
-    /**
-     * Renders and focuses the unique input if it is visible.
-     * 
-     * @private
-     */
-    _render: function() {
-        var $el = QWeb.render('AddToAlertBoardMenu', {
-            widget: this
-        });
-        this._replaceElement($el);
-        if (this.isOpen) {
-            this.$input = this.$('.o_add_to_alert_board_input');
-            this.$input.val(this.action.name);
-            this.$input.focus();
-        }
-    },
-    /**
-     * Hides and displays the submenu which allows adding custom filters.
-     * 
-     * @private
-     */
-    _toggleMenu: function() {
-        this.isOpen = !this.isOpen;
-        this._render();
-    },
-
-    //--------------------------------------------------------------------------
+    //---------------------------------------------------------------------
     // Handlers
@@ -167,4 +78,4 @@
     // Handlers
-    //--------------------------------------------------------------------------
+    //---------------------------------------------------------------------
 
     /**
@@ -169,23 +80,4 @@
 
     /**
-     * @private
-     * @param {jQueryEvent} event
-     */
-    _onAddToAlertBoardInputClick: function(event) {
-        event.preventDefault();
-        event.stopPropagation();
-        this.$input.focus();
-    },
-    /**
-     * @private
-     * @param {jQueryEvent} event
-     */
-    _onAddToAlertBoardConfirmButtonClick: function(event) {
-        event.preventDefault();
-        event.stopPropagation();
-        this._addToAlertBoard();
-    },
-    /**
-     * @private
-     * @param {jQueryEvent} event
+     * @param {KeyboardEvent} ev
      */
@@ -191,5 +83,6 @@
      */
-    _onAlertKeyUp: function(event) {
-        if (event.which === $.ui.keyCode.ENTER) {
-            this._addToAlertBoard();
+    onInputKeydown(ev) {
+        if (ev.key === "Enter") {
+            ev.preventDefault();
+            this.addToAlertBoard();
         }
@@ -195,12 +88,7 @@
         }
-    },
-    /**
-     * @private
-     * @param {jQueryEvent} event
-     */
-    _onAlertMenuHeaderClick: function(event) {
-        event.preventDefault();
-        event.stopPropagation();
-        this._toggleMenu();
-    },
+    }
+}
+
+AddToAlertBoard.template = "board_alerts.AddToAlertBoard";
+AddToAlertBoard.components = {Dropdown};
 
@@ -206,3 +94,8 @@
 
-    });
+export const addToAlertBoardItem = {
+    Component: AddToAlertBoard,
+    groupNumber: 4,
+    isDisplayed: ({config}) =>
+        config.actionType === "ir.actions.act_window" && config.actionId,
+};
 
@@ -208,6 +101,2 @@
 
-    // Use prio=11 here so this comes right after the base "add_to_board_menu" which has prio=10.
-    favorites_submenus_registry.add('add_to_alert_board_menu', AddToAlertBoardMenu, 11);
-
-    return AddToAlertBoardMenu;
-});
+favoriteMenuRegistry.add("add-to-board-alerts", addToAlertBoardItem, {sequence: 11});
diff --git a/static/src/xml/alert_board.xml b/static/src/xml/alert_board.xml
index ff39af1a9d50ba1f598f807932876aa939d58849_c3RhdGljL3NyYy94bWwvYWxlcnRfYm9hcmQueG1s..f13b4b6ca20c6f4d6faa688f5a5d4e258e189ab9_c3RhdGljL3NyYy94bWwvYWxlcnRfYm9hcmQueG1s 100644
--- a/static/src/xml/alert_board.xml
+++ b/static/src/xml/alert_board.xml
@@ -1,1 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" ?>
 <!-- QWeb template for the alert board. -->
@@ -1,19 +2,26 @@
 <!-- QWeb template for the alert board. -->
-
-<template>
-
-    <!-- Include a link in the "Favorites" menu to add to the alert dashboard. Same
-        as the default "Add to my dashboard" link defined in
-        odoo/addons/board/static/src/xml/board.xml. -->
-    <div t-name="AddToAlertBoardMenu">
-        <button type="button" class="dropdown-item o_add_to_alert_board o_menu_header">Add to my alert dashboard</button>
-        <div t-if="widget.isOpen" class="dropdown-item-text o_add_to_alert_board">
-            <input class="o_input o_add_to_alert_board_input" type="text" />
-        </div>
-        <div t-if="widget.isOpen" class="dropdown-item-text o_add_to_alert_board">
-            <button type="button"
-                class="btn btn-primary o_add_to_alert_board_confirm_button">Add</button>
-        </div>
-    </div>
-
-</template>
+<templates xml:space="preserve">
+    <t t-name="board_alerts.AddToAlertBoard" owl="1">
+        <Dropdown class="'o_add_to_board'">
+            <t t-set-slot="toggler">Add to my alert dashboard</t>
+            <div class="px-3 py-2">
+                <input
+                    type="text"
+                    class="o_input"
+                    t-ref="autofocus"
+                    t-model.trim="state.name"
+                    t-on-keydown="onInputKeydown"
+                />
+            </div>
+            <div class="px-3 py-2">
+                <button
+                    type="button"
+                    class="btn btn-primary"
+                    t-on-click="addToAlertBoard"
+                >
+                    Add
+                </button>
+            </div>
+        </Dropdown>
+    </t>
+</templates>
diff --git a/views/board_alerts_assets.xml b/views/board_alerts_assets.xml
deleted file mode 100644
index ff39af1a9d50ba1f598f807932876aa939d58849_dmlld3MvYm9hcmRfYWxlcnRzX2Fzc2V0cy54bWw=..0000000000000000000000000000000000000000
--- a/views/board_alerts_assets.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<odoo>
-
-    <!-- Include assets used by alert boards. -->
-
-    <template id="assets_backend" name="board_alerts assets"
-        inherit_id="web.assets_backend">
-        <xpath expr="." position="inside">
-            <link rel="stylesheet" type="text/scss"
-                href="/board_alerts/static/src/scss/alert_board.scss" />
-            <script type="text/javascript" src="/board_alerts/static/src/js/alert_board.js"></script>
-        </xpath>
-    </template>
-
-</odoo>
diff --git a/wizard/board_alerts_dlg.py b/wizard/board_alerts_dlg.py
index ff39af1a9d50ba1f598f807932876aa939d58849_d2l6YXJkL2JvYXJkX2FsZXJ0c19kbGcucHk=..f13b4b6ca20c6f4d6faa688f5a5d4e258e189ab9_d2l6YXJkL2JvYXJkX2FsZXJ0c19kbGcucHk= 100644
--- a/wizard/board_alerts_dlg.py
+++ b/wizard/board_alerts_dlg.py
@@ -10,8 +10,7 @@
     _description = "Board alert sender dialog box"
 
     def send_board_alerts(self):
-        """Send board alerts then show emails.
-        """
+        """Send board alerts then show emails."""
 
         self.env["res.users"].send_board_alerts()
 
diff --git a/wizard/board_alerts_dlg.xml b/wizard/board_alerts_dlg.xml
index ff39af1a9d50ba1f598f807932876aa939d58849_d2l6YXJkL2JvYXJkX2FsZXJ0c19kbGcueG1s..f13b4b6ca20c6f4d6faa688f5a5d4e258e189ab9_d2l6YXJkL2JvYXJkX2FsZXJ0c19kbGcueG1s 100644
--- a/wizard/board_alerts_dlg.xml
+++ b/wizard/board_alerts_dlg.xml
@@ -1,2 +1,2 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8" ?>
 <odoo>
@@ -2,5 +2,4 @@
 <odoo>
-
     <!-- Dialog shown before manually sending board alert emails, to have some
         kind of confirmation. -->
 
@@ -9,6 +8,5 @@
         <field name="model">board_alerts_dlg</field>
         <field name="arch" type="xml">
             <form>
-
                 <footer>
                     <separator
@@ -13,4 +11,5 @@
                 <footer>
                     <separator
-                        string="Warning! Emails will be sent when clicking on the &quot;Send board alerts&quot; button." />
+                        string="Warning! Emails will be sent when clicking on the &quot;Send board alerts&quot; button."
+                    />
 
@@ -16,5 +15,9 @@
 
-                    <button string="Send board alerts" name="send_board_alerts"
-                        type="object" class="oe_highlight" />
+                    <button
+                        string="Send board alerts"
+                        name="send_board_alerts"
+                        type="object"
+                        class="oe_highlight"
+                    />
                     <button string="Cancel" class="oe_link" special="cancel" />
                 </footer>
@@ -19,6 +22,5 @@
                     <button string="Cancel" class="oe_link" special="cancel" />
                 </footer>
-
             </form>
         </field>
     </record>
@@ -32,7 +34,11 @@
         <field name="target">new</field>
     </record>
 
-    <menuitem id="menu_board_alerts_dlg" action="action_board_alerts_dlg"
-        parent="base.menu_reporting_config" sequence="10" groups="base.group_no_one" />
-
+    <menuitem
+        id="menu_board_alerts_dlg"
+        action="action_board_alerts_dlg"
+        parent="spreadsheet_dashboard.spreadsheet_dashboard_menu_configuration"
+        sequence="20"
+        groups="base.group_no_one"
+    />
 </odoo>