Merge branch 'develop' into cmd/ctrl-to-see-fieldname

This commit is contained in:
Shariq Ansari 2022-12-22 11:36:36 +05:30 committed by Shariq Ansari
commit 1b8bf0f64c
13 changed files with 124 additions and 47 deletions

38
.github/workflows/release_notes.yml vendored Normal file
View file

@ -0,0 +1,38 @@
# This action:
#
# 1. Generates release notes using github API.
# 2. Strips unnecessary info like chore/style etc from notes.
# 3. Updates release info.
# This action needs to be maintained on all branches that do releases.
name: 'Release Notes'
on:
workflow_dispatch:
inputs:
tag_name:
description: 'Tag of release like v13.0.0'
required: true
type: string
release:
types: [released]
permissions:
contents: read
jobs:
regen-notes:
name: 'Regenerate release notes'
runs-on: ubuntu-latest
steps:
- name: Update notes
run: |
NEW_NOTES=$(gh api --method POST -H "Accept: application/vnd.github+json" /repos/frappe/frappe/releases/generate-notes -f tag_name=$RELEASE_TAG | jq -r '.body' | sed -E '/^\* (chore|ci|test|docs|style)/d' )
RELEASE_ID=$(gh api -H "Accept: application/vnd.github+json" /repos/frappe/frappe/releases/tags/$RELEASE_TAG | jq -r '.id')
gh api --method PATCH -H "Accept: application/vnd.github+json" /repos/frappe/frappe/releases/$RELEASE_ID -f body=$NEW_NOTES
env:
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
RELEASE_TAG: ${{ github.event.inputs.tag_name || github.event.release.tag_name }}

View file

@ -13,9 +13,9 @@
[
"@semantic-release/git", {
"assets": ["frappe/__init__.py"],
"message": "chore(release): Bumped to Version ${nextRelease.version}\n\n${nextRelease.notes}"
"message": "chore(release): Bumped to Version ${nextRelease.version}"
}
],
"@semantic-release/github"
]
}
}

View file

@ -532,7 +532,7 @@ def _mariadb():
command = [
mysql,
"--port",
frappe.conf.db_port or MariaDBDatabase.default_port,
str(frappe.conf.db_port or MariaDBDatabase.default_port),
"-u",
frappe.conf.db_name,
f"-p{frappe.conf.db_password}",
@ -548,7 +548,13 @@ def _mariadb():
def _psql():
psql = which("psql")
subprocess.run([psql, "-d", frappe.conf.db_name])
host = frappe.conf.db_host or "127.0.0.1"
port = frappe.conf.db_port or "5432"
env = os.environ.copy()
env["PGPASSWORD"] = frappe.conf.db_password
conn_string = f"postgresql://{frappe.conf.db_name}@{host}:{port}/{frappe.conf.db_name}"
subprocess.run([psql, conn_string], check=True, env=env)
@click.command("jupyter")

View file

@ -133,7 +133,7 @@ class Contact(Document):
def get_default_contact(doctype, name):
"""Returns default contact for the given doctype, name"""
out = frappe.db.sql(
'''select parent,
"""select parent,
IFNULL((select is_primary_contact from tabContact c where c.name = dl.parent), 0)
as is_primary_contact
from
@ -141,7 +141,7 @@ def get_default_contact(doctype, name):
where
dl.link_doctype=%s and
dl.link_name=%s and
dl.parenttype = 'Contact' ''',
dl.parenttype = 'Contact' """,
(doctype, name),
as_dict=True,
)

View file

@ -59,10 +59,7 @@ class CommunicationEmailMixin:
* if email copy is requested by sender, then add sender to CC.
* If this doc is created through inbound mail, then add doc owner to cc list
* remove all the thread_notify disabled users.
* Make sure that all users enabled in the system
* Remove admin from email list
* FixMe: Removed adding TODO owners to cc list. Check if that is needed.
* Remove standard users from email list
"""
if hasattr(self, "_final_cc"):
return self._final_cc
@ -80,13 +77,12 @@ class CommunicationEmailMixin:
cc = set(cc) - set(self.filter_thread_notification_disbled_users(cc))
cc = cc - set(self.mail_recipients(is_inbound_mail_communcation=is_inbound_mail_communcation))
cc = cc - set(self.filter_disabled_users(cc))
# # Incase of inbound mail, to and cc already received the mail, no need to send again.
if is_inbound_mail_communcation:
cc = cc - set(self.cc_list() + self.to_list())
self._final_cc = list(filter(lambda id: id != "Administrator", cc))
self._final_cc = [m for m in cc if m not in frappe.STANDARD_USERS]
return self._final_cc
def get_mail_cc_with_displayname(self, is_inbound_mail_communcation=False, include_sender=False):
@ -99,8 +95,7 @@ class CommunicationEmailMixin:
"""
* Thread_notify check
* Email unsubscribe list
* User must be enabled in the system
* remove_administrator_from_email_list
* remove standard users.
"""
if hasattr(self, "_final_bcc"):
return self._final_bcc
@ -110,13 +105,12 @@ class CommunicationEmailMixin:
bcc = bcc - {self.sender_mailid}
bcc = bcc - set(self.filter_thread_notification_disbled_users(bcc))
bcc = bcc - set(self.mail_recipients(is_inbound_mail_communcation=is_inbound_mail_communcation))
bcc = bcc - set(self.filter_disabled_users(bcc))
# Incase of inbound mail, to and cc & bcc already received the mail, no need to send again.
if is_inbound_mail_communcation:
bcc = bcc - set(self.bcc_list() + self.to_list())
self._final_bcc = list(filter(lambda id: id != "Administrator", bcc))
self._final_bcc = [m for m in bcc if m not in frappe.STANDARD_USERS]
return self._final_bcc
def get_mail_bcc_with_displayname(self, is_inbound_mail_communcation=False):

View file

@ -343,7 +343,7 @@ class TestCommunicationEmailMixin(FrappeTestCase):
user = self.new_user(email="bcc+2@test.com", enabled=0)
comm = self.new_communication(bcc=bcc_list)
res = comm.get_mail_bcc_with_displayname()
self.assertCountEqual(res, ["bcc+1@test.com"])
self.assertCountEqual(res, bcc_list)
user.delete()
comm.delete()

View file

@ -12,10 +12,10 @@ class ErrorSnapshot(Document):
def onload(self):
if not self.parent_error_snapshot:
self.db_set("seen", True, update_modified=False)
self.db_set("seen", 1, update_modified=False)
for relapsed in frappe.get_all("Error Snapshot", filters={"parent_error_snapshot": self.name}):
frappe.db.set_value("Error Snapshot", relapsed.name, "seen", True, update_modified=False)
frappe.db.set_value("Error Snapshot", relapsed.name, "seen", 1, update_modified=False)
frappe.local.flags.commit = True
@ -32,7 +32,7 @@ class ErrorSnapshot(Document):
self.update({"parent_error_snapshot": parent["name"]})
frappe.db.set_value("Error Snapshot", parent["name"], "relapses", parent["relapses"] + 1)
if parent["seen"]:
frappe.db.set_value("Error Snapshot", parent["name"], "seen", False)
frappe.db.set_value("Error Snapshot", parent["name"], "seen", 0)
@staticmethod
def clear_old_logs(days=30):

View file

@ -2,24 +2,6 @@ frappe.ui.form.Control = class BaseControl {
constructor(opts) {
$.extend(this, opts);
this.make();
// if developer_mode=1, show fieldname as tooltip
if (frappe.boot.user && frappe.boot.developer_mode === 1 && this.$wrapper) {
this.$wrapper.attr("title", __(this.df.fieldname));
} else if (this.$wrapper) {
// show fieldname as tooltip when cmd/ctrl key is pressed
$(document).on("keydown", (e) => {
if (e.metaKey) {
this.$wrapper.attr("title", __(this.df.fieldname));
}
});
$(document).on("keyup", (e) => {
if (!e.metaKey) {
this.$wrapper.removeAttr("title");
}
});
}
if (this.render_input) {
this.refresh();
}
@ -31,6 +13,7 @@ frappe.ui.form.Control = class BaseControl {
.attr("data-fieldname", this.df.fieldname);
this.wrapper = this.$wrapper.get(0);
this.wrapper.fieldobj = this; // reference for event handlers
this.$wrapper.append(`<span class="tooltip-content">${__(this.df.fieldname)}</span>`);
}
make_wrapper() {

View file

@ -35,6 +35,7 @@ frappe.ui.form.Layout = class Layout {
}
this.setup_tab_events();
this.setup_tooltip_events();
this.render();
}
@ -529,6 +530,19 @@ frappe.ui.form.Layout = class Layout {
});
}
setup_tooltip_events() {
$(document).on("keydown", (e) => {
if (e.metaKey) {
this.wrapper.addClass("show-tooltip");
}
});
$(document).on("keyup", (e) => {
if (!e.metaKey) {
this.wrapper.removeClass("show-tooltip");
}
});
}
handle_tab(doctype, fieldname, shift) {
let grid_row = null,
prev = null,

View file

@ -1256,8 +1256,8 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
// shift select checkboxes
if (e.shiftKey && this.$checkbox_cursor && !$target.is(this.$checkbox_cursor)) {
const name_1 = this.$checkbox_cursor.data().name;
const name_2 = $target.data().name;
const name_1 = decodeURIComponent(this.$checkbox_cursor.data().name);
const name_2 = decodeURIComponent($target.data().name);
const index_1 = this.data.findIndex((d) => d.name === name_1);
const index_2 = this.data.findIndex((d) => d.name === name_2);
let [min_index, max_index] = [index_1, index_2];
@ -1268,7 +1268,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
let docnames = this.data.slice(min_index + 1, max_index).map((d) => d.name);
const selector = docnames
.map((name) => `.list-row-checkbox[data-name="${name}"]`)
.map((name) => `.list-row-checkbox[data-name="${encodeURIComponent(name)}"]`)
.join(",");
this.$result.find(selector).prop("checked", true);
}

View file

@ -1,6 +1,29 @@
@import "../common/form.scss";
@import '~cropperjs/dist/cropper.min';
.tooltip-content {
position: absolute;
bottom: 104%;
left: 0;
z-index: 9999;
padding: 2px 6px;
border-radius: var(--border-radius-sm);
background: var(--gray-dark);
color: var(--text-dark);
font-size: var(--text-xs);
opacity: 0;
cursor: default;
transition: opacity 0.3s, transform 3s;
pointer-events: none;
}
.show-tooltip .frappe-control:hover .tooltip-content {
opacity: 1;
transform: translate3d(0,0,0);
pointer-events: auto;
}
.std-form-layout > .form-layout > .form-page {
border-radius: var(--border-radius-md);
box-shadow: var(--card-shadow);

View file

@ -29,7 +29,7 @@ import frappe.recorder
from frappe.installer import add_to_installed_apps, remove_app
from frappe.query_builder.utils import db_type_is
from frappe.tests.test_query_builder import run_only_if
from frappe.tests.utils import FrappeTestCase
from frappe.tests.utils import FrappeTestCase, timeout
from frappe.utils import add_to_date, get_bench_path, get_bench_relative_path, now
from frappe.utils.backups import BackupGenerator, fetch_latest_backups
from frappe.utils.jinja_globals import bundled_asset
@ -763,3 +763,10 @@ class TestCommandUtils(FrappeTestCase):
app_groups = get_app_groups()
self.assertIn("frappe", app_groups)
self.assertIsInstance(app_groups["frappe"], click.Group)
class TestDBCli(BaseTestCommands):
@timeout(10)
def test_db_cli(self):
self.execute("bench --site {site} db-console", kwargs={"cmd_input": rb"\q"})
self.assertEqual(self.returncode, 0)

View file

@ -429,6 +429,18 @@ jobs:
name: Server
services:
redis-cache:
image: redis:alpine
ports:
- 13000:6379
redis-queue:
image: redis:alpine
ports:
- 11000:6379
redis-socketio:
image: redis:alpine
ports:
- 12000:6379
mariadb:
image: mariadb:10.6
env:
@ -439,17 +451,17 @@ jobs:
steps:
- name: Clone
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Setup Python
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Setup Node
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: 14
node-version: 16
check-latest: true
- name: Cache pip
@ -465,7 +477,7 @@ jobs:
id: yarn-cache-dir-path
run: 'echo "::set-output name=dir::$(yarn cache dir)"'
- uses: actions/cache@v2
- uses: actions/cache@v3
id: yarn-cache
with:
path: ${{{{ steps.yarn-cache-dir-path.outputs.dir }}}}