Merge branch 'develop' into no_currency_field_found

This commit is contained in:
Suraj Shetty 2020-03-13 16:08:14 +05:30 committed by GitHub
commit be04015ddd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 188 additions and 67 deletions

View file

@ -3,7 +3,7 @@ pull_request_rules:
conditions:
- status-success=Codacy/PR Quality Review
- status-success=Semantic Pull Request
- status-success=continuous-integration/travis-ci/pr
- status-success=Travis CI - Pull Request
- status-success=security/snyk - package.json (frappe)
- status-success=security/snyk - requirements.txt (frappe)
- label!=don't-merge
@ -16,7 +16,7 @@ pull_request_rules:
conditions:
- status-success=Codacy/PR Quality Review
- status-success=Semantic Pull Request
- status-success=continuous-integration/travis-ci/pr
- status-success=Travis CI - Pull Request
- status-success=security/snyk - package.json (frappe)
- status-success=security/snyk - requirements.txt (frappe)
- label!=don't-merge

View file

@ -2,8 +2,8 @@ context('Form', () => {
before(() => {
cy.login();
cy.visit('/desk#workspace/Website');
cy.window().its('frappe').then(frappe => {
frappe.call("frappe.tests.ui_test_helpers.create_contact_records");
return cy.window().its('frappe').then(frappe => {
return frappe.call("frappe.tests.ui_test_helpers.create_contact_records");
});
});
beforeEach(() => {

View file

@ -180,7 +180,7 @@ Cypress.Commands.add('fill_field', (fieldname, value, fieldtype = 'Data') => {
cy.get('.datepickers-container .datepicker.active').should('exist');
}
if (fieldtype === 'Time') {
cy.get('@input').clear();
cy.get('@input').clear().wait(200);
}
if (fieldtype === 'Select') {

View file

@ -289,7 +289,7 @@ def log(msg):
debug_log.append(as_unicode(msg))
def msgprint(msg, title=None, raise_exception=0, as_table=False, indicator=None, alert=False, primary_action=None):
def msgprint(msg, title=None, raise_exception=0, as_table=False, indicator=None, alert=False, primary_action=None, is_minimizable=None):
"""Print a message to the user (via HTTP response).
Messages are sent in the `__server_messages` property in the
response JSON and shown in a pop-up / modal.
@ -344,6 +344,9 @@ def msgprint(msg, title=None, raise_exception=0, as_table=False, indicator=None,
if indicator:
out.indicator = indicator
if is_minimizable:
out.is_minimizable = is_minimizable
if alert:
out.alert = 1
@ -374,12 +377,12 @@ def clear_last_message():
if len(local.message_log) > 0:
local.message_log = local.message_log[:-1]
def throw(msg, exc=ValidationError, title=None):
def throw(msg, exc=ValidationError, title=None, is_minimizable=None):
"""Throw execption and show message (`msgprint`).
:param msg: Message.
:param exc: Exception class. Default `frappe.ValidationError`"""
msgprint(msg, raise_exception=exc, title=title, indicator='red')
msgprint(msg, raise_exception=exc, title=title, indicator='red', is_minimizable=is_minimizable)
def emit_js(js, user=False, **kwargs):
if user == False:

View file

@ -26,9 +26,11 @@
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Desk Page",
"extends_another_page": 0,
"idx": 0,
"is_standard": 1,
"label": "Tools",
"modified": "2020-03-05 11:27:26.106013",
"modified": "2020-03-12 16:30:41.841895",
"modified_by": "Administrator",
"module": "Automation",
"name": "Tools",

View file

@ -12,6 +12,7 @@ from six import text_type
@click.command('new-site')
@click.argument('site')
@click.option('--db-name', help='Database name')
@click.option('--db-password', help='Database password')
@click.option('--db-type', default='mariadb', type=click.Choice(['mariadb', 'postgres']), help='Optional "postgres" or "mariadb". Default is "mariadb"')
@click.option('--db-host', help='Database Host')
@click.option('--db-port', type=int, help='Database Port')
@ -25,21 +26,21 @@ from six import text_type
@click.option('--install-app', multiple=True, help='Install app after installation')
def new_site(site, mariadb_root_username=None, mariadb_root_password=None, admin_password=None,
verbose=False, install_apps=None, source_sql=None, force=None, no_mariadb_socket=False,
install_app=None, db_name=None, db_type=None, db_host=None, db_port=None):
install_app=None, db_name=None, db_password=None, db_type=None, db_host=None, db_port=None):
"Create a new site"
frappe.init(site=site, new_site=True)
_new_site(db_name, site, mariadb_root_username=mariadb_root_username,
mariadb_root_password=mariadb_root_password, admin_password=admin_password,
verbose=verbose, install_apps=install_app, source_sql=source_sql, force=force,
no_mariadb_socket=no_mariadb_socket, db_type=db_type, db_host=db_host, db_port=db_port)
no_mariadb_socket=no_mariadb_socket, db_password=db_password, db_type=db_type, db_host=db_host, db_port=db_port)
if len(frappe.utils.get_sites()) == 1:
use(site)
def _new_site(db_name, site, mariadb_root_username=None, mariadb_root_password=None,
admin_password=None, verbose=False, install_apps=None, source_sql=None, force=False,
no_mariadb_socket=False, reinstall=False, db_type=None, db_host=None, db_port=None):
no_mariadb_socket=False, reinstall=False, db_password=None, db_type=None, db_host=None, db_port=None):
"""Install a new Frappe site"""
if not force and os.path.exists(site):
@ -73,7 +74,7 @@ def _new_site(db_name, site, mariadb_root_username=None, mariadb_root_password=N
install_db(root_login=mariadb_root_username, root_password=mariadb_root_password,
db_name=db_name, admin_password=admin_password, verbose=verbose,
source_sql=source_sql, force=force, reinstall=reinstall, db_type=db_type, db_host=db_host, db_port=db_port, no_mariadb_socket=no_mariadb_socket)
source_sql=source_sql, force=force, reinstall=reinstall, db_password=db_password, db_type=db_type, db_host=db_host, db_port=db_port, no_mariadb_socket=no_mariadb_socket)
apps_to_install = ['frappe'] + (frappe.conf.get("install_apps") or []) + (list(install_apps) or [])
for app in apps_to_install:

View file

@ -38,9 +38,11 @@
"disable_user_customization": 1,
"docstatus": 0,
"doctype": "Desk Page",
"extends_another_page": 0,
"idx": 0,
"is_standard": 1,
"label": "Settings",
"modified": "2020-03-05 11:27:25.766522",
"modified": "2020-03-12 16:30:43.510434",
"modified_by": "Administrator",
"module": "Core",
"name": "Settings",
@ -66,5 +68,6 @@
"link_to": "Website Settings",
"type": "DocType"
}
]
],
"shortcuts_label": "Settings"
}

View file

@ -23,9 +23,11 @@
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Desk Page",
"extends_another_page": 0,
"idx": 0,
"is_standard": 1,
"label": "Users",
"modified": "2020-03-05 11:27:26.166080",
"modified": "2020-03-12 16:30:42.483376",
"modified_by": "Administrator",
"module": "Core",
"name": "Users",

View file

@ -21,9 +21,11 @@
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Desk Page",
"extends_another_page": 0,
"idx": 0,
"is_standard": 1,
"label": "Customization",
"modified": "2020-03-05 11:27:26.137718",
"modified": "2020-03-12 16:30:42.155206",
"modified_by": "Administrator",
"module": "Custom",
"name": "Customization",

View file

@ -15,6 +15,7 @@ class Workspace:
def build_cache(self):
self.doc = frappe.get_doc("Desk Page", self.page_name)
self.get_pages_to_extend()
user = frappe.get_user()
user.build_permissions()
@ -27,6 +28,22 @@ class Workspace:
self.restricted_doctypes = build_domain_restriced_doctype_cache()
self.restricted_pages = build_domain_restriced_page_cache()
def get_pages_to_extend(self):
pages = frappe.get_all("Desk Page", filters={
"extends": self.page_name,
'restrict_to_domain': ['in', frappe.get_active_domains()]
})
pages = [frappe.get_doc("Desk Page", page['name']) for page in pages]
self.extended_cards = []
self.extended_charts = []
self.extended_shortcuts = []
for page in pages:
self.extended_cards = self.extended_cards + page.cards
self.extended_charts = self.extended_charts + page.charts
self.extended_shortcuts = self.extended_shortcuts + page.shortcuts
def is_item_allowed(self, name, item_type):
item_type = item_type.lower()
@ -43,12 +60,12 @@ class Workspace:
def build_workspace(self):
self.cards = {
'label': self.doc.charts_label,
'label': self.doc.cards_label,
'items': self.get_cards()
}
self.charts = {
'label': self.doc.shortcuts_label,
'label': self.doc.charts_label,
'items': self.get_charts()
}
@ -59,6 +76,8 @@ class Workspace:
def get_cards(self):
cards = self.doc.cards + get_custom_reports_and_doctypes(self.doc.module)
if len(self.extended_cards):
cards = cards + self.extended_cards
default_country = frappe.db.get_default("country")
def _doctype_contains_a_record(name):
@ -120,15 +139,29 @@ class Workspace:
def get_charts(self):
if frappe.has_permission("Dashboard Chart", throw=False):
return [chart for chart in self.doc.charts]
charts = self.doc.charts
if len(self.extended_charts):
charts = charts + self.extended_charts
return [chart for chart in charts]
return []
def get_shortcuts(self):
def _in_active_domains(item):
if not item.restrict_to_domain:
return True
else:
return item.restrict_to_domain in frappe.get_active_domains()
items = []
for item in self.doc.shortcuts:
shortcuts = self.doc.shortcuts
if len(self.extended_shortcuts):
shortcuts = shortcuts + self.extended_shortcuts
for item in shortcuts:
new_item = item.as_dict().copy()
new_item['name'] = _(item.link_to)
if self.is_item_allowed(item.link_to, item.type):
if self.is_item_allowed(item.link_to, item.type) and _in_active_domains(item):
if item.type == "Page":
page = self.allowed_pages[item.link_to]
new_item['label'] = _(page.get("title", frappe.unscrub(item.link_to)))
@ -173,7 +206,10 @@ def get_desk_sidebar_items():
"""Get list of sidebar items for desk
"""
# don't get domain restricted pages
filters = {'restrict_to_domain': ['in', frappe.get_active_domains()]}
filters = {
'restrict_to_domain': ['in', frappe.get_active_domains()],
'extends_another_page': False
}
if not frappe.local.conf.developer_mode:
filters['developer_mode_only'] = '0'
@ -200,12 +236,8 @@ def get_table_with_counts():
def get_custom_reports_and_doctypes(module):
return [
frappe._dict({
"title": "Custom Reports",
"links": get_custom_report_list(module)
}),
frappe._dict({
"title": "Custom DocTypes",
"links": get_custom_doctype_list(module)
"title": "Custom",
"links": get_custom_doctype_list(module) + get_custom_report_list(module)
})
]

View file

@ -2,7 +2,17 @@
// For license information, please see license.txt
frappe.ui.form.on('Desk Page', {
// refresh: function(frm) {
// }
refresh: function(frm) {
frm.get_field("is_standard").toggle(frappe.boot.developer_mode);
frm.get_field("extends_another_page").toggle(frappe.boot.developer_mode);
if (!frappe.boot.developer_mode) {
frm.set_read_only();
frm.fields
.filter(field => field.has_input)
.forEach(field => {
frm.set_df_property(field.df.fieldname, "read_only", "1");
});
frm.disable_save();
}
}
});

View file

@ -8,12 +8,15 @@
"engine": "InnoDB",
"field_order": [
"label",
"extends",
"module",
"restrict_to_domain",
"category",
"restrict_to_domain",
"onboarding",
"icon",
"column_break_3",
"onboarding",
"extends_another_page",
"is_standard",
"developer_mode_only",
"disable_user_customization",
"pin_to_top",
@ -55,6 +58,7 @@
"options": "Desk Shortcut"
},
{
"depends_on": "eval:doc.extends_another_page == 0",
"fieldname": "onboarding",
"fieldtype": "Data",
"label": "Onboarding"
@ -64,6 +68,7 @@
"fieldtype": "Link",
"label": "Restrict to Domain",
"options": "Domain",
"read_only_depends_on": "eval:doc.extends_another_page == 0",
"search_index": 1
},
{
@ -75,6 +80,7 @@
"options": "Module Def"
},
{
"depends_on": "eval:doc.extends_another_page == 0",
"fieldname": "icon",
"fieldtype": "Data",
"label": "Icon"
@ -94,10 +100,12 @@
"fieldtype": "Select",
"label": "Category",
"options": "Modules\nDomains\nPlaces\nAdministration",
"read_only_depends_on": "eval:doc.extends_another_page == 1",
"search_index": 1
},
{
"default": "0",
"depends_on": "eval:doc.extends_another_page == 0",
"fieldname": "developer_mode_only",
"fieldtype": "Check",
"label": "Developer Mode Only",
@ -105,7 +113,7 @@
},
{
"default": "0",
"depends_on": "eval:doc.pin_to_bottom!=1",
"depends_on": "eval:doc.pin_to_bottom!=1 && doc.extends_another_page == 0",
"fieldname": "pin_to_top",
"fieldtype": "Check",
"label": "Pin To Top",
@ -113,6 +121,7 @@
},
{
"default": "0",
"depends_on": "eval:doc.extends_another_page == 0",
"fieldname": "disable_user_customization",
"fieldtype": "Check",
"label": "Disable User Customization",
@ -120,7 +129,7 @@
},
{
"default": "0",
"depends_on": "eval:doc.pin_to_top!=1",
"depends_on": "eval:doc.pin_to_top!=1 && doc.extends_another_page == 0",
"fieldname": "pin_to_bottom",
"fieldtype": "Check",
"label": "Pin To Bottom",
@ -152,10 +161,29 @@
"fieldname": "section_break_18",
"fieldtype": "Section Break",
"label": "Link Cards"
},
{
"default": "0",
"fieldname": "is_standard",
"fieldtype": "Check",
"label": "Is Standard"
},
{
"default": "0",
"fieldname": "extends_another_page",
"fieldtype": "Check",
"label": "Extends Another Page"
},
{
"depends_on": "eval:doc.extends_another_page == 1",
"fieldname": "extends",
"fieldtype": "Link",
"label": "Extends",
"options": "Desk Page"
}
],
"links": [],
"modified": "2020-03-02 20:08:44.856046",
"modified": "2020-03-12 16:38:16.206732",
"modified_by": "Administrator",
"module": "Desk",
"name": "Desk Page",

View file

@ -10,9 +10,19 @@ from frappe.model.document import Document
class DeskPage(Document):
def validate(self):
if (not (frappe.flags.in_install or frappe.flags.in_patch or frappe.flags.in_test or frappe.flags.in_fixtures)
and not frappe.conf.developer_mode):
if (self.is_standard and not frappe.conf.developer_mode and not disable_saving_as_standard()):
frappe.throw(_("You need to be in developer mode to edit this document"))
def on_update(self):
export_to_files(record_list=[['Desk Page', self.name]], record_module=self.module)
if disable_saving_as_standard():
return
if frappe.conf.developer_mode and self.is_standard:
export_to_files(record_list=[['Desk Page', self.name]], record_module=self.module)
def disable_saving_as_standard():
return frappe.flags.in_install or \
frappe.flags.in_patch or \
frappe.flags.in_test or \
frappe.flags.in_fixtures or \
frappe.flags.in_migrate

View file

@ -9,6 +9,7 @@
"icon",
"column_break_4",
"link_to",
"restrict_to_domain",
"is_query_report",
"section_break_5",
"stats_filter",
@ -74,11 +75,17 @@
{
"fieldname": "column_break_4",
"fieldtype": "Column Break"
},
{
"fieldname": "restrict_to_domain",
"fieldtype": "Link",
"label": "Restrict to Domain",
"options": "Domain"
}
],
"istable": 1,
"links": [],
"modified": "2020-02-28 12:59:46.870172",
"modified": "2020-03-11 13:09:00.180528",
"modified_by": "Administrator",
"module": "Desk",
"name": "Desk Shortcut",

View file

@ -22,12 +22,12 @@ from frappe.core.doctype.scheduled_job_type.scheduled_job_type import sync_jobs
def install_db(root_login="root", root_password=None, db_name=None, source_sql=None,
admin_password=None, verbose=True, force=0, site_config=None, reinstall=False,
db_type=None, db_host=None, db_port=None, no_mariadb_socket=False):
db_password=None, db_type=None, db_host=None, db_port=None, no_mariadb_socket=False):
if not db_type:
db_type = frappe.conf.db_type or 'mariadb'
make_conf(db_name, site_config=site_config, db_type=db_type, db_host=db_host, db_port=db_port)
make_conf(db_name, site_config=site_config, db_password=db_password, db_type=db_type, db_host=db_host, db_port=db_port)
frappe.flags.in_install_db = True
frappe.flags.root_login = root_login

View file

@ -29,10 +29,12 @@
"disable_user_customization": 1,
"docstatus": 0,
"doctype": "Desk Page",
"extends_another_page": 0,
"icon": "frapicon-dashboard",
"idx": 0,
"is_standard": 1,
"label": "Integrations",
"modified": "2020-03-05 11:27:26.195829",
"modified": "2020-03-12 16:30:42.823316",
"modified_by": "Administrator",
"module": "Integrations",
"name": "Integrations",

View file

@ -35,10 +35,16 @@ class S3BackupSettings(Document):
frappe.throw(_("Invalid Access Key ID or Secret Access Key."))
try:
conn.create_bucket(Bucket=bucket_lower, CreateBucketConfiguration={
'LocationConstraint': self.region})
except ClientError:
frappe.throw(_("Unable to create bucket: {0}. Change it to a more unique name.").format(bucket_lower))
# Head_bucket returns a 200 OK if the bucket exists and have access to it.
conn.head_bucket(Bucket=bucket_lower)
except ClientError as e:
error_code = e.response['Error']['Code']
if error_code == '403':
frappe.throw(_("Do not have permission to access {0} bucket.").format(bucket_lower))
else: # '400'-Bad request or '404'-Not Found return
# try to create bucket
conn.create_bucket(Bucket=bucket_lower, CreateBucketConfiguration={
'LocationConstraint': self.region})
@frappe.whitelist()

View file

@ -16,16 +16,15 @@ def update_document_title(doctype, docname, title_field=None, old_title=None, ne
"""
Update title from header in form view
"""
if docname and new_name and not docname == new_name:
docname = rename_doc(doctype=doctype, old=docname, new=new_name, merge=merge)
if old_title and new_title and not old_title == new_title:
frappe.db.set_value(doctype, docname, title_field, new_title)
frappe.msgprint(_('Saved'), alert=True, indicator='green')
if docname and new_name and not docname == new_name:
return rename_doc(doctype=doctype, old=docname, new=new_name, merge=merge)
return docname
@frappe.whitelist()
def rename_doc(doctype, old, new, force=False, merge=False, ignore_permissions=False, ignore_if_exists=False, show_alert=True):
"""

View file

@ -266,3 +266,5 @@ frappe.patches.v12_0.change_existing_dashboard_chart_filters
execute:frappe.delete_doc("Test Runner")
execute:frappe.delete_doc_if_exists('DocType', 'Google Maps Settings')
execute:frappe.db.set_default('desktop:home_page', 'workspace')
execute:frappe.delete_doc_if_exists('DocType', 'GSuite Settings')
execute:frappe.delete_doc_if_exists('DocType', 'GSuite Templates')

View file

@ -2,6 +2,8 @@ import frappe
import json
def execute():
if not frappe.db.table_exists('Dashboard Chart'):
return
charts_to_modify = frappe.db.get_all('Dashboard Chart',
fields = ['name', 'filters_json', 'document_type'],

View file

@ -1,12 +1,14 @@
import frappe
from pymysql import InternalError
# This patch deletes all the duplicate indexes created for same column
# The patch only checks for indexes with UNIQUE constraints
def execute():
if frappe.db.db_type != 'mariadb': return
all_tables = frappe.db.get_tables()
if frappe.db.db_type != 'mariadb':
return
all_tables = frappe.db.get_tables()
final_deletion_map = frappe._dict()
for table in all_tables:
@ -34,11 +36,14 @@ def execute():
# build drop index query
for (table_name, index_list) in final_deletion_map.items():
query = "ALTER TABLE `{}` ".format(table_name)
query_parts = []
query_list = []
alter_query = "ALTER TABLE `{}`".format(table_name)
for index in index_list:
query_parts.append("DROP INDEX `{}`".format(index))
query_list.append("{} DROP INDEX `{}`".format(alter_query, index))
query = query + ', '.join(query_parts)
frappe.db.sql(query)
for query in query_list:
try:
frappe.db.sql(query)
except InternalError:
pass

View file

@ -23,7 +23,6 @@ frappe.ui.form.LinkedWith = class LinkedWith {
make_dialog() {
this.dialog = new frappe.ui.Dialog({
hide_on_page_refresh: true,
title: __("Linked With")
});

View file

@ -200,7 +200,7 @@ $(window).on('hashchange', function() {
return;
// hide open dialog
if(window.cur_dialog && cur_dialog.hide_on_page_refresh) {
if(window.cur_dialog) {
if (!cur_dialog.minimizable) {
cur_dialog.hide();
} else if (!cur_dialog.is_minimized) {

View file

@ -14,9 +14,9 @@ frappe.ui.DashboardChart = class DashboardChart {
this.get_settings().then(() => {
this.prepare_chart_object();
this.prepare_container();
this.setup_filter_button();
if (!this.options.hide_actions || this.options.hide_actions == undefined) {
this.setup_filter_button();
if (this.chart_doc.timeseries && this.chart_doc.chart_type !== 'Custom') {
this.render_time_series_filters();
}

View file

@ -79,7 +79,7 @@ frappe.prompt = function(fields, callback, title, primary_label) {
return d;
}
frappe.msgprint = function(msg, title) {
frappe.msgprint = function(msg, title, is_minimizable) {
if(!msg) return;
if($.isPlainObject(msg)) {
@ -117,7 +117,8 @@ frappe.msgprint = function(msg, title) {
frappe.msg_dialog.custom_onhide();
}
frappe.msg_dialog.msg_area.empty();
}
},
minimizable: data.is_minimizable || is_minimizable
});
// class "msgprint" is used in tests

View file

@ -297,7 +297,7 @@ class DesktopPage {
},
{
color: "red",
description: __("DocType has Open Entries")
description: __("Has Open Entries")
}
].map(item => {
return `<div class="legend-item small text-muted justify-flex-start">

View file

@ -1148,6 +1148,9 @@ body.no-sidebar {
bottom: 0;
margin: 0;
max-width: 500px;
.modal-content {
min-height: 0;
}
}
.modal-body {
display: none;

View file

@ -30,9 +30,11 @@
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Desk Page",
"extends_another_page": 0,
"idx": 0,
"is_standard": 1,
"label": "Website",
"modified": "2020-03-05 11:27:26.219436",
"modified": "2020-03-12 16:30:43.092622",
"modified_by": "Administrator",
"module": "Website",
"name": "Website",