Merge branch 'develop' of github.com:frappe/frappe into mv-custom-script-client-script
This commit is contained in:
commit
6c4da1f228
172 changed files with 2400 additions and 19127 deletions
|
|
@ -1,2 +0,0 @@
|
|||
exclude_paths:
|
||||
- '**.sql'
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
version = 1
|
||||
|
||||
test_patterns = [
|
||||
"**/test_*.py"
|
||||
]
|
||||
|
||||
exclude_patterns = [
|
||||
"frappe/patches/**",
|
||||
"*.min.js"
|
||||
]
|
||||
|
||||
[[analyzers]]
|
||||
name = "python"
|
||||
enabled = true
|
||||
|
||||
[analyzers.meta]
|
||||
runtime_version = "3.x.x"
|
||||
|
|
@ -5,5 +5,4 @@ frappe/core/doctype/doctype/boilerplate/*
|
|||
frappe/core/doctype/report/boilerplate/*
|
||||
frappe/public/js/frappe/class.js
|
||||
frappe/templates/includes/*
|
||||
frappe/tests/testcafe/*
|
||||
frappe/www/website_script.js
|
||||
frappe/www/website_script.js
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ pull_request_rules:
|
|||
- name: Automatic squash on CI success and review
|
||||
conditions:
|
||||
- status-success=Sider
|
||||
- status-success=Semantic Pull Request
|
||||
- status-success=Travis CI - Pull Request
|
||||
- status-success=security/snyk (frappe)
|
||||
- label!=dont-merge
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# stolen from http://cgit.drupalcode.org/octopus/commit/?id=db4f837
|
||||
includedir=`mysql_config --variable=pkgincludedir`
|
||||
thiscwd=`pwd`
|
||||
_THIS_DB_VERSION=`mysql -V 2>&1 | tr -d "\n" | cut -d" " -f6 | awk '{ print $1}' | cut -d"-" -f1 | awk '{ print $1}' | sed "s/[\,']//g"`
|
||||
if [ "$_THIS_DB_VERSION" = "5.5.40" ] && [ ! -e "$includedir-$_THIS_DB_VERSION-fixed.log" ] ; then
|
||||
cd $includedir
|
||||
sudo patch -p1 < $thiscwd/ci/my_config.h.patch &> /dev/null
|
||||
sudo touch $includedir-$_THIS_DB_VERSION-fixed.log
|
||||
fi
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
diff -burp a/my_config.h b/my_config.h
|
||||
--- a/my_config.h 2014-10-09 19:32:46.000000000 -0400
|
||||
+++ b/my_config.h 2014-10-09 19:35:12.000000000 -0400
|
||||
@@ -641,17 +641,4 @@
|
||||
#define SIZEOF_TIME_T 8
|
||||
/* #undef TIME_T_UNSIGNED */
|
||||
|
||||
-/*
|
||||
- stat structure (from <sys/stat.h>) is conditionally defined
|
||||
- to have different layout and size depending on the defined macros.
|
||||
- The correct macro is defined in my_config.h, which means it MUST be
|
||||
- included first (or at least before <features.h> - so, practically,
|
||||
- before including any system headers).
|
||||
-
|
||||
- __GLIBC__ is defined in <features.h>
|
||||
-*/
|
||||
-#ifdef __GLIBC__
|
||||
-#error <my_config.h> MUST be included first!
|
||||
-#endif
|
||||
-
|
||||
#endif
|
||||
|
||||
|
|
@ -18,7 +18,7 @@ context('Control Rating', () => {
|
|||
get_dialog_with_rating().as('dialog');
|
||||
|
||||
cy.get('div.rating')
|
||||
.children('i.fa')
|
||||
.children('svg')
|
||||
.first()
|
||||
.click()
|
||||
.should('have.class', 'star-click');
|
||||
|
|
@ -33,11 +33,11 @@ context('Control Rating', () => {
|
|||
get_dialog_with_rating();
|
||||
|
||||
cy.get('div.rating')
|
||||
.children('i.fa')
|
||||
.children('svg')
|
||||
.first()
|
||||
.invoke('trigger', 'mouseenter')
|
||||
.should('have.class', 'star-hover')
|
||||
.invoke('trigger', 'mouseleave')
|
||||
.should('not.have.class', 'star-hover');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@ Cypress.Commands.add('get_open_dialog', () => {
|
|||
});
|
||||
|
||||
Cypress.Commands.add('hide_dialog', () => {
|
||||
cy.wait(200);
|
||||
cy.wait(300);
|
||||
cy.get_open_dialog().find('.btn-modal-close').click();
|
||||
cy.get('.modal:visible').should('not.exist');
|
||||
});
|
||||
|
|
@ -312,7 +312,6 @@ Cypress.Commands.add('add_filter', () => {
|
|||
cy.get('.filter-section .filter-button').click();
|
||||
cy.wait(300);
|
||||
cy.get('.filter-popover').should('exist');
|
||||
cy.get('.filter-popover').find('.add-filter').click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('clear_filters', () => {
|
||||
|
|
|
|||
|
|
@ -181,6 +181,9 @@ def make_form_dict(request):
|
|||
else:
|
||||
args = request.form or request.args
|
||||
|
||||
if not isinstance(args, dict):
|
||||
frappe.throw("Invalid request arguments")
|
||||
|
||||
try:
|
||||
frappe.local.form_dict = frappe._dict({ k:v[0] if isinstance(v, (list, tuple)) else v \
|
||||
for k, v in iteritems(args) })
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ from frappe.model.document import Document
|
|||
from frappe.core.doctype.communication.email import make
|
||||
from frappe.utils.background_jobs import get_jobs
|
||||
from frappe.automation.doctype.assignment_rule.assignment_rule import get_repeated
|
||||
from frappe.contacts.doctype.contact.contact import get_contacts_linked_from
|
||||
from frappe.contacts.doctype.contact.contact import get_contacts_linking_to
|
||||
|
||||
month_map = {'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6, 'Yearly': 12}
|
||||
week_map = {'Monday': 0, 'Tuesday': 1, 'Wednesday': 2, 'Thursday': 3, 'Friday': 4, 'Saturday': 5, 'Sunday': 6}
|
||||
|
|
@ -328,13 +330,8 @@ class AutoRepeat(Document):
|
|||
|
||||
def fetch_linked_contacts(self):
|
||||
if self.reference_doctype and self.reference_document:
|
||||
res = frappe.db.get_all('Contact',
|
||||
fields=['email_id'],
|
||||
filters=[
|
||||
['Dynamic Link', 'link_doctype', '=', self.reference_doctype],
|
||||
['Dynamic Link', 'link_name', '=', self.reference_document]
|
||||
])
|
||||
|
||||
res = get_contacts_linking_to(self.reference_doctype, self.reference_document, fields=['email_id'])
|
||||
res += get_contacts_linked_from(self.reference_doctype, self.reference_document, fields=['email_id'])
|
||||
email_ids = list(set([d.email_id for d in res]))
|
||||
if not email_ids:
|
||||
frappe.msgprint(_('No contacts linked to document'), alert=True)
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ from frappe.website.doctype.web_page_view.web_page_view import is_tracking_enabl
|
|||
from frappe.social.doctype.energy_point_log.energy_point_log import get_energy_points
|
||||
from frappe.model.base_document import get_controller
|
||||
from frappe.social.doctype.post.post import frequently_visited_links
|
||||
from frappe.core.doctype.navbar_settings.navbar_settings import get_navbar_settings
|
||||
from frappe.core.doctype.navbar_settings.navbar_settings import get_navbar_settings, get_app_logo
|
||||
|
||||
def get_bootinfo():
|
||||
"""build and return boot info"""
|
||||
|
|
@ -62,6 +62,7 @@ def get_bootinfo():
|
|||
doclist.extend(get_meta_bundle("Page"))
|
||||
bootinfo.home_folder = frappe.db.get_value("File", {"is_home_folder": 1})
|
||||
bootinfo.navbar_settings = get_navbar_settings()
|
||||
bootinfo.notification_settings = get_notification_settings()
|
||||
|
||||
# ipinfo
|
||||
if frappe.session.data.get('ipinfo'):
|
||||
|
|
@ -90,6 +91,7 @@ def get_bootinfo():
|
|||
bootinfo.link_preview_doctypes = get_link_preview_doctypes()
|
||||
bootinfo.additional_filters_config = get_additional_filters_from_hooks()
|
||||
bootinfo.desk_settings = get_desk_settings()
|
||||
bootinfo.app_logo_url = get_app_logo()
|
||||
|
||||
return bootinfo
|
||||
|
||||
|
|
@ -323,4 +325,7 @@ def get_desk_settings():
|
|||
for key in desk_properties:
|
||||
desk_settings[key] = desk_settings.get(key) or role.get(key)
|
||||
|
||||
return desk_settings
|
||||
return desk_settings
|
||||
|
||||
def get_notification_settings():
|
||||
return frappe.get_cached_doc('Notification Settings', frappe.session.user)
|
||||
|
|
|
|||
|
|
@ -256,3 +256,27 @@ def get_contact_with_phone_number(number):
|
|||
def get_contact_name(email_id):
|
||||
contact = frappe.get_list("Contact Email", filters={"email_id": email_id}, fields=["parent"], limit=1)
|
||||
return contact[0].parent if contact else None
|
||||
|
||||
def get_contacts_linking_to(doctype, docname, fields=None):
|
||||
"""Return a list of contacts containing a link to the given document."""
|
||||
return frappe.get_list('Contact', fields=fields, filters=[
|
||||
['Dynamic Link', 'link_doctype', '=', doctype],
|
||||
['Dynamic Link', 'link_name', '=', docname]
|
||||
])
|
||||
|
||||
def get_contacts_linked_from(doctype, docname, fields=None):
|
||||
"""Return a list of contacts that are contained in (linked from) the given document."""
|
||||
link_fields = frappe.get_meta(doctype).get('fields', {
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Contact'
|
||||
})
|
||||
if not link_fields:
|
||||
return []
|
||||
|
||||
contact_names = frappe.get_value(doctype, docname, fieldname=[f.fieldname for f in link_fields])
|
||||
if not contact_names:
|
||||
return []
|
||||
|
||||
return frappe.get_list('Contact', fields=fields, filters={
|
||||
'name': ('in', contact_names)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -656,7 +656,7 @@ class DocType(Document):
|
|||
flags = {"flags": re.ASCII} if six.PY3 else {}
|
||||
|
||||
# a DocType name should not start or end with an empty space
|
||||
if re.match("^[ \t\n\r]+|[ \t\n\r]+$", name, **flags):
|
||||
if re.search("^[ \t\n\r]+|[ \t\n\r]+$", name, **flags):
|
||||
frappe.throw(_("DocType's name should not start or end with whitespace"), frappe.NameError)
|
||||
|
||||
# a DocType's name should not start with a number or underscore
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class NavbarSettings(Document):
|
|||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def get_app_logo():
|
||||
app_logo = frappe.db.get_single_value('Navbar Settings', 'app_logo')
|
||||
app_logo = frappe.db.get_single_value('Navbar Settings', 'app_logo', cache=True)
|
||||
if not app_logo:
|
||||
app_logo = frappe.get_hooks('app_logo_url')[-1]
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from typing import Dict, List
|
||||
|
||||
import frappe, json
|
||||
from frappe.model.document import Document
|
||||
|
|
@ -11,12 +12,13 @@ from datetime import datetime
|
|||
from croniter import croniter
|
||||
from frappe.utils.background_jobs import enqueue, get_jobs
|
||||
|
||||
|
||||
class ScheduledJobType(Document):
|
||||
def autoname(self):
|
||||
self.name = '.'.join(self.method.split('.')[-2:])
|
||||
self.name = ".".join(self.method.split(".")[-2:])
|
||||
|
||||
def validate(self):
|
||||
if self.frequency != 'All':
|
||||
if self.frequency != "All":
|
||||
# force logging for all events other than continuous ones (ALL)
|
||||
self.create_log = 1
|
||||
|
||||
|
|
@ -84,7 +86,7 @@ class ScheduledJobType(Document):
|
|||
|
||||
def log_status(self, status):
|
||||
# log file
|
||||
frappe.logger("scheduler").info('Scheduled Job {0}: {1} for {2}'.format(status, self.method, frappe.local.site))
|
||||
frappe.logger("scheduler").info(f"Scheduled Job {status}: {self.method} for {frappe.local.site}")
|
||||
self.update_scheduler_log(status)
|
||||
|
||||
def update_scheduler_log(self, status):
|
||||
|
|
@ -111,28 +113,28 @@ class ScheduledJobType(Document):
|
|||
|
||||
|
||||
@frappe.whitelist()
|
||||
def execute_event(doc):
|
||||
frappe.only_for('System Manager')
|
||||
def execute_event(doc: str):
|
||||
frappe.only_for("System Manager")
|
||||
doc = json.loads(doc)
|
||||
frappe.get_doc('Scheduled Job Type', doc.get('name')).enqueue(force=True)
|
||||
frappe.get_doc("Scheduled Job Type", doc.get("name")).enqueue(force=True)
|
||||
|
||||
|
||||
def run_scheduled_job(job_type):
|
||||
'''This is a wrapper function that runs a hooks.scheduler_events method'''
|
||||
def run_scheduled_job(job_type: str):
|
||||
"""This is a wrapper function that runs a hooks.scheduler_events method"""
|
||||
try:
|
||||
frappe.get_doc('Scheduled Job Type', dict(method=job_type)).execute()
|
||||
frappe.get_doc("Scheduled Job Type", dict(method=job_type)).execute()
|
||||
except Exception:
|
||||
print(frappe.get_traceback())
|
||||
|
||||
|
||||
def sync_jobs(hooks=None):
|
||||
def sync_jobs(hooks: Dict = None):
|
||||
frappe.reload_doc("core", "doctype", "scheduled_job_type")
|
||||
scheduler_events = hooks or frappe.get_hooks("scheduler_events")
|
||||
all_events = insert_events(scheduler_events)
|
||||
clear_events(all_events)
|
||||
|
||||
|
||||
def insert_events(scheduler_events):
|
||||
def insert_events(scheduler_events: Dict) -> List:
|
||||
cron_jobs, event_jobs = [], []
|
||||
for event_type in scheduler_events:
|
||||
events = scheduler_events.get(event_type)
|
||||
|
|
@ -144,7 +146,7 @@ def insert_events(scheduler_events):
|
|||
return cron_jobs + event_jobs
|
||||
|
||||
|
||||
def insert_cron_jobs(events):
|
||||
def insert_cron_jobs(events: Dict) -> List:
|
||||
cron_jobs = []
|
||||
for cron_format in events:
|
||||
for event in events.get(cron_format):
|
||||
|
|
@ -153,25 +155,29 @@ def insert_cron_jobs(events):
|
|||
return cron_jobs
|
||||
|
||||
|
||||
def insert_event_jobs(events, event_type):
|
||||
def insert_event_jobs(events: List, event_type: str) -> List:
|
||||
event_jobs = []
|
||||
for event in events:
|
||||
event_jobs.append(event)
|
||||
frequency = event_type.replace('_', ' ').title()
|
||||
frequency = event_type.replace("_", " ").title()
|
||||
insert_single_event(frequency, event)
|
||||
return event_jobs
|
||||
|
||||
|
||||
def insert_single_event(frequency, event, cron_format=None):
|
||||
def insert_single_event(frequency: str, event: str, cron_format: str = None):
|
||||
cron_expr = {"cron_format": cron_format} if cron_format else {}
|
||||
doc = frappe.get_doc({
|
||||
"doctype": "Scheduled Job Type",
|
||||
"method": event,
|
||||
"cron_format": cron_format,
|
||||
"frequency": frequency
|
||||
})
|
||||
doc = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Scheduled Job Type",
|
||||
"method": event,
|
||||
"cron_format": cron_format,
|
||||
"frequency": frequency,
|
||||
}
|
||||
)
|
||||
|
||||
if not frappe.db.exists("Scheduled Job Type", {"method": event, "frequency": frequency, **cron_expr }):
|
||||
if not frappe.db.exists(
|
||||
"Scheduled Job Type", {"method": event, "frequency": frequency, **cron_expr}
|
||||
):
|
||||
try:
|
||||
doc.insert()
|
||||
except frappe.DuplicateEntryError:
|
||||
|
|
@ -179,7 +185,12 @@ def insert_single_event(frequency, event, cron_format=None):
|
|||
doc.insert()
|
||||
|
||||
|
||||
def clear_events(all_events):
|
||||
for event in frappe.get_all("Scheduled Job Type", ("name", "method")):
|
||||
if event.method not in all_events:
|
||||
def clear_events(all_events: List):
|
||||
for event in frappe.get_all(
|
||||
"Scheduled Job Type", fields=["name", "method", "server_script"]
|
||||
):
|
||||
is_server_script = event.server_script
|
||||
is_defined_in_hooks = event.method in all_events
|
||||
|
||||
if not (is_defined_in_hooks or is_server_script):
|
||||
frappe.delete_doc("Scheduled Job Type", event.name)
|
||||
|
|
|
|||
|
|
@ -6,46 +6,11 @@ frappe.ui.form.on('Server Script', {
|
|||
frm.trigger('setup_help');
|
||||
},
|
||||
refresh: function(frm) {
|
||||
if (frm.doc.script_type === 'Scheduler Event' && !frm.doc.disabled) {
|
||||
frm.add_custom_button('Schedule Script', function() {
|
||||
var d = new frappe.ui.Dialog({
|
||||
title: "Schedule Script Execution",
|
||||
fields: [
|
||||
{
|
||||
fieldname: "event_type",
|
||||
label: __('Select Event Type'),
|
||||
fieldtype: "Select",
|
||||
options: "All\nHourly\nDaily\nWeekly\nMonthly\nYearly\nHourly Long\nDaily Long\nWeekly Long\nMonthly Long"
|
||||
},
|
||||
],
|
||||
primary_action_label: __('Schedule Script'),
|
||||
primary_action: () => {
|
||||
d.get_primary_btn().attr('disabled', true);
|
||||
var data = d.get_values();
|
||||
d.hide();
|
||||
if(data) {
|
||||
frm.events.schedule_script(frm, data);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
d.show();
|
||||
|
||||
});
|
||||
if (frm.doc.script_type != 'Scheduler Event') {
|
||||
frm.dashboard.hide();
|
||||
}
|
||||
},
|
||||
|
||||
schedule_script(frm, data) {
|
||||
frm.call({
|
||||
method: "frappe.core.doctype.server_script.server_script.setup_scheduler_events",
|
||||
args: {
|
||||
'script_name': frm.doc.name,
|
||||
'frequency': data.event_type
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setup_help(frm) {
|
||||
frm.get_field('help_html').html(`
|
||||
<h4>DocType Event</h4>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
"field_order": [
|
||||
"script_type",
|
||||
"reference_doctype",
|
||||
"event_frequency",
|
||||
"doctype_event",
|
||||
"api_method",
|
||||
"allow_guest",
|
||||
|
|
@ -84,11 +85,24 @@
|
|||
{
|
||||
"fieldname": "help_html",
|
||||
"fieldtype": "HTML"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.script_type == \"Scheduler Event\"",
|
||||
"fieldname": "event_frequency",
|
||||
"fieldtype": "Select",
|
||||
"label": "Event Frequency",
|
||||
"mandatory_depends_on": "eval:doc.script_type == \"Scheduler Event\"",
|
||||
"options": "All\nHourly\nDaily\nWeekly\nMonthly\nYearly\nHourly Long\nDaily Long\nWeekly Long\nMonthly Long"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-01-03 18:50:14.767595",
|
||||
"links": [
|
||||
{
|
||||
"link_doctype": "Scheduled Job Type",
|
||||
"link_fieldname": "server_script"
|
||||
}
|
||||
],
|
||||
"modified": "2021-02-18 12:36:19.803425",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "Server Script",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import ast
|
||||
from typing import Dict, List
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
|
@ -14,67 +15,146 @@ from frappe import _
|
|||
|
||||
class ServerScript(Document):
|
||||
def validate(self):
|
||||
frappe.only_for('Script Manager', True)
|
||||
frappe.only_for("Script Manager", True)
|
||||
self.validate_script()
|
||||
self.sync_scheduled_jobs()
|
||||
self.clear_scheduled_events()
|
||||
|
||||
def on_update(self):
|
||||
frappe.cache().delete_value("server_script_map")
|
||||
self.sync_scheduler_events()
|
||||
|
||||
def on_trash(self):
|
||||
if self.script_type == "Scheduler Event":
|
||||
for job in self.scheduled_jobs:
|
||||
frappe.delete_doc("Scheduled Job Type", job.name)
|
||||
|
||||
@property
|
||||
def scheduled_jobs(self) -> List[Dict[str, str]]:
|
||||
return frappe.get_all(
|
||||
"Scheduled Job Type",
|
||||
filters={"server_script": self.name},
|
||||
fields=["name", "stopped"],
|
||||
)
|
||||
|
||||
def validate_script(self):
|
||||
"""Utilizes the ast module to check for syntax errors
|
||||
"""
|
||||
ast.parse(self.script)
|
||||
|
||||
@staticmethod
|
||||
def on_update():
|
||||
frappe.cache().delete_value('server_script_map')
|
||||
def sync_scheduled_jobs(self):
|
||||
"""Sync Scheduled Job Type statuses if Server Script's disabled status is changed
|
||||
"""
|
||||
if self.script_type != "Scheduler Event" or not self.has_value_changed("disabled"):
|
||||
return
|
||||
|
||||
def execute_method(self):
|
||||
if self.script_type == 'API':
|
||||
# validate if guest is allowed
|
||||
if frappe.session.user == 'Guest' and not self.allow_guest:
|
||||
raise frappe.PermissionError
|
||||
_globals, _locals = safe_exec(self.script)
|
||||
return _globals.frappe.flags # output can be stored in flags
|
||||
else:
|
||||
# wrong report type!
|
||||
for scheduled_job in self.scheduled_jobs:
|
||||
if bool(scheduled_job.stopped) != bool(self.disabled):
|
||||
job = frappe.get_doc("Scheduled Job Type", scheduled_job.name)
|
||||
job.stopped = self.disabled
|
||||
job.save()
|
||||
|
||||
def sync_scheduler_events(self):
|
||||
"""Create or update Scheduled Job Type documents for Scheduler Event Server Scripts
|
||||
"""
|
||||
if not self.disabled and self.event_frequency and self.script_type == "Scheduler Event":
|
||||
setup_scheduler_events(script_name=self.name, frequency=self.event_frequency)
|
||||
|
||||
def clear_scheduled_events(self):
|
||||
"""Deletes existing scheduled jobs by Server Script if self.event_frequency has changed
|
||||
"""
|
||||
if self.script_type == "Scheduler Event" and self.has_value_changed("event_frequency"):
|
||||
for scheduled_job in self.scheduled_jobs:
|
||||
frappe.delete_doc("Scheduled Job Type", scheduled_job.name)
|
||||
|
||||
def execute_method(self) -> Dict:
|
||||
"""Specific to API endpoint Server Scripts
|
||||
|
||||
Raises:
|
||||
frappe.DoesNotExistError: If self.script_type is not API
|
||||
frappe.PermissionError: If self.allow_guest is unset for API accessed by Guest user
|
||||
|
||||
Returns:
|
||||
dict: Evaluates self.script with frappe.utils.safe_exec.safe_exec and returns the flags set in it's safe globals
|
||||
"""
|
||||
# wrong report type!
|
||||
if self.script_type != "API":
|
||||
raise frappe.DoesNotExistError
|
||||
|
||||
def execute_doc(self, doc):
|
||||
# execute event
|
||||
safe_exec(self.script, None, dict(doc = doc))
|
||||
# validate if guest is allowed
|
||||
if frappe.session.user == "Guest" and not self.allow_guest:
|
||||
raise frappe.PermissionError
|
||||
|
||||
# output can be stored in flags
|
||||
_globals, _locals = safe_exec(self.script)
|
||||
return _globals.frappe.flags
|
||||
|
||||
def execute_doc(self, doc: Document):
|
||||
"""Specific to Document Event triggered Server Scripts
|
||||
|
||||
Args:
|
||||
doc (Document): Executes script with for a certain document's events
|
||||
"""
|
||||
safe_exec(self.script, _locals={"doc": doc})
|
||||
|
||||
def execute_scheduled_method(self):
|
||||
if self.script_type == 'Scheduler Event':
|
||||
safe_exec(self.script)
|
||||
else:
|
||||
# wrong report type!
|
||||
"""Specific to Scheduled Jobs via Server Scripts
|
||||
|
||||
Raises:
|
||||
frappe.DoesNotExistError: If script type is not a scheduler event
|
||||
"""
|
||||
if self.script_type != "Scheduler Event":
|
||||
raise frappe.DoesNotExistError
|
||||
|
||||
def get_permission_query_conditions(self, user):
|
||||
safe_exec(self.script)
|
||||
|
||||
def get_permission_query_conditions(self, user: str) -> List[str]:
|
||||
"""Specific to Permission Query Server Scripts
|
||||
|
||||
Args:
|
||||
user (str): Takes user email to execute script and return list of conditions
|
||||
|
||||
Returns:
|
||||
list: Returns list of conditions defined by rules in self.script
|
||||
"""
|
||||
locals = {"user": user, "conditions": ""}
|
||||
safe_exec(self.script, None, locals)
|
||||
if locals["conditions"]:
|
||||
return locals["conditions"]
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def setup_scheduler_events(script_name, frequency):
|
||||
method = frappe.scrub('{0}-{1}'.format(script_name, frequency))
|
||||
scheduled_script = frappe.db.get_value('Scheduled Job Type',
|
||||
dict(method=method))
|
||||
"""Creates or Updates Scheduled Job Type documents based on the specified script name and frequency
|
||||
|
||||
Args:
|
||||
script_name (str): Name of the Server Script document
|
||||
frequency (str): Event label compatible with the Frappe scheduler
|
||||
"""
|
||||
method = frappe.scrub(f"{script_name}-{frequency}")
|
||||
scheduled_script = frappe.db.get_value("Scheduled Job Type", {"method": method})
|
||||
|
||||
if not scheduled_script:
|
||||
doc = frappe.get_doc(dict(
|
||||
doctype = 'Scheduled Job Type',
|
||||
method = method,
|
||||
frequency = frequency,
|
||||
server_script = script_name
|
||||
))
|
||||
frappe.get_doc(
|
||||
{
|
||||
"doctype": "Scheduled Job Type",
|
||||
"method": method,
|
||||
"frequency": frequency,
|
||||
"server_script": script_name,
|
||||
}
|
||||
).insert()
|
||||
|
||||
doc.insert()
|
||||
|
||||
frappe.msgprint(_('Enabled scheduled execution for script {0}').format(script_name))
|
||||
frappe.msgprint(_("Enabled scheduled execution for script {0}").format(script_name))
|
||||
|
||||
else:
|
||||
doc = frappe.get_doc('Scheduled Job Type', scheduled_script)
|
||||
doc.update(dict(
|
||||
doctype = 'Scheduled Job Type',
|
||||
method = method,
|
||||
frequency = frequency,
|
||||
server_script = script_name
|
||||
))
|
||||
doc = frappe.get_doc("Scheduled Job Type", scheduled_script)
|
||||
|
||||
if doc.frequency == frequency:
|
||||
return
|
||||
|
||||
doc.frequency = frequency
|
||||
doc.save()
|
||||
|
||||
frappe.msgprint(_('Scheduled execution for script {0} has updated').format(script_name))
|
||||
frappe.msgprint(
|
||||
_("Scheduled execution for script {0} has updated").format(script_name)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# MIT License. See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe, unittest
|
||||
import frappe, unittest, uuid
|
||||
|
||||
from frappe.model.delete_doc import delete_doc
|
||||
from frappe.utils.data import today, add_to_date
|
||||
|
|
@ -240,6 +240,29 @@ class TestUser(unittest.TestCase):
|
|||
|
||||
self.assertRaises(frappe.ValidationError, user.reset_password, False)
|
||||
|
||||
def test_user_rollback(self):
|
||||
""" """
|
||||
frappe.db.commit()
|
||||
frappe.db.begin()
|
||||
user_id = str(uuid.uuid4())
|
||||
email = f'{user_id}@example.com'
|
||||
try:
|
||||
frappe.flags.in_import = True # disable throttling
|
||||
frappe.get_doc(dict(
|
||||
doctype='User',
|
||||
email=email,
|
||||
first_name=user_id,
|
||||
)).insert()
|
||||
finally:
|
||||
frappe.flags.in_import = False
|
||||
|
||||
# Check user has been added
|
||||
self.assertIsNotNone(frappe.db.get("User", {"email": email}))
|
||||
|
||||
# Check that rollback works
|
||||
frappe.db.rollback()
|
||||
self.assertIsNone(frappe.db.get("User", {"email": email}))
|
||||
|
||||
|
||||
def delete_contact(user):
|
||||
frappe.db.sql("DELETE FROM `tabContact` WHERE `email_id`= %s", user)
|
||||
|
|
|
|||
|
|
@ -302,7 +302,7 @@
|
|||
"no_copy": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"default": "1",
|
||||
"fieldname": "logout_all_sessions",
|
||||
"fieldtype": "Check",
|
||||
"label": "Logout From All Devices After Changing Password"
|
||||
|
|
@ -669,7 +669,7 @@
|
|||
}
|
||||
],
|
||||
"max_attachments": 5,
|
||||
"modified": "2021-01-02 11:21:50.507786",
|
||||
"modified": "2021-02-01 16:11:06.037543",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "User",
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@ class KanbanBoard(Document):
|
|||
def on_update(self):
|
||||
frappe.clear_cache(doctype=self.reference_doctype)
|
||||
|
||||
def before_insert(self):
|
||||
for column in self.columns:
|
||||
column.order = get_order_for_column(self, column.column_name)
|
||||
|
||||
def validate_column_name(self):
|
||||
for column in self.columns:
|
||||
if not column.column_name:
|
||||
|
|
@ -125,6 +129,53 @@ def update_order(board_name, order):
|
|||
board.save()
|
||||
return board, updated_cards
|
||||
|
||||
@frappe.whitelist()
|
||||
def update_order_for_single_card(board_name, docname, from_colname, to_colname, old_index, new_index):
|
||||
'''Save the order of cards in columns'''
|
||||
board = frappe.get_doc('Kanban Board', board_name)
|
||||
doctype = board.reference_doctype
|
||||
fieldname = board.field_name
|
||||
old_index = frappe.parse_json(old_index)
|
||||
new_index = frappe.parse_json(new_index)
|
||||
|
||||
# save current order and index of columns to be updated
|
||||
from_col_order, from_col_idx = get_kanban_column_order_and_index(board, from_colname)
|
||||
to_col_order, to_col_idx = get_kanban_column_order_and_index(board, to_colname)
|
||||
|
||||
if from_colname == to_colname:
|
||||
from_col_order = to_col_order
|
||||
|
||||
to_col_order.insert(new_index, from_col_order.pop((old_index)))
|
||||
|
||||
# save updated order
|
||||
board.columns[from_col_idx].order = frappe.as_json(from_col_order)
|
||||
board.columns[to_col_idx].order = frappe.as_json(to_col_order)
|
||||
board.save()
|
||||
|
||||
# update changed value in doc
|
||||
frappe.set_value(doctype, docname, fieldname, to_colname)
|
||||
|
||||
return board
|
||||
|
||||
def get_kanban_column_order_and_index(board, colname):
|
||||
for i, col in enumerate(board.columns):
|
||||
if col.column_name == colname:
|
||||
col_order = frappe.parse_json(col.order)
|
||||
col_idx = i
|
||||
|
||||
return col_order, col_idx
|
||||
|
||||
@frappe.whitelist()
|
||||
def add_card(board_name, docname, colname):
|
||||
board = frappe.get_doc('Kanban Board', board_name)
|
||||
|
||||
col_order, col_idx = get_kanban_column_order_and_index(board, colname)
|
||||
col_order.insert(0, docname)
|
||||
|
||||
board.columns[col_idx].order = frappe.as_json(col_order)
|
||||
|
||||
board.save()
|
||||
return board
|
||||
|
||||
@frappe.whitelist()
|
||||
def quick_kanban_board(doctype, board_name, field_name, project=None):
|
||||
|
|
@ -133,6 +184,13 @@ def quick_kanban_board(doctype, board_name, field_name, project=None):
|
|||
doc = frappe.new_doc('Kanban Board')
|
||||
meta = frappe.get_meta(doctype)
|
||||
|
||||
doc.kanban_board_name = board_name
|
||||
doc.reference_doctype = doctype
|
||||
doc.field_name = field_name
|
||||
|
||||
if project:
|
||||
doc.filters = '[["Task","project","=","{0}"]]'.format(project)
|
||||
|
||||
options = ''
|
||||
for field in meta.fields:
|
||||
if field.fieldname == field_name:
|
||||
|
|
@ -149,12 +207,6 @@ def quick_kanban_board(doctype, board_name, field_name, project=None):
|
|||
column_name=column
|
||||
))
|
||||
|
||||
doc.kanban_board_name = board_name
|
||||
doc.reference_doctype = doctype
|
||||
doc.field_name = field_name
|
||||
|
||||
if project:
|
||||
doc.filters = '[["Task","project","=","{0}"]]'.format(project)
|
||||
|
||||
if doctype in ['Note', 'ToDo']:
|
||||
doc.private = 1
|
||||
|
|
@ -162,6 +214,12 @@ def quick_kanban_board(doctype, board_name, field_name, project=None):
|
|||
doc.save()
|
||||
return doc
|
||||
|
||||
def get_order_for_column(board, colname):
|
||||
filters = [[board.reference_doctype, board.field_name, '=', colname]]
|
||||
if board.filters:
|
||||
filters.append(frappe.parse_json(board.filters)[0])
|
||||
|
||||
return frappe.as_json(frappe.get_list(board.reference_doctype, filters=filters, pluck='name'))
|
||||
|
||||
@frappe.whitelist()
|
||||
def update_column_order(board_name, order):
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ def create_notification_settings(user):
|
|||
_doc = frappe.new_doc('Notification Settings')
|
||||
_doc.name = user
|
||||
_doc.insert(ignore_permissions=True)
|
||||
frappe.db.commit()
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ def get_result(doc, filters, to_date=None):
|
|||
filters = frappe.parse_json(filters)
|
||||
|
||||
if not filters:
|
||||
filters = []
|
||||
filters = []
|
||||
|
||||
if to_date:
|
||||
filters.append([doc.document_type, 'creation', '<', to_date])
|
||||
|
|
@ -107,9 +107,13 @@ def get_percentage_difference(doc, filters, result):
|
|||
return
|
||||
|
||||
previous_result = calculate_previous_result(doc, filters)
|
||||
difference = (result - previous_result)/100.0
|
||||
|
||||
return difference
|
||||
if previous_result == 0:
|
||||
return None
|
||||
else:
|
||||
if result == previous_result:
|
||||
return 0
|
||||
else:
|
||||
return ((result/previous_result)-1)*100.0
|
||||
|
||||
|
||||
def calculate_previous_result(doc, filters):
|
||||
|
|
@ -197,4 +201,4 @@ def add_card_to_dashboard(args):
|
|||
card.save()
|
||||
|
||||
dashboard.append('cards', dashboard_link)
|
||||
dashboard.save()
|
||||
dashboard.save()
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ frappe.setup.SetupWizard = class SetupWizard extends frappe.ui.Slides {
|
|||
this.abort_setup(r.message.fail);
|
||||
}
|
||||
},
|
||||
error: this.abort_setup("Error in setup", true)
|
||||
error: () => this.abort_setup("Error in setup")
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -151,32 +151,30 @@ class UserProfile {
|
|||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
render_percentage_chart(field, title) {
|
||||
// REDESIGN-TODO: chart seems to be broken. Enable this once fixed.
|
||||
this.wrapper.find('.percentage-chart-container').hide();
|
||||
// frappe.xcall('frappe.desk.page.user_profile.user_profile.get_energy_points_percentage_chart_data', {
|
||||
// user: this.user_id,
|
||||
// field: field
|
||||
// }).then(chart => {
|
||||
// if (chart.labels.length) {
|
||||
// this.percentage_chart = new frappe.Chart('.performance-percentage-chart', {
|
||||
// type: 'percentage',
|
||||
// data: {
|
||||
// labels: chart.labels,
|
||||
// datasets: chart.datasets
|
||||
// },
|
||||
// truncateLegends: 1,
|
||||
// barOptions: {
|
||||
// height: 11,
|
||||
// depth: 1
|
||||
// },
|
||||
// height: 200,
|
||||
// maxSlices: 8,
|
||||
// colors: ['purple', 'blue', 'cyan', 'teal', 'pink', 'red', 'orange', 'yellow'],
|
||||
// });
|
||||
// } else {
|
||||
// this.wrapper.find('.percentage-chart-container').hide();
|
||||
// }
|
||||
// });
|
||||
frappe.xcall('frappe.desk.page.user_profile.user_profile.get_energy_points_percentage_chart_data', {
|
||||
user: this.user_id,
|
||||
field: field
|
||||
}).then(chart => {
|
||||
if (chart.labels.length) {
|
||||
this.percentage_chart = new frappe.Chart('.performance-percentage-chart', {
|
||||
type: 'percentage',
|
||||
data: {
|
||||
labels: chart.labels,
|
||||
datasets: chart.datasets
|
||||
},
|
||||
truncateLegends: 1,
|
||||
barOptions: {
|
||||
height: 11,
|
||||
depth: 1
|
||||
},
|
||||
height: 200,
|
||||
maxSlices: 8,
|
||||
colors: ['purple', 'blue', 'cyan', 'teal', 'pink', 'red', 'orange', 'yellow'],
|
||||
});
|
||||
} else {
|
||||
this.wrapper.find('.percentage-chart-container').hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
create_line_chart_filters() {
|
||||
|
|
@ -452,4 +450,4 @@ class UserProfileTimeline extends BaseTimeline {
|
|||
}
|
||||
|
||||
frappe.provide('frappe.ui');
|
||||
frappe.ui.UserProfile = UserProfile;
|
||||
frappe.ui.UserProfile = UserProfile;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class TestEmailBody(unittest.TestCase):
|
|||
<div>
|
||||
<h3>Hey John Doe!</h3>
|
||||
<p>This is embedded image you asked for</p>
|
||||
<img embed="assets/frappe/images/favicon.png" />
|
||||
<img embed="assets/frappe/images/frappe-favicon.svg" />
|
||||
</div>
|
||||
'''
|
||||
email_text = '''
|
||||
|
|
@ -25,7 +25,7 @@ Hey John Doe!
|
|||
This is the text version of this email
|
||||
'''
|
||||
|
||||
img_path = os.path.abspath('assets/frappe/images/favicon.png')
|
||||
img_path = os.path.abspath('assets/frappe/images/frappe-favicon.svg')
|
||||
with open(img_path, 'rb') as f:
|
||||
img_content = f.read()
|
||||
img_base64 = base64.b64encode(img_content).decode()
|
||||
|
|
@ -77,12 +77,11 @@ This is the text version of this email
|
|||
|
||||
def test_image(self):
|
||||
img_signature = '''
|
||||
Content-Type: image/png
|
||||
Content-Type: image/svg+xml
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: base64
|
||||
Content-Disposition: inline; filename="favicon.png"
|
||||
Content-Disposition: inline; filename="frappe-favicon.svg"
|
||||
'''
|
||||
|
||||
self.assertTrue(img_signature in self.email_string)
|
||||
self.assertTrue(self.img_base64 in self.email_string)
|
||||
|
||||
|
|
@ -117,7 +116,7 @@ w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|||
def test_replace_filename_with_cid(self):
|
||||
original_message = '''
|
||||
<div>
|
||||
<img embed="assets/frappe/images/favicon.png" alt="test" />
|
||||
<img embed="assets/frappe/images/frappe-favicon.svg" alt="test" />
|
||||
<img embed="notexists.jpg" />
|
||||
</div>
|
||||
'''
|
||||
|
|
|
|||
|
|
@ -2729,11 +2729,11 @@
|
|||
},
|
||||
"Zimbabwe": {
|
||||
"code": "zw",
|
||||
"currency": "ZWD",
|
||||
"currency_fraction": "Thebe",
|
||||
"currency": "ZWL",
|
||||
"currency_fraction": "Cent",
|
||||
"currency_fraction_units": 100,
|
||||
"currency_name": "Zimbabwe Dollar",
|
||||
"currency_symbol": "P",
|
||||
"currency_symbol": "ZWL$",
|
||||
"number_format": "# ###.##",
|
||||
"timezones": [
|
||||
"Africa/Harare"
|
||||
|
|
|
|||
|
|
@ -58,6 +58,11 @@ website_route_rules = [
|
|||
{"from_route": "/kb/<category>", "to_route": "Help Article"},
|
||||
{"from_route": "/newsletters", "to_route": "Newsletter"},
|
||||
{"from_route": "/profile", "to_route": "me"},
|
||||
{"from_route": "/app/<path:app_path>", "to_route": "app"},
|
||||
]
|
||||
|
||||
website_redirects = [
|
||||
{"source": r"/desk(.*)", "target": r"/app\1"},
|
||||
]
|
||||
|
||||
base_template = "templates/base.html"
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ class SocialLoginKey(Document):
|
|||
"provider_name": "Frappe",
|
||||
"enable_social_login": 1,
|
||||
"custom_base_url": 1,
|
||||
"icon":"/assets/frappe/images/favicon.png",
|
||||
"icon":"/assets/frappe/images/frappe-favicon.svg",
|
||||
"redirect_url": "/api/method/frappe.www.login.login_via_frappe",
|
||||
"api_endpoint": "/api/method/frappe.integrations.oauth2.openid_profile",
|
||||
"api_endpoint_args":None,
|
||||
|
|
|
|||
|
|
@ -1015,6 +1015,8 @@ class Document(BaseDocument):
|
|||
|
||||
def notify_update(self):
|
||||
"""Publish realtime that the current document is modified"""
|
||||
if frappe.flags.in_patch: return
|
||||
|
||||
frappe.publish_realtime("doc_update", {"modified": self.modified, "doctype": self.doctype, "name": self.name},
|
||||
doctype=self.doctype, docname=self.name, after_commit=True)
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ def sync_for(app_name, force=0, sync_everything = False, verbose=False, reset_pe
|
|||
|
||||
for module_name in frappe.local.app_modules.get(app_name) or []:
|
||||
folder = os.path.dirname(frappe.get_module(app_name + "." + module_name).__file__)
|
||||
get_doc_files(files, folder, force, sync_everything, verbose=verbose)
|
||||
get_doc_files(files, folder)
|
||||
|
||||
l = len(files)
|
||||
if l:
|
||||
|
|
@ -77,7 +77,7 @@ def sync_for(app_name, force=0, sync_everything = False, verbose=False, reset_pe
|
|||
# print each progress bar on new line
|
||||
print()
|
||||
|
||||
def get_doc_files(files, start_path, force=0, sync_everything = False, verbose=False):
|
||||
def get_doc_files(files, start_path):
|
||||
"""walk and sync all doctypes and pages"""
|
||||
|
||||
# load in sequence - warning for devs
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ frappe.patches.v9_1.resave_domain_settings
|
|||
frappe.patches.v9_1.revert_domain_settings
|
||||
frappe.patches.v9_1.move_feed_to_activity_log
|
||||
execute:frappe.delete_doc('Page', 'data-import-tool', ignore_missing=True)
|
||||
frappe.patches.v10_0.reload_countries_and_currencies # 14-10-2020
|
||||
frappe.patches.v10_0.reload_countries_and_currencies # 2021-02-03
|
||||
frappe.patches.v10_0.refactor_social_login_keys
|
||||
frappe.patches.v10_0.enable_chat_by_default_within_system_settings
|
||||
frappe.patches.v10_0.remove_custom_field_for_disabled_domain
|
||||
|
|
@ -329,4 +329,5 @@ frappe.core.doctype.page.patches.drop_unused_pages
|
|||
execute:frappe.get_doc('Role', 'Guest').save() # remove desk access
|
||||
frappe.patches.v13_0.rename_desk_page_to_workspace # 02.02.2021
|
||||
frappe.patches.v13_0.delete_package_publish_tool
|
||||
frappe.patches.v13_0.rename_list_view_setting_to_list_view_settings
|
||||
frappe.patches.v13_0.rename_custom_client_script
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# MIT License. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
if frappe.db.table_exists('List View Setting'):
|
||||
existing_list_view_settings = frappe.get_all('List View Settings', as_list=True)
|
||||
for list_view_setting in frappe.get_all('List View Setting', fields = ['disable_count', 'disable_sidebar_stats', 'disable_auto_refresh', 'name']):
|
||||
name = list_view_setting.pop('name')
|
||||
if name not in [x[0] for x in existing_list_view_settings]:
|
||||
list_view_setting['doctype'] = 'List View Settings'
|
||||
list_view_settings = frappe.get_doc(list_view_setting)
|
||||
# setting name here is necessary because autoname is set as prompt
|
||||
list_view_settings.name = name
|
||||
list_view_settings.insert()
|
||||
frappe.delete_doc("DocType", "List View Setting", force=True)
|
||||
frappe.db.commit()
|
||||
|
|
@ -5,6 +5,7 @@ from __future__ import unicode_literals
|
|||
import frappe
|
||||
from frappe.utils import is_image
|
||||
from frappe.model.document import Document
|
||||
from frappe import _
|
||||
|
||||
class LetterHead(Document):
|
||||
def before_insert(self):
|
||||
|
|
@ -13,14 +14,20 @@ class LetterHead(Document):
|
|||
|
||||
def validate(self):
|
||||
self.set_image()
|
||||
if not self.is_default:
|
||||
if not frappe.db.sql("""select count(*) from `tabLetter Head` where ifnull(is_default,0)=1"""):
|
||||
self.validate_disabled_and_default()
|
||||
|
||||
def validate_disabled_and_default(self):
|
||||
if self.disabled and self.is_default:
|
||||
frappe.throw(_("Letter Head cannot be both disabled and default"))
|
||||
|
||||
if not self.is_default and not self.disabled:
|
||||
if not frappe.db.exists('Letter Head', dict(is_default=1)):
|
||||
self.is_default = 1
|
||||
|
||||
def set_image(self):
|
||||
if self.source=='Image':
|
||||
if self.image and is_image(self.image):
|
||||
self.content = '<img src="{}" style="width: 100%;">'.format(self.image)
|
||||
self.content = '<img src="{}">'.format(self.image)
|
||||
frappe.msgprint(frappe._('Header HTML set from attachment {0}').format(self.image), alert = True)
|
||||
else:
|
||||
frappe.msgprint(frappe._('Please attach an image file to set HTML'), alert = True, indicator = 'orange')
|
||||
|
|
|
|||
|
|
@ -412,6 +412,12 @@ frappe.ui.form.PrintView = class {
|
|||
<link href="${frappe.urllib.get_base_url()}/assets/css/printview.css" rel="stylesheet">`
|
||||
);
|
||||
|
||||
if (frappe.utils.is_rtl(this.lang_code)) {
|
||||
this.$print_format_body.find('head').append(
|
||||
`<link type="text/css" rel="stylesheet" href="${frappe.urllib.get_base_url()}/assets/css/frappe-rtl.css"></link>`
|
||||
);
|
||||
}
|
||||
|
||||
this.$print_format_body.find('body').html(
|
||||
`<div class="print-format print-format-preview">${out.html}</div>`
|
||||
);
|
||||
|
|
|
|||
|
|
@ -27,8 +27,6 @@
|
|||
"public/js/frappe/microtemplate.js",
|
||||
"public/js/frappe/query_string.js",
|
||||
|
||||
"public/js/frappe/ui/dropzone.js",
|
||||
"public/js/frappe/ui/upload.html",
|
||||
"public/js/frappe/upload.js",
|
||||
|
||||
"public/js/frappe/model/meta.js",
|
||||
|
|
@ -36,7 +34,6 @@
|
|||
"public/js/frappe/model/perm.js",
|
||||
|
||||
"website/js/website.js",
|
||||
"public/js/frappe/utils/rating_icons.html",
|
||||
"public/js/frappe/socketio_client.js"
|
||||
],
|
||||
"js/bootstrap-4-web.min.js": "website/js/bootstrap-4.js",
|
||||
|
|
@ -62,7 +59,6 @@
|
|||
],
|
||||
"js/dialog.min.js": [
|
||||
"public/js/frappe/dom.js",
|
||||
|
||||
"public/js/frappe/form/formatters.js",
|
||||
"public/js/frappe/form/layout.js",
|
||||
"public/js/frappe/ui/field_group.js",
|
||||
|
|
@ -79,8 +75,6 @@
|
|||
"public/css/octicons/octicons.css",
|
||||
"public/less/desk.less",
|
||||
"public/less/module.less",
|
||||
"public/less/link_preview.less",
|
||||
"public/less/form.less",
|
||||
"public/less/mobile.less",
|
||||
"public/less/controls.less",
|
||||
"public/less/chat.less",
|
||||
|
|
@ -99,22 +93,21 @@
|
|||
"public/scss/print.scss"
|
||||
],
|
||||
"concat:js/libs.min.js": [
|
||||
"public/js/lib/awesomplete/awesomplete.min.js",
|
||||
"public/js/lib/Sortable.min.js",
|
||||
"public/js/lib/jquery/jquery.hotkeys.js",
|
||||
"node_modules/bootstrap/dist/js/bootstrap.bundle.min.js",
|
||||
"node_modules/vue/dist/vue.min.js",
|
||||
"node_modules/moment/min/moment-with-locales.min.js",
|
||||
"node_modules/moment-timezone/builds/moment-timezone-with-data.min.js",
|
||||
"public/js/lib/socket.io.min.js",
|
||||
"node_modules/socket.io-client/dist/socket.io.slim.js",
|
||||
"public/js/lib/jSignature.min.js",
|
||||
"public/js/frappe/translate.js",
|
||||
"public/js/lib/leaflet/leaflet.js",
|
||||
"public/js/lib/leaflet/leaflet.draw.js",
|
||||
"public/js/lib/leaflet/L.Control.Locate.js",
|
||||
"public/js/lib/leaflet/easy-button.js"
|
||||
],
|
||||
"js/desk.min.js": [
|
||||
"public/js/frappe/translate.js",
|
||||
"public/js/frappe/class.js",
|
||||
"public/js/frappe/polyfill.js",
|
||||
"public/js/frappe/provide.js",
|
||||
|
|
@ -152,7 +145,6 @@
|
|||
"public/js/frappe/ui/dialog.js",
|
||||
"public/js/frappe/ui/capture.js",
|
||||
"public/js/frappe/ui/app_icon.js",
|
||||
"public/js/frappe/ui/dropzone.js",
|
||||
"public/js/frappe/ui/theme_switcher.js",
|
||||
|
||||
"public/js/frappe/model/model.js",
|
||||
|
|
@ -179,7 +171,6 @@
|
|||
"public/js/frappe/utils/preview_email.js",
|
||||
"public/js/frappe/utils/file_manager.js",
|
||||
|
||||
"public/js/frappe/ui/upload.html",
|
||||
"public/js/frappe/upload.js",
|
||||
"public/js/frappe/ui/tree.js",
|
||||
|
||||
|
|
@ -194,7 +185,6 @@
|
|||
"public/js/frappe/ui/toolbar/search.js",
|
||||
"public/js/frappe/ui/toolbar/tag_utils.js",
|
||||
"public/js/frappe/ui/toolbar/search.html",
|
||||
"public/js/frappe/ui/toolbar/search_header.html",
|
||||
"public/js/frappe/ui/toolbar/search_utils.js",
|
||||
"public/js/frappe/ui/toolbar/about.js",
|
||||
"public/js/frappe/ui/toolbar/navbar.html",
|
||||
|
|
@ -210,11 +200,11 @@
|
|||
"public/js/frappe/ui/sort_selector.js",
|
||||
|
||||
"public/js/frappe/change_log.html",
|
||||
"public/js/frappe/ui/workspace_loading_skeleton.html",
|
||||
"public/js/frappe/desk.js",
|
||||
"public/js/frappe/query_string.js",
|
||||
|
||||
"public/js/frappe/ui/comment.js",
|
||||
"public/js/frappe/utils/rating_icons.html",
|
||||
|
||||
"public/js/frappe/chat.js",
|
||||
"public/js/frappe/utils/energy_point_utils.js",
|
||||
|
|
@ -232,7 +222,6 @@
|
|||
"public/js/frappe/form/form.js",
|
||||
"public/js/frappe/meta_tag.js"
|
||||
],
|
||||
"css/list.min.css": "public/less/gantt.less",
|
||||
"js/list.min.js": [
|
||||
"public/js/frappe/ui/listing.html",
|
||||
|
||||
|
|
@ -299,11 +288,12 @@
|
|||
"css/web_form.css": [
|
||||
"website/css/web_form.css",
|
||||
"public/css/octicons/octicons.css",
|
||||
"public/less/controls.less",
|
||||
"public/scss/controls.scss",
|
||||
"node_modules/frappe-datatable/dist/frappe-datatable.css"
|
||||
],
|
||||
"css/email.css": "public/scss/email.scss",
|
||||
"js/barcode_scanner.min.js": "public/js/frappe/barcode_scanner/quagga.js",
|
||||
"js/user_profile_controller.min.js": "desk/page/user_profile/user_profile_controller.js",
|
||||
"css/login.css": "public/scss/login.scss"
|
||||
"css/login.css": "public/scss/login.scss",
|
||||
"js/data_import_tools.min.js": "public/js/frappe/data_import/index.js"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,253 +0,0 @@
|
|||
/* the element that this class is applied to, should have a max width for this to work*/
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
a {
|
||||
cursor: pointer;
|
||||
}
|
||||
a,
|
||||
a:hover,
|
||||
a:active,
|
||||
a:focus,
|
||||
.btn,
|
||||
.btn:hover,
|
||||
.btn:active,
|
||||
.btn:focus {
|
||||
outline: 0;
|
||||
}
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
p {
|
||||
margin: 10px 0px;
|
||||
}
|
||||
.text-color {
|
||||
color: #36414C !important;
|
||||
}
|
||||
.text-muted {
|
||||
color: #8D99A6 !important;
|
||||
}
|
||||
.text-extra-muted {
|
||||
color: #d1d8dd !important;
|
||||
}
|
||||
a,
|
||||
.badge {
|
||||
-webkit-transition: 0.2s;
|
||||
-o-transition: 0.2s;
|
||||
transition: 0.2s;
|
||||
}
|
||||
.btn {
|
||||
-webkit-transition: background-color 0.2s;
|
||||
-o-transition: background-color 0.2s;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
a.disabled,
|
||||
a.disabled:hover {
|
||||
color: #888;
|
||||
cursor: default;
|
||||
text-decoration: none;
|
||||
}
|
||||
a.grey,
|
||||
.sidebar-section a,
|
||||
.control-value a,
|
||||
.data-row a {
|
||||
text-decoration: none;
|
||||
}
|
||||
a.grey:hover,
|
||||
.sidebar-section a:hover,
|
||||
.control-value a:hover,
|
||||
.data-row a:hover,
|
||||
a.grey:focus,
|
||||
.sidebar-section a:focus,
|
||||
.control-value a:focus,
|
||||
.data-row a:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
a.text-muted,
|
||||
a.text-extra-muted {
|
||||
text-decoration: none;
|
||||
}
|
||||
.underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.inline-block {
|
||||
display: inline-block;
|
||||
}
|
||||
.bold,
|
||||
.strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
kbd {
|
||||
color: inherit;
|
||||
background-color: #F0F4F7;
|
||||
}
|
||||
.btn [class^="fa fa-"],
|
||||
.nav [class^="fa fa-"],
|
||||
.btn [class*="fa fa-"],
|
||||
.nav [class*="fa fa-"] {
|
||||
display: inline-block;
|
||||
}
|
||||
.dropdown-menu > li > a {
|
||||
padding: 14px;
|
||||
white-space: normal;
|
||||
}
|
||||
.dropdown-menu {
|
||||
min-width: 200px;
|
||||
padding: 0px;
|
||||
font-size: 12px;
|
||||
max-height: 400px;
|
||||
overflow: auto;
|
||||
border-radius: 0px 0px 4px 4px;
|
||||
}
|
||||
.dropdown-menu .dropdown-header {
|
||||
padding: 3px 14px;
|
||||
font-size: 11px;
|
||||
font-weight: 200;
|
||||
padding-top: 12px;
|
||||
}
|
||||
.dropdown-menu .divider {
|
||||
margin: 0px;
|
||||
}
|
||||
a.badge-hover:hover .badge,
|
||||
a.badge-hover:focus .badge,
|
||||
a.badge-hover:active .badge {
|
||||
background-color: #D8DFE5;
|
||||
}
|
||||
.msgprint {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.msgprint pre {
|
||||
text-align: left;
|
||||
}
|
||||
.centered {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
-webkit-transform: translate(-50%, -50%);
|
||||
}
|
||||
.border-top {
|
||||
border-top: 1px solid #d1d8dd;
|
||||
}
|
||||
.border-bottom {
|
||||
border-bottom: 1px solid #d1d8dd;
|
||||
}
|
||||
.border-left {
|
||||
border-left: 1px solid #d1d8dd;
|
||||
}
|
||||
.border-right {
|
||||
border-right: 1px solid #d1d8dd;
|
||||
}
|
||||
.border {
|
||||
border: 1px solid #d1d8dd;
|
||||
}
|
||||
.close-inline {
|
||||
font-size: 120%;
|
||||
font-weight: bold;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
color: inherit;
|
||||
display: inline-block;
|
||||
}
|
||||
.close-inline:hover,
|
||||
.close-inline:focus {
|
||||
text-decoration: none;
|
||||
}
|
||||
.middle {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.full-center-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
.full-center {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 100%;
|
||||
transform: translate(-50%, -50%);
|
||||
-webkit-transform: translate(-50%, -50%);
|
||||
}
|
||||
#freeze {
|
||||
z-index: 1020;
|
||||
bottom: 0px;
|
||||
opacity: 0;
|
||||
background-color: #fafbfc;
|
||||
}
|
||||
#freeze .freeze-message-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
#freeze .freeze-message {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 100%;
|
||||
transform: translate(-50%, -50%);
|
||||
-webkit-transform: translate(-50%, -50%);
|
||||
text-align: center;
|
||||
color: #36414C !important;
|
||||
}
|
||||
#freeze.dark {
|
||||
background-color: #334143;
|
||||
}
|
||||
#freeze.in {
|
||||
opacity: 0.5;
|
||||
}
|
||||
a.no-decoration {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
a.no-decoration:hover,
|
||||
a.no-decoration:focus,
|
||||
a.no-decoration:active {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
.padding {
|
||||
padding: 15px;
|
||||
}
|
||||
.margin {
|
||||
margin: 15px;
|
||||
}
|
||||
.margin-top {
|
||||
margin-top: 15px;
|
||||
}
|
||||
.margin-bottom {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.margin-left {
|
||||
margin-left: 15px;
|
||||
}
|
||||
.margin-right {
|
||||
margin-right: 15px;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.text-center-xs {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
.grayscale {
|
||||
-webkit-filter: grayscale(100%);
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
.uppercase {
|
||||
padding-bottom: 4px;
|
||||
text-transform: uppercase;
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.4px;
|
||||
color: #8D99A6;
|
||||
}
|
||||
.ellipsis {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 100%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
|
@ -1,604 +0,0 @@
|
|||
/* the element that this class is applied to, should have a max width for this to work*/
|
||||
.navbar .dropdown-toggle {
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
.navbar-fixed-top {
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
}
|
||||
.navbar a {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.navbar-icon-home {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.navbar-icon-home:hover,
|
||||
.navbar-icon-home:focus,
|
||||
.navbar-icon-home:active,
|
||||
.navbar-icon-home-hover {
|
||||
opacity: 1;
|
||||
Filter: alpha(opacity=100);
|
||||
/* For IE8 and earlier */
|
||||
}
|
||||
.navbar-user-image {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 3px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
@media (max-width: 991px) {
|
||||
.navbar-desk {
|
||||
width: 35% !important;
|
||||
}
|
||||
.navbar-desk ~ ul > li {
|
||||
float: left;
|
||||
}
|
||||
.navbar-desk ~ ul > li a {
|
||||
padding-left: 10px !important;
|
||||
padding-right: 10px !important;
|
||||
}
|
||||
.navbar-desk ~ ul > li a .avatar {
|
||||
margin-right: 0;
|
||||
}
|
||||
.dropdown-navbar-new-comments > a {
|
||||
padding: 8px 0 !important;
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.navbar-desk {
|
||||
width: 50% !important;
|
||||
}
|
||||
}
|
||||
#search-modal .modal-dialog,
|
||||
#search-modal .modal-content {
|
||||
background: transparent;
|
||||
}
|
||||
#search-modal .modal-header {
|
||||
background: #fff;
|
||||
width: 100%;
|
||||
}
|
||||
#search-modal .modal-header form {
|
||||
vertical-align: middle;
|
||||
}
|
||||
#search-modal .modal-header button {
|
||||
line-height: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: 9;
|
||||
padding: 9px;
|
||||
}
|
||||
.dropdown-navbar-new-comments > a {
|
||||
border: 0;
|
||||
}
|
||||
.dropdown-navbar-new-comments .dropdown-menu {
|
||||
margin-top: 0;
|
||||
}
|
||||
.dropdown-help .dropdown-menu {
|
||||
width: 350px !important;
|
||||
max-height: 440px;
|
||||
overflow: auto;
|
||||
}
|
||||
.dropdown-help .dropdown-menu .input-group {
|
||||
width: 100%;
|
||||
background-color: #f5f7fa;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
.dropdown-help .dropdown-menu input {
|
||||
width: 100%;
|
||||
padding: 5px 10px;
|
||||
outline: none;
|
||||
border-radius: 3px 0 0 3px;
|
||||
border: 1px solid #d1d8dd;
|
||||
opacity: 0.9;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.dropdown-help .dropdown-menu button {
|
||||
border: 1px solid #d1d8dd;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.dropdown-help .dropdown-menu {
|
||||
position: fixed !important;
|
||||
top: 40px;
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.dropdown-mobile.open .dropdown-menu {
|
||||
position: absolute;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.14902);
|
||||
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
|
||||
background-color: #fff;
|
||||
right: 0;
|
||||
left: auto;
|
||||
}
|
||||
.dropdown-mobile.open .dropdown-menu > li > a {
|
||||
padding: 12px;
|
||||
}
|
||||
.dropdown-help {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
.navbar-new-comments {
|
||||
display: inline-block;
|
||||
min-width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
padding: 2px 5px;
|
||||
background-color: #b8c2cc;
|
||||
}
|
||||
.navbar-new-comments-true {
|
||||
background-color: #ff5858;
|
||||
}
|
||||
.navbar-form .awesomplete {
|
||||
margin-left: -15px;
|
||||
width: 300px;
|
||||
}
|
||||
@media (max-width: 1199px) {
|
||||
.navbar-form .awesomplete {
|
||||
width: 280px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 991px) {
|
||||
.navbar-form .awesomplete {
|
||||
width: 250px;
|
||||
}
|
||||
}
|
||||
#navbar-search {
|
||||
width: 100%;
|
||||
background-color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
.navbar .navbar-search-icon {
|
||||
color: #6C7680;
|
||||
font-size: inherit;
|
||||
position: relative;
|
||||
right: 24px;
|
||||
top: 1px;
|
||||
}
|
||||
.navbar .badge {
|
||||
font-weight: normal;
|
||||
}
|
||||
#navbar-search-results {
|
||||
left: auto;
|
||||
right: inherit;
|
||||
margin-top: -1px;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.navbar-center {
|
||||
float: left;
|
||||
color: #6C7680;
|
||||
}
|
||||
#navbar-breadcrumbs > li > a:before {
|
||||
font-family: FontAwesome;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
text-decoration: inherit;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
*margin-right: 0.3em;
|
||||
display: inline-block;
|
||||
speak: none;
|
||||
font-size: 24px;
|
||||
transition: 0.2s;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
content: "\f105";
|
||||
margin-right: 10px;
|
||||
color: #C0C9D2;
|
||||
}
|
||||
#navbar-breadcrumbs > li > a:hover:before,
|
||||
#navbar-breadcrumbs > li > a:focus:before,
|
||||
#navbar-breadcrumbs > li > a:active:before {
|
||||
color: #36414C;
|
||||
}
|
||||
#navbar-breadcrumbs > li > a {
|
||||
padding: 6px 15px 10px 0px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 170px;
|
||||
}
|
||||
@media (min-width: 991px) and (max-width: 1199px) {
|
||||
#navbar-breadcrumbs > li > a {
|
||||
max-width: 120px;
|
||||
}
|
||||
}
|
||||
.toolbar-user-fullname {
|
||||
max-width: 150px;
|
||||
display: inline-block;
|
||||
}
|
||||
.navbar-brand > img {
|
||||
display: inline-block;
|
||||
}
|
||||
.toggle-sidebar {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.navbar-default .navbar-nav > li > a,
|
||||
.navbar-default .navbar-brand {
|
||||
color: #8D99A6;
|
||||
}
|
||||
body {
|
||||
font-size: 16px;
|
||||
line-height: 1.65em;
|
||||
color: #454e57;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
.container {
|
||||
max-width: 870px;
|
||||
}
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
.splash {
|
||||
border-bottom: 1px solid #d1d8dd;
|
||||
}
|
||||
.splash .jumbotron {
|
||||
background-color: transparent;
|
||||
padding: 40px 0 60px 0;
|
||||
text-align: center;
|
||||
}
|
||||
.splash .jumbotron h1 {
|
||||
font-size: 48px;
|
||||
font-weight: 400;
|
||||
opacity: 0.9;
|
||||
color: #2E3338;
|
||||
}
|
||||
.splash .jumbotron p {
|
||||
font-size: 24px;
|
||||
font-color: #8D99A6 !important;
|
||||
letter-spacing: 0px;
|
||||
opacity: 0.7;
|
||||
margin-bottom: 90px;
|
||||
font-weight: 300;
|
||||
line-height: 1.4em;
|
||||
}
|
||||
.splash .section {
|
||||
padding: 30px 0 0 0;
|
||||
}
|
||||
.page-container {
|
||||
padding-top: 38px;
|
||||
margin: 0 auto;
|
||||
max-width: 870px;
|
||||
}
|
||||
.page-container .webpage-content ol > li,
|
||||
.page-container .webpage-content ul > li {
|
||||
margin: 13px auto;
|
||||
}
|
||||
.page-container .webpage-content ol > li li,
|
||||
.page-container .webpage-content ul > li li {
|
||||
margin: 4px auto;
|
||||
}
|
||||
.page-container .webpage-content ol li ol {
|
||||
list-style-type: disc;
|
||||
}
|
||||
.page-container .webpage-content ul,
|
||||
.page-container .webpage-content ol {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.page-container .page-content {
|
||||
width: 83%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
#page-index {
|
||||
padding-top: 0;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
#page-index .page-content {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
body[data-path="index"] .navbar .toggle-sidebar i {
|
||||
color: #fff;
|
||||
}
|
||||
code {
|
||||
color: #e66a12;
|
||||
background: #fff6df;
|
||||
}
|
||||
pre {
|
||||
background: #fafbfc;
|
||||
border: 1px solid #e1e9f0;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.hljs {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 1.2em 1.5em 1.5em;
|
||||
color: #454e57;
|
||||
}
|
||||
.hljs-keyword,
|
||||
.hljs-tag,
|
||||
.css .hljs-class,
|
||||
.css .hljs-id,
|
||||
.lisp .hljs-title,
|
||||
.nginx .hljs-title,
|
||||
.hljs-request,
|
||||
.hljs-status,
|
||||
.clojure .hljs-attribute {
|
||||
color: #e66a12;
|
||||
}
|
||||
.diff .hljs-deletion,
|
||||
.hljs-string,
|
||||
.hljs-tag .hljs-value,
|
||||
.hljs-preprocessor,
|
||||
.hljs-pragma,
|
||||
.hljs-built_in,
|
||||
.hljs-javadoc,
|
||||
.smalltalk .hljs-class,
|
||||
.smalltalk .hljs-localvars,
|
||||
.smalltalk .hljs-array,
|
||||
.css .hljs-rules .hljs-value,
|
||||
.hljs-attr_selector,
|
||||
.hljs-pseudo,
|
||||
.apache .hljs-cbracket,
|
||||
.tex .hljs-formula,
|
||||
.coffeescript .hljs-attribute {
|
||||
color: #dd4a68;
|
||||
}
|
||||
.hljs-number,
|
||||
.hljs-date,
|
||||
.hljs-regexp,
|
||||
.hljs-literal,
|
||||
.hljs-hexcolor,
|
||||
.smalltalk .hljs-symbol,
|
||||
.smalltalk .hljs-char,
|
||||
.go .hljs-constant,
|
||||
.hljs-change,
|
||||
.lasso .hljs-variable,
|
||||
.makefile .hljs-variable,
|
||||
.asciidoc .hljs-bullet,
|
||||
.markdown .hljs-bullet,
|
||||
.asciidoc .hljs-link_url,
|
||||
.markdown .hljs-link_url {
|
||||
color: #7575ff;
|
||||
}
|
||||
.hljs-shebang,
|
||||
.diff .hljs-addition,
|
||||
.hljs-comment,
|
||||
.hljs-annotation,
|
||||
.hljs-template_comment,
|
||||
.hljs-pi,
|
||||
.hljs-doctype {
|
||||
color: #6a906a;
|
||||
}
|
||||
.dos .hljs-keyword,
|
||||
.hljs-decorator,
|
||||
.hljs-title,
|
||||
.hljs-type,
|
||||
.diff .hljs-header,
|
||||
.ruby .hljs-class .hljs-parent,
|
||||
.apache .hljs-tag,
|
||||
.nginx .hljs-built_in,
|
||||
.tex .hljs-command,
|
||||
.hljs-prompt {
|
||||
color: #4f4fa4;
|
||||
}
|
||||
.navbar {
|
||||
background-color: #36414C !important;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
.navbar .container {
|
||||
max-width: 870px;
|
||||
}
|
||||
.navbar .brand-logo {
|
||||
width: 30px;
|
||||
margin-top: -4px;
|
||||
margin-right: 7px;
|
||||
}
|
||||
.navbar a {
|
||||
font-size: 16px;
|
||||
font-weight: normal;
|
||||
color: #fff !important;
|
||||
}
|
||||
.navbar a.navbar-brand {
|
||||
font-weight: bold;
|
||||
}
|
||||
.navbar a.toggle-sidebar {
|
||||
margin-top: 8px;
|
||||
}
|
||||
.sidebar a {
|
||||
font-size: 14px;
|
||||
padding-top: 14px !important;
|
||||
padding-bottom: 14px !important;
|
||||
}
|
||||
.breadcrumb {
|
||||
line-height: 1em;
|
||||
color: #8D99A6;
|
||||
background-color: transparent;
|
||||
margin-bottom: 32px;
|
||||
padding: 0px;
|
||||
padding-left: 20px;
|
||||
background: url('/assets/img/up.png') 0% 30% no-repeat;
|
||||
}
|
||||
.breadcrumb .icon {
|
||||
display: none;
|
||||
}
|
||||
.breadcrumb a,
|
||||
.breadcrumb a:hover,
|
||||
.breadcrumb a:focus,
|
||||
.breadcrumb a:visited {
|
||||
color: #7575ff;
|
||||
font-size: 16px;
|
||||
}
|
||||
.hero-and-content a,
|
||||
.hero-and-content a:hover,
|
||||
.hero-and-content a:focus,
|
||||
.hero-and-content a:visited {
|
||||
color: #5E64FF;
|
||||
}
|
||||
.hero-and-content a.btn {
|
||||
color: inherit;
|
||||
}
|
||||
a.btn-primary {
|
||||
color: #7575ff;
|
||||
}
|
||||
a.btn-primary:hover,
|
||||
a.btn-primary:focus,
|
||||
a.btn-primary:visited {
|
||||
color: #7575ff;
|
||||
}
|
||||
.btn-next-wrapper {
|
||||
margin-top: 32px;
|
||||
text-align: right;
|
||||
}
|
||||
h2 {
|
||||
margin-top: 48px;
|
||||
font-size: 24px;
|
||||
}
|
||||
h3,
|
||||
h4 {
|
||||
margin-top: 48px;
|
||||
}
|
||||
p {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.hero-and-content > p {
|
||||
max-width: 723px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.navbar {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
padding: 15px 0px;
|
||||
border-radius: 0px;
|
||||
border-bottom: 1px solid #d1d8dd;
|
||||
}
|
||||
.section {
|
||||
padding: 64px 0 0 0;
|
||||
}
|
||||
.dev-header {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.docs-footer {
|
||||
padding: 30px 0px 60px 0px;
|
||||
border-top: 1px solid #d1d8dd;
|
||||
max-width: 870px;
|
||||
margin: 0 auto;
|
||||
margin-top: 80px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.docs-footer h3 {
|
||||
margin-top: 24px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.docs-footer img.frappe-bird {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: #fff;
|
||||
margin-bottom: 10px;
|
||||
padding: 5px;
|
||||
}
|
||||
.docs-footer a {
|
||||
color: #8D99A6;
|
||||
}
|
||||
.docs-footer li {
|
||||
display: inline-block;
|
||||
margin: 0 10px;
|
||||
}
|
||||
.docs-footer .built-with-frappe {
|
||||
margin-top: -50px;
|
||||
}
|
||||
.browser-image {
|
||||
min-height: 200px;
|
||||
border: 1px solid #d1d8dd;
|
||||
border-bottom: 0px;
|
||||
}
|
||||
.fake-browser-frame {
|
||||
position: relative;
|
||||
margin: 24px auto 0px;
|
||||
box-shadow: 0px -6px 100px 1px rgba(0, 0, 0, 0.1), 0px -6px 50px 1px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
.fake-browser-frame::before {
|
||||
content: "";
|
||||
height: 24px;
|
||||
position: absolute;
|
||||
top: -24px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
border: 1px solid #d1d8dd;
|
||||
background: #f5f7fa;
|
||||
border-bottom: none;
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
.fake-browser-frame::after {
|
||||
content: '\f111 \00a0\00a0 \f111 \00a0\00a0 \f111';
|
||||
position: absolute;
|
||||
color: #d1d8dd;
|
||||
top: -15px;
|
||||
left: 8px;
|
||||
/* octicon */
|
||||
font: normal normal;
|
||||
font-size: 8px;
|
||||
font-family: 'FontAwesome';
|
||||
line-height: 1;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.fake-iphone-frame {
|
||||
position: relative;
|
||||
padding: 40px 8px;
|
||||
border: 1px solid #d1d8dd;
|
||||
border-radius: 15px;
|
||||
}
|
||||
.fake-ipad-frame {
|
||||
position: relative;
|
||||
padding: 8px 40px;
|
||||
border: 1px solid #d1d8dd;
|
||||
border-radius: 15px;
|
||||
}
|
||||
hr {
|
||||
margin: 48px 0px 30px;
|
||||
}
|
||||
.edit {
|
||||
color: #8d99a6;
|
||||
}
|
||||
a.edit,
|
||||
a.edit:hover,
|
||||
a.edit:focus,
|
||||
a.edit:visited,
|
||||
.edit-container .icon {
|
||||
color: #8d99a6;
|
||||
}
|
||||
.btn-next {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
.btn-next:after {
|
||||
content: " \2192";
|
||||
}
|
||||
#current td {
|
||||
font-weight: bold;
|
||||
}
|
||||
#current td code {
|
||||
font-weight: normal;
|
||||
background: transparent;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, "Open Sans", sans-serif;
|
||||
color: #454e57;
|
||||
font-size: 16px;
|
||||
}
|
||||
.hero-and-content [data-html-block="hero"] {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
.page-content-wrapper > .row .col-sm-8 {
|
||||
width: 100%;
|
||||
}
|
||||
.page-content-wrapper > .row .col-sm-4 {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-display: swap;
|
||||
font-style: normal;
|
||||
font-weight: 100;
|
||||
src: url("/assets/frappe/css/fonts/inter/inter_thin.woff2") format("woff2"),
|
||||
|
|
@ -7,6 +8,7 @@
|
|||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-display: swap;
|
||||
font-style: italic;
|
||||
font-weight: 100;
|
||||
src: url("/assets/frappe/css/fonts/inter/inter_thinitalic.woff2") format("woff2"),
|
||||
|
|
@ -15,6 +17,7 @@
|
|||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-display: swap;
|
||||
font-style: normal;
|
||||
font-weight: 200;
|
||||
src: url("/assets/frappe/css/fonts/inter/inter_extralight.woff2") format("woff2"),
|
||||
|
|
@ -22,6 +25,7 @@
|
|||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-display: swap;
|
||||
font-style: italic;
|
||||
font-weight: 200;
|
||||
src: url("/assets/frappe/css/fonts/inter/inter_extralightitalic.woff2") format("woff2"),
|
||||
|
|
@ -30,6 +34,7 @@
|
|||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-display: swap;
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: url("/assets/frappe/css/fonts/inter/inter_light.woff2") format("woff2"),
|
||||
|
|
@ -37,6 +42,7 @@
|
|||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-display: swap;
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
src: url("/assets/frappe/css/fonts/inter/inter_lightitalic.woff2") format("woff2"),
|
||||
|
|
@ -45,6 +51,7 @@
|
|||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-display: swap;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url("/assets/frappe/css/fonts/inter/inter_regular.woff2") format("woff2"),
|
||||
|
|
@ -52,6 +59,7 @@
|
|||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-display: swap;
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
src: url("/assets/frappe/css/fonts/inter/inter_italic.woff2") format("woff2"),
|
||||
|
|
@ -60,6 +68,7 @@
|
|||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-display: swap;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
src: url("/assets/frappe/css/fonts/inter/inter_medium.woff2") format("woff2"),
|
||||
|
|
@ -67,6 +76,7 @@
|
|||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-display: swap;
|
||||
font-style: italic;
|
||||
font-weight: 500;
|
||||
src: url("/assets/frappe/css/fonts/inter/inter_mediumitalic.woff2") format("woff2"),
|
||||
|
|
@ -75,6 +85,7 @@
|
|||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-display: swap;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: url("/assets/frappe/css/fonts/inter/inter_semibold.woff2") format("woff2"),
|
||||
|
|
@ -82,6 +93,7 @@
|
|||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-display: swap;
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
src: url("/assets/frappe/css/fonts/inter/inter_semibolditalic.woff2") format("woff2"),
|
||||
|
|
@ -90,6 +102,7 @@
|
|||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-display: swap;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: url("/assets/frappe/css/fonts/inter/inter_bold.woff2") format("woff2"),
|
||||
|
|
@ -97,6 +110,7 @@
|
|||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-display: swap;
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
src: url("/assets/frappe/css/fonts/inter/inter_bolditalic.woff2") format("woff2"),
|
||||
|
|
@ -105,6 +119,7 @@
|
|||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-display: swap;
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
src: url("/assets/frappe/css/fonts/inter/inter_extrabold.woff2") format("woff2"),
|
||||
|
|
@ -112,6 +127,7 @@
|
|||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-display: swap;
|
||||
font-style: italic;
|
||||
font-weight: 800;
|
||||
src: url("/assets/frappe/css/fonts/inter/inter_extrabolditalic.woff2") format("woff2"),
|
||||
|
|
@ -120,6 +136,7 @@
|
|||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-display: swap;
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
src: url("/assets/frappe/css/fonts/inter/inter_black.woff2") format("woff2"),
|
||||
|
|
@ -127,8 +144,9 @@
|
|||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-display: swap;
|
||||
font-style: italic;
|
||||
font-weight: 900;
|
||||
src: url("/assets/frappe/css/fonts/inter/inter_blackitalic.woff2") format("woff2"),
|
||||
url("/assets/frappe/css/fonts/inter/inter_blackitalic.woff") format("woff");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,729 +0,0 @@
|
|||
.form-print-wrapper {
|
||||
border: 1px solid #d1d8dd;
|
||||
border-top: none;
|
||||
}
|
||||
.print-preview-wrapper {
|
||||
padding: 30px 0px;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
.print-toolbar {
|
||||
margin: 0px;
|
||||
padding: 10px 0px;
|
||||
border-bottom: 1px solid #d1d8dd;
|
||||
}
|
||||
.print-toolbar > div {
|
||||
padding-right: 0px;
|
||||
}
|
||||
.print-toolbar > div:last-child {
|
||||
padding-right: 15px;
|
||||
}
|
||||
.form-inner-toolbar {
|
||||
padding: 10px 15px 0px;
|
||||
background-color: #fafbfc;
|
||||
text-align: right;
|
||||
}
|
||||
.form-inner-toolbar .btn {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.form-clickable-section {
|
||||
border-top: 1px solid #d1d8dd;
|
||||
padding: 10px 15px;
|
||||
background-color: #F7FAFC;
|
||||
}
|
||||
.form-page.second-page {
|
||||
border-top: 1px solid #d1d8dd;
|
||||
}
|
||||
.form-message {
|
||||
padding: 15px 30px;
|
||||
border-bottom: 1px solid #d1d8dd;
|
||||
}
|
||||
.document-flow-wrapper {
|
||||
padding: 40px 15px 30px;
|
||||
font-size: 12px;
|
||||
border-bottom: 1px solid #EBEFF2;
|
||||
}
|
||||
.document-flow-wrapper .document-flow {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
.document-flow-wrapper .document-flow .document-flow-link-wrapper {
|
||||
width: 140px;
|
||||
display: inline-block;
|
||||
}
|
||||
.document-flow-wrapper .document-flow .document-flow-link-wrapper:not(:last-child) {
|
||||
border-top: 1px solid #b8c2cc;
|
||||
margin-right: -4px;
|
||||
}
|
||||
.document-flow-wrapper .document-flow .document-flow-link-wrapper:last-child {
|
||||
margin-right: -140px;
|
||||
}
|
||||
.document-flow-wrapper .document-flow .document-flow-link {
|
||||
margin-top: -10px;
|
||||
display: inline-block;
|
||||
}
|
||||
.document-flow-wrapper .document-flow .document-flow-link:not(.disabled):hover .document-flow-link-label,
|
||||
.document-flow-wrapper .document-flow .document-flow-link:not(.disabled):focus .document-flow-link-label,
|
||||
.document-flow-wrapper .document-flow .document-flow-link:not(.disabled):active .document-flow-link-label {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.document-flow-wrapper .document-flow .document-flow-link-label {
|
||||
display: inline-block;
|
||||
margin-left: -50%;
|
||||
margin-top: 5px;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.document-flow-wrapper {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.form-dashboard {
|
||||
background-color: #fafbfc;
|
||||
}
|
||||
.form-dashboard-wrapper {
|
||||
margin: -15px 0px;
|
||||
}
|
||||
.form-documents h6 {
|
||||
margin-top: 15px;
|
||||
}
|
||||
.form-dashboard-section {
|
||||
margin: 0px -15px;
|
||||
padding: 15px 30px;
|
||||
border-bottom: 1px solid #EBEFF2;
|
||||
}
|
||||
.form-dashboard-section:first-child {
|
||||
padding-top: 0px;
|
||||
}
|
||||
.form-dashboard-section:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.form-heatmap .heatmap {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.form-heatmap .heatmap-message {
|
||||
margin-top: 10px;
|
||||
}
|
||||
@media (max-width: 991px) {
|
||||
.form-heatmap {
|
||||
overflow: hidden;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
}
|
||||
.inline-graph .inline-graph-half {
|
||||
width: 48%;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
height: 30px;
|
||||
}
|
||||
.inline-graph .inline-graph-half .inline-graph-count {
|
||||
font-size: 10px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 3px;
|
||||
padding: 0px 5px;
|
||||
text-align: left;
|
||||
}
|
||||
.inline-graph .inline-graph-half .inline-graph-bar {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 20px;
|
||||
}
|
||||
.inline-graph .inline-graph-half .inline-graph-bar-inner {
|
||||
display: block;
|
||||
float: left;
|
||||
background-color: #d1d8dd;
|
||||
height: 6px;
|
||||
border-radius: 0px 3px 3px 0px;
|
||||
}
|
||||
.inline-graph .inline-graph-half .inline-graph-bar-inner.dark {
|
||||
background-color: #36414C;
|
||||
}
|
||||
.inline-graph .inline-graph-half:first-child {
|
||||
border-right: 1px solid #d1d8dd;
|
||||
margin-right: -3px;
|
||||
}
|
||||
.inline-graph .inline-graph-half:first-child .inline-graph-count {
|
||||
text-align: right;
|
||||
}
|
||||
.inline-graph .inline-graph-half:first-child .inline-graph-bar-inner {
|
||||
float: right;
|
||||
border-radius: 3px 0px 0px 3px;
|
||||
}
|
||||
.progress-area {
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
.form-links .document-link {
|
||||
margin-bottom: 10px;
|
||||
height: 22px;
|
||||
}
|
||||
.form-links .document-link:hover .badge-link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.form-links .document-link:hover .badge-link[disabled='disabled'] {
|
||||
text-decoration: none;
|
||||
}
|
||||
.form-links .count {
|
||||
display: inline-block;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
h6.uppercase,
|
||||
.h6.uppercase {
|
||||
font-size: 11px;
|
||||
font-weight: normal;
|
||||
letter-spacing: 0.4px;
|
||||
text-transform: uppercase;
|
||||
color: #8D99A6;
|
||||
}
|
||||
.form-section {
|
||||
margin: 0px;
|
||||
padding: 15px;
|
||||
}
|
||||
.form-section .form-section-description {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.form-section .form-section-heading {
|
||||
margin: 10px 0px;
|
||||
}
|
||||
.form-section .section-head {
|
||||
margin: 0px 0px 15px 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.form-section .section-head .collapse-indicator {
|
||||
color: #d1d8dd;
|
||||
margin-left: 10px;
|
||||
position: relative;
|
||||
bottom: -1px;
|
||||
}
|
||||
.form-section .section-head .collapse-indicator.octicon-chevron-up {
|
||||
bottom: -2px;
|
||||
}
|
||||
.form-section .section-head.collapsed {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
.form-section:not(:last-child),
|
||||
.form-inner-toolbar {
|
||||
border-bottom: 1px solid #d1d8dd;
|
||||
}
|
||||
.empty-section {
|
||||
display: none !important;
|
||||
}
|
||||
.modal .form-layout {
|
||||
margin: -15px;
|
||||
}
|
||||
.modal .form-grid .form-layout {
|
||||
margin: 0px;
|
||||
}
|
||||
.modal .form-section {
|
||||
padding: 15px 7px;
|
||||
}
|
||||
.help ol {
|
||||
padding-left: 19px;
|
||||
}
|
||||
.field_description_top {
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
.user-actions {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.user-actions a {
|
||||
font-weight: bold;
|
||||
}
|
||||
.badge-important {
|
||||
background-color: #e74c3c;
|
||||
}
|
||||
.address-box {
|
||||
background-color: #fafbfc;
|
||||
padding: 0px 15px;
|
||||
margin: 15px 0px;
|
||||
border: 1px solid #d1d8dd;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.timeline {
|
||||
margin: 30px 0px;
|
||||
}
|
||||
.timeline .timeline-head .comment-input {
|
||||
height: auto;
|
||||
}
|
||||
.timeline-item {
|
||||
margin-top: 0px;
|
||||
}
|
||||
.timeline-item b {
|
||||
color: #36414C !important;
|
||||
}
|
||||
.timeline-item blockquote {
|
||||
font-size: inherit;
|
||||
}
|
||||
.timeline-item .btn-more {
|
||||
margin-left: 65px;
|
||||
}
|
||||
.timeline-item .gmail_extra {
|
||||
display: none;
|
||||
}
|
||||
.timeline-items {
|
||||
position: relative;
|
||||
}
|
||||
.timeline {
|
||||
position: relative;
|
||||
}
|
||||
.timeline::before {
|
||||
content: " ";
|
||||
border-left: 1px solid #d1d8dd;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
bottom: -124px;
|
||||
left: 43px;
|
||||
z-index: 0;
|
||||
}
|
||||
.timeline.in-dialog::before {
|
||||
bottom: 0px;
|
||||
}
|
||||
@media (max-width: 991px) {
|
||||
.timeline::before {
|
||||
bottom: -64px;
|
||||
}
|
||||
}
|
||||
.timeline-item.user-content {
|
||||
margin: 30px 0px 30px 27px;
|
||||
}
|
||||
.timeline-item.user-content .media-body {
|
||||
border: 1px solid #d1d8dd;
|
||||
border-radius: 3px;
|
||||
margin-left: -7px;
|
||||
position: relative;
|
||||
max-width: calc(100% - 50px);
|
||||
padding-right: 0px;
|
||||
overflow: visible;
|
||||
}
|
||||
.timeline-item.user-content .avatar-medium {
|
||||
margin-right: 10px;
|
||||
height: 45px;
|
||||
width: 45px;
|
||||
}
|
||||
.timeline-item.user-content .action-btns {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
padding: 8px 15px 0 5px;
|
||||
}
|
||||
.timeline-item.user-content .action-btns .edit-btn-container {
|
||||
margin-right: 13px;
|
||||
}
|
||||
.timeline-item.user-content .comment-header {
|
||||
background-color: #fafbfc;
|
||||
padding: 10px 15px 8px 13px;
|
||||
margin: 0px;
|
||||
color: #8D99A6;
|
||||
border-bottom: 1px solid #EBEFF2;
|
||||
}
|
||||
.timeline-item.user-content .comment-header.links-active {
|
||||
padding-right: 77px;
|
||||
}
|
||||
.timeline-item.user-content .comment-header .asset-details {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
.timeline-item.user-content .comment-header .asset-details .btn-link {
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.timeline-item.user-content .comment-header .asset-details .btn-link:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
.timeline-item.user-content .comment-header .commented-on-small {
|
||||
display: none;
|
||||
}
|
||||
.timeline-item.user-content .comment-header .octicon-heart {
|
||||
color: #ff5858;
|
||||
cursor: pointer;
|
||||
}
|
||||
.timeline-item.user-content .reply {
|
||||
padding: 15px;
|
||||
overflow: auto;
|
||||
}
|
||||
.timeline-item.user-content .reply > div > p:first-child {
|
||||
margin-top: 0px;
|
||||
}
|
||||
.timeline-item.user-content .reply > div > p:last-child {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
.timeline-item.user-content .reply hr {
|
||||
margin: 10px 0px;
|
||||
}
|
||||
.timeline-item.user-content .close-btn-container .close {
|
||||
color: inherit;
|
||||
opacity: 1;
|
||||
padding: 0;
|
||||
font-size: 18px;
|
||||
}
|
||||
.timeline-item.user-content .edit-btn-container {
|
||||
padding: 0;
|
||||
}
|
||||
.timeline-item.user-content .edit-btn-container .edit {
|
||||
color: inherit;
|
||||
font-size: 21px;
|
||||
line-height: 1;
|
||||
}
|
||||
.timeline-item.user-content .edit-btn-container .edit .octicon-check {
|
||||
font-size: 1em;
|
||||
}
|
||||
.timeline-item.user-content .edit-btn-container .edit:hover,
|
||||
.timeline-item.user-content .edit-btn-container .edit:focus {
|
||||
color: #000;
|
||||
}
|
||||
.timeline-item.user-content .comment-likes {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.timeline-item.user-content .media-body:after,
|
||||
.timeline-item.user-content .media-body:before {
|
||||
right: 100%;
|
||||
top: 15px;
|
||||
border: solid transparent;
|
||||
content: " ";
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
}
|
||||
.timeline-item.user-content .media-body:after {
|
||||
border-color: rgba(136, 183, 213, 0);
|
||||
border-right-color: #fafbfc;
|
||||
border-width: 6px;
|
||||
margin-top: -6px;
|
||||
}
|
||||
.timeline-item.user-content .media-body:before {
|
||||
border-color: rgba(194, 225, 245, 0);
|
||||
border-right-color: #d1d8dd;
|
||||
border-width: 7px;
|
||||
margin-top: -7px;
|
||||
}
|
||||
.timeline-item.notification-content {
|
||||
padding-left: 30px;
|
||||
margin: 30px 0px;
|
||||
position: relative;
|
||||
color: #8D99A6;
|
||||
}
|
||||
.timeline-item.notification-content * {
|
||||
color: #8D99A6;
|
||||
}
|
||||
.timeline-item.notification-content .fa-fw {
|
||||
margin-left: 36px;
|
||||
}
|
||||
.timeline-item.notification-content div.small {
|
||||
padding-left: 40px;
|
||||
}
|
||||
.timeline-item.notification-content div.small .fa-fw {
|
||||
margin-left: 0px;
|
||||
}
|
||||
.timeline-item.notification-content .octicon-heart {
|
||||
color: #ff5858 !important;
|
||||
}
|
||||
.timeline-item.notification-content::before {
|
||||
content: " ";
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
background-color: #d1d8dd;
|
||||
position: absolute;
|
||||
left: 40px;
|
||||
border-radius: 50%;
|
||||
top: 5px;
|
||||
}
|
||||
.timeline-item .reply-link {
|
||||
margin-left: 15px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.timeline-head {
|
||||
background-color: white;
|
||||
border: 1px solid #d1d8dd;
|
||||
border-radius: 3px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.timeline-head .comment-input-header {
|
||||
background-color: #fafbfc;
|
||||
padding: 7px 15px;
|
||||
border-bottom: 1px solid #EBEFF2;
|
||||
}
|
||||
.timeline-head .comment-input-container {
|
||||
padding: 15px;
|
||||
}
|
||||
.timeline-head .comment-input-container .awesomplete > ul {
|
||||
min-width: 200px;
|
||||
}
|
||||
.timeline-head .comment-input {
|
||||
border-color: #EBEFF2;
|
||||
max-width: 100%;
|
||||
}
|
||||
.timeline-head .comment-input:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.timeline-head {
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
border-radius: 0px;
|
||||
}
|
||||
}
|
||||
.signature-field {
|
||||
min-height: 300px;
|
||||
background: #fff;
|
||||
border: 1px solid #d1d8dd;
|
||||
border-radius: 3px;
|
||||
position: relative;
|
||||
margin-top: -10px;
|
||||
}
|
||||
.signature-display {
|
||||
margin: 7px 0px;
|
||||
background: #fff;
|
||||
}
|
||||
.signature-btn-row {
|
||||
position: absolute;
|
||||
bottom: 12px;
|
||||
right: 12px;
|
||||
}
|
||||
.signature-reset {
|
||||
z-index: 10;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
padding: 4px 0px;
|
||||
}
|
||||
.signature-img {
|
||||
background: #fff;
|
||||
border-radius: 3px;
|
||||
margin-top: 5px;
|
||||
max-height: 150px;
|
||||
}
|
||||
.timeline-new-email {
|
||||
margin: 30px 0px;
|
||||
padding-left: 70px;
|
||||
position: relative;
|
||||
}
|
||||
.timeline-new-email::before {
|
||||
content: " ";
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
background-color: #d1d8dd;
|
||||
position: absolute;
|
||||
left: 40px;
|
||||
border-radius: 50%;
|
||||
top: 5px;
|
||||
}
|
||||
.form-footer h5 {
|
||||
margin: 15px 0px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.control-label,
|
||||
.grid-heading-row {
|
||||
color: #8D99A6;
|
||||
font-size: 12px;
|
||||
}
|
||||
.control-label {
|
||||
margin-bottom: 5px;
|
||||
font-weight: normal;
|
||||
}
|
||||
.like-disabled-input {
|
||||
margin-bottom: 7px;
|
||||
min-height: 30px;
|
||||
font-weight: bold;
|
||||
background-color: #f5f7fa;
|
||||
padding: 5px 10px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.disabled-check {
|
||||
color: #f5f7fa;
|
||||
margin-right: 5px;
|
||||
margin-bottom: -2px;
|
||||
}
|
||||
.like-disabled-input.for-description {
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
}
|
||||
.frappe-control {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.frappe-control .help-box {
|
||||
margin-top: 3px;
|
||||
}
|
||||
.frappe-control pre {
|
||||
white-space: pre-wrap;
|
||||
background-color: inherit;
|
||||
border: none;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
.flex-justify-center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.flex-justify-end {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.hide-control {
|
||||
display: none !important;
|
||||
}
|
||||
.shared-user {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.attach-missing-image,
|
||||
.attach-image-display {
|
||||
cursor: pointer;
|
||||
}
|
||||
select.form-control {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
.form-control.bold {
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
background-color: #fffdf4;
|
||||
}
|
||||
.form-control[data-fieldtype="Password"] {
|
||||
position: inherit;
|
||||
}
|
||||
.password-strength-indicator {
|
||||
float: right;
|
||||
padding: 15px;
|
||||
margin-top: -41px;
|
||||
margin-right: -7px;
|
||||
}
|
||||
.password-strength-message {
|
||||
margin-top: -10px;
|
||||
}
|
||||
.control-code,
|
||||
.control-code.bold {
|
||||
height: 400px;
|
||||
font-family: Monaco, "Courier New", monospace;
|
||||
color: #36414C;
|
||||
font-size: 12px;
|
||||
line-height: 1.7em;
|
||||
}
|
||||
.delivery-status-indicator {
|
||||
display: inline-block;
|
||||
margin-top: -3px;
|
||||
margin-left: 1px;
|
||||
font-weight: 500;
|
||||
color: #8D99A6;
|
||||
}
|
||||
.attach-btn {
|
||||
margin-top: 10px;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.layout-main .form-column.col-sm-12 > form > .input-max-width {
|
||||
max-width: 50%;
|
||||
padding-right: 15px;
|
||||
}
|
||||
.col-sm-6 .form-grid .form-column.col-sm-12 > form > .input-max-width {
|
||||
max-width: none;
|
||||
padding-right: 0px;
|
||||
}
|
||||
.form-column.col-sm-6 textarea[data-fieldtype="Code"] {
|
||||
height: 120px !important;
|
||||
}
|
||||
}
|
||||
@media (max-width: 991px) {
|
||||
.form-section .form-section-heading {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.form-section .section-head {
|
||||
padding: 15px 15px 15px 0px;
|
||||
}
|
||||
.form-section .section-body .form-column:first-child .radio,
|
||||
.form-section .section-body .form-column:first-child .checkbox {
|
||||
margin-top: 0;
|
||||
}
|
||||
.form-column {
|
||||
border-bottom: 1px solid #EBEFF2;
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
.form-column:last-child {
|
||||
border-bottom: 0px;
|
||||
}
|
||||
.form-section {
|
||||
padding-left: 0px !important;
|
||||
padding-right: 0px !important;
|
||||
}
|
||||
.form-grid {
|
||||
margin-left: -17px;
|
||||
margin-right: -17px;
|
||||
border-left: none !important;
|
||||
border-right: none !important;
|
||||
border-radius: none;
|
||||
}
|
||||
.form-page .form-section {
|
||||
padding: 0px 15px;
|
||||
}
|
||||
.frappe-control.form-page {
|
||||
padding: 7px 15px;
|
||||
border-bottom: 1px solid #EBEFF2;
|
||||
margin: 0px -15px;
|
||||
}
|
||||
.frappe-control.form-page .link-btn {
|
||||
top: -2px;
|
||||
}
|
||||
.frappe-control.form-page .like-disabled-input {
|
||||
min-height: 0px !important;
|
||||
}
|
||||
.frappe-control.form-page:last-child {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
.form-page .frappe-control:last-child {
|
||||
border-bottom: 0px;
|
||||
}
|
||||
.form-page .frappe-control[data-fieldtype="Table"] {
|
||||
padding: 0px 15px;
|
||||
margin-top: -1px;
|
||||
border-bottom: none;
|
||||
}
|
||||
.form-page .frappe-control[data-fieldtype="Table"] label {
|
||||
margin-top: 7px;
|
||||
}
|
||||
.form-page .form-control {
|
||||
border: none;
|
||||
border-bottom: 1px solid #d1d8dd;
|
||||
box-shadow: none;
|
||||
background-color: inherit;
|
||||
height: auto;
|
||||
padding: 0px;
|
||||
margin-bottom: 7px;
|
||||
border-radius: 0px;
|
||||
text-align: left !important;
|
||||
}
|
||||
.form-page .form-control:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
/* goals */
|
||||
.goals-page-container {
|
||||
background-color: #fafbfc;
|
||||
padding-top: 1px;
|
||||
}
|
||||
.goals-page-container .goal-container {
|
||||
background-color: #fff;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||
border-radius: 2px;
|
||||
padding: 10px;
|
||||
margin: 10px;
|
||||
}
|
||||
body[data-route^="Form/Communication"] textarea[data-fieldname="subject"] {
|
||||
height: 80px !important;
|
||||
}
|
||||
.frappe-control[data-fieldtype="Attach"] .attached-file {
|
||||
position: relative;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.frappe-control[data-fieldtype="Attach"] .attached-file .close {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
|
@ -1,411 +0,0 @@
|
|||
/* the element that this class is applied to, should have a max width for this to work*/
|
||||
html {
|
||||
min-height: 100%;
|
||||
}
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0px;
|
||||
padding: 0px !important;
|
||||
}
|
||||
html,
|
||||
body {
|
||||
overflow-x: hidden;
|
||||
overflow-y: overlay;
|
||||
}
|
||||
@media (max-width: 991px) {
|
||||
.intro-area,
|
||||
.footnote-area {
|
||||
padding: 15px;
|
||||
}
|
||||
.grid-row-open {
|
||||
top: 0;
|
||||
}
|
||||
.layout-main {
|
||||
position: relative;
|
||||
}
|
||||
body[data-route^="Form"] .page-title h1 {
|
||||
margin-top: 12px;
|
||||
}
|
||||
body[data-route^="Form"] .page-title h1.editable-title {
|
||||
padding-right: 80px;
|
||||
}
|
||||
body[data-route^="Form"] .page-title .indicator {
|
||||
display: inline-block;
|
||||
margin-top: 12px;
|
||||
}
|
||||
body[data-route^="Form"] .page-actions {
|
||||
padding-top: 20px !important;
|
||||
padding-bottom: 0px !important;
|
||||
padding-left: 0px !important;
|
||||
}
|
||||
body[data-route^="Form"] .page-head .sub-heading {
|
||||
font-weight: normal;
|
||||
font-size: 10px;
|
||||
display: block;
|
||||
position: absolute;
|
||||
right: 140px;
|
||||
min-width: 200px;
|
||||
}
|
||||
body[data-route^="Form"] .title-text {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.toggle-navbar-new-comments {
|
||||
padding: 8px 0px !important;
|
||||
}
|
||||
.navbar > .container > .navbar-header {
|
||||
float: left;
|
||||
width: 80%;
|
||||
}
|
||||
.navbar > .container > .navbar-right {
|
||||
float: right;
|
||||
}
|
||||
.module-item {
|
||||
padding: 7px 0px !important;
|
||||
}
|
||||
.module-item h4 {
|
||||
font-weight: normal;
|
||||
}
|
||||
#navbar-breadcrumbs {
|
||||
margin: 0px;
|
||||
display: inline-block;
|
||||
max-width: 150px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
#navbar-breadcrumbs > li,
|
||||
#navbar-breadcrumbs > li > a {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
#navbar-breadcrumbs > li > a:before {
|
||||
content: "\f104";
|
||||
margin-right: 10px;
|
||||
color: #6C7680;
|
||||
}
|
||||
#navbar-breadcrumbs li:not(:nth-last-child(-n+1)) {
|
||||
display: none;
|
||||
}
|
||||
.navbar-nav {
|
||||
margin: 0px;
|
||||
margin-right: -15px;
|
||||
}
|
||||
.sidebar .form-group {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
#sidebar-search {
|
||||
height: 27px;
|
||||
}
|
||||
.sidebar .navbar-search-icon {
|
||||
float: right;
|
||||
color: #6C7680;
|
||||
font-size: inherit;
|
||||
position: relative;
|
||||
right: 7px;
|
||||
top: -20px;
|
||||
height: 0;
|
||||
}
|
||||
.sidebar form {
|
||||
padding: 7px;
|
||||
}
|
||||
.sidebar .main-menu {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 41px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.sidebar .user-menu {
|
||||
padding: 9px 14px;
|
||||
background-color: #f5f7fa;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
.sidebar .user-menu,
|
||||
.sidebar .user-menu .octicon {
|
||||
color: #6C7680;
|
||||
}
|
||||
.sidebar .user-menu img {
|
||||
margin-top: -1px;
|
||||
}
|
||||
body[data-route^="Module"] .navbar-center {
|
||||
display: block !important;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 25%;
|
||||
right: 25%;
|
||||
text-align: center;
|
||||
}
|
||||
body.no-breadcrumbs .navbar .navbar-home {
|
||||
display: inline-block !important;
|
||||
padding-left: 0px;
|
||||
margin-left: 0px;
|
||||
padding-top: 6px;
|
||||
}
|
||||
body.no-breadcrumbs .navbar .navbar-home:before {
|
||||
font-family: FontAwesome;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
text-decoration: inherit;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
*margin-right: 0.3em;
|
||||
display: inline-block;
|
||||
speak: none;
|
||||
font-size: 24px;
|
||||
transition: 0.2s;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
content: "\f104";
|
||||
margin-right: 10px;
|
||||
color: #6C7680;
|
||||
}
|
||||
body.no-breadcrumbs .navbar .navbar-home:hover:before,
|
||||
body.no-breadcrumbs .navbar .navbar-home:focus:before,
|
||||
body.no-breadcrumbs .navbar .navbar-home:active:before {
|
||||
color: #36414C !important;
|
||||
}
|
||||
body[data-route=""] .navbar .navbar-home,
|
||||
body[data-route="desktop"] .navbar .navbar-home {
|
||||
padding: 8px 10px;
|
||||
}
|
||||
body[data-route=""] .navbar .navbar-home:before,
|
||||
body[data-route="desktop"] .navbar .navbar-home:before {
|
||||
display: none;
|
||||
}
|
||||
body[data-route=""] .navbar .navbar-home img,
|
||||
body[data-route="desktop"] .navbar .navbar-home img {
|
||||
margin-top: 0;
|
||||
}
|
||||
body[data-route=""] .toggle-sidebar,
|
||||
body[data-route="desktop"] .toggle-sidebar {
|
||||
display: none !important;
|
||||
}
|
||||
body[data-sidebar="0"] .toggle-sidebar {
|
||||
display: none !important;
|
||||
}
|
||||
body[data-sidebar="0"] #navbar-breadcrumbs,
|
||||
body[data-sidebar="0"] .navbar-home {
|
||||
margin-left: 15px !important;
|
||||
}
|
||||
}
|
||||
@media (max-width: 991px) and (max-width: 480px) {
|
||||
#navbar-breadcrumbs li > a {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.toggle-sidebar {
|
||||
margin-right: 0;
|
||||
}
|
||||
body[data-route^="Form"] .page-title .title-text {
|
||||
font-size: 16px;
|
||||
width: calc(100% - 90px);
|
||||
}
|
||||
body[data-route^="Form"] .page-title .indicator {
|
||||
float: left;
|
||||
margin-top: 10px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.modal .modal-dialog {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
.modal .modal-content {
|
||||
border-radius: 0px;
|
||||
border: none;
|
||||
height: 100%;
|
||||
}
|
||||
.modal .modal-body .form-layout {
|
||||
margin: -15px;
|
||||
}
|
||||
.modal .file-upload .input-upload {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
.modal .file-upload .input-upload .btn-browse {
|
||||
width: 100%;
|
||||
}
|
||||
.modal .file-upload .web-link-wrapper {
|
||||
display: block;
|
||||
width: 100% !important;
|
||||
text-align: center;
|
||||
}
|
||||
.modal .file-upload .web-link-wrapper .file-upload-or {
|
||||
display: block;
|
||||
margin: 15px 24px;
|
||||
}
|
||||
.modal .file-upload .web-link-wrapper .input-link {
|
||||
width: 100% !important;
|
||||
}
|
||||
.layout-main-section-wrapper {
|
||||
padding: 0px;
|
||||
}
|
||||
.layout-main-section {
|
||||
border-left-color: transparent !important;
|
||||
border-right-color: transparent !important;
|
||||
}
|
||||
.list-row {
|
||||
padding: 13px 15px !important;
|
||||
}
|
||||
.doclist-row {
|
||||
position: relative;
|
||||
padding-right: 10px;
|
||||
}
|
||||
.doclist-row .list-id {
|
||||
font-weight: normal;
|
||||
}
|
||||
.doclist-row .list-row-id {
|
||||
left: 18px;
|
||||
text-align: left;
|
||||
margin-top: 3px;
|
||||
}
|
||||
.doclist-row.has-checkbox .list-row-id {
|
||||
left: 40px;
|
||||
}
|
||||
.doclist-row .list-row-indicator {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
top: -20px;
|
||||
}
|
||||
.doclist-row .list-row-modified {
|
||||
margin-right: -10px;
|
||||
}
|
||||
.doclist-row .list-row-left {
|
||||
z-index: 1;
|
||||
}
|
||||
.doclist-row .list-row-right {
|
||||
float: right;
|
||||
}
|
||||
.doclist-row .list-row-right .list-row-indicator {
|
||||
top: 4px;
|
||||
}
|
||||
.doclist-row .list-row-right .list-row-indicator .indicator::before,
|
||||
.doclist-row .list-row-right .list-row-indicator .indicator::after {
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
.doclist-row .list-row-right.no-right-column {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 10px;
|
||||
left: -10px;
|
||||
width: 100%;
|
||||
}
|
||||
body[data-route^="chat"] .navbar-center {
|
||||
display: block !important;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 25%;
|
||||
right: 25%;
|
||||
text-align: center;
|
||||
}
|
||||
#page-chat .layout-side-section {
|
||||
position: relative;
|
||||
left: 0px;
|
||||
border-right: 1px solid #d1d8dd;
|
||||
padding-left: 0px;
|
||||
float: left;
|
||||
width: 76px;
|
||||
}
|
||||
#page-chat .layout-main-section-wrapper {
|
||||
position: absolute;
|
||||
left: 75px;
|
||||
right: 0px;
|
||||
border-left: 1px solid #d1d8dd;
|
||||
float: left;
|
||||
}
|
||||
#page-chat .module-sidebar-item {
|
||||
margin: 0px;
|
||||
}
|
||||
#page-chat .module-sidebar-item .chat-sidebar-link {
|
||||
padding: 15px;
|
||||
}
|
||||
#page-chat .timeline-head {
|
||||
padding: 15px 15px 7px;
|
||||
}
|
||||
#page-chat .list-row {
|
||||
padding: 7px 0px;
|
||||
}
|
||||
#page-chat .message-row-right {
|
||||
margin-top: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
body[data-route^="Form"] .page-head .sub-heading {
|
||||
right: 90px;
|
||||
}
|
||||
.timeline::before {
|
||||
content: none;
|
||||
}
|
||||
.timeline .timeline-new-email {
|
||||
margin: 20px 0;
|
||||
padding-left: 15px;
|
||||
}
|
||||
.timeline .timeline-new-email::before {
|
||||
content: none;
|
||||
}
|
||||
.timeline .timeline-item.user-content {
|
||||
margin: 20px 15px;
|
||||
}
|
||||
.timeline .timeline-item.user-content .media-body {
|
||||
margin-left: 0;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.timeline .timeline-item.user-content .media-body:before {
|
||||
content: none;
|
||||
}
|
||||
.timeline .timeline-item.user-content .action-btns {
|
||||
padding: 7px 10px 2px 5px;
|
||||
}
|
||||
.timeline .timeline-item.user-content .action-btns .edit-btn-container {
|
||||
margin-right: 0;
|
||||
}
|
||||
.timeline .timeline-item.user-content .comment-header {
|
||||
padding: 7px 10px;
|
||||
}
|
||||
.timeline .timeline-item.user-content .comment-header .links-active {
|
||||
padding-right: 10px;
|
||||
}
|
||||
.timeline .timeline-item.user-content .comment-header .reply-link {
|
||||
margin-left: 0;
|
||||
}
|
||||
.timeline .timeline-item.user-content .comment-header .asset-details {
|
||||
width: calc(100% - 30px);
|
||||
}
|
||||
.timeline .timeline-item.user-content .avatar-medium {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.timeline .timeline-item.user-content .reply {
|
||||
padding: 10px;
|
||||
}
|
||||
.timeline .timeline-item.user-content .commented-on-small {
|
||||
display: inline-block;
|
||||
}
|
||||
.timeline .timeline-item.user-content .commented-on-small {
|
||||
display: inline-block;
|
||||
}
|
||||
.timeline .timeline-item.notification-content {
|
||||
padding-left: 15px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.timeline .timeline-item.notification-content::before {
|
||||
content: none;
|
||||
}
|
||||
.timeline .timeline-item.notification-content .small {
|
||||
padding-left: 0;
|
||||
}
|
||||
.timeline .timeline-item .delivery-status-indicator {
|
||||
float: left;
|
||||
margin: 0 5px 0 0;
|
||||
}
|
||||
.timeline .asset-details {
|
||||
line-height: 24px;
|
||||
/*Height of avtar image -36px to align text center vertically*/
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<svg width="0" height="0" class="d-block" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg aria-hidden="true" style="position: absolute; width: 0; height: 0; overflow: hidden;" class="d-block" xmlns="http://www.w3.org/2000/svg">
|
||||
<symbol viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" id="icon-resting">
|
||||
<path d="M7.606 3.799L8 4.302l.394-.503.106-.14c.048-.065.08-.108.129-.159a3.284 3.284 0 0 1 4.72 0c.424.434.655 1.245.65 2.278-.006 1.578-.685 2.931-1.728 4.159-1.05 1.234-2.439 2.308-3.814 3.328a.763.763 0 0 1-.914 0c-1.375-1.02-2.764-2.094-3.814-3.328C2.686 8.709 2.007 7.357 2 5.778c-.004-1.033.227-1.844.651-2.278a3.284 3.284 0 0 1 4.72 0c.05.05.081.094.129.158.028.038.061.083.106.14z"
|
||||
stroke="var(--icon-stroke)"></path>
|
||||
|
|
@ -138,7 +138,10 @@
|
|||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.25 6C3.25 5.72386 3.47386 5.5 3.75 5.5H20.2474C20.5236 5.5 20.7474 5.72386 20.7474 6C20.7474 6.27614 20.5236 6.5 20.2474 6.5H3.75C3.47386 6.5 3.25 6.27614 3.25 6ZM3.25 12C3.25 11.7239 3.47386 11.5 3.75 11.5H20.2474C20.5236 11.5 20.7474 11.7239 20.7474 12C20.7474 12.2761 20.5236 12.5 20.2474 12.5H3.75C3.47386 12.5 3.25 12.2761 3.25 12ZM3.75 17.5C3.47386 17.5 3.25 17.7239 3.25 18C3.25 18.2761 3.47386 18.5 3.75 18.5H20.2474C20.5236 18.5 20.7474 18.2761 20.7474 18C20.7474 17.7239 20.5236 17.5 20.2474 17.5H3.75Z" fill="var(--icon-stroke)"/>
|
||||
</symbol>
|
||||
<symbol fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" id="icon-lock">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.077 1.45h-.055a3.356 3.356 0 00-3.387 3.322v.35H3.75a2 2 0 00-2 2v5.391a2 2 0 002 2h8.539a2 2 0 002-2V7.122a2 2 0 00-2-2h-.885v-.285A3.356 3.356 0 008.082 1.45h-.005zm2.327 3.672V4.83a2.356 2.356 0 00-2.33-2.38h-.06a2.356 2.356 0 00-2.38 2.33v.342h4.77zm-6.654 1a1 1 0 00-1 1v5.391a1 1 0 001 1h8.539a1 1 0 001-1V7.122a1 1 0 00-1-1H3.75zm4.27 4.269a.573.573 0 100-1.147.573.573 0 000 1.147zm1.573-.574a1.573 1.573 0 11-3.147 0 1.573 1.573 0 013.147 0z"></path>
|
||||
<path stroke="none" fill-rule="evenodd" clip-rule="evenodd" d="M8.077 1.45h-.055a3.356 3.356 0 00-3.387 3.322v.35H3.75a2 2 0 00-2 2v5.391a2 2 0 002 2h8.539a2 2 0 002-2V7.122a2 2 0 00-2-2h-.885v-.285A3.356 3.356 0 008.082 1.45h-.005zm2.327 3.672V4.83a2.356 2.356 0 00-2.33-2.38h-.06a2.356 2.356 0 00-2.38 2.33v.342h4.77zm-6.654 1a1 1 0 00-1 1v5.391a1 1 0 001 1h8.539a1 1 0 001-1V7.122a1 1 0 00-1-1H3.75zm4.27 4.269a.573.573 0 100-1.147.573.573 0 000 1.147zm1.573-.574a1.573 1.573 0 11-3.147 0 1.573 1.573 0 013.147 0z" fill="#1F272E"></path>
|
||||
</symbol>
|
||||
<symbol width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" id="icon-unlock">
|
||||
<path stroke="none" fill-rule="evenodd" clip-rule="evenodd" d="M8.07685 1.45034H8.02155C7.13255 1.44218 6.2766 1.78707 5.64159 2.40938C5.00596 3.03229 4.64377 3.88215 4.63464 4.77206L4.63462 4.77206V4.77719V5.12175H3.75C2.64543 5.12175 1.75 6.01719 1.75 7.12175V12.5134C1.75 13.6179 2.64543 14.5134 3.75 14.5134H12.2885C13.393 14.5134 14.2885 13.6179 14.2885 12.5134V7.12175C14.2885 6.01718 13.393 5.12175 12.2885 5.12175H5.63462V4.77988C5.64166 4.156 5.89586 3.56033 6.34152 3.12359C6.78776 2.68627 7.38942 2.4441 8.01419 2.45031L8.01418 2.45034H8.01916H8.07417C8.69805 2.45738 9.29371 2.71158 9.73045 3.15724C9.92373 3.35446 10.2403 3.35766 10.4375 3.16438C10.6347 2.9711 10.6379 2.65453 10.4447 2.45731C9.82175 1.82169 8.97189 1.45949 8.08198 1.45036L8.08198 1.45034H8.07685ZM3.75 6.12175C3.19772 6.12175 2.75 6.56947 2.75 7.12175V12.5134C2.75 13.0656 3.19772 13.5134 3.75 13.5134H12.2885C12.8407 13.5134 13.2885 13.0656 13.2885 12.5134V7.12175C13.2885 6.56947 12.8407 6.12175 12.2885 6.12175H3.75ZM8.01936 10.3909C8.33605 10.3909 8.59279 10.1342 8.59279 9.81752C8.59279 9.50083 8.33605 9.24409 8.01936 9.24409C7.70266 9.24409 7.44593 9.50083 7.44593 9.81752C7.44593 10.1342 7.70266 10.3909 8.01936 10.3909ZM9.59279 9.81752C9.59279 10.6865 8.88834 11.3909 8.01936 11.3909C7.15038 11.3909 6.44593 10.6865 6.44593 9.81752C6.44593 8.94854 7.15038 8.24409 8.01936 8.24409C8.88834 8.24409 9.59279 8.94854 9.59279 9.81752Z" fill="#1F272E"/>
|
||||
</symbol>
|
||||
<symbol viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" id="icon-list_alt">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.5 3.722c0-.454.316-.722.59-.722h9.82c.274 0 .59.268.59.722v8.556c0 .454-.316.722-.59.722H3.09c-.274 0-.59-.268-.59-.722V3.722zM3.09 2c-.93 0-1.59.826-1.59 1.722v8.556c0 .896.66 1.722 1.59 1.722h9.82c.93 0 1.59-.826 1.59-1.722V3.722C14.5 2.826 13.84 2 12.91 2H3.09zM5 4.5a.5.5 0 0 0 0 1h4.002a.5.5 0 1 0 0-1H5zM5 7a.5.5 0 0 0 0 1h5.002a.5.5 0 1 0 0-1H5zm-.5 3a.5.5 0 0 1 .5-.5h2.27a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5z"
|
||||
|
|
@ -677,4 +680,17 @@
|
|||
<path d="M6.04544 17.5001C7.1751 17.5001 8.09087 16.5843 8.09087 15.4546C8.09087 14.325 7.1751 13.4092 6.04544 13.4092C4.91577 13.4092 4 14.325 4 15.4546C4 16.5843 4.91577 17.5001 6.04544 17.5001Z" stroke="var(--icon-stroke)" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M14.2271 6.59087C15.3567 6.59087 16.2725 5.6751 16.2725 4.54544C16.2725 3.41577 15.3567 2.5 14.2271 2.5C13.0974 2.5 12.1816 3.41577 12.1816 4.54544C12.1816 5.6751 13.0974 6.59087 14.2271 6.59087Z" stroke="var(--icon-stroke)" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</symbol>
|
||||
<symbol fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" id="icon-restriction">
|
||||
<path d="M8 14A6 6 0 108 2a6 6 0 000 12zM4 4l8 8" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
</symbol>
|
||||
<symbol viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg" id="icon-arrow-right" stroke-width="1.2">
|
||||
<path d="M10 6.00223L1 5.99973" stroke="var(--icon-stroke)" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M7.70015 3.00244L10.7001 6.00244L7.70015 9.00244" stroke="var(--icon-stroke)" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</symbol>
|
||||
<symbol viewBox="0 0 16 22" xmlns="http://www.w3.org/2000/svg" id="icon-dialpad">
|
||||
<path fill-rule="evenodd" stroke="none" fill="var(--icon-stroke)" d="M8 18c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zM2 0C.9 0 0 .9 0 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6C.9 6 0 6.9 0 8s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12-8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-6 8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zM8 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6C6.9 0 6 .9 6 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" stroke="var(--icon-stroke)" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</symbol>
|
||||
<symbol viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" id="icon-star">
|
||||
<path d="M11.5516 2.90849C11.735 2.53687 12.265 2.53687 12.4484 2.90849L14.8226 7.71919C14.8954 7.86677 15.0362 7.96905 15.1991 7.99271L20.508 8.76415C20.9181 8.82374 21.0818 9.32772 20.7851 9.61699L16.9435 13.3616C16.8257 13.4765 16.7719 13.642 16.7997 13.8042L17.7066 19.0916C17.7766 19.5001 17.3479 19.8116 16.9811 19.6187L12.2327 17.1223C12.087 17.0457 11.913 17.0457 11.7673 17.1223L7.01888 19.6187C6.65207 19.8116 6.22335 19.5001 6.29341 19.0916L7.20028 13.8042C7.2281 13.642 7.17433 13.4765 7.05648 13.3616L3.21491 9.61699C2.91815 9.32772 3.08191 8.82374 3.49202 8.76415L8.80094 7.99271C8.9638 7.96905 9.10458 7.86677 9.17741 7.71919L11.5516 2.90849Z" fill="var(--star-fill)" stroke="var(--star-fill)"/>
|
||||
</symbol>
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 91 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.5 KiB |
|
|
@ -1,52 +0,0 @@
|
|||
// used in documenation site built via document generator
|
||||
|
||||
$(function() {
|
||||
if(window.hljs) {
|
||||
$('pre code').each(function(i, block) {
|
||||
hljs.highlightBlock(block);
|
||||
});
|
||||
}
|
||||
|
||||
// search
|
||||
$('.sidebar-navbar-items .octicon-search, .navbar .octicon-search').parent().on("click", function() {
|
||||
var modal = frappe.get_modal("Search",
|
||||
'<p><input class="search-input form-control" type="text" placeholder="Search text..." tabindex="1"></p>\
|
||||
<p><a class="btn btn-sm btn-default btn-search" href="#" target="_blank" tabindex="2">Search via Google</a></p>');
|
||||
modal.find(".search-input").on("keyup", function(e) {
|
||||
if(e.which===13) {
|
||||
modal.find(".btn-search").trigger("click");
|
||||
}
|
||||
if(e.which===9) {
|
||||
e.preventDefault();
|
||||
modal.find(".btn-search").focus();
|
||||
return false;
|
||||
}
|
||||
var text = $(this).val();
|
||||
modal.find(".btn-search").attr("href", "https://google.com/search?q="
|
||||
+ text + "+site:" + (window.docs_base_url || ""));
|
||||
});
|
||||
modal.modal("show");
|
||||
return false;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
frappe = {
|
||||
get_modal: function(title, body_html) {
|
||||
var modal = $('<div class="modal" style="overflow: auto;" tabindex="-1">\
|
||||
<div class="modal-dialog">\
|
||||
<div class="modal-content">\
|
||||
<div class="modal-header">\
|
||||
<a type="button" class="close"\
|
||||
data-dismiss="modal" aria-hidden="true">×</a>\
|
||||
<h4 class="modal-title">'+title+'</h4>\
|
||||
</div>\
|
||||
<div class="modal-body ui-front">'+body_html+'\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>').appendTo(document.body);
|
||||
|
||||
return modal;
|
||||
},
|
||||
};
|
||||
|
|
@ -1305,8 +1305,6 @@ class {
|
|||
this.set_wrapper(selector ? selector : "body")
|
||||
this.set_options(options)
|
||||
|
||||
// Load Emojis.
|
||||
frappe.chat.emoji()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2783,7 +2781,8 @@ frappe.chat.setup = () => {
|
|||
}
|
||||
}
|
||||
|
||||
$(document).on('ready toolbar_setup', () =>
|
||||
{
|
||||
frappe.chat.setup()
|
||||
})
|
||||
// TODO: Re-enable after re-designing chat
|
||||
// $(document).on('ready toolbar_setup', () =>
|
||||
// {
|
||||
// frappe.chat.setup()
|
||||
// })
|
||||
|
|
|
|||
|
|
@ -188,8 +188,8 @@ frappe.data_import.ImportPreview = class ImportPreview {
|
|||
.join(',');
|
||||
this.datatable.style.setStyle(row_classes, {
|
||||
pointerEvents: 'none',
|
||||
backgroundColor: frappe.ui.color.get_color_shade('white', 'light'),
|
||||
color: frappe.ui.color.get_color_shade('black', 'extra-light')
|
||||
backgroundColor: frappe.ui.color.get_color_shade('gray', 'extra-light'),
|
||||
color: frappe.ui.color.get_color_shade('gray', 'dark')
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,10 +45,7 @@ frappe.Application = Class.extend({
|
|||
this.setup_frappe_vue();
|
||||
this.load_bootinfo();
|
||||
this.load_user_permissions();
|
||||
this.set_app_logo_url()
|
||||
.then(() => {
|
||||
this.make_nav_bar();
|
||||
});
|
||||
this.make_nav_bar();
|
||||
this.set_favicon();
|
||||
this.setup_analytics();
|
||||
this.set_fullwidth_if_enabled();
|
||||
|
|
@ -82,8 +79,11 @@ frappe.Application = Class.extend({
|
|||
}
|
||||
|
||||
if (frappe.user_roles.includes('System Manager')) {
|
||||
this.show_change_log();
|
||||
this.show_update_available();
|
||||
// delayed following requests to make boot faster
|
||||
setTimeout(() => {
|
||||
this.show_change_log();
|
||||
this.show_update_available();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
if (!frappe.boot.developer_mode) {
|
||||
|
|
@ -470,19 +470,6 @@ frappe.Application = Class.extend({
|
|||
$('<link rel="shortcut icon" href="' + link + '" type="image/x-icon">').appendTo("head");
|
||||
$('<link rel="icon" href="' + link + '" type="image/x-icon">').appendTo("head");
|
||||
},
|
||||
|
||||
set_app_logo_url: function() {
|
||||
return frappe.call('frappe.core.doctype.navbar_settings.navbar_settings.get_app_logo')
|
||||
.then(r => {
|
||||
frappe.app.logo_url = r.message;
|
||||
if (window.cordova) {
|
||||
let host = frappe.request.url;
|
||||
host = host.slice(0, host.length - 1);
|
||||
frappe.app.logo_url = host + frappe.app.logo_url;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
trigger_primary_action: function() {
|
||||
if(window.cur_dialog && cur_dialog.display) {
|
||||
// trigger primary
|
||||
|
|
@ -498,6 +485,7 @@ frappe.Application = Class.extend({
|
|||
if (frappe.utils.is_rtl()) {
|
||||
var ls = document.createElement('link');
|
||||
ls.rel="stylesheet";
|
||||
ls.type = "text/css";
|
||||
ls.href= "assets/css/frappe-rtl.css";
|
||||
document.getElementsByTagName('head')[0].appendChild(ls);
|
||||
$('body').addClass('frappe-rtl');
|
||||
|
|
|
|||
|
|
@ -11,17 +11,18 @@
|
|||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<a :href="file.doc.file_url" v-if="file.doc" target="_blank">
|
||||
<a class="flex" :href="file.doc.file_url" v-if="file.doc" target="_blank">
|
||||
<span class="file-name">{{ file.name | file_name }}</span>
|
||||
<i v-html="frappe.utils.icon(file.doc.is_private ? 'lock' : 'unlock')"></i>
|
||||
<div class="ml-2" v-html="private_icon"></div>
|
||||
</a>
|
||||
<span class="flex" v-else>
|
||||
<span class="file-name">{{ file.name | file_name }}</span>
|
||||
<span class="cursor-pointer" @click="$emit('toggle_private')" :title="__('Toggle Public/Private')">
|
||||
<i v-html="frappe.utils.icon(file.is_private ? 'lock' : 'unlock')"></i>
|
||||
</span>
|
||||
<button class="ml-2 btn-reset" @click="$emit('toggle_private')" :title="__('Toggle Public/Private')">
|
||||
<div v-html="private_icon"></div>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span class="file-size">
|
||||
{{ file.file_obj.size | file_size }}
|
||||
|
|
@ -30,7 +31,7 @@
|
|||
</div>
|
||||
<div class="file-actions">
|
||||
<ProgressRing
|
||||
v-show="file.uploading"
|
||||
v-show="file.uploading && !uploaded"
|
||||
primary="var(--primary-color)"
|
||||
secondary="var(--gray-200)"
|
||||
radius="24"
|
||||
|
|
@ -76,6 +77,12 @@ export default {
|
|||
}
|
||||
},
|
||||
computed: {
|
||||
private_icon() {
|
||||
return frappe.utils.icon(this.is_private ? 'lock' : 'unlock');
|
||||
},
|
||||
is_private() {
|
||||
return this.file.doc ? this.file.doc.is_private : this.file.private;
|
||||
},
|
||||
uploaded() {
|
||||
return this.file.total && this.file.total === this.file.progress && !this.file.failed;
|
||||
},
|
||||
|
|
@ -156,9 +163,10 @@ export default {
|
|||
}
|
||||
|
||||
.file-actions {
|
||||
width: 2.5rem;
|
||||
width: 3rem;
|
||||
flex-shrink: 0;
|
||||
margin-left: auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.file-actions .btn {
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@
|
|||
>
|
||||
<div v-if="!is_dragging">
|
||||
<div class="text-center">
|
||||
{{ __('Drag and drop files here or') }}
|
||||
{{ __('Drag and drop files here or upload from') }}
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
<div class="mt-2 text-center">
|
||||
<button class="btn btn-file-upload" @click="browse_files">
|
||||
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="15" cy="15" r="15" fill="url(#paint0_linear)"/>
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
<div class="mt-1">{{ __('Select File') }}</div>
|
||||
<div class="mt-1">{{ __('My Device') }}</div>
|
||||
</button>
|
||||
<input
|
||||
type="file"
|
||||
|
|
@ -55,6 +55,14 @@
|
|||
</svg>
|
||||
<div class="mt-1">{{ __('Link') }}</div>
|
||||
</button>
|
||||
<button v-if="allow_take_photo" class="btn btn-file-upload" @click="capture_image">
|
||||
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="15" cy="15" r="15" fill="#CE315B"/>
|
||||
<path d="M11.5 10.5H9.5C8.67157 10.5 8 11.1716 8 12V20C8 20.8284 8.67157 21.5 9.5 21.5H20.5C21.3284 21.5 22 20.8284 22 20V12C22 11.1716 21.3284 10.5 20.5 10.5H18.5L17.3 8.9C17.1111 8.64819 16.8148 8.5 16.5 8.5H13.5C13.1852 8.5 12.8889 8.64819 12.7 8.9L11.5 10.5Z" stroke="white" stroke-linejoin="round"/>
|
||||
<circle cx="15" cy="16" r="2.5" stroke="white"/>
|
||||
</svg>
|
||||
<div class="mt-1">{{ __('Camera') }}</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="text-muted text-medium">
|
||||
{{ upload_notes }}
|
||||
|
|
@ -65,21 +73,13 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="file-preview-area" v-show="files.length && !show_file_browser && !show_web_link">
|
||||
<!-- <div class="margin-bottom" v-if="!upload_complete">
|
||||
<label>
|
||||
<input type="checkbox" class="input-with-feedback" @change="e => toggle_all_private(e.target.checked)">
|
||||
<span class="text-medium" style="font-weight: normal;">
|
||||
{{ __('Make all attachments private') }}
|
||||
</span>
|
||||
</label>
|
||||
</div> -->
|
||||
<div class="file-preview-container">
|
||||
<FilePreview
|
||||
v-for="(file, i) in files"
|
||||
:key="file.name"
|
||||
:file="file"
|
||||
@remove="remove_file(i)"
|
||||
@toggle_private="toggle_private(i)"
|
||||
@remove="remove_file(file)"
|
||||
@toggle_private="file.private = !file.private"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex align-center" v-if="show_upload_button && currently_uploading === -1">
|
||||
|
|
@ -187,6 +187,9 @@ export default {
|
|||
return this.files.length > 0
|
||||
&& this.files.every(
|
||||
file => file.total !== 0 && file.progress === file.total);
|
||||
},
|
||||
allow_take_photo() {
|
||||
return window.navigator.mediaDevices;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -206,15 +209,19 @@ export default {
|
|||
on_file_input(e) {
|
||||
this.add_files(this.$refs.file_input.files);
|
||||
},
|
||||
remove_file(i) {
|
||||
this.files = this.files.filter((file, j) => i !== j);
|
||||
remove_file(file) {
|
||||
this.files = this.files.filter(f => f !== file);
|
||||
},
|
||||
toggle_private(i) {
|
||||
this.files[i].private = !this.files[i].private;
|
||||
},
|
||||
toggle_all_private(flag) {
|
||||
if (flag == null) {
|
||||
flag = this.files.every(file => file.private);
|
||||
toggle_all_private() {
|
||||
let flag;
|
||||
let private_values = this.files.filter(file => file.private);
|
||||
if (private_values.length < this.files.length) {
|
||||
// there are some private and some public
|
||||
// set all to private
|
||||
flag = true;
|
||||
} else {
|
||||
// all are private, set all to public
|
||||
flag = false;
|
||||
}
|
||||
this.files = this.files.map(file => {
|
||||
file.private = flag;
|
||||
|
|
@ -416,7 +423,25 @@ export default {
|
|||
|
||||
xhr.send(form_data);
|
||||
});
|
||||
}
|
||||
},
|
||||
capture_image() {
|
||||
const capture = new frappe.ui.Capture({
|
||||
animate: false,
|
||||
error: true
|
||||
});
|
||||
capture.show();
|
||||
capture.submit(data_url => {
|
||||
let filename = `capture_${frappe.datetime.now_datetime().replaceAll(/[: -]/g, '_')}.png`;
|
||||
this.url_to_file(data_url, filename, 'image/png').then((file) =>
|
||||
this.add_files([file])
|
||||
);
|
||||
});
|
||||
},
|
||||
url_to_file(url, filename, mime_type) {
|
||||
return fetch(url)
|
||||
.then(res => res.arrayBuffer())
|
||||
.then(buffer => new File([buffer], filename, { type: mime_type }));
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -48,6 +48,13 @@ export default class FileUploader {
|
|||
|
||||
this.uploader = this.$fileuploader.$children[0];
|
||||
|
||||
this.uploader.$watch('files', (files) => {
|
||||
let all_private = files.every(file => file.private);
|
||||
if (this.dialog) {
|
||||
this.dialog.set_secondary_action_label(all_private ? __('Set all public') : __('Set all private'));
|
||||
}
|
||||
}, { deep: true });
|
||||
|
||||
if (files && files.length) {
|
||||
this.uploader.add_files(files);
|
||||
}
|
||||
|
|
@ -66,8 +73,10 @@ export default class FileUploader {
|
|||
title: __('Upload'),
|
||||
primary_action_label: __('Upload'),
|
||||
primary_action: () => this.upload_files(),
|
||||
secondary_action_label: __('Toggle Private'),
|
||||
secondary_action: () => this.uploader.toggle_all_private()
|
||||
secondary_action_label: __('Set all private'),
|
||||
secondary_action: () => {
|
||||
this.uploader.toggle_all_private();
|
||||
}
|
||||
});
|
||||
|
||||
this.wrapper = this.dialog.body;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import Awesomplete from 'awesomplete';
|
||||
|
||||
frappe.ui.form.ControlAutocomplete = frappe.ui.form.ControlData.extend({
|
||||
trigger_change_on_input_event: false,
|
||||
make_input() {
|
||||
this._super();
|
||||
this.setup_awesomplete();
|
||||
|
|
@ -89,18 +90,16 @@ frappe.ui.form.ControlAutocomplete = frappe.ui.form.ControlData.extend({
|
|||
});
|
||||
|
||||
this.$input.on("awesomplete-open", () => {
|
||||
let modal = this.$input.parents('.modal-dialog')[0];
|
||||
if (modal) {
|
||||
$(modal).removeClass("modal-dialog-scrollable");
|
||||
}
|
||||
this.toggle_container_scroll('.modal-dialog', 'modal-dialog-scrollable');
|
||||
this.toggle_container_scroll('.grid-form-body .form-area', 'scrollable');
|
||||
|
||||
this.autocomplete_open = true;
|
||||
});
|
||||
|
||||
this.$input.on("awesomplete-close", () => {
|
||||
let modal = this.$input.parents('.modal-dialog')[0];
|
||||
if (modal) {
|
||||
$(modal).addClass("modal-dialog-scrollable");
|
||||
}
|
||||
this.toggle_container_scroll('.modal-dialog', 'modal-dialog-scrollable', true);
|
||||
this.toggle_container_scroll('.grid-form-body .form-area', 'scrollable', true);
|
||||
|
||||
this.autocomplete_open = false;
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ frappe.ui.form.ControlBarcode = frappe.ui.form.ControlData.extend({
|
|||
this.default_svg = '<svg height=80></svg>';
|
||||
let $input_wrapper = this.$wrapper.find('.control-input-wrapper');
|
||||
this.barcode_area = $(
|
||||
`<div class="barcode-wrapper border">${this.default_svg}</div>`
|
||||
`<div class="barcode-wrapper">${this.default_svg}</div>`
|
||||
);
|
||||
this.barcode_area.appendTo($input_wrapper);
|
||||
},
|
||||
|
|
@ -55,7 +55,14 @@ frappe.ui.form.ControlBarcode = frappe.ui.form.ControlData.extend({
|
|||
|
||||
get_options(value) {
|
||||
// get JsBarcode options
|
||||
let options = JSON.parse('{ "height" : 40 }');
|
||||
let options = {};
|
||||
options.background = "var(--control-bg)";
|
||||
options.lineColor = "var(--text-color)";
|
||||
options.font = "var(--font-stack)";
|
||||
options.fontSize = "16";
|
||||
options.width = "3";
|
||||
options.height = "50";
|
||||
|
||||
if (frappe.utils.is_json(this.df.options)) {
|
||||
options = JSON.parse(this.df.options);
|
||||
if (options.format && options.format === 'EAN') {
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ frappe.ui.form.Control = Class.extend({
|
|||
frappe.model.get_doc(this.doctype, this.docname), this.perm || (this.frm && this.frm.perm), explain);
|
||||
|
||||
// Match parent grid controls read only status
|
||||
if (status === 'Write' && (this.grid || (this.layout && this.layout.grid))) {
|
||||
if (status === 'Write' && (this.grid || (this.layout && this.layout.grid) && !cint(this.df.allow_on_submit))) {
|
||||
var grid = this.grid || this.layout.grid;
|
||||
if (grid.display_status == 'Read') {
|
||||
status = 'Read';
|
||||
|
|
|
|||
|
|
@ -127,13 +127,6 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
|
|||
let display_value = frappe.format(value, this.df, { no_icon: true, inline: true }, doc);
|
||||
this.disp_area && $(this.disp_area).html(display_value);
|
||||
},
|
||||
|
||||
bind_change_event: function() {
|
||||
var me = this;
|
||||
this.$input && this.$input.on("change", this.change || function(e) {
|
||||
me.parse_validate_and_set_in_model(me.get_input_value(), e);
|
||||
});
|
||||
},
|
||||
set_label: function(label) {
|
||||
if(label) this.df.label = label;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ frappe.provide('frappe.phone_call');
|
|||
frappe.ui.form.ControlData = frappe.ui.form.ControlInput.extend({
|
||||
html_element: "input",
|
||||
input_type: "text",
|
||||
trigger_change_on_input_event: true,
|
||||
make_input: function() {
|
||||
if(this.$input) return;
|
||||
|
||||
|
|
@ -22,8 +23,20 @@ frappe.ui.form.ControlData = frappe.ui.form.ControlInput.extend({
|
|||
this.has_input = true;
|
||||
this.bind_change_event();
|
||||
this.setup_autoname_check();
|
||||
// somehow this event does not bubble up to document
|
||||
// after v7, if you can debug, remove this
|
||||
},
|
||||
bind_change_event: function() {
|
||||
const change_handler = e => {
|
||||
if (this.change) this.change(e);
|
||||
else {
|
||||
let value = this.get_input_value();
|
||||
this.parse_validate_and_set_in_model(value, e);
|
||||
}
|
||||
};
|
||||
this.$input.on("change", change_handler);
|
||||
if (this.trigger_change_on_input_event) {
|
||||
// debounce to avoid repeated validations on value change
|
||||
this.$input.on("input", frappe.utils.debounce(change_handler, 500));
|
||||
}
|
||||
},
|
||||
setup_autoname_check: function() {
|
||||
if (!this.df.parent) return;
|
||||
|
|
@ -116,5 +129,9 @@ frappe.ui.form.ControlData = frappe.ui.form.ControlInput.extend({
|
|||
} else {
|
||||
return v;
|
||||
}
|
||||
},
|
||||
toggle_container_scroll: function(el_class, scroll_class, add=false) {
|
||||
let el = this.$input.parents(el_class)[0];
|
||||
if (el) $(el).toggleClass(scroll_class, add);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
frappe.ui.form.ControlDate = frappe.ui.form.ControlData.extend({
|
||||
trigger_change_on_input_event: false,
|
||||
make_input: function() {
|
||||
this._super();
|
||||
this.make_picker();
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ frappe.ui.form.ControlImage = frappe.ui.form.Control.extend({
|
|||
this.$img = $("<img src='"+doc[this.df.options]+"' class='img-responsive'>")
|
||||
.appendTo(this.$body);
|
||||
} else {
|
||||
this.$buffer = $("<div class='missing-image'><i class='octicon octicon-circle-slash'></i></div>")
|
||||
this.$buffer = $(`<div class='missing-image'>${frappe.utils.icon('restriction', 'md')}</div>`)
|
||||
.appendTo(this.$body);
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
frappe.ui.form.ControlInt = frappe.ui.form.ControlData.extend({
|
||||
trigger_change_on_input_event: false,
|
||||
make: function () {
|
||||
this._super();
|
||||
// $(this.label_area).addClass('pull-right');
|
||||
|
|
|
|||
|
|
@ -9,16 +9,17 @@ import Awesomplete from 'awesomplete';
|
|||
frappe.ui.form.recent_link_validations = {};
|
||||
|
||||
frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
|
||||
trigger_change_on_input_event: false,
|
||||
make_input: function() {
|
||||
var me = this;
|
||||
// line-height: 1 is for Mozilla 51, shows extra padding otherwise
|
||||
$('<div class="link-field ui-front" style="position: relative; line-height: 1;">\
|
||||
<input type="text" class="input-with-feedback form-control">\
|
||||
<span class="link-btn">\
|
||||
<a class="btn-open no-decoration" title="' + __("Open Link") + '">\
|
||||
<i class="octicon octicon-arrow-right"></i></a>\
|
||||
</span>\
|
||||
</div>').prependTo(this.input_area);
|
||||
$(`<div class="link-field ui-front" style="position: relative;">
|
||||
<input type="text" class="input-with-feedback form-control">
|
||||
<span class="link-btn">
|
||||
<a class="btn-open no-decoration" title="${__("Open Link")}">
|
||||
${frappe.utils.icon('arrow-right', 'xs')}
|
||||
</a>
|
||||
</span>
|
||||
</div>`).prependTo(this.input_area);
|
||||
this.$input_area = $(this.input_area);
|
||||
this.$input = this.$input_area.find('input');
|
||||
this.$link = this.$input_area.find('.link-btn');
|
||||
|
|
@ -135,7 +136,7 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
|
|||
return $('<li></li>')
|
||||
.data('item.autocomplete', d)
|
||||
.prop('aria-selected', 'false')
|
||||
.html('<a><p>' + html + '</p></a>')
|
||||
.html(`<a><p class="ellipsis" title="${_label}">${html}</p></a>`)
|
||||
.get(0);
|
||||
},
|
||||
sort: function() {
|
||||
|
|
@ -235,18 +236,16 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
|
|||
});
|
||||
|
||||
this.$input.on("awesomplete-open", () => {
|
||||
let modal = this.$input.parents('.modal-dialog')[0];
|
||||
if (modal) {
|
||||
$(modal).removeClass("modal-dialog-scrollable");
|
||||
}
|
||||
this.toggle_container_scroll('.modal-dialog', 'modal-dialog-scrollable');
|
||||
this.toggle_container_scroll('.grid-form-body .form-area', 'scrollable');
|
||||
|
||||
this.autocomplete_open = true;
|
||||
});
|
||||
|
||||
this.$input.on("awesomplete-close", () => {
|
||||
let modal = this.$input.parents('.modal-dialog')[0];
|
||||
if (modal) {
|
||||
$(modal).addClass("modal-dialog-scrollable");
|
||||
}
|
||||
this.toggle_container_scroll('.modal-dialog', 'modal-dialog-scrollable', true);
|
||||
this.toggle_container_scroll('.grid-form-body .form-area', 'scrollable', true);
|
||||
|
||||
this.autocomplete_open = false;
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
frappe.ui.form.ControlMultiSelectList = frappe.ui.form.ControlData.extend({
|
||||
trigger_change_on_input_event: false,
|
||||
make_input() {
|
||||
let template = `
|
||||
<div class="multiselect-list dropdown">
|
||||
|
|
|
|||
|
|
@ -84,12 +84,12 @@ frappe.ui.form.ControlMultiSelectPills = frappe.ui.form.ControlAutocomplete.exte
|
|||
|
||||
get_pill_html(value) {
|
||||
const encoded_value = encodeURIComponent(value);
|
||||
return `<div class="btn-group tb-selected-value" data-value="${encoded_value}">
|
||||
<button class="btn btn-default btn-xs btn-link-to-form">${__(value)}</button>
|
||||
<button class="btn btn-default btn-xs btn-remove">
|
||||
${frappe.utils.icon('close')}
|
||||
return `
|
||||
<button class="data-pill btn tb-selected-value" data-value="${encoded_value}">
|
||||
<span class="btn-link-to-form">${__(value)}</span>
|
||||
<span class="btn-remove">${frappe.utils.icon('close')}</span>
|
||||
</button>
|
||||
</div>`;
|
||||
`;
|
||||
},
|
||||
|
||||
get_awesomplete_settings() {
|
||||
|
|
|
|||
|
|
@ -1,22 +1,24 @@
|
|||
frappe.ui.form.ControlRating = frappe.ui.form.ControlInt.extend({
|
||||
make_input() {
|
||||
this._super();
|
||||
let stars = '';
|
||||
[1, 2, 3, 4, 5].forEach(i => {
|
||||
stars += `<svg class="icon icon-md" data-rating=${i}>
|
||||
<use href="#icon-star"></use>
|
||||
</svg>`;
|
||||
});
|
||||
const star_template = `
|
||||
<div class="rating">
|
||||
<i class="fa fa-fw fa-star" data-rating=1></i>
|
||||
<i class="fa fa-fw fa-star" data-rating=2></i>
|
||||
<i class="fa fa-fw fa-star" data-rating=3></i>
|
||||
<i class="fa fa-fw fa-star" data-rating=4></i>
|
||||
<i class="fa fa-fw fa-star" data-rating=5></i>
|
||||
${stars}
|
||||
</div>
|
||||
`;
|
||||
|
||||
$(this.input_area).html(star_template);
|
||||
|
||||
$(this.input_area).find('i').hover((ev) => {
|
||||
$(this.input_area).find('svg').hover((ev) => {
|
||||
const el = $(ev.currentTarget);
|
||||
let star_value = el.data('rating');
|
||||
el.parent().children('i.fa').each( function(e) {
|
||||
el.parent().children('svg').each( function(e) {
|
||||
if (e < star_value) {
|
||||
$(this).addClass('star-hover');
|
||||
} else {
|
||||
|
|
@ -25,16 +27,16 @@ frappe.ui.form.ControlRating = frappe.ui.form.ControlInt.extend({
|
|||
});
|
||||
}, (ev) => {
|
||||
const el = $(ev.currentTarget);
|
||||
el.parent().children('i.fa').each( function() {
|
||||
el.parent().children('svg').each( function() {
|
||||
$(this).removeClass('star-hover');
|
||||
});
|
||||
});
|
||||
|
||||
$(this.input_area).find('i').click((ev) => {
|
||||
$(this.input_area).find('svg').click((ev) => {
|
||||
const el = $(ev.currentTarget);
|
||||
let star_value = el.data('rating');
|
||||
el.parent().children('i.fa').each( function(e) {
|
||||
if (e < star_value){
|
||||
el.parent().children('svg').each( function(e) {
|
||||
if (e < star_value) {
|
||||
$(this).addClass('star-click');
|
||||
} else {
|
||||
$(this).removeClass('star-click');
|
||||
|
|
@ -50,8 +52,8 @@ frappe.ui.form.ControlRating = frappe.ui.form.ControlInt.extend({
|
|||
return cint(this.value, null);
|
||||
},
|
||||
set_formatted_input(value) {
|
||||
let el = $(this.input_area).find('i');
|
||||
el.children('i.fa').prevObject.each( function(e) {
|
||||
let el = $(this.input_area).find('svg');
|
||||
el.children('svg').prevObject.each( function(e) {
|
||||
if (e < value) {
|
||||
$(this).addClass('star-click');
|
||||
} else {
|
||||
|
|
@ -59,4 +61,4 @@ frappe.ui.form.ControlRating = frappe.ui.form.ControlInt.extend({
|
|||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ frappe.ui.form.ControlSignature = frappe.ui.form.ControlData.extend({
|
|||
|
||||
this.img_wrapper = $(`<div class="signature-display">
|
||||
<div class="missing-image attach-missing-image">
|
||||
<i class="octicon octicon-circle-slash"></i>
|
||||
${frappe.utils.icon('restriction', 'md')}</i>
|
||||
</div></div>`)
|
||||
.appendTo(this.wrapper);
|
||||
this.img = $("<img class='img-responsive attach-image-display'>")
|
||||
|
|
@ -29,15 +29,21 @@ frappe.ui.form.ControlSignature = frappe.ui.form.ControlData.extend({
|
|||
let width = this.body.width();
|
||||
if (width > 0 && !this.$pad) {
|
||||
this.$pad = this.body.jSignature({
|
||||
height: 300,
|
||||
height: 200,
|
||||
color: "var(--text-color)",
|
||||
width: this.body.width(),
|
||||
lineWidth: 3
|
||||
lineWidth: 2,
|
||||
"background-color": "var(--control-bg)"
|
||||
}).on('change',
|
||||
this.on_save_sign.bind(this));
|
||||
this.load_pad();
|
||||
this.$reset_button_wrapper = $(`<div class="signature-btn-row">
|
||||
<a href="#" type="button" class="signature-reset btn btn-default">
|
||||
<i class="glyphicon glyphicon-repeat"></i></a>`)
|
||||
this.$reset_button_wrapper = $(`
|
||||
<div class="signature-btn-row">
|
||||
<a href="#" type="button" class="signature-reset btn icon-btn">
|
||||
${frappe.utils.icon('refresh', 'sm')}
|
||||
</a>
|
||||
</div>
|
||||
`)
|
||||
.appendTo(this.$pad)
|
||||
.on("click", '.signature-reset', () => {
|
||||
this.on_reset_sign();
|
||||
|
|
|
|||
|
|
@ -123,12 +123,12 @@ frappe.ui.form.ControlTableMultiSelect = frappe.ui.form.ControlLink.extend({
|
|||
},
|
||||
get_pill_html(value) {
|
||||
const encoded_value = encodeURIComponent(value);
|
||||
return `<div class="btn-group tb-selected-value" data-value="${encoded_value}">
|
||||
<button class="btn btn-default btn-xs btn-link-to-form">${__(value)}</button>
|
||||
<button class="btn btn-default btn-xs btn-remove">
|
||||
${frappe.utils.icon('close')}
|
||||
return `
|
||||
<button class="data-pill btn tb-selected-value" data-value="${encoded_value}">
|
||||
<span class="btn-link-to-form">${__(value)}</span>
|
||||
<span class="btn-remove">${frappe.utils.icon('close')}</span>
|
||||
</button>
|
||||
</div>`;
|
||||
`;
|
||||
},
|
||||
get_options() {
|
||||
return (this.get_link_field() || {}).options;
|
||||
|
|
|
|||
|
|
@ -317,7 +317,7 @@ class FormTimeline extends BaseTimeline {
|
|||
custom_timeline_contents.push({
|
||||
icon: custom_item.icon,
|
||||
icon_size: 'sm',
|
||||
is_card: custom_item.show_card,
|
||||
is_card: custom_item.is_card,
|
||||
creation: custom_item.creation,
|
||||
content: custom_item.content || frappe.render_template(custom_item.template, custom_item.template_data),
|
||||
});
|
||||
|
|
@ -509,4 +509,4 @@ class FormTimeline extends BaseTimeline {
|
|||
}
|
||||
}
|
||||
|
||||
export default FormTimeline;
|
||||
export default FormTimeline;
|
||||
|
|
|
|||
|
|
@ -564,13 +564,8 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
let me = this;
|
||||
return new Promise((resolve, reject) => {
|
||||
btn && $(btn).prop("disabled", true);
|
||||
$(document.activeElement).blur();
|
||||
|
||||
frappe.ui.form.close_grid_form();
|
||||
// let any pending js process finish
|
||||
setTimeout(function() {
|
||||
me.validate_and_save(save_action, callback, btn, on_error, resolve, reject);
|
||||
}, 100);
|
||||
me.validate_and_save(save_action, callback, btn, on_error, resolve, reject);
|
||||
}).then(() => {
|
||||
me.show_success_action();
|
||||
}).catch((e) => {
|
||||
|
|
@ -1503,7 +1498,7 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
|
||||
const escaped_name = encodeURIComponent(value);
|
||||
|
||||
return `<a class="indicator ${get_color(doc || {})}" href="/app/${frappe.router.slug(df.options)}/${escaped_name}" data-doctype="${doctype}" data-name="${value}">${label}</a>'`;
|
||||
return `<a class="indicator ${get_color(doc || {})}" href="/app/${frappe.router.slug(df.options)}/${escaped_name}" data-doctype="${doctype}" data-name="${value}">${label}</a>`;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,11 +61,14 @@ frappe.form.formatters = {
|
|||
return frappe.form.formatters._right(flt(value, precision) + "%", options);
|
||||
},
|
||||
Rating: function(value) {
|
||||
return `<span class="rating">
|
||||
${Array.from(new Array(5)).map((_, i) =>
|
||||
`<i class="fa fa-fw fa-star ${i < (value || 0) ? "star-click": "" } star-icon" data-idx="${(i+1)}"></i>`
|
||||
).join('')}
|
||||
</span>`;
|
||||
const rating_html = `${[1, 2, 3, 4, 5].map(i =>
|
||||
`<svg class="icon icon-md ${i <= (value || 0) ? "star-click": "" }" data-idx="${i}">
|
||||
<use href="#icon-star"></use>
|
||||
</svg>`
|
||||
).join('')}`;
|
||||
return `<div class="rating">
|
||||
${rating_html}
|
||||
</div>`;
|
||||
},
|
||||
Currency: function (value, docfield, options, doc) {
|
||||
var currency = frappe.meta.get_field_currency(docfield, doc);
|
||||
|
|
|
|||
|
|
@ -268,7 +268,7 @@ export default class Grid {
|
|||
}
|
||||
|
||||
refresh(force) {
|
||||
if (this.frm.setting_dependency) return;
|
||||
if (this.frm && this.frm.setting_dependency) return;
|
||||
|
||||
this.data = this.get_data();
|
||||
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ export default class GridRow {
|
|||
this.open_form_button = $(`
|
||||
<div class="btn-open-row">
|
||||
<a>${frappe.utils.icon('edit', 'xs')}</a>
|
||||
<div class="hidden-xs edit-grid-row">Edit</div>
|
||||
<div class="hidden-xs edit-grid-row">${ __("Edit") }</div>
|
||||
</div>
|
||||
`)
|
||||
.appendTo($('<div class="col col-xs-1"></div>').appendTo(this.row))
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ export default class GridRowForm {
|
|||
</div>
|
||||
</div>
|
||||
<div class="grid-form-body">
|
||||
<div class="form-area"></div>
|
||||
<div class="form-area scrollable"></div>
|
||||
<div class="grid-footer-toolbar hidden-xs flex justify-between">
|
||||
<div class="grid-shortcuts">
|
||||
<span> ${frappe.utils.icon("keyboard", "md")} </span>
|
||||
|
|
|
|||
|
|
@ -152,9 +152,13 @@ frappe.ui.form.LinkSelector = Class.extend({
|
|||
d = me.target.add_new_row();
|
||||
},
|
||||
() => frappe.timeout(0.1),
|
||||
() => frappe.model.set_value(d.doctype, d.name, me.fieldname, value),
|
||||
() => frappe.timeout(0.5),
|
||||
() => frappe.model.set_value(d.doctype, d.name, me.qty_fieldname, data.qty),
|
||||
() => {
|
||||
let args = {};
|
||||
args[me.fieldname] = value;
|
||||
args[me.qty_fieldname] = data.qty;
|
||||
|
||||
return frappe.model.set_value(d.doctype, d.name, args);
|
||||
},
|
||||
() => frappe.show_alert(__("Added {0} ({1})", [value, data.qty]))
|
||||
]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ frappe.ui.form.Sidebar = class {
|
|||
if (follow == null) {
|
||||
follow = this.frm.get_docinfo().is_document_followed;
|
||||
}
|
||||
this.follow_button.text(follow ? "Unfollow" : "Follow");
|
||||
this.follow_button.text(follow ? __("Unfollow") : __("Follow"));
|
||||
}
|
||||
|
||||
refresh_like() {
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@
|
|||
</a>
|
||||
<ul class="dropdown-menu list-stats-dropdown" role="menu">
|
||||
<div class="dropdown-search">
|
||||
<input type="text" placeholder="Search" data-element="search" class="form-control input-xs">
|
||||
<input type="text" placeholder={{__("Search") }} data-element="search" class="form-control input-xs">
|
||||
</div>
|
||||
<div class="stat-result">
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -164,8 +164,8 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
|
|||
const match_rules_list = frappe.perm.get_match_rules(this.doctype);
|
||||
if (match_rules_list.length) {
|
||||
this.restricted_list = $(
|
||||
`<button class="btn btn-default btn-xs restricted-button flex align-center">
|
||||
${frappe.utils.icon('lock', 'xs')}
|
||||
`<button class="btn btn-xs restricted-button flex align-center">
|
||||
${frappe.utils.icon('restriction', 'xs')}
|
||||
</button>`
|
||||
).click(() => this.show_restrictions(match_rules_list)).appendTo(this.page.page_form);
|
||||
}
|
||||
|
|
@ -676,7 +676,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
|
|||
|
||||
if (col.type === "Tag") {
|
||||
const tags_display_class = !this.tags_shown ? 'hide' : '';
|
||||
let tags_html = doc._user_tags ? this.get_tags_html(doc._user_tags) : '<div class="tags-empty">-</div>';
|
||||
let tags_html = doc._user_tags ? this.get_tags_html(doc._user_tags, 2) : '<div class="tags-empty">-</div>';
|
||||
return `
|
||||
<div class="list-row-col tag-col ${tags_display_class} hidden-xs ellipsis">
|
||||
${tags_html}
|
||||
|
|
@ -732,7 +732,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
|
|||
html = df.options ? `<img src="${doc[df.options]}"
|
||||
style="max-height: 30px; max-width: 100%;">`
|
||||
: `<div class="missing-image small">
|
||||
<span class="octicon octicon-circle-slash"></span>
|
||||
${frappe.utils.icon('restriction')}
|
||||
</div>`;
|
||||
} else if (df.fieldtype === "Select") {
|
||||
html = `<span class="filterable indicator-pill ${frappe.utils.guess_colour(
|
||||
|
|
@ -790,13 +790,19 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
|
|||
`;
|
||||
}
|
||||
|
||||
get_tags_html(user_tags) {
|
||||
get_tags_html(user_tags, limit, colored=false) {
|
||||
let get_tag_html = tag => {
|
||||
let color = '', style = '';
|
||||
if (tag) {
|
||||
return `<div class="tag-pill ellipsis" title="${tag}">${tag}</div>`;
|
||||
if (colored) {
|
||||
color = frappe.get_palette(tag);
|
||||
style = `background-color: var(${color[0]}); color: var(${color[1]})`;
|
||||
}
|
||||
|
||||
return `<div class="tag-pill ellipsis" title="${tag}" style="${style}">${tag}</div>`;
|
||||
}
|
||||
};
|
||||
return user_tags.split(',').slice(1, 3).map(get_tag_html).join('');
|
||||
return user_tags.split(',').slice(1, limit + 1).map(get_tag_html).join('');
|
||||
}
|
||||
|
||||
get_meta_html(doc) {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ frappe.views.ListViewSelect = class ListViewSelect {
|
|||
add_view_to_menu(view, action) {
|
||||
let $el = this.page.add_custom_menu_item(
|
||||
this.parent,
|
||||
view,
|
||||
__(view),
|
||||
action,
|
||||
true,
|
||||
null,
|
||||
|
|
@ -51,10 +51,15 @@ frappe.views.ListViewSelect = class ListViewSelect {
|
|||
action: () => this.set_route("report"),
|
||||
current_view_handler: () => {
|
||||
const reports = this.get_reports();
|
||||
this.setup_dropdown_in_sidebar("Report", reports, {
|
||||
label: __("Report Builder"),
|
||||
action: () => this.set_route("report")
|
||||
});
|
||||
let default_action = {};
|
||||
// Only add action if current route is not report builder
|
||||
if (frappe.get_route().length > 3) {
|
||||
default_action = {
|
||||
label: __("Report Builder"),
|
||||
action: () => this.set_route("report")
|
||||
};
|
||||
}
|
||||
this.setup_dropdown_in_sidebar("Report", reports, default_action);
|
||||
}
|
||||
},
|
||||
Dashboard: {
|
||||
|
|
@ -147,8 +152,9 @@ frappe.views.ListViewSelect = class ListViewSelect {
|
|||
${__("No {} Found", [view])}
|
||||
</div>`;
|
||||
} else {
|
||||
const page_name = this.get_page_name();
|
||||
items.map(item => {
|
||||
if (item.name == this.get_page_name()) {
|
||||
if (item.name.toLowerCase() == page_name.toLowerCase()) {
|
||||
placeholder = item.name;
|
||||
}
|
||||
html += `<li><a class="dropdown-item" href="${item.route}">${
|
||||
|
|
@ -212,7 +218,7 @@ frappe.views.ListViewSelect = class ListViewSelect {
|
|||
const report_type =
|
||||
r.report_type === "Report Builder"
|
||||
? `/app/list/${r.ref_doctype}/report`
|
||||
: "query-report";
|
||||
: "/app/query-report";
|
||||
|
||||
const route =
|
||||
r.route || report_type + "/" + (r.title || r.name);
|
||||
|
|
|
|||
|
|
@ -362,9 +362,7 @@ $.extend(frappe.model, {
|
|||
);
|
||||
} else if (!opts.source_name && opts.frm) {
|
||||
opts.source_name = opts.frm.doc.name;
|
||||
|
||||
// Allow opening a mapped doc without a source document name
|
||||
} else if (!opts.frm) {
|
||||
} else if (!opts.frm && !opts.source_name) {
|
||||
opts.source_name = null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -492,7 +492,7 @@ frappe.request.report_error = function(xhr, request_opts) {
|
|||
|
||||
if (!frappe.error_dialog) {
|
||||
frappe.error_dialog = new frappe.ui.Dialog({
|
||||
title: 'Server Error',
|
||||
title: __('Server Error'),
|
||||
primary_action_label: __('Report'),
|
||||
primary_action: () => {
|
||||
if (error_report_email) {
|
||||
|
|
|
|||
|
|
@ -12,16 +12,16 @@
|
|||
* // returns "data:image/pngbase64,..."
|
||||
*/
|
||||
frappe._.get_data_uri = element => {
|
||||
const $element = $(element);
|
||||
const width = $element.width();
|
||||
const height = $element.height();
|
||||
|
||||
const width = element.videoWidth;
|
||||
const height = element.videoHeight;
|
||||
|
||||
const $canvas = $('<canvas/>');
|
||||
$canvas[0].width = width;
|
||||
$canvas[0].height = height;
|
||||
|
||||
const context = $canvas[0].getContext('2d');
|
||||
context.drawImage($element[0], 0, 0, width, height);
|
||||
context.drawImage(element, 0, 0, width, height);
|
||||
|
||||
const data_uri = $canvas[0].toDataURL('image/png');
|
||||
|
||||
|
|
@ -55,52 +55,57 @@ frappe.ui.Capture = class {
|
|||
|
||||
render() {
|
||||
return navigator.mediaDevices.getUserMedia({ video: true }).then(stream => {
|
||||
this.stream = stream;
|
||||
|
||||
this.dialog = new frappe.ui.Dialog({
|
||||
title: this.options.title,
|
||||
animate: this.options.animate,
|
||||
action: {
|
||||
secondary: {
|
||||
label: '<b>×</b>'
|
||||
}
|
||||
}
|
||||
on_hide: () => this.stop_media_stream()
|
||||
});
|
||||
|
||||
this.dialog.get_close_btn().on('click', () => {
|
||||
this.hide();
|
||||
});
|
||||
|
||||
const set_take_photo_action = () => {
|
||||
this.dialog.set_primary_action(__('Take Photo'), () => {
|
||||
const data_url = frappe._.get_data_uri(video);
|
||||
$e.find('.fc-p').attr('src', data_url);
|
||||
|
||||
$e.find('.fc-s').hide();
|
||||
$e.find('.fc-p').show();
|
||||
|
||||
this.dialog.set_secondary_action_label(__('Retake'));
|
||||
this.dialog.get_secondary_btn().show();
|
||||
|
||||
this.dialog.set_primary_action(__('Submit'), () => {
|
||||
this.hide();
|
||||
if (this.callback) this.callback(data_url);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
set_take_photo_action();
|
||||
|
||||
this.dialog.set_secondary_action(() => {
|
||||
$e.find('.fc-p').hide();
|
||||
$e.find('.fc-s').show();
|
||||
|
||||
this.dialog.get_secondary_btn().hide();
|
||||
this.dialog.get_primary_btn().off('click');
|
||||
set_take_photo_action();
|
||||
});
|
||||
|
||||
this.dialog.get_secondary_btn().hide();
|
||||
|
||||
const $e = $(frappe.ui.Capture.TEMPLATE);
|
||||
|
||||
const video = $e.find('video')[0];
|
||||
video.srcObject = stream;
|
||||
video.srcObject = this.stream;
|
||||
video.play();
|
||||
|
||||
const $container = $(this.dialog.body);
|
||||
|
||||
$container.html($e);
|
||||
|
||||
$e.find('.fc-btf').hide();
|
||||
|
||||
$e.find('.fc-bcp').click(() => {
|
||||
const data_url = frappe._.get_data_uri(video);
|
||||
$e.find('.fc-p').attr('src', data_url);
|
||||
|
||||
$e.find('.fc-s').hide();
|
||||
$e.find('.fc-p').show();
|
||||
|
||||
$e.find('.fc-btu').hide();
|
||||
$e.find('.fc-btf').show();
|
||||
});
|
||||
|
||||
$e.find('.fc-br').click(() => {
|
||||
$e.find('.fc-p').hide();
|
||||
$e.find('.fc-s').show();
|
||||
|
||||
$e.find('.fc-btf').hide();
|
||||
$e.find('.fc-btu').show();
|
||||
});
|
||||
|
||||
$e.find('.fc-bs').click(() => {
|
||||
const data_url = frappe._.get_data_uri(video);
|
||||
this.hide();
|
||||
|
||||
if (this.callback) this.callback(data_url);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -123,6 +128,15 @@ frappe.ui.Capture = class {
|
|||
|
||||
hide() {
|
||||
if (this.dialog) this.dialog.hide();
|
||||
this.stop_media_stream();
|
||||
}
|
||||
|
||||
stop_media_stream() {
|
||||
if (this.stream) {
|
||||
this.stream.getTracks().forEach((track) => {
|
||||
track.stop();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
submit(fn) {
|
||||
|
|
@ -138,43 +152,9 @@ frappe.ui.Capture.ERR_MESSAGE = __('Unable to load camera.');
|
|||
frappe.ui.Capture.TEMPLATE = `
|
||||
<div class="frappe-capture">
|
||||
<div class="panel panel-default">
|
||||
<img class="fc-p img-responsive"/>
|
||||
<div class="fc-s embed-responsive embed-responsive-16by9">
|
||||
<video class="embed-responsive-item">${frappe.ui.Capture.ERR_MESSAGE}</video>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="fc-btf">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="pull-left">
|
||||
<button class="btn btn-default fc-br">
|
||||
<small>${__('Retake')}</small>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="pull-right">
|
||||
<button class="btn btn-primary fc-bs">
|
||||
<small>${__('Submit')}</small>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fc-btu">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
${''}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="pull-right">
|
||||
<button class="btn btn-default fc-bcp">
|
||||
<small>${__('Take Photo')}</small>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="embed-responsive embed-responsive-16by9">
|
||||
<img class="fc-p embed-responsive-item" style="object-fit: contain; display: none;"/>
|
||||
<video class="fc-s embed-responsive-item">${frappe.ui.Capture.ERR_MESSAGE}</video>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -39,7 +39,8 @@ frappe.ui.color = {
|
|||
};
|
||||
|
||||
if(Object.keys(shades).includes(shade)) {
|
||||
return frappe.ui.color_map[color_name][shades[shade]];
|
||||
const color = this.get_color(color_name);
|
||||
return color ? color[shades[shade]] : color_name;
|
||||
} else {
|
||||
// eslint-disable-next-line
|
||||
console.warn(`'shade' can be one of ${Object.keys(shades)} and not ${shade}`);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup {
|
|||
$(this.wrapper).addClass("modal-sm");
|
||||
else if (this.size == "large" )
|
||||
$(this.wrapper).addClass("modal-lg");
|
||||
else if (this.size == "extra-large" )
|
||||
$(this.wrapper).addClass("modal-xl");
|
||||
|
||||
this.make_head();
|
||||
this.modal_body = this.$wrapper.find(".modal-body");
|
||||
|
|
|
|||
|
|
@ -1,57 +0,0 @@
|
|||
// DropZone
|
||||
frappe.ui.DropZone = class
|
||||
{
|
||||
constructor (selector, options) {
|
||||
this.options = Object.assign({ }, frappe.ui.DropZone.OPTIONS, options);
|
||||
this.$container = $(selector);
|
||||
this.$wrapper = $(frappe.ui.DropZone.TEMPLATE);
|
||||
|
||||
this.make();
|
||||
}
|
||||
|
||||
make ( ) {
|
||||
const me = this;
|
||||
const $dropzone = this.$wrapper.find('.panel-body');
|
||||
const $title = $dropzone.find('.dropzone-title');
|
||||
$title.html(this.options.title);
|
||||
|
||||
$dropzone.on('dragover', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
$title.html(__('Drop'));
|
||||
});
|
||||
$dropzone.on('dragleave', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
$title.html(me.options.title);
|
||||
});
|
||||
$dropzone.on('drop', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
const files = e.originalEvent.dataTransfer.files;
|
||||
me.options.drop(files);
|
||||
|
||||
$title.html(me.options.title);
|
||||
});
|
||||
|
||||
this.$container.html(this.$wrapper);
|
||||
}
|
||||
};
|
||||
frappe.ui.DropZone.TEMPLATE =
|
||||
`
|
||||
<div class="panel panel-default"
|
||||
style="
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
margin-bottom: 0 !important
|
||||
">
|
||||
<div class="panel-body">
|
||||
<div class="dropzone-title text-muted text-center">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
frappe.ui.DropZone.OPTIONS =
|
||||
{
|
||||
title: __('Drop Here')
|
||||
};
|
||||
|
|
@ -214,6 +214,7 @@ frappe.ui.Filter = class {
|
|||
df.read_only = 0;
|
||||
df.hidden = 0;
|
||||
df.is_filter = true;
|
||||
delete df.hidden_due_to_dependency;
|
||||
|
||||
let c = condition ? condition : this.utils.get_default_condition(df);
|
||||
this.set_condition(c);
|
||||
|
|
|
|||
|
|
@ -74,8 +74,8 @@ frappe.ui.FilterGroup = class {
|
|||
}
|
||||
this.set_filter_events();
|
||||
}
|
||||
|
||||
hide_empty_filters && this.toggle_empty_filters(false);
|
||||
this.toggle_empty_filters(false);
|
||||
!hide_empty_filters && this.add_filter(this.doctype, 'name');
|
||||
});
|
||||
|
||||
this.filter_button.on('hidden.bs.popover', () => {
|
||||
|
|
@ -286,7 +286,9 @@ frappe.ui.FilterGroup = class {
|
|||
return $(`
|
||||
<div class="filter-area">
|
||||
<div class="filter-edit-area">
|
||||
<div class="text-muted empty-filters text-center">${__('No filters selected')}</div>
|
||||
<div class="text-muted empty-filters text-center">
|
||||
${__('No filters selected')}
|
||||
</div>
|
||||
</div>
|
||||
<hr class="divider"></hr>
|
||||
<div class="filter-action-buttons">
|
||||
|
|
|
|||
|
|
@ -3,12 +3,8 @@ frappe.provide('frappe.search');
|
|||
frappe.ui.Notifications = class Notifications {
|
||||
constructor() {
|
||||
this.tabs = {};
|
||||
frappe.model
|
||||
.with_doc('Notification Settings', frappe.session.user)
|
||||
.then(doc => {
|
||||
this.notifications_settings = doc;
|
||||
this.make();
|
||||
});
|
||||
this.notification_settings = frappe.boot.notification_settings;
|
||||
this.make();
|
||||
}
|
||||
|
||||
make() {
|
||||
|
|
@ -23,7 +19,6 @@ frappe.ui.Notifications = class Notifications {
|
|||
this.user = frappe.session.user;
|
||||
|
||||
this.setup_headers();
|
||||
let me = this;
|
||||
this.setup_dropdown_events();
|
||||
}
|
||||
|
||||
|
|
@ -109,7 +104,7 @@ frappe.ui.Notifications = class Notifications {
|
|||
let tabView = new item.view(
|
||||
item.el,
|
||||
this.dropdown,
|
||||
this.notifications_settings
|
||||
this.notification_settings
|
||||
);
|
||||
this.tabs[item.id] = tabView;
|
||||
}
|
||||
|
|
@ -444,4 +439,4 @@ class EventsView extends BaseNotificationsView {
|
|||
|
||||
this.container.html(html);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ frappe.ui.Page = Class.extend({
|
|||
this.get_main_icon(this.icon);
|
||||
|
||||
this.body = this.main = this.wrapper.find(".layout-main-section");
|
||||
this.container = this.wrapper.find(".page-body");
|
||||
this.sidebar = this.wrapper.find(".layout-side-section");
|
||||
this.footer = this.wrapper.find(".layout-footer");
|
||||
this.indicator = this.wrapper.find(".indicator-pill");
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<header class="navbar navbar-expand sticky-top" role="navigation">
|
||||
<div class="container">
|
||||
<a class="navbar-brand navbar-home" href="/app">
|
||||
<img class="app-logo" style="width: {{ navbar_settings.logo_width || 24 }}px" src="{{ frappe.app.logo_url }}">
|
||||
<img class="app-logo" style="width: {{ navbar_settings.logo_width || 24 }}px" src="{{ frappe.boot.app_logo_url }}">
|
||||
</a>
|
||||
<ul class="nav navbar-nav d-none d-sm-flex" id="navbar-breadcrumbs"></ul>
|
||||
<div class="collapse navbar-collapse justify-content-end">
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ frappe.search.SearchDialog = class {
|
|||
|
||||
let $results_list = $(`<div class="results-summary">
|
||||
<div class="result-section full-list ${type}-section col-sm-12">
|
||||
<div class="result-title">${type}</div>
|
||||
<div class="result-title"> ${ __(type) }</div>
|
||||
<div class="result-body">
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -340,7 +340,7 @@ frappe.search.SearchDialog = class {
|
|||
}
|
||||
|
||||
let $result_section = $(`<div class="col-sm-12 result-section" data-type="${type}">
|
||||
<div class="result-title">${type}</div>
|
||||
<div class="result-title">${__(type)}</div>
|
||||
<div class="result-body">
|
||||
${more_html}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
<div class="file-upload">
|
||||
<div class="input-upload">
|
||||
<input class="input-upload-file hidden" type="file" {{ opts.allow_multiple ? "multiple" : "" }} name="filedata" />
|
||||
<button class="btn btn-primary btn-sm btn-browse">{%= __("Browse") %}</button>
|
||||
</div>
|
||||
<div class="uploaded-filename hidden" style="width: 100%; margin-top: 12px;"></div>
|
||||
<div class="web-link-wrapper" style="width: calc(100% - 80px);">
|
||||
<span class="text-muted file-upload-or">{%= __("or") %}</span>
|
||||
<div class="input-link" style="width: calc(100% - 30px);">
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon">
|
||||
<span class="hidden-xs">{%= __("Web Link") %}</span>
|
||||
<i class="fa fa-link visible-xs"></i>
|
||||
</div>
|
||||
<input class="form-control" type="text" name="file_url"
|
||||
placeholder="{%= (opts.sample_url || "e.g. http://example.com/somefile.png") %}"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="private-file hidden">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" checked> {{ __("Private") }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
24
frappe/public/js/frappe/ui/workspace_loading_skeleton.html
Normal file
24
frappe/public/js/frappe/ui/workspace_loading_skeleton.html
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<div class="workspace-skeleton">
|
||||
<div class="widget-group">
|
||||
<div class="widget-group-head skeleton-header">
|
||||
<div class="widget-group-title skeleton-card"></div>
|
||||
</div>
|
||||
<div class="widget-group-body grid-col-3">
|
||||
<div class="widget shortcut-widget-box skeleton-card"></div>
|
||||
<div class="widget shortcut-widget-box skeleton-card"></div>
|
||||
<div class="widget shortcut-widget-box skeleton-card"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="widget-group skeleton-body">
|
||||
<div class="widget-group-head skeleton-header">
|
||||
<div class="widget-group-title skeleton-card"></div>
|
||||
</div>
|
||||
<div class="widget-group-body grid-col-3">
|
||||
<div class="widget links-widget-box skeleton-card"></div>
|
||||
<div class="widget links-widget-box skeleton-card"></div>
|
||||
<div class="widget links-widget-box skeleton-card"></div>
|
||||
<div class="widget links-widget-box skeleton-card"></div>
|
||||
<div class="widget links-widget-box skeleton-card"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
{% if show_label %}
|
||||
{{ __("Rating: ") }}
|
||||
{% endif %}
|
||||
{% for(var i=1, l=6; i<l; i++) { %}
|
||||
<i class="fa fa-fw {{ i<=rating? "fa-star": "fa-star-o" }} star-icon" data-idx=1></i>
|
||||
{% } %}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<div>
|
||||
{% if label && data.show_label %}
|
||||
{{ __("{0}: ", label) }}
|
||||
{% endif %}
|
||||
{% for(var i=1, l=6; i<l; i++) { %}
|
||||
<i class="fa fa-fw {{ i<=rating? "fa-star": "fa-star-o" }} star-icon" data-idx=1></i>
|
||||
{% } %}
|
||||
</div>
|
||||
|
|
@ -708,7 +708,7 @@ Object.assign(frappe.utils, {
|
|||
title = frappe._title_prefix + " " + title.replace(/<[^>]*>/g, "");
|
||||
}
|
||||
document.title = title;
|
||||
|
||||
|
||||
// save for re-routing
|
||||
const sub_path = frappe.router.get_sub_path();
|
||||
frappe.route_titles[sub_path] = title;
|
||||
|
|
@ -922,8 +922,8 @@ Object.assign(frappe.utils, {
|
|||
message: __('Copied to clipboard.')
|
||||
});
|
||||
},
|
||||
is_rtl() {
|
||||
return ["ar", "he", "fa"].includes(frappe.boot.lang);
|
||||
is_rtl(lang=null) {
|
||||
return ["ar", "he", "fa"].includes(lang || frappe.boot.lang);
|
||||
},
|
||||
bind_actions_with_object($el, object) {
|
||||
// remove previously bound event
|
||||
|
|
@ -1172,7 +1172,7 @@ Object.assign(frappe.utils, {
|
|||
} else if (type === "page") {
|
||||
route = item.name;
|
||||
} else if (type === "dashboard") {
|
||||
route = "dashboard/" + item.name;
|
||||
route = `dashboard-view/${item.name}`;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -125,8 +125,9 @@ frappe.breadcrumbs = {
|
|||
|
||||
set_list_breadcrumb(breadcrumbs) {
|
||||
const doctype = breadcrumbs.doctype;
|
||||
const doctype_meta = frappe.get_doc('DocType', doctype);
|
||||
if ((doctype==="User" && !frappe.user.has_role('System Manager'))
|
||||
|| frappe.get_doc('DocType', doctype).issingle) {
|
||||
|| (doctype_meta && doctype_meta.issingle)) {
|
||||
// no user listview for non-system managers and single doctypes
|
||||
} else {
|
||||
let route;
|
||||
|
|
@ -137,7 +138,7 @@ frappe.breadcrumbs = {
|
|||
} else {
|
||||
route = doctype_route;
|
||||
}
|
||||
$(`<li><a href="/app/${route}">${doctype}</a></li>`)
|
||||
$(`<li><a href="/app/${route}">${__(doctype)}</a></li>`)
|
||||
.appendTo(this.$breadcrumbs);
|
||||
}
|
||||
},
|
||||
|
|
@ -146,7 +147,7 @@ frappe.breadcrumbs = {
|
|||
const doctype = breadcrumbs.doctype;
|
||||
const docname = frappe.get_route()[2];
|
||||
let form_route = `/app/${frappe.router.slug(doctype)}/${docname}`;
|
||||
$(`<li><a href="${form_route}">${docname}</a></li>`)
|
||||
$(`<li><a href="${form_route}">${__(docname)}</a></li>`)
|
||||
.appendTo(this.$breadcrumbs);
|
||||
|
||||
if (view === "form") {
|
||||
|
|
|
|||
|
|
@ -94,11 +94,15 @@ frappe.views.CalendarView = class CalendarView extends frappe.views.ListView {
|
|||
}
|
||||
|
||||
get required_libs() {
|
||||
return [
|
||||
let assets = [
|
||||
'assets/frappe/js/lib/fullcalendar/fullcalendar.min.css',
|
||||
'assets/frappe/js/lib/fullcalendar/fullcalendar.min.js',
|
||||
'assets/frappe/js/lib/fullcalendar/locale-all.js'
|
||||
];
|
||||
let user_language = frappe.boot.user.language;
|
||||
if (user_language && user_language !== 'en') {
|
||||
assets.push('assets/frappe/js/lib/fullcalendar/locale-all.js');
|
||||
}
|
||||
return assets;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ frappe.views.CommunicationComposer = Class.extend({
|
|||
label: __("Send me a copy"),
|
||||
fieldtype: "Check",
|
||||
fieldname: "send_me_a_copy",
|
||||
default: 1 // frappe.boot.user.send_me_a_copy
|
||||
default: frappe.boot.user.send_me_a_copy
|
||||
},
|
||||
{
|
||||
label: __("Send Read Receipt"),
|
||||
|
|
|
|||
|
|
@ -124,7 +124,12 @@ frappe.provide("frappe.views");
|
|||
const new_cards = state.cards.slice();
|
||||
new_cards[index] = card;
|
||||
updater.set({ cards: new_cards });
|
||||
fluxify.doAction('update_order');
|
||||
const args = {
|
||||
new: 1,
|
||||
name: card.name,
|
||||
colname: updated_doc[state.board.field_name],
|
||||
};
|
||||
fluxify.doAction('update_order_for_single_card', args);
|
||||
});
|
||||
} else {
|
||||
frappe.new_doc(this.doctype, doc);
|
||||
|
|
@ -155,6 +160,53 @@ frappe.provide("frappe.views");
|
|||
fluxify.doAction('update_card', updated_card);
|
||||
});
|
||||
},
|
||||
update_order_for_single_card: function(updater, card) {
|
||||
// cache original order
|
||||
const _cards = this.cards.slice();
|
||||
const _columns = this.columns.slice();
|
||||
let args = {};
|
||||
let method_name = "";
|
||||
|
||||
if (card.new) {
|
||||
method_name = "add_card";
|
||||
args = {
|
||||
board_name: this.board.name,
|
||||
docname: card.name,
|
||||
colname: card.colname,
|
||||
};
|
||||
} else {
|
||||
method_name = "update_order_for_single_card";
|
||||
args = {
|
||||
board_name: this.board.name,
|
||||
docname: unescape(card.name),
|
||||
from_colname: card.from_colname,
|
||||
to_colname: card.to_colname,
|
||||
old_index: card.old_index,
|
||||
new_index: card.new_index,
|
||||
};
|
||||
}
|
||||
|
||||
frappe.call({
|
||||
method: method_prefix + method_name,
|
||||
args: args,
|
||||
callback: (r) => {
|
||||
let board = r.message;
|
||||
let updated_cards = [{'name': card.name, 'column': card.to_colname || card.colname}];
|
||||
let cards = update_cards_column(updated_cards);
|
||||
let columns = prepare_columns(board.columns);
|
||||
updater.set({
|
||||
cards: cards,
|
||||
columns: columns
|
||||
});
|
||||
}
|
||||
}).fail(function() {
|
||||
// revert original order
|
||||
updater.set({
|
||||
cards: _cards,
|
||||
columns: _columns
|
||||
});
|
||||
});
|
||||
},
|
||||
update_order: function(updater) {
|
||||
// cache original order
|
||||
const _cards = this.cards.slice();
|
||||
|
|
@ -446,16 +498,24 @@ frappe.provide("frappe.views");
|
|||
group: "cards",
|
||||
animation: 150,
|
||||
dataIdAttr: 'data-name',
|
||||
forceFallback: true,
|
||||
onStart: function() {
|
||||
wrapper.find('.kanban-card.add-card').fadeOut(200, function() {
|
||||
wrapper.find('.kanban-cards').height('100vh');
|
||||
});
|
||||
},
|
||||
onEnd: function() {
|
||||
onEnd: function(e) {
|
||||
wrapper.find('.kanban-card.add-card').fadeIn(100);
|
||||
wrapper.find('.kanban-cards').height('auto');
|
||||
// update order
|
||||
fluxify.doAction('update_order');
|
||||
const args = {
|
||||
name: $(e.item).attr('data-name'),
|
||||
from_colname: $(e.from).parents('.kanban-column').attr('data-column-value'),
|
||||
to_colname: $(e.to).parents('.kanban-column').attr('data-column-value'),
|
||||
old_index: e.oldIndex,
|
||||
new_index: e.newIndex,
|
||||
};
|
||||
fluxify.doAction('update_order_for_single_card', args);
|
||||
},
|
||||
onAdd: function() {
|
||||
},
|
||||
|
|
@ -546,14 +606,24 @@ frappe.provide("frappe.views");
|
|||
var opts = {
|
||||
name: card.name,
|
||||
title: remove_img_tags(card.title),
|
||||
disable_click: card._disable_click ? 'disable-click' : ''
|
||||
disable_click: card._disable_click ? 'disable-click' : '',
|
||||
creation: card.creation,
|
||||
};
|
||||
self.$card = $(frappe.render_template('kanban_card', opts))
|
||||
.appendTo(wrapper);
|
||||
}
|
||||
|
||||
function get_tags_html(card) {
|
||||
return card.tags
|
||||
? `<div class="kanban-tags">
|
||||
${cur_list.get_tags_html(card.tags, 3, true)}
|
||||
</div>`
|
||||
: '';
|
||||
}
|
||||
|
||||
function render_card_meta() {
|
||||
var html = "";
|
||||
let html = get_tags_html(card);
|
||||
|
||||
if (card.comment_count > 0)
|
||||
html +=
|
||||
`<span class="list-comment-count small text-muted ">
|
||||
|
|
@ -563,7 +633,10 @@ frappe.provide("frappe.views");
|
|||
|
||||
const $assignees_group = get_assignees_group();
|
||||
|
||||
html += `<span class="kanban-assignments"></span>`;
|
||||
html += `
|
||||
<span class="kanban-assignments"></span>
|
||||
${cur_list.get_like_html(card)}
|
||||
`;
|
||||
|
||||
if (card.color && frappe.ui.color.validate_hex(card.color)) {
|
||||
const $div = $('<div>');
|
||||
|
|
@ -630,6 +703,9 @@ frappe.provide("frappe.views");
|
|||
doctype: state.doctype,
|
||||
name: card.name,
|
||||
title: card[state.card_meta.title_field.fieldname],
|
||||
creation: moment(card.creation).format('MMM DD, YYYY'),
|
||||
_liked_by: card._liked_by,
|
||||
tags: card._user_tags,
|
||||
column: card[state.board.field_name],
|
||||
assigned_list: card.assigned_list || assigned_list,
|
||||
comment_count: card.comment_count || comment_count,
|
||||
|
|
|
|||
|
|
@ -2,9 +2,12 @@
|
|||
<a class="kanban-card-redirect" href="#">
|
||||
<div class="kanban-card content">
|
||||
<div class="kanban-title-area">
|
||||
<div class="kanban-card-title ellipsis" title="{{title}}">
|
||||
<div class="kanban-card-title" title="{{title}}">
|
||||
{{ title }}
|
||||
</div>
|
||||
<div class="kanban-card-creation">
|
||||
{{ creation }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="kanban-card-meta">
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -73,7 +73,11 @@ frappe.views.KanbanView = class KanbanView extends frappe.views.ListView {
|
|||
}
|
||||
|
||||
setup_view() {
|
||||
if (this.board.columns.length > 5) {
|
||||
this.page.container.addClass('full-width');
|
||||
}
|
||||
this.setup_realtime_updates();
|
||||
this.setup_like();
|
||||
}
|
||||
|
||||
set_fields() {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue