Browse Source

Merge branch 'develop' into timeline-missing-comments

version-14
Suraj Shetty 3 years ago
committed by GitHub
parent
commit
92fceb88d5
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 207 additions and 68 deletions
  1. +1
    -0
      .github/workflows/server-mariadb-tests.yml
  2. +1
    -0
      .github/workflows/server-postgres-tests.yml
  3. +0
    -2
      frappe/desk/treeview.py
  4. +1
    -1
      frappe/public/js/frappe/form/controls/base_control.js
  5. +2
    -0
      frappe/public/js/frappe/form/controls/comment.js
  6. +3
    -0
      frappe/public/js/frappe/form/controls/text_editor.js
  7. +4
    -0
      frappe/public/js/frappe/form/form.js
  8. +54
    -27
      frappe/public/js/frappe/list/bulk_operations.js
  9. +17
    -0
      frappe/public/js/frappe/ui/page.js
  10. +14
    -12
      frappe/public/js/frappe/views/workspace/workspace.js
  11. +26
    -26
      frappe/public/scss/desk/desktop.scss
  12. +67
    -0
      frappe/tests/test_webform.py
  13. +3
    -0
      frappe/translate.py
  14. +6
    -0
      frappe/www/_test/_test_webform.py
  15. +8
    -0
      frappe/www/list.py

+ 1
- 0
.github/workflows/server-mariadb-tests.yml View File

@@ -121,6 +121,7 @@ jobs:
ORCHESTRATOR_URL: http://test-orchestrator.frappe.io

- name: Upload coverage data
if: ${{ steps.check-build.outputs.build == 'strawberry' }}
uses: codecov/codecov-action@v2
with:
name: MariaDB


+ 1
- 0
.github/workflows/server-postgres-tests.yml View File

@@ -124,6 +124,7 @@ jobs:
ORCHESTRATOR_URL: http://test-orchestrator.frappe.io

- name: Upload coverage data
if: ${{ steps.check-build.outputs.build == 'strawberry' }}
uses: codecov/codecov-action@v2
with:
name: Postgres


+ 0
- 2
frappe/desk/treeview.py View File

@@ -69,13 +69,11 @@ def make_tree_args(**kwarg):

doctype = kwarg['doctype']
parent_field = 'parent_' + doctype.lower().replace(' ', '_')
name_field = kwarg.get('name_field', doctype.lower().replace(' ', '_') + '_name')

if kwarg['is_root'] == 'false': kwarg['is_root'] = False
if kwarg['is_root'] == 'true': kwarg['is_root'] = True

kwarg.update({
name_field: kwarg[name_field],
parent_field: kwarg.get("parent") or kwarg.get(parent_field)
})



+ 1
- 1
frappe/public/js/frappe/form/controls/base_control.js View File

@@ -131,7 +131,7 @@ frappe.ui.form.Control = class BaseControl {
if (!this.doc.__islocal) {
new frappe.views.TranslationManager({
'df': this.df,
'source_text': value,
'source_text': this.value,
'target_language': this.doc.language,
'doc': this.doc
});


+ 2
- 0
frappe/public/js/frappe/form/controls/comment.js View File

@@ -104,8 +104,10 @@ frappe.ui.form.ControlComment = class ControlComment extends frappe.ui.form.Cont
return [
['bold', 'italic', 'underline'],
['blockquote', 'code-block'],
[{ 'direction': "rtl" }],
['link', 'image'],
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
[{ 'align': [] }],
['clean']
];
}


+ 3
- 0
frappe/public/js/frappe/form/controls/text_editor.js View File

@@ -164,8 +164,11 @@ frappe.ui.form.ControlTextEditor = class ControlTextEditor extends frappe.ui.for
['bold', 'italic', 'underline', 'clean'],
[{ 'color': [] }, { 'background': [] }],
['blockquote', 'code-block'],
// Adding Direction tool to give the user the ability to change text direction.
[{ 'direction': "rtl" }],
['link', 'image'],
[{ 'list': 'ordered' }, { 'list': 'bullet' }, { 'list': 'check' }],
[{ 'align': [] }],
[{ 'indent': '-1'}, { 'indent': '+1' }],
[{'table': [
'insert-table',


+ 4
- 0
frappe/public/js/frappe/form/form.js View File

@@ -1152,6 +1152,10 @@ frappe.ui.form.Form = class FrappeForm {
return btn;
}

change_custom_button_type(label, group, type) {
this.page.change_inner_button_type(label, group, type);
}

clear_custom_buttons() {
this.page.clear_inner_toolbar();
this.page.clear_user_actions();


+ 54
- 27
frappe/public/js/frappe/list/bulk_operations.js View File

@@ -4,7 +4,7 @@ export default class BulkOperations {
this.doctype = doctype;
}

print(docs) {
print (docs) {
const print_settings = frappe.model.get_doc(':Print Settings', 'Print Settings');
const allow_print_for_draft = cint(print_settings.allow_print_for_draft);
const is_submittable = frappe.model.is_submittable(this.doctype);
@@ -27,31 +27,38 @@ export default class BulkOperations {
if (valid_docs.length > 0) {
const dialog = new frappe.ui.Dialog({
title: __('Print Documents'),
fields: [{
'fieldtype': 'Check',
'label': __('With Letterhead'),
'fieldname': 'with_letterhead'
},
{
'fieldtype': 'Select',
'label': __('Print Format'),
'fieldname': 'print_sel',
options: frappe.meta.get_print_formats(this.doctype)
}]
fields: [
{
'fieldtype': 'Select',
'label': __('Letter Head'),
'fieldname': 'letter_sel',
'default': __('No Letterhead'),
options: this.get_letterhead_options()
},
{
'fieldtype': 'Select',
'label': __('Print Format'),
'fieldname': 'print_sel',
options: frappe.meta.get_print_formats(this.doctype)
}
]
});

dialog.set_primary_action(__('Print'), args => {
if (!args) return;
const default_print_format = frappe.get_meta(this.doctype).default_print_format;
const with_letterhead = args.with_letterhead ? 1 : 0;
const with_letterhead = args.letter_sel == __("No Letterhead") ? 0 : 1;
const print_format = args.print_sel ? args.print_sel : default_print_format;
const json_string = JSON.stringify(valid_docs);
const letterhead = args.letter_sel;
const w = window.open('/api/method/frappe.utils.print_format.download_multi_pdf?' +
'doctype=' + encodeURIComponent(this.doctype) +
'&name=' + encodeURIComponent(json_string) +
'&format=' + encodeURIComponent(print_format) +
'&no_letterhead=' + (with_letterhead ? '0' : '1'));
'&no_letterhead=' + (with_letterhead ? '0' : '1') +
'&letterhead=' + encodeURIComponent(letterhead)
);

if (!w) {
frappe.msgprint(__('Please enable pop-ups'));
return;
@@ -64,7 +71,28 @@ export default class BulkOperations {
}
}

delete(docnames, done = null) {
get_letterhead_options () {
const letterhead_options = [__("No Letterhead")];
frappe.call({
method: "frappe.client.get_list",
args: {
doctype: 'Letter Head',
fields: ['name', 'is_default'],
limit: 0
},
async: false,
callback (r) {
if (r.message) {
r.message.forEach(letterhead => {
letterhead_options.push(letterhead.name);
});
}
}
});
return letterhead_options;
}

delete (docnames, done = null) {
frappe
.call({
method: 'frappe.desk.reportview.delete_items',
@@ -88,7 +116,7 @@ export default class BulkOperations {
});
}

assign(docnames, done) {
assign (docnames, done) {
if (docnames.length > 0) {
const assign_to = new frappe.ui.form.AssignToDialog({
obj: this,
@@ -106,7 +134,7 @@ export default class BulkOperations {
}
}

apply_assignment_rule(docnames, done) {
apply_assignment_rule (docnames, done) {
if (docnames.length > 0) {
frappe.call('frappe.automation.doctype.assignment_rule.assignment_rule.bulk_apply', {
doctype: this.doctype,
@@ -115,7 +143,7 @@ export default class BulkOperations {
}
}

submit_or_cancel(docnames, action='submit', done=null) {
submit_or_cancel (docnames, action = 'submit', done = null) {
action = action.toLowerCase();
frappe
.call({
@@ -140,7 +168,7 @@ export default class BulkOperations {
});
}

edit(docnames, field_mappings, done) {
edit (docnames, field_mappings, done) {
let field_options = Object.keys(field_mappings).sort();
const status_regex = /status/i;

@@ -198,16 +226,16 @@ export default class BulkOperations {

if (default_field) set_value_field(dialog); // to set `Value` df based on default `Field`

function set_value_field(dialogObj) {
function set_value_field (dialogObj) {
const new_df = Object.assign({},
field_mappings[dialogObj.get_value('field')]);
/* if the field label has status in it and
if it has select fieldtype with no default value then
set a default value from the available option. */
if(new_df.label.match(status_regex) &&
if (new_df.label.match(status_regex) &&
new_df.fieldtype === 'Select' && !new_df.default) {
let options = [];
if(typeof new_df.options==="string") {
if (typeof new_df.options === "string") {
options = new_df.options.split("\n");
}
//set second option as default if first option is an empty string
@@ -223,8 +251,7 @@ export default class BulkOperations {
dialog.show();
}


add_tags(docnames, done) {
add_tags (docnames, done) {
const dialog = new frappe.ui.Dialog({
title: __('Add Tags'),
fields: [
@@ -233,7 +260,7 @@ export default class BulkOperations {
fieldname: 'tags',
label: __("Tags"),
reqd: true,
get_data: function(txt) {
get_data: function (txt) {
return frappe.db.get_link_options("Tag", txt);
}
},
@@ -262,7 +289,7 @@ export default class BulkOperations {
dialog.show();
}

export(doctype, docnames) {
export (doctype, docnames) {
frappe.require('data_import_tools.bundle.js', () => {
const data_exporter = new frappe.data_import.DataExporter(doctype, 'Insert New Records');
data_exporter.dialog.set_value('export_records', 'by_filter');


+ 17
- 0
frappe/public/js/frappe/ui/page.js View File

@@ -618,6 +618,23 @@ frappe.ui.Page = class Page {
}
}

change_inner_button_type(label, group, type) {
let btn;

if (group) {
var $group = this.get_inner_group_button(__(group));
if ($group.length) {
btn = $group.find(`.dropdown-item[data-label="${encodeURIComponent(label)}"]`);
}
} else {
btn = this.inner_toolbar.find(`button[data-label="${encodeURIComponent(label)}"]`);
}

if (btn) {
btn.removeClass().addClass(`btn btn-${type} ellipsis`);
}
}

add_inner_message(message) {
let $message = $(`<span class='inner-page-message text-muted small'>${message}</div>`);
this.inner_toolbar.find('.inner-page-message').remove();


+ 14
- 12
frappe/public/js/frappe/views/workspace/workspace.js View File

@@ -155,7 +155,7 @@ frappe.views.Workspace = class Workspace {
});

// Scroll sidebar to selected page if it is not in viewport.
!frappe.dom.is_element_in_viewport(this.sidebar.find('.selected'))
!frappe.dom.is_element_in_viewport(this.sidebar.find('.selected'))
&& this.sidebar.find('.selected')[0].scrollIntoView();
}

@@ -185,7 +185,7 @@ frappe.views.Workspace = class Workspace {
}

append_item(item, container) {
let is_current_page = frappe.router.slug(item.title) == frappe.router.slug(this.get_page_to_show().name)
let is_current_page = frappe.router.slug(item.title) == frappe.router.slug(this.get_page_to_show().name)
&& item.public == this.get_page_to_show().public;
if (is_current_page) {
item.selected = true;
@@ -253,11 +253,13 @@ frappe.views.Workspace = class Workspace {
if (!this.page_data || Object.keys(this.page_data).length === 0) return;

return frappe.dashboard_utils.get_dashboard_settings().then(settings => {
let chart_config = settings.chart_config ? JSON.parse(settings.chart_config) : {};
if (this.page_data.charts && this.page_data.charts.items) {
this.page_data.charts.items.map(chart => {
chart.chart_settings = chart_config[chart.chart_name] || {};
});
if (settings) {
let chart_config = settings.chart_config ? JSON.parse(settings.chart_config) : {};
if (this.page_data.charts && this.page_data.charts.items) {
this.page_data.charts.items.map(chart => {
chart.chart_settings = chart_config[chart.chart_name] || {};
});
}
}
});
});
@@ -560,7 +562,7 @@ frappe.views.Workspace = class Workspace {
fieldname: 'is_public',
depends_on: `eval:${this.has_access}`,
onchange: function() {
d.set_df_property('parent', 'options',
d.set_df_property('parent', 'options',
this.get_value() ? me.public_parent_pages : me.private_parent_pages);
}
},
@@ -704,9 +706,9 @@ frappe.views.Workspace = class Workspace {
}
});

let blocks = outputData.blocks.filter(
item => item.type != 'card' ||
(item.data.card_name !== 'Custom Documents' &&
let blocks = outputData.blocks.filter(
item => item.type != 'card' ||
(item.data.card_name !== 'Custom Documents' &&
item.data.card_name !== 'Custom Reports')
);

@@ -752,4 +754,4 @@ frappe.views.Workspace = class Workspace {
this.setup_pages();
this.undo.readOnly = true;
}
};
};

+ 26
- 26
frappe/public/scss/desk/desktop.scss View File

@@ -17,10 +17,10 @@ body {
}

.standard-sidebar-section {
margin-top: var(--margin-xl);
margin-bottom: var(--margin-xl);

&:first-of-type {
margin-top: var(--margin-sm);
&:last-of-type {
margin-bottom: var(--margin-sm);
}
}
}
@@ -143,7 +143,7 @@ body {
font-weight: 500;
line-height: 1.3em;
color: var(--heading-color);
svg {
flex: none;
margin-right: 6px;
@@ -863,7 +863,7 @@ body {
.drag-handle {
display: inline-block;
}
.delete-page {
display: inline-block;
margin-right: 8px;
@@ -888,44 +888,44 @@ body {

.codex-editor {
min-height: 630px;
.codex-editor__redactor{
display: flex;
flex-wrap: wrap;
flex-direction: row;
margin: 0px -7px;
padding-bottom: 20px !important;
.ce-block{
width: 100%;
padding-left: 0;
padding-right: 0;
&.ce-block--selected {
.ce-block__content {
background-color: inherit;
}
}
.ce-block__content {
max-width: 100%;
height: 100%;
padding: 7px;
&> div {
height: 100%;
}
.tune-btn > * {
pointer-events: none;
}
.ce-header {
padding: 0 !important;
margin-bottom: 0 !important;
flex: 1;
}
.widget{
&.header {
display: flex;
@@ -938,11 +938,11 @@ body {
background-color: var(--control-bg);
color: var(--text-muted);
}
&:focus {
outline: none;
}
&.new-widget {
align-items: inherit;
}
@@ -959,7 +959,7 @@ body {
gap: 5px;
background-color: var(--card-bg);
padding-left: 5px;
.drag-handle {
cursor: all-scroll;
cursor: -webkit-grabbing;
@@ -969,22 +969,22 @@ body {
}
}
}
svg {
fill: none;
}
.ce-toolbar {
svg {
fill: currentColor;
}
.icon {
stroke: none;
width: fit-content;
height: fit-content;
}
.ce-settings {
width: fit-content;

@@ -1011,18 +1011,18 @@ body {
border-radius: 0 4px 4px 0;z-index: 0;
}
}
.ce-toolbar__settings-btn {
display: none;
}
}
.ce-inline-tool, .ce-inline-toolbar__dropdown {
.icon {
fill: currentColor;
}
}
@media (min-width: 1199px) {
.ce-toolbar__content {
max-width: 930px;
@@ -1033,14 +1033,14 @@ body {
max-width: 760px;
}
}
@media (max-width: 1199px) {
.ce-block.col-4 {
flex: 0 0 50%;
max-width: 50%;
}
}
@media (max-width: 750px) {
.ce-block.col-4 {
flex: 0 0 100%;
@@ -1053,6 +1053,6 @@ body {
max-width: 100%;
}
}
}
}

+ 67
- 0
frappe/tests/test_webform.py View File

@@ -0,0 +1,67 @@
import unittest

import frappe
from frappe.www.list import get_list_context


class TestWebsite(unittest.TestCase):
def test_get_context_hook_of_webform(self):
create_custom_doctype()
create_webform()

# check context for apps without any hook
context_list = get_list_context("", "Custom Doctype", "test-webform")
self.assertFalse(context_list)

# create a hook to get webform_context
set_webform_hook(
"webform_list_context",
"frappe.www._test._test_webform.webform_list_context",
)
# check context for apps with hook
context_list = get_list_context("", "Custom Doctype", "test-webform")
self.assertTrue(context_list)


def create_custom_doctype():
frappe.get_doc(
{
"doctype": "DocType",
"name": "Custom Doctype",
"module": "Core",
"custom": 1,
"fields": [{"label": "Title", "fieldname": "title", "fieldtype": "Data"}],
}
).insert(ignore_if_duplicate=True)


def create_webform():
frappe.get_doc(
{
"doctype": "Web Form",
"module": "Core",
"title": "Test Webform",
"route": "test-webform",
"doc_type": "Custom Doctype",
"web_form_fields": [
{
"doctype": "Web Form Field",
"fieldname": "title",
"fieldtype": "Data",
"label": "Title",
}
],
}
).insert(ignore_if_duplicate=True)


def set_webform_hook(key, value):
from frappe import hooks

# reset hooks
for hook in "webform_list_context":
if hasattr(hooks, hook):
delattr(hooks, hook)

setattr(hooks, key, value)
frappe.cache().delete_key("app_hooks")

+ 3
- 0
frappe/translate.py View File

@@ -821,6 +821,9 @@ def update_translations_for_source(source=None, translation_dict=None):

translation_dict = json.loads(translation_dict)

if is_html(source):
source = strip_html_tags(source)

# for existing records
translation_records = frappe.db.get_values('Translation', {
'source_text': source


+ 6
- 0
frappe/www/_test/_test_webform.py View File

@@ -0,0 +1,6 @@
def webform_list_context(module):
return {"get_list": get_webform_context_list}


def get_webform_context_list():
pass

+ 8
- 0
frappe/www/list.py View File

@@ -161,6 +161,14 @@ def get_list_context(context, doctype, web_form_name=None):
module = load_doctype_module(doctype)
list_context = update_context_from_module(module, list_context)

# get context for custom webform
if meta.custom and web_form_name:
webform_list_contexts = frappe.get_hooks('webform_list_context')
if webform_list_contexts:
out = frappe._dict(frappe.get_attr(webform_list_contexts[0])(meta.module) or {})
if out:
list_context = out

# get context from web form module
if web_form_name:
web_form = frappe.get_doc('Web Form', web_form_name)


Loading…
Cancel
Save