Merge branch 'develop' into print-format-builder-beta

This commit is contained in:
mergify[bot] 2021-10-22 04:38:08 +00:00 committed by GitHub
commit 868d545ba5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 215 additions and 549 deletions

View file

@ -50,6 +50,7 @@ if [ "$TYPE" == "server" ]; then sed -i 's/^socketio:/# socketio:/g' Procfile; f
if [ "$TYPE" == "server" ]; then sed -i 's/^redis_socketio:/# redis_socketio:/g' Procfile; fi
if [ "$TYPE" == "ui" ]; then bench setup requirements --node; fi
if [ "$TYPE" == "server" ]; then bench setup requirements --dev; fi
# install node-sass which is required for website theme test
cd ./apps/frappe || exit

3
dev-requirements.txt Normal file
View file

@ -0,0 +1,3 @@
Faker~=8.1.0
pyngrok~=5.0.5
unittest-xml-reporting~=3.0.4

View file

@ -30,9 +30,6 @@ from .utils.lazy_loader import lazy_import
from frappe.query_builder import get_query_builder, patch_query_execute
# Lazy imports
faker = lazy_import('faker')
__version__ = '14.0.0-dev'
__title__ = "Frappe Framework"
@ -1838,6 +1835,7 @@ def parse_json(val):
return parse_json(val)
def mock(type, size=1, locale='en'):
import faker
results = []
fake = faker.Faker(locale)
if type not in dir(fake):

View file

@ -1,20 +1,13 @@
{
"category": "",
"charts": [],
"content": "[{\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"ToDo\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Note\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"File\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Assignment Rule\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Auto Repeat\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Tools\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Email\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Automation\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Event Streaming\", \"col\": 4}}]",
"creation": "2020-03-02 14:53:24.980279",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
"extends": "",
"extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "tool",
"idx": 0,
"is_default": 0,
"is_standard": 0,
"label": "Tools",
"links": [
{
@ -215,15 +208,12 @@
"type": "Link"
}
],
"modified": "2021-08-05 12:16:02.839180",
"modified": "2021-08-05 12:16:02.839181",
"modified_by": "Administrator",
"module": "Automation",
"name": "Tools",
"onboarding": "",
"owner": "Administrator",
"parent_page": "",
"pin_to_bottom": 0,
"pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],

View file

@ -16,7 +16,6 @@ from frappe.utils.minify import JavascriptMinify
import click
import psutil
from urllib.parse import urlparse
from simple_chalk import green
from semantic_version import Version
from requests import head
from requests.exceptions import HTTPError
@ -108,7 +107,7 @@ def fetch_assets(url, frappe_head):
if not assets_archive:
raise AssetsNotDownloadedError(f"Assets could not be retrived from {url}")
print(f"\n{green('')} Downloaded Frappe assets from {url}")
click.echo(click.style("", fg="green") + f" Downloaded Frappe assets from {url}")
return assets_archive
@ -131,7 +130,7 @@ def setup_assets(assets_archive):
directories_created.add(asset_directory)
tar.makefile(file, dest)
print("{0} Restored {1}".format(green(''), show))
click.echo(click.style("", fg="green") + f" Restored {show}")
return directories_created
@ -379,7 +378,7 @@ def make_asset_dirs(hard_link=False):
except Exception:
print(fail_message, end="\r")
print(unstrip(f"{green('')} Application Assets Linked") + "\n")
click.echo(unstrip(click.style("", fg="green") + " Application Assets Linked") + "\n")
def link_assets_dir(source, target, hard_link=False):

View file

@ -282,18 +282,17 @@ def bulk_update(docs):
docs = json.loads(docs)
failed_docs = []
for doc in docs:
doc.pop("flags", None)
try:
ddoc = {key: val for key, val in doc.items() if key not in ['doctype', 'docname']}
doctype = doc['doctype']
docname = doc['docname']
doc = frappe.get_doc(doctype, docname)
doc.update(ddoc)
doc.save()
except:
existing_doc = frappe.get_doc(doc.pop("doctype"), doc.pop("docname"))
existing_doc.update(doc)
existing_doc.save()
except Exception:
failed_docs.append({
'doc': doc,
'exc': frappe.utils.get_traceback()
})
return {'failed_docs': failed_docs}
@frappe.whitelist()

View file

@ -1,21 +1,13 @@
{
"cards_label": "Elements",
"category": "",
"charts": [],
"content": "[{\"type\":\"header\",\"data\":{\"text\":\"Your Shortcuts\",\"level\":4,\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"DocType\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Workspace\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Report\",\"col\":4}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"Elements\",\"level\":4,\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Modules\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Models\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Views\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Scripting\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Packages\",\"col\":4}}]",
"creation": "2021-01-02 10:51:16.579957",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
"extends": "",
"extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "tool",
"idx": 0,
"is_default": 0,
"is_standard": 0,
"label": "Build",
"links": [
{
@ -230,15 +222,12 @@
"type": "Link"
}
],
"modified": "2021-09-05 21:14:52.384815",
"modified": "2021-09-05 21:14:52.384816",
"modified_by": "Administrator",
"module": "Core",
"name": "Build",
"onboarding": "",
"owner": "Administrator",
"parent_page": "",
"pin_to_bottom": 0,
"pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],

View file

@ -1,20 +1,13 @@
{
"category": "",
"charts": [],
"content": "[{\"type\": \"header\", \"data\": {\"text\": \"Settings\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"System Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Print Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Website Settings\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Data\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Email / Notifications\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Website\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Core\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Printing\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Workflow\", \"col\": 4}}]",
"content": "[{\"type\":\"header\",\"data\": {\"text\":\"Settings\",\"level\": 4,\"col\": 12}}, {\"type\":\"shortcut\",\"data\": {\"shortcut_name\":\"System Settings\",\"col\": 4}}, {\"type\":\"shortcut\",\"data\": {\"shortcut_name\":\"Print Settings\",\"col\": 4}}, {\"type\":\"shortcut\",\"data\": {\"shortcut_name\":\"Website Settings\",\"col\": 4}}, {\"type\":\"spacer\",\"data\": {\"col\": 12}}, {\"type\":\"header\",\"data\": {\"text\":\"Reports & Masters\",\"level\": 4,\"col\": 12}}, {\"type\":\"card\",\"data\": {\"card_name\":\"Data\",\"col\": 4}}, {\"type\":\"card\",\"data\": {\"card_name\":\"Email / Notifications\",\"col\": 4}}, {\"type\":\"card\",\"data\": {\"card_name\":\"Website\",\"col\": 4}}, {\"type\":\"card\",\"data\": {\"card_name\":\"Core\",\"col\": 4}}, {\"type\":\"card\",\"data\": {\"card_name\":\"Printing\",\"col\": 4}}, {\"type\":\"card\",\"data\": {\"card_name\":\"Workflow\",\"col\": 4}}]",
"creation": "2020-03-02 15:09:40.527211",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
"extends": "",
"extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "setting",
"idx": 0,
"is_default": 0,
"is_standard": 0,
"label": "Settings",
"links": [
{
@ -374,15 +367,12 @@
"type": "Link"
}
],
"modified": "2021-08-05 12:16:03.456173",
"modified": "2021-08-05 12:16:03.456174",
"modified_by": "Administrator",
"module": "Core",
"name": "Settings",
"onboarding": "",
"owner": "Administrator",
"parent_page": "",
"pin_to_bottom": 0,
"pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],
@ -407,6 +397,5 @@
"type": "DocType"
}
],
"shortcuts_label": "Settings",
"title": "Settings"
}

View file

@ -1,20 +1,13 @@
{
"category": "",
"charts": [],
"content": "[{\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"User\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Role\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Permission Manager\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"User Profile\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"User Type\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Users\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Logs\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Permissions\", \"col\": 4}}]",
"creation": "2020-03-02 15:12:16.754449",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
"extends": "",
"extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "users",
"idx": 0,
"is_default": 0,
"is_standard": 0,
"label": "Users",
"links": [
{
@ -152,15 +145,12 @@
"type": "Link"
}
],
"modified": "2021-08-05 12:16:03.010204",
"modified": "2021-08-05 12:16:03.010205",
"modified_by": "Administrator",
"module": "Core",
"name": "Users",
"onboarding": "",
"owner": "Administrator",
"parent_page": "",
"pin_to_bottom": 0,
"pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],

View file

@ -131,7 +131,7 @@ def create_custom_field(doctype, df, ignore_validate=False):
"permlevel": 0,
"fieldtype": 'Data',
"hidden": 0,
# Looks like we always use this programatically?
# Looks like we always use this programatically?
# "is_standard": 1
})
custom_field.update(df)
@ -146,24 +146,29 @@ def create_custom_fields(custom_fields, ignore_validate = False, update=True):
if not ignore_validate and frappe.flags.in_setup_wizard:
ignore_validate = True
for doctype, fields in custom_fields.items():
for doctypes, fields in custom_fields.items():
if isinstance(fields, dict):
# only one field
fields = [fields]
for df in fields:
field = frappe.db.get_value("Custom Field", {"dt": doctype, "fieldname": df["fieldname"]})
if not field:
try:
df["owner"] = "Administrator"
create_custom_field(doctype, df, ignore_validate=ignore_validate)
except frappe.exceptions.DuplicateEntryError:
pass
elif update:
custom_field = frappe.get_doc("Custom Field", field)
custom_field.flags.ignore_validate = ignore_validate
custom_field.update(df)
custom_field.save()
if isinstance(doctypes, str):
# only one doctype
doctypes = (doctypes,)
for doctype in doctypes:
for df in fields:
field = frappe.db.get_value("Custom Field", {"dt": doctype, "fieldname": df["fieldname"]})
if not field:
try:
df["owner"] = "Administrator"
create_custom_field(doctype, df, ignore_validate=ignore_validate)
except frappe.exceptions.DuplicateEntryError:
pass
elif update:
custom_field = frappe.get_doc("Custom Field", field)
custom_field.flags.ignore_validate = ignore_validate
custom_field.update(df)
custom_field.save()
frappe.clear_cache(doctype=doctype)
frappe.db.updatedb(doctype)

View file

@ -6,7 +6,42 @@
import frappe
import unittest
test_records = frappe.get_test_records('Custom Field')
test_records = frappe.get_test_records("Custom Field")
class TestCustomField(unittest.TestCase):
pass
def test_create_custom_fields(self):
from .custom_field import create_custom_fields
create_custom_fields(
{
"Address": [
{
"fieldname": "_test_custom_field_1",
"label": "_Test Custom Field 1",
"fieldtype": "Data",
"insert_after": "phone",
},
],
("Address", "Contact"): [
{
"fieldname": "_test_custom_field_2",
"label": "_Test Custom Field 2",
"fieldtype": "Data",
"insert_after": "phone",
},
],
}
)
frappe.db.commit()
self.assertTrue(
frappe.db.exists("Custom Field", "Address-_test_custom_field_1")
)
self.assertTrue(
frappe.db.exists("Custom Field", "Address-_test_custom_field_2")
)
self.assertTrue(
frappe.db.exists("Custom Field", "Contact-_test_custom_field_2")
)

View file

@ -1,20 +1,13 @@
{
"category": "",
"charts": [],
"content": "[{\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Customize Form\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Custom Role\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Client Script\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Server Script\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Dashboards\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Form Customization\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Other\", \"col\": 4}}]",
"creation": "2020-03-02 15:15:03.839594",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
"extends": "",
"extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "customization",
"idx": 0,
"is_default": 0,
"is_standard": 0,
"label": "Customization",
"links": [
{
@ -130,15 +123,12 @@
"type": "Link"
}
],
"modified": "2021-08-05 12:15:57.486112",
"modified": "2021-08-05 12:15:57.486113",
"modified_by": "Administrator",
"module": "Custom",
"name": "Customization",
"onboarding": "",
"owner": "Administrator",
"parent_page": "",
"pin_to_bottom": 0,
"pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],

View file

@ -32,9 +32,6 @@ class Workspace:
self.page_name = page.get('name')
self.page_title = page.get('title')
self.public_page = page.get('public')
self.extended_links = []
self.extended_charts = []
self.extended_shortcuts = []
self.workspace_manager = "Workspace Manager" in frappe.get_roles()
self.user = frappe.get_user()
@ -151,21 +148,6 @@ class Workspace:
return doc
def get_pages_to_extend(self):
pages = frappe.get_all("Workspace", filters={
"extends": self.page_name,
'restrict_to_domain': ['in', frappe.get_active_domains()],
'for_user': '',
'module': ['in', self.allowed_modules]
})
pages = [frappe.get_cached_doc("Workspace", page['name']) for page in pages]
for page in pages:
self.extended_links = self.extended_links + page.get_link_groups()
self.extended_charts = self.extended_charts + page.charts
self.extended_shortcuts = self.extended_shortcuts + page.shortcuts
def is_item_allowed(self, name, item_type):
if frappe.session.user == "Administrator":
return True
@ -187,17 +169,14 @@ class Workspace:
def build_workspace(self):
self.cards = {
'label': _(self.doc.cards_label),
'items': self.get_links()
}
self.charts = {
'label': _(self.doc.charts_label),
'items': self.get_charts()
}
self.shortcuts = {
'label': _(self.doc.shortcuts_label),
'items': self.get_shortcuts()
}
@ -249,9 +228,6 @@ class Workspace:
if not self.doc.hide_custom:
cards = cards + get_custom_reports_and_doctypes(self.doc.module)
if len(self.extended_links):
cards = merge_cards_based_on_label(cards + self.extended_links)
default_country = frappe.db.get_default("country")
new_data = []
@ -289,8 +265,6 @@ class Workspace:
all_charts = []
if frappe.has_permission("Dashboard Chart", throw=False):
charts = self.doc.charts
if len(self.extended_charts):
charts = charts + self.extended_charts
for chart in charts:
if frappe.has_permission('Dashboard Chart', doc=chart.chart_name):
@ -311,8 +285,6 @@ class Workspace:
items = []
shortcuts = self.doc.shortcuts
if len(self.extended_shortcuts):
shortcuts = shortcuts + self.extended_shortcuts
for item in shortcuts:
new_item = item.as_dict().copy()
@ -380,8 +352,7 @@ def get_desktop_page(page):
'charts': wspace.charts,
'shortcuts': wspace.shortcuts,
'cards': wspace.cards,
'onboardings': wspace.onboardings,
'allow_customization': not wspace.doc.disable_user_customization
'onboardings': wspace.onboardings
}
except DoesNotExistError:
frappe.log_error(frappe.get_traceback())
@ -414,7 +385,7 @@ def get_wspace_sidebar_items():
# Filter Page based on Permission
for page in all_pages:
try:
wspace = Workspace(page)
wspace = Workspace(page, True)
if wspace.is_permitted() and wspace.is_page_allowed() or has_access:
if page.public:
pages.append(page)
@ -461,7 +432,6 @@ def get_custom_doctype_list(module):
return out
def get_custom_report_list(module):
"""Returns list on new style reports for modules."""
reports = frappe.get_all("Report", fields=["name", "ref_doctype", "report_type"], filters=
@ -482,85 +452,6 @@ def get_custom_report_list(module):
return out
def get_custom_workspace_for_user(page):
"""Get custom page from workspace if exists or create one
Args:
page (stirng): Page name
Returns:
Object: Document object
"""
filters = {
'extends': page,
'for_user': frappe.session.user,
}
pages = frappe.get_list("Workspace", filters=filters)
if pages:
return frappe.get_doc("Workspace", pages[0])
doc = frappe.new_doc("Workspace")
doc.extends = page
doc.for_user = frappe.session.user
return doc
@frappe.whitelist()
def save_customization(page, config):
"""Save customizations as a separate doctype in Workspace per user
Args:
page (string): Name of the page to be edited
config (dict): Dictionary config of al widgets
Returns:
Boolean: Customization saving status
"""
original_page = frappe.get_doc("Workspace", page)
page_doc = get_custom_workspace_for_user(page)
# Update field values
page_doc.update({
"icon": original_page.icon,
"charts_label": original_page.charts_label,
"cards_label": original_page.cards_label,
"shortcuts_label": original_page.shortcuts_label,
"module": original_page.module,
"onboarding": original_page.onboarding,
"developer_mode_only": original_page.developer_mode_only,
"category": original_page.category
})
config = _dict(loads(config))
if config.charts:
page_doc.charts = prepare_widget(config.charts, "Workspace Chart", "charts")
if config.shortcuts:
page_doc.shortcuts = prepare_widget(config.shortcuts, "Workspace Shortcut", "shortcuts")
if config.cards:
page_doc.build_links_table_from_cards(config.cards)
# Set label
page_doc.label = page + '-' + frappe.session.user
try:
if page_doc.is_new():
page_doc.insert(ignore_permissions=True)
else:
page_doc.save(ignore_permissions=True)
except (ValidationError, TypeError) as e:
# Create a json string to log
json_config = dumps(config, sort_keys=True, indent=4)
# Error log body
log = \
"""
page: {0}
config: {1}
exception: {2}
""".format(page, json_config, e)
frappe.log_error(log, _("Could not save customization"))
return False
return True
def save_new_widget(doc, page, blocks, new_widgets):
widgets = _dict(loads(new_widgets))
@ -593,6 +484,7 @@ def save_new_widget(doc, page, blocks, new_widgets):
return False
return True
def clean_up(original_page, blocks):
page_widgets = {}
@ -670,40 +562,14 @@ def prepare_widget(config, doctype, parentfield):
prepare_widget_list.append(doc)
return prepare_widget_list
@frappe.whitelist()
def update_onboarding_step(name, field, value):
"""Update status of onboaridng step
Args:
name (string): Name of the doc
field (string): field to be updated
value: Value to be updated
name (string): Name of the doc
field (string): field to be updated
value: Value to be updated
"""
frappe.db.set_value("Onboarding Step", name, field, value)
@frappe.whitelist()
def reset_customization(page):
"""Reset workspace customizations for a user
Args:
page (string): Name of the page to be reset
"""
page_doc = get_custom_workspace_for_user(page)
page_doc.delete()
def merge_cards_based_on_label(cards):
"""Merge cards with common label."""
cards_dict = {}
for card in cards:
label = card.get('label')
if label in cards_dict:
links = cards_dict[label].links + card.links
cards_dict[label].update(dict(links=links))
cards_dict[label] = cards_dict.pop(label)
else:
cards_dict[label] = card
return list(cards_dict.values())

View file

@ -8,14 +8,9 @@ frappe.ui.form.on('Workspace', {
refresh: function(frm) {
frm.enable_save();
frm.get_field("is_standard").toggle(frappe.boot.developer_mode);
frm.get_field("developer_mode_only").toggle(frappe.boot.developer_mode);
if (frm.doc.for_user) {
frm.set_df_property("extends", "read_only", true);
}
if (frm.doc.for_user || (frm.doc.is_standard && !frappe.boot.developer_mode)) {
if (frm.doc.for_user || (frm.doc.public && !frm.has_perm('write') &&
!frappe.user.has_role('Workspace Manager'))) {
frm.trigger('disable_form');
}
},

View file

@ -11,32 +11,19 @@
"title",
"sequence_id",
"for_user",
"extends",
"parent_page",
"module",
"category",
"column_break_3",
"icon",
"restrict_to_domain",
"onboarding",
"column_break_3",
"extends_another_page",
"is_default",
"is_standard",
"developer_mode_only",
"disable_user_customization",
"pin_to_top",
"pin_to_bottom",
"hide_custom",
"public",
"content",
"section_break_2",
"charts_label",
"charts",
"section_break_15",
"shortcuts_label",
"shortcuts",
"section_break_18",
"cards_label",
"links",
"roles_section",
"roles"
@ -63,7 +50,6 @@
"options": "Workspace Chart"
},
{
"depends_on": "eval:!doc.extends_another_page || !doc.is_standard || frappe.boot.developer_mode",
"fieldname": "shortcuts",
"fieldtype": "Table",
"label": "Shortcuts",
@ -74,7 +60,6 @@
"fieldtype": "Link",
"label": "Restrict to Domain",
"options": "Domain",
"read_only_depends_on": "eval:doc.extends_another_page == 0",
"search_index": 1
},
{
@ -89,64 +74,6 @@
"fieldname": "column_break_3",
"fieldtype": "Column Break"
},
{
"fieldname": "category",
"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",
"search_index": 1
},
{
"default": "0",
"depends_on": "eval:doc.pin_to_bottom!=1 && doc.extends_another_page == 0",
"fieldname": "pin_to_top",
"fieldtype": "Check",
"label": "Pin To Top",
"search_index": 1
},
{
"default": "0",
"depends_on": "eval:doc.extends_another_page == 0",
"fieldname": "disable_user_customization",
"fieldtype": "Check",
"label": "Disable User Customization",
"search_index": 1
},
{
"default": "0",
"depends_on": "eval:doc.pin_to_top!=1 && doc.extends_another_page == 0",
"fieldname": "pin_to_bottom",
"fieldtype": "Check",
"label": "Pin To Bottom",
"search_index": 1
},
{
"depends_on": "eval:!doc.extends_another_page || !doc.is_standard",
"fieldname": "charts_label",
"fieldtype": "Data",
"label": "Label"
},
{
"depends_on": "eval:!doc.extends_another_page || !doc.is_standard",
"fieldname": "shortcuts_label",
"fieldtype": "Data",
"label": "Label"
},
{
"depends_on": "eval:!doc.extends_another_page || !doc.is_standard",
"fieldname": "cards_label",
"fieldtype": "Data",
"label": "Label"
},
{
"collapsible": 1,
"collapsible_depends_on": "shortcuts",
@ -161,40 +88,12 @@
"fieldtype": "Section Break",
"label": "Link Cards"
},
{
"default": "0",
"fieldname": "is_standard",
"fieldtype": "Check",
"label": "Is Standard",
"search_index": 1
},
{
"default": "0",
"fieldname": "extends_another_page",
"fieldtype": "Check",
"label": "Extends Another Page",
"search_index": 1
},
{
"depends_on": "eval:doc.extends_another_page == 1 || doc.for_user",
"fieldname": "extends",
"fieldtype": "Link",
"label": "Extends",
"options": "Workspace",
"search_index": 1
},
{
"fieldname": "for_user",
"fieldtype": "Data",
"label": "For User",
"read_only": 1
},
{
"fieldname": "onboarding",
"fieldtype": "Link",
"label": "Onboarding",
"options": "Module Onboarding"
},
{
"default": "0",
"description": "Checking this will hide custom doctypes and reports cards in Links section",
@ -213,21 +112,14 @@
"label": "Links",
"options": "Workspace Link"
},
{
"default": "0",
"depends_on": "extends_another_page",
"description": "Sets the current page as default for all users",
"fieldname": "is_default",
"fieldtype": "Check",
"label": "Is Default"
},
{
"default": "0",
"fieldname": "public",
"fieldtype": "Check",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Public"
"label": "Public",
"search_index": 1
},
{
"fieldname": "title",
@ -266,7 +158,7 @@
],
"in_create": 1,
"links": [],
"modified": "2021-09-16 12:01:06.450621",
"modified": "2021-09-16 12:01:06.450622",
"modified_by": "Administrator",
"module": "Desk",
"name": "Workspace",

View file

@ -13,8 +13,8 @@ from json import loads
class Workspace(Document):
def validate(self):
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"))
if (self.public and not is_workspace_manager() and not disable_saving_as_public()):
frappe.throw(_("You need to be Workspace Manager to edit this document"))
validate_route_conflict(self.doctype, self.name)
try:
@ -23,15 +23,8 @@ class Workspace(Document):
except Exception:
frappe.throw(_("Content data shoud be a list"))
duplicate_exists = frappe.db.exists("Workspace", {
"name": ["!=", self.name], 'is_default': 1, 'extends': self.extends
})
if self.is_default and self.name and duplicate_exists:
frappe.throw(_("You can only have one default page that extends a particular standard page."))
def on_update(self):
if disable_saving_as_standard():
if disable_saving_as_public():
return
if frappe.conf.developer_mode and self.module and self.public:
@ -39,12 +32,7 @@ class Workspace(Document):
@staticmethod
def get_module_page_map():
filters = {
'extends_another_page': 0,
'for_user': '',
}
pages = frappe.get_all("Workspace", fields=["name", "module"], filters=filters, as_list=1)
pages = frappe.get_all("Workspace", fields=["name", "module"], filters={'for_user': ''}, as_list=1)
return { page[1]: page[0] for page in pages if page[1] }
@ -76,35 +64,6 @@ class Workspace(Document):
return cards
def build_links_table_from_cards(self, config):
# Empty links table
self.links = []
order = config.get('order')
widgets = config.get('widgets')
for idx, name in enumerate(order):
card = widgets[name].copy()
links = loads(card.get('links'))
self.append('links', {
"label": card.get('label'),
"type": "Card Break",
"icon": card.get('icon'),
"hidden": card.get('hidden') or False
})
for link in links:
self.append('links', {
"label": link.get('label'),
"type": "Link",
"link_type": link.get('link_type'),
"link_to": link.get('link_to'),
"onboard": link.get('onboard'),
"only_for": link.get('only_for'),
"dependencies": link.get('dependencies'),
"is_query_report": link.get('is_query_report')
})
def build_links_table_from_card(self, config):
for idx, card in enumerate(config):
@ -137,7 +96,7 @@ class Workspace(Document):
"idx": self.links[-1].idx + 1
})
def disable_saving_as_standard():
def disable_saving_as_public():
return frappe.flags.in_install or \
frappe.flags.in_patch or \
frappe.flags.in_test or \
@ -212,7 +171,7 @@ def save_page(title, icon, parent, public, sb_public_items, sb_private_items, de
def delete_pages(deleted_pages):
for page in deleted_pages:
if page.get("public") and "Workspace Manager" not in frappe.get_roles():
if page.get("public") and not is_workspace_manager():
return {"name": page.get("title"), "public": 1, "label": page.get("label")}
if frappe.db.exists("Workspace", page.get("name")):
@ -227,7 +186,7 @@ def sort_pages(sb_public_items, sb_private_items):
if sb_private_items:
sort_page(wspace_private_pages, sb_private_items)
if sb_public_items and "Workspace Manager" in frappe.get_roles():
if sb_public_items and is_workspace_manager():
sort_page(wspace_public_pages, sb_public_items)
def sort_page(wspace_pages, pages):
@ -242,3 +201,6 @@ def sort_page(wspace_pages, pages):
def get_page_list(fields, filters):
return frappe.get_list("Workspace", fields=fields, filters=filters, order_by='sequence_id asc')
def is_workspace_manager():
return "Workspace Manager" in frappe.get_roles()

View file

@ -1,20 +1,13 @@
{
"category": "",
"charts": [],
"content": "[{\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Backup\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Google Services\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Authentication\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Payments\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings\", \"col\": 4}}]",
"creation": "2020-03-02 15:16:18.714190",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
"extends": "",
"extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "integration",
"idx": 0,
"is_default": 0,
"is_standard": 0,
"label": "Integrations",
"links": [
{
@ -267,15 +260,12 @@
"type": "Link"
}
],
"modified": "2021-08-05 12:16:00.355267",
"modified": "2021-08-05 12:16:00.355268",
"modified_by": "Administrator",
"module": "Integrations",
"name": "Integrations",
"onboarding": "",
"owner": "Administrator",
"parent_page": "",
"pin_to_bottom": 0,
"pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],

View file

@ -458,7 +458,7 @@ def bulk_rename(doctype, rows=None, via_console = False):
"""Bulk rename documents
:param doctype: DocType to be renamed
:param rows: list of documents as `((oldname, newname), ..)`"""
:param rows: list of documents as `((oldname, newname, merge(optional)), ..)`"""
if not rows:
frappe.throw(_("Please select a valid csv file with data"))
@ -471,8 +471,9 @@ def bulk_rename(doctype, rows=None, via_console = False):
for row in rows:
# if row has some content
if len(row) > 1 and row[0] and row[1]:
merge = len(row) > 2 and (row[2] == "1" or row[2].lower() == "true")
try:
if rename_doc(doctype, row[0], row[1]):
if rename_doc(doctype, row[0], row[1], merge=merge):
msg = _("Successful: {0} to {1}").format(row[0], row[1])
frappe.db.commit()
else:

View file

@ -182,4 +182,4 @@ frappe.patches.v13_0.jinja_hook
frappe.patches.v13_0.update_notification_channel_if_empty
frappe.patches.v14_0.drop_data_import_legacy
frappe.patches.v14_0.rename_cancelled_documents
frappe.patches.v14_0.update_workspace2 # 25.08.2021
frappe.patches.v14_0.update_workspace2 # 20.09.2021

View file

@ -4,8 +4,8 @@ from frappe import _
def execute():
frappe.reload_doc('desk', 'doctype', 'workspace', force=True)
order_by = "pin_to_top desc, pin_to_bottom asc, name asc"
for seq, wspace in enumerate(frappe.get_all('Workspace', order_by=order_by)):
for seq, wspace in enumerate(frappe.get_all('Workspace', order_by='name asc')):
doc = frappe.get_doc('Workspace', wspace.name)
content = create_content(doc)
update_wspace(doc, seq, content)
@ -53,7 +53,7 @@ def update_wspace(doc, seq, content):
if not doc.title and not doc.content and not doc.is_standard and not doc.public:
doc.sequence_id = seq + 1
doc.content = json.dumps(content)
doc.public = 0
doc.public = 0 if doc.for_user else 1
doc.title = doc.extends or doc.label
doc.extends = ''
doc.category = ''

View file

@ -283,7 +283,7 @@ frappe.Application = class Application {
frappe.workspaces = {};
for (let page of frappe.boot.allowed_workspaces || []) {
frappe.modules[page.module]=page;
frappe.workspaces[frappe.router.slug(page.title)] = page;
frappe.workspaces[frappe.router.slug(page.name)] = page;
}
}

View file

@ -302,7 +302,7 @@ class FormTimeline extends BaseTimeline {
(this.doc_info.info_logs || []).forEach(info_log => {
info_timeline_contents.push({
creation: info_log.creation,
content: `${this.get_user_link(info_log.comment_email)} ${info_log.content}`,
content: `${this.get_user_link(info_log.owner)} ${info_log.content}`,
});
});
return info_timeline_contents;

View file

@ -133,12 +133,14 @@ frappe.router = {
// /app/user/user-001 = ["Form", "User", "user-001"]
// /app/event/view/calendar/default = ["List", "Event", "Calendar", "Default"]
let private_wspace = route[1] && `${route[1]}-${frappe.user.name.toLowerCase()}`;
if (frappe.workspaces[route[0]]) {
// public workspace
route = ['Workspaces', frappe.workspaces[route[0]].title];
} else if (route[0] == 'private' && frappe.workspaces[route[1]]) {
} else if (route[0] == 'private' && frappe.workspaces[private_wspace]) {
// private workspace
route = ['Workspaces', 'private', frappe.workspaces[route[1]].title];
route = ['Workspaces', 'private', frappe.workspaces[private_wspace].title];
} else if (this.routes[route[0]]) {
// route
route = this.set_doctype_route(route);
@ -363,7 +365,8 @@ frappe.router = {
return a;
}
}).join('/');
let default_page = frappe.workspaces['home'] ? 'home' : Object.keys(frappe.workspaces)[0];
let private_home = frappe.workspaces[`home-${frappe.user.name.toLowerCase()}`];
let default_page = private_home ? 'private/home' : frappe.workspaces['home'] ? 'home' : Object.keys(frappe.workspaces)[0];
return '/app/' + (path_string || default_page);
},

View file

@ -50,38 +50,31 @@ frappe.search.AwesomeBar = class AwesomeBar {
this.awesomplete = awesomplete;
$input.on("input", function(e) {
$input.on("input", frappe.utils.debounce(function(e) {
var value = e.target.value;
var txt = value.trim().replace(/\s\s+/g, ' ');
var last_space = txt.lastIndexOf(' ');
me.global_results = [];
// if(txt && txt.length > 1) {
// me.global.get_awesome_bar_options(txt.toLowerCase(), me);
// }
var $this = $(this);
clearTimeout($this.data('timeout'));
me.options = [];
$this.data('timeout', setTimeout(function(){
me.options = [];
if(txt && txt.length > 1) {
if(last_space !== -1) {
me.set_specifics(txt.slice(0,last_space), txt.slice(last_space+1));
}
me.add_defaults(txt);
me.options = me.options.concat(me.build_options(txt));
me.options = me.options.concat(me.global_results);
} else {
me.options = me.options.concat(
me.deduplicate(frappe.search.utils.get_recent_pages(txt || "")));
me.options = me.options.concat(frappe.search.utils.get_frequent_links());
if (txt && txt.length > 1) {
if (last_space !== -1) {
me.set_specifics(txt.slice(0, last_space), txt.slice(last_space+1));
}
me.add_help();
me.add_defaults(txt);
me.options = me.options.concat(me.build_options(txt));
me.options = me.options.concat(me.global_results);
} else {
me.options = me.options.concat(
me.deduplicate(frappe.search.utils.get_recent_pages(txt || "")));
me.options = me.options.concat(frappe.search.utils.get_frequent_links());
}
me.add_help();
awesomplete.list = me.deduplicate(me.options);
}, 100));
awesomplete.list = me.deduplicate(me.options);
});
}, 500));
var open_recent = function() {
if (!this.autocomplete_open) {

View file

@ -23,6 +23,14 @@ if (!Array.prototype.uniqBy) {
});
}
// Python's dict.setdefault ported for JS objects
Object.defineProperty(Object.prototype, "setDefault", {
value: function(key, default_value) {
if (!(key in this)) this[key] = default_value;
return this[key];
}
});
// Pluralize
String.prototype.plural = function(revert) {
const plural = {

View file

@ -517,9 +517,6 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
} else {
this.page.show_form();
}
this.page.body[0].style.setProperty('--report-filter-height', this.page.page_form.css('height'));
this.page.body.parent().css('margin-bottom', 'unset');
}
set_filters(filters) {
@ -834,7 +831,6 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
if (this.raw_data.add_total_row) {
data = data.slice();
data.splice(-1, 1);
this.$page.find('.layout-main-section')[0].style.setProperty('--report-total-height', '310px');
}
this.$report.show();

View file

@ -50,8 +50,6 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView {
this.setup_columns();
super.setup_new_doc_event();
this.page.main.addClass('report-view');
this.page.body[0].style.setProperty('--report-filter-height', this.page.page_form.css('height'));
this.page.body.parent().css('margin-bottom', 'unset');
}
toggle_side_bar() {

View file

@ -30,7 +30,7 @@ export default class Card extends Block {
this.new('card', 'links');
if (this.data && this.data.card_name) {
let has_data = this.make('card', this.data.card_name, 'links');
let has_data = this.make('card', __(this.data.card_name), 'links');
if (!has_data) return;
}

View file

@ -30,7 +30,7 @@ export default class Chart extends Block {
this.new('chart');
if (this.data && this.data.chart_name) {
let has_data = this.make('chart', this.data.chart_name);
let has_data = this.make('chart', __(this.data.chart_name));
if (!has_data) return;
}

View file

@ -27,7 +27,7 @@ export default class Header extends Block {
data = {};
}
newData.text = data.text || '';
newData.text = (data.text && __(data.text.replace(/(\n|\t)/gm, ""))) || '';
newData.level = parseInt(data.level) || this.defaultLevel.number;
newData.col = parseInt(data.col) || 12;

View file

@ -177,7 +177,7 @@ export default class Paragraph extends Block {
set data(data) {
this._data = data || {};
this._element.innerHTML = this._data.text || '';
this._element.innerHTML = __(this._data.text) || '';
}
static get pasteConfig() {

View file

@ -29,7 +29,7 @@ export default class Shortcut extends Block {
this.new('shortcut');
if (this.data && this.data.shortcut_name) {
let has_data = this.make('shortcut', this.data.shortcut_name);
let has_data = this.make('shortcut', __(this.data.shortcut_name));
if (!has_data) return;
}

View file

@ -51,38 +51,37 @@ frappe.views.Workspace = class Workspace {
this.body = this.wrapper.find(".layout-main-section");
}
setup_pages(reload) {
this.get_pages().then(pages => {
this.all_pages = pages.pages;
this.has_access = pages.has_access;
async setup_pages(reload) {
this.sidebar_pages = !this.discard ? await this.get_pages() : this.sidebar_pages;
this.all_pages = this.sidebar_pages.pages;
this.has_access = this.sidebar_pages.has_access;
this.all_pages.forEach(page => {
page.is_editable = !page.public || pages.has_access;
});
this.public_pages = this.all_pages.filter(page => page.public);
this.private_pages = this.all_pages.filter(page => !page.public);
if (this.all_pages) {
frappe.workspaces = {};
for (let page of this.all_pages) {
frappe.workspaces[frappe.router.slug(page.title)] = {title: page.title};
}
if (this.new_page && this.new_page.name) {
if (!frappe.workspaces[frappe.router.slug(this.new_page.name)]) {
this.new_page = { name: this.all_pages[0].title, public: this.all_pages[0].public };
}
if (this.new_page.public) {
frappe.set_route(`${frappe.router.slug(this.new_page.name)}`);
} else {
frappe.set_route(`private/${frappe.router.slug(this.new_page.name)}`);
}
this.new_page = null;
}
this.make_sidebar();
reload && this.show();
}
this.all_pages.forEach(page => {
page.is_editable = !page.public || this.has_access;
});
this.public_pages = this.all_pages.filter(page => page.public);
this.private_pages = this.all_pages.filter(page => !page.public);
if (this.all_pages) {
frappe.workspaces = {};
for (let page of this.all_pages) {
frappe.workspaces[frappe.router.slug(page.name)] = {title: page.title};
}
if (this.new_page && this.new_page.name) {
if (!frappe.workspaces[frappe.router.slug(this.new_page.label)]) {
this.new_page = { name: this.all_pages[0].title, public: this.all_pages[0].public };
}
if (this.new_page.public) {
frappe.set_route(`${frappe.router.slug(this.new_page.name)}`);
} else {
frappe.set_route(`private/${frappe.router.slug(this.new_page.name)}`);
}
this.new_page = null;
}
this.make_sidebar();
reload && this.show();
}
}
get_pages() {
@ -95,10 +94,10 @@ frappe.views.Workspace = class Workspace {
<div class="desk-sidebar-item standard-sidebar-item ${item.selected ? "selected" : ""}">
<a
href="/app/${item.public ? frappe.router.slug(item.title) : 'private/'+frappe.router.slug(item.title) }"
class="item-anchor ${item.is_editable ? "" : "block-click" }" title="${item.title}"
class="item-anchor ${item.is_editable ? "" : "block-click" }" title="${__(item.title)}"
>
<span class="sidebar-item-icon" item-icon=${item.icon || "folder-normal"}>${frappe.utils.icon(item.icon || "folder-normal", "md")}</span>
<span class="sidebar-item-label">${item.title}<span>
<span class="sidebar-item-label">${__(item.title)}<span>
</a>
<div class="sidebar-item-control"></div>
</div>
@ -152,8 +151,8 @@ 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)
&& item.public == this.get_page_to_show().public;
item.selected = is_current_page;
if (is_current_page) {
item.selected = true;
this.current_page = { name: item.title, public: item.public };
}
@ -219,14 +218,14 @@ frappe.views.Workspace = class Workspace {
if (!this.page_data || Object.keys(this.page_data).length === 0) return;
if (this.page_data.charts && this.page_data.charts.items.length === 0) return;
return frappe.dashboard_utils.get_dashboard_settings().then(settings => {
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] || {};
});
}
this.page_data.charts.items.map(chart => {
chart.chart_settings = chart_config[chart.chart_name] || {};
});
this.pages[page.name] = this.page_data;
}
});
@ -272,8 +271,7 @@ frappe.views.Workspace = class Workspace {
<div id="editorjs" class="desk-page page-main-content"></div>
`).appendTo(this.body);
}
this.$page.prepend(frappe.render_template('workspace_loading_skeleton'));
this.$page.find('.codex-editor').addClass('hidden');
this.create_skeleton();
if (this.all_pages) {
let pages = page.public ? this.public_pages : this.private_pages;
@ -293,8 +291,7 @@ frappe.views.Workspace = class Workspace {
this.prepare_editorjs();
$('.item-anchor').removeClass('disable-click');
this.$page.find('.codex-editor').removeClass('hidden');
this.$page.find('.workspace-skeleton').remove();
this.remove_skeleton();
}
}
@ -336,10 +333,10 @@ frappe.views.Workspace = class Workspace {
this.page.clear_secondary_action();
this.page.clear_inner_toolbar();
current_page.is_editable && this.page.set_secondary_action(__("Edit"), () => {
current_page.is_editable && this.page.set_secondary_action(__("Edit"), async () => {
if (!this.editor || !this.editor.readOnly) return;
this.is_read_only = false;
this.editor.readOnly.toggle();
await this.editor.readOnly.toggle();
this.editor.isReady.then(() => {
this.initialize_editorjs_undo();
this.setup_customization_buttons(current_page);
@ -383,13 +380,13 @@ frappe.views.Workspace = class Workspace {
this.page.set_secondary_action(
__("Discard"),
() => {
async () => {
this.discard = true;
this.page.clear_primary_action();
this.page.clear_secondary_action();
this.page.clear_inner_toolbar();
this.editor.readOnly.toggle();
await this.editor.readOnly.toggle();
this.is_read_only = true;
this.deleted_sidebar_items = [];
this.reload();
frappe.show_alert({ message: __("Customizations Discarded"), indicator: "info" });
}
@ -568,10 +565,10 @@ frappe.views.Workspace = class Workspace {
}
}
]
}).then(() => {
}).then(async () => {
if (this.editor.configuration.readOnly) {
this.is_read_only = false;
this.editor.readOnly.toggle();
await this.editor.readOnly.toggle();
}
this.add_page_to_sidebar(values);
this.show_sidebar_actions();
@ -646,7 +643,10 @@ frappe.views.Workspace = class Workspace {
this.tools = {
header: {
class: this.blocks['header'],
inlineToolbar: true
inlineToolbar: true,
config: {
defaultLevel: 4
}
},
paragraph: {
class: this.blocks['paragraph'],
@ -693,6 +693,7 @@ frappe.views.Workspace = class Workspace {
save_page() {
frappe.dom.freeze();
this.create_skeleton();
let save = true;
if (!this.title && this.current_page) {
let pages = this.current_page.public ? this.public_pages : this.private_pages;
@ -740,13 +741,6 @@ frappe.views.Workspace = class Workspace {
if (res.message) {
me.new_page = res.message;
me.pages[res.message.label] && delete me.pages[res.message.label];
me.title = '';
me.icon = '';
me.parent = '';
me.public = false;
me.sorted_public_items = [];
me.sorted_private_items = [];
me.deleted_sidebar_items = [];
me.reload();
frappe.show_alert({ message: __("Page Saved Successfully"), indicator: "green" });
}
@ -759,9 +753,26 @@ frappe.views.Workspace = class Workspace {
}
reload() {
this.$page.prepend(frappe.render_template('workspace_loading_skeleton'));
this.$page.find('.codex-editor').addClass('hidden');
this.title = '';
this.icon = '';
this.parent = '';
this.public = false;
this.sorted_public_items = [];
this.sorted_private_items = [];
this.deleted_sidebar_items = [];
this.create_skeleton();
this.setup_pages(true);
this.discard = false;
this.undo.readOnly = true;
}
create_skeleton() {
this.$page.prepend(frappe.render_template('workspace_loading_skeleton'));
this.$page.find('.codex-editor').addClass('hidden');
}
remove_skeleton() {
this.$page.find('.codex-editor').removeClass('hidden');
this.$page.find('.workspace-skeleton').remove();
}
};

View file

@ -191,7 +191,6 @@ export class SingleWidgetGroup {
Object.assign(this, opts);
this.widgets_list = [];
this.widgets_dict = {};
this.widget_order = [];
this.make();
}

View file

@ -84,39 +84,17 @@
margin-bottom: 10px;
}
.layout-main-section {
--report-filter-height: 0px;
--report-total-height: 275px;
}
.report-wrapper {
overflow: auto;
.datatable {
height: calc(100vh - var(--report-filter-height) - 205px);
.dt-scrollable {
height: calc(100vh - var(--report-filter-height) - var(--report-total-height));
}
}
}
.report-view {
.result {
min-height: 50vh !important;
.dt-row:last-child:not(.dt-row-filter) {
.dt-cell {
border-bottom: 1px solid var(--border-color);
}
}
.datatable {
height: calc(100vh - var(--report-filter-height) - 225px);
.dt-scrollable {
height: calc(100vh - var(--report-filter-height) - 295px);
}
}
}
}

View file

@ -1,20 +1,13 @@
{
"category": "",
"charts": [],
"content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"Website\", \"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Blog Post\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Blogger\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Web Page\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Web Form\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Website Settings\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Setup\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Blog\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Web Site\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Portal\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Knowledge Base\", \"col\": 4}}]",
"creation": "2020-03-02 14:13:51.089373",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
"extends": "",
"extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "website",
"idx": 0,
"is_default": 0,
"is_standard": 0,
"label": "Website",
"links": [
{
@ -239,15 +232,12 @@
"type": "Link"
}
],
"modified": "2021-08-05 12:16:03.154032",
"modified": "2021-08-05 12:16:03.154033",
"modified_by": "Administrator",
"module": "Website",
"name": "Website",
"onboarding": "Website",
"owner": "Administrator",
"parent_page": "",
"pin_to_bottom": 0,
"pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],

View file

@ -12,7 +12,6 @@ croniter~=1.0.11
cryptography~=3.4.7
dropbox~=11.7.0
email-reply-parser~=0.5.12
Faker~=8.1.0
git-url-parse~=1.2.2
gitdb~=4.0.7
GitPython~=3.1.14
@ -44,7 +43,6 @@ pyasn1~=0.4.8
pycryptodome~=3.10.1
PyJWT~=2.0.1
PyMySQL~=1.0.2
pyngrok~=5.0.5
pyOpenSSL~=20.0.1
pyotp~=2.6.0
PyPDF2~=1.26.0
@ -64,12 +62,10 @@ rq~=1.8.0
rsa>=4.1 # not directly required, pinned by Snyk to avoid a vulnerability
schedule~=1.1.0
semantic-version~=2.8.5
simple-chalk~=0.1.0
six~=1.15.0
sqlparse~=0.4.1
stripe~=2.56.0
terminaltables~=3.1.0
unittest-xml-reporting~=3.0.4
urllib3~=1.26.4
Werkzeug~=0.16.1
Whoosh~=2.7.4