diff --git a/frappe/automation/desk_page/tools/tools.json b/frappe/automation/desk_page/tools/tools.json index 235498724d..2164a4ce38 100644 --- a/frappe/automation/desk_page/tools/tools.json +++ b/frappe/automation/desk_page/tools/tools.json @@ -3,7 +3,7 @@ { "hidden": 0, "label": "Tools", - "links": "[\n {\n \"description\": \"Documents assigned to you and by you.\",\n \"label\": \"To Do\",\n \"name\": \"ToDo\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Event and other calendars.\",\n \"label\": \"Calendar\",\n \"link\": \"List/Event/Calendar\",\n \"name\": \"Event\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Private and public Notes.\",\n \"label\": \"Note\",\n \"name\": \"Note\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Files\",\n \"name\": \"File\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Activity log of all users.\",\n \"label\": \"Activity\",\n \"name\": \"activity\",\n \"type\": \"page\"\n }\n]" + "links": "[\n {\n \"description\": \"Documents assigned to you and by you.\",\n \"label\": \"To Do\",\n \"name\": \"ToDo\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Event and other calendars.\",\n \"label\": \"Calendar\",\n \"link\": \"List/Event/Calendar\",\n \"name\": \"Event\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Private and public Notes.\",\n \"label\": \"Note\",\n \"name\": \"Note\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Files\",\n \"name\": \"File\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Video\",\n \"name\": \"Video\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Activity log of all users.\",\n \"label\": \"Activity\",\n \"name\": \"activity\",\n \"type\": \"page\"\n }\n]" }, { "hidden": 0, @@ -32,7 +32,7 @@ "idx": 0, "is_standard": 1, "label": "Tools", - "modified": "2020-04-01 11:24:40.804346", + "modified": "2020-04-20 18:21:14.152537", "modified_by": "Administrator", "module": "Automation", "name": "Tools", diff --git a/frappe/core/doctype/video/__init__.py b/frappe/core/doctype/video/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/core/doctype/video/test_video.py b/frappe/core/doctype/video/test_video.py new file mode 100644 index 0000000000..0bed1e98d6 --- /dev/null +++ b/frappe/core/doctype/video/test_video.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2020, Frappe Technologies and Contributors +# See license.txt +from __future__ import unicode_literals + +# import frappe +import unittest + +class TestVideo(unittest.TestCase): + pass diff --git a/frappe/core/doctype/video/video.js b/frappe/core/doctype/video/video.js new file mode 100644 index 0000000000..36ea240a36 --- /dev/null +++ b/frappe/core/doctype/video/video.js @@ -0,0 +1,8 @@ +// Copyright (c) 2020, Frappe Technologies and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Video', { + // refresh: function(frm) { + + // } +}); diff --git a/frappe/core/doctype/video/video.json b/frappe/core/doctype/video/video.json new file mode 100644 index 0000000000..b0a154f5d4 --- /dev/null +++ b/frappe/core/doctype/video/video.json @@ -0,0 +1,93 @@ +{ + "actions": [], + "allow_import": 1, + "allow_rename": 1, + "autoname": "field:title", + "creation": "2018-10-17 05:47:13.087395", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "title", + "provider", + "url", + "column_break_4", + "publish_date", + "duration", + "section_break_7", + "description" + ], + "fields": [ + { + "fieldname": "title", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Title", + "reqd": 1, + "unique": 1 + }, + { + "fieldname": "provider", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Provider", + "options": "YouTube\nVimeo", + "reqd": 1 + }, + { + "fieldname": "url", + "fieldtype": "Data", + "in_list_view": 1, + "label": "URL", + "reqd": 1 + }, + { + "fieldname": "column_break_4", + "fieldtype": "Column Break" + }, + { + "fieldname": "publish_date", + "fieldtype": "Date", + "label": "Publish Date" + }, + { + "fieldname": "duration", + "fieldtype": "Data", + "label": "Duration" + }, + { + "fieldname": "section_break_7", + "fieldtype": "Section Break" + }, + { + "fieldname": "description", + "fieldtype": "Text Editor", + "in_list_view": 1, + "label": "Description", + "reqd": 1 + } + ], + "links": [], + "modified": "2020-04-17 13:34:06.461574", + "modified_by": "Administrator", + "module": "Core", + "name": "Video", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "All", + "share": 1, + "write": 1 + } + ], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/frappe/core/doctype/video/video.py b/frappe/core/doctype/video/video.py new file mode 100644 index 0000000000..fdbd3a1abe --- /dev/null +++ b/frappe/core/doctype/video/video.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2020, Frappe Technologies and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +# import frappe +from frappe.model.document import Document + +class Video(Document): + pass diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index 9ab1ef7799..ca6261076e 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -11,11 +11,12 @@ from frappe.model import default_fields, table_fields from frappe.model.naming import set_new_name from frappe.model.utils.link_count import notify_link_count from frappe.modules import load_doctype_module -from frappe.model import display_fieldtypes, data_fieldtypes +from frappe.model import display_fieldtypes from frappe.utils.password import get_decrypted_password, set_encrypted_password -from frappe.utils import (cint, flt, now, cstr, strip_html, getdate, get_datetime, to_timedelta, +from frappe.utils import (cint, flt, now, cstr, strip_html, sanitize_html, sanitize_email, cast_fieldtype) from frappe.utils.html_utils import unescape_html +from bs4 import BeautifulSoup max_positive_value = { 'smallint': 2 ** 15, @@ -678,7 +679,7 @@ class BaseDocument(object): # doesn't look like html so no need continue - elif "" in value and not ("" in value and not bool(BeautifulSoup(value, "html.parser").find()): # should be handled separately via the markdown converter function continue diff --git a/frappe/public/build.json b/frappe/public/build.json index 75a89e5010..7f55924a6b 100755 --- a/frappe/public/build.json +++ b/frappe/public/build.json @@ -90,6 +90,7 @@ "public/css/font-awesome.css", "public/css/octicons/octicons.css", "public/less/desk.less", + "public/less/module.less", "public/less/flex.less", "public/less/indicator.less", "public/less/avatar.less", diff --git a/frappe/public/js/frappe/views/breadcrumbs.js b/frappe/public/js/frappe/views/breadcrumbs.js index 2aef1a8218..1c1049391f 100644 --- a/frappe/public/js/frappe/views/breadcrumbs.js +++ b/frappe/public/js/frappe/views/breadcrumbs.js @@ -6,9 +6,10 @@ frappe.breadcrumbs = { preferred: { "File": "", + "Video": "", "Dashboard": "Customization", "Dashboard Chart": "Customization", - "Dashboard Chart Source": "Customization", + "Dashboard Chart Source": "Customization" }, module_map: { diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js index 17b32b3a52..ba290417f5 100755 --- a/frappe/public/js/frappe/views/communication.js +++ b/frappe/public/js/frappe/views/communication.js @@ -20,7 +20,8 @@ frappe.views.CommunicationComposer = Class.extend({ primary_action: function() { me.delete_saved_draft(); me.send_action(); - } + }, + minimizable: true }); ['recipients', 'cc', 'bcc'].forEach(field => { diff --git a/frappe/public/less/module.less b/frappe/public/less/module.less new file mode 100644 index 0000000000..f924778864 --- /dev/null +++ b/frappe/public/less/module.less @@ -0,0 +1,147 @@ +@import "variables.less"; + +.module-head { + padding: 15px 30px; + border-bottom: 1px solid @light-border-color; +} + +.module-head h1 { + padding: 0px; + margin: 0px; +} + +.module-body { + padding: 0px 15px; + + .section-head { + margin-bottom: 15px; + margin-top: 0px; + } +} + +.module-section { + border-bottom: 1px solid @light-border-color; + + .module-section-link { + line-height: 1.5em; + // font-size: 14px; + } +} + +.module-section-column { + padding: 30px; +} + +@media(min-width: @screen-xs) { + .module-section:nth-child(even) { + background-color: @light-bg; + } + + .module-section:last-child { + border-bottom: none; + } +} + +@media(max-width: @screen-sm) { + .module-body { + margin-top: 15px; + border-top: 1px solid @border-color; + } +} + +@media(max-width: @screen-xs) { + .module-body { + margin-top: 0; + border-top: 1px solid transparent; + } +} + +@media(max-width: @screen-xs) { + .module-section { + border: none; + } + + .module-section-column { + border-bottom: 1px solid @light-border-color; + } + + .module-section-column:nth-child(even) { + background-color: @light-bg; + } + + .module-section:last-child .module-section-column:last-child { + border-bottom: none; + } +} + + +.module-item { + margin: 0px; + padding: 7px; + font-weight: 400; + border-bottom: 1px solid @border-color; + cursor: pointer; + transition: 0.2s; + -webkit-transition: 0.2s; +} + +.module-item h4 { + display: inline-block; +} + +.module-item .module-item-description { + margin-top: -5px; +} + +.module-item .badge { + margin-top: -2px; + margin-left: 3px; +} + +.module-item:hover, .module-item:focus { + background-color: @panel-bg; +} + +.module-item:last-child { + border: none; +} + +.module-link.active .icon-chevron-right { + margin-top: 4px; + display: block !important; +} + +.module-item-progress { + margin-bottom: 10px; + height: 17px; +} + +.module-item-progress-total { + height: 7px; + background-color: #999999; + width: 0px; +} + +.module-item-progress-open { + height: 7px; + background-color: red; + width: 0px; +} + +@media(max-width: @screen-xs) { + + body[data-route^="Module"] { + .page-title { + width: 100%; + } + + + .page-actions { + display: none !important; + } + + .layout-main-section { + border-bottom: 0px; + } + } +} diff --git a/frappe/website/doctype/web_view/web_view.json b/frappe/website/doctype/web_view/web_view.json index 8c42f51421..d4ccbad0e4 100644 --- a/frappe/website/doctype/web_view/web_view.json +++ b/frappe/website/doctype/web_view/web_view.json @@ -3,7 +3,6 @@ "allow_guest_to_view": 1, "allow_import": 1, "allow_rename": 1, - "autoname": "field:title", "beta": 1, "creation": "2020-03-16 15:28:03.828741", "doctype": "DocType", @@ -117,7 +116,7 @@ "has_web_view": 1, "is_published_field": "published", "links": [], - "modified": "2020-04-19 12:25:48.014935", + "modified": "2020-04-22 00:54:23.413077", "modified_by": "Administrator", "module": "Website", "name": "Web View", diff --git a/rollup/config.js b/rollup/config.js index 93bb226927..5f0b2bc60a 100644 --- a/rollup/config.js +++ b/rollup/config.js @@ -11,6 +11,7 @@ const buble = require('rollup-plugin-buble'); const { terser } = require('rollup-plugin-terser'); const vue = require('rollup-plugin-vue'); const frappe_html = require('./frappe-html-plugin'); +const less_loader = require('./less-loader'); const production = process.env.FRAPPE_ENV === 'production'; @@ -116,6 +117,7 @@ function get_rollup_options_for_css(output_file, input_files) { // less -> css postcss({ extract: output_path, + loaders: [less_loader], use: [ ['less', { // import other less/css files starting from these folders @@ -130,7 +132,8 @@ function get_rollup_options_for_css(output_file, input_files) { path.resolve(bench_path, '**/*.scss'), path.resolve(bench_path, '**/*.css') ], - minimize: minimize_css + minimize: minimize_css, + sourceMap: output_file.startsWith('css/') && !production }) ]; diff --git a/rollup/less-loader.js b/rollup/less-loader.js new file mode 100644 index 0000000000..5c4c89f87b --- /dev/null +++ b/rollup/less-loader.js @@ -0,0 +1,54 @@ +const pify = require('pify'); +const importCwd = require('import-cwd'); +const path = require('path'); + +const getFileName = filepath => path.basename(filepath); + +function loadModule(moduleId) { + // Trying to load module normally (relative to plugin directory) + try { + return require(moduleId); + } catch (_) { + // Ignore error + } + + // Then, trying to load it relative to CWD + return importCwd.silent(moduleId); +} + +module.exports = { + name: 'less', + test: /\.less$/, + async process({ + code + }) { + const less = loadModule('less'); + if (!less) { + throw new Error('You need to install "less" packages in order to process Less files'); + } + + let { + css, + map, + imports + } = await pify(less.render.bind(less))(code, { + ...this.options, + sourceMap: this.sourceMap && { outputSourceFiles: true }, + filename: this.id + }); + + for (const dep of imports) { + this.dependencies.add(dep); + } + + if (map) { + map = JSON.parse(map); + map.sources = map.sources.map(source => getFileName(source)); + } + + return { + code: css, + map + }; + } +}; \ No newline at end of file