Merge branch 'develop' into bench_version_branch_commit
This commit is contained in:
commit
199990decc
25 changed files with 310 additions and 271 deletions
|
|
@ -89,7 +89,7 @@ class CommunicationEmailMixin:
|
|||
return self._final_cc
|
||||
|
||||
def get_mail_cc_with_displayname(self, is_inbound_mail_communcation=False, include_sender = False):
|
||||
cc_list = self.mail_cc(is_inbound_mail_communcation=False, include_sender = False)
|
||||
cc_list = self.mail_cc(is_inbound_mail_communcation=is_inbound_mail_communcation, include_sender = include_sender)
|
||||
return [self.get_email_with_displayname(email) for email in cc_list]
|
||||
|
||||
def mail_bcc(self, is_inbound_mail_communcation=False):
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@
|
|||
"label": "Field Type",
|
||||
"oldfieldname": "fieldtype",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "Attach\nAttach Image\nBarcode\nButton\nCheck\nCode\nColor\nColumn Break\nCurrency\nData\nDate\nDatetime\nDuration\nDynamic Link\nFloat\nGeolocation\nHTML\nImage\nInt\nLink\nLong Text\nMarkdown Editor\nPassword\nPercent\nRating\nRead Only\nSection Break\nSelect\nSmall Text\nTable\nTable MultiSelect\nText\nText Editor\nTime\nSignature",
|
||||
"options": "Attach\nAttach Image\nBarcode\nButton\nCheck\nCode\nColor\nColumn Break\nCurrency\nData\nDate\nDatetime\nDuration\nDynamic Link\nFloat\nFold\nGeolocation\nHeading\nHTML\nHTML Editor\nImage\nInt\nLink\nLong Text\nMarkdown Editor\nPassword\nPercent\nRead Only\nRating\nSection Break\nSelect\nSmall Text\nTable\nTable MultiSelect\nText\nText Editor\nTime\nSignature",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
|
|
@ -417,7 +417,7 @@
|
|||
"idx": 1,
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2020-10-29 06:14:43.073329",
|
||||
"modified": "2021-07-12 04:54:12.042319",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Custom",
|
||||
"name": "Custom Field",
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ from frappe import _
|
|||
from time import time
|
||||
from frappe.utils import now, getdate, cast_fieldtype, get_datetime
|
||||
from frappe.model.utils.link_count import flush_local_link_count
|
||||
from frappe.utils import cint
|
||||
|
||||
|
||||
class Database(object):
|
||||
|
|
@ -556,8 +555,7 @@ class Database(object):
|
|||
if not df:
|
||||
frappe.throw(_('Invalid field name: {0}').format(frappe.bold(fieldname)), self.InvalidColumnName)
|
||||
|
||||
if df.fieldtype in frappe.model.numeric_fieldtypes:
|
||||
val = cint(val)
|
||||
val = cast_fieldtype(df.fieldtype, val)
|
||||
|
||||
self.value_cache[doctype][fieldname] = val
|
||||
|
||||
|
|
|
|||
|
|
@ -452,6 +452,7 @@ def get_custom_report_list(module):
|
|||
"type": "Link",
|
||||
"link_type": "report",
|
||||
"doctype": r.ref_doctype,
|
||||
"dependencies": r.ref_doctype,
|
||||
"is_query_report": 1 if r.report_type in ("Query Report", "Script Report", "Custom Report") else 0,
|
||||
"label": _(r.name),
|
||||
"link_to": r.name,
|
||||
|
|
|
|||
|
|
@ -144,8 +144,8 @@ def upload_file():
|
|||
file_url = frappe.form_dict.file_url
|
||||
folder = frappe.form_dict.folder or 'Home'
|
||||
method = frappe.form_dict.method
|
||||
filename = frappe.form_dict.file_name
|
||||
content = None
|
||||
filename = None
|
||||
|
||||
if 'file' in files:
|
||||
file = files['file']
|
||||
|
|
@ -155,7 +155,7 @@ def upload_file():
|
|||
frappe.local.uploaded_file = content
|
||||
frappe.local.uploaded_filename = filename
|
||||
|
||||
if frappe.session.user == 'Guest' or (user and not user.has_desk_access()):
|
||||
if not file_url and (frappe.session.user == "Guest" or (user and not user.has_desk_access())):
|
||||
import mimetypes
|
||||
filetype = mimetypes.guess_type(filename)[0]
|
||||
if filetype not in ALLOWED_MIMETYPES:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"actions": [],
|
||||
"creation": "2019-06-14 00:08:37.255003",
|
||||
"doctype": "DocType",
|
||||
"engine": "InnoDB",
|
||||
|
|
@ -8,7 +9,10 @@
|
|||
"client_id",
|
||||
"client_secret",
|
||||
"sb_01",
|
||||
"api_key"
|
||||
"api_key",
|
||||
"section_break_7",
|
||||
"google_drive_picker_enabled",
|
||||
"app_id"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
|
|
@ -18,10 +22,12 @@
|
|||
"label": "Enable"
|
||||
},
|
||||
{
|
||||
"description": "The Client ID obtained from the Google Cloud Console under <a href=\"https://console.cloud.google.com/apis/credentials\">\n\"APIs & Services\" > \"Credentials\"\n</a>",
|
||||
"fieldname": "client_id",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Client ID"
|
||||
"label": "Client ID",
|
||||
"mandatory_depends_on": "google_drive_picker_enabled"
|
||||
},
|
||||
{
|
||||
"fieldname": "client_secret",
|
||||
|
|
@ -30,10 +36,11 @@
|
|||
"label": "Client Secret"
|
||||
},
|
||||
{
|
||||
"description": "Used For Google Maps Integration.",
|
||||
"description": "The browser API key obtained from the Google Cloud Console under <a href=\"https://console.cloud.google.com/apis/credentials\">\n\"APIs & Services\" > \"Credentials\"\n</a>",
|
||||
"fieldname": "api_key",
|
||||
"fieldtype": "Data",
|
||||
"label": "API Key"
|
||||
"label": "API Key",
|
||||
"mandatory_depends_on": "google_drive_picker_enabled"
|
||||
},
|
||||
{
|
||||
"depends_on": "enable",
|
||||
|
|
@ -46,10 +53,30 @@
|
|||
"fieldname": "sb_01",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "API Key"
|
||||
},
|
||||
{
|
||||
"depends_on": "google_drive_picker_enabled",
|
||||
"description": "The project number obtained from Google Cloud Console under <a href=\"https://console.cloud.google.com/iam-admin/settings\">\n\"IAM & Admin\" > \"Settings\"\n</a>",
|
||||
"fieldname": "app_id",
|
||||
"fieldtype": "Data",
|
||||
"label": "App ID",
|
||||
"mandatory_depends_on": "google_drive_picker_enabled"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_7",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Google Drive Picker"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "google_drive_picker_enabled",
|
||||
"fieldtype": "Check",
|
||||
"label": "Google Drive Picker Enabled"
|
||||
}
|
||||
],
|
||||
"issingle": 1,
|
||||
"modified": "2019-08-06 22:37:41.699703",
|
||||
"links": [],
|
||||
"modified": "2021-06-29 18:26:07.094851",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Integrations",
|
||||
"name": "Google Settings",
|
||||
|
|
@ -64,16 +91,6 @@
|
|||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"role": "All",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
|
|
|
|||
|
|
@ -2,11 +2,26 @@
|
|||
# Copyright (c) 2019, Frappe Technologies and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class GoogleSettings(Document):
|
||||
pass
|
||||
|
||||
def get_auth_url():
|
||||
return "https://www.googleapis.com/oauth2/v4/token"
|
||||
return "https://www.googleapis.com/oauth2/v4/token"
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_file_picker_settings():
|
||||
"""Return all the data FileUploader needs to start the Google Drive Picker."""
|
||||
google_settings = frappe.get_single("Google Settings")
|
||||
if not (google_settings.enable and google_settings.google_drive_picker_enabled):
|
||||
return {}
|
||||
|
||||
return {
|
||||
"enabled": True,
|
||||
"appId": google_settings.app_id,
|
||||
"developerKey": google_settings.api_key,
|
||||
"clientId": google_settings.client_id
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021, Frappe Technologies and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
|
||||
from .google_settings import get_file_picker_settings
|
||||
|
||||
class TestGoogleSettings(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
settings = frappe.get_single("Google Settings")
|
||||
settings.client_id = "test_client_id"
|
||||
settings.app_id = "test_app_id"
|
||||
settings.api_key = "test_api_key"
|
||||
settings.save()
|
||||
|
||||
def test_picker_disabled(self):
|
||||
"""Google Drive Picker should be disabled if it is not enabled in Google Settings."""
|
||||
frappe.db.set_value("Google Settings", None, "enable", 1)
|
||||
frappe.db.set_value("Google Settings", None, "google_drive_picker_enabled", 0)
|
||||
settings = get_file_picker_settings()
|
||||
|
||||
self.assertEqual(settings, {})
|
||||
|
||||
def test_google_disabled(self):
|
||||
"""Google Drive Picker should be disabled if Google integration is not enabled."""
|
||||
frappe.db.set_value("Google Settings", None, "enable", 0)
|
||||
frappe.db.set_value("Google Settings", None, "google_drive_picker_enabled", 1)
|
||||
settings = get_file_picker_settings()
|
||||
|
||||
self.assertEqual(settings, {})
|
||||
|
||||
def test_picker_enabled(self):
|
||||
"""If picker is enabled, get_file_picker_settings should return the credentials."""
|
||||
frappe.db.set_value("Google Settings", None, "enable", 1)
|
||||
frappe.db.set_value("Google Settings", None, "google_drive_picker_enabled", 1)
|
||||
settings = get_file_picker_settings()
|
||||
|
||||
self.assertEqual(True, settings.get("enabled", False))
|
||||
self.assertEqual("test_client_id", settings.get("clientId", ""))
|
||||
self.assertEqual("test_app_id", settings.get("appId", ""))
|
||||
self.assertEqual("test_api_key", settings.get("developerKey", ""))
|
||||
1
frappe/public/icons/social/google_drive.svg
Normal file
1
frappe/public/icons/social/google_drive.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg viewBox="0 0 87.3 78" xmlns="http://www.w3.org/2000/svg"><path d="m6.6 66.85 3.85 6.65c.8 1.4 1.95 2.5 3.3 3.3l13.75-23.8h-27.5c0 1.55.4 3.1 1.2 4.5z" fill="#0066da"/><path d="m43.65 25-13.75-23.8c-1.35.8-2.5 1.9-3.3 3.3l-25.4 44a9.06 9.06 0 0 0 -1.2 4.5h27.5z" fill="#00ac47"/><path d="m73.55 76.8c1.35-.8 2.5-1.9 3.3-3.3l1.6-2.75 7.65-13.25c.8-1.4 1.2-2.95 1.2-4.5h-27.502l5.852 11.5z" fill="#ea4335"/><path d="m43.65 25 13.75-23.8c-1.35-.8-2.9-1.2-4.5-1.2h-18.5c-1.6 0-3.15.45-4.5 1.2z" fill="#00832d"/><path d="m59.8 53h-32.3l-13.75 23.8c1.35.8 2.9 1.2 4.5 1.2h50.8c1.6 0 3.15-.45 4.5-1.2z" fill="#2684fc"/><path d="m73.4 26.5-12.7-22c-.8-1.4-1.95-2.5-3.3-3.3l-13.75 23.8 16.15 28h27.45c0-1.55-.4-3.1-1.2-4.5z" fill="#ffba00"/></svg>
|
||||
|
After Width: | Height: | Size: 742 B |
|
|
@ -63,6 +63,12 @@
|
|||
</svg>
|
||||
<div class="mt-1">{{ __('Camera') }}</div>
|
||||
</button>
|
||||
<button v-if="google_drive_settings.enabled" class="btn btn-file-upload" @click="show_google_drive_picker">
|
||||
<svg width="30" height="30">
|
||||
<image xlink:href="/assets/frappe/icons/social/google_drive.svg" width="30" height="30"/>
|
||||
</svg>
|
||||
<div class="mt-1">{{ __('Google Drive') }}</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="text-muted text-medium">
|
||||
{{ upload_notes }}
|
||||
|
|
@ -116,6 +122,7 @@
|
|||
import FilePreview from './FilePreview.vue';
|
||||
import FileBrowser from './FileBrowser.vue';
|
||||
import WebLink from './WebLink.vue';
|
||||
import GoogleDrivePicker from '../../integrations/google_drive_picker';
|
||||
|
||||
export default {
|
||||
name: 'FileUploader',
|
||||
|
|
@ -173,6 +180,24 @@ export default {
|
|||
currently_uploading: -1,
|
||||
show_file_browser: false,
|
||||
show_web_link: false,
|
||||
allow_take_photo: false,
|
||||
google_drive_settings: {
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.allow_take_photo = window.navigator.mediaDevices;
|
||||
if (frappe.user_id !== "Guest") {
|
||||
frappe.call({
|
||||
// method only available after login
|
||||
method: "frappe.integrations.doctype.google_settings.google_settings.get_file_picker_settings",
|
||||
callback: (resp) => {
|
||||
if (!resp.exc) {
|
||||
this.google_drive_settings = resp.message;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
@ -187,9 +212,6 @@ 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: {
|
||||
|
|
@ -408,6 +430,10 @@ export default {
|
|||
form_data.append('file_url', file.file_url);
|
||||
}
|
||||
|
||||
if (file.file_name) {
|
||||
form_data.append('file_name', file.file_name);
|
||||
}
|
||||
|
||||
if (this.doctype && this.docname) {
|
||||
form_data.append('doctype', this.doctype);
|
||||
form_data.append('docname', this.docname);
|
||||
|
|
@ -437,6 +463,25 @@ export default {
|
|||
);
|
||||
});
|
||||
},
|
||||
show_google_drive_picker() {
|
||||
let dialog = cur_dialog;
|
||||
dialog.hide();
|
||||
let google_drive = new GoogleDrivePicker({
|
||||
pickerCallback: data => this.google_drive_callback(data, dialog),
|
||||
...this.google_drive_settings
|
||||
});
|
||||
google_drive.loadPicker();
|
||||
},
|
||||
google_drive_callback(data, dialog) {
|
||||
if (data.action == google.picker.Action.PICKED) {
|
||||
this.upload_file({
|
||||
file_url: data.docs[0].url,
|
||||
file_name: data.docs[0].name
|
||||
});
|
||||
} else if (data.action == google.picker.Action.CANCEL) {
|
||||
dialog.show();
|
||||
}
|
||||
},
|
||||
url_to_file(url, filename, mime_type) {
|
||||
return fetch(url)
|
||||
.then(res => res.arrayBuffer())
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ frappe.ui.form.Dashboard = class FormDashboard {
|
|||
constructor(opts) {
|
||||
$.extend(this, opts);
|
||||
this.setup_dashboard_sections();
|
||||
this.set_open_count = frappe.utils.throttle(this.set_open_count, 500);
|
||||
}
|
||||
|
||||
setup_dashboard_sections() {
|
||||
|
|
@ -179,7 +178,6 @@ frappe.ui.form.Dashboard = class FormDashboard {
|
|||
return;
|
||||
}
|
||||
this.render_links();
|
||||
// this.set_open_count();
|
||||
show = true;
|
||||
}
|
||||
|
||||
|
|
@ -206,6 +204,7 @@ frappe.ui.form.Dashboard = class FormDashboard {
|
|||
$(this).removeClass('hidden');
|
||||
}
|
||||
});
|
||||
this.set_open_count();
|
||||
}
|
||||
|
||||
init_data() {
|
||||
|
|
|
|||
|
|
@ -1265,7 +1265,9 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
if (df && df[property] != value) {
|
||||
df[property] = value;
|
||||
if (table_field && table_row_name) {
|
||||
this.fields_dict[fieldname].grid.grid_rows_by_docname[table_row_name].refresh_field(fieldname);
|
||||
if (this.fields_dict[fieldname].grid.grid_rows_by_docname[table_row_name]) {
|
||||
this.fields_dict[fieldname].grid.grid_rows_by_docname[table_row_name].refresh_field(fieldname);
|
||||
}
|
||||
} else {
|
||||
this.refresh_field(fieldname);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,8 +171,8 @@ frappe.router = {
|
|||
} else {
|
||||
standard_route = ['List', doctype_route.doctype, frappe.utils.to_title_case(route[2])];
|
||||
if (route[3]) {
|
||||
// calendar / kanban / dashboard name
|
||||
standard_route.push(route[3]);
|
||||
// calendar / kanban / dashboard / folder name
|
||||
standard_route.push(...route.splice(3, route.length));
|
||||
}
|
||||
}
|
||||
return standard_route;
|
||||
|
|
@ -297,8 +297,8 @@ frappe.router = {
|
|||
if (route[2] && route[2] !== 'list' && !$.isPlainObject(route[2])) {
|
||||
new_route = [this.slug(route[1]), 'view', route[2].toLowerCase()];
|
||||
|
||||
// calendar / inbox
|
||||
if (route[3]) new_route.push(route[3]);
|
||||
// calendar / inbox / file folder
|
||||
if (route[3]) new_route.push(...route.slice(3, route.length));
|
||||
} else {
|
||||
if ($.isPlainObject(route[2])) {
|
||||
frappe.route_options = route[2];
|
||||
|
|
|
|||
|
|
@ -1202,6 +1202,8 @@ Object.assign(frappe.utils, {
|
|||
} else if (type === "report") {
|
||||
if (item.is_query_report) {
|
||||
route = "query-report/" + item.name;
|
||||
} else if (!item.doctype) {
|
||||
route = "/report/" + item.name;
|
||||
} else {
|
||||
route = frappe.router.slug(item.doctype) + "/view/report/" + item.name;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -315,7 +315,7 @@ frappe.views.FileView = class FileView extends frappe.views.ListView {
|
|||
acc += "/" + curr;
|
||||
}
|
||||
return acc;
|
||||
}, "/app/file");
|
||||
}, "/app/file/view");
|
||||
|
||||
return `<a href="${route}">${folder}</a>`;
|
||||
})
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ class DesktopPage {
|
|||
return;
|
||||
}
|
||||
this.refresh();
|
||||
}).finally(this.page.find('.workspace_loading_skeleton').remove);
|
||||
}).finally(() => this.page.find('.workspace_loading_skeleton').remove());
|
||||
}
|
||||
|
||||
refresh() {
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ export default class LinksWidget extends Widget {
|
|||
is_query_report: item.is_query_report
|
||||
};
|
||||
|
||||
if (item.link_type == "Report" && !item.is_query_report) {
|
||||
if (item.link_type.toLowerCase() == "report" && !item.is_query_report) {
|
||||
opts.doctype = item.dependencies;
|
||||
}
|
||||
|
||||
|
|
|
|||
77
frappe/public/js/integrations/google_drive_picker.js
Normal file
77
frappe/public/js/integrations/google_drive_picker.js
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/* global gapi:false, google:false */
|
||||
export default class GoogleDrivePicker {
|
||||
constructor({
|
||||
pickerCallback,
|
||||
enabled,
|
||||
appId,
|
||||
developerKey,
|
||||
clientId
|
||||
} = {}) {
|
||||
this.scope = ['https://www.googleapis.com/auth/drive.readonly'];
|
||||
this.pickerApiLoaded = false;
|
||||
this.enabled = enabled;
|
||||
this.appId = appId;
|
||||
this.pickerCallback = pickerCallback;
|
||||
this.developerKey = developerKey;
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
loadPicker() {
|
||||
// load the google API library
|
||||
$.ajax({
|
||||
method: "GET",
|
||||
url: "https://apis.google.com/js/api.js",
|
||||
dataType: "script",
|
||||
cache: true
|
||||
}).done(this.loadGapi.bind(this));
|
||||
}
|
||||
|
||||
loadGapi() {
|
||||
// load auth and picker libraries
|
||||
if (!frappe.boot.user.google_drive_token) {
|
||||
gapi.load('auth', this.onAuthApiLoad.bind(this));
|
||||
}
|
||||
|
||||
gapi.load('picker', this.onPickerApiLoad.bind(this));
|
||||
}
|
||||
|
||||
onAuthApiLoad() {
|
||||
gapi.auth.authorize({
|
||||
'client_id': this.clientId,
|
||||
'scope': this.scope,
|
||||
'immediate': false
|
||||
}, this.handleAuthResult.bind(this));
|
||||
}
|
||||
|
||||
handleAuthResult(authResult) {
|
||||
if (authResult && !authResult.error) {
|
||||
frappe.boot.user.google_drive_token = authResult.access_token;
|
||||
this.createPicker();
|
||||
}
|
||||
}
|
||||
|
||||
onPickerApiLoad() {
|
||||
this.pickerApiLoaded = true;
|
||||
this.createPicker();
|
||||
}
|
||||
|
||||
createPicker() {
|
||||
// Create and render a Picker object for searching images.
|
||||
if (this.pickerApiLoaded && frappe.boot.user.google_drive_token) {
|
||||
var view = new google.picker.DocsView(google.picker.ViewId.DOCS)
|
||||
.setParent('root') // show the root folder by default
|
||||
.setIncludeFolders(true); // also show folders, not just files
|
||||
|
||||
var picker = new google.picker.PickerBuilder()
|
||||
.setAppId(this.appId)
|
||||
.setDeveloperKey(this.developerKey)
|
||||
.setOAuthToken(frappe.boot.user.google_drive_token)
|
||||
.addView(view)
|
||||
.setLocale(frappe.boot.lang)
|
||||
.setCallback(this.pickerCallback)
|
||||
.build();
|
||||
|
||||
picker.setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ html {
|
|||
/* Works on Chrome, Edge, and Safari */
|
||||
*::-webkit-scrollbar-thumb {
|
||||
background: var(--scrollbar-thumb-color);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-track,
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
@import './website/index';
|
||||
@import './website/index';
|
||||
|
|
|
|||
|
|
@ -145,20 +145,21 @@
|
|||
|
||||
.section-with-cards .card {
|
||||
@include transition();
|
||||
border: none;
|
||||
|
||||
.card-body {
|
||||
padding: 0 1.5rem 2rem 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: $gray-500;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
line-height: 1;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
&.card-sm {
|
||||
.card-body {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: $font-size-base;
|
||||
font-weight: 600;
|
||||
|
|
@ -169,10 +170,6 @@
|
|||
}
|
||||
}
|
||||
&.card-md {
|
||||
.card-body {
|
||||
padding: 1.75rem;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: $font-size-lg;
|
||||
font-weight: 600;
|
||||
|
|
@ -186,10 +183,6 @@
|
|||
}
|
||||
}
|
||||
&.card-lg {
|
||||
.card-body {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: $font-size-xl;
|
||||
font-weight: bold;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
import unittest
|
||||
from random import choice
|
||||
import datetime
|
||||
|
||||
import frappe
|
||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
|
||||
|
|
@ -45,11 +46,35 @@ class TestDB(unittest.TestCase):
|
|||
frappe.db.escape("香港濟生堂製藥有限公司 - IT".encode("utf-8"))
|
||||
|
||||
def test_get_single_value(self):
|
||||
frappe.db.set_value('System Settings', 'System Settings', 'backup_limit', 5)
|
||||
frappe.db.commit()
|
||||
#setup
|
||||
values_dict = {
|
||||
"Float": 1.5,
|
||||
"Int": 1,
|
||||
"Percent": 55.5,
|
||||
"Currency": 12.5,
|
||||
"Data": "Test",
|
||||
"Date": datetime.datetime.now().date(),
|
||||
"Datetime": datetime.datetime.now(),
|
||||
"Time": datetime.timedelta(hours=9, minutes=45, seconds=10)
|
||||
}
|
||||
test_inputs = [{
|
||||
"fieldtype": fieldtype,
|
||||
"value": value} for fieldtype, value in values_dict.items()]
|
||||
for fieldtype in values_dict.keys():
|
||||
create_custom_field("Print Settings", {
|
||||
"fieldname": f"test_{fieldtype.lower()}",
|
||||
"label": f"Test {fieldtype}",
|
||||
"fieldtype": fieldtype,
|
||||
})
|
||||
|
||||
limit = frappe.db.get_single_value('System Settings', 'backup_limit')
|
||||
self.assertEqual(limit, 5)
|
||||
#test
|
||||
for inp in test_inputs:
|
||||
fieldname = f"test_{inp['fieldtype'].lower()}"
|
||||
frappe.db.set_value("Print Settings", "Print Settings", fieldname, inp["value"])
|
||||
self.assertEqual(frappe.db.get_single_value("Print Settings", fieldname), inp["value"])
|
||||
|
||||
#teardown
|
||||
clear_custom_fields("Print Settings")
|
||||
|
||||
def test_log_touched_tables(self):
|
||||
frappe.flags.in_migrate = True
|
||||
|
|
@ -132,29 +157,29 @@ class TestDB(unittest.TestCase):
|
|||
|
||||
# Testing read
|
||||
self.assertEqual(list(frappe.get_all("ToDo", fields=[random_field], limit=1)[0])[0], random_field)
|
||||
self.assertEqual(list(frappe.get_all("ToDo", fields=["`{0}` as total".format(random_field)], limit=1)[0])[0], "total")
|
||||
self.assertEqual(list(frappe.get_all("ToDo", fields=[f"`{random_field}` as total"], limit=1)[0])[0], "total")
|
||||
|
||||
# Testing read for distinct and sql functions
|
||||
self.assertEqual(list(
|
||||
frappe.get_all("ToDo",
|
||||
fields=["`{0}` as total".format(random_field)],
|
||||
fields=[f"`{random_field}` as total"],
|
||||
distinct=True,
|
||||
limit=1,
|
||||
)[0]
|
||||
)[0], "total")
|
||||
self.assertEqual(list(
|
||||
frappe.get_all("ToDo",
|
||||
fields=["`{0}`".format(random_field)],
|
||||
fields=[f"`{random_field}`"],
|
||||
distinct=True,
|
||||
limit=1,
|
||||
)[0]
|
||||
)[0], random_field)
|
||||
self.assertEqual(list(
|
||||
frappe.get_all("ToDo",
|
||||
fields=["count(`{0}`)".format(random_field)],
|
||||
fields=[f"count(`{random_field}`)"],
|
||||
limit=1
|
||||
)[0]
|
||||
)[0], "count" if frappe.conf.db_type == "postgres" else "count(`{0}`)".format(random_field))
|
||||
)[0], "count" if frappe.conf.db_type == "postgres" else f"count(`{random_field}`)")
|
||||
|
||||
# Testing update
|
||||
frappe.db.set_value(test_doctype, random_doc, random_field, random_value)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
# Copyright (c) 2021, Frappe Technologies and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestWorkflowAction(unittest.TestCase):
|
||||
pass
|
||||
|
|
@ -1,262 +1,77 @@
|
|||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "",
|
||||
"beta": 0,
|
||||
"actions": [],
|
||||
"creation": "2018-05-17 18:29:03.923384",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"status",
|
||||
"reference_name",
|
||||
"reference_doctype",
|
||||
"user",
|
||||
"workflow_state",
|
||||
"completed_by"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Status",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Open\nCompleted",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"options": "Open\nCompleted"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "reference_name",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Reference Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "reference_doctype",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "reference_doctype",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Reference Document Type",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "DocType",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "user",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "User",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "User",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "workflow_state",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Workflow State",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "completed_by",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Completed By",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "User",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"options": "User"
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-09-05 14:22:27.664645",
|
||||
"links": [],
|
||||
"modified": "2021-07-01 09:07:52.848618",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Workflow",
|
||||
"name": "Workflow Action",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 0,
|
||||
"delete": 1,
|
||||
"email": 0,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "All",
|
||||
"set_user_permissions": 0,
|
||||
"share": 0,
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
"role": "All"
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "reference_name",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
"track_changes": 1
|
||||
}
|
||||
|
|
@ -4148,16 +4148,11 @@ minimatch@^3.0.4, minimatch@~3.0.2:
|
|||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimist@^1.1.3, minimist@^1.2.5:
|
||||
minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
||||
|
||||
minimist@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
|
||||
integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
|
||||
|
||||
minipass@^3.0.0:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue