diff --git a/frappe/handler.py b/frappe/handler.py
index de86c15c8f..8d0c18a00b 100755
--- a/frappe/handler.py
+++ b/frappe/handler.py
@@ -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:
diff --git a/frappe/integrations/doctype/google_settings/google_settings.json b/frappe/integrations/doctype/google_settings/google_settings.json
index 086c56c020..6f25fa4bf6 100644
--- a/frappe/integrations/doctype/google_settings/google_settings.json
+++ b/frappe/integrations/doctype/google_settings/google_settings.json
@@ -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 \n\"APIs & Services\" > \"Credentials\"\n",
"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 \n\"APIs & Services\" > \"Credentials\"\n",
"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 \n\"IAM & Admin\" > \"Settings\"\n",
+ "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,
diff --git a/frappe/integrations/doctype/google_settings/google_settings.py b/frappe/integrations/doctype/google_settings/google_settings.py
index 9a3f3c8ae2..db65abdb65 100644
--- a/frappe/integrations/doctype/google_settings/google_settings.py
+++ b/frappe/integrations/doctype/google_settings/google_settings.py
@@ -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"
\ No newline at end of file
+ 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
+ }
diff --git a/frappe/integrations/doctype/google_settings/test_google_settings.py b/frappe/integrations/doctype/google_settings/test_google_settings.py
new file mode 100644
index 0000000000..32d43a323b
--- /dev/null
+++ b/frappe/integrations/doctype/google_settings/test_google_settings.py
@@ -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", ""))
diff --git a/frappe/printing/page/print/print.js b/frappe/printing/page/print/print.js
index fc59065c64..ca2a340661 100644
--- a/frappe/printing/page/print/print.js
+++ b/frappe/printing/page/print/print.js
@@ -113,22 +113,20 @@ frappe.ui.form.PrintView = class {
},
).$input;
- this.letterhead_selector = this.add_sidebar_item(
+ this.letterhead_selector_df = this.add_sidebar_item(
{
- fieldtype: 'Select',
+ fieldtype: 'Autocomplete',
fieldname: 'letterhead',
label: __('Select Letterhead'),
- options: [
- this.get_default_option_for_select(__('Select Letterhead')),
- __('No Letterhead')
- ],
+ placeholder: __('Select Letterhead'),
+ options: [__('No Letterhead')],
change: () => this.preview(),
default: this.print_settings.with_letterhead
? __('No Letterhead')
: __('Select Letterhead')
},
- ).$input;
-
+ );
+ this.letterhead_selector = this.letterhead_selector_df.$input;
this.sidebar_dynamic_section = $(
`
{{ 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())
diff --git a/frappe/public/js/frappe/form/dashboard.js b/frappe/public/js/frappe/form/dashboard.js
index 6833f68073..b2b0c11d54 100644
--- a/frappe/public/js/frappe/form/dashboard.js
+++ b/frappe/public/js/frappe/form/dashboard.js
@@ -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() {
diff --git a/frappe/public/js/frappe/router.js b/frappe/public/js/frappe/router.js
index 12caf4ab94..2bfa7c7be6 100644
--- a/frappe/public/js/frappe/router.js
+++ b/frappe/public/js/frappe/router.js
@@ -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];
diff --git a/frappe/public/js/frappe/ui/capture.js b/frappe/public/js/frappe/ui/capture.js
index 676c997b31..d408fadb33 100644
--- a/frappe/public/js/frappe/ui/capture.js
+++ b/frappe/public/js/frappe/ui/capture.js
@@ -116,10 +116,7 @@ frappe.ui.Capture = class {
})
.catch(err => {
if (this.options.error) {
- const alert = `
${
- frappe.ui.Capture.ERR_MESSAGE
- }`;
- frappe.show_alert(alert, 3);
+ frappe.show_alert(frappe.ui.Capture.ERR_MESSAGE, 3);
}
throw err;
diff --git a/frappe/public/js/frappe/views/file/file_view.js b/frappe/public/js/frappe/views/file/file_view.js
index 6f0cdcc0f1..e020bff4dd 100644
--- a/frappe/public/js/frappe/views/file/file_view.js
+++ b/frappe/public/js/frappe/views/file/file_view.js
@@ -315,7 +315,7 @@ frappe.views.FileView = class FileView extends frappe.views.ListView {
acc += "/" + curr;
}
return acc;
- }, "/app/file");
+ }, "/app/file/view");
return `
${folder}`;
})
diff --git a/frappe/public/js/frappe/views/workspace/workspace.js b/frappe/public/js/frappe/views/workspace/workspace.js
index 80f8c00705..f16228dca0 100644
--- a/frappe/public/js/frappe/views/workspace/workspace.js
+++ b/frappe/public/js/frappe/views/workspace/workspace.js
@@ -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() {
diff --git a/frappe/public/js/integrations/google_drive_picker.js b/frappe/public/js/integrations/google_drive_picker.js
new file mode 100644
index 0000000000..9d7971e75c
--- /dev/null
+++ b/frappe/public/js/integrations/google_drive_picker.js
@@ -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);
+ }
+ }
+}
diff --git a/frappe/public/scss/desk/scrollbar.scss b/frappe/public/scss/desk/scrollbar.scss
index d8fb49e5ce..9790ed0116 100644
--- a/frappe/public/scss/desk/scrollbar.scss
+++ b/frappe/public/scss/desk/scrollbar.scss
@@ -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,
diff --git a/frappe/workflow/doctype/workflow_action/test_workflow_action.py b/frappe/workflow/doctype/workflow_action/test_workflow_action.py
new file mode 100644
index 0000000000..a2f4f26193
--- /dev/null
+++ b/frappe/workflow/doctype/workflow_action/test_workflow_action.py
@@ -0,0 +1,8 @@
+# Copyright (c) 2021, Frappe Technologies and Contributors
+# See license.txt
+
+# import frappe
+import unittest
+
+class TestWorkflowAction(unittest.TestCase):
+ pass
diff --git a/frappe/workflow/doctype/workflow_action/workflow_action.json b/frappe/workflow/doctype/workflow_action/workflow_action.json
index 810f22c184..f1290d001f 100644
--- a/frappe/workflow/doctype/workflow_action/workflow_action.json
+++ b/frappe/workflow/doctype/workflow_action/workflow_action.json
@@ -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
}
\ No newline at end of file