@@ -10,6 +10,7 @@ const path_join = path.resolve; | |||
const app = require('express')(); | |||
const http = require('http').Server(app); | |||
const io = require('socket.io')(http); | |||
const touch = require("touch"); | |||
// basic setup | |||
const sites_path = path_join(__dirname, '..', '..', '..', 'sites'); | |||
@@ -42,6 +43,7 @@ function build(minify) { | |||
for (const output_path in build_map) { | |||
pack(output_path, build_map[output_path], minify); | |||
} | |||
touch(path_join(sites_path, '.build'), {force:true}); | |||
} | |||
let socket_connection = false; | |||
@@ -228,7 +230,7 @@ function watch_less(ondirty) { | |||
const less_paths = app_paths.map(path => path_join(path, 'public', 'less')); | |||
const to_watch = filter_valid_paths(less_paths); | |||
chokidar.watch(to_watch).on('change', (filename, stats) => { | |||
chokidar.watch(to_watch).on('change', (filename) => { | |||
console.log(filename, 'dirty'); | |||
var last_index = filename.lastIndexOf('/'); | |||
const less_path = filename.slice(0, last_index); | |||
@@ -236,17 +238,18 @@ function watch_less(ondirty) { | |||
filename = filename.split('/').pop(); | |||
compile_less_file(filename, less_path, public_path) | |||
.then(css_file_path => { | |||
// build the target css file for which this css file is input | |||
for (const target in build_map) { | |||
const sources = build_map[target]; | |||
if (sources.includes(css_file_path)) { | |||
pack(target, sources); | |||
ondirty && ondirty(target); | |||
break; | |||
.then(css_file_path => { | |||
// build the target css file for which this css file is input | |||
for (const target in build_map) { | |||
const sources = build_map[target]; | |||
if (sources.includes(css_file_path)) { | |||
pack(target, sources); | |||
ondirty && ondirty(target); | |||
break; | |||
} | |||
} | |||
} | |||
}) | |||
}); | |||
touch(path_join(sites_path, '.build'), {force:true}); | |||
}); | |||
} | |||
@@ -265,6 +268,7 @@ function watch_js(ondirty) { | |||
// break; | |||
} | |||
} | |||
touch(path_join(sites_path, '.build'), {force:true}); | |||
}); | |||
} | |||
@@ -10,7 +10,7 @@ frappe.ui.form.on("Note", { | |||
// toggle edit | |||
frm.add_custom_button("Edit", function() { | |||
frm.events.set_editable(frm, !frm.is_note_editable); | |||
}) | |||
}); | |||
frm.events.set_editable(frm, false); | |||
} | |||
}, | |||
@@ -24,12 +24,12 @@ frappe.ui.form.on("Note", { | |||
frm.set_df_property("content", "read_only", editable ? 0: 1); | |||
// hide all other fields | |||
$.each(frm.fields_dict, function(fieldname, field) { | |||
$.each(frm.fields_dict, function(fieldname) { | |||
if(fieldname !== "content") { | |||
frm.set_df_property(fieldname, "hidden", editable ? 0: 1); | |||
} | |||
}) | |||
}); | |||
// no label, description for content either | |||
frm.get_field("content").toggle_label(editable); | |||
@@ -49,7 +49,7 @@ hr { | |||
border-top: none; | |||
} | |||
.email-footer-container { | |||
margin-top: 10px; | |||
margin-top: 30px; | |||
} | |||
.email-footer-container > div:not(:last-child) { | |||
margin-bottom: 5px; | |||
@@ -183,6 +183,25 @@ | |||
.listview-main-section .octicon-heart { | |||
cursor: pointer; | |||
} | |||
.listview-main-section .page-form { | |||
padding-left: 17px; | |||
} | |||
@media (max-width: 991px) { | |||
.listview-main-section .page-form { | |||
padding-left: 25px; | |||
} | |||
} | |||
.listview-main-section .page-form .octicon-search { | |||
float: left; | |||
padding-top: 7px; | |||
margin-left: -4px; | |||
margin-right: -4px; | |||
} | |||
@media (max-width: 991px) { | |||
.listview-main-section .page-form .octicon-search { | |||
margin-left: -12px; | |||
} | |||
} | |||
.like-action.octicon-heart { | |||
color: #ff5858; | |||
} | |||
@@ -486,7 +486,7 @@ frappe.Application = Class.extend({ | |||
return; | |||
} | |||
window.onbeforeunload = function () { | |||
if (frappe.flags.in_test) return false; | |||
if (frappe.flags.in_test) return null; | |||
var unsaved_docs = []; | |||
for (doctype in locals) { | |||
for (name in locals[doctype]) { | |||
@@ -233,6 +233,7 @@ frappe.ui.form.Timeline = Class.extend({ | |||
new frappe.views.CommunicationComposer({ | |||
doc: me.frm.doc, | |||
txt: "", | |||
subject: __('Reply'), | |||
frm: me.frm, | |||
last_email: last_email | |||
}); | |||
@@ -185,6 +185,9 @@ frappe.ui.BaseList = Class.extend({ | |||
} | |||
if (this.meta) { | |||
var filter_count = 1; | |||
$(`<span class="octicon octicon-search text-muted small"></span>`) | |||
.appendTo(this.page.page_form); | |||
this.page.add_field({ | |||
fieldtype: 'Data', | |||
label: 'ID', | |||
@@ -193,14 +196,14 @@ frappe.ui.BaseList = Class.extend({ | |||
onchange: () => { me.refresh(true); } | |||
}); | |||
this.meta.fields.forEach(function(df) { | |||
this.meta.fields.forEach(function(df, i) { | |||
if(df.in_standard_filter && !frappe.model.no_value_type.includes(df.fieldtype)) { | |||
let options = df.options; | |||
let condition = '='; | |||
let fieldtype = df.fieldtype; | |||
if (['Text', 'Small Text', 'Text Editor', 'Data'].includes(fieldtype)) { | |||
fieldtype = 'Data', | |||
condition = 'like' | |||
fieldtype = 'Data'; | |||
condition = 'like'; | |||
} | |||
if(df.fieldtype == "Select" && df.options) { | |||
options = df.options.split("\n"); | |||
@@ -209,7 +212,7 @@ frappe.ui.BaseList = Class.extend({ | |||
options = options.join("\n"); | |||
} | |||
} | |||
me.page.add_field({ | |||
let f = me.page.add_field({ | |||
fieldtype: fieldtype, | |||
label: __(df.label), | |||
options: options, | |||
@@ -217,6 +220,13 @@ frappe.ui.BaseList = Class.extend({ | |||
condition: condition, | |||
onchange: () => {me.refresh(true);} | |||
}); | |||
filter_count ++; | |||
if (filter_count > 3) { | |||
$(f.wrapper).addClass('hidden-sm').addClass('hidden-xs'); | |||
} | |||
if (filter_count > 5) { | |||
return false; | |||
} | |||
} | |||
}); | |||
} | |||
@@ -400,8 +400,13 @@ frappe.ui.Page = Class.extend({ | |||
.addClass('col-md-2') | |||
.attr("title", __(df.label)).tooltip(); | |||
// html fields in toolbar are only for display | |||
if (df.fieldtype=='HTML') { | |||
return; | |||
} | |||
// hidden fields dont have $input | |||
if(!f.$input) f.make_input(); | |||
if (!f.$input) f.make_input(); | |||
f.$input.addClass("input-sm").attr("placeholder", __(df.label)); | |||
@@ -12,7 +12,7 @@ frappe.views.CommunicationComposer = Class.extend({ | |||
make: function() { | |||
var me = this; | |||
this.dialog = new frappe.ui.Dialog({ | |||
title: (this.subject || ""), | |||
title: (this.subject || __("New Email")), | |||
no_submit_on_enter: true, | |||
fields: this.get_fields(), | |||
primary_action_label: __("Send"), | |||
@@ -444,6 +444,7 @@ frappe.views.CommunicationComposer = Class.extend({ | |||
send_email: function(btn, form_values, selected_attachments, print_html, print_format) { | |||
var me = this; | |||
me.dialog.hide(); | |||
if((form_values.send_email || form_values.communication_medium === "Email") && !form_values.recipients) { | |||
frappe.msgprint(__("Enter Email Recipient(s)")); | |||
@@ -496,8 +497,6 @@ frappe.views.CommunicationComposer = Class.extend({ | |||
[ frappe.utils.escape_html(r.message["emails_not_sent_to"]) ]) ); | |||
} | |||
me.dialog.hide(); | |||
if ((frappe.last_edited_communication[me.doc] || {})[me.key]) { | |||
delete frappe.last_edited_communication[me.doc][me.key]; | |||
} | |||
@@ -506,7 +505,7 @@ frappe.views.CommunicationComposer = Class.extend({ | |||
cur_frm.timeline.input.val(""); | |||
cur_frm.reload_doc(); | |||
} | |||
// try the success callback if it exists | |||
if (me.success) { | |||
try { | |||
@@ -515,10 +514,10 @@ frappe.views.CommunicationComposer = Class.extend({ | |||
console.log(e); | |||
} | |||
} | |||
} else { | |||
frappe.msgprint(__("There were errors while sending email. Please try again.")); | |||
// try the error callback if it exists | |||
if (me.error) { | |||
try { | |||
@@ -64,7 +64,7 @@ hr { | |||
} | |||
.email-footer-container { | |||
margin-top: 10px; | |||
margin-top: 30px; | |||
& > div:not(:last-child) { | |||
margin-bottom: 5px; | |||
@@ -226,8 +226,27 @@ | |||
padding: 5px 15px; | |||
} | |||
.listview-main-section .octicon-heart { | |||
cursor: pointer; | |||
.listview-main-section { | |||
.octicon-heart { | |||
cursor: pointer; | |||
} | |||
.page-form { | |||
padding-left: 17px; | |||
@media (max-width: @screen-sm) { | |||
padding-left: 25px; | |||
} | |||
.octicon-search { | |||
float: left; | |||
padding-top: 7px; | |||
margin-left: -4px; | |||
margin-right: -4px; | |||
@media (max-width: @screen-sm) { | |||
margin-left: -12px; | |||
} | |||
} | |||
} | |||
} | |||
.like-action.octicon-heart { | |||
@@ -20,7 +20,7 @@ | |||
<link rel="icon" | |||
href="{{ favicon or "/assets/frappe/images/favicon.png" }}" type="image/x-icon"> | |||
{% for include in include_css -%} | |||
<link type="text/css" rel="stylesheet" href="{{ include }}"> | |||
<link type="text/css" rel="stylesheet" href="{{ include }}?ver={{ build_version }}"> | |||
{%- endfor -%} | |||
</head> | |||
<body> | |||
@@ -55,7 +55,7 @@ | |||
</script> | |||
{% for include in include_js %} | |||
<script type="text/javascript" src="{{ include }}"></script> | |||
<script type="text/javascript" src="{{ include }}?ver={{ build_version }}"></script> | |||
{% endfor %} | |||
{% include "templates/includes/app_analytics/google_analytics.html" %} | |||
{% include "templates/includes/app_analytics/mixpanel_analytics.html" %} | |||
@@ -35,7 +35,8 @@ def get_context(context): | |||
# remove script tags from boot | |||
boot_json = re.sub("\<script\>[^<]*\</script\>", "", boot_json) | |||
return { | |||
context.update({ | |||
"no_cache": 1, | |||
"build_version": get_build_version(), | |||
"include_js": hooks["app_include_js"], | |||
"include_css": hooks["app_include_css"], | |||
@@ -46,7 +47,7 @@ def get_context(context): | |||
(boot.user.background_image or boot.default_background_image) or None), | |||
"google_analytics_id": frappe.conf.get("google_analytics_id"), | |||
"mixpanel_id": frappe.conf.get("mixpanel_id") | |||
} | |||
}) | |||
@frappe.whitelist() | |||
def get_desk_assets(build_version): | |||
@@ -64,7 +65,7 @@ def get_desk_assets(build_version): | |||
try: | |||
with open(os.path.join(frappe.local.sites_path, path) ,"r") as f: | |||
assets[0]["data"] = assets[0]["data"] + "\n" + text_type(f.read(), "utf-8") | |||
except IOError as e: | |||
except IOError: | |||
pass | |||
for path in data["include_css"]: | |||
@@ -78,5 +79,4 @@ def get_desk_assets(build_version): | |||
} | |||
def get_build_version(): | |||
return str(os.path.getmtime(os.path.join(frappe.local.sites_path, "assets", "js", | |||
"desk.min.js"))) | |||
return str(os.path.getmtime(os.path.join(frappe.local.sites_path, '.build'))) |
@@ -9,16 +9,16 @@ | |||
{% block page_content %} | |||
<!-- {{ for_test }} --> | |||
<section class='for-login'> | |||
<div class="login-content page-card" style="margin-top: 20px;"> | |||
<div class="login-content page-card" style="margin-top: 60px;"> | |||
<form class="form-signin form-login" role="form"> | |||
<div class="page-card-head"> | |||
<span class="indicator blue" data-text="{{ _("Sign In") }}"></span> | |||
</div> | |||
<input type="text" id="login_email" | |||
class="form-control" placeholder="{{ | |||
_('Email address or Mobile number') | |||
if frappe.utils.cint(frappe.db.get_value('System Settings', 'System Settings', 'allow_login_using_mobile_number')) | |||
class="form-control" placeholder="{{ | |||
_('Email address or Mobile number') | |||
if frappe.utils.cint(frappe.db.get_value('System Settings', 'System Settings', 'allow_login_using_mobile_number')) | |||
else _('Email address') }}" | |||
required autofocus> | |||
@@ -27,6 +27,7 @@ | |||
"nightwatch": "^0.9.16", | |||
"redis": "^2.7.1", | |||
"socket.io": "^2.0.1", | |||
"superagent": "^3.5.2" | |||
"superagent": "^3.5.2", | |||
"touch": "^3.1.0" | |||
} | |||
} |