diff --git a/odex30_base/odex30_web/i18n/ar_001.po b/odex30_base/odex30_web/i18n/ar_001.po deleted file mode 100644 index 805626c..0000000 --- a/odex30_base/odex30_web/i18n/ar_001.po +++ /dev/null @@ -1,457 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * odex30_web -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 18.0+e\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-01-01 22:17+0000\n" -"PO-Revision-Date: 2026-01-01 22:17+0000\n" -"Last-Translator: \n" -"Language-Team: \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" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.js:0 -msgid "%s days" -msgstr "%s أيام" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/settings_form_view/res_config_edition.xml:0 -msgid "(Enterprise Edition)" -msgstr "(النسخة الشركاتية)" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.js:0 -msgid "1 month" -msgstr "شهر واحد" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/views/list/list_renderer_desktop.xml:0 -msgid "Add Custom Field" -msgstr "إضافة حقل مخصص" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/views/kanban/kanban_header_patch.js:0 -msgid "Automations" -msgstr "الأتمتة" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0 -msgid "Build new apps from scratch" -msgstr "بناء تطبيقات جديدة من الصفر" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0 -msgid "Build new reports" -msgstr "بناء تقارير جديدة" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/share_url/burger_menu.xml:0 -msgid "Close menu" -msgstr "إغلاق القائمة" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "" -"Contact your sales representative to help you to unlink your previous " -"database" -msgstr "" -"تواصل مع مندوب المبيعات لمساعدتك في فصل قاعدة البيانات السابقة" -"" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0 -msgid "Create automation rules" -msgstr "إنشاء قواعد الأتمتة" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0 -msgid "Customize Reports" -msgstr "تخصيص التقارير" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0 -msgid "Customize any screen" -msgstr "تخصيص أي شاشة" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/color_scheme/color_scheme_menu_items.js:0 -msgid "Dark Mode" -msgstr "الوضع الداكن" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/settings_form_view/res_config_edition.xml:0 -msgid "Database expiration:" -msgstr "انتهاء صلاحية قاعدة البيانات:" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0 -msgid "Define webhooks" -msgstr "تعريف Webhooks" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0 -msgid "Discard" -msgstr "إلغاء" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "Dismiss" -msgstr "إغلاق" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "Error reason:" -msgstr "سبب الخطأ:" - -#. module: odex30_web -#: model:ir.model,name:odex30_web.model_ir_http -msgid "HTTP Routing" -msgstr "مسار HTTP" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/home_menu_service.js:0 -msgid "Home" -msgstr "الرئيسية" - -#. module: odex30_web -#: model:ir.model.fields,field_description:odex30_web.field_res_users_settings__homemenu_config -msgid "Home Menu Configuration" -msgstr "إعدادات قائمة الرئيسية" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/navbar/navbar.js:0 -msgid "Home menu" -msgstr "قائمة الرئيسية" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "I paid, please recheck!" -msgstr "لقد دفعت، يرجى إعادة التحقق!" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0 -msgid "Install Odoo Studio and its dependencies" -msgstr "تثبيت Odoo Studio وتبعياته" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0 -msgid "Learn More" -msgstr "تعرف على المزيد" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "Log in as an administrator to correct the issue." -msgstr "سجل الدخول كمدير لإصلاح المشكلة." - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/home_menu.xml:0 -msgid "No result" -msgstr "لا توجد نتائج" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/settings_form_view/res_config_edition.xml:0 -msgid "Odoo" -msgstr "أودو" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/settings_form_view/res_config_edition.xml:0 -msgid "Odoo Enterprise Edition License V1.0" -msgstr "رخصة Odoo Enterprise Edition V1.0" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/views/list/list_renderer_desktop.js:0 -msgid "Odoo Studio - Add new fields to any view" -msgstr "Odoo Studio - إضافة حقول جديدة إلى أي عرض" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/views/kanban/kanban_header_patch.js:0 -msgid "Odoo Studio - Customize workflows in minutes" -msgstr "Odoo Studio - تخصيص سير العمل في دقائق" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "Odoo Support" -msgstr "دعم أودو" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "Paste code here" -msgstr "الصق الكود هنا" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/navbar/navbar.js:0 -msgid "Previous view" -msgstr "العرض السابق" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.js:0 -msgid "Register" -msgstr "تسجيل" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "Register your subscription" -msgstr "تسجيل اشتراكك" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "Renew now" -msgstr "تجديد الآن" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.js:0 -msgid "Retry" -msgstr "إعادة المحاولة" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "Send an email" -msgstr "إرسال بريد إلكتروني" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "Sending the instructions by email ..." -msgstr "إرسال التعليمات بالبريد الإلكتروني..." - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/share_url/share_url.js:0 -msgid "Share" -msgstr "مشاركة" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/share_url/burger_menu.xml:0 -msgid "Share URL" -msgstr "مشاركة الرابط" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "" -"Something went wrong while registering your database. You can try again or " -"contact" -msgstr "" -"حدث خطأ أثناء تسجيل قاعدة البيانات. يمكنك المحاولة مرة أخرى أو التواصل" -" مع" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0 -msgid "Start using Odoo Studio" -msgstr "ابدأ استخدام Odoo Studio" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "Subscription Code:" -msgstr "كود الاشتراك:" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/home_menu.xml:0 -msgid "TIP" -msgstr "نصيحة" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "" -"Thank you, your registration was successful! Your database is valid until" -msgstr "" -"شكراً، تم تسجيلك بنجاح! قاعدة بياناتك صالحة حتى" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/enterprise_subscription_service.js:0 -msgid "" -"Thank you, your registration was successful! Your database is valid until " -"%s." -msgstr "" -"شكراً، تم تسجيلك بنجاح! قاعدة بياناتك صالحة حتى %s." - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "" -"The instructions to unlink your subscription from the previous database(s) " -"have been sent" -msgstr "" -"تم إرسال التعليمات لفصل اشتراكك من قواعد البيانات السابقة" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.js:0 -msgid "This database has expired. " -msgstr "انتهت صلاحية هذه قاعدة البيانات. " - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.js:0 -msgid "This database will expire in %s. " -msgstr "ستنتهي صلاحية قاعدة البيانات هذه في %s. " - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.js:0 -msgid "This demo database will expire in %s. " -msgstr "ستنتهي صلاحية قاعدة بيانات العرض التجريبي في %s. " - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "Unable to send the instructions by email, please contact the" -msgstr "تعذر إرسال التعليمات بالبريد الإلكتروني، يرجى التواصل مع" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0 -msgid "Unleash the power of Odoo Studio:" -msgstr "استخدم قوة Odoo Studio:" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "Upgrade your subscription" -msgstr "ترقية اشتراكك" - -#. module: odex30_web -#: model:ir.model,name:odex30_web.model_res_users_settings -msgid "User Settings" -msgstr "إعدادات المستخدم" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0 -msgid "Want to tailor-make your Odoo?" -msgstr "هل تريد تخصيص أودو حسب احتياجاتك؟" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "" -"You have more users or more apps installed than your subscription allows." -msgstr "" -"لديك مستخدمون أو تطبيقات مثبتة أكثر مما يسمح به اشتراكك." - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "" -"You will be able to register your database once you have installed your " -"first app." -msgstr "" -"يمكنك تسجيل قاعدة البيانات بعد تثبيت أول تطبيق." - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "Your subscription code" -msgstr "كود اشتراكك" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.js:0 -msgid "" -"Your subscription expired %s days ago. This database will be blocked soon. " -msgstr "" -"انتهى اشتراكك منذ %s أيام. سيتم حظر قاعدة البيانات قريباً. " - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.js:0 -msgid "Your subscription expires in %s days. " -msgstr "ينتهي اشتراكك بعد %s أيام. " - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "Your subscription is already linked to a database." -msgstr "اشتراكك مرتبط بقاعدة بيانات بالفعل." - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "Your subscription was updated and is valid until" -msgstr "تم تحديث اشتراكك وهو صالح حتى" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0 -msgid "and more!" -msgstr "وأكثر!" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "buy a subscription" -msgstr "شراء اشتراك" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "buy a subscription." -msgstr "شراء اشتراك." - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "or" -msgstr "أو" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0 -msgid "to the subscription owner to confirm the change, enter a new code or" -msgstr "" -"لصاحب الاشتراك لتأكيد التغيير، أدخل كود جديد أو" - -#. module: odex30_web -#. odoo-javascript -#: code:addons/odex30_web/static/src/webclient/home_menu/home_menu.xml:0 -msgid "— open me anywhere with" -msgstr "" diff --git a/odex30_base/odex30_web/static/description/icon.png b/odex30_base/odex30_web/static/description/icon.png new file mode 100644 index 0000000..d3b8d45 Binary files /dev/null and b/odex30_base/odex30_web/static/description/icon.png differ diff --git a/odex30_base/odex30_web/static/img/background-dark.jpg b/odex30_base/odex30_web/static/img/background-dark.jpg deleted file mode 100644 index ce69f95..0000000 Binary files a/odex30_base/odex30_web/static/img/background-dark.jpg and /dev/null differ diff --git a/odex30_base/odex30_web/static/img/background-dark.png b/odex30_base/odex30_web/static/img/background-dark.png new file mode 100644 index 0000000..ac94fc4 Binary files /dev/null and b/odex30_base/odex30_web/static/img/background-dark.png differ diff --git a/odex30_base/odex30_web/static/img/background-light.png b/odex30_base/odex30_web/static/img/background-light.png new file mode 100644 index 0000000..63ffa6c Binary files /dev/null and b/odex30_base/odex30_web/static/img/background-light.png differ diff --git a/odex30_base/odex30_web/static/img/background-light.svg b/odex30_base/odex30_web/static/img/background-light.svg deleted file mode 100644 index aa437a1..0000000 --- a/odex30_base/odex30_web/static/img/background-light.svg +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/odex30_base/odex30_web/static/src/core/search/search_panel/search_panel.dark.scss b/odex30_base/odex30_web/static/src/core/search/search_panel/search_panel.dark.scss deleted file mode 100644 index 5bf10d1..0000000 --- a/odex30_base/odex30_web/static/src/core/search/search_panel/search_panel.dark.scss +++ /dev/null @@ -1,9 +0,0 @@ -// = Search Panel -// ============================================================================ -// No CSS hacks, variables overrides only - -.o_search_panel_section { - .o_popover > & .list-group { - --#{$prefix}list-group-active-bg: #{$o-gray-400}; - } -} diff --git a/odex30_base/odex30_web/static/src/webclient/home_menu/enterprise_subscription_service.js b/odex30_base/odex30_web/static/src/webclient/home_menu/enterprise_subscription_service.js deleted file mode 100644 index e3c65c1..0000000 --- a/odex30_base/odex30_web/static/src/webclient/home_menu/enterprise_subscription_service.js +++ /dev/null @@ -1,195 +0,0 @@ -/** @odoo-module **/ - -import { registry } from "@web/core/registry"; -import { session } from "@web/session"; -import { browser } from "@web/core/browser/browser"; -import { deserializeDateTime, serializeDate, formatDate } from "@web/core/l10n/dates"; -import { useService } from "@web/core/utils/hooks"; -import { _t } from "@web/core/l10n/translation"; -import { ExpirationPanel } from "./expiration_panel"; -import { cookie } from "@web/core/browser/cookie"; -import { rpc } from "@web/core/network/rpc"; - -const { DateTime } = luxon; -import { Component, xml, useState } from "@odoo/owl"; - -function daysUntil(datetime) { - const duration = datetime.diff(DateTime.utc(), "days"); - return Math.round(duration.values.days); -} - -export class SubscriptionManager { - constructor(env, { orm, notification }) { - this.env = env; - this.orm = orm; - this.notification = notification; - if (session.expiration_date) { - this.expirationDate = deserializeDateTime(session.expiration_date); - } else { - // If no date found, assume 1 month and hope for the best - this.expirationDate = DateTime.utc().plus({ days: 30 }); - } - this.expirationReason = session.expiration_reason; - // Hack: we need to know if there is at least one app installed (except from App and - // Settings). We use mail to do that, as it is a dependency of almost every addon. To - // determine whether mail is installed or not, we check for the presence of the key - // "storeData" in session_info, as it is added in mail. - this.hasInstalledApps = "storeData" in session; - // "user" or "admin" - this.warningType = session.warning; - this.lastRequestStatus = null; - this.isWarningHidden = cookie.get("oe_instance_hide_panel"); - } - - get formattedExpirationDate() { - return formatDate(this.expirationDate, { format: "DDD" }); - } - - get daysLeft() { - return daysUntil(this.expirationDate); - } - - get unregistered() { - return ["trial", "demo", false].includes(this.expirationReason); - } - - hideWarning() { - // Hide warning for 24 hours. - cookie.set("oe_instance_hide_panel", true, 24 * 60 * 60); - this.isWarningHidden = true; - } - - async buy() { - const limitDate = serializeDate(DateTime.utc().minus({ days: 15 })); - const args = [ - [ - ["share", "=", false], - ["login_date", ">=", limitDate], - ], - ]; - const nbUsers = await this.orm.call("res.users", "search_count", args); - browser.location = `https://www.odoo.com/odoo-enterprise/upgrade?num_users=${nbUsers}`; - } - - async submitCode(OdexCode) { - const [oldDate, ] = await Promise.all([ - this.orm.call("ir.config_parameter", "get_param", ["database.expiration_date"]), - this.orm.call("ir.config_parameter", "set_param", [ - "database.enterprise_code", - OdexCode, - ]) - ]); - - await this.orm.call("publisher_warranty.contract", "update_notification", [[]]); - - const [linkedSubscriptionUrl, linkedEmail, expirationDate] = await Promise.all([ - this.orm.call("ir.config_parameter", "get_param", [ - "database.already_linked_subscription_url", - ]), - this.orm.call("ir.config_parameter", "get_param", ["database.already_linked_email"]), - this.orm.call("ir.config_parameter", "get_param", [ - "database.expiration_date", - ]) - ]); - - if (linkedSubscriptionUrl) { - this.lastRequestStatus = "link"; - this.linkedSubscriptionUrl = linkedSubscriptionUrl; - this.mailDeliveryStatus = null; - this.linkedEmail = linkedEmail; - } else if (expirationDate !== oldDate) { - this.lastRequestStatus = "success"; - this.expirationDate = deserializeDateTime(expirationDate); - if (this.daysLeft > 30) { - this.notification.add( - _t( - "Thank you, your registration was successful! Your database is valid until %s.", - this.formattedExpirationDate - ), - { type: "success" } - ); - } - } else { - this.lastRequestStatus = "error"; - } - } - - async checkStatus() { - await this.orm.call("publisher_warranty.contract", "update_notification", [[]]); - - const expirationDateStr = await this.orm.call("ir.config_parameter", "get_param", [ - "database.expiration_date", - ]); - this.lastRequestStatus = "update"; - this.expirationDate = deserializeDateTime(expirationDateStr); - } - - async sendUnlinkEmail() { - const sendUnlinkInstructionsUrl = await this.orm.call("ir.config_parameter", "get_param", [ - "database.already_linked_send_mail_url", - ]); - this.mailDeliveryStatus = "ongoing"; - const { result, reason } = await rpc(sendUnlinkInstructionsUrl); - if (result) { - this.mailDeliveryStatus = "success"; - } else { - this.mailDeliveryStatus = "fail"; - this.mailDeliveryStatusError = reason; - } - } - - async renew() { - const OdexCode = await this.orm.call("ir.config_parameter", "get_param", [ - "database.enterprise_code", - ]); - - const url = "https://www.odoo.com/odoo-enterprise/renew"; - const contractQueryString = OdexCode ? `?contract=${OdexCode}` : ""; - browser.location = `${url}${contractQueryString}`; - } - - async upsell() { - const limitDate = serializeDate(DateTime.utc().minus({ days: 15 })); - const [OdexCode, nbUsers] = await Promise.all([ - this.orm.call("ir.config_parameter", "get_param", ["database.enterprise_code"]), - this.orm.call("res.users", "search_count", [ - [ - ["share", "=", false], - ["login_date", ">=", limitDate], - ], - ]), - ]); - const url = "https://www.odoo.com/odoo-enterprise/upsell"; - const contractQueryString = OdexCode ? `&contract=${OdexCode}` : ""; - browser.location = `${url}?num_users=${nbUsers}${contractQueryString}`; - } -} - -class ExpiredSubscriptionBlockUI extends Component { - static props = {}; - // TODO the "o_blockUI" div in there seems useless (it has 0 height and thus displays and does nothing) - static template = xml` - -
-
- -
- `; - static components = { ExpirationPanel }; - setup() { - this.subscription = useState(useService("enterprise_subscription")); - } -} - -export const enterpriseSubscriptionService = { - name: "enterprise_subscription", - dependencies: ["orm", "notification"], - start(env, { orm, notification }) { - registry - .category("main_components") - .add("expired_subscription_block_ui", { Component: ExpiredSubscriptionBlockUI }); - return new SubscriptionManager(env, { orm, notification }); - }, -}; - -registry.category("services").add("enterprise_subscription", enterpriseSubscriptionService); diff --git a/odex30_base/odex30_web/static/src/webclient/home_menu/expiration_panel.js b/odex30_base/odex30_web/static/src/webclient/home_menu/expiration_panel.js deleted file mode 100644 index 57d48a2..0000000 --- a/odex30_base/odex30_web/static/src/webclient/home_menu/expiration_panel.js +++ /dev/null @@ -1,97 +0,0 @@ -/** @odoo-module **/ - -import { useService } from "@web/core/utils/hooks"; -import { Transition } from "@web/core/transition"; -import { _t } from "@web/core/l10n/translation"; -import { Component, useState, useRef } from "@odoo/owl"; - -const { DateTime } = luxon; - -/** - * Expiration panel - * - * Component representing the banner located on top of the home menu. Its purpose - * is to display the expiration state of the current database and to help the - * user to buy/renew its subscription. - * @extends Component - */ -export class ExpirationPanel extends Component { - static template = "DatabaseExpirationPanel"; - static props = {}; - static components = { Transition }; - - setup() { - this.subscription = useState(useService("enterprise_subscription")); - - this.state = useState({ - displayRegisterForm: false, - }); - - this.inputRef = useRef("input"); - } - - get buttonText() { - return this.subscription.lastRequestStatus === "error" ? _t("Retry") : _t("Register"); - } - - get alertType() { - if (this.subscription.lastRequestStatus === "success") { - return "success"; - } - const { daysLeft } = this.subscription; - if (daysLeft <= 6) { - return "danger"; - } else if (daysLeft <= 16) { - return "warning"; - } - return "info"; - } - - get expirationMessage() { - const { daysLeft } = this.subscription; - if (daysLeft <= 0) { - return _t("This database has expired. "); - } - const delay = daysLeft === 30 ? _t("1 month") : _t("%s days", daysLeft); - if (this.subscription.expirationReason === "demo") { - return _t("This demo database will expire in %s. ", delay); - } - - const expirationDate = this.subscription.expirationDate; - const today = DateTime.now(); - const diff = expirationDate.diff(today); - - if (this.subscription.expirationReason !== 'renewal') { - return _t("This database will expire in %s. ", delay); - } else { - if (daysLeft > 15) { - return _t( - "Your subscription expires in %s days. ", - daysLeft - 15 - ); - } else { - return _t( - "Your subscription expired %s days ago. This database will be blocked soon. ", - (diff.as("days") | 0) - ); - } - } - } - - showRegistrationForm() { - this.state.displayRegisterForm = !this.state.displayRegisterForm; - } - - async onCodeSubmit() { - const OdexCode = this.inputRef.el.value; - if (!OdexCode) { - return; - } - await this.subscription.submitCode(OdexCode); - if (this.subscription.lastRequestStatus === "success") { - this.state.displayRegisterForm = false; - } else { - this.state.buttonText = _t("Retry"); - } - } -} diff --git a/odex30_base/odex30_web/static/src/webclient/home_menu/expiration_panel.scss b/odex30_base/odex30_web/static/src/webclient/home_menu/expiration_panel.scss deleted file mode 100644 index 5d7511f..0000000 --- a/odex30_base/odex30_web/static/src/webclient/home_menu/expiration_panel.scss +++ /dev/null @@ -1,8 +0,0 @@ -.database_expiration_panel .oe_instance_register_form { - max-height: 0; - transition: max-height 0.4s; - - &.o-vertical-slide-enter-active { - max-height: 10rem; // fixed value is required to properly trigger transition - } -} diff --git a/odex30_base/odex30_web/static/src/webclient/home_menu/expiration_panel.xml b/odex30_base/odex30_web/static/src/webclient/home_menu/expiration_panel.xml deleted file mode 100644 index be99fd1..0000000 --- a/odex30_base/odex30_web/static/src/webclient/home_menu/expiration_panel.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - diff --git a/odex30_base/odex30_web/static/src/webclient/home_menu/home_menu_background.dark.scss b/odex30_base/odex30_web/static/src/webclient/home_menu/home_menu_background.dark.scss index 8c59efa..358d38b 100644 --- a/odex30_base/odex30_web/static/src/webclient/home_menu/home_menu_background.dark.scss +++ b/odex30_base/odex30_web/static/src/webclient/home_menu/home_menu_background.dark.scss @@ -4,5 +4,5 @@ .o_home_menu_background { --homeMenu-bg-color: #000511; - --homeMenu-bg-image: url("/odex30_web/static/img/background-dark.jpg"); + --homeMenu-bg-image: url("/odex30_web/static/img/background-dark.png"); } diff --git a/odex30_base/odex30_web/static/src/webclient/home_menu/home_menu_background.scss b/odex30_base/odex30_web/static/src/webclient/home_menu/home_menu_background.scss index e00bcb9..65a3cdd 100644 --- a/odex30_base/odex30_web/static/src/webclient/home_menu/home_menu_background.scss +++ b/odex30_base/odex30_web/static/src/webclient/home_menu/home_menu_background.scss @@ -4,6 +4,6 @@ size: cover; attachment: fixed; color: var(--homeMenu-bg-color, #{$o-gray-200}); - image: var(--homeMenu-bg-image, url("/odex30_web/static/img/background-light.svg")); + image: var(--homeMenu-bg-image, url("/odex30_web/static/img/background-light.png")); } } diff --git a/odex30_base/odex30_web/static/tests/helpers.js b/odex30_base/odex30_web/static/tests/helpers.js deleted file mode 100644 index c743b5e..0000000 --- a/odex30_base/odex30_web/static/tests/helpers.js +++ /dev/null @@ -1,9 +0,0 @@ -/** @odoo-module */ - -import { createWebClient } from "@web/../tests/webclient/helpers"; -import { WebClientOdex } from "@odex30_web/webclient/webclient"; - -export function createOdexWebClient(params) { - params.WebClientClass = WebClientOdex; - return createWebClient(params); -} diff --git a/odex30_base/odex30_web/static/tests/mobile/burger_menu.test.js b/odex30_base/odex30_web/static/tests/mobile/burger_menu.test.js deleted file mode 100644 index e6afdb2..0000000 --- a/odex30_base/odex30_web/static/tests/mobile/burger_menu.test.js +++ /dev/null @@ -1,107 +0,0 @@ -import { beforeEach, describe, expect, test } from "@odoo/hoot"; -import { click, queryAll } from "@odoo/hoot-dom"; -import { animationFrame, runAllTimers } from "@odoo/hoot-mock"; -import { defineActions, defineMenus, mountWithCleanup } from "@web/../tests/web_test_helpers"; - -import { Component, onMounted, xml } from "@odoo/owl"; - -import { registry } from "@web/core/registry"; -import { WebClientOdex } from "@odex30_web/webclient/webclient"; - -const actionRegistry = registry.category("actions"); - -const queryAllRoot = (selector) => queryAll(selector, { root: document.body }); - -class TestClientAction extends Component { - static template = xml` -
- ClientAction_ -
`; - static props = ["*"]; - setup() { - onMounted(() => this.env.config.setDisplayName(`Client action ${this.props.action.id}`)); - } -} - -describe.current.tags("mobile"); - -beforeEach(() => { - defineMenus([ - { - id: 1, - name: "App1", - appID: 1, - actionID: 1001, - xmlid: "menu_1", - }, - ]); -}); - -test("Burger Menu on home menu", async () => { - expect.assertions(5); - - await mountWithCleanup(WebClientOdex); - await animationFrame(); - expect(queryAllRoot(".o_burger_menu")).toHaveCount(0); - expect(queryAllRoot(".o_home_menu")).toBeVisible(); - - await click(queryAllRoot(".o_mobile_menu_toggle")); - await runAllTimers(); - await animationFrame(); - expect(queryAllRoot(".o_burger_menu")).toHaveCount(1); - expect(queryAllRoot(".o_user_menu_mobile")).toHaveCount(1); - await click(queryAllRoot(".o_sidebar_close")); - await animationFrame(); - expect(".o_burger_menu").toHaveCount(0); -}); - -test("Burger Menu on home menu over an App", async () => { - expect.assertions(5); - - actionRegistry.add("__test__client__action__", TestClientAction); - - defineMenus([ - { - id: 1, - children: [ - { - id: 99, - name: "SubMenu", - appID: 1, - actionID: 1002, - webIconData: undefined, - webIcon: false, - }, - ], - }, - ]); - - defineActions([ - { - id: 1001, - tag: "__test__client__action__", - target: "main", - type: "ir.actions.client", - params: { description: "Id 1" }, - }, - ]); - - await mountWithCleanup(WebClientOdex); - await animationFrame(); - - await click(queryAllRoot(".o_draggable:first-of-type .o_app")); - await animationFrame(); - await click(queryAllRoot(".o_menu_toggle")); - await animationFrame(); - await click(queryAllRoot(".o_sidebar_topbar a.btn-primary")); - await animationFrame(); - - expect(queryAllRoot(".o_burger_menu")).toHaveCount(0); - expect(queryAllRoot(".o_home_menu")).toBeVisible(); - - await click(queryAllRoot(".o_mobile_menu_toggle")); - await animationFrame(); - expect(queryAllRoot(".o_burger_menu")).toHaveCount(1); - expect(queryAllRoot(".o_burger_menu nav.o_burger_menu_content li")).toHaveCount(0); - expect(queryAllRoot(".o_burger_menu_content")).not.toHaveClass("o_burger_menu_dark"); -}); diff --git a/odex30_base/odex30_web/static/tests/mobile/pivot_view.test.js b/odex30_base/odex30_web/static/tests/mobile/pivot_view.test.js deleted file mode 100644 index 67b23d9..0000000 --- a/odex30_base/odex30_web/static/tests/mobile/pivot_view.test.js +++ /dev/null @@ -1,72 +0,0 @@ -import { describe, expect, test } from "@odoo/hoot"; -import { click } from "@odoo/hoot-dom"; -import { animationFrame } from "@odoo/hoot-mock"; -import { defineModels, fields, models, mountView } from "@web/../tests/web_test_helpers"; - -class Partner extends models.Model { - foo = fields.Integer({ aggregator: "sum" }); - - _records = [ - { - id: 1, - foo: 12, - }, - { - id: 2, - foo: 1, - }, - { - id: 3, - foo: 17, - }, - { - id: 4, - foo: 2, - }, - ]; -} - -defineModels([Partner]); - -describe.current.tags("mobile"); - -test("simple pivot rendering", async () => { - expect.assertions(2); - - await mountView({ - type: "pivot", - resModel: "partner", - arch: /* xml */ ` - - - - `, - }); - - expect(".o_pivot_view").toHaveClass("o_view_controller"); - expect("td.o_pivot_cell_value:contains(32)").toHaveCount(1, { - message: "should contain a pivot cell with the sum of all records", - }); -}); - -test("unselecting all measures should not crash pivot rendering", async () => { - expect.assertions(1); - - await mountView({ - type: "pivot", - resModel: "partner", - arch: /* xml */ ` - - - - `, - }); - - await click(".dropdown-toggle.btn.btn-primary:eq(1)"); - await animationFrame(); - await click(".dropdown-item.o_menu_item.selected:eq(0)"); - await animationFrame(); - expect("div.o_nocontent_help").toHaveCount(1, { - message: "Instead of error action helper will appear", - }); -}); diff --git a/odex30_base/odex30_web/static/tests/mobile/webclient_mobile.test.js b/odex30_base/odex30_web/static/tests/mobile/webclient_mobile.test.js deleted file mode 100644 index 952d9c0..0000000 --- a/odex30_base/odex30_web/static/tests/mobile/webclient_mobile.test.js +++ /dev/null @@ -1,112 +0,0 @@ -import { describe, expect, test } from "@odoo/hoot"; -import { click, queryFirst } from "@odoo/hoot-dom"; -import { animationFrame, mockMatchMedia } from "@odoo/hoot-mock"; -import { - defineActions, - defineModels, - fields, - getService, - models, - mountWithCleanup, -} from "@web/../tests/web_test_helpers"; - -import { UserMenu } from "@web/webclient/user_menu/user_menu"; -import { WebClientOdex } from "@odex30_web/webclient/webclient"; - -class Partner extends models.Model { - name = fields.Char(); - - _records = [ - { id: 1, name: "First record" }, - { id: 2, name: "Second record" }, - ]; - _views = { - form: ` -
- - - -
- `, - kanban: ` - - - - - - - - `, - list: ``, - }; -} - -defineModels([Partner]); - -defineActions([ - { - id: 1, - xml_id: "action_1", - name: "Partners Action 1", - res_model: "partner", - views: [[false, "kanban"]], - }, - { - id: 3, - xml_id: "action_3", - name: "Partners", - res_model: "partner", - views: [ - [false, "list"], - [false, "kanban"], - [false, "form"], - ], - }, -]); - -describe.current.tags("mobile"); - -test("scroll position is kept", async () => { - // This test relies on the fact that the scrollable element in mobile - // is view's root node. - const firstRecord = Partner._records[0]; - delete firstRecord.id; - Partner._records = [...Array(80)].map((_, i) => ({ - ...firstRecord, - name: `Record ${i + 1}`, - })); - - await mountWithCleanup(WebClientOdex); - await animationFrame(); - - // partners in list/kanban - await getService("action").doAction(3); - expect(".o_kanban_view").toHaveCount(1); - - queryFirst(".o_kanban_view").scrollTo(0, 123); - await click(".o_kanban_record:eq(20)"); - await animationFrame(); - expect(".o_form_view").toHaveCount(1); - expect(".o_kanban_view").toHaveCount(0); - - await click(".o_breadcrumb .o_back_button"); - await animationFrame(); - expect(".o_form_view").toHaveCount(0); - expect(".o_kanban_view").toHaveCount(1); -}); - -test("Share URL item is not present in the user menu when screen is small", async () => { - mockMatchMedia({ ["display-mode"]: "standalone" }); - - await mountWithCleanup(UserMenu); - - expect(".o_user_menu").toHaveCount(1); - queryFirst(".o_user_menu").classList.remove("d-none"); - - await click(".o_user_menu button"); - await animationFrame(); - - expect(".o_user_menu .dropdown-item").toHaveCount(0, { - message: "share button is not visible", - }); -}); diff --git a/odex30_base/odex30_web/static/tests/tours/web_enterprise_tours.js b/odex30_base/odex30_web/static/tests/tours/web_enterprise_tours.js deleted file mode 100644 index 35f1bc8..0000000 --- a/odex30_base/odex30_web/static/tests/tours/web_enterprise_tours.js +++ /dev/null @@ -1,17 +0,0 @@ -/** @odoo-module */ -import { registry } from "@web/core/registry"; - -registry.category("web_tour.tours").add("odex30_web.test_studio_list_upsell", { - steps: () => [ - { - trigger: ".o_list_view", - }, - { - trigger: ".o_optional_columns_dropdown > button", - run: "click", - }, - { - trigger: " .o-dropdown--menu .dropdown-item-studio", - }, - ], -}); diff --git a/odex30_base/odex30_web/static/tests/views/list.test.js b/odex30_base/odex30_web/static/tests/views/list.test.js deleted file mode 100644 index e282075..0000000 --- a/odex30_base/odex30_web/static/tests/views/list.test.js +++ /dev/null @@ -1,348 +0,0 @@ -import { beforeEach, describe, expect, test } from "@odoo/hoot"; -import { click, queryAll } from "@odoo/hoot-dom"; -import { animationFrame } from "@odoo/hoot-mock"; -import { - contains, - defineModels, - fields, - getDropdownMenu, - getService, - models, - mountView, - mountWithCleanup, - onRpc, - patchWithCleanup, -} from "@web/../tests/web_test_helpers"; - -import { browser } from "@web/core/browser/browser"; -import { user } from "@web/core/user"; -import { WebClientOdex } from "@odex30_web/webclient/webclient"; - -class Foo extends models.Model { - foo = fields.Char(); - bar = fields.Boolean(); - - _records = [ - { id: 1, bar: true, foo: "yop" }, - { id: 2, bar: true, foo: "blip" }, - { id: 3, bar: true, foo: "gnap" }, - { id: 4, bar: false, foo: "blip" }, - ]; -} - -defineModels([Foo]); - -const getDefaultConfig = () => ({ - actionId: 1, - actionType: "ir.actions.act_window", -}); - -describe.current.tags("desktop"); - -beforeEach(() => { - onRpc("has_group", () => true); -}); - -test("add custom field button with other optional columns - studio not installed", async () => { - expect.assertions(8); - - onRpc("search_read", ({ model }) => { - if (model === "ir.module.module") { - expect.step("studio_module_id"); - return [{ id: 42 }]; - } - }); - onRpc("button_immediate_install", ({ model, args }) => { - if (model === "ir.module.module") { - expect(args[0]).toEqual([42], { - message: "Should be the id of studio module returned by the search read", - }); - expect.step("studio_module_install"); - return true; - } - }); - await mountView({ - type: "list", - resModel: "foo", - arch: /* xml */ ` - - - - - `, - config: getDefaultConfig(), - }); - - patchWithCleanup(browser.location, { - reload: function () { - expect.step("window_reload"); - }, - }); - - expect(".o_data_row").toHaveCount(4); - expect(".o_optional_columns_dropdown_toggle").toHaveCount(1); - - await click(".o_optional_columns_dropdown_toggle"); - await animationFrame(); - const dropdown = getDropdownMenu(".o_optional_columns_dropdown"); - - expect(queryAll(".dropdown-item", { root: dropdown })).toHaveCount(2); - expect(queryAll(".dropdown-item-studio", { root: dropdown })).toHaveCount(1); - - await click(".dropdown-item-studio"); - await animationFrame(); - expect(".modal-studio").toHaveCount(1); - - await click(".modal .o_install_studio"); - await animationFrame(); - expect(browser.localStorage.getItem("openStudioOnReload")).toBe("main"); - expect.verifySteps(["studio_module_id", "studio_module_install", "window_reload"]); -}); - -test("add custom field button without other optional columns - studio not installed", async () => { - expect.assertions(8); - - onRpc("search_read", ({ model }) => { - if (model === "ir.module.module") { - expect.step("studio_module_id"); - return [{ id: 42 }]; - } - }); - onRpc("button_immediate_install", ({ model, args }) => { - if (model === "ir.module.module") { - expect(args[0]).toEqual([42], { - message: "Should be the id of studio module returned by the search read", - }); - expect.step("studio_module_install"); - return true; - } - }); - await mountView({ - type: "list", - resModel: "foo", - config: getDefaultConfig(), - arch: /* xml */ ` - - - - - `, - }); - - patchWithCleanup(browser.location, { - reload: function () { - expect.step("window_reload"); - }, - }); - - expect(".o_data_row").toHaveCount(4); - expect(".o_optional_columns_dropdown_toggle").toHaveCount(1); - - await click(".o_optional_columns_dropdown_toggle"); - await animationFrame(); - const dropdown = getDropdownMenu(".o_optional_columns_dropdown"); - - expect(queryAll(".dropdown-item", { root: dropdown })).toHaveCount(1); - expect(queryAll(".dropdown-item-studio", { root: dropdown })).toHaveCount(1); - - await click(".dropdown-item-studio"); - await animationFrame(); - expect(".modal-studio").toHaveCount(1); - - await click(".modal .o_install_studio"); - await animationFrame(); - expect(browser.localStorage.getItem("openStudioOnReload")).toBe("main"); - expect.verifySteps(["studio_module_id", "studio_module_install", "window_reload"]); -}); - -test("add custom field button not shown to non-system users (with opt. col.)", async () => { - expect.assertions(3); - - patchWithCleanup(user, { isSystem: false }); - - await mountView({ - type: "list", - resModel: "foo", - config: getDefaultConfig(), - arch: /* xml */ ` - - - - - `, - }); - - expect(".o_optional_columns_dropdown_toggle").toHaveCount(1); - - await click(".o_optional_columns_dropdown_toggle"); - await animationFrame(); - const dropdown = getDropdownMenu(".o_optional_columns_dropdown"); - expect(queryAll(".dropdown-item", { root: dropdown })).toHaveCount(1); - expect(queryAll(".dropdown-item-studio", { root: dropdown })).toHaveCount(0); -}); - -test("add custom field button not shown to non-system users (wo opt. col.)", async () => { - patchWithCleanup(user, { isSystem: false }); - - await mountView({ - type: "list", - resModel: "foo", - config: getDefaultConfig(), - arch: /* xml */ ` - - - - - `, - }); - - expect(".o_optional_columns_dropdown_toggle").toHaveCount(0); -}); - -test("add custom field button not shown with invalid action", async () => { - expect.assertions(1); - - patchWithCleanup(user, { isSystem: false }); - - await mountView({ - type: "list", - resModel: "foo", - config: { ...getDefaultConfig(), actionId: null }, - arch: /* xml */ ` - - - - - `, - }); - - expect(".o_optional_columns_dropdown_toggle").toHaveCount(0); -}); - -test("add custom field button not shown with bank statement line model", async () => { - class AccountBankStatementLine extends models.Model { - name = fields.Char(); - _views = { - kanban: ` - - - - `, - list: ` `, - }; - } - defineModels([AccountBankStatementLine]); - - expect.assertions(3); - - await mountWithCleanup(WebClientOdex); - await animationFrame(); - - await getService("action").doAction({ - xml_id: "test", - id: 1312, - name: "test", - res_id: 1, - res_model: "account.bank.statement.line", - type: "ir.actions.act_window", - views: [[false, "kanban"], [false, "list"]], - }); - - expect("button.o_switch_view.o_list[data-tooltip='List']").toHaveCount(1); - await contains("button.o_switch_view.o_list[data-tooltip='List']").click(); - expect(".o_list_renderer .o_list_controller button.dropdown-toggle").toHaveCount(1); - await contains(".o_list_renderer .o_list_controller button.dropdown-toggle").click(); - expect(".dropdown-item-studio").toHaveCount(0); -}); - -test("x2many should not be editable", async () => { - class Bar extends models.Model {} - defineModels([Bar]); - Foo._fields.o2m = fields.One2many({ relation: "bar" }); - - await mountView({ - type: "form", - resModel: "foo", - arch: /* xml */ ` -
- - - - - - - - -
- - - `, - }); - expect(".o_optional_columns_dropdown_toggle").toHaveCount(0); - await click(".nav-link:eq(1)"); - await animationFrame(); - await click(".nav-link:eq(0)"); - await animationFrame(); - expect(".o_field_widget").toHaveCount(1); - expect(".o_optional_columns_dropdown_toggle").toHaveCount(0); -}); - -test("upsell studio feature is not polluted by another view", async () => { - class Partner extends models.Model { - name = fields.Char(); - - _views = { - list: ` `, - }; - } - - defineModels([Partner]); - - await mountWithCleanup(WebClientOdex); - await animationFrame(); - - await getService("action").doAction({ - xml_id: "editable", - id: 999, - type: "ir.actions.act_window", - views: [[false, "list"]], - res_model: "partner", - }); - - await click(".o_optional_columns_dropdown_toggle"); - await animationFrame(); - expect(".dropdown-item").toHaveCount(2); - expect(".dropdown-item-studio").toHaveCount(1); - - await getService("action").doAction({ - id: 99, - xml_id: "in_dialog", - type: "ir.actions.act_window", - views: [[false, "list"]], - res_model: "partner", - target: "new", - }); - - await click(".modal .o_optional_columns_dropdown_toggle"); - await animationFrame(); - let dropdown = getDropdownMenu(".modal .o_optional_columns_dropdown"); - expect(queryAll(".dropdown-item", { root: dropdown })).toHaveCount(1); - expect(queryAll(".dropdown-item-studio", { root: dropdown })).toHaveCount(0); - await click(".modal-header .btn-close"); - await animationFrame(); - expect(".modal").toHaveCount(0); - - await click(".o_optional_columns_dropdown_toggle"); - await animationFrame(); - expect(".o-dropdown--menu").toHaveCount(0); - await click(".o_optional_columns_dropdown_toggle"); - await animationFrame(); - - dropdown = getDropdownMenu(".o_optional_columns_dropdown"); - expect(queryAll(".dropdown-item", { root: dropdown })).toHaveCount(2); - expect(queryAll(".dropdown-item-studio", { root: dropdown })).toHaveCount(1); -}); diff --git a/odex30_base/odex30_web/static/tests/webclient/action_manager_mobile.test.js b/odex30_base/odex30_web/static/tests/webclient/action_manager_mobile.test.js deleted file mode 100644 index 16f7303..0000000 --- a/odex30_base/odex30_web/static/tests/webclient/action_manager_mobile.test.js +++ /dev/null @@ -1,164 +0,0 @@ -import { describe, expect, test } from "@odoo/hoot"; -import { click } from "@odoo/hoot-dom"; -import { animationFrame } from "@odoo/hoot-mock"; -import { - defineActions, - defineModels, - getService, - fields, - models, - mountWithCleanup, - onRpc, - stepAllNetworkCalls, -} from "@web/../tests/web_test_helpers"; - -import { redirect } from "@web/core/utils/urls"; -import { WebClientOdex } from "@odex30_web/webclient/webclient"; - -class Partner extends models.Model { - name = fields.Char(); - - _records = [ - { id: 1, name: "First record" }, - { id: 2, name: "Second record" }, - ]; - _views = { - form: ` -
- - - -
- `, - kanban: ` - - - - - - - - `, - list: ``, - }; -} - -defineModels([Partner]); - -defineActions([ - { - id: 1, - name: "Partners Action 1", - res_model: "partner", - views: [ - [false, "list"], - [false, "kanban"], - [false, "form"], - ], - }, - { - id: 2, - name: "Partners Action 2", - res_model: "partner", - views: [ - [false, "list"], - [false, "form"], - ], - }, -]); - -describe.current.tags("mobile"); - -test("uses a mobile-friendly view by default (if possible)", async () => { - onRpc("has_group", () => true); - - await mountWithCleanup(WebClientOdex); - await animationFrame(); - // should default on a mobile-friendly view (kanban) for action 1 - await getService("action").doAction(1); - - expect(".o_list_view").toHaveCount(0); - expect(".o_kanban_view").toHaveCount(1); - - // there is no mobile-friendly view for action 2, should use the first one (list) - await getService("action").doAction(2); - - expect(".o_list_view").toHaveCount(1); - expect(".o_kanban_view").toHaveCount(0); -}); - -test("lazy load mobile-friendly view", async () => { - stepAllNetworkCalls(); - - redirect("/odoo/action-1/new"); - await mountWithCleanup(WebClientOdex); - await animationFrame(); - - expect(".o_list_view").toHaveCount(0); - expect(".o_kanban_view").toHaveCount(0); - expect(".o_form_view").toHaveCount(1); - - // go back to lazy loaded view - await click(".o_breadcrumb .o_back_button"); - await animationFrame(); - expect(".o_list_view").toHaveCount(0); - expect(".o_form_view").toHaveCount(0); - expect(".o_kanban_view").toHaveCount(1); - - expect.verifySteps([ - "/web/webclient/translations", - "/web/webclient/load_menus", - "/web/action/load", - "get_views", - "onchange", // default_get/onchange to open form view - "web_search_read", // web search read when coming back to Kanban - ]); -}); - -test("lazy load mobile-friendly view; legacy url", async () => { - stepAllNetworkCalls(); - - redirect("/web#action=1&view_type=form"); - await mountWithCleanup(WebClientOdex); - await animationFrame(); - - expect(".o_list_view").toHaveCount(0); - expect(".o_kanban_view").toHaveCount(0); - expect(".o_form_view").toHaveCount(1); - - // go back to lazy loaded view - await click(".o_breadcrumb .o_back_button"); - await animationFrame(); - expect(".o_list_view").toHaveCount(0); - expect(".o_form_view").toHaveCount(0); - expect(".o_kanban_view").toHaveCount(1); - - expect.verifySteps([ - "/web/webclient/translations", - "/web/webclient/load_menus", - "/web/action/load", - "get_views", - "onchange", // default_get/onchange to open form view - "web_search_read", // web search read when coming back to Kanban - ]); -}); - -test("view switcher button should be displayed in dropdown on mobile screens", async () => { - // This test will spawn a kanban view (mobile friendly). - // so, the "legacy" code won't be tested here. - await mountWithCleanup(WebClientOdex); - await animationFrame(); - - await getService("action").doAction(1); - - expect(".o_control_panel .o_cp_switch_buttons > button").toHaveCount(1); - expect(".o_control_panel .o_cp_switch_buttons .o_switch_view.o_kanban").toHaveCount(0); - expect(".o_control_panel .o_cp_switch_buttons button.o_switch_view").toHaveCount(0); - - expect(".o_control_panel .o_cp_switch_buttons > button > i").toHaveClass("oi-view-kanban"); - await click(".o_control_panel .o_cp_switch_buttons > button"); - await animationFrame(); - - expect(".dropdown-item:has(.oi-view-kanban)").toHaveClass("selected"); - expect(".dropdown-item:has(.oi-view-list)").not.toHaveClass("selected"); -}); diff --git a/odex30_base/odex30_web/static/tests/webclient/clickbot.test.js b/odex30_base/odex30_web/static/tests/webclient/clickbot.test.js deleted file mode 100644 index c95039e..0000000 --- a/odex30_base/odex30_web/static/tests/webclient/clickbot.test.js +++ /dev/null @@ -1,176 +0,0 @@ -import { beforeEach, describe, expect, test } from "@odoo/hoot"; -import { Deferred, mockDate } from "@odoo/hoot-mock"; -import { - defineActions, - defineMenus, - defineModels, - fields, - models, - mountWithCleanup, - onRpc, - patchWithCleanup, -} from "@web/../tests/web_test_helpers"; - -import { browser } from "@web/core/browser/browser"; -import { WebClient } from "@web/webclient/webclient"; -import { SUCCESS_SIGNAL } from "@web/webclient/clickbot/clickbot"; - -class Foo extends models.Model { - foo = fields.Char(); - bar = fields.Boolean(); - date = fields.Date(); - - _records = [ - { id: 1, bar: true, foo: "yop", date: "2017-01-25" }, - { id: 2, bar: true, foo: "blip" }, - { id: 3, bar: true, foo: "gnap" }, - { id: 4, bar: false, foo: "blip" }, - ]; - - _views = { - search: /* xml */ ` - - - - - `, - list: /* xml */ ` - - - - `, - kanban: /* xml */ ` - - - - - - `, - }; -} - -describe.current.tags("desktop"); - -defineModels([Foo]); - -beforeEach(() => { - defineActions([ - { - id: 1001, - name: "App1", - res_model: "foo", - views: [ - [false, "list"], - [false, "kanban"], - ], - xml_id: "app1", - }, - { - id: 1002, - name: "App2 Menu 1", - res_model: "foo", - views: [[false, "kanban"]], - xml_id: "app2_menu1", - }, - { - id: 1022, - name: "App2 Menu 2", - res_model: "foo", - views: [[false, "list"]], - xml_id: "app2_menu2", - }, - ]); - defineMenus([ - { id: 1, name: "App1", appID: 1, actionID: 1001, xmlid: "app1" }, - { - id: 2, - children: [ - { - id: 3, - name: "menu 1", - appID: 2, - actionID: 1002, - xmlid: "app2_menu1", - }, - { - id: 4, - name: "menu 2", - appID: 2, - actionID: 1022, - xmlid: "app2_menu2", - }, - ], - name: "App2", - appID: 2, - actionID: 1002, - xmlid: "app2", - }, - ]); -}); - -test("clickbot clickeverywhere test", async () => { - onRpc("has_group", () => true); - mockDate("2017-10-08T15:35:11.000"); - const clickEverywhereDef = new Deferred(); - patchWithCleanup(browser, { - console: { - log: (msg) => { - expect.step(msg); - if (msg === SUCCESS_SIGNAL) { - clickEverywhereDef.resolve(); - } - }, - error: (msg) => { - expect.step(msg); - clickEverywhereDef.resolve(); - }, - }, - }); - const webClient = await mountWithCleanup(WebClient); - patchWithCleanup(odoo, { - __WOWL_DEBUG__: { root: webClient }, - }); - window.clickEverywhere(); - await clickEverywhereDef; - expect.verifySteps([ - "Clicking on: apps menu toggle button", - "Testing app menu: app1", - "Testing menu App1 app1", - 'Clicking on: menu item "App1"', - "Testing 2 filters", - 'Clicking on: filter "Not Bar"', - 'Clicking on: filter "Date"', - 'Clicking on: filter option "October"', - "Testing view switch: kanban", - "Clicking on: kanban view switcher", - "Testing 2 filters", - 'Clicking on: filter "Not Bar"', - 'Clicking on: filter "Date"', - 'Clicking on: filter option "October"', - "Clicking on: apps menu toggle button", - "Testing app menu: app2", - "Testing menu App2 app2", - 'Clicking on: menu item "App2"', - "Testing 2 filters", - 'Clicking on: filter "Not Bar"', - 'Clicking on: filter "Date"', - 'Clicking on: filter option "October"', - "Testing menu menu 1 app2_menu1", - 'Clicking on: menu item "menu 1"', - "Testing 2 filters", - 'Clicking on: filter "Not Bar"', - 'Clicking on: filter "Date"', - 'Clicking on: filter option "October"', - "Testing menu menu 2 app2_menu2", - 'Clicking on: menu item "menu 2"', - "Testing 2 filters", - 'Clicking on: filter "Not Bar"', - 'Clicking on: filter "Date"', - 'Clicking on: filter option "October"', - "Successfully tested 2 apps", - "Successfully tested 2 menus", - "Successfully tested 0 modals", - "Successfully tested 10 filters", - SUCCESS_SIGNAL, - ]); -}); diff --git a/odex30_base/odex30_web/static/tests/webclient/expiration_panel.test.js b/odex30_base/odex30_web/static/tests/webclient/expiration_panel.test.js deleted file mode 100644 index 2a9bf4c..0000000 --- a/odex30_base/odex30_web/static/tests/webclient/expiration_panel.test.js +++ /dev/null @@ -1,615 +0,0 @@ -import { expect, test } from "@odoo/hoot"; -import { click, queryFirst, edit } from "@odoo/hoot-dom"; -import { animationFrame, mockDate, runAllTimers } from "@odoo/hoot-mock"; -import { - getService, - mockService, - mountWithCleanup, - onRpc, - patchWithCleanup, - serverState, -} from "@web/../tests/web_test_helpers"; - -import { session } from "@web/session"; -import { browser } from "@web/core/browser/browser"; -import { WebClientOdex } from "@odex30_web/webclient/webclient"; - -test("Expiration Panel one app installed", async () => { - mockDate("2019-10-10T12:00:00"); - - patchWithCleanup(session, { - expiration_date: "2019-11-09 12:00:00", - expiration_reason: "", - storeData: true, - warning: "admin", - }); - await mountWithCleanup(WebClientOdex); - await animationFrame(); - await getService("action").doAction("menu"); - - expect(".oe_instance_register").toHaveText("This database will expire in 1 month."); - - expect(".database_expiration_panel").toHaveClass("alert-info"); - - // Close the expiration panel - await click(".oe_instance_hide_panel"); - await animationFrame(); - - expect(".database_expiration_panel").toHaveCount(0); -}); - -test("Expiration Panel one app installed, buy subscription", async () => { - expect.assertions(6); - - mockDate("2019-10-10T12:00:00"); - patchWithCleanup(session, { - expiration_date: "2019-10-24 12:00:00", - expiration_reason: "demo", - storeData: true, // used by subscription service to know whether mail is installed - warning: "admin", - }); - onRpc("res.users", "search_count", () => 7); - await mountWithCleanup(WebClientOdex); - await animationFrame(); - await runAllTimers(); - - expect(".oe_instance_register").toHaveText( - "This demo database will expire in 14 days. Register your subscription or buy a subscription." - ); - - expect(".database_expiration_panel").toHaveClass("alert-warning", { - message: "Color should be orange", - }); - - expect(".oe_instance_register_show").toHaveCount(1, { - message: "Part 'Register your subscription'", - }); - expect(".oe_instance_buy").toHaveCount(1, { message: "Part 'buy a subscription'" }); - expect(".oe_instance_register_form").toHaveCount(0, { - message: "There should be no registration form", - }); - - // Click on 'buy subscription' - await click(".oe_instance_buy"); - await animationFrame(); - - expect(browser.location.href).toBe("https://www.odoo.com/odoo-enterprise/upgrade?num_users=7"); -}); - -test("Expiration Panel one app installed, try several times to register subscription", async () => { - expect.assertions(33); - - mockDate("2019-10-10T12:00:00"); - - let callToGetParamCount = 0; - - patchWithCleanup(session, { - expiration_date: "2019-10-15 12:00:00", - expiration_reason: "trial", - storeData: true, // used by subscription service to know whether mail is installed - warning: "admin", - }); - - mockService("notification", { - add: (message, options) => { - expect.step(JSON.stringify({ message, options })); - }, - }); - onRpc("get_param", ({ args }) => { - expect.step("get_param"); - if (args[0] === "database.already_linked_subscription_url") { - return false; - } - if (args[0] === "database.already_linked_email") { - return "super_company_admin@gmail.com"; - } - expect(args[0]).toBe("database.expiration_date"); - callToGetParamCount++; - if (callToGetParamCount <= 3) { - return "2019-10-15 12:00:00"; - } else { - return "2019-11-15 12:00:00"; - } - }); - onRpc("set_param", ({ args }) => { - expect.step("set_param"); - expect(args[0]).toBe("database.enterprise_code"); - if (callToGetParamCount === 1) { - expect(args[1]).toBe("ABCDEF"); - } else { - expect(args[1]).toBe("ABC"); - } - return true; - }); - onRpc("update_notification", ({ args }) => { - expect.step("update_notification"); - expect(args[0]).toBeInstanceOf(Array); - expect(args[0]).toHaveLength(0); - return true; - }); - onRpc("res.users", "search_count", () => 7); - await mountWithCleanup(WebClientOdex); - await animationFrame(); - - expect(".oe_instance_register").toHaveText( - "This database will expire in 5 days. Register your subscription or buy a subscription." - ); - - expect(".database_expiration_panel").toHaveClass("alert-danger", { - message: "Color should be red", - }); - - expect(".oe_instance_register_show").toHaveCount(1, { - message: "Part 'Register your subscription'", - }); - expect(".oe_instance_buy").toHaveCount(1, { message: "Part 'buy a subscription'" }); - expect(".oe_instance_register_form").toHaveCount(0, { - message: "There should be no registration form", - }); - - // Click on 'buy subscription' - await click(".oe_instance_register_show"); - await animationFrame(); - - expect(".oe_instance_register_form").toHaveCount(1, { - message: "there should be a registration form", - }); - expect('.oe_instance_register_form input[placeholder="Paste code here"]').toHaveCount(1, { - message: "with an input with place holder 'Paste code here'", - }); - expect(".oe_instance_register_form button").toHaveCount(1, { - message: "and a button 'Register'", - }); - expect(".oe_instance_register_form button").toHaveText("Register"); - - await click(".oe_instance_register_form button"); - await animationFrame(); - - expect(".oe_instance_register_form").toHaveCount(1, { - message: "there should be a registration form", - }); - expect('.oe_instance_register_form input[placeholder="Paste code here"]').toHaveCount(1, { - message: "with an input with place holder 'Paste code here'", - }); - expect(".oe_instance_register_form button").toHaveCount(1, { - message: "and a button 'Register'", - }); - - await click(".oe_instance_register_form input"); - await edit("ABCDEF"); - await animationFrame(); - await click(".oe_instance_register_form button"); - await animationFrame(); - - expect(queryFirst(".oe_instance_register")).toHaveText( - "Something went wrong while registering your database. You can try again or contact Odoo Support." - ); - expect(".database_expiration_panel").toHaveClass("alert-danger", { - message: "Color should be red", - }); - expect("span.oe_instance_error").toHaveCount(1); - expect(".oe_instance_register_form").toHaveCount(1, { - message: "there should be a registration form", - }); - expect('.oe_instance_register_form input[placeholder="Paste code here"]').toHaveCount(1, { - message: "with an input with place holder 'Paste code here'", - }); - expect(".oe_instance_register_form button").toHaveCount(1, { - message: "and a button 'Register'", - }); - expect(".oe_instance_register_form button").toHaveText("Retry"); - - await click(".oe_instance_register_form input"); - await edit("ABC"); - await animationFrame(); - await click(".oe_instance_register_form button"); - await animationFrame(); - - expect(".database_expiration_panel").toHaveCount(0, { - message: "expiration panel should be gone", - }); - - expect.verifySteps([ - // second try to submit - "get_param", - "set_param", - "update_notification", - "get_param", - "get_param", - "get_param", - // third try - "get_param", - "set_param", - "update_notification", - "get_param", - "get_param", - "get_param", - `{"message":"Thank you, your registration was successful! Your database is valid until November 15, 2019.","options":{"type":"success"}}`, - ]); -}); - -test("Expiration Panel one app installed, subscription already linked", async () => { - expect.assertions(5); - - mockDate("2019-10-10T12:00:00"); - - let getExpirationDateCount = 0; - - patchWithCleanup(session, { - expiration_date: "2019-10-15 12:00:00", - expiration_reason: "trial", - storeData: true, // used by subscription service to know whether mail is installed - warning: "admin", - }); - onRpc("/already/linked/send/mail/url", () => ({ - result: false, - reason: "By design", - })); - onRpc("get_param", ({ args }) => { - expect.step("get_param"); - if (args[0] === "database.expiration_date") { - getExpirationDateCount++; - if (getExpirationDateCount === 1) { - return "2019-10-15 12:00:00"; - } else { - return "2019-11-17 12:00:00"; - } - } - if (args[0] === "database.already_linked_subscription_url") { - return "www.super_company.com"; - } - if (args[0] === "database.already_linked_send_mail_url") { - return "/already/linked/send/mail/url"; - } - if (args[0] === "database.already_linked_email") { - return "super_company_admin@gmail.com"; - } - }); - onRpc("set_param", () => { - expect.step("set_param"); - return true; - }); - onRpc("update_notification", () => { - expect.step("update_notification"); - return true; - }); - await mountWithCleanup(WebClientOdex); - await animationFrame(); - - expect(".oe_instance_register").toHaveText( - "This database will expire in 5 days. Register your subscription or buy a subscription." - ); - // Click on 'register your subscription' - await click(".oe_instance_register_show"); - await animationFrame(); - await click(".oe_instance_register_form input"); - await edit("ABC"); - await click(".oe_instance_register_form button"); - await animationFrame(); - - expect(".oe_instance_register.oe_database_already_linked").toHaveText( - `Your subscription is already linked to a database.\nSend an email to the subscription owner to confirm the change, enter a new code or buy a subscription.` - ); - - await click("a.oe_contract_send_mail"); - await animationFrame(); - expect(".database_expiration_panel").toHaveClass("alert-danger", { - message: "Color should be red", - }); - - expect(".oe_instance_register.oe_database_already_linked").toHaveText( - `Your subscription is already linked to a database.\nSend an email to the subscription owner to confirm the change, enter a new code or buy a subscription.\n\nUnable to send the instructions by email, please contact the Odoo Support\nError reason: By design` - ); - - expect.verifySteps([ - "get_param", - "set_param", - "update_notification", - "get_param", - "get_param", - "get_param", - "get_param", - ]); -}); - -test("One app installed, database expired", async () => { - expect.assertions(8); - - mockDate("2019-10-10T12:00:00"); - - let callToGetParamCount = 0; - - patchWithCleanup(session, { - expiration_date: "2019-10-08 12:00:00", - expiration_reason: "trial", - storeData: true, // used by subscription service to know whether mail is installed - warning: "admin", - }); - onRpc("/already/linked/send/mail/url", () => ({ - result: false, - reason: "By design", - })); - onRpc("get_param", ({ args }) => { - if (args[0] === "database.already_linked_subscription_url") { - return false; - } - callToGetParamCount++; - if (callToGetParamCount === 1) { - return "2019-10-09 12:00:00"; - } else { - return "2019-11-09 12:00:00"; - } - }); - onRpc("set_param", () => true); - onRpc("update_notification", () => true); - await mountWithCleanup(WebClientOdex); - await animationFrame(); - - expect(".oe_instance_register").toHaveText( - "This database has expired. Register your subscription or buy a subscription." - ); - expect(".o_blockUI").toHaveCount(1, { message: "UI should be blocked" }); - - expect(".database_expiration_panel").toHaveClass("alert-danger", { - message: "Color should be red", - }); - expect(".oe_instance_register_show").toHaveCount(1, { - message: "Part 'Register your subscription'", - }); - expect(".oe_instance_buy").toHaveCount(1, { message: "Part 'buy a subscription'" }); - - expect(".oe_instance_register_form").toHaveCount(0); - - // Click on 'Register your subscription' - await click(".oe_instance_register_show"); - await animationFrame(); - await click(".oe_instance_register_form input"); - await edit("ABC"); - await click(".oe_instance_register_form button"); - await animationFrame(); - - expect(".oe_instance_register").toHaveText( - "Thank you, your registration was successful! Your database is valid until November 9, 2019." - ); - expect(".o_blockUI").toHaveCount(0, { message: "UI should no longer be blocked" }); -}); - -test("One app installed, renew", async () => { - expect.assertions(7); - - mockDate("2019-10-10T12:00:00"); - - patchWithCleanup(session, { - expiration_date: "2019-10-20 12:00:00", - expiration_reason: "renewal", - storeData: true, // used by subscription service to know whether mail is installed - warning: "admin", - }); - onRpc("get_param", ({ args }) => { - expect.step("get_param"); - expect(args[0]).toBe("database.enterprise_code"); - return "ABC"; - }); - await mountWithCleanup(WebClientOdex); - await animationFrame(); - - expect(".oe_instance_register").toHaveText( - "Your subscription expired 9 days ago. This database will be blocked soon.\n" + - "Renew now\n" + - "I paid, please recheck!" - ); - - expect(".database_expiration_panel").toHaveClass("alert-warning", { - message: "Color should be orange", - }); - expect(".oe_instance_renew").toHaveCount(1, { message: "Part 'Register your subscription'" }); - expect("a.check_enterprise_status").toHaveCount(1, { - message: "there should be a button for status checking", - }); - - expect(".oe_instance_register_form").toHaveCount(0); - - // Click on 'Renew your subscription' - await click(".oe_instance_renew"); - await animationFrame(); - - expect.verifySteps(["get_param"]); -}); - -test("One app installed, check status and get success", async () => { - expect.assertions(4); - - mockDate("2019-10-10T12:00:00"); - - patchWithCleanup(session, { - expiration_date: "2019-10-20 12:00:00", - expiration_reason: "renewal", - storeData: true, // used by subscription service to know whether mail is installed - warning: "admin", - }); - onRpc("get_param", ({ args }) => { - expect.step("get_param"); - expect(args[0]).toBe("database.expiration_date"); - return "2019-10-24 12:00:00"; - }); - onRpc("update_notification", () => { - expect.step("update_notification"); - return true; - }); - await mountWithCleanup(WebClientOdex); - await animationFrame(); - - // click on "I paid, please recheck!" - expect("a.check_enterprise_status").toHaveText("I paid, please recheck!"); - await click("a.check_enterprise_status"); - await animationFrame(); - - expect(".oe_instance_register.oe_subscription_updated").toHaveText( - "Your subscription was updated and is valid until October 24, 2019." - ); - - expect.verifySteps(["update_notification", "get_param"]); -}); - -// Why would we want to reload the page when we check the status and it hasn't changed? -test.skip("One app installed, check status and get page reload", async () => { - expect.assertions(4); - - mockDate("2019-10-10T12:00:00"); - - patchWithCleanup(session, { - expiration_date: "2019-10-20 12:00:00", - expiration_reason: "renewal", - storeData: true, // used by subscription service to know whether mail is installed - warning: "admin", - }); - onRpc("get_param", () => { - expect.step("get_param"); - return "2019-10-20 12:00:00"; - }); - onRpc("update_notification", () => { - expect.step("update_notification"); - return true; - }); - await mountWithCleanup(WebClientOdex); - await animationFrame(); - - // click on "I paid, please recheck!" - await click("a.check_enterprise_status"); - await animationFrame(); - - expect.verifySteps(["update_notification", "get_param", "reloadPage"]); -}); - -test("One app installed, upgrade database", async () => { - expect.assertions(4); - - mockDate("2019-10-10T12:00:00"); - - patchWithCleanup(session, { - expiration_date: "2019-10-20 12:00:00", - expiration_reason: "upsell", - storeData: true, // used by subscription service to know whether mail is installed - warning: "admin", - }); - onRpc("get_param", ({ args }) => { - expect.step("get_param"); - expect(args[0]).toBe("database.enterprise_code"); - return "ABC"; - }); - onRpc("search_count", () => { - expect.step("search_count"); - return 13; - }); - onRpc("update_notification", () => true); - await mountWithCleanup(WebClientOdex); - await animationFrame(); - await runAllTimers(); - - expect(".oe_instance_register").toHaveText( - "This database will expire in 10 days. You have more users or more apps installed than your subscription allows.\n\n" + - "Upgrade your subscription\n" + - "I paid, please recheck!" - ); - - await click("a.oe_instance_upsell"); - await animationFrame(); - - expect.verifySteps(["get_param", "search_count"]); - expect(browser.location.href).toBe( - "https://www.odoo.com/odoo-enterprise/upsell?num_users=13&contract=ABC" - ); -}); - -test("One app installed, message for non admin user", async () => { - expect.assertions(2); - - mockDate("2019-10-10T12:00:00"); - - patchWithCleanup(session, { - expiration_date: "2019-11-08 12:00:00", - expiration_reason: "", - storeData: true, // used by subscription service to know whether mail is installed - warning: "user", - }); - await mountWithCleanup(WebClientOdex); - await animationFrame(); - - expect(".oe_instance_register").toHaveText( - "This database will expire in 29 days. Log in as an administrator to correct the issue." - ); - - expect(".database_expiration_panel").toHaveClass("alert-info", { - message: "Color should be grey", - }); -}); - -test("One app installed, navigation to renewal page", async () => { - expect.assertions(8); - - mockDate("2019-11-10T00:00:00"); - - patchWithCleanup(session, { - expiration_date: "2019-10-20 12:00:00", - expiration_reason: "renewal", - storeData: true, // used by subscription service to know whether mail is installed - warning: "admin", - }); - onRpc("get_param", ({ args }) => { - expect.step("get_param"); - expect(args[0]).toBe("database.enterprise_code"); - return "ABC"; - }); - onRpc("update_notification", () => { - expect.step("update_notification"); - return true; - }); - await mountWithCleanup(WebClientOdex); - await animationFrame(); - await runAllTimers(); - - expect(".oe_instance_register").toHaveText( - "This database has expired.\nRenew now\nI paid, please recheck!" - ); - - expect(".database_expiration_panel").toHaveClass("alert-danger"); - expect(".oe_instance_renew").toHaveCount(1, { message: "Part 'Register your subscription'" }); - expect("a.check_enterprise_status").toHaveCount(1, { - message: "there should be a button for status checking", - }); - - expect(".oe_instance_register_form").toHaveCount(0); - - // Click on 'Renew your subscription' - await click(".oe_instance_renew"); - await animationFrame(); - - expect(browser.location.href).toBe("https://www.odoo.com/odoo-enterprise/renew?contract=ABC"); - - expect.verifySteps(["get_param"]); -}); - -test("One app installed, different locale (arabic)", async () => { - expect.assertions(1); - - mockDate("2019-25-09T12:00:00"); - - patchWithCleanup(session, { - expiration_date: "2019-10-20 12:00:00", - expiration_reason: "renewal", - storeData: true, // used by subscription service to know whether mail is installed - warning: "admin", - }); - serverState.lang = "ar-001"; - onRpc("get_param", () => "2019-11-09 12:00:00"); - onRpc("update_notification", () => true); - await mountWithCleanup(WebClientOdex); - await animationFrame(); - - await click("a.check_enterprise_status"); - await animationFrame(); - - expect(".oe_instance_register").toHaveText( - "Your subscription was updated and is valid until ٩ نوفمبر ٢٠١٩." - ); -}); diff --git a/odex30_base/odex30_web/static/tests/webclient/home_menu.test.js b/odex30_base/odex30_web/static/tests/webclient/home_menu.test.js deleted file mode 100644 index 13020ed..0000000 --- a/odex30_base/odex30_web/static/tests/webclient/home_menu.test.js +++ /dev/null @@ -1,353 +0,0 @@ -import { describe, expect, test } from "@odoo/hoot"; -import { click, drag, keyDown, pointerDown, queryFirst } from "@odoo/hoot-dom"; -import { advanceTime, animationFrame, mockDate, mockTouch } from "@odoo/hoot-mock"; -import { - getService, - mountWithCleanup, - onRpc, - patchWithCleanup, -} from "@web/../tests/web_test_helpers"; - -import { reactive } from "@odoo/owl"; -import { session } from "@web/session"; -import { HomeMenu } from "@odex30_web/webclient/home_menu/home_menu"; -import { reorderApps } from "@web/webclient/menus/menu_helpers"; - -async function walkOn(path) { - for (const step of path) { - await keyDown(`${step.shiftKey ? "shift+" : ""}${step.key}`); - await animationFrame(); - expect(`.o_menuitem:eq(${step.index})`).toHaveClass("o_focused", { - message: `step ${step.number}`, - }); - } -} - -const getDefaultHomeMenuProps = () => { - const apps = [ - { - actionID: 121, - href: "/odoo/action-121", - appID: 1, - id: 1, - label: "Discuss", - parents: "", - webIcon: false, - xmlid: "app.1", - }, - { - actionID: 122, - href: "/odoo/action-122", - appID: 2, - id: 2, - label: "Calendar", - parents: "", - webIcon: false, - xmlid: "app.2", - }, - { - actionID: 123, - href: "/odoo/contacts", - appID: 3, - id: 3, - label: "Contacts", - parents: "", - webIcon: false, - xmlid: "app.3", - }, - ]; - return { apps, reorderApps: (order) => reorderApps(apps, order) }; -}; - -describe.current.tags("desktop"); - -test("ESC Support", async () => { - await mountWithCleanup(HomeMenu, { - props: getDefaultHomeMenuProps(), - }); - patchWithCleanup(getService("home_menu"), { - async toggle(show) { - expect.step(`toggle ${show}`); - }, - }); - await keyDown("escape"); - expect.verifySteps(["toggle false"]); -}); - -test("Click on an app", async () => { - await mountWithCleanup(HomeMenu, { - props: getDefaultHomeMenuProps(), - }); - patchWithCleanup(getService("menu"), { - async selectMenu(menu) { - expect.step(`selectMenu ${menu.id}`); - }, - }); - await click(".o_menuitem:eq(0)"); - await animationFrame(); - expect.verifySteps(["selectMenu 1"]); -}); - -test("Display Expiration Panel (no module installed)", async () => { - mockDate("2019-10-09T00:00:00"); - - patchWithCleanup(session, { - expiration_date: "2019-11-01 12:00:00", - expiration_reason: "", - isMailInstalled: false, - warning: "admin", - }); - - await mountWithCleanup(HomeMenu, { - props: getDefaultHomeMenuProps(), - }); - - expect(".database_expiration_panel").toHaveCount(1); - expect(".database_expiration_panel .oe_instance_register").toHaveText( - "You will be able to register your database once you have installed your first app.", - { message: "There should be an expiration panel displayed" } - ); - - // Close the expiration panel - await click(".database_expiration_panel .oe_instance_hide_panel"); - await animationFrame(); - expect(".database_expiration_panel").toHaveCount(0); -}); - -test("Navigation (only apps, only one line)", async () => { - expect.assertions(8); - - const homeMenuProps = { - apps: new Array(3).fill().map((x, i) => { - return { - actionID: 120 + i, - href: "/odoo/act" + (120 + i), - appID: i + 1, - id: i + 1, - label: `0${i}`, - parents: "", - webIcon: false, - xmlid: `app.${i}`, - }; - }), - reorderApps: (order) => reorderApps(homeMenuProps.apps, order), - }; - await mountWithCleanup(HomeMenu, { - props: homeMenuProps, - }); - - const path = [ - { number: 0, key: "ArrowDown", index: 0 }, - { number: 1, key: "ArrowRight", index: 1 }, - { number: 2, key: "Tab", index: 2 }, - { number: 3, key: "ArrowRight", index: 0 }, - { number: 4, key: "Tab", shiftKey: true, index: 2 }, - { number: 5, key: "ArrowLeft", index: 1 }, - { number: 6, key: "ArrowDown", index: 1 }, - { number: 7, key: "ArrowUp", index: 1 }, - ]; - - await walkOn(path); -}); - -test("Navigation (only apps, two lines, one incomplete)", async () => { - expect.assertions(19); - - const homeMenuProps = { - apps: new Array(8).fill().map((x, i) => { - return { - actionID: 121, - href: "/odoo/action-121", - appID: i + 1, - id: i + 1, - label: `0${i}`, - parents: "", - webIcon: false, - xmlid: `app.${i}`, - }; - }), - reorderApps: (order) => reorderApps(homeMenuProps.apps, order), - }; - await mountWithCleanup(HomeMenu, { - props: homeMenuProps, - }); - - const path = [ - { number: 1, key: "ArrowRight", index: 0 }, - { number: 2, key: "ArrowUp", index: 6 }, - { number: 3, key: "ArrowUp", index: 0 }, - { number: 4, key: "ArrowDown", index: 6 }, - { number: 5, key: "ArrowDown", index: 0 }, - { number: 6, key: "ArrowRight", index: 1 }, - { number: 7, key: "ArrowRight", index: 2 }, - { number: 8, key: "ArrowUp", index: 7 }, - { number: 9, key: "ArrowUp", index: 1 }, - { number: 10, key: "ArrowRight", index: 2 }, - { number: 11, key: "ArrowDown", index: 7 }, - { number: 12, key: "ArrowDown", index: 1 }, - { number: 13, key: "ArrowUp", index: 7 }, - { number: 14, key: "ArrowRight", index: 6 }, - { number: 15, key: "ArrowLeft", index: 7 }, - { number: 16, key: "ArrowUp", index: 1 }, - { number: 17, key: "ArrowLeft", index: 0 }, - { number: 18, key: "ArrowLeft", index: 5 }, - { number: 19, key: "ArrowRight", index: 0 }, - ]; - - await walkOn(path); -}); - -test("Navigation and open an app in the home menu", async () => { - expect.assertions(6); - - await mountWithCleanup(HomeMenu, { - props: getDefaultHomeMenuProps(), - }); - patchWithCleanup(getService("menu"), { - async selectMenu(menu) { - expect.step(`selectMenu ${menu.id}`); - }, - }); - // No app selected so nothing to open - await keyDown("enter"); - expect.verifySteps([]); - - const path = [ - { number: 0, key: "ArrowDown", index: 0 }, - { number: 1, key: "ArrowRight", index: 1 }, - { number: 2, key: "Tab", index: 2 }, - { number: 3, key: "shift+Tab", index: 1 }, - ]; - - await walkOn(path); - - // open first app (Calendar) - await keyDown("enter"); - - expect.verifySteps(["selectMenu 2"]); -}); - -test("Reorder apps in home menu using drag and drop", async () => { - const homeMenuProps = { - apps: reactive( - new Array(8).fill().map((x, i) => { - return { - actionID: 121, - href: "/odoo/action-121", - appID: i + 1, - id: i + 1, - label: `0${i}`, - parents: "", - webIcon: false, - xmlid: `app.${i}`, - }; - }) - ), - reorderApps: (order) => reorderApps(homeMenuProps.apps, order), - }; - onRpc("set_res_users_settings", () => { - expect.step(`set_res_users_settings`); - return { - id: 1, - homemenu_config: '["app.1","app.2","app.3","app.0","app.4","app.5","app.6","app.7"]', - }; - }); - await mountWithCleanup(HomeMenu, { - props: homeMenuProps, - }); - - const { moveTo, drop } = await drag(".o_draggable:first-child"); - await advanceTime(250); - expect(".o_draggable:first-child a").not.toHaveClass("o_dragged_app"); - await advanceTime(250); - expect(".o_draggable:first-child a").toHaveClass("o_dragged_app"); - await moveTo(".o_draggable:first-child", { - position: { - x: 70, - y: 35, - }, - relative: true, - }); - await drop(".o_draggable:not(.o_dragged):eq(3)"); - await animationFrame(); - expect.verifySteps(["set_res_users_settings"]); - expect(".o_app:eq(0)").toHaveAttribute("data-menu-xmlid", "app.1", { - message: "first displayed app has app.1 xmlid", - }); - expect(".o_app:eq(3)").toHaveAttribute("data-menu-xmlid", "app.0", { - message: "app 0 is now at 4th position", - }); -}); - -test("The HomeMenu input takes the focus when you press a key only if no other element is the activeElement", async () => { - await mountWithCleanup(HomeMenu, { - props: getDefaultHomeMenuProps(), - }); - expect(".o_search_hidden").toBeFocused(); - - const activeElement = document.createElement("div"); - getService("ui").activateElement(activeElement); - // remove the focus from the input - const otherInput = document.createElement("input"); - queryFirst(".o_home_menu").appendChild(otherInput); - await pointerDown(otherInput); - await pointerDown(document.body); - expect(".o_search_hidden").not.toBeFocused(); - - await keyDown("a"); - await animationFrame(); - expect(".o_search_hidden").not.toBeFocused(); - - getService("ui").deactivateElement(activeElement); - await keyDown("a"); - await animationFrame(); - expect(".o_search_hidden").toBeFocused(); -}); - -test("The HomeMenu input does not take the focus if it is already on another input", async () => { - await mountWithCleanup(HomeMenu, { - props: getDefaultHomeMenuProps(), - }); - expect(".o_search_hidden").toBeFocused(); - - const otherInput = document.createElement("input"); - queryFirst(".o_home_menu").appendChild(otherInput); - await pointerDown(otherInput); - await keyDown("a"); - await animationFrame(); - expect(".o_search_hidden").not.toBeFocused(); - - otherInput.remove(); - await keyDown("a"); - await animationFrame(); - expect(".o_search_hidden").toBeFocused(); -}); - -test("The HomeMenu input does not take the focus if it is already on a textarea", async () => { - await mountWithCleanup(HomeMenu, { - props: getDefaultHomeMenuProps(), - }); - expect(".o_search_hidden").toBeFocused(); - - const textarea = document.createElement("textarea"); - queryFirst(".o_home_menu").appendChild(textarea); - await pointerDown(textarea); - await keyDown("a"); - await animationFrame(); - expect(".o_search_hidden").not.toBeFocused(); - - textarea.remove(); - await keyDown("a"); - await animationFrame(); - expect(".o_search_hidden").toBeFocused(); -}); - -test("home search input shouldn't be focused on touch devices", async () => { - mockTouch(true); - await mountWithCleanup(HomeMenu, { - props: getDefaultHomeMenuProps(), - }); - expect(".o_search_hidden").not.toBeFocused({ - message: "home menu search input shouldn't have the focus", - }); -}); diff --git a/odex30_base/odex30_web/static/tests/webclient/webclient_enterprise.test.js b/odex30_base/odex30_web/static/tests/webclient/webclient_enterprise.test.js deleted file mode 100644 index ef36fdf..0000000 --- a/odex30_base/odex30_web/static/tests/webclient/webclient_enterprise.test.js +++ /dev/null @@ -1,798 +0,0 @@ -import { beforeEach, describe, expect, test } from "@odoo/hoot"; -import { click, keyDown, queryAll, queryFirst } from "@odoo/hoot-dom"; -import { animationFrame, Deferred, mockMatchMedia } from "@odoo/hoot-mock"; -import { Component, onMounted, xml } from "@odoo/owl"; -import { - clearRegistry, - contains, - defineActions, - defineMenus, - defineModels, - fields, - getMockEnv, - getService, - models, - mountWithCleanup, - onRpc, - patchWithCleanup, - serverState, - stepAllNetworkCalls, -} from "@web/../tests/web_test_helpers"; -import { browser } from "@web/core/browser/browser"; -import { router } from "@web/core/browser/router"; -import { registry } from "@web/core/registry"; -import { config as transitionConfig } from "@web/core/transition"; -import { user } from "@web/core/user"; -import { redirect } from "@web/core/utils/urls"; -import { UserMenu } from "@web/webclient/user_menu/user_menu"; -import { shareUrlMenuItem } from "@odex30_web/webclient/share_url/share_url"; -import { WebClientOdex } from "@odex30_web/webclient/webclient"; - -const actionRegistry = registry.category("actions"); - -/** - * @param {{ env: import("@web/env").OdooEnv }} [options] - */ -async function mountWebClientOdex(options) { - await mountWithCleanup(WebClientOdex, options); - // Wait for visual changes caused by a potential loadState - await animationFrame(); - // wait for BlankComponent - await animationFrame(); - // wait for the regular rendering - await animationFrame(); -} - -async function goToHomeMenu() { - await click(".o_menu_toggle"); - await animationFrame(); - - if (getMockEnv().isSmall) { - await click(queryFirst(".o_sidebar_topbar a.btn-primary", { root: document.body })); - await animationFrame(); - } -} - -defineActions([ - { - id: 1, - xml_id: "action_1", - name: "Partners Action 1", - res_model: "partner", - views: [[false, "kanban"]], - }, - { - id: 2, - xml_id: "action_2", - type: "ir.actions.server", - }, - { - id: 3, - xml_id: "action_3", - name: "Partners", - res_model: "partner", - views: [ - [false, "list"], - [false, "kanban"], - [false, "form"], - ], - }, - { - id: 4, - xml_id: "action_4", - name: "Partners Action 4", - res_model: "partner", - views: [ - [false, "kanban"], - [false, "list"], - [false, "form"], - ], - }, - { - id: 5, - xml_id: "action_5", - name: "Create a Partner", - res_model: "partner", - target: "new", - views: [[false, "form"]], - }, - { - id: 6, - xml_id: "action_6", - name: "Partner", - res_id: 2, - res_model: "partner", - target: "inline", - views: [[false, "form"]], - }, - { - id: 1001, - tag: "__test__client__action__", - target: "main", - type: "ir.actions.client", - params: { description: "Id 1" }, - }, - { - id: 1002, - tag: "__test__client__action__", - target: "main", - type: "ir.actions.client", - params: { description: "Id 2" }, - }, -]); - -defineMenus([ - { id: 0 }, // prevents auto-loading the first action - { id: 1, name: "App1", appID: 1, actionID: 1001, xmlid: "menu_1" }, - { id: 2, name: "App2", appID: 2, actionID: 1002, xmlid: "menu_2" }, -]); -class Partner extends models.Model { - name = fields.Char(); - foo = fields.Char(); - parent_id = fields.Many2one({ relation: "partner" }); - child_ids = fields.One2many({ relation: "partner", relation_field: "parent_id" }); - - _records = [ - { id: 1, name: "First record", foo: "yop", parent_id: 3 }, - { id: 2, name: "Second record", foo: "blip", parent_id: 3 }, - { id: 3, name: "Third record", foo: "gnap", parent_id: 1 }, - { id: 4, name: "Fourth record", foo: "plop", parent_id: 1 }, - { id: 5, name: "Fifth record", foo: "zoup", parent_id: 1 }, - ]; - _views = { - kanban: ` - - - - - - - - `, - list: ``, - form: ` -
-
-
- - - - -
- `, - search: ``, - }; -} -defineModels([Partner]); -class TestClientAction extends Component { - static template = xml` -
- ClientAction_ -
- `; - static props = ["*"]; - - setup() { - onMounted(() => { - this.env.config.setDisplayName(`Client action ${this.props.action.id}`); - }); - } -} - -onRpc("has_group", () => true); - -beforeEach(() => { - actionRegistry.add("__test__client__action__", TestClientAction); - patchWithCleanup(transitionConfig, { disabled: true }); -}); - -describe("basic flow with home menu", () => { - stepAllNetworkCalls(); - onRpc("partner", "get_formview_action", () => ({ - type: "ir.actions.act_window", - res_model: "partner", - view_type: "form", - view_mode: "form", - views: [[false, "form"]], - target: "current", - res_id: 2, - })); - defineMenus( - [ - { - id: 1, - name: "App1", - appID: 1, - actionID: 4, - xmlid: "menu_1", - }, - ], - { mode: "replace" } - ); - test("1 -- start up", async () => { - await mountWebClientOdex(); - expect.verifySteps(["/web/webclient/translations", "/web/webclient/load_menus"]); - expect(document.body).toHaveClass("o_home_menu_background"); - expect(".o_home_menu").toHaveCount(1); - expect(".o_menu_toggle").not.toBeVisible(); - expect(".o_app.o_menuitem").toHaveCount(1); - }); - - test("2 -- navbar updates on displaying an action", async () => { - await mountWebClientOdex(); - expect.verifySteps(["/web/webclient/translations", "/web/webclient/load_menus"]); - await contains(".o_app.o_menuitem").click(); - await animationFrame(); - expect.verifySteps(["/web/action/load", "get_views", "web_search_read"]); - expect(document.body).not.toHaveClass("o_home_menu_background"); - expect(".o_home_menu").toHaveCount(0); - expect(".o_kanban_view").toHaveCount(1); - expect(".o_menu_toggle").toBeVisible(); - expect(".o_menu_toggle").not.toHaveClass("o_menu_toggle_back"); - }); - - test("3 -- push another action in the breadcrumb", async () => { - await mountWebClientOdex(); - expect.verifySteps(["/web/webclient/translations", "/web/webclient/load_menus"]); - await contains(".o_app.o_menuitem").click(); - await animationFrame(); - expect.verifySteps(["/web/action/load", "get_views", "web_search_read"]); - expect(".o_kanban_view").toHaveCount(1); - await contains(".o_kanban_record").click(); - await animationFrame(); // there is another tick to update navbar and destroy HomeMenu - expect.verifySteps(["web_read"]); - expect(".o_menu_toggle").toBeVisible(); - expect(".o_form_view").toHaveCount(1); - expect(".o_breadcrumb .active").toHaveText("First record"); - }); - - test.tags("desktop"); - test("4 -- push a third action in the breadcrumb", async () => { - Partner._views["form"] = ` -
- - - - `; - await mountWebClientOdex(); - expect.verifySteps(["/web/webclient/translations", "/web/webclient/load_menus"]); - await contains(".o_app.o_menuitem").click(); - await animationFrame(); - expect.verifySteps(["/web/action/load", "get_views", "web_search_read"]); - expect(".o_kanban_view").toHaveCount(1); - await contains(".o_kanban_record").click(); - expect.verifySteps(["web_read"]); - await contains('.o_field_widget[name="parent_id"] .o_external_button', { - visible: false, - }).click(); - expect.verifySteps(["get_formview_action", "get_views", "web_read"]); - expect(".o_form_view").toHaveCount(1); - expect(".o_breadcrumb .active").toHaveText("Second record"); - // The third one is the active one - expect(".breadcrumb-item").toHaveCount(2); - }); - - test("5 -- switch to HomeMenu from an action with 2 breadcrumbs", async () => { - Partner._views["form"] = ` -
- - - - `; - await mountWebClientOdex(); - expect.verifySteps(["/web/webclient/translations", "/web/webclient/load_menus"]); - await contains(".o_app.o_menuitem").click(); - await animationFrame(); - expect.verifySteps(["/web/action/load", "get_views", "web_search_read"]); - expect(".o_kanban_view").toHaveCount(1); - await contains(".o_kanban_record").click(); - expect.verifySteps(["web_read"]); - await contains('.o_field_widget[name="parent_id"] .o_external_button', { - visible: false, - }).click(); - expect.verifySteps(["get_formview_action", "get_views", "web_read"]); - await goToHomeMenu(); - expect.verifySteps([]); - expect(".o_menu_toggle").toHaveClass("o_menu_toggle_back"); - expect(".o_home_menu").toHaveCount(1); - expect(".o_form_view").not.toHaveCount(); - }); - - test.tags("desktop"); - test("6 -- back to underlying action with many breadcrumbs", async () => { - Partner._views["form"] = ` -
- - - - `; - await mountWebClientOdex(); - expect.verifySteps(["/web/webclient/translations", "/web/webclient/load_menus"]); - await contains(".o_app.o_menuitem").click(); - await animationFrame(); - expect.verifySteps(["/web/action/load", "get_views", "web_search_read"]); - expect(".o_kanban_view").toHaveCount(1); - await contains(".o_kanban_record").click(); - expect.verifySteps(["web_read"]); - await contains('.o_field_widget[name="parent_id"] .o_external_button', { - visible: false, - }).click(); - expect.verifySteps(["get_formview_action", "get_views", "web_read"]); - await contains(".o_menu_toggle").click(); - - // can't click again too soon because of the mutex in home_menu - // service (waiting for the url to be updated) - await animationFrame(); - - await contains(".o_menu_toggle").click(); - - expect.verifySteps(["web_read"]); - expect(".o_home_menu").toHaveCount(0); - expect(".o_form_view").toHaveCount(1); - expect(".o_menu_toggle").not.toHaveClass("o_menu_toggle_back"); - expect(".o_breadcrumb .active").toHaveText("Second record"); - // Third breadcrumb is the active one - expect(".breadcrumb-item").toHaveCount(2); - }); -}); - -test("restore the newly created record in form view", async () => { - defineActions( - [ - { - id: 6, - xml_id: "action_6", - name: "Partner", - res_model: "partner", - views: [[false, "form"]], - }, - ], - { mode: "replace" } - ); - await mountWebClientOdex(); - - await getService("action").doAction(6); - expect(".o_form_view").toHaveCount(1); - expect(".o_form_view .o_form_editable").toHaveCount(1); - await contains(".o_field_widget[name=name] input").edit("red right hand"); - await contains(".o_form_button_save").click(); - expect(".o_breadcrumb .active").toHaveText("red right hand"); - await goToHomeMenu(); - expect(".o_form_view").not.toHaveCount(); - - // can't click again too soon because of the mutex in home_menu - // service (waiting for the url to be updated) - await animationFrame(); - - await contains(".o_menu_toggle").click(); - expect(".o_form_view").toHaveCount(1); - expect(".o_form_view .o_form_saved").toHaveCount(1); - expect(".o_breadcrumb .active").toHaveText("red right hand"); -}); - -test.tags("desktop"); -test("fast clicking on restore (implementation detail)", async () => { - expect.assertions(8); - - let doVeryFastClick = false; - - class DelayedClientAction extends Component { - static template = xml`
- -
`; - static props = ["*"]; - setup() { - onMounted(() => { - if (doVeryFastClick) { - doVeryFastClick = false; - click(".o_menu_toggle"); // go to home menu - } - }); - } - } - - registry.category("actions").add("DelayedClientAction", DelayedClientAction); - await mountWebClientOdex(); - await getService("action").doAction("DelayedClientAction"); - await animationFrame(); - await contains(".o_menu_toggle").click(); // go to home menu - expect(".o_home_menu").toBeVisible(); - expect(".delayed_client_action").not.toHaveCount(); - - doVeryFastClick = true; - await contains(".o_menu_toggle").click(); // back - expect(".o_home_menu").toHaveCount(0); - expect(".delayed_client_action").toHaveCount(1); - await animationFrame(); // waiting for DelayedClientAction - expect(".o_home_menu").toBeVisible(); - expect(".delayed_client_action").not.toHaveCount(); - - await contains(".o_menu_toggle").click(); // back - await animationFrame(); - expect(".o_home_menu").toHaveCount(0); - expect(".delayed_client_action").toHaveCount(1); -}); - -test("clear unCommittedChanges when toggling home menu", async () => { - expect.assertions(6); - // Edit a form view, don't save, toggle home menu - // the autosave feature of the Form view is activated - // and relied upon by this test - - onRpc("web_save", ({ args, model }) => { - expect(model).toBe("partner"); - expect(args[1]).toEqual({ - name: "red right hand", - foo: false, - }); - }); - - await mountWebClientOdex(); - await getService("action").doAction(3, { viewType: "form" }); - expect(".o_form_view .o_form_editable").toHaveCount(1); - await contains(".o_field_widget[name=name] input").edit("red right hand"); - - await goToHomeMenu(); - expect(".o_form_view").toHaveCount(0); - expect(".modal").toHaveCount(0); - expect(".o_home_menu").toHaveCount(1); -}); - -test("can have HomeMenu and dialog action", async () => { - await mountWebClientOdex(); - expect(".o_home_menu").toHaveCount(1); - expect(".modal .o_form_view").toHaveCount(0); - await getService("action").doAction(5); - expect(".modal .o_form_view").toHaveCount(1); - expect(".modal .o_form_view").toBeVisible(); - expect(".o_home_menu").toHaveCount(1); -}); - -test("supports attachments of apps deleted", async () => { - // When doing a pg_restore without the filestore - // LPE fixme: may not be necessary anymore since menus are not HomeMenu props anymore - defineMenus([ - { - id: 1, - appID: 1, - actionID: 1, - xmlid: "", - name: "Partners", - webIconData: "", - webIcon: "bloop,bloop", - }, - ]); - serverState.debug = "1"; - await mountWebClientOdex(); - expect(".o_home_menu").toHaveCount(1); -}); - -test.tags("desktop"); -test("debug manager resets to global items when home menu is displayed", async () => { - const debugRegistry = registry.category("debug"); - debugRegistry.category("default").add("item_1", () => ({ - type: "item", - description: "globalItem", - callback: () => {}, - sequence: 10, - })); - onRpc("has_access", () => true); - serverState.debug = "1"; - await mountWebClientOdex(); - await contains(".o_debug_manager .dropdown-toggle").click(); - expect(".dropdown-item:contains('globalItem')").toHaveCount(1); - expect(".dropdown-item:contains('View: Kanban')").toHaveCount(0); - - await contains(".o_debug_manager .dropdown-toggle").click(); - await getService("action").doAction(1); - await contains(".o_debug_manager .dropdown-toggle").click(); - expect(".dropdown-item:contains('globalItem')").toHaveCount(1); - expect(".dropdown-item:contains('View: Kanban')").toHaveCount(1); - - await contains(".o_menu_toggle").click(); - await contains(".o_debug_manager .dropdown-toggle").click(); - expect(".dropdown-item:contains('globalItem')").toHaveCount(1); - expect(".dropdown-item:contains('View: Kanban')").toHaveCount(0); - - await contains(".o_debug_manager .dropdown-toggle").click(); - await getService("action").doAction(3); - await contains(".o_debug_manager .dropdown-toggle").click(); - expect(".dropdown-item:contains('globalItem')").toHaveCount(1); - expect(".dropdown-item:contains('View: List')").toHaveCount(1); - expect(".dropdown-item:contains('View: Kanban')").toHaveCount(0); -}); - -test("url state is well handled when going in and out of the HomeMenu", async () => { - patchWithCleanup(browser.location, { - origin: "http://example.com", - }); - redirect("/odoo"); - await mountWebClientOdex(); - expect(router.current).toEqual({ - action: "menu", - actionStack: [ - { - action: "menu", - displayName: "Home", - }, - ], - }); - expect(browser.history.length).toBe(1); - - await contains(".o_apps > .o_draggable:eq(1) > .o_app").click(); - await animationFrame(); - expect(router.current).toEqual({ - action: 1002, - actionStack: [ - { - action: 1002, - displayName: "Client action 1002", - }, - ], - }); - expect(browser.history.length).toBe(2); - expect(browser.location.href).toBe("http://example.com/odoo/action-1002"); - - await goToHomeMenu(); - await animationFrame(); - expect(router.current).toEqual( - { - action: "menu", - actionStack: [ - { - action: 1002, - displayName: "Client action 1002", - }, - { - action: "menu", - displayName: "Home", - }, - ], - }, - { - message: - "the actionStack is required to be able to restore the menu toggle back button and the underlying breadcrumbs", - } - ); - expect(browser.history.length).toBe(3); - expect(browser.location.href).toBe("http://example.com/odoo", { - message: - "despite the actionStack being in the router state, the url shouldn't have any path", - }); - - await contains(".o_apps > .o_draggable:eq(0) > .o_app").click(); - await animationFrame(); - expect(router.current).toEqual( - { - action: 1001, - actionStack: [ - { - action: 1001, - displayName: "Client action 1001", - }, - ], - }, - { message: "clicking another app creates a new action stack (ie empties the breadcrumb)" } - ); - expect(browser.history.length).toBe(4); - expect(browser.location.href).toBe("http://example.com/odoo/action-1001"); - - browser.history.back(); - await animationFrame(); - expect(router.current).toEqual( - { - action: "menu", - actionStack: [ - { - action: 1002, - displayName: "Client action 1002", - }, - { - action: "menu", - displayName: "Home", - }, - ], - globalState: {}, - }, - { message: "actionStack was restored" } - ); - expect(browser.history.length).toBe(4, { - message: "the previous history entry still exists (available with forward button)", - }); - expect(browser.location.href).toBe("http://example.com/odoo"); - - await contains(".o_menu_toggle").click(); - await animationFrame(); - expect(router.current).toEqual({ - action: 1002, - actionStack: [ - { - action: 1002, - displayName: "Client action 1002", - }, - ], - }); - expect(browser.history.length).toBe(4); - expect(browser.location.href).toBe("http://example.com/odoo/action-1002"); -}); - -test.tags("desktop"); -test("underlying action's menu items are invisible when HomeMenu is displayed", async () => { - defineMenus([ - { - id: 1, - children: [ - { - id: 99, - name: "SubMenu", - appID: 1, - actionID: 1002, - xmlid: "", - webIconData: undefined, - webIcon: false, - }, - ], - }, - ]); - await mountWebClientOdex(); - expect("nav .o_menu_sections").toHaveCount(0); - expect("nav .o_menu_brand").toHaveCount(0); - await contains(".o_app.o_menuitem:nth-child(1)").click(); - await animationFrame(); - expect("nav .o_menu_sections").toHaveCount(1); - expect("nav .o_menu_brand").toHaveCount(1); - expect(".o_menu_sections").toBeVisible(); - expect(".o_menu_brand").toBeVisible(); - await contains(".o_menu_toggle").click(); - expect("nav .o_menu_sections").toHaveCount(1); - expect("nav .o_menu_brand").toHaveCount(1); - expect(".o_menu_sections").not.toBeVisible(); - expect(".o_menu_brand").not.toBeVisible(); -}); - -test("go back to home menu using browser back button", async () => { - await mountWebClientOdex(); - expect(".o_home_menu").toHaveCount(1); - expect(".o_main_navbar .o_menu_toggle").not.toBeVisible(); - - await contains(".o_apps > .o_draggable:nth-child(2) > .o_app").click(); - expect(".test_client_action").toHaveCount(0); - await animationFrame(); - expect(".test_client_action").toHaveCount(1); - expect(".o_home_menu").toHaveCount(0); - - browser.history.back(); - await animationFrame(); - await animationFrame(); - expect(".test_client_action").toHaveCount(0); - expect(".o_home_menu").toHaveCount(1); - expect(".o_main_navbar .o_menu_toggle").not.toBeVisible(); -}); - -test("initial action crashes", async () => { - expect.errors(1); - redirect("/odoo/action-__test__client__action__?menu_id=1"); - const ClientAction = registry.category("actions").get("__test__client__action__"); - class Override extends ClientAction { - setup() { - super.setup(); - expect.step("clientAction setup"); - throw new Error("my error"); - } - } - registry.category("actions").add("__test__client__action__", Override, { force: true }); - - await mountWebClientOdex(); - expect.verifySteps(["clientAction setup"]); - expect("nav .o_menu_toggle").toHaveCount(1); - expect("nav .o_menu_toggle").toBeVisible(); - expect(".o_action_manager").toHaveInnerHTML(""); - expect(router.current).toEqual({ - action: "__test__client__action__", - menu_id: 1, - actionStack: [ - { - action: "__test__client__action__", - }, - ], - }); - await animationFrame(); - expect.verifyErrors(["my error"]); -}); - -test("Apps are reordered at startup based on session's user settings", async () => { - // Config is written with apps xmlids order (default is menu_1, menu_2) - patchWithCleanup(user, { - get settings() { - return { id: 1, homemenu_config: '["menu_2","menu_1"]' }; - }, - }); - await mountWebClientOdex(); - - const apps = queryAll(".o_app"); - expect(apps[0]).toHaveAttribute("data-menu-xmlid", "menu_2", { - message: "first displayed app has menu_2 xmlid", - }); - expect(apps[1]).toHaveAttribute("data-menu-xmlid", "menu_1", { - message: "second displayed app has menu_1 xmlid", - }); - expect(apps[0]).toHaveText("App2", { message: "first displayed app is App2" }); - expect(apps[1]).toHaveText("App1", { message: "second displayed app is App1" }); -}); - -test.tags("desktop"); -test("Share URL item is present in the user menu when running as PWA", async () => { - mockMatchMedia({ ["display-mode"]: "standalone" }); - clearRegistry(registry.category("user_menuitems")); - // This service adds a "Dark Mode" item to the user menu items on start - registry.category("services").remove("color_scheme"); - registry.category("user_menuitems").add("share_url", shareUrlMenuItem); - - await mountWithCleanup(UserMenu); - await contains(".o_user_menu button").click(); - - expect(".o-dropdown--menu .dropdown-item").toHaveCount(1); - expect(".o-dropdown--menu .dropdown-item").toHaveText("Share"); -}); - -test.tags("desktop"); -test("Share URL item is not present in the user menu when not running as PWA", async () => { - mockMatchMedia({ ["display-mode"]: "browser" }); - clearRegistry(registry.category("user_menuitems")); - // This service adds a "Dark Mode" item to the user menu items on start - registry.category("services").remove("color_scheme"); - registry.category("user_menuitems").add("share_url", shareUrlMenuItem); - - await mountWithCleanup(UserMenu); - await contains(".o_user_menu button").click(); - - expect(".o-dropdown--menu .dropdown-item").not.toHaveCount(); -}); - -test("Navigate to an application from the HomeMenu should generate only one pushState", async () => { - patchWithCleanup(history, { - pushState(state, title, url) { - super.pushState(...arguments); - const parsedUrl = new URL(url); - expect.step(parsedUrl.pathname + parsedUrl.search); - }, - }); - await mountWebClientOdex(); - - await contains(".o_apps > .o_draggable:nth-child(2) > .o_app").click(); - await animationFrame(); - expect(".test_client_action").toHaveCount(1); - expect(".test_client_action").toHaveText("ClientAction_Id 2"); - - await goToHomeMenu(); - expect(".o_home_menu").toHaveCount(1); - - await contains(".o_apps > .o_draggable:nth-child(1) > .o_app").click(); - await animationFrame(); - expect(".test_client_action").toHaveCount(1); - expect(".test_client_action").toHaveText("ClientAction_Id 1"); - - await goToHomeMenu(); - await animationFrame(); - expect(".o_home_menu").toHaveCount(1); - expect.verifySteps(["/odoo", "/odoo/action-1002", "/odoo", "/odoo/action-1001", "/odoo"]); -}); - -test.tags("desktop"); -test("Should not crash when opening an app via palette and immediately entering input in the palette search", async () => { - await mountWebClientOdex(); - - const def = new Deferred(); - onRpc("web_search_read", () => def); - await keyDown("a"); - await animationFrame(); - await keyDown("Enter"); - await keyDown("a"); - await animationFrame(); - def.resolve(); - await animationFrame(); - expect(".test_client_action").toHaveCount(1); - expect(".test_client_action").toHaveText("ClientAction_Id 1"); -}); diff --git a/odex30_base/odex30_web/tests/__init__.py b/odex30_base/odex30_web/tests/__init__.py deleted file mode 100644 index 018fafd..0000000 --- a/odex30_base/odex30_web/tests/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ - -from . import test_odex diff --git a/odex30_base/odex30_web/tests/test_odex.py b/odex30_base/odex30_web/tests/test_odex.py deleted file mode 100644 index 9d6d88d..0000000 --- a/odex30_base/odex30_web/tests/test_odex.py +++ /dev/null @@ -1,68 +0,0 @@ -import base64 - -from odoo.tests.common import HttpCase, tagged - - -class LoadMenusTests(HttpCase): - - def setUp(self): - super().setUp() - self.menu = self.env["ir.ui.menu"].create({ - "name": "test_menu", - "parent_id": False, - }) - - def search(*args, **kwargs): - return self.menu - - self.patch(type(self.env["ir.ui.menu"]), "search", search) - self.authenticate("admin", "admin") - - def test_web_icon(self): - self.menu.web_icon = False - self.menu.web_icon_data = b"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+BCQAHBQICJmhD1AAAAABJRU5ErkJggg==" - - menu_loaded = self.url_open("/web/webclient/load_menus/1234") - - expected = { - str(self.menu.id): { - "actionID": False, - "actionModel": False, - "actionPath": False, - "appID": self.menu.id, - "children": [], - "id": self.menu.id, - "name": "test_menu", - "webIcon": False, - "webIconData": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+BCQAHBQICJmhD1AAAAABJRU5ErkJggg==", - "webIconDataMimetype": "image/png", - "xmlid": "" - }, - "root": { - "actionID": False, - "actionModel": False, - "actionPath": False, - "appID": False, - "children": [ - self.menu.id - ], - "id": "root", - "name": "root", - "webIcon": None, - "webIconData": None, - "webIconDataMimetype": None, - "xmlid": "", - "backgroundImage": None, - } - } - - self.assertDictEqual(menu_loaded.json(), expected) - - -@tagged("-at_install", "post_install") -class TestWeb(HttpCase): - def test_studio_list_upsell(self): - invoice_action = self.env.ref("account.action_move_out_invoice_type", raise_if_not_found=False) - if not invoice_action: - return - self.start_tour("/odoo/action-account.action_move_out_invoice_type", "odex30_web.test_studio_list_upsell", login="admin") diff --git a/odex30_base/odex30_web/version.py b/odex30_base/odex30_web/version.py deleted file mode 100644 index cf28214..0000000 --- a/odex30_base/odex30_web/version.py +++ /dev/null @@ -1,10 +0,0 @@ - -import odoo - -odoo.release.version_info = odoo.release.version_info[:5] + ('e',) -if '+e' not in odoo.release.version: - odoo.release.version = '{0}+e{1}{2}'.format(*odoo.release.version.partition('-')) - -odoo.service.common.RPC_VERSION_1.update( - server_version=odoo.release.version, - server_version_info=odoo.release.version_info)