diff --git a/web_quick_start_screen/README.rst b/web_quick_start_screen/README.rst new file mode 100644 index 000000000000..429386e0d0fa --- /dev/null +++ b/web_quick_start_screen/README.rst @@ -0,0 +1,141 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +================== +Quick Start Screen +================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:eba97aa3c66b586477be732ab6d70494f16d1805d2bd24a15b92d0c70d20f29a + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github + :target: https://github.com/OCA/web/tree/19.0/web_quick_start_screen + :alt: OCA/web +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/web-19-0/web-19-0-web_quick_start_screen + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/web&target_branch=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module adds a configurable start screen so users can go right into +their more common tasks. + +It can be configured at the user level or just be used as common +screens. + +**Table of contents** + +.. contents:: + :local: + +Use Cases / Context +=================== + +Some users use repeatedly the same actions on and on and sometimes those +actions are so many clicks away which tends to be frustrating. + +Configuration +============= + +To create quick actions: + +- Go to *Settings > Technical > User Interface > Screen actions* and + create o modify an existing one. +- Choose the desired action, a name, a description and an icon. +- You can add an optional context so you can reuse existing actions. You + can use ``ref()`` to get an id that you can use in your + context. You can also use ``datetime`` and ``context_today`` in that + same way you can do in ``ir.filters``. + +To create quick start screens: + +- Go to *Settings > Technical > User Interface > Quick start screens* + and create or modify an existing one. +- Choose a descriptive name and link some quick screen actions. + +To assign a quick start screen to a user: + +- Go to *Settings > Users and groups > Users* and select one. +- In the *Preferences* tab, *Menus customization* section, you can + choose which *Quick start screen* will that user use. +- If you want to make the user start always in his start screen, in the + same section select the action *Quick Start Screen*. + +To activate the quick start screen menu for a user: + +- Go to *Settings > Users and groups > Users* (with debug mode on) +- In *Technical* groups, set *Quick Start Screen* on. + +Usage +===== + +When you have the proper config, once you login, you'll go to the quick +actions screen. Just click in and start working. + +Known issues / Roadmap +====================== + +- Right now there's no much permissions handling, but it could be made + similarly to how menus deal with them. +- Also we could add the possibility of quick actions for users the same + way that favorite filters work. +- A tour helper that clicked in every defined action would be helpfull + to detect possible issues. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Tecnativa + +Contributors +------------ + +- `Tecnativa `__ + + - Pedro M. Baeza + - David Vidal + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/web `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/web_quick_start_screen/__init__.py b/web_quick_start_screen/__init__.py new file mode 100644 index 000000000000..0650744f6bc6 --- /dev/null +++ b/web_quick_start_screen/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/web_quick_start_screen/__manifest__.py b/web_quick_start_screen/__manifest__.py new file mode 100644 index 000000000000..2b95b6033303 --- /dev/null +++ b/web_quick_start_screen/__manifest__.py @@ -0,0 +1,28 @@ +# Copyright 2024 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +{ + "name": "Quick Start Screen", + "summary": "Configurable start screen for quick actions", + "version": "19.0.1.0.0", + "author": "Tecnativa, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/web", + "license": "AGPL-3", + "category": "web", + "depends": ["web"], + "data": [ + "security/ir.model.access.csv", + "security/security.xml", + "views/quick_screen_action_view.xml", + "views/quick_start_screen_views.xml", + "views/res_users_views.xml", + ], + "demo": [ + "demo/quick_screen_action_demo_data.xml", + ], + "assets": { + "web.assets_backend": [ + "web_quick_start_screen/static/src/scss/quick_start_screen.scss", + "web_quick_start_screen/static/src/js/**/*", + ], + }, +} diff --git a/web_quick_start_screen/demo/quick_screen_action_demo_data.xml b/web_quick_start_screen/demo/quick_screen_action_demo_data.xml new file mode 100644 index 000000000000..72d729d71b47 --- /dev/null +++ b/web_quick_start_screen/demo/quick_screen_action_demo_data.xml @@ -0,0 +1,60 @@ + + + + Contacts + Browse contacts]]> + + fa-users + 7 + + + Access rights + Explore access rights]]> + + fa-eye + 4 + + + Configure screen actions + Configure this screen actions]]> + + + + + Demo start screen + + + + + + + + diff --git a/web_quick_start_screen/i18n/es.po b/web_quick_start_screen/i18n/es.po new file mode 100644 index 000000000000..45d83d593797 --- /dev/null +++ b/web_quick_start_screen/i18n/es.po @@ -0,0 +1,257 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_quick_start_screen +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 19.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-08-23 12:21+0000\n" +"PO-Revision-Date: 2026-04-13 08:14+0000\n" +"Last-Translator: Ed-Spain \n" +"Language-Team: \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.15.2\n" + +#. module: web_quick_start_screen +#: model_terms:quick.start.screen.action,description:web_quick_start_screen.quick_start_screen_action_contacts_demo +msgid "Browse contacts" +msgstr "Explorar contactos" + +#. module: web_quick_start_screen +#: model_terms:quick.start.screen.action,description:web_quick_start_screen.quick_start_screen_action_config_actions_demo +msgid "Configure this screen actions" +msgstr "Configurar acciones de pantalla" + +#. module: web_quick_start_screen +#: model_terms:quick.start.screen.action,description:web_quick_start_screen.quick_start_screen_action_access_rights_demo +msgid "Explore access rights" +msgstr "Ver derechos de acceso" + +#. module: web_quick_start_screen +#: model:quick.start.screen.action,name:web_quick_start_screen.quick_start_screen_action_access_rights_demo +msgid "Access rights" +msgstr "Derechos de acceso" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__action_ids +msgid "Action" +msgstr "Acción" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__action_ref_id +msgid "Action Ref" +msgstr "Referencia de acción" + +#. module: web_quick_start_screen +#: model:ir.model,name:web_quick_start_screen.model_quick_start_screen_action +msgid "Actions to be launched from a quick start screen" +msgstr "Acciones que serán lanzadas desde la pantalla de inicio" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__active +msgid "Active" +msgstr "Activo" + +#. module: web_quick_start_screen +#: model:ir.model.fields,help:web_quick_start_screen.field_quick_start_screen_action__context +msgid "" +"Add extra context if needed. You can use `ref('')` and it will " +"beevaluated. You can also use `datetime` and `context_today` in the same " +"way`ir.filters` do." +msgstr "" +"Añadir contexto adicional si se necesita. Puede utilizar `ref('')` " +"y será evaluado. También puede utilizar `datetime` y `context_today` del " +"mismo modo que se hace en `ir.filters`." + +#. module: web_quick_start_screen +#: model:ir.model.fields,help:web_quick_start_screen.field_quick_start_screen_action__domain +msgid "" +"Add extra domain if needed. You can use `ref('')` and it will " +"beevaluated. You can also use `datetime` and `context_today` in the same " +"way`ir.filters` do." +msgstr "" +"Añadir un dominio adicional si se necesita. Puede utilizar " +"`ref('')` y será evaluado. También puede utilizar `datetime` y " +"`context_today` del mismo modo que se hace en `ir.filters`." + +#. module: web_quick_start_screen +#: model:ir.model.fields,help:web_quick_start_screen.field_quick_start_screen_action__color +msgid "Choose the icon color" +msgstr "Escoja el color del icono" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__color +msgid "Color" +msgstr "Color" + +#. module: web_quick_start_screen +#: model:quick.start.screen.action,name:web_quick_start_screen.quick_start_screen_action_config_actions_demo +msgid "Configure screen actions" +msgstr "Configurar acciones de pantalla" + +#. module: web_quick_start_screen +#: model:quick.start.screen.action,name:web_quick_start_screen.quick_start_screen_action_contacts_demo +msgid "Contacts" +msgstr "Contactos" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__context +msgid "Context" +msgstr "Contexto" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__create_uid +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__create_date +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__create_date +msgid "Created on" +msgstr "Creado el" + +#. module: web_quick_start_screen +#: model:quick.start.screen,name:web_quick_start_screen.quick_start_screen_demo +msgid "Demo start screen" +msgstr "Pantalla de inicio demo" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__description +msgid "Description" +msgstr "Descripción" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__display_name +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__display_name +msgid "Display Name" +msgstr "Nombre mostrado" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__domain +msgid "Domain" +msgstr "Dominio" + +#. module: web_quick_start_screen +#: model_terms:ir.ui.view,arch_db:web_quick_start_screen.quick_start_screen_tree_view +msgid "Go to the start screen" +msgstr "Ir a la pantalla de inicio" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__id +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__id +msgid "ID" +msgstr "ID (identificación)" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__icon_name +msgid "Icon Name" +msgstr "Nombre del icono" + +#. module: web_quick_start_screen +#: model:ir.model.fields,help:web_quick_start_screen.field_quick_start_screen_action__icon_name +msgid "Just set the Font Awesome icon name. e.g.: fa-truck" +msgstr "" +"Tan solo establezca el nombre de icono de Font Awesome: p.e..: fa-truck" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen____last_update +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action____last_update +msgid "Last Modified on" +msgstr "Última modificación en" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__write_uid +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__write_uid +msgid "Last Updated by" +msgstr "Última actualización de" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__write_date +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__write_date +msgid "Last Updated on" +msgstr "Última actualización en" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__name +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__name +msgid "Name" +msgstr "Nombre" + +#. module: web_quick_start_screen +#: model:ir.actions.server,name:web_quick_start_screen.start_screen_action +#: model:ir.model.fields,field_description:web_quick_start_screen.field_res_users__quick_start_screen_id +#: model:res.groups,name:web_quick_start_screen.group_quick_start_screen +msgid "Quick Start Screen" +msgstr "Pantalla de inicio rápido" + +#. module: web_quick_start_screen +#: model:ir.actions.act_window,name:web_quick_start_screen.quick_start_screen_action_action +#: model:ir.ui.menu,name:web_quick_start_screen.menu_quick_start_screen_action +msgid "Quick Start Screen Actions" +msgstr "Acciones de pantalla de inicio rápido" + +#. module: web_quick_start_screen +#: model:ir.actions.act_window,name:web_quick_start_screen.start_screen_action_config +#: model:ir.ui.menu,name:web_quick_start_screen.menu_quick_start_screen_action_config +msgid "Quick Start Screens" +msgstr "Pantallas de inicio rápido" + +#. module: web_quick_start_screen +#: model:ir.model,name:web_quick_start_screen.model_quick_start_screen +msgid "Quick action selection screen" +msgstr "Pantalla de selección rápida de acciones" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__sequence +msgid "Sequence" +msgstr "Secuencia" + +#. module: web_quick_start_screen +#. odoo-python +#: code:addons/web_quick_start_screen/models/quick_start_screen.py:0 +#: model:ir.ui.menu,name:web_quick_start_screen.menu_start +#: model:ir.ui.menu,name:web_quick_start_screen.menu_start_screen +#, python-format +msgid "Start" +msgstr "Inicio" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__image +msgid "Start screen icon" +msgstr "Icono de pantalla de inicio" + +#. module: web_quick_start_screen +#: model:ir.model,name:web_quick_start_screen.model_res_users +msgid "User" +msgstr "Usuario" + +#. module: web_quick_start_screen +#: model:ir.model.fields.selection,name:web_quick_start_screen.selection__quick_start_screen_action__action_ref_id__ir_actions_act_url +msgid "ir.actions.act_url" +msgstr "ir.actions.act_url" + +#. module: web_quick_start_screen +#: model:ir.model.fields.selection,name:web_quick_start_screen.selection__quick_start_screen_action__action_ref_id__ir_actions_act_window +msgid "ir.actions.act_window" +msgstr "ir.actions.act_window" + +#. module: web_quick_start_screen +#: model:ir.model.fields.selection,name:web_quick_start_screen.selection__quick_start_screen_action__action_ref_id__ir_actions_client +msgid "ir.actions.client" +msgstr "ir.actions.client" + +#. module: web_quick_start_screen +#: model:ir.model.fields.selection,name:web_quick_start_screen.selection__quick_start_screen_action__action_ref_id__ir_actions_report +msgid "ir.actions.report" +msgstr "ir.actions.report" + +#. module: web_quick_start_screen +#: model:ir.model.fields.selection,name:web_quick_start_screen.selection__quick_start_screen_action__action_ref_id__ir_actions_server +msgid "ir.actions.server" +msgstr "ir.actions.server" diff --git a/web_quick_start_screen/i18n/it.po b/web_quick_start_screen/i18n/it.po new file mode 100644 index 000000000000..6c9be2b966ba --- /dev/null +++ b/web_quick_start_screen/i18n/it.po @@ -0,0 +1,248 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_quick_start_screen +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 19.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-04-15 14:30+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.10.4\n" + +#. module: web_quick_start_screen +#: model_terms:quick.start.screen.action,description:web_quick_start_screen.quick_start_screen_action_contacts_demo +msgid "Browse contacts" +msgstr "Sfogliacontatti" + +#. module: web_quick_start_screen +#: model_terms:quick.start.screen.action,description:web_quick_start_screen.quick_start_screen_action_config_actions_demo +msgid "Configure this screen actions" +msgstr "Configura queste azioni schermata" + +#. module: web_quick_start_screen +#: model_terms:quick.start.screen.action,description:web_quick_start_screen.quick_start_screen_action_access_rights_demo +msgid "Explore access rights" +msgstr "Esplora diritti di accesso" + +#. module: web_quick_start_screen +#: model:quick.start.screen.action,name:web_quick_start_screen.quick_start_screen_action_access_rights_demo +msgid "Access rights" +msgstr "Diritti di accesso" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__action_ids +msgid "Action" +msgstr "Azione" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__action_ref_id +msgid "Action Ref" +msgstr "Rif. azione" + +#. module: web_quick_start_screen +#: model:ir.model,name:web_quick_start_screen.model_quick_start_screen_action +msgid "Actions to be launched from a quick start screen" +msgstr "Azioni da lanciare da una schermata di avvio rapido" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__active +msgid "Active" +msgstr "Attiva" + +#. module: web_quick_start_screen +#: model:ir.model.fields,help:web_quick_start_screen.field_quick_start_screen_action__context +msgid "" +"Add extra context if needed. You can use `ref('')` and it will " +"beevaluated. You can also use `datetime` and `context_today` in the same " +"way`ir.filters` do." +msgstr "" +"Aggiungere contesto aggiuntivo se necessario. Si può usare `ref('')` " +"e verrà valutato. Si può anche usare `datetime` e `context_today` allo " +"stesso modo di `ir.filters`." + +#. module: web_quick_start_screen +#: model:ir.model.fields,help:web_quick_start_screen.field_quick_start_screen_action__domain +msgid "" +"Add extra domain if needed. You can use `ref('')` and it will " +"beevaluated. You can also use `datetime` and `context_today` in the same " +"way`ir.filters` do." +msgstr "" +"Aggiungere dominio aggiuntivo se necessario. Si può usare `ref('')` " +"e verrà valutato. Si può anche usare `datetime` e `context_today` allo " +"stesso modo di `ir.filters`." + +#. module: web_quick_start_screen +#: model:ir.model.fields,help:web_quick_start_screen.field_quick_start_screen_action__color +msgid "Choose the icon color" +msgstr "Scegli il colore icona" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__color +msgid "Color" +msgstr "Colore" + +#. module: web_quick_start_screen +#: model:quick.start.screen.action,name:web_quick_start_screen.quick_start_screen_action_config_actions_demo +msgid "Configure screen actions" +msgstr "Configura azioni schermata" + +#. module: web_quick_start_screen +#: model:quick.start.screen.action,name:web_quick_start_screen.quick_start_screen_action_contacts_demo +msgid "Contacts" +msgstr "Contatti" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__context +msgid "Context" +msgstr "Contesto" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__create_uid +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__create_uid +msgid "Created by" +msgstr "Creato da" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__create_date +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__create_date +msgid "Created on" +msgstr "Creato il" + +#. module: web_quick_start_screen +#: model:quick.start.screen,name:web_quick_start_screen.quick_start_screen_demo +msgid "Demo start screen" +msgstr "Schermata avvio demo" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__description +msgid "Description" +msgstr "Descrizione" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__display_name +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__domain +msgid "Domain" +msgstr "Dominio" + +#. module: web_quick_start_screen +#: model_terms:ir.ui.view,arch_db:web_quick_start_screen.quick_start_screen_list_view +msgid "Go to the start screen" +msgstr "Vai alla schermata di avvio" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__id +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__id +msgid "ID" +msgstr "ID" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__icon_name +msgid "Icon Name" +msgstr "Nome icona" + +#. module: web_quick_start_screen +#: model:ir.model.fields,help:web_quick_start_screen.field_quick_start_screen_action__icon_name +msgid "Just set the Font Awesome icon name. e.g.: fa-truck" +msgstr "Imposta solo il nome dell'icona Font Awesome. Es.: fa-truck" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__write_uid +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__write_uid +msgid "Last Updated by" +msgstr "Ultimo aggiornamento di" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__write_date +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__write_date +msgid "Last Updated on" +msgstr "Ultimo aggiornamento il" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__name +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__name +msgid "Name" +msgstr "Nome" + +#. module: web_quick_start_screen +#: model:ir.actions.server,name:web_quick_start_screen.start_screen_action +#: model:ir.model.fields,field_description:web_quick_start_screen.field_res_users__quick_start_screen_id +#: model:res.groups,name:web_quick_start_screen.group_quick_start_screen +msgid "Quick Start Screen" +msgstr "Schermata avvio rapido" + +#. module: web_quick_start_screen +#: model:ir.actions.act_window,name:web_quick_start_screen.quick_start_screen_action_action +#: model:ir.ui.menu,name:web_quick_start_screen.menu_quick_start_screen_action +msgid "Quick Start Screen Actions" +msgstr "Azioni schermata avvio rapido" + +#. module: web_quick_start_screen +#: model:ir.actions.act_window,name:web_quick_start_screen.start_screen_action_config +#: model:ir.ui.menu,name:web_quick_start_screen.menu_quick_start_screen_action_config +msgid "Quick Start Screens" +msgstr "Schermate avvio rapido" + +#. module: web_quick_start_screen +#: model:ir.model,name:web_quick_start_screen.model_quick_start_screen +msgid "Quick action selection screen" +msgstr "Schermata selezione azione rapida" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__sequence +msgid "Sequence" +msgstr "Sequenza" + +#. module: web_quick_start_screen +#. odoo-python +#: code:addons/web_quick_start_screen/models/quick_start_screen.py:0 +#: model:ir.ui.menu,name:web_quick_start_screen.menu_start +#: model:ir.ui.menu,name:web_quick_start_screen.menu_start_screen +msgid "Start" +msgstr "Avvio" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__image +msgid "Start screen icon" +msgstr "Icona avvio schermata" + +#. module: web_quick_start_screen +#: model:ir.model,name:web_quick_start_screen.model_res_users +msgid "User" +msgstr "Utente" + +#. module: web_quick_start_screen +#: model:ir.model.fields.selection,name:web_quick_start_screen.selection__quick_start_screen_action__action_ref_id__ir_actions_act_url +msgid "ir.actions.act_url" +msgstr "ir.actions.act_url" + +#. module: web_quick_start_screen +#: model:ir.model.fields.selection,name:web_quick_start_screen.selection__quick_start_screen_action__action_ref_id__ir_actions_act_window +msgid "ir.actions.act_window" +msgstr "ir.actions.act_window" + +#. module: web_quick_start_screen +#: model:ir.model.fields.selection,name:web_quick_start_screen.selection__quick_start_screen_action__action_ref_id__ir_actions_client +msgid "ir.actions.client" +msgstr "ir.actions.client" + +#. module: web_quick_start_screen +#: model:ir.model.fields.selection,name:web_quick_start_screen.selection__quick_start_screen_action__action_ref_id__ir_actions_report +msgid "ir.actions.report" +msgstr "ir.actions.report" + +#. module: web_quick_start_screen +#: model:ir.model.fields.selection,name:web_quick_start_screen.selection__quick_start_screen_action__action_ref_id__ir_actions_server +msgid "ir.actions.server" +msgstr "ir.actions.server" diff --git a/web_quick_start_screen/i18n/web_quick_start_screen.pot b/web_quick_start_screen/i18n/web_quick_start_screen.pot new file mode 100644 index 000000000000..1b43dd031a90 --- /dev/null +++ b/web_quick_start_screen/i18n/web_quick_start_screen.pot @@ -0,0 +1,239 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_quick_start_screen +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 19.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: web_quick_start_screen +#: model_terms:quick.start.screen.action,description:web_quick_start_screen.quick_start_screen_action_contacts_demo +msgid "Browse contacts" +msgstr "" + +#. module: web_quick_start_screen +#: model_terms:quick.start.screen.action,description:web_quick_start_screen.quick_start_screen_action_config_actions_demo +msgid "Configure this screen actions" +msgstr "" + +#. module: web_quick_start_screen +#: model_terms:quick.start.screen.action,description:web_quick_start_screen.quick_start_screen_action_access_rights_demo +msgid "Explore access rights" +msgstr "" + +#. module: web_quick_start_screen +#: model:quick.start.screen.action,name:web_quick_start_screen.quick_start_screen_action_access_rights_demo +msgid "Access rights" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__action_ids +msgid "Action" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__action_ref_id +msgid "Action Ref" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model,name:web_quick_start_screen.model_quick_start_screen_action +msgid "Actions to be launched from a quick start screen" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__active +msgid "Active" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields,help:web_quick_start_screen.field_quick_start_screen_action__context +msgid "" +"Add extra context if needed. You can use `ref('')` and it will " +"beevaluated. You can also use `datetime` and `context_today` in the same " +"way`ir.filters` do." +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields,help:web_quick_start_screen.field_quick_start_screen_action__domain +msgid "" +"Add extra domain if needed. You can use `ref('')` and it will " +"beevaluated. You can also use `datetime` and `context_today` in the same " +"way`ir.filters` do." +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields,help:web_quick_start_screen.field_quick_start_screen_action__color +msgid "Choose the icon color" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__color +msgid "Color" +msgstr "" + +#. module: web_quick_start_screen +#: model:quick.start.screen.action,name:web_quick_start_screen.quick_start_screen_action_config_actions_demo +msgid "Configure screen actions" +msgstr "" + +#. module: web_quick_start_screen +#: model:quick.start.screen.action,name:web_quick_start_screen.quick_start_screen_action_contacts_demo +msgid "Contacts" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__context +msgid "Context" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__create_uid +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__create_uid +msgid "Created by" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__create_date +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__create_date +msgid "Created on" +msgstr "" + +#. module: web_quick_start_screen +#: model:quick.start.screen,name:web_quick_start_screen.quick_start_screen_demo +msgid "Demo start screen" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__description +msgid "Description" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__display_name +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__display_name +msgid "Display Name" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__domain +msgid "Domain" +msgstr "" + +#. module: web_quick_start_screen +#: model_terms:ir.ui.view,arch_db:web_quick_start_screen.quick_start_screen_list_view +msgid "Go to the start screen" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__id +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__id +msgid "ID" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__icon_name +msgid "Icon Name" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields,help:web_quick_start_screen.field_quick_start_screen_action__icon_name +msgid "Just set the Font Awesome icon name. e.g.: fa-truck" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__write_uid +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__write_date +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__write_date +msgid "Last Updated on" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen__name +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__name +msgid "Name" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.actions.server,name:web_quick_start_screen.start_screen_action +#: model:ir.model.fields,field_description:web_quick_start_screen.field_res_users__quick_start_screen_id +#: model:res.groups,name:web_quick_start_screen.group_quick_start_screen +msgid "Quick Start Screen" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.actions.act_window,name:web_quick_start_screen.quick_start_screen_action_action +#: model:ir.ui.menu,name:web_quick_start_screen.menu_quick_start_screen_action +msgid "Quick Start Screen Actions" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.actions.act_window,name:web_quick_start_screen.start_screen_action_config +#: model:ir.ui.menu,name:web_quick_start_screen.menu_quick_start_screen_action_config +msgid "Quick Start Screens" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model,name:web_quick_start_screen.model_quick_start_screen +msgid "Quick action selection screen" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__sequence +msgid "Sequence" +msgstr "" + +#. module: web_quick_start_screen +#. odoo-python +#: code:addons/web_quick_start_screen/models/quick_start_screen.py:0 +#: model:ir.ui.menu,name:web_quick_start_screen.menu_start +#: model:ir.ui.menu,name:web_quick_start_screen.menu_start_screen +msgid "Start" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields,field_description:web_quick_start_screen.field_quick_start_screen_action__image +msgid "Start screen icon" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model,name:web_quick_start_screen.model_res_users +msgid "User" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields.selection,name:web_quick_start_screen.selection__quick_start_screen_action__action_ref_id__ir_actions_act_url +msgid "ir.actions.act_url" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields.selection,name:web_quick_start_screen.selection__quick_start_screen_action__action_ref_id__ir_actions_act_window +msgid "ir.actions.act_window" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields.selection,name:web_quick_start_screen.selection__quick_start_screen_action__action_ref_id__ir_actions_client +msgid "ir.actions.client" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields.selection,name:web_quick_start_screen.selection__quick_start_screen_action__action_ref_id__ir_actions_report +msgid "ir.actions.report" +msgstr "" + +#. module: web_quick_start_screen +#: model:ir.model.fields.selection,name:web_quick_start_screen.selection__quick_start_screen_action__action_ref_id__ir_actions_server +msgid "ir.actions.server" +msgstr "" diff --git a/web_quick_start_screen/models/__init__.py b/web_quick_start_screen/models/__init__.py new file mode 100644 index 000000000000..778d6b620af3 --- /dev/null +++ b/web_quick_start_screen/models/__init__.py @@ -0,0 +1,3 @@ +from . import quick_start_screen +from . import quick_start_screen_action +from . import res_users diff --git a/web_quick_start_screen/models/quick_start_screen.py b/web_quick_start_screen/models/quick_start_screen.py new file mode 100644 index 000000000000..4667e9ed2e43 --- /dev/null +++ b/web_quick_start_screen/models/quick_start_screen.py @@ -0,0 +1,68 @@ +# Copyright 2024 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from collections import defaultdict + +from odoo import api, fields, models, tools + + +class QuicktStartScreen(models.Model): + _name = "quick.start.screen" + _description = "Quick action selection screen" + + name = fields.Char(translate=True) + action_ids = fields.Many2many(comodel_name="quick.start.screen.action") + + @api.model + @tools.ormcache("frozenset(self.env.user.group_ids.ids)") + def _visible_action_ids(self): + """Inspired on how menus visibility work in core""" + screen_actions = self.action_ids.search([]).sudo() # pylint: disable=no-search-all + visible = self.action_ids.browse() + access = self.env["ir.model.access"] + MODEL_BY_TYPE = { + "ir.actions.act_window": "res_model", + "ir.actions.report": "model", + "ir.actions.server": "model_name", + } + # performance trick: determine the ids to prefetch by type + prefetch_ids = defaultdict(list) + for action in screen_actions.mapped("action_ref_id"): + prefetch_ids[action._name].append(action.id) + for screen_action in screen_actions: + action = screen_action.action_ref_id + action = action.with_prefetch(prefetch_ids[action._name]) + model_name = ( + action._name in MODEL_BY_TYPE and action[MODEL_BY_TYPE[action._name]] + ) + if not model_name or access.check(model_name, "read", False): + visible += screen_action + return set(visible.ids) + + def _prepare_screen_action(self): + return { + "display_name": self.name or self.env._("Start"), + "name": self.name or self.env._("Start"), + "res_model": "quick.start.screen.action", + "target": "current", + "type": "ir.actions.act_window", + "view_mode": "kanban", + "views": [ + [ + self.env.ref( + "web_quick_start_screen.quick_start_screen_action_kanban" + ).id, + "kanban", + ] + ], + } + + def action_screen_actions(self): + """Normally called from a server action""" + if not self: + self = self.env.user.quick_start_screen_id + if not self: + self = self.browse(self.env.context.get("default_quick_start_screen_id")) + action = self._prepare_screen_action() + visible_actions = set(self.action_ids.ids) & self._visible_action_ids() + action["domain"] = [("id", "in", list(visible_actions))] + return action diff --git a/web_quick_start_screen/models/quick_start_screen_action.py b/web_quick_start_screen/models/quick_start_screen_action.py new file mode 100644 index 000000000000..d44a5f37def1 --- /dev/null +++ b/web_quick_start_screen/models/quick_start_screen_action.py @@ -0,0 +1,74 @@ +# Copyright 2024 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from odoo import fields, models +from odoo.tools.safe_eval import datetime, safe_eval + + +class DecontracStartScreenAction(models.Model): + _name = "quick.start.screen.action" + _description = "Actions to be launched from a quick start screen" + _order = "sequence, id" + + active = fields.Boolean(default=True) + sequence = fields.Integer() + name = fields.Char(required=True, translate=True) + image = fields.Image("Start screen icon", max_width=128, max_height=128, store=True) + icon_name = fields.Char(help="Just set the Font Awesome icon name. e.g.: fa-truck") + color = fields.Integer(help="Choose the icon color") + description = fields.Html(translate=True) + action_ref_id = fields.Reference( + selection=[ + ("ir.actions.report", "ir.actions.report"), + ("ir.actions.act_window", "ir.actions.act_window"), + ("ir.actions.act_url", "ir.actions.act_url"), + ("ir.actions.server", "ir.actions.server"), + ("ir.actions.client", "ir.actions.client"), + ], + required=True, + ) + domain = fields.Char( + help="Add extra domain if needed. You can use `ref('')` and it will be " + "evaluated. You can also use `datetime` and `context_today` in the same way" + "`ir.filters` do." + ) + context = fields.Char( + help="Add extra context if needed. You can use `ref('')` and it will be" + "evaluated. You can also use `datetime` and `context_today` in the same way" + "`ir.filters` do." + ) + + def _safe_eval(self, expresion): + return safe_eval( + expresion, + { + "ref": lambda r: self.env.ref(r).id, + "datetime": datetime, + "context_today": datetime.datetime.now, + }, + ) + + def _get_extra_context(self): + self.ensure_one() + return self._safe_eval(self.context or "{}") + + def run_action(self): + """Execute the action. We can override the action context if needed""" + self.ensure_one() + action = self.action_ref_id._get_action_dict() + if self.context: + extra_context = self._get_extra_context() + # We need to deal with the active_id and overwrite it if needed + # MIG TODO: Check if this is affected + active_id = extra_context.get("active_id", 0) + action_ctx = action.get("context", "{}") + if isinstance(action_ctx, str): + action_ctx = safe_eval(action_ctx, {"active_id": active_id}) + elif not isinstance(action_ctx, dict): + action_ctx = {} + action["context"] = dict( + action_ctx, + **extra_context, + ) + if self.domain: + action["domain"] = self._safe_eval(self.domain) + return action diff --git a/web_quick_start_screen/models/res_users.py b/web_quick_start_screen/models/res_users.py new file mode 100644 index 000000000000..0632d0a2b107 --- /dev/null +++ b/web_quick_start_screen/models/res_users.py @@ -0,0 +1,9 @@ +# Copyright 2024 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from odoo import fields, models + + +class ResUsers(models.Model): + _inherit = "res.users" + + quick_start_screen_id = fields.Many2one(comodel_name="quick.start.screen") diff --git a/web_quick_start_screen/pyproject.toml b/web_quick_start_screen/pyproject.toml new file mode 100644 index 000000000000..4231d0cccb3d --- /dev/null +++ b/web_quick_start_screen/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/web_quick_start_screen/readme/CONFIGURE.md b/web_quick_start_screen/readme/CONFIGURE.md new file mode 100644 index 000000000000..0f44803ba51d --- /dev/null +++ b/web_quick_start_screen/readme/CONFIGURE.md @@ -0,0 +1,27 @@ +To create quick actions: + +- Go to *Settings > Technical > User Interface > Screen actions* and create o modify an + existing one. +- Choose the desired action, a name, a description and an icon. +- You can add an optional context so you can reuse existing actions. You can use + `ref()` to get an id that you can use in your context. You can also use + `datetime` and `context_today` in that same way you can do in `ir.filters`. + +To create quick start screens: + +- Go to *Settings > Technical > User Interface > Quick start screens* and create or + modify an existing one. +- Choose a descriptive name and link some quick screen actions. + +To assign a quick start screen to a user: + +- Go to *Settings > Users and groups > Users* and select one. +- In the *Preferences* tab, *Menus customization* section, you can choose which + *Quick start screen* will that user use. +- If you want to make the user start always in his start screen, in the same section + select the action *Quick Start Screen*. + +To activate the quick start screen menu for a user: + +- Go to *Settings > Users and groups > Users* (with debug mode on) +- In *Technical* groups, set *Quick Start Screen* on. diff --git a/web_quick_start_screen/readme/CONTEXT.md b/web_quick_start_screen/readme/CONTEXT.md new file mode 100644 index 000000000000..e1dadc6d5cba --- /dev/null +++ b/web_quick_start_screen/readme/CONTEXT.md @@ -0,0 +1,2 @@ +Some users use repeatedly the same actions on and on and sometimes those actions are +so many clicks away which tends to be frustrating. diff --git a/web_quick_start_screen/readme/CONTRIBUTORS.md b/web_quick_start_screen/readme/CONTRIBUTORS.md new file mode 100644 index 000000000000..649292fb7bfc --- /dev/null +++ b/web_quick_start_screen/readme/CONTRIBUTORS.md @@ -0,0 +1,3 @@ +- [Tecnativa](https://tecnativa.com) + - Pedro M. Baeza + - David Vidal diff --git a/web_quick_start_screen/readme/DESCRIPTION.md b/web_quick_start_screen/readme/DESCRIPTION.md new file mode 100644 index 000000000000..ec1608d2917d --- /dev/null +++ b/web_quick_start_screen/readme/DESCRIPTION.md @@ -0,0 +1,4 @@ +This module adds a configurable start screen so users can go right into their more +common tasks. + +It can be configured at the user level or just be used as common screens. diff --git a/web_quick_start_screen/readme/ROADMAP.md b/web_quick_start_screen/readme/ROADMAP.md new file mode 100644 index 000000000000..cda0b2a6e82f --- /dev/null +++ b/web_quick_start_screen/readme/ROADMAP.md @@ -0,0 +1,6 @@ +- Right now there's no much permissions handling, but it could be made similarly to how + menus deal with them. +- Also we could add the possibility of quick actions for users the same way that + favorite filters work. +- A tour helper that clicked in every defined action would be helpfull to detect + possible issues. diff --git a/web_quick_start_screen/readme/USAGE.md b/web_quick_start_screen/readme/USAGE.md new file mode 100644 index 000000000000..d03757e244ec --- /dev/null +++ b/web_quick_start_screen/readme/USAGE.md @@ -0,0 +1,2 @@ +When you have the proper config, once you login, you'll go to the quick actions +screen. Just click in and start working. diff --git a/web_quick_start_screen/security/ir.model.access.csv b/web_quick_start_screen/security/ir.model.access.csv new file mode 100644 index 000000000000..9613ba4f55ae --- /dev/null +++ b/web_quick_start_screen/security/ir.model.access.csv @@ -0,0 +1,5 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +web_quick_start_screen.access_start_screen,access_quick_start_screen,web_quick_start_screen.model_quick_start_screen,base.group_user,1,1,0,0 +web_quick_start_screen.access_quick_start_screen_action,access_quick_start_screen_action,web_quick_start_screen.model_quick_start_screen_action,base.group_user,1,1,0,0 +web_quick_start_screen.access_start_screen_admin,access_quick_start_screen_admin,web_quick_start_screen.model_quick_start_screen,base.group_system,1,1,1,1 +web_quick_start_screen.access_quick_start_screen_action_admin,access_quick_start_screen_action_admin,web_quick_start_screen.model_quick_start_screen_action,base.group_system,1,1,1,1 diff --git a/web_quick_start_screen/security/security.xml b/web_quick_start_screen/security/security.xml new file mode 100644 index 000000000000..c4f1818d85fe --- /dev/null +++ b/web_quick_start_screen/security/security.xml @@ -0,0 +1,6 @@ + + + + Quick Start Screen + + diff --git a/web_quick_start_screen/static/description/icon.png b/web_quick_start_screen/static/description/icon.png new file mode 100644 index 000000000000..6600373f3d44 Binary files /dev/null and b/web_quick_start_screen/static/description/icon.png differ diff --git a/web_quick_start_screen/static/description/icon.svg b/web_quick_start_screen/static/description/icon.svg new file mode 100644 index 000000000000..4b855791ed90 --- /dev/null +++ b/web_quick_start_screen/static/description/icon.svg @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + diff --git a/web_quick_start_screen/static/description/index.html b/web_quick_start_screen/static/description/index.html new file mode 100644 index 000000000000..d15f61e24df8 --- /dev/null +++ b/web_quick_start_screen/static/description/index.html @@ -0,0 +1,493 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Quick Start Screen

+ +

Beta License: AGPL-3 OCA/web Translate me on Weblate Try me on Runboat

+

This module adds a configurable start screen so users can go right into +their more common tasks.

+

It can be configured at the user level or just be used as common +screens.

+

Table of contents

+ +
+

Use Cases / Context

+

Some users use repeatedly the same actions on and on and sometimes those +actions are so many clicks away which tends to be frustrating.

+
+
+

Configuration

+

To create quick actions:

+
    +
  • Go to Settings > Technical > User Interface > Screen actions and +create o modify an existing one.
  • +
  • Choose the desired action, a name, a description and an icon.
  • +
  • You can add an optional context so you can reuse existing actions. You +can use ref(<xml_id>) to get an id that you can use in your +context. You can also use datetime and context_today in that +same way you can do in ir.filters.
  • +
+

To create quick start screens:

+
    +
  • Go to Settings > Technical > User Interface > Quick start screens +and create or modify an existing one.
  • +
  • Choose a descriptive name and link some quick screen actions.
  • +
+

To assign a quick start screen to a user:

+
    +
  • Go to Settings > Users and groups > Users and select one.
  • +
  • In the Preferences tab, Menus customization section, you can +choose which Quick start screen will that user use.
  • +
  • If you want to make the user start always in his start screen, in the +same section select the action Quick Start Screen.
  • +
+

To activate the quick start screen menu for a user:

+
    +
  • Go to Settings > Users and groups > Users (with debug mode on)
  • +
  • In Technical groups, set Quick Start Screen on.
  • +
+
+
+

Usage

+

When you have the proper config, once you login, you’ll go to the quick +actions screen. Just click in and start working.

+
+
+

Known issues / Roadmap

+
    +
  • Right now there’s no much permissions handling, but it could be made +similarly to how menus deal with them.
  • +
  • Also we could add the possibility of quick actions for users the same +way that favorite filters work.
  • +
  • A tour helper that clicked in every defined action would be helpfull +to detect possible issues.
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Tecnativa
  • +
+
+
+

Contributors

+
    +
  • Tecnativa
      +
    • Pedro M. Baeza
    • +
    • David Vidal
    • +
    +
  • +
+
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/web project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+
+ + diff --git a/web_quick_start_screen/static/src/js/kanban_controller.esm.js b/web_quick_start_screen/static/src/js/kanban_controller.esm.js new file mode 100644 index 000000000000..ebba83b783b1 --- /dev/null +++ b/web_quick_start_screen/static/src/js/kanban_controller.esm.js @@ -0,0 +1,15 @@ +/* Copyright 2024 Tecnativa - David Vidal + * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */ +import {ControlPanel} from "@web/search/control_panel/control_panel"; +import {kanbanView} from "@web/views/kanban/kanban_view"; +import {registry} from "@web/core/registry"; + +export class QuickStartScreenControlPanel extends ControlPanel { + static template = "start_screen.ControlPanel"; +} + +export const quickStartScreenView = { + ...kanbanView, + ControlPanel: QuickStartScreenControlPanel, +}; +registry.category("views").add("quick_start_screen", quickStartScreenView); diff --git a/web_quick_start_screen/static/src/js/start_screen_control_panel.xml b/web_quick_start_screen/static/src/js/start_screen_control_panel.xml new file mode 100644 index 000000000000..ef786a1ecc05 --- /dev/null +++ b/web_quick_start_screen/static/src/js/start_screen_control_panel.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/web_quick_start_screen/static/src/scss/quick_start_screen.scss b/web_quick_start_screen/static/src/scss/quick_start_screen.scss new file mode 100644 index 000000000000..52654cc46e97 --- /dev/null +++ b/web_quick_start_screen/static/src/scss/quick_start_screen.scss @@ -0,0 +1,6 @@ +// Set all the colors but the "no-color" one +@for $size from 2 through length($o-colors) { + .o_start_icon_color_#{$size - 1} { + color: nth($o-colors, $size); + } +} diff --git a/web_quick_start_screen/tests/__init__.py b/web_quick_start_screen/tests/__init__.py new file mode 100644 index 000000000000..b6c3f9d863b9 --- /dev/null +++ b/web_quick_start_screen/tests/__init__.py @@ -0,0 +1,2 @@ +from . import test_web_quick_start_screen_common +from . import test_web_quick_start_screen diff --git a/web_quick_start_screen/tests/test_web_quick_start_screen.py b/web_quick_start_screen/tests/test_web_quick_start_screen.py new file mode 100644 index 000000000000..a490b9223407 --- /dev/null +++ b/web_quick_start_screen/tests/test_web_quick_start_screen.py @@ -0,0 +1,422 @@ +# Copyright 2024 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from unittest.mock import patch + +from odoo import Command + +from .test_web_quick_start_screen_common import WebQuickStartScreenCommon + + +class TestQuickStartActionsCommon(WebQuickStartScreenCommon): + def _test_screen_action(self, screen_action): + """Basic test helper. For a more complete one we'd need a tour""" + action = screen_action.run_action() + if action["type"] == "ir.actions.server": + action = ( + self.env.ref(action["xml_id"]) + .with_context(**screen_action._get_extra_context()) + .run() + ) + return action + + +class TestQuickStartActions(TestQuickStartActionsCommon): + def test_demo_screen_actions(self): + """Let's test every action screen in our demo data""" + for action in self.start_screen_1.action_ids: + self._test_screen_action(action) + + def test_screen_action_server(self): + """Test _test_screen_action with a server action to cover lines 14-15""" + server_action = self.env["ir.actions.server"].create( + { + "name": "Test Server Action", + "model_id": self.env["ir.model"]._get_id("res.partner"), + "state": "code", + "code": "action = {'type': 'ir.actions.act_window_close'}", + } + ) + self.env["ir.model.data"].create( + { + "name": "test_server_action", + "module": "web_quick_start_screen", + "model": "ir.actions.server", + "res_id": server_action.id, + } + ) + action_server = self.env["quick.start.screen.action"].create( + { + "name": "Server Action", + "action_ref_id": f"ir.actions.server,{server_action.id}", + } + ) + res = self._test_screen_action(action_server) + self.assertEqual(res.get("type"), "ir.actions.act_window_close") + + +class TestQuickStartScreenVisibility(WebQuickStartScreenCommon): + """Tests for _visible_action_ids covering access-check branches""" + + def test_visible_action_ids_with_model(self): + """Actions with an act_window ref should appear when user has read access""" + visible = self.start_screen_1._visible_action_ids() + self.assertIn(self.quick_start_screen_action_1.id, visible) + self.assertIn(self.quick_start_screen_action_2.id, visible) + + def test_visible_action_ids_no_model_access(self): + """Actions whose model has no read access should be excluded""" + # Clear ormcache so the body executes fresh under the mock + self.env.registry.clear_cache() + # Patch ir.model.access.check to deny access + with patch.object( + type(self.env["ir.model.access"]), + "check", + return_value=False, + ): + visible = self.start_screen_1._visible_action_ids() + # Since check returns False, act_window actions should be excluded + self.assertNotIn(self.quick_start_screen_action_1.id, visible) + + def test_visible_action_ids_with_report_action(self): + """ir.actions.report (model field) is included when user has read access""" + report_action = self.env["ir.actions.report"].create( + { + "name": "Dummy Report", + "model": "res.partner", + "report_name": "dummy.report", + } + ) + action_report = self.env["quick.start.screen.action"].create( + { + "name": "Report Visibility", + "action_ref_id": f"ir.actions.report,{report_action.id}", + } + ) + screen = self.env["quick.start.screen"].create( + { + "name": "Report Screen", + "action_ids": [Command.link(action_report.id)], + } + ) + visible = screen._visible_action_ids() + self.assertIn(action_report.id, visible) + + def test_visible_action_ids_with_server_action(self): + """ir.actions.server (model_name field) is included when user has read access""" + model_id = ( + self.env["ir.model"].search([("model", "=", "res.partner")], limit=1).id + ) + server_action = self.env["ir.actions.server"].create( + { + "name": "Visibility Server Action", + "model_id": model_id, + "state": "code", + "code": "action = {'type': 'ir.actions.act_window_close'}", + } + ) + action_server = self.env["quick.start.screen.action"].create( + { + "name": "Server Visibility", + "action_ref_id": f"ir.actions.server,{server_action.id}", + } + ) + screen = self.env["quick.start.screen"].create( + { + "name": "Server Screen", + "action_ids": [Command.link(action_server.id)], + } + ) + visible = screen._visible_action_ids() + self.assertIn(action_server.id, visible) + + def test_visible_action_ids_action_without_model(self): + """Actions whose action type has no associated model field (e.g. act_url) + should always be visible regardless of access check""" + act_url = self.env["ir.actions.act_url"].create( + {"name": "Test URL", "url": "https://odoo.com", "target": "new"} + ) + action_url = self.env["quick.start.screen.action"].create( + { + "name": "URL Action", + "action_ref_id": f"ir.actions.act_url,{act_url.id}", + } + ) + screen = self.env["quick.start.screen"].create( + { + "name": "URL Screen", + "action_ids": [Command.link(action_url.id)], + } + ) + visible = screen._visible_action_ids() + self.assertIn(action_url.id, visible) + + def test_visible_action_ids_with_client_action(self): + """ir.actions.client has no model field, so it should always be visible""" + act_client = self.env["ir.actions.client"].create( + {"name": "Test Client Action", "tag": "test_tag"} + ) + action_client = self.env["quick.start.screen.action"].create( + { + "name": "Client Action", + "action_ref_id": f"ir.actions.client,{act_client.id}", + } + ) + screen = self.env["quick.start.screen"].create( + { + "name": "Client Screen", + "action_ids": [Command.link(action_client.id)], + } + ) + visible = screen._visible_action_ids() + self.assertIn(action_client.id, visible) + + +class TestQuickStartScreenAction(WebQuickStartScreenCommon): + """Tests for action_screen_actions covering all self-resolution branches""" + + def test_action_screen_actions_with_self(self): + """Calling on a concrete record returns the kanban action""" + action = self.start_screen_1.action_screen_actions() + self.assertEqual(action["type"], "ir.actions.act_window") + self.assertEqual(action["view_mode"], "kanban") + self.assertEqual(action["res_model"], "quick.start.screen.action") + + def test_action_screen_actions_uses_user_screen_when_empty(self): + """Calling on an empty set falls back to the user's quick_start_screen_id""" + self.env.user.quick_start_screen_id = self.start_screen_1 + empty = self.env["quick.start.screen"].browse([]) + action = empty.action_screen_actions() + self.assertEqual(action["type"], "ir.actions.act_window") + + def test_action_screen_actions_uses_context_default_when_no_user_screen(self): + """When user has no screen, + falls back to default_quick_start_screen_id in context""" + self.env.user.quick_start_screen_id = False + empty = self.env["quick.start.screen"].browse([]) + action = empty.with_context( + default_quick_start_screen_id=self.start_screen_1.id + ).action_screen_actions() + self.assertEqual(action["type"], "ir.actions.act_window") + + def test_action_screen_actions_name_fallback(self): + """Screen without a name uses 'Start' as display/action name""" + unnamed_screen = self.env["quick.start.screen"].create( + { + "action_ids": [ + Command.link(self.quick_start_screen_action_1.id), + ], + } + ) + action = unnamed_screen.action_screen_actions() + self.assertEqual(action["name"], self.env._("Start")) + + def test_action_screen_actions_with_name(self): + """Screen with a name propagates it to the action""" + action = self.start_screen_1.action_screen_actions() + self.assertEqual(action["name"], "start_screen_1") + + def test_action_screen_actions_domain_filters_invisible(self): + """Domain in the returned action only includes visible action ids""" + visible_ids = self.start_screen_1._visible_action_ids() + action = self.start_screen_1.action_screen_actions() + domain = action["domain"] + # domain is [("id", "in", [...])] + filtered_ids = set(domain[0][2]) + # All returned ids must be in the visible set + self.assertTrue(filtered_ids.issubset(visible_ids)) + + def test_action_screen_actions_empty_with_no_fallback(self): + """When called on empty set with no user screen and no context default, + _prepare_screen_action is still called (self becomes empty browse)""" + self.env.user.quick_start_screen_id = False + empty = self.env["quick.start.screen"].browse([]) + # browse([]) resolves to empty; _prepare_screen_action runs with no name + action = empty.action_screen_actions() + self.assertEqual(action["type"], "ir.actions.act_window") + self.assertEqual(action["name"], self.env._("Start")) + + +class TestQuickStartScreenActionModel(WebQuickStartScreenCommon): + """Tests for quick.start.screen.action methods""" + + def _make_server_action(self): + """Helper: create a simple server action""" + return self.env["ir.actions.server"].create( + { + "name": "Test Server Action", + "model_id": self.env["ir.model"] + .search([("model", "=", "res.partner")], limit=1) + .id, + "state": "code", + "code": "action = {'type': 'ir.actions.act_window_close'}", + } + ) + + def test_run_action_without_context_or_domain(self): + """run_action without extra context/domain returns raw action dict""" + action = self.quick_start_screen_action_1.run_action() + self.assertIsInstance(action, dict) + self.assertIn("type", action) + + def test_run_action_with_extra_context(self): + """run_action merges extra context into the action""" + self.quick_start_screen_action_1.write( + {"context": "{'search_default_customer': 1}"} + ) + action = self.quick_start_screen_action_1.run_action() + self.assertEqual(action["context"].get("search_default_customer"), 1) + + def test_run_action_with_context_active_id(self): + """run_action handles active_id in extra context correctly""" + self.quick_start_screen_action_1.write( + {"context": "{'active_id': 42, 'my_flag': True}"} + ) + action = self.quick_start_screen_action_1.run_action() + self.assertTrue(action["context"].get("my_flag")) + + def test_run_action_with_domain(self): + """run_action applies extra domain from the domain field""" + self.quick_start_screen_action_1.write( + {"domain": "[('is_company', '=', True)]"} + ) + action = self.quick_start_screen_action_1.run_action() + self.assertIn(("is_company", "=", True), action["domain"]) + + def test_run_action_with_domain_and_context(self): + """run_action applies both extra domain and context""" + self.quick_start_screen_action_1.write( + { + "domain": "[('is_company', '=', True)]", + "context": "{'search_default_customer': 1}", + } + ) + action = self.quick_start_screen_action_1.run_action() + self.assertIn(("is_company", "=", True), action["domain"]) + self.assertEqual(action["context"].get("search_default_customer"), 1) + + def test_get_extra_context_empty(self): + """_get_extra_context returns {} when context field is empty""" + ctx = self.quick_start_screen_action_1._get_extra_context() + self.assertEqual(ctx, {}) + + def test_get_extra_context_with_value(self): + """_get_extra_context evaluates and returns the context dict""" + self.quick_start_screen_action_1.write({"context": "{'key': 'val'}"}) + ctx = self.quick_start_screen_action_1._get_extra_context() + self.assertEqual(ctx.get("key"), "val") + + def test_safe_eval_with_ref(self): + """_safe_eval supports ref() calls""" + partner_action_id = self.env.ref("base.action_partner_form").id + result = self.quick_start_screen_action_1._safe_eval( + "ref('base.action_partner_form')" + ) + self.assertEqual(result, partner_action_id) + + def test_safe_eval_with_datetime(self): + """_safe_eval exposes the datetime module""" + result = self.quick_start_screen_action_1._safe_eval( + "datetime.date(2024, 1, 1)" + ) + import datetime as dt + + self.assertEqual(result, dt.date(2024, 1, 1)) + + def test_safe_eval_with_context_today(self): + """_safe_eval exposes context_today callable""" + result = self.quick_start_screen_action_1._safe_eval("context_today()") + self.assertIsNotNone(result) + + def test_run_action_with_server_action(self): + """run_action works for an ir.actions.server reference""" + server_action = self._make_server_action() + action_rec = self.env["quick.start.screen.action"].create( + { + "name": "Server Action", + "action_ref_id": f"ir.actions.server,{server_action.id}", + } + ) + action = action_rec.run_action() + self.assertIn("type", action) + + def test_run_action_with_report_action(self): + """run_action works for an ir.actions.report reference""" + report_action = self.env["ir.actions.report"].create( + { + "name": "Dummy Report", + "model": "res.partner", + "report_name": "dummy.report", + } + ) + action_rec = self.env["quick.start.screen.action"].create( + { + "name": "Report Action", + "action_ref_id": f"ir.actions.report,{report_action.id}", + } + ) + action = action_rec.run_action() + self.assertIn("type", action) + + def test_run_action_with_url_action(self): + """run_action works for an ir.actions.act_url reference""" + url_action = self.env["ir.actions.act_url"].create( + { + "name": "Test URL", + "url": "https://odoo.com", + "target": "new", + } + ) + action_rec = self.env["quick.start.screen.action"].create( + { + "name": "URL Action", + "action_ref_id": f"ir.actions.act_url,{url_action.id}", + } + ) + action = action_rec.run_action() + self.assertEqual(action.get("type"), "ir.actions.act_url") + + def test_run_action_with_client_action(self): + """run_action works for an ir.actions.client reference""" + client_action = self.env["ir.actions.client"].create( + { + "name": "Test Client", + "tag": "test_tag", + } + ) + action_rec = self.env["quick.start.screen.action"].create( + { + "name": "Client Action", + "action_ref_id": f"ir.actions.client,{client_action.id}", + } + ) + action = action_rec.run_action() + self.assertEqual(action.get("type"), "ir.actions.client") + + def test_run_action_with_dict_context(self): + """run_action handles action context that is already a dict (Odoo 19+)""" + with patch.object( + type(self.quick_start_screen_action_1.action_ref_id), + "_get_action_dict", + return_value={"type": "ir.actions.act_window", "context": {"existing": 1}}, + ): + self.quick_start_screen_action_1.write({"context": "{'extra': 2}"}) + action = self.quick_start_screen_action_1.run_action() + self.assertEqual(action["context"].get("existing"), 1) + self.assertEqual(action["context"].get("extra"), 2) + + +class TestResUsers(WebQuickStartScreenCommon): + """Tests for the res.users extension""" + + def test_user_quick_start_screen_field_exists(self): + """quick_start_screen_id field is accessible on res.users""" + user = self.env.user + # Field should exist and be assignable + user.quick_start_screen_id = self.start_screen_1 + self.assertEqual(user.quick_start_screen_id, self.start_screen_1) + + def test_user_quick_start_screen_field_can_be_unset(self): + """quick_start_screen_id can be cleared""" + self.env.user.quick_start_screen_id = self.start_screen_1 + self.env.user.quick_start_screen_id = False + self.assertFalse(self.env.user.quick_start_screen_id) diff --git a/web_quick_start_screen/tests/test_web_quick_start_screen_common.py b/web_quick_start_screen/tests/test_web_quick_start_screen_common.py new file mode 100644 index 000000000000..624399d516e1 --- /dev/null +++ b/web_quick_start_screen/tests/test_web_quick_start_screen_common.py @@ -0,0 +1,41 @@ +from odoo import Command +from odoo.tests.common import TransactionCase + + +class WebQuickStartScreenCommon(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + + cls.quick_start_screen_action_1 = cls.env["quick.start.screen.action"].create( + { + "name": "Contacts", + "description": "Browse contacts", + "action_ref_id": f"ir.actions.act_window," + f"{cls.env.ref('base.action_partner_form').id}", + "icon_name": "fa-users", + "color": 7, + } + ) + + cls.quick_start_screen_action_2 = cls.env["quick.start.screen.action"].create( + { + "name": "Access rights", + "description": "Explore access rights", + "action_ref_id": f"ir.actions.act_window," + f"{cls.env.ref('base.ir_access_act').id}", + "icon_name": "fa-eyes", + "color": 4, + } + ) + + cls.start_screen_1 = cls.env["quick.start.screen"].create( + { + "name": "start_screen_1", + "action_ids": [ + Command.link(cls.quick_start_screen_action_1.id), + Command.link(cls.quick_start_screen_action_2.id), + ], + } + ) diff --git a/web_quick_start_screen/views/quick_screen_action_view.xml b/web_quick_start_screen/views/quick_screen_action_view.xml new file mode 100644 index 000000000000..44bca345fa2d --- /dev/null +++ b/web_quick_start_screen/views/quick_screen_action_view.xml @@ -0,0 +1,89 @@ + + + + quick.start.screen.action + + + + + + + + + + + quick.start.screen.action + + + + + + + + + + + + +
+

+ + + +

+
+
+
+
+
+ + quick.start.screen.action + +
+ + + + + + + + + + + + +
+
+
+ + Quick Start Screen Actions + quick.start.screen.action + list,form + + +
diff --git a/web_quick_start_screen/views/quick_start_screen_views.xml b/web_quick_start_screen/views/quick_start_screen_views.xml new file mode 100644 index 000000000000..751235648610 --- /dev/null +++ b/web_quick_start_screen/views/quick_start_screen_views.xml @@ -0,0 +1,55 @@ + + + + quick.start.screen + + + + +