Merge branch 'discussions-component-redesign' of https://github.com/pateljannat/frappe into discussions-component-redesign
This commit is contained in:
commit
064c879a31
75 changed files with 722 additions and 526 deletions
|
|
@ -16,3 +16,6 @@ fe20515c23a3ac41f1092bf0eaf0a0a452ec2e85
|
|||
|
||||
# Refactor "not a in b" -> "a not in b"
|
||||
745297a49d516e5e3c4bb3e1b0c4235e7d31165d
|
||||
|
||||
# Clean up whitespace
|
||||
b2fc959307c7c79f5584625569d5aed04133ba13
|
||||
|
|
|
|||
|
|
@ -1,15 +1,24 @@
|
|||
name: Semgrep
|
||||
name: Linters
|
||||
|
||||
on:
|
||||
pull_request: { }
|
||||
|
||||
jobs:
|
||||
semgrep:
|
||||
|
||||
linters:
|
||||
name: Frappe Linter
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
|
||||
- name: Install and Run Pre-commit
|
||||
uses: pre-commit/action@v2.0.3
|
||||
|
||||
- name: Download Semgrep rules
|
||||
run: git clone --depth 1 https://github.com/frappe/semgrep-rules.git frappe-semgrep-rules
|
||||
|
||||
23
.pre-commit-config.yaml
Normal file
23
.pre-commit-config.yaml
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
exclude: 'node_modules|.git'
|
||||
default_stages: [commit]
|
||||
fail_fast: false
|
||||
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.0.1
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
files: "frappe.*"
|
||||
exclude: ".*json$|.*txt$|.*csv|.*md|.*svg"
|
||||
- id: check-yaml
|
||||
- id: no-commit-to-branch
|
||||
args: ['--branch', 'develop']
|
||||
- id: check-merge-conflict
|
||||
- id: check-ast
|
||||
|
||||
|
||||
ci:
|
||||
autoupdate_schedule: weekly
|
||||
skip: []
|
||||
submodules: false
|
||||
|
|
@ -3,7 +3,6 @@ codecov:
|
|||
|
||||
coverage:
|
||||
status:
|
||||
patch: off
|
||||
project:
|
||||
default: false
|
||||
server:
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ class Importer:
|
|||
|
||||
if not self.data_import.status == "Partial Success":
|
||||
self.data_import.db_set("status", "Partial Success")
|
||||
|
||||
|
||||
# commit after every successful import
|
||||
frappe.db.commit()
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
from frappe.tests.utils import FrappeTestCase
|
||||
|
||||
class Test{classname}(unittest.TestCase):
|
||||
|
||||
class Test{classname}(FrappeTestCase):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -314,19 +314,19 @@ result = [
|
|||
{
|
||||
"parent_column": "Parent 1",
|
||||
"column_1": 200,
|
||||
"column_2": 150.50
|
||||
"column_2": 150.50
|
||||
},
|
||||
{
|
||||
"parent_column": "Child 1",
|
||||
"column_1": 100,
|
||||
"column_2": 75.25,
|
||||
"parent_value": "Parent 1"
|
||||
"parent_value": "Parent 1"
|
||||
},
|
||||
{
|
||||
"parent_column": "Child 2",
|
||||
"column_1": 100,
|
||||
"column_2": 75.25,
|
||||
"parent_value": "Parent 1"
|
||||
"parent_value": "Parent 1"
|
||||
}
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -244,7 +244,13 @@ class Query:
|
|||
_operator = OPERATOR_MAP[value[0]]
|
||||
conditions = conditions.where(_operator(Field(key), value[1]))
|
||||
else:
|
||||
conditions = conditions.where(_operator(Field(key), value))
|
||||
if value is not None:
|
||||
conditions = conditions.where(_operator(Field(key), value))
|
||||
else:
|
||||
_table = conditions._from[0]
|
||||
field = getattr(_table, key)
|
||||
conditions = conditions.where(field.isnull())
|
||||
|
||||
conditions = self.add_conditions(conditions, **kwargs)
|
||||
return conditions
|
||||
|
||||
|
|
|
|||
|
|
@ -495,7 +495,7 @@ frappe.ui.form.on('Dashboard Chart', {
|
|||
|
||||
set_parent_document_type: async function(frm) {
|
||||
let document_type = frm.doc.document_type;
|
||||
let doc_is_table = document_type &&
|
||||
let doc_is_table = document_type &&
|
||||
(await frappe.db.get_value('DocType', document_type, 'istable')).message.istable;
|
||||
|
||||
frm.set_df_property('parent_document_type', 'hidden', !doc_is_table);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ frappe.ui.form.on('Form Tour', {
|
|||
frm.add_custom_button(__('Show Tour'), async () => {
|
||||
const issingle = await check_if_single(frm.doc.reference_doctype);
|
||||
let route_changed = null;
|
||||
|
||||
|
||||
if (issingle) {
|
||||
route_changed = frappe.set_route('Form', frm.doc.reference_doctype);
|
||||
} else if (frm.doc.first_document) {
|
||||
|
|
|
|||
|
|
@ -76,26 +76,6 @@ def archive_restore_column(board_name, column_title, status):
|
|||
return doc.columns
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def update_doc(doc):
|
||||
'''Updates the doc when card is edited'''
|
||||
doc = json.loads(doc)
|
||||
|
||||
try:
|
||||
to_update = doc
|
||||
doctype = doc['doctype']
|
||||
docname = doc['name']
|
||||
doc = frappe.get_doc(doctype, docname)
|
||||
doc.update(to_update)
|
||||
doc.save()
|
||||
except:
|
||||
return {
|
||||
'doc': doc,
|
||||
'exc': frappe.utils.get_traceback()
|
||||
}
|
||||
return doc
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def update_order(board_name, order):
|
||||
'''Save the order of cards in columns'''
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ frappe.views.calendar["ToDo"] = {
|
|||
"options": "reference_type",
|
||||
"label": __("Task")
|
||||
}
|
||||
|
||||
|
||||
],
|
||||
get_events_method: "frappe.desk.calendar.get_events"
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ frappe.ui.form.on('Workspace', {
|
|||
refresh: function(frm) {
|
||||
frm.enable_save();
|
||||
|
||||
if (frm.doc.for_user || (frm.doc.public && !frm.has_perm('write') &&
|
||||
if (frm.doc.for_user || (frm.doc.public && !frm.has_perm('write') &&
|
||||
!frappe.user.has_role('Workspace Manager'))) {
|
||||
frm.trigger('disable_form');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,9 +176,9 @@ def update_page(name, title, icon, parent, public):
|
|||
|
||||
doc = frappe.get_doc("Workspace", name)
|
||||
|
||||
filters = {
|
||||
filters = {
|
||||
'parent_page': doc.title,
|
||||
'public': doc.public
|
||||
'public': doc.public
|
||||
}
|
||||
child_docs = frappe.get_list("Workspace", filters=filters)
|
||||
|
||||
|
|
@ -255,7 +255,7 @@ def delete_page(page):
|
|||
def sort_pages(sb_public_items, sb_private_items):
|
||||
if not loads(sb_public_items) and not loads(sb_private_items):
|
||||
return
|
||||
|
||||
|
||||
sb_public_items = loads(sb_public_items)
|
||||
sb_private_items = loads(sb_private_items)
|
||||
|
||||
|
|
@ -292,7 +292,7 @@ def last_sequence_id(doc):
|
|||
if not doc_exists:
|
||||
return 0
|
||||
|
||||
return frappe.db.get_list('Workspace',
|
||||
return frappe.db.get_list('Workspace',
|
||||
fields=['sequence_id'],
|
||||
filters={
|
||||
'public': doc.public,
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ def get_context(context):
|
|||
""")
|
||||
|
||||
def validate_standard(self):
|
||||
if self.is_standard and not frappe.conf.developer_mode:
|
||||
if self.is_standard and self.enabled and not frappe.conf.developer_mode:
|
||||
frappe.throw(_('Cannot edit Standard Notification. To edit, please disable this and duplicate it'))
|
||||
|
||||
def validate_condition(self):
|
||||
|
|
|
|||
|
|
@ -630,7 +630,7 @@ class InboundMail(Email):
|
|||
if self.reference_document():
|
||||
data['reference_doctype'] = self.reference_document().doctype
|
||||
data['reference_name'] = self.reference_document().name
|
||||
else:
|
||||
else:
|
||||
if append_to and append_to != 'Communication':
|
||||
reference_doc = self._create_reference_document(append_to)
|
||||
if reference_doc:
|
||||
|
|
|
|||
|
|
@ -3,6 +3,6 @@
|
|||
|
||||
frappe.ui.form.on('Razorpay Settings', {
|
||||
refresh: function(frm) {
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
|
|
@ -471,7 +471,7 @@ class Document(BaseDocument):
|
|||
|
||||
# We'd probably want the creation and owner to be set via API
|
||||
# or Data import at some point, that'd have to be handled here
|
||||
if self.is_new() and not (frappe.flags.in_patch or frappe.flags.in_migrate):
|
||||
if self.is_new() and not (frappe.flags.in_install or frappe.flags.in_patch or frappe.flags.in_migrate):
|
||||
self.creation = self.modified
|
||||
self.owner = self.modified_by
|
||||
|
||||
|
|
@ -860,14 +860,14 @@ class Document(BaseDocument):
|
|||
|
||||
def run_method(self, method, *args, **kwargs):
|
||||
"""run standard triggers, plus those in hooks"""
|
||||
if "flags" in kwargs:
|
||||
del kwargs["flags"]
|
||||
|
||||
if hasattr(self, method) and hasattr(getattr(self, method), "__call__"):
|
||||
fn = lambda self, *args, **kwargs: getattr(self, method)(*args, **kwargs)
|
||||
else:
|
||||
# hack! to run hooks even if method does not exist
|
||||
fn = lambda self, *args, **kwargs: None
|
||||
def fn(self, *args, **kwargs):
|
||||
method_object = getattr(self, method, None)
|
||||
|
||||
# Cannot have a field with same name as method
|
||||
# If method found in __dict__, expect it to be callable
|
||||
if method in self.__dict__ or callable(method_object):
|
||||
return method_object(*args, **kwargs)
|
||||
|
||||
fn.__name__ = str(method)
|
||||
out = Document.hook(fn)(self, *args, **kwargs)
|
||||
|
|
|
|||
|
|
@ -77,13 +77,15 @@ def rename_doc(
|
|||
) -> str:
|
||||
"""Rename a doc(dt, old) to doc(dt, new) and update all linked fields of type "Link"."""
|
||||
if not frappe.db.exists(doctype, old):
|
||||
frappe.errprint(_("Failed: {0} to {1} because {0} doesn't exist.").format(old, new))
|
||||
return
|
||||
|
||||
if ignore_if_exists and frappe.db.exists(doctype, new):
|
||||
frappe.errprint(_("Failed: {0} to {1} because {1} already exists.").format(old, new))
|
||||
return
|
||||
|
||||
if old==new:
|
||||
frappe.msgprint(_('Please select a new name to rename'))
|
||||
frappe.errprint(_("Ignored: {0} to {1} no changes made because old and new name are the same.").format(old, new))
|
||||
return
|
||||
|
||||
force = cint(force)
|
||||
|
|
@ -540,15 +542,16 @@ def bulk_rename(doctype: str, rows: Optional[List[List]] = None, via_console: bo
|
|||
msg = _("Successful: {0} to {1}").format(row[0], row[1])
|
||||
frappe.db.commit()
|
||||
else:
|
||||
msg = _("Ignored: {0} to {1}").format(row[0], row[1])
|
||||
msg = None
|
||||
except Exception as e:
|
||||
msg = _("** Failed: {0} to {1}: {2}").format(row[0], row[1], repr(e))
|
||||
frappe.db.rollback()
|
||||
|
||||
if via_console:
|
||||
print(msg)
|
||||
else:
|
||||
rename_log.append(msg)
|
||||
if msg:
|
||||
if via_console:
|
||||
print(msg)
|
||||
else:
|
||||
rename_log.append(msg)
|
||||
|
||||
frappe.enqueue('frappe.utils.global_search.rebuild_for_doctype', doctype=doctype)
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ patches by using INI like file format:
|
|||
import configparser
|
||||
import time
|
||||
from enum import Enum
|
||||
from textwrap import dedent, indent
|
||||
from typing import List, Optional
|
||||
|
||||
import frappe
|
||||
|
|
@ -148,21 +149,36 @@ def run_single(patchmodule=None, method=None, methodargs=None, force=False):
|
|||
def execute_patch(patchmodule, method=None, methodargs=None):
|
||||
"""execute the patch"""
|
||||
block_user(True)
|
||||
frappe.db.begin()
|
||||
|
||||
if patchmodule.startswith("execute:"):
|
||||
has_patch_file = False
|
||||
patch = patchmodule.split("execute:")[1]
|
||||
docstring = ""
|
||||
else:
|
||||
has_patch_file = True
|
||||
patch = f"{patchmodule.split()[0]}.execute"
|
||||
_patch = frappe.get_attr(patch)
|
||||
docstring = _patch.__doc__ or ""
|
||||
|
||||
if docstring:
|
||||
docstring = "\n" + indent(dedent(docstring), "\t")
|
||||
|
||||
print(f"Executing {patchmodule or methodargs} in {frappe.local.site} ({frappe.db.cur_db_name}){docstring}")
|
||||
|
||||
start_time = time.time()
|
||||
frappe.db.begin()
|
||||
try:
|
||||
print('Executing {patch} in {site} ({db})'.format(patch=patchmodule or str(methodargs),
|
||||
site=frappe.local.site, db=frappe.db.cur_db_name))
|
||||
if patchmodule:
|
||||
if patchmodule.startswith("finally:"):
|
||||
# run run patch at the end
|
||||
frappe.flags.final_patches.append(patchmodule)
|
||||
else:
|
||||
if patchmodule.startswith("execute:"):
|
||||
exec(patchmodule.split("execute:")[1],globals())
|
||||
if has_patch_file:
|
||||
_patch()
|
||||
else:
|
||||
frappe.get_attr(patchmodule.split()[0] + ".execute")()
|
||||
exec(patch, globals())
|
||||
update_patch_log(patchmodule)
|
||||
|
||||
elif method:
|
||||
method(**methodargs)
|
||||
|
||||
|
|
@ -174,7 +190,7 @@ def execute_patch(patchmodule, method=None, methodargs=None):
|
|||
frappe.db.commit()
|
||||
end_time = time.time()
|
||||
block_user(False)
|
||||
print('Success: Done in {time}s'.format(time = round(end_time - start_time, 3)))
|
||||
print(f"Success: Done in {round(end_time - start_time, 3)}s")
|
||||
|
||||
return True
|
||||
|
||||
|
|
|
|||
|
|
@ -189,6 +189,7 @@ frappe.patches.v14_0.update_workspace2 # 20.09.2021
|
|||
frappe.patches.v14_0.save_ratings_in_fraction #23-12-2021
|
||||
frappe.patches.v14_0.transform_todo_schema
|
||||
frappe.patches.v14_0.remove_post_and_post_comment
|
||||
frappe.patches.v14_0.reset_creation_datetime
|
||||
|
||||
[post_model_sync]
|
||||
frappe.patches.v14_0.drop_data_import_legacy
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ def execute():
|
|||
for file in files:
|
||||
file_path = file.file_url
|
||||
file_name = file_path.split('/')[-1]
|
||||
|
||||
|
||||
if not file_path.startswith(('/private/', '/files/')):
|
||||
continue
|
||||
|
||||
|
|
|
|||
41
frappe/patches/v14_0/reset_creation_datetime.py
Normal file
41
frappe/patches/v14_0/reset_creation_datetime.py
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import glob
|
||||
import json
|
||||
import frappe
|
||||
import os
|
||||
from frappe.query_builder import DocType as _DocType
|
||||
|
||||
|
||||
def execute():
|
||||
"""Resetting creation datetimes for DocTypes"""
|
||||
DocType = _DocType("DocType")
|
||||
doctype_jsons = glob.glob(
|
||||
os.path.join("..", "apps", "frappe", "frappe", "**", "doctype", "**", "*.json")
|
||||
)
|
||||
|
||||
frappe_modules = frappe.get_all(
|
||||
"Module Def", filters={"app_name": "frappe"}, pluck="name"
|
||||
)
|
||||
site_doctypes = frappe.get_all(
|
||||
"DocType",
|
||||
filters={"module": ("in", frappe_modules), "custom": False},
|
||||
fields=["name", "creation"],
|
||||
)
|
||||
|
||||
for dt_path in doctype_jsons:
|
||||
with open(dt_path) as f:
|
||||
try:
|
||||
file_schema = frappe._dict(json.load(f))
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
if not file_schema.name:
|
||||
continue
|
||||
|
||||
_site_schema = [x for x in site_doctypes if x.name == file_schema.name]
|
||||
if not _site_schema:
|
||||
continue
|
||||
|
||||
if file_schema.creation != _site_schema[0].creation:
|
||||
frappe.qb.update(DocType).set(
|
||||
DocType.creation, file_schema.creation
|
||||
).where(DocType.name == file_schema.name).run()
|
||||
|
|
@ -160,7 +160,7 @@ frappe.ui.form.ControlDate = class ControlDate extends frappe.ui.form.ControlDat
|
|||
get_df_options() {
|
||||
let df_options = this.df.options;
|
||||
if (!df_options) return {};
|
||||
|
||||
|
||||
let options = {};
|
||||
if (typeof df_options === 'string') {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ frappe.ui.form.ControlTable = class ControlTable extends frappe.ui.form.Control
|
|||
if (frappe.model.no_value_type.includes(field.fieldtype)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const is_field_matching = () => {
|
||||
return (
|
||||
field.fieldname.toLowerCase() === field_name ||
|
||||
|
|
|
|||
|
|
@ -88,6 +88,9 @@ frappe.ui.form.ControlTextEditor = class ControlTextEditor extends frappe.ui.for
|
|||
make_quill_editor() {
|
||||
if (this.quill) return;
|
||||
this.quill_container = $('<div>').appendTo(this.input_area);
|
||||
if (this.df.max_height) {
|
||||
$(this.quill_container).css({'max-height': this.df.max_height, 'overflow': 'auto'});
|
||||
}
|
||||
this.quill = new Quill(this.quill_container[0], this.get_quill_options());
|
||||
this.bind_events();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ export default class GridPagination {
|
|||
}
|
||||
|
||||
// only allow numbers from 0-9 and up, down, left, right arrow keys
|
||||
if (charCode > 31 && (charCode < 48 || charCode > 57) &&
|
||||
if (charCode > 31 && (charCode < 48 || charCode > 57) &&
|
||||
![37, 38, 39, 40].includes(charCode)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -615,6 +615,7 @@ export default class GridRow {
|
|||
if (!this.doc) {
|
||||
$col.attr("title", txt);
|
||||
}
|
||||
df.fieldname && $col.static_area.toggleClass('reqd', Boolean(df.reqd));
|
||||
|
||||
$col.df = df;
|
||||
$col.column_index = ci;
|
||||
|
|
|
|||
|
|
@ -148,6 +148,7 @@ frappe.ui.form.save = function (frm, action, callback, btn) {
|
|||
});
|
||||
|
||||
if (frm.is_new() && frm.meta.autoname === 'Prompt' && !frm.doc.__newname) {
|
||||
has_errors = true;
|
||||
error_fields = [__('Name'), ...error_fields];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -103,7 +103,9 @@ frappe.ui.form.Toolbar = class Toolbar {
|
|||
docname,
|
||||
name: new_name,
|
||||
title: new_title,
|
||||
merge
|
||||
merge,
|
||||
freeze: true,
|
||||
freeze_message: __("Updating related fields...")
|
||||
}).then(new_docname => {
|
||||
if (new_name != docname) {
|
||||
$(document).trigger("rename", [doctype, docname, new_docname || new_name]);
|
||||
|
|
@ -172,6 +174,7 @@ frappe.ui.form.Toolbar = class Toolbar {
|
|||
d.show();
|
||||
d.set_primary_action(__("Rename"), (values) => {
|
||||
d.disable_primary_action();
|
||||
d.hide();
|
||||
this.rename_document_title(values.name, values.title, values.merge)
|
||||
.then(() => {
|
||||
d.hide();
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ frappe.views.ListViewSelect = class ListViewSelect {
|
|||
const views_wrapper = this.sidebar.sidebar.find(".views-section");
|
||||
views_wrapper.find(".sidebar-label").html(`${__(view)}`);
|
||||
const $dropdown = views_wrapper.find(".views-dropdown");
|
||||
|
||||
|
||||
let placeholder = `${__("Select {0}", [__(view)])}`;
|
||||
let html = ``;
|
||||
|
||||
|
|
|
|||
|
|
@ -615,10 +615,13 @@ $.extend(frappe.model, {
|
|||
});
|
||||
|
||||
d.set_primary_action(__("Rename"), function() {
|
||||
d.hide();
|
||||
var args = d.get_values();
|
||||
if(!args) return;
|
||||
return frappe.call({
|
||||
method:"frappe.rename_doc",
|
||||
freeze: true,
|
||||
freeze_message: "Updating related fields...",
|
||||
args: {
|
||||
doctype: doctype,
|
||||
old: docname,
|
||||
|
|
|
|||
|
|
@ -50,6 +50,11 @@ frappe.call = function(opts) {
|
|||
}
|
||||
var args = $.extend({}, opts.args);
|
||||
|
||||
if (args.freeze) {
|
||||
opts.freeze = opts.freeze || args.freeze;
|
||||
opts.freeze_message = opts.freeze_message || args.freeze_message;
|
||||
}
|
||||
|
||||
// cmd
|
||||
if(opts.module && opts.page) {
|
||||
args.cmd = opts.module+'.page.'+opts.page+'.'+opts.page+'.'+opts.method;
|
||||
|
|
|
|||
|
|
@ -112,9 +112,9 @@ frappe.ui.FieldSelect = class FieldSelect {
|
|||
// main table
|
||||
var main_table_fields = std_filters.concat(frappe.meta.docfield_list[me.doctype]);
|
||||
$.each(frappe.utils.sort(main_table_fields, "label", "string"), function(i, df) {
|
||||
let doctype = frappe.get_meta(me.doctype).istable && me.parent_doctype ?
|
||||
let doctype = frappe.get_meta(me.doctype).istable && me.parent_doctype ?
|
||||
me.parent_doctype : me.doctype;
|
||||
|
||||
|
||||
// show fields where user has read access and if report hide flag is not set
|
||||
if (frappe.perm.has_perm(doctype, df.permlevel, "read"))
|
||||
me.add_field_option(df);
|
||||
|
|
@ -132,9 +132,9 @@ frappe.ui.FieldSelect = class FieldSelect {
|
|||
}
|
||||
|
||||
$.each(frappe.utils.sort(child_table_fields, "label", "string"), function(i, df) {
|
||||
let doctype = frappe.get_meta(me.doctype).istable && me.parent_doctype ?
|
||||
let doctype = frappe.get_meta(me.doctype).istable && me.parent_doctype ?
|
||||
me.parent_doctype : me.doctype;
|
||||
|
||||
|
||||
// show fields where user has read access and if report hide flag is not set
|
||||
if (frappe.perm.has_perm(doctype, df.permlevel, "read"))
|
||||
me.add_field_option(df);
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ Object.assign(frappe.utils, {
|
|||
};
|
||||
|
||||
return String(txt).replace(
|
||||
/[&<>"'`=/]/g,
|
||||
/[&<>"'`=/]/g,
|
||||
char => escape_html_mapping[char] || char
|
||||
);
|
||||
},
|
||||
|
|
@ -262,7 +262,7 @@ Object.assign(frappe.utils, {
|
|||
};
|
||||
|
||||
return String(txt).replace(
|
||||
/&|<|>|"|'|/|`|=/g,
|
||||
/&|<|>|"|'|/|`|=/g,
|
||||
char => unescape_html_mapping[char] || char
|
||||
);
|
||||
},
|
||||
|
|
@ -1435,7 +1435,7 @@ Object.assign(frappe.utils, {
|
|||
// for link titles
|
||||
frappe._link_titles = {};
|
||||
}
|
||||
|
||||
|
||||
frappe._link_titles[doctype + "::" + name] = value;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -150,18 +150,6 @@ frappe.provide("frappe.views");
|
|||
}
|
||||
updater.set({ cards: cards });
|
||||
},
|
||||
update_doc: function(updater, doc, card) {
|
||||
var state = this;
|
||||
return frappe.call({
|
||||
method: method_prefix + "update_doc",
|
||||
args: { doc: doc },
|
||||
freeze: true
|
||||
}).then(function(r) {
|
||||
var updated_doc = r.message;
|
||||
var updated_card = prepare_card(card, state, updated_doc);
|
||||
fluxify.doAction('update_card', updated_card);
|
||||
});
|
||||
},
|
||||
update_order_for_single_card: function(updater, card) {
|
||||
// cache original order
|
||||
const _cards = this.cards.slice();
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@
|
|||
<link href="{{ base_url }}/assets/frappe/css/bootstrap.css" rel="stylesheet">
|
||||
<link type="text/css" rel="stylesheet"
|
||||
href="{{ base_url }}/assets/frappe/css/font-awesome.css">
|
||||
<link rel="stylesheet" type="text/css" href="{{ base_url }}/assets/frappe/css/tree.css">
|
||||
<link rel="stylesheet" type="text/css" href="{{ base_url }}/assets/frappe/css/tree.css">
|
||||
<style>
|
||||
{{ print_css }}
|
||||
</style>
|
||||
<style>
|
||||
.tree.opened::before,
|
||||
.tree-node.opened::before,
|
||||
.tree:last-child::after,
|
||||
.tree.opened::before,
|
||||
.tree-node.opened::before,
|
||||
.tree:last-child::after,
|
||||
.tree-node:last-child::after {
|
||||
z-index: 1;
|
||||
border-left: 1px solid #d1d8dd;
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
text-decoration: none;
|
||||
cursor: default;
|
||||
}
|
||||
.tree.opened > .tree-children > .tree-node > .tree-link::before,
|
||||
.tree.opened > .tree-children > .tree-node > .tree-link::before,
|
||||
.tree-node.opened > .tree-children > .tree-node > .tree-link::before {
|
||||
border-top: 1px solid #d1d8dd;
|
||||
z-index: 1;
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ export default class Block {
|
|||
document.documentElement.addEventListener('mousemove', do_drag, false);
|
||||
document.documentElement.addEventListener('mouseup', stop_drag, false);
|
||||
}
|
||||
|
||||
|
||||
function do_drag(e) {
|
||||
$(this).css("cursor", "col-resize");
|
||||
$('.widget').css("pointer-events", "none");
|
||||
|
|
@ -72,7 +72,7 @@ export default class Block {
|
|||
} else {
|
||||
window.getSelection().removeAllRanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function stop_drag() {
|
||||
$(this).css("cursor", "default");
|
||||
|
|
@ -221,7 +221,7 @@ export default class Block {
|
|||
$widget_control.prepend($button);
|
||||
|
||||
this.dropdown_list.forEach((item) => {
|
||||
if ((item.label == 'Expand' || item.label == 'Shrink') &&
|
||||
if ((item.label == 'Expand' || item.label == 'Shrink') &&
|
||||
me.options && !me.options.allow_resize) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ export default class Header extends Block {
|
|||
if (data.text !== undefined) {
|
||||
let text = this._data.text || '';
|
||||
const contains_html_tag = /<[a-z][\s\S]*>/i.test(text);
|
||||
this._element.innerHTML = contains_html_tag ?
|
||||
this._element.innerHTML = contains_html_tag ?
|
||||
text : `<span class="h${this._settings.default_size}">${text}</span>`;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ export default class HeaderSize {
|
|||
|
||||
checkState(selection) {
|
||||
let termWrapper = this.api.selection.findParentTag('SPAN');
|
||||
|
||||
|
||||
for (const h of ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']) {
|
||||
if (termWrapper && termWrapper.classList.contains(h)) {
|
||||
let num = h.match(/\d+/)[0];
|
||||
|
|
@ -57,7 +57,7 @@ export default class HeaderSize {
|
|||
span.innerText = range.toString();
|
||||
|
||||
this.remove_parent_tag(range, range.commonAncestorContainer, span);
|
||||
|
||||
|
||||
range.extractContents();
|
||||
range.insertNode(span);
|
||||
this.api.inlineToolbar.close();
|
||||
|
|
@ -90,7 +90,7 @@ export default class HeaderSize {
|
|||
renderActions() {
|
||||
this.actions = document.createElement('div');
|
||||
this.actions.classList = 'header-level-select';
|
||||
|
||||
|
||||
this.headerLevels = new Array(6).fill().map((_, idx) => {
|
||||
const $header_level = document.createElement('div');
|
||||
$header_level.classList.add(`h${idx+1}`, 'header-level');
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ export default class Paragraph extends Block {
|
|||
this.wrapper.appendChild(this._element);
|
||||
this._element.classList.remove('widget');
|
||||
$para_control.appendTo(this.wrapper);
|
||||
|
||||
|
||||
this.wrapper.classList.add('widget', 'paragraph', 'edit-mode');
|
||||
|
||||
this.open_block_list();
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ frappe.views.Workspace = class Workspace {
|
|||
$sidebar[0].firstElementChild.classList.add("selected");
|
||||
if (sidebar_page) sidebar_page.selected = true;
|
||||
|
||||
// open child sidebar section if closed
|
||||
// open child sidebar section if closed
|
||||
$sidebar.parent().hasClass('hidden') &&
|
||||
$sidebar.parent().removeClass('hidden');
|
||||
|
||||
|
|
@ -244,7 +244,7 @@ frappe.views.Workspace = class Workspace {
|
|||
this.pages[page.name] = data.message;
|
||||
|
||||
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;
|
||||
if (this.page_data.charts && this.page_data.charts.items.length === 0) return;
|
||||
|
||||
return frappe.dashboard_utils.get_dashboard_settings().then(settings => {
|
||||
if (settings) {
|
||||
|
|
@ -596,9 +596,9 @@ frappe.views.Workspace = class Workspace {
|
|||
}
|
||||
|
||||
update_cached_values(old_item, new_item, duplicate, new_page) {
|
||||
let [from_pages, to_pages] = old_item.public ?
|
||||
let [from_pages, to_pages] = old_item.public ?
|
||||
[this.public_pages, this.private_pages] : [this.private_pages, this.public_pages];
|
||||
|
||||
|
||||
let old_item_index = from_pages.findIndex(page => page.title == old_item.title);
|
||||
duplicate && old_item_index++;
|
||||
|
||||
|
|
@ -859,7 +859,7 @@ frappe.views.Workspace = class Workspace {
|
|||
public: page.attributes['item-public'].value
|
||||
});
|
||||
|
||||
let $drop_icon = $(page).find('.sidebar-item-control .drop-icon').first();
|
||||
let $drop_icon = $(page).find('.sidebar-item-control .drop-icon').first();
|
||||
if ($(page).find('.sidebar-child-item > *').length != 0) {
|
||||
$drop_icon.removeClass('hidden');
|
||||
} else {
|
||||
|
|
@ -993,13 +993,13 @@ frappe.views.Workspace = class Workspace {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
this.update_cached_values(new_page, new_page, true, true);
|
||||
|
||||
|
||||
let pre_url = new_page.public ? '' : 'private/';
|
||||
let route = pre_url + frappe.router.slug(new_page.title);
|
||||
frappe.set_route(route);
|
||||
|
||||
|
||||
this.make_sidebar();
|
||||
this.show_sidebar_actions();
|
||||
});
|
||||
|
|
@ -1010,15 +1010,15 @@ frappe.views.Workspace = class Workspace {
|
|||
|
||||
validate_page(new_page, old_page) {
|
||||
let message = "";
|
||||
let [from_pages, to_pages] = new_page.is_public ?
|
||||
let [from_pages, to_pages] = new_page.is_public ?
|
||||
[this.private_pages, this.public_pages] : [this.public_pages, this.private_pages];
|
||||
|
||||
let section = this.sidebar_categories[new_page.is_public];
|
||||
|
||||
if (to_pages && to_pages.filter(p => p.title == new_page.title)[0]) {
|
||||
message = `Page with title ${new_page.title} already exist.`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (frappe.router.doctype_route_exist(frappe.router.slug(new_page.title))) {
|
||||
message = "Doctype with same route already exist. Please choose different title.";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -698,12 +698,12 @@ export default class ChartWidget extends Widget {
|
|||
.get_filters_for_chart_type(this.chart_doc).then(filters => {
|
||||
chart_saved_filters = this.update_default_date_filters(filters, chart_saved_filters);
|
||||
this.filters =
|
||||
frappe.utils.parse_array(user_saved_filters) || frappe.utils.parse_array(this.filters)
|
||||
frappe.utils.parse_array(user_saved_filters) || frappe.utils.parse_array(this.filters)
|
||||
|| frappe.utils.parse_array(chart_saved_filters);
|
||||
});
|
||||
} else {
|
||||
this.filters =
|
||||
frappe.utils.parse_array(user_saved_filters) || frappe.utils.parse_array(this.filters)
|
||||
frappe.utils.parse_array(user_saved_filters) || frappe.utils.parse_array(this.filters)
|
||||
|| frappe.utils.parse_array(chart_saved_filters);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
|
|
|||
2
frappe/public/js/lib/jSignature.min.js
vendored
2
frappe/public/js/lib/jSignature.min.js
vendored
|
|
@ -993,7 +993,7 @@ jSignatureClass.prototype.resetCanvas = function(data, dontClear){
|
|||
ctx.shadowBlur = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ctx.strokeStyle = settings.color;
|
||||
|
||||
// setting up new dataEngine
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
*/
|
||||
/*
|
||||
|
||||
|
||||
1. Buttons
|
||||
|
||||
*/
|
||||
|
|
@ -257,7 +257,7 @@ a.pswp__share--download:hover {
|
|||
padding: 0 10px; }
|
||||
|
||||
/*
|
||||
|
||||
|
||||
4. Caption
|
||||
|
||||
*/
|
||||
|
|
@ -338,8 +338,8 @@ a.pswp__share--download:hover {
|
|||
margin: 0; }
|
||||
|
||||
.pswp--css_animation .pswp__preloader__cut {
|
||||
/*
|
||||
The idea of animating inner circle is based on Polymer ("material") loading indicator
|
||||
/*
|
||||
The idea of animating inner circle is based on Polymer ("material") loading indicator
|
||||
by Keanu Lee https://blog.keanulee.com/2014/10/20/the-tale-of-three-spinners.html
|
||||
*/
|
||||
position: relative;
|
||||
|
|
@ -409,7 +409,7 @@ a.pswp__share--download:hover {
|
|||
transform: rotate(0); } }
|
||||
|
||||
/*
|
||||
|
||||
|
||||
6. Additional styles
|
||||
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
*
|
||||
* UI on top of main sliding area (caption, arrows, close button, etc.).
|
||||
* Built just using public methods/properties of PhotoSwipe.
|
||||
*
|
||||
*
|
||||
*/
|
||||
(function (root, factory) {
|
||||
(function (root, factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define(factory);
|
||||
} else if (typeof exports === 'object') {
|
||||
|
|
@ -48,11 +48,11 @@ var PhotoSwipeUI_Default =
|
|||
_options,
|
||||
_defaultUIOptions = {
|
||||
barsSize: {top:44, bottom:'auto'},
|
||||
closeElClasses: ['item', 'caption', 'zoom-wrap', 'ui', 'top-bar'],
|
||||
timeToIdle: 4000,
|
||||
closeElClasses: ['item', 'caption', 'zoom-wrap', 'ui', 'top-bar'],
|
||||
timeToIdle: 4000,
|
||||
timeToIdleOutside: 1000,
|
||||
loadingIndicatorDelay: 1000, // 2s
|
||||
|
||||
|
||||
addCaptionHTMLFn: function(item, captionEl /*, isFake */) {
|
||||
if(!item.title) {
|
||||
captionEl.children[0].innerHTML = '';
|
||||
|
|
@ -92,7 +92,7 @@ var PhotoSwipeUI_Default =
|
|||
getTextForShare: function( /* shareButtonData */ ) {
|
||||
return pswp.currItem.title || '';
|
||||
},
|
||||
|
||||
|
||||
indexIndicatorSep: ' / ',
|
||||
fitControlsWidth: 1200
|
||||
|
||||
|
|
@ -136,12 +136,12 @@ var PhotoSwipeUI_Default =
|
|||
}
|
||||
_blockControlsTap = true;
|
||||
|
||||
// Some versions of Android don't prevent ghost click event
|
||||
// Some versions of Android don't prevent ghost click event
|
||||
// when preventDefault() was called on touchstart and/or touchend.
|
||||
//
|
||||
// This happens on v4.3, 4.2, 4.1,
|
||||
// older versions strangely work correctly,
|
||||
// but just in case we add delay on all of them)
|
||||
//
|
||||
// This happens on v4.3, 4.2, 4.1,
|
||||
// older versions strangely work correctly,
|
||||
// but just in case we add delay on all of them)
|
||||
var tapDelay = framework.features.isOldAndroid ? 600 : 30;
|
||||
_blockControlsTapTimeout = setTimeout(function() {
|
||||
_blockControlsTap = false;
|
||||
|
|
@ -172,8 +172,8 @@ var PhotoSwipeUI_Default =
|
|||
_toggleShareModal = function() {
|
||||
|
||||
_shareModalHidden = !_shareModalHidden;
|
||||
|
||||
|
||||
|
||||
|
||||
if(!_shareModalHidden) {
|
||||
_toggleShareModalClass();
|
||||
setTimeout(function() {
|
||||
|
|
@ -189,7 +189,7 @@ var PhotoSwipeUI_Default =
|
|||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
|
||||
if(!_shareModalHidden) {
|
||||
_updateShareURLs();
|
||||
}
|
||||
|
|
@ -211,13 +211,13 @@ var PhotoSwipeUI_Default =
|
|||
}
|
||||
|
||||
window.open(target.href, 'pswp_share', 'scrollbars=yes,resizable=yes,toolbar=no,'+
|
||||
'location=yes,width=550,height=420,top=100,left=' +
|
||||
'location=yes,width=550,height=420,top=100,left=' +
|
||||
(window.screen ? Math.round(screen.width / 2 - 275) : 100) );
|
||||
|
||||
if(!_shareModalHidden) {
|
||||
_toggleShareModal();
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
},
|
||||
_updateShareURLs = function() {
|
||||
|
|
@ -242,7 +242,7 @@ var PhotoSwipeUI_Default =
|
|||
|
||||
shareButtonOut += '<a href="' + shareURL + '" target="_blank" '+
|
||||
'class="pswp__share--' + shareButtonData.id + '"' +
|
||||
(shareButtonData.download ? 'download' : '') + '>' +
|
||||
(shareButtonData.download ? 'download' : '') + '>' +
|
||||
shareButtonData.label + '</a>';
|
||||
|
||||
if(_options.parseShareButtonOut) {
|
||||
|
|
@ -297,7 +297,7 @@ var PhotoSwipeUI_Default =
|
|||
_setupLoadingIndicator = function() {
|
||||
// Setup loading indicator
|
||||
if(_options.preloaderEl) {
|
||||
|
||||
|
||||
_toggleLoadingIndicator(true);
|
||||
|
||||
_listen('beforeChange', function() {
|
||||
|
|
@ -310,18 +310,18 @@ var PhotoSwipeUI_Default =
|
|||
if(pswp.currItem && pswp.currItem.loading) {
|
||||
|
||||
if( !pswp.allowProgressiveImg() || (pswp.currItem.img && !pswp.currItem.img.naturalWidth) ) {
|
||||
// show preloader if progressive loading is not enabled,
|
||||
// show preloader if progressive loading is not enabled,
|
||||
// or image width is not defined yet (because of slow connection)
|
||||
_toggleLoadingIndicator(false);
|
||||
_toggleLoadingIndicator(false);
|
||||
// items-controller.js function allowProgressiveImg
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
_toggleLoadingIndicator(true); // hide preloader
|
||||
}
|
||||
|
||||
}, _options.loadingIndicatorDelay);
|
||||
|
||||
|
||||
});
|
||||
_listen('imageLoadComplete', function(index, item) {
|
||||
if(pswp.currItem === item) {
|
||||
|
|
@ -341,8 +341,8 @@ var PhotoSwipeUI_Default =
|
|||
var gap = item.vGap;
|
||||
|
||||
if( _fitControlsInViewport() ) {
|
||||
|
||||
var bars = _options.barsSize;
|
||||
|
||||
var bars = _options.barsSize;
|
||||
if(_options.captionEl && bars.bottom === 'auto') {
|
||||
if(!_fakeCaptionContainer) {
|
||||
_fakeCaptionContainer = framework.createEl('pswp__caption pswp__caption--fake');
|
||||
|
|
@ -360,7 +360,7 @@ var PhotoSwipeUI_Default =
|
|||
} else {
|
||||
gap.bottom = bars.bottom === 'auto' ? 0 : bars.bottom;
|
||||
}
|
||||
|
||||
|
||||
// height of top bar is static, no need to calculate it
|
||||
gap.top = bars.top;
|
||||
} else {
|
||||
|
|
@ -371,7 +371,7 @@ var PhotoSwipeUI_Default =
|
|||
// Hide controls when mouse is used
|
||||
if(_options.timeToIdle) {
|
||||
_listen('mouseUsed', function() {
|
||||
|
||||
|
||||
framework.bind(document, 'mousemove', _onIdleMouseMove);
|
||||
framework.bind(document, 'mouseout', _onMouseLeaveWindow);
|
||||
|
||||
|
|
@ -418,77 +418,77 @@ var PhotoSwipeUI_Default =
|
|||
|
||||
|
||||
var _uiElements = [
|
||||
{
|
||||
name: 'caption',
|
||||
{
|
||||
name: 'caption',
|
||||
option: 'captionEl',
|
||||
onInit: function(el) {
|
||||
_captionContainer = el;
|
||||
}
|
||||
onInit: function(el) {
|
||||
_captionContainer = el;
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'share-modal',
|
||||
{
|
||||
name: 'share-modal',
|
||||
option: 'shareEl',
|
||||
onInit: function(el) {
|
||||
onInit: function(el) {
|
||||
_shareModal = el;
|
||||
},
|
||||
onTap: function() {
|
||||
_toggleShareModal();
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'button--share',
|
||||
{
|
||||
name: 'button--share',
|
||||
option: 'shareEl',
|
||||
onInit: function(el) {
|
||||
onInit: function(el) {
|
||||
_shareButton = el;
|
||||
},
|
||||
onTap: function() {
|
||||
_toggleShareModal();
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'button--zoom',
|
||||
{
|
||||
name: 'button--zoom',
|
||||
option: 'zoomEl',
|
||||
onTap: pswp.toggleDesktopZoom
|
||||
},
|
||||
{
|
||||
name: 'counter',
|
||||
{
|
||||
name: 'counter',
|
||||
option: 'counterEl',
|
||||
onInit: function(el) {
|
||||
onInit: function(el) {
|
||||
_indexIndicator = el;
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'button--close',
|
||||
{
|
||||
name: 'button--close',
|
||||
option: 'closeEl',
|
||||
onTap: pswp.close
|
||||
},
|
||||
{
|
||||
name: 'button--arrow--left',
|
||||
{
|
||||
name: 'button--arrow--left',
|
||||
option: 'arrowEl',
|
||||
onTap: pswp.prev
|
||||
},
|
||||
{
|
||||
name: 'button--arrow--right',
|
||||
{
|
||||
name: 'button--arrow--right',
|
||||
option: 'arrowEl',
|
||||
onTap: pswp.next
|
||||
},
|
||||
{
|
||||
name: 'button--fs',
|
||||
{
|
||||
name: 'button--fs',
|
||||
option: 'fullscreenEl',
|
||||
onTap: function() {
|
||||
onTap: function() {
|
||||
if(_fullscrenAPI.isFullscreen()) {
|
||||
_fullscrenAPI.exit();
|
||||
} else {
|
||||
_fullscrenAPI.enter();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'preloader',
|
||||
{
|
||||
name: 'preloader',
|
||||
option: 'preloaderEl',
|
||||
onInit: function(el) {
|
||||
onInit: function(el) {
|
||||
_loadingIndicator = el;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
];
|
||||
|
|
@ -514,12 +514,12 @@ var PhotoSwipeUI_Default =
|
|||
if(classAttr.indexOf('pswp__' + uiElement.name) > -1 ) {
|
||||
|
||||
if( _options[uiElement.option] ) { // if element is not disabled from options
|
||||
|
||||
|
||||
framework.removeClass(item, 'pswp__element--disabled');
|
||||
if(uiElement.onInit) {
|
||||
uiElement.onInit(item);
|
||||
}
|
||||
|
||||
|
||||
//item.style.display = 'block';
|
||||
} else {
|
||||
framework.addClass(item, 'pswp__element--disabled');
|
||||
|
|
@ -538,7 +538,7 @@ var PhotoSwipeUI_Default =
|
|||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ui.init = function() {
|
||||
|
||||
|
|
@ -574,9 +574,9 @@ var PhotoSwipeUI_Default =
|
|||
_listen('preventDragEvent', function(e, isDown, preventObj) {
|
||||
var t = e.target || e.srcElement;
|
||||
if(
|
||||
t &&
|
||||
t.getAttribute('class') && e.type.indexOf('mouse') > -1 &&
|
||||
( t.getAttribute('class').indexOf('__caption') > 0 || (/(SMALL|STRONG|EM)/i).test(t.tagName) )
|
||||
t &&
|
||||
t.getAttribute('class') && e.type.indexOf('mouse') > -1 &&
|
||||
( t.getAttribute('class').indexOf('__caption') > 0 || (/(SMALL|STRONG|EM)/i).test(t.tagName) )
|
||||
) {
|
||||
preventObj.prevent = false;
|
||||
}
|
||||
|
|
@ -634,7 +634,7 @@ var PhotoSwipeUI_Default =
|
|||
framework.addClass( _controls, 'pswp__ui--hidden');
|
||||
ui.setIdle(false);
|
||||
});
|
||||
|
||||
|
||||
|
||||
if(!_options.showAnimationDuration) {
|
||||
framework.removeClass( _controls, 'pswp__ui--hidden');
|
||||
|
|
@ -649,7 +649,7 @@ var PhotoSwipeUI_Default =
|
|||
});
|
||||
|
||||
_listen('parseVerticalMargin', _applyNavBarGaps);
|
||||
|
||||
|
||||
_setupUIElements();
|
||||
|
||||
if(_options.shareEl && _shareButton && _shareModal) {
|
||||
|
|
@ -673,7 +673,7 @@ var PhotoSwipeUI_Default =
|
|||
ui.update = function() {
|
||||
// Don't update UI if it's hidden
|
||||
if(_controlsVisible && pswp.currItem) {
|
||||
|
||||
|
||||
ui.updateIndexIndicator();
|
||||
|
||||
if(_options.captionEl) {
|
||||
|
|
@ -704,19 +704,19 @@ var PhotoSwipeUI_Default =
|
|||
pswp.setScrollOffset( 0, framework.getScrollY() );
|
||||
}, 50);
|
||||
}
|
||||
|
||||
|
||||
// toogle pswp--fs class on root element
|
||||
framework[ (_fullscrenAPI.isFullscreen() ? 'add' : 'remove') + 'Class' ](pswp.template, 'pswp--fs');
|
||||
};
|
||||
|
||||
ui.updateIndexIndicator = function() {
|
||||
if(_options.counterEl) {
|
||||
_indexIndicator.innerHTML = (pswp.getCurrentIndex()+1) +
|
||||
_options.indexIndicatorSep +
|
||||
_indexIndicator.innerHTML = (pswp.getCurrentIndex()+1) +
|
||||
_options.indexIndicatorSep +
|
||||
_options.getNumItemsFn();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
ui.onGlobalTap = function(e) {
|
||||
e = e || window.event;
|
||||
var target = e.target || e.srcElement;
|
||||
|
|
@ -742,7 +742,7 @@ var PhotoSwipeUI_Default =
|
|||
pswp.toggleDesktopZoom(e.detail.releasePoint);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
// tap anywhere (except buttons) to toggle visibility of controls
|
||||
|
|
@ -759,7 +759,7 @@ var PhotoSwipeUI_Default =
|
|||
pswp.close();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
ui.onMouseOver = function(e) {
|
||||
|
|
@ -809,7 +809,7 @@ var PhotoSwipeUI_Default =
|
|||
eventK: 'moz' + tF
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} else if(dE.webkitRequestFullscreen) {
|
||||
api = {
|
||||
|
|
@ -829,21 +829,21 @@ var PhotoSwipeUI_Default =
|
|||
}
|
||||
|
||||
if(api) {
|
||||
api.enter = function() {
|
||||
api.enter = function() {
|
||||
// disable close-on-scroll in fullscreen
|
||||
_initalCloseOnScrollValue = _options.closeOnScroll;
|
||||
_options.closeOnScroll = false;
|
||||
_initalCloseOnScrollValue = _options.closeOnScroll;
|
||||
_options.closeOnScroll = false;
|
||||
|
||||
if(this.enterK === 'webkitRequestFullscreen') {
|
||||
pswp.template[this.enterK]( Element.ALLOW_KEYBOARD_INPUT );
|
||||
} else {
|
||||
return pswp.template[this.enterK]();
|
||||
return pswp.template[this.enterK]();
|
||||
}
|
||||
};
|
||||
api.exit = function() {
|
||||
api.exit = function() {
|
||||
_options.closeOnScroll = _initalCloseOnScrollValue;
|
||||
|
||||
return document[this.exitK]();
|
||||
return document[this.exitK]();
|
||||
|
||||
};
|
||||
api.isFullscreen = function() { return document[this.elementK]; };
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -11,10 +11,10 @@ function prettyDate(time){
|
|||
var date = new Date((time || "").replace(/-/g,"/").replace(/[TZ]/g," ").replace(/\.[0-9]*/, "")),
|
||||
diff = (((new Date()).getTime() - date.getTime()) / 1000),
|
||||
day_diff = Math.floor(diff / 86400);
|
||||
|
||||
|
||||
if ( isNaN(day_diff) || day_diff < 0 )
|
||||
return '';
|
||||
|
||||
|
||||
return day_diff == 0 && (
|
||||
diff < 60 && "just now" ||
|
||||
diff < 120 && "1 minute ago" ||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,13 @@
|
|||
border-bottom: 1px solid var(--table-border-color);
|
||||
color: var(--text-muted);
|
||||
font-size: var(--text-md);
|
||||
|
||||
.grid-static-col {
|
||||
.static-area.reqd:after {
|
||||
content: ' *';
|
||||
color: var(--red-400);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rows .grid-row .data-row,
|
||||
|
|
|
|||
|
|
@ -1070,11 +1070,11 @@ body {
|
|||
}
|
||||
|
||||
.resizer {
|
||||
width: 10px;
|
||||
width: 10px;
|
||||
height: 100%;
|
||||
position:absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
position:absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
cursor: col-resize;
|
||||
border-color: transparent;
|
||||
transition: border-color 0.3s ease-in-out;
|
||||
|
|
@ -1089,8 +1089,8 @@ body {
|
|||
margin-bottom: 0 !important;
|
||||
flex: 1;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1124,11 +1124,11 @@ body {
|
|||
color: var(--text-muted);
|
||||
border: 1px dashed var(--gray-400);
|
||||
cursor: pointer;
|
||||
|
||||
|
||||
.widget-control > * {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
|
||||
.spacer-left {
|
||||
min-width: 74px;
|
||||
}
|
||||
|
|
@ -1158,7 +1158,7 @@ body {
|
|||
gap: 5px;
|
||||
background-color: var(--card-bg);
|
||||
padding-left: 5px;
|
||||
|
||||
|
||||
.drag-handle {
|
||||
cursor: all-scroll;
|
||||
cursor: grabbing;
|
||||
|
|
@ -1325,7 +1325,7 @@ body {
|
|||
padding: 6px 10px;
|
||||
font-size: small;
|
||||
border-radius: var(--border-radius-sm);
|
||||
margin: 1px 0px;
|
||||
margin: 1px 0px;
|
||||
}
|
||||
|
||||
.dropdown-item-icon {
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ $level-margin-right: 8px;
|
|||
box-shadow: none;
|
||||
margin-left: 0px !important;
|
||||
border: 1px solid var(--dark-border-color);
|
||||
|
||||
|
||||
&.btn-info {
|
||||
background-color: var(--gray-400);
|
||||
border-color: var(--gray-400);
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ body {
|
|||
min-width: 50%;
|
||||
padding: 0 4px;
|
||||
margin-bottom: var(--margin-md);
|
||||
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,18 +163,18 @@
|
|||
padding: var(--padding-lg);
|
||||
box-shadow: var(--card-shadow);
|
||||
border-radius: var(--border-radius-md);
|
||||
|
||||
|
||||
.new-comment-fields {
|
||||
flex: 1;
|
||||
|
||||
|
||||
.form-label {
|
||||
font-weight: var(--text-bold);
|
||||
}
|
||||
|
||||
|
||||
.comment-text-area textarea {
|
||||
resize: none;
|
||||
}
|
||||
|
||||
|
||||
@media (min-width: 576px) {
|
||||
.comment-by {
|
||||
padding-right: 0px !important;
|
||||
|
|
@ -184,7 +184,7 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#comment-list {
|
||||
position: relative;
|
||||
|
|
@ -206,7 +206,7 @@
|
|||
top: 10px;
|
||||
left: -17px;
|
||||
}
|
||||
|
||||
|
||||
.comment-content {
|
||||
box-shadow: var(--card-shadow);
|
||||
border-radius: var(--border-radius-md);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
width: 80%
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.back-to-home {
|
||||
font-size: var(--text-base);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,6 +80,8 @@
|
|||
|
||||
.dropdown-menu {
|
||||
padding: 0.25rem;
|
||||
box-shadow: var(--shadow-lg);
|
||||
border-color: var(--gray-200);
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
|
|
@ -308,4 +310,4 @@ h5.modal-title {
|
|||
|
||||
.empty-list-icon {
|
||||
height: 70px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
|
||||
.navbar-toggler {
|
||||
border-color: rgba(255,255,255, 0.1);
|
||||
|
||||
|
||||
.icon {
|
||||
stroke: none;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
.portal-row {
|
||||
padding: 1rem 0;
|
||||
|
||||
|
||||
a {
|
||||
color: $body-color;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
[data-doctype="Web Form"] {
|
||||
.page-content-wrapper {
|
||||
|
||||
|
||||
.breadcrumb-container.container {
|
||||
@include media-breakpoint-up(sm) {
|
||||
padding-left: 0;
|
||||
|
|
|
|||
|
|
@ -2,12 +2,14 @@
|
|||
# Copyright (c) 2019, Frappe Technologies and Contributors
|
||||
# License: MIT. See LICENSE
|
||||
import frappe
|
||||
import unittest
|
||||
|
||||
from frappe.tests.utils import FrappeTestCase
|
||||
from .energy_point_log import get_energy_points as _get_energy_points, create_review_points_log, review
|
||||
from frappe.utils.testutils import add_custom_field, clear_custom_fields
|
||||
from frappe.desk.form.assign_to import add as assign_to
|
||||
|
||||
class TestEnergyPointLog(unittest.TestCase):
|
||||
|
||||
class TestEnergyPointLog(FrappeTestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
settings = frappe.get_single('Energy Point Settings')
|
||||
|
|
@ -140,9 +142,10 @@ class TestEnergyPointLog(unittest.TestCase):
|
|||
|
||||
# for criticism
|
||||
criticism_points = 2
|
||||
todo = create_a_todo(description='Bad patch')
|
||||
energy_points_before_review = energy_points_after_review
|
||||
review_points_before_review = review_points_after_review
|
||||
review(created_todo, criticism_points, 'test@example.com', 'You could have done better.', 'Criticism')
|
||||
review(todo, criticism_points, 'test@example.com', 'You could have done better.', 'Criticism')
|
||||
energy_points_after_review = get_points('test@example.com')
|
||||
review_points_after_review = get_points('test2@example.com', 'review_points')
|
||||
self.assertEqual(energy_points_after_review, energy_points_before_review - criticism_points)
|
||||
|
|
@ -332,11 +335,14 @@ def create_energy_point_rule_for_todo(multiplier_field=None, for_doc_event='Cust
|
|||
'apply_only_once': apply_once
|
||||
}).insert(ignore_permissions=1)
|
||||
|
||||
def create_a_todo():
|
||||
|
||||
def create_a_todo(description=None):
|
||||
if not description:
|
||||
description = 'Fix a bug'
|
||||
return frappe.get_doc({
|
||||
'doctype': 'ToDo',
|
||||
'description': 'Fix a bug',
|
||||
}).insert()
|
||||
'description': description,
|
||||
}).insert(ignore_permissions=True)
|
||||
|
||||
|
||||
def get_points(user, point_type='energy_points'):
|
||||
|
|
|
|||
|
|
@ -38,6 +38,6 @@
|
|||
like
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
@ -12,7 +12,11 @@
|
|||
{# powered #}
|
||||
<div class="footer-col-right col-sm-6 col-12 footer-powered">
|
||||
{% block powered %}
|
||||
{% include "templates/includes/footer/footer_powered.html" %}
|
||||
{%- if footer_powered -%}
|
||||
{{ footer_powered }}
|
||||
{%- else -%}
|
||||
{% include "templates/includes/footer/footer_powered.html" %}
|
||||
{%- endif -%}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -95,8 +95,6 @@
|
|||
min-width: 200px;
|
||||
padding: 0px;
|
||||
font-size: 85%;
|
||||
|
||||
// only rounded bottoms
|
||||
border-radius: 0px 0px 4px 4px;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<p>{{ payment_message or _("Your payment was successfully accepted") }}</p>
|
||||
{% if not payment_message %}
|
||||
<div>
|
||||
<a
|
||||
<a
|
||||
href='{{ frappe.form_dict.redirect_to or "/" }}'
|
||||
class='btn btn-primary btn-sm'>
|
||||
{{ _("Continue") }}
|
||||
|
|
|
|||
|
|
@ -97,6 +97,12 @@ class TestReportview(unittest.TestCase):
|
|||
self.assertFalse(result
|
||||
in DatabaseQuery("DocType").execute(filters={"name": ["not in", 'DocType,DocField']}))
|
||||
|
||||
def test_none_filter(self):
|
||||
query = frappe.db.query.get_sql("DocType", fields="name", filters={"restrict_to_domain": None})
|
||||
sql = str(query).replace('`', '').replace('"', '')
|
||||
condition = 'restrict_to_domain IS NULL'
|
||||
self.assertIn(condition, sql)
|
||||
|
||||
def test_or_filters(self):
|
||||
data = DatabaseQuery("DocField").execute(
|
||||
filters={"parent": "DocType"}, fields=["fieldname", "fieldtype"],
|
||||
|
|
@ -149,7 +155,6 @@ class TestReportview(unittest.TestCase):
|
|||
filters={"creation": ["between", ["2016-07-06", "2016-07-07"]]},
|
||||
fields=["name"])
|
||||
|
||||
|
||||
def test_ignore_permissions_for_get_filters_cond(self):
|
||||
frappe.set_user('test2@example.com')
|
||||
self.assertRaises(frappe.PermissionError, get_filters_cond, 'DocType', dict(istable=1), [])
|
||||
|
|
@ -351,7 +356,6 @@ class TestReportview(unittest.TestCase):
|
|||
self.assertTrue(len(data) == 0)
|
||||
self.assertTrue(len(frappe.get_all('Nested DocType', {'name': ('not ancestors of', 'Root')})) == len(frappe.get_all('Nested DocType')))
|
||||
|
||||
|
||||
def test_is_set_is_not_set(self):
|
||||
res = DatabaseQuery('DocType').execute(filters={'autoname': ['is', 'not set']})
|
||||
self.assertTrue({'name': 'Integration Request'} in res)
|
||||
|
|
|
|||
|
|
@ -319,3 +319,21 @@ class TestDocument(unittest.TestCase):
|
|||
self.assertIsInstance(doc, Note)
|
||||
self.assertIsInstance(doc.as_dict().get("age"), timedelta)
|
||||
self.assertIsInstance(doc.get_valid_dict().get("age"), timedelta)
|
||||
|
||||
def test_run_method(self):
|
||||
doc = frappe.get_last_doc("User")
|
||||
|
||||
# Case 1: Override with a string
|
||||
doc.as_dict = ""
|
||||
|
||||
# run_method should throw TypeError
|
||||
self.assertRaisesRegex(TypeError, "not callable", doc.run_method, "as_dict")
|
||||
|
||||
# Case 2: Override with a function
|
||||
def my_as_dict(*args, **kwargs):
|
||||
return "success"
|
||||
|
||||
doc.as_dict = my_as_dict
|
||||
|
||||
# run_method should get overridden
|
||||
self.assertEqual(doc.run_method("as_dict"), "success")
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
import frappe
|
||||
import frappe.defaults
|
||||
import unittest
|
||||
import frappe.model.meta
|
||||
from frappe.permissions import (add_user_permission, remove_user_permission,
|
||||
clear_user_permissions_for_doctype, get_doc_permissions, add_permission, update_permission_property)
|
||||
|
|
@ -14,7 +13,7 @@ from frappe.core.doctype.user_permission.user_permission import clear_user_permi
|
|||
from frappe.desk.form.load import getdoc
|
||||
from frappe.utils.data import now_datetime
|
||||
|
||||
from frappe.tests.test_utils import FrappeTestCase
|
||||
from frappe.tests.utils import FrappeTestCase
|
||||
|
||||
test_dependencies = ['Blogger', 'Blog Post', "User", "Contact", "Salutation"]
|
||||
|
||||
|
|
|
|||
|
|
@ -510,16 +510,3 @@ class TestLinkTitle(unittest.TestCase):
|
|||
todo.delete()
|
||||
user.delete()
|
||||
prop_setter.delete()
|
||||
|
||||
|
||||
class FrappeTestCase(unittest.TestCase):
|
||||
"""Base test class for Frappe tests."""
|
||||
@classmethod
|
||||
def setUpClass(cls) -> None:
|
||||
frappe.db.commit()
|
||||
return super().setUpClass()
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls) -> None:
|
||||
frappe.db.rollback()
|
||||
return super().tearDownClass()
|
||||
|
|
|
|||
76
frappe/tests/utils.py
Normal file
76
frappe/tests/utils.py
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
import copy
|
||||
import signal
|
||||
import unittest
|
||||
from contextlib import contextmanager
|
||||
|
||||
import frappe
|
||||
|
||||
|
||||
class FrappeTestCase(unittest.TestCase):
|
||||
"""Base test class for Frappe tests."""
|
||||
@classmethod
|
||||
def setUpClass(cls) -> None:
|
||||
frappe.db.commit()
|
||||
return super().setUpClass()
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls) -> None:
|
||||
frappe.db.rollback()
|
||||
return super().tearDownClass()
|
||||
|
||||
|
||||
@contextmanager
|
||||
def change_settings(doctype, settings_dict):
|
||||
""" A context manager to ensure that settings are changed before running
|
||||
function and restored after running it regardless of exceptions occured.
|
||||
This is useful in tests where you want to make changes in a function but
|
||||
don't retain those changes.
|
||||
import and use as decorator to cover full function or using `with` statement.
|
||||
|
||||
example:
|
||||
@change_settings("Print Settings", {"send_print_as_pdf": 1})
|
||||
def test_case(self):
|
||||
...
|
||||
"""
|
||||
|
||||
try:
|
||||
settings = frappe.get_doc(doctype)
|
||||
# remember setting
|
||||
previous_settings = copy.deepcopy(settings_dict)
|
||||
for key in previous_settings:
|
||||
previous_settings[key] = getattr(settings, key)
|
||||
|
||||
# change setting
|
||||
for key, value in settings_dict.items():
|
||||
setattr(settings, key, value)
|
||||
settings.save()
|
||||
# singles are cached by default, clear to avoid flake
|
||||
frappe.db.value_cache[settings] = {}
|
||||
yield # yield control to calling function
|
||||
|
||||
finally:
|
||||
# restore settings
|
||||
settings = frappe.get_doc(doctype)
|
||||
for key, value in previous_settings.items():
|
||||
setattr(settings, key, value)
|
||||
settings.save()
|
||||
|
||||
|
||||
def timeout(seconds=30, error_message="Test timed out."):
|
||||
""" Timeout decorator to ensure a test doesn't run for too long.
|
||||
|
||||
adapted from https://stackoverflow.com/a/2282656"""
|
||||
def decorator(func):
|
||||
def _handle_timeout(signum, frame):
|
||||
raise Exception(error_message)
|
||||
|
||||
def wrapper(*args, **kwargs):
|
||||
signal.signal(signal.SIGALRM, _handle_timeout)
|
||||
signal.alarm(seconds)
|
||||
try:
|
||||
result = func(*args, **kwargs)
|
||||
finally:
|
||||
signal.alarm(0)
|
||||
return result
|
||||
return wrapper
|
||||
return decorator
|
||||
|
|
@ -35,7 +35,7 @@ def get_random(doctype, filters=None, doc=False):
|
|||
condition = " where " + " and ".join(condition)
|
||||
else:
|
||||
condition = ""
|
||||
|
||||
|
||||
out = frappe.db.multisql({
|
||||
'mariadb': """select name from `tab%s` %s
|
||||
order by RAND() limit 1 offset 0""" % (doctype, condition),
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
"copyright",
|
||||
"address",
|
||||
"footer_items",
|
||||
"footer_powered",
|
||||
"footer_template",
|
||||
"footer_template_values",
|
||||
"edit_footer_template_values",
|
||||
|
|
@ -142,7 +143,6 @@
|
|||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"collapsible_depends_on": "top_bar_items",
|
||||
"fieldname": "top_bar",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Navbar"
|
||||
|
|
@ -189,7 +189,8 @@
|
|||
"description": "Address and other legal information you may want to put in the footer.",
|
||||
"fieldname": "address",
|
||||
"fieldtype": "Text Editor",
|
||||
"label": "Address"
|
||||
"label": "Address",
|
||||
"max_height": "8rem"
|
||||
},
|
||||
{
|
||||
"fieldname": "footer_items",
|
||||
|
|
@ -391,6 +392,7 @@
|
|||
"label": "App Logo"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "account_deletion_settings_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Account Deletion Settings"
|
||||
|
|
@ -406,6 +408,11 @@
|
|||
"fieldname": "auto_account_deletion",
|
||||
"fieldtype": "Int",
|
||||
"label": "Auto Account Deletion within (Days)"
|
||||
},
|
||||
{
|
||||
"fieldname": "footer_powered",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Footer \"Powered By\""
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-cog",
|
||||
|
|
@ -414,7 +421,7 @@
|
|||
"issingle": 1,
|
||||
"links": [],
|
||||
"max_attachments": 10,
|
||||
"modified": "2021-12-15 17:28:59.255184",
|
||||
"modified": "2022-02-28 23:05:42.493192",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Website",
|
||||
"name": "Website Settings",
|
||||
|
|
@ -437,5 +444,6 @@
|
|||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "ASC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
|
|
@ -120,7 +120,8 @@ def get_website_settings(context=None):
|
|||
"facebook_share", "google_plus_one", "twitter_share", "linked_in_share",
|
||||
"disable_signup", "hide_footer_signup", "head_html", "title_prefix",
|
||||
"navbar_template", "footer_template", "navbar_search", "enable_view_tracking",
|
||||
"footer_logo", "call_to_action", "call_to_action_url", "show_language_picker"]:
|
||||
"footer_logo", "call_to_action", "call_to_action_url", "show_language_picker",
|
||||
"footer_powered"]:
|
||||
if hasattr(settings, k):
|
||||
context[k] = settings.get(k)
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
add_top_padding=1,
|
||||
add_bottom_padding=1,
|
||||
) }}
|
||||
|
||||
|
||||
|
||||
{% if doc.get({"doctype":"Company History"}) %}
|
||||
<section class="section section-padding-bottom">
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@
|
|||
{% if item.target %}target="{{ item.target }}"{% endif %}>
|
||||
{{ _(item.title or item.label) }}
|
||||
</a>
|
||||
{%- endfor %}
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,6 @@ no_cache = 1
|
|||
def get_context(context):
|
||||
if frappe.session.user=='Guest':
|
||||
frappe.throw(_("You need to be logged in to access this page"), frappe.PermissionError)
|
||||
|
||||
|
||||
context.current_user = frappe.get_doc("User", frappe.session.user)
|
||||
context.show_sidebar=True
|
||||
|
|
@ -53,8 +53,8 @@
|
|||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="empty-apps-state">
|
||||
<img src="/assets/frappe/images/ui-states/empty-app-state.svg"/>
|
||||
<div class="font-weight-bold mt-4">
|
||||
<img src="/assets/frappe/images/ui-states/empty-app-state.svg"/>
|
||||
<div class="font-weight-bold mt-4">
|
||||
{{ _("No Active Sessions")}}
|
||||
</div>
|
||||
<div class="text-muted mt-2">
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue