Merge branch 'develop' of https://github.com/frappe/frappe into auto-generate-rtl-style
This commit is contained in:
commit
3d3d8bdfca
25 changed files with 97 additions and 73 deletions
2
.github/workflows/ui-tests.yml
vendored
2
.github/workflows/ui-tests.yml
vendored
|
|
@ -105,3 +105,5 @@ jobs:
|
|||
|
||||
- name: UI Tests
|
||||
run: cd ~/frappe-bench/ && bench --site test_site run-ui-tests frappe --headless --parallel --ci-build-id $GITHUB_RUN_ID
|
||||
env:
|
||||
CYPRESS_RECORD_KEY: 4a48f41c-11b3-425b-aa88-c58048fa69eb
|
||||
|
|
|
|||
|
|
@ -4,13 +4,10 @@
|
|||
# the repo. Unless a later match takes precedence,
|
||||
|
||||
* @frappe/frappe-review-team
|
||||
website/ @prssanna
|
||||
web_form/ @prssanna
|
||||
templates/ @surajshetty3416
|
||||
www/ @surajshetty3416
|
||||
integrations/ @leela
|
||||
patches/ @surajshetty3416
|
||||
dashboard/ @prssanna
|
||||
email/ @leela
|
||||
event_streaming/ @ruchamahabal
|
||||
data_import* @netchampfaris
|
||||
|
|
|
|||
|
|
@ -661,7 +661,7 @@ def run_ui_tests(context, app, headless=False, parallel=True, ci_build_id=None):
|
|||
frappe.commands.popen("yarn add cypress@^6 cypress-file-upload@^5 --no-lockfile")
|
||||
|
||||
# run for headless mode
|
||||
run_or_open = 'run --browser firefox --record --key 4a48f41c-11b3-425b-aa88-c58048fa69eb' if headless else 'open'
|
||||
run_or_open = 'run --browser firefox --record' if headless else 'open'
|
||||
command = '{site_env} {password_env} {cypress} {run_or_open}'
|
||||
formatted_command = command.format(site_env=site_env, password_env=password_env, cypress=cypress_path, run_or_open=run_or_open)
|
||||
|
||||
|
|
@ -770,19 +770,23 @@ def set_config(context, key, value, global_=False, parse=False, as_dict=False):
|
|||
@click.command('version')
|
||||
def get_version():
|
||||
"Show the versions of all the installed apps"
|
||||
from git import Repo
|
||||
from frappe.utils.change_log import get_app_branch
|
||||
frappe.init('')
|
||||
|
||||
for m in sorted(frappe.get_all_apps()):
|
||||
branch_name = get_app_branch(m)
|
||||
module = frappe.get_module(m)
|
||||
app_hooks = frappe.get_module(m + ".hooks")
|
||||
for app in sorted(frappe.get_all_apps()):
|
||||
branch_name = get_app_branch(app)
|
||||
module = frappe.get_module(app)
|
||||
app_hooks = frappe.get_module(app + ".hooks")
|
||||
repo = Repo(frappe.get_app_path(app, ".."))
|
||||
branch = repo.head.ref.name
|
||||
commit = repo.head.ref.commit.hexsha[:7]
|
||||
|
||||
if hasattr(app_hooks, '{0}_version'.format(branch_name)):
|
||||
print("{0} {1}".format(m, getattr(app_hooks, '{0}_version'.format(branch_name))))
|
||||
click.echo("{0} {1} {2} ({3})".format(app, getattr(app_hooks, '{0}_version'.format(branch_name)), branch, commit))
|
||||
|
||||
elif hasattr(module, "__version__"):
|
||||
print("{0} {1}".format(m, module.__version__))
|
||||
click.echo("{0} {1} {2} ({3})".format(app, module.__version__, branch, commit))
|
||||
|
||||
|
||||
@click.command('rebuild-global-search')
|
||||
|
|
|
|||
|
|
@ -85,8 +85,6 @@ def make(doctype=None, name=None, content=None, subject=None, sent_or_received =
|
|||
if attachments:
|
||||
add_attachments(comm.name, attachments)
|
||||
|
||||
frappe.db.commit()
|
||||
|
||||
if cint(send_email):
|
||||
if not comm.get_outgoing_email_account():
|
||||
frappe.throw(msg=OUTGOING_EMAIL_ACCOUNT_MISSING, exc=frappe.OutgoingEmailError)
|
||||
|
|
|
|||
|
|
@ -368,6 +368,7 @@ def get_desktop_page(page):
|
|||
'allow_customization': not wspace.doc.disable_user_customization
|
||||
}
|
||||
except DoesNotExistError:
|
||||
frappe.log_error(frappe.get_traceback())
|
||||
return {}
|
||||
|
||||
@frappe.whitelist()
|
||||
|
|
|
|||
|
|
@ -43,19 +43,19 @@ class Workspace(Document):
|
|||
|
||||
def get_link_groups(self):
|
||||
cards = []
|
||||
current_card = {
|
||||
current_card = frappe._dict({
|
||||
"label": "Link",
|
||||
"type": "Card Break",
|
||||
"icon": None,
|
||||
"hidden": False,
|
||||
}
|
||||
})
|
||||
|
||||
card_links = []
|
||||
|
||||
for link in self.links:
|
||||
link = link.as_dict()
|
||||
if link.type == "Card Break":
|
||||
if card_links and (not current_card.only_for or current_card.only_for == frappe.get_system_settings('country')):
|
||||
if card_links and (not current_card.only_for or current_card.only_for == frappe.get_system_settings('country')):
|
||||
current_card['links'] = card_links
|
||||
cards.append(current_card)
|
||||
|
||||
|
|
|
|||
|
|
@ -83,11 +83,15 @@ class BaseDocument(object):
|
|||
|
||||
@property
|
||||
def meta(self):
|
||||
if not hasattr(self, "_meta"):
|
||||
if not getattr(self, "_meta", None):
|
||||
self._meta = frappe.get_meta(self.doctype)
|
||||
|
||||
return self._meta
|
||||
|
||||
def __getstate__(self):
|
||||
self._meta = None
|
||||
return self.__dict__
|
||||
|
||||
def update(self, d):
|
||||
""" Update multiple fields of a doctype using a dictionary of key-value pairs.
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ frappe.ui.form.Attachments = class Attachments {
|
|||
this.parent.find(".add-attachment-btn").click(function() {
|
||||
me.new_attachment();
|
||||
});
|
||||
this.add_attachment_wrapper = this.parent.find(".add_attachment").parent();
|
||||
this.add_attachment_wrapper = this.parent.find(".add-attachment-btn");
|
||||
this.attachments_label = this.parent.find(".attachments-label");
|
||||
}
|
||||
max_reached(raise_exception=false) {
|
||||
|
|
@ -39,7 +39,7 @@ frappe.ui.form.Attachments = class Attachments {
|
|||
this.parent.find(".attachment-row").remove();
|
||||
|
||||
var max_reached = this.max_reached();
|
||||
this.add_attachment_wrapper.toggleClass("hide", !max_reached);
|
||||
this.add_attachment_wrapper.toggle(!max_reached);
|
||||
|
||||
// add attachment objects
|
||||
var attachments = this.get_attachments();
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
{% } %}
|
||||
<div class="col-md-4">
|
||||
<div class="form-link-title">
|
||||
<span>{{ transactions[i].label }}<span>
|
||||
<span>{{ __(transactions[i].label) }}<span>
|
||||
</div>
|
||||
{% for (let j=0; j < transactions[i].items.length; j++) { %}
|
||||
{% let doctype = transactions[i].items[j]; %}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
{% } %}
|
||||
<div class="col-md-4">
|
||||
<div class="form-link-title">
|
||||
<span>{{ reports[i].label }}</span>
|
||||
<span>{{ __(reports[i].label) }}</span>
|
||||
</div>
|
||||
{% for (let j=0; j < reports[i].items.length; j++) { %}
|
||||
{% let report = reports[i].items[j]; %}
|
||||
|
|
|
|||
|
|
@ -728,7 +728,7 @@ frappe.views.CommunicationComposer = class {
|
|||
const SALUTATION_END_COMMENT = "<!-- salutation-ends -->";
|
||||
if (this.real_name && !message.includes(SALUTATION_END_COMMENT)) {
|
||||
this.message = `
|
||||
<p>${__('Dear')} ${this.real_name},</p>
|
||||
<p>${__('Dear {0},', [this.real_name], 'Salutation in new email')},</p>
|
||||
${SALUTATION_END_COMMENT}<br>
|
||||
${message}
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ export default class LinksWidget extends Widget {
|
|||
const opts = {
|
||||
name: item.link_to,
|
||||
type: item.link_type,
|
||||
doctype: item.doctype,
|
||||
is_query_report: item.is_query_report
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -291,10 +291,18 @@ var verify_token = function (event) {
|
|||
}
|
||||
|
||||
var request_otp = function (r) {
|
||||
const otp_form_template = '{{ _("Verification") }}<input type="text" id="login_token" autocomplete="off" class="form-control" placeholder={{ _("Verification Code") }} required="" autofocus="">{{ _("Verify") }}';
|
||||
$('.login-content').empty();
|
||||
$('.login-content:visible').append(
|
||||
$('<div>').attr({ 'id': 'twofactor_div' }).html(otp_form_template)
|
||||
`<div id="twofactor_div">
|
||||
<form class="form-verify">
|
||||
<div class="page-card-head">
|
||||
<span class="indicator blue" data-text="Verification">{{ _("Verification") }}</span>
|
||||
</div>
|
||||
<div id="otp_div"></div>
|
||||
<input type="text" id="login_token" autocomplete="off" class="form-control" placeholder={{ _("Verification Code") }} required="" autofocus="">
|
||||
<button class="btn btn-sm btn-primary btn-block mt-3" id="verify_token">{{ _("Verify") }}</button>
|
||||
</form>
|
||||
</div>`
|
||||
);
|
||||
// add event handler for submit button
|
||||
verify_token();
|
||||
|
|
|
|||
|
|
@ -1,20 +1,9 @@
|
|||
<!-- base template for testing -->
|
||||
<html>
|
||||
<head>
|
||||
{%- block style %}
|
||||
{% if colocated_css -%}
|
||||
<style>{{ colocated_css }}</style>
|
||||
{%- endif %}
|
||||
{%- endblock -%}
|
||||
</head>
|
||||
<body>
|
||||
{% include "templates/includes/breadcrumbs.html" %}
|
||||
<h1>This is for testing</h1>
|
||||
{% block content %}{% endblock %}
|
||||
{%- block script %}
|
||||
{% if colocated_js -%}
|
||||
<script>{{ colocated_js }}</script>
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
20
frappe/templates/test/_test_base_breadcrumbs.html
Normal file
20
frappe/templates/test/_test_base_breadcrumbs.html
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<!-- base template for testing -->
|
||||
<html>
|
||||
<head>
|
||||
{%- block style %}
|
||||
{% if colocated_css -%}
|
||||
<style>{{ colocated_css }}</style>
|
||||
{%- endif %}
|
||||
{%- endblock -%}
|
||||
</head>
|
||||
<body>
|
||||
{% include "templates/includes/breadcrumbs.html" %}
|
||||
<h1>This is for testing</h1>
|
||||
{% block content %}{% endblock %}
|
||||
{%- block script %}
|
||||
{% if colocated_js -%}
|
||||
<script>{{ colocated_js }}</script>
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -244,14 +244,22 @@ class TestWebsite(unittest.TestCase):
|
|||
self.assertIn("<script>console.log('test data');</script>", content)
|
||||
self.assertIn("background-color: var(--bg-color);", content)
|
||||
|
||||
def test_raw_assets_are_loaded(self):
|
||||
content = get_response_content('/_test/assets/js_asset.min.js')
|
||||
# minified js files should not be passed through jinja renderer
|
||||
self.assertEqual("//{% if title %} {{title}} {% endif %}\nconsole.log('in');", content)
|
||||
|
||||
content = get_response_content('/_test/assets/css_asset.css')
|
||||
self.assertEqual("""body{color:red}""", content)
|
||||
|
||||
def test_breadcrumbs(self):
|
||||
content = get_response_content('/_test/_test_folder/_test_page')
|
||||
self.assertIn('<span itemprop="name">Test TOC</span>', content)
|
||||
self.assertIn('<span itemprop="name">Test Folder</span>', content)
|
||||
self.assertIn('<span itemprop="name"> Test Page</span>', content)
|
||||
|
||||
content = get_response_content('/_test/_test_folder/index')
|
||||
self.assertIn('<span itemprop="name"> Test</span>', content)
|
||||
self.assertIn('<span itemprop="name">Test TOC</span>', content)
|
||||
self.assertIn('<span itemprop="name">Test Folder</span>', content)
|
||||
|
||||
def test_get_context_without_context_object(self):
|
||||
content = get_response_content('/_test/_test_no_context')
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ class TemplatePage(BaseTemplatePage):
|
|||
|
||||
self.set_pymodule()
|
||||
self.update_context()
|
||||
self.setup_template()
|
||||
self.setup_template_source()
|
||||
self.load_colocated_files()
|
||||
self.set_properties_from_source()
|
||||
self.post_process_context()
|
||||
|
|
@ -118,7 +118,7 @@ class TemplatePage(BaseTemplatePage):
|
|||
if os.path.exists(os.path.join(self.app_path, self.pymodule_path)):
|
||||
self.pymodule_name = self.app + "." + self.pymodule_path.replace(os.path.sep, ".")[:-3]
|
||||
|
||||
def setup_template(self):
|
||||
def setup_template_source(self):
|
||||
'''Setup template source, frontmatter and markdown conversion'''
|
||||
self.source = self.get_raw_template()
|
||||
self.extract_frontmatter()
|
||||
|
|
@ -126,7 +126,6 @@ class TemplatePage(BaseTemplatePage):
|
|||
|
||||
def update_context(self):
|
||||
self.set_page_properties()
|
||||
self.set_properties_from_source()
|
||||
self.context.build_version = frappe.utils.get_build_version()
|
||||
|
||||
if self.pymodule_name:
|
||||
|
|
@ -150,8 +149,7 @@ class TemplatePage(BaseTemplatePage):
|
|||
|
||||
def set_page_properties(self):
|
||||
self.context.base_template = self.context.base_template \
|
||||
or get_base_template(self.path) \
|
||||
or 'templates/web.html'
|
||||
or get_base_template(self.path)
|
||||
self.context.basepath = self.basepath
|
||||
self.context.basename = self.basename
|
||||
self.context.name = self.name
|
||||
|
|
@ -203,13 +201,10 @@ class TemplatePage(BaseTemplatePage):
|
|||
frappe.errprint(frappe.utils.get_traceback())
|
||||
|
||||
def render_template(self):
|
||||
if self.source:
|
||||
if self.template_path.endswith('min.js'):
|
||||
html = self.source # static
|
||||
else:
|
||||
html = frappe.render_template(self.source, self.context)
|
||||
elif self.template_path:
|
||||
if self.path.endswith('min.js'):
|
||||
html = self.get_raw_template() # static
|
||||
else:
|
||||
html = frappe.get_template(self.template_path).render(self.context)
|
||||
|
||||
return html
|
||||
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ def get_doctypes_with_web_view():
|
|||
doctypes_with_web_view = frappe.get_all('DocType', fields=['name', 'module'],
|
||||
filters=dict(has_web_view=1))
|
||||
module_app_map = frappe.local.module_app
|
||||
doctypes += [d.name for d in doctypes_with_web_view if module_app_map[frappe.scrub(d.module)] in installed_apps]
|
||||
doctypes += [d.name for d in doctypes_with_web_view if module_app_map.get(frappe.scrub(d.module)) in installed_apps]
|
||||
return doctypes
|
||||
|
||||
return frappe.cache().get_value('doctypes_with_web_view', _get)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
{% extends base_template_path %}
|
||||
{% block content %}
|
||||
{% include "templates/includes/web_sidebar.html" %}
|
||||
<p>Test content</p>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
def get_context(context):
|
||||
context.base_template_path = 'frappe/templates/test/_test_base.html'
|
||||
context.base_template_path = 'frappe/templates/test/_test_base_breadcrumbs.html'
|
||||
context.add_breadcrumbs = 1
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
title: Test TOC
|
||||
title: Test Folder
|
||||
add_breadcrumbs: 1
|
||||
show_sidebar: 1
|
||||
base_template: templates/web.html
|
||||
---
|
||||
|
||||
# Index
|
||||
|
||||
{index}
|
||||
0
frappe/www/_test/assets/__init__.py
Normal file
0
frappe/www/_test/assets/__init__.py
Normal file
1
frappe/www/_test/assets/css_asset.css
Normal file
1
frappe/www/_test/assets/css_asset.css
Normal file
|
|
@ -0,0 +1 @@
|
|||
body{color:red}
|
||||
2
frappe/www/_test/assets/js_asset.min.js
vendored
Normal file
2
frappe/www/_test/assets/js_asset.min.js
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
//{% if title %} {{title}} {% endif %}
|
||||
console.log('in');
|
||||
37
yarn.lock
37
yarn.lock
|
|
@ -1381,12 +1381,12 @@ component-bind@1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1"
|
||||
integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=
|
||||
|
||||
component-emitter@1.2.1, component-emitter@^1.2.0:
|
||||
component-emitter@1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
|
||||
integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=
|
||||
|
||||
component-emitter@~1.3.0:
|
||||
component-emitter@^1.2.0, component-emitter@~1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
|
||||
integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
|
||||
|
|
@ -1713,28 +1713,14 @@ debug@2.6.9:
|
|||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@^3.0.1:
|
||||
debug@^3.0.1, debug@^3.1.0, debug@^3.2.6:
|
||||
version "3.2.7"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
|
||||
integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
debug@^3.1.0, debug@^3.2.6:
|
||||
version "3.2.6"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
|
||||
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
debug@^4.1.1, debug@~4.1.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
|
||||
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
debug@^4.2.0, debug@^4.3.1:
|
||||
debug@^4.1.1, debug@^4.2.0, debug@^4.3.1:
|
||||
version "4.3.1"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
|
||||
integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
|
||||
|
|
@ -1748,6 +1734,13 @@ debug@~3.1.0:
|
|||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@~4.1.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
|
||||
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
decamelize@^1.0.0, decamelize@^1.1.2, decamelize@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
||||
|
|
@ -6484,11 +6477,11 @@ socket.io-client@2.4.0:
|
|||
to-array "0.1.4"
|
||||
|
||||
socket.io-parser@~3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f"
|
||||
integrity sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.2.tgz#ef872009d0adcf704f2fbe830191a14752ad50b6"
|
||||
integrity sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg==
|
||||
dependencies:
|
||||
component-emitter "1.2.1"
|
||||
component-emitter "~1.3.0"
|
||||
debug "~3.1.0"
|
||||
isarray "2.0.1"
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue