Merge branch 'frappe:develop' into tabs_on_grid_row_form

This commit is contained in:
avc 2025-12-10 07:26:38 +01:00 committed by GitHub
commit c9c58fd089
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 114 additions and 120 deletions

View file

@ -100,7 +100,7 @@ runs:
run: |
# Install System Dependencies
start_time=$(date +%s)
curl -LsS https://r.mariadb.com/downloads/mariadb_repo_setup | sudo bash -s -- --mariadb-server-version="mariadb-11.8.5"
curl -LsS https://r.mariadb.com/downloads/mariadb_repo_setup | sudo bash -s -- --mariadb-server-version="mariadb-11.8.5" --skip-maxscale
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -

View file

@ -78,7 +78,7 @@ context("Awesome Bar", () => {
cy.get("@awesome_bar").type("new web page");
cy.wait(150); // Wait a bit before hitting enter
cy.get("@awesome_bar").type("{enter}");
cy.get(".title-text:visible").should("have.text", "New Web Page");
cy.get(".title-text-form:visible").should("have.text", "New Web Page");
});
it("calculates math expressions", () => {

View file

@ -224,7 +224,7 @@ context("Attach Control with Failed Document Save", () => {
.should("have.attr", "href")
.and("equal", "https://wallpaperplay.com/walls/full/8/2/b/72402.jpg");
cy.get(".title-text").then(($value) => {
cy.get(".title-text-form").then(($value) => {
docname = $value.text();
});
});
@ -238,6 +238,18 @@ context("Attach Control with Failed Document Save", () => {
.blur()
.wait(500);
cy.get('input[data-fieldname="attached_to_name"]').click().type(docname).blur();
cy.findByRole("button", { name: "+ Add a Filter" }).click();
cy.get(".fieldname-select-area .form-control")
.last()
.click()
.type("Attached To Doctype{enter}")
.blur()
.wait(500);
cy.get('input[data-fieldname="attached_to_doctype"]')
.last()
.click()
.type("Test Mandatory Attach Control")
.blur();
cy.get(".filter-popover .apply-filters").click({ force: true });
cy.get("header .level-right .list-count").should("contain.text", "1 of 1");
});

View file

@ -53,7 +53,7 @@ context("Data Control", () => {
"contains",
"/desk/test-data-control/new-test-data-control"
);
cy.get(".title-text").should("have.text", "New Test Data Control");
cy.get(".title-text-form").should("have.text", "New Test Data Control");
cy.get('.frappe-control[data-fieldname="name1"]')
.find("label")
.should("have.class", "reqd");

View file

@ -226,6 +226,6 @@ context("View", () => {
it("Route to Website Workspace", () => {
cy.visit("/desk/website");
cy.get(".title-text").should("contain", "Website");
cy.get(".workspace-title").should("contain", "Website");
});
});

View file

@ -647,7 +647,8 @@ class ImportFile:
elif extension == "xls":
data = read_xls_file_from_attached_file(content)
self.validate_columns_of_import_file(data)
if self.import_type == INSERT:
self.validate_columns_of_import_file(data)
return data

View file

@ -38,9 +38,9 @@ app_include_css = [
"report.bundle.css",
]
app_include_icons = [
"/assets/frappe/icons/icons.svg",
"/assets/frappe/icons/timeless/icons.svg",
"/assets/frappe/icons/espresso/icons.svg",
"/assets/frappe/icons/icons.svg",
]
doctype_js = {

View file

@ -561,7 +561,9 @@ frappe.ui.form.Layout = class Layout {
if (tabs_content.getBoundingClientRect().top < 100) {
tabs_content.scrollIntoView();
setTimeout(() => {
$(".page-head").css("top", "-15px");
if (frappe.boot.read_only || frappe.boot.user.impersonated_by) {
$(".page-head").css("top", "-15px");
}
$(".form-tabs-list").removeClass("form-tabs-sticky-down");
$(".form-tabs-list").addClass("form-tabs-sticky-up");
}, 3);

View file

@ -176,9 +176,9 @@ frappe.views.BaseList = class BaseList {
}
setup_page_head() {
this.set_breadcrumbs();
this.set_title();
this.set_menu_items();
this.set_breadcrumbs();
}
set_title() {

View file

@ -1,28 +1,12 @@
<div class="page-head flex">
<div class="page-head flex {% if frappe.boot.read_only || frappe.boot.user.impersonated_by %}show-navbar{% endif %}">
<div class="container">
<div class="row flex-nowrap align-center page-head-content justify-between">
<div class="col-md-4 col-sm-6 col-xs-7 page-title">
<!-- <div class="title-image hide hidden-md hidden-lg"></div> -->
<!-- title -->
<button class="btn-reset sidebar-toggle-btn">
<svg class="es-icon icon-md sidebar-toggle-placeholder">
<use href="#es-line-align-justify"></use>
</svg>
<span class="sidebar-toggle-icon">
<svg class="es-icon icon-md">
<use href="#es-line-sidebar-collapse">
</use>
</svg>
</span>
</button>
<div class="col-md-5 col-sm-6 col-xs-7 page-title">
<div class="flex fill-width title-area">
<div>
<div class="flex">
<h3 class="ellipsis title-text"></h3>
<span class="indicator-pill whitespace-nowrap"></span>
</div>
<div class="ellipsis sub-heading hide text-muted"></div>
</div>
{% if (!frappe.is_mobile()) { %}
<ul class="nav d-sm-flex navbar-breadcrumbs"></ul>
{% endif %}
<span class="indicator-pill whitespace-nowrap"></span>
<button class="btn btn-default more-button hide">
<svg class="icon icon-sm">
<use href="#icon-dot-horizontal">

View file

@ -53,9 +53,13 @@ frappe.ui.Page = class Page {
frappe.utils.throttle(() => {
$(".page-head").toggleClass("drop-shadow", !!document.documentElement.scrollTop);
let current_scroll = document.documentElement.scrollTop;
if (current_scroll > 0 && last_scroll <= current_scroll) {
if (
current_scroll > 0 &&
last_scroll <= current_scroll &&
(frappe.boot.read_only || frappe.boot.user.impersonated_by)
) {
$(".page-head").css("top", "-15px");
} else {
} else if (frappe.boot.read_only || frappe.boot.user.impersonated_by) {
$(".page-head").css("top", "var(--navbar-height)");
}
last_scroll = current_scroll;

View file

@ -1,15 +1,28 @@
<div class="sticky-top">
{% if (frappe.boot.read_only || frappe.boot.user.impersonated_by || frappe.is_mobile()) { %}
<header class="navbar navbar-expand" role="navigation">
<div class="container">
<a class="navbar-brand navbar-home" href="/desk">
<img
class="app-logo"
src="{{ frappe.boot.app_data[0].app_logo_url }}"
alt="{{ __("App Logo") }}"
>
<a class="navbar-brand navbar-home">
<span class="app-logo">
<svg class="es-icon icon-md">
<use href="#es-line-align-justify"></use>
</svg>
</span>
</a>
<ul class="nav navbar-nav d-none d-sm-flex" id="navbar-breadcrumbs"></ul>
{% if (frappe.is_mobile()) { %}
<ul class="nav d-sm-flex navbar-breadcrumbs mobile-no-divider"></ul>
{% endif %}
<div class="collapse navbar-collapse justify-content-end">
{% if (frappe.boot.read_only) { %}
<span class="indicator-pill yellow no-indicator-dot read-only-banner" title="{%= __("Your site is undergoing maintenance or being updated.") %}">
{%= __("Read Only Mode") %}
</span>
{% } %}
{% if (frappe.boot.user.impersonated_by) { %}
<span class="indicator-pill red no-indicator-dot" title="{%= __("You are impersonating as another user.") %}">
{%= __("Impersonating {0}", [frappe.boot.user.name]) %}
</span>
{% } %}
{% if frappe.is_mobile() %}
<div class="search-bar text-muted hidden">
<div
@ -17,44 +30,16 @@
class="navbar-modal-search-mobile"
placeholder="Search for type a command"
>
<span class="search-icon">
<svg class="icon icon-sm"><use href="#icon-search"></use></svg>
</span>
</div>
<span class="search-icon">
<svg class="icon icon-sm"><use href="#icon-search"></use></svg>
</span>
</div>
</div>
{% endif %}
<ul class="navbar-nav">
<li class="nav-item dropdown dropdown-navbar-user dropdown-mobile">
<button
class="btn-reset nav-link"
data-toggle="dropdown"
aria-label="{{ __("User Menu") }}"
>
{{ avatar }}
</button>
<div class="dropdown-menu dropdown-menu-right" id="toolbar-user" role="menu">
{% for item in navbar_settings.settings_dropdown %}
{% var condition = item.condition ? eval(item.condition) : true %}
{% if (condition && !item.hidden) { %}
{% if (item.route) { %}
<a class="dropdown-item" href="{{ item.route }}">
{%= __(item.item_label) %}
</a>
{% } else if (item.action) { %}
<button class="btn-reset dropdown-item" onclick="return {{ item.action }}">
{%= __(item.item_label) %}
</button>
{% } else { %}
<div class="dropdown-divider"></div>
{% } %}
{% } %}
{% endfor %}
</div>
</li>
</ul>
</div>
</div>
</header>
{% endif %}
{% if !localStorage.getItem("dismissed_announcement_widget") && strip_html(navbar_settings.announcement_widget) != '' %}
<div class="announcement-widget form-message p-2 m-0" style="position: relative; z-index: -1; border-radius: 0; background-color: var(--bg-blue);">

View file

@ -6,18 +6,24 @@ frappe.provide("frappe.search");
frappe.ui.toolbar.Toolbar = class {
constructor() {
$("header").replaceWith(
frappe.render_template("navbar", {
avatar: frappe.avatar(frappe.session.user, "avatar-medium"),
navbar_settings: frappe.boot.navbar_settings,
})
);
if (
frappe.boot.read_only ||
frappe.boot.user.impersonated_by ||
(!localStorage.getItem("dismissed_announcement_widget") &&
strip_html(frappe.boot.navbar_settings.announcement_widget) != "") ||
frappe.is_mobile()
) {
$("header").replaceWith(
frappe.render_template("navbar", {
navbar_settings: frappe.boot.navbar_settings,
})
);
}
$(".dropdown-toggle").dropdown();
$("#toolbar-user a[href]").click(function () {
$(this).closest(".dropdown-menu").prev().dropdown("toggle");
});
// this.setup_awesomebar();
this.setup_read_only_mode();
this.setup_announcement_widget();
this.make();
@ -33,9 +39,7 @@ frappe.ui.toolbar.Toolbar = class {
change_toolbar() {
$(".navbar .container").css("max-width", "43%");
$(".navbar-brand").css("display", "block");
$(".navbar-brand .app-logo").attr("src", frappe.boot.navbar_settings.app_logo);
let nav_elements = $(".navbar-nav").children();
$("form").css("display", "none");
$("");
for (let i = 0; i < nav_elements.length - 1; i++) {
$(nav_elements[i]).attr("style", "display: none !important");
@ -112,18 +116,10 @@ frappe.ui.toolbar.Toolbar = class {
}
show_app_logo() {
let route = frappe.get_route();
if (route[0] == "List") {
this.navbar.html("");
this.navbar.html(this.app_logo);
this.navbar.attr("href", "");
this.bind_click();
} else if (route[0] == "Form") {
if (route[0] == "Form") {
this.add_back_button();
}
}
set_app_logo(logo_url) {
$(".navbar-brand .app-logo").attr("src", logo_url);
}
};
$.extend(frappe.ui.toolbar, {

View file

@ -67,9 +67,10 @@ frappe.breadcrumbs = {
this.set_list_breadcrumb(breadcrumbs);
this.set_form_breadcrumb(breadcrumbs, view);
} else if (breadcrumbs.doctype && view === "list") {
// pass
this.set_list_breadcrumb(breadcrumbs);
} else if (breadcrumbs.doctype && view == "dashboard-view") {
this.set_list_breadcrumb(breadcrumbs);
this.set_dashboard_breadcrumb(breadcrumbs);
}
}
@ -80,10 +81,13 @@ frappe.breadcrumbs = {
this.append_breadcrumb_element(breadcrumbs.route, breadcrumbs.label);
},
append_breadcrumb_element(route, label) {
append_breadcrumb_element(route, label, css_classes) {
const el = document.createElement("li");
const a = document.createElement("a");
a.href = route;
if (css_classes) {
a.classList.add(css_classes);
}
a.innerText = label;
el.appendChild(a);
this.$breadcrumbs.append(el);
@ -185,7 +189,7 @@ frappe.breadcrumbs = {
} else {
route = doctype_route;
}
this.append_breadcrumb_element(`/desk/${route}`, __(doctype));
this.append_breadcrumb_element(`/desk/${route}`, __(doctype), "title-text");
}
},
@ -193,15 +197,15 @@ frappe.breadcrumbs = {
const doctype = breadcrumbs.doctype;
let docname = frappe.get_route().slice(2).join("/");
let doc = frappe.get_doc(doctype, docname);
if (doc.__islocal) return; // new doc, no breadcrumb required
let title = frappe.model.get_doc_title(doc);
if (title == doc.name) return; // title and name are same, don't add breadcrumb
let form_route = `/desk/${frappe.router.slug(doctype)}/${encodeURIComponent(docname)}`;
this.append_breadcrumb_element(form_route, doc.name);
let docname_title;
if (docname.startsWith("new-" + doctype.toLowerCase().replace(/ /g, "-"))) {
docname_title = __("New {0}", [__(doctype)]);
} else {
docname_title = doc.name;
}
this.append_breadcrumb_element(form_route, docname_title, "title-text-form");
if (view === "form") {
let last_crumb = this.$breadcrumbs.find("li").last();
@ -238,7 +242,7 @@ frappe.breadcrumbs = {
},
clear() {
this.$breadcrumbs = $("#navbar-breadcrumbs").empty();
this.$breadcrumbs = $(".navbar-breadcrumbs").empty();
},
toggle(show) {

View file

@ -4,9 +4,8 @@
background-color: white;
}
/*! This comment will be included even in compressed mode. */
#navbar-breadcrumbs {
.navbar-breadcrumbs {
a {
font-size: var(--text-lg);
text-decoration: none;
color: var(--ink-gray-5);
font-weight: var(--weight-medium);
@ -28,6 +27,12 @@
}
}
&.mobile-no-divider {
a:before {
content: "";
}
}
li:first-child a:before {
// no angle before first item
content: none;

View file

@ -512,7 +512,10 @@
top: calc(var(--navbar-height) - 1px);
}
.form-tabs-sticky-down {
top: calc(var(--navbar-height) + var(--page-head-height) - 1px);
top: calc(var(--navbar-height) - 2px);
&.show-navbar {
top: calc(var(--navbar-height) + var(--page-head-height) - 1px);
}
}
.progress-area {

View file

@ -64,9 +64,10 @@ body {
}
}
#navbar-breadcrumbs {
.navbar-breadcrumbs {
display: inline-block;
max-width: 150px;
max-width: 200px;
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
@ -78,18 +79,18 @@ body {
}
}
#navbar-breadcrumbs > li,
#navbar-breadcrumbs > li > a {
.navbar-breadcrumbs > li,
.navbar-breadcrumbs > li > a {
display: inline-block;
vertical-align: middle;
}
#navbar-breadcrumbs > li > a:before {
.navbar-breadcrumbs > li > a:before {
// .breadcrumb-divider-left();
}
// select all except last 2
#navbar-breadcrumbs li:not(:nth-last-child(-n + 1)) {
.navbar-breadcrumbs li:not(:nth-last-child(-n + 1)) {
display: none;
}

View file

@ -35,15 +35,9 @@
.title-area {
display: inline-flex;
align-items: center;
.title-text {
@include get_textstyle("xl", "semibold");
cursor: pointer;
margin-bottom: 0px;
margin-right: var(--margin-sm);
max-width: 25vw;
}
.indicator-pill {
margin-top: 2px;
margin-left: var(--margin-sm);
}
.sub-heading {
@include get_textstyle("sm", "regular");
@ -107,10 +101,13 @@
.page-head {
z-index: 6;
position: sticky;
top: var(--navbar-height);
background: var(--bg-color);
border-bottom: 1px solid var(--border-color);
transition: 0.5s top;
top: 0;
&.show-navbar {
top: var(--navbar-height);
}
.page-head-content {
height: var(--page-head-height);