From 0a60d1cd964900dd02e81deb8e8cd0db3ab4512d Mon Sep 17 00:00:00 2001 From: Prateeksha Singh Date: Sun, 19 Aug 2018 19:39:00 +0530 Subject: [PATCH 1/9] [hub] Publishing Dialog, Sync category - Hub Category selection - Recycled --- erpnext/hub_node/api.py | 12 +- .../item_to_hub_item/__init__.py | 25 ++-- .../hub_tracked_item/hub_tracked_item.json | 74 +++++++++- erpnext/public/js/hub/pages/publish.js | 126 ++++++++++++++---- 4 files changed, 198 insertions(+), 39 deletions(-) diff --git a/erpnext/hub_node/api.py b/erpnext/hub_node/api.py index 559e22a2c8..86ad031b0c 100644 --- a/erpnext/hub_node/api.py +++ b/erpnext/hub_node/api.py @@ -42,11 +42,19 @@ def get_valid_items(search_value=''): def publish_selected_items(items_to_publish): items_to_publish = json.loads(items_to_publish) if not len(items_to_publish): - return + frappe.throw('No items to publish') - for item_code in items_to_publish: + for item in items_to_publish: + item_code = item.get('item_code') frappe.db.set_value('Item', item_code, 'publish_in_hub', 1) + frappe.get_doc({ + 'doctype': 'Hub Tracked Item', + 'item_code': item_code, + 'hub_category': item.get('hub_category'), + # 'images': item.get('images') + }).insert() + try: hub_settings = frappe.get_doc('Hub Settings') item_sync_preprocess() diff --git a/erpnext/hub_node/data_migration_mapping/item_to_hub_item/__init__.py b/erpnext/hub_node/data_migration_mapping/item_to_hub_item/__init__.py index 9445e3a8dc..3f1352099c 100644 --- a/erpnext/hub_node/data_migration_mapping/item_to_hub_item/__init__.py +++ b/erpnext/hub_node/data_migration_mapping/item_to_hub_item/__init__.py @@ -1,19 +1,24 @@ -import io, base64, urllib, os +import frappe, io, base64, urllib, os def pre_process(doc): - file_path = doc.image - file_name = os.path.basename(file_path) + # file_path = doc.image + # file_name = os.path.basename(file_path) - if file_path.startswith('http'): - url = file_path - file_path = os.path.join('/tmp', file_name) - urllib.urlretrieve(url, file_path) + # if file_path.startswith('http'): + # url = file_path + # file_path = os.path.join('/tmp', file_name) + # urllib.urlretrieve(url, file_path) - with io.open(file_path, 'rb') as f: - doc.image = base64.b64encode(f.read()) + # with io.open(file_path, 'rb') as f: + # doc.image = base64.b64encode(f.read()) - doc.image_file_name = file_name + # doc.image_file_name = file_name + + cached_details = frappe.get_doc('Hub Tracked Item', doc.item_code) + + if cached_details: + doc.hub_category = cached_details.hub_category return doc diff --git a/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.json b/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.json index 063c87817c..7a0bc2a251 100644 --- a/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.json +++ b/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.json @@ -3,6 +3,7 @@ "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, + "autoname": "field:item_code", "beta": 0, "creation": "2018-03-18 09:33:50.267762", "custom": 0, @@ -14,6 +15,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,6 +43,70 @@ "search_index": 0, "set_only_once": 0, "translatable": 0, + "unique": 1 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "hub_category", + "fieldtype": "Data", + "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": "Hub Category", + "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 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "images", + "fieldtype": "Long Text", + "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": "Images", + "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 } ], @@ -49,12 +115,12 @@ "hide_toolbar": 0, "idx": 0, "image_view": 0, - "in_create": 1, + "in_create": 0, "is_submittable": 0, "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-03-18 09:34:01.757713", + "modified": "2018-08-19 19:30:01.449904", "modified_by": "Administrator", "module": "Hub Node", "name": "Hub Tracked Item", @@ -63,7 +129,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -89,5 +154,6 @@ "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/public/js/hub/pages/publish.js b/erpnext/public/js/hub/pages/publish.js index a76f9467c6..035278bbcd 100644 --- a/erpnext/public/js/hub/pages/publish.js +++ b/erpnext/public/js/hub/pages/publish.js @@ -3,13 +3,17 @@ import { get_item_card_container_html } from '../components/items_container'; import { get_local_item_card_html } from '../components/item_card'; import { make_search_bar } from '../components/search_bar'; + erpnext.hub.Publish = class Publish extends SubPage { make_wrapper() { super.make_wrapper(); - this.items_to_publish = []; + this.items_to_publish = {}; this.unpublished_items = []; this.fetched_items = []; + this.cache = erpnext.hub.cache.items_to_publish; + this.cache = []; + frappe.realtime.on("items-sync", (data) => { this.$wrapper.find('.progress-bar').css('width', data.progress_percent+'%'); @@ -58,7 +62,7 @@ erpnext.hub.Publish = class Publish extends SubPage { } get_publishing_header() { - const title_html = `${__('Select Products to Publish')}`; + const title_html = `
${__('Select Products to Publish')}
`; const subtitle_html = `

${__(`Only products with an image, description and category can be published. @@ -71,6 +75,9 @@ erpnext.hub.Publish = class Publish extends SubPage { `; return $(` +

${__('Selected Products')}
+
+
${title_html} @@ -87,27 +94,97 @@ erpnext.hub.Publish = class Publish extends SubPage { .then(this.refresh.bind(this)) }); + this.selected_items_container = this.$wrapper.find('.selected-items'); + + this.$current_selected_card = null; + + this.make_publishing_dialog(); + this.$wrapper.on('click', '.hub-card', (e) => { const $target = $(e.currentTarget); - $target.toggleClass('active'); + const item_code = $target.attr('data-id'); + this.show_publishing_dialog_for_item(item_code); - // Get total items - const total_items = this.$wrapper.find('.hub-card.active').length; + this.$current_selected_card = $target.parent(); - let button_label; - if (total_items > 0) { - const more_than_one = total_items > 1; - button_label = __('Publish {0} item{1}', [total_items, more_than_one ? 's' : '']); - } else { - button_label = __('Publish'); - } + this.update_selected_items_count() - this.$wrapper.find('.publish-items') - .text(button_label) - .prop('disabled', total_items === 0); }); } + make_publishing_dialog() { + this.publishing_dialog = new frappe.ui.Dialog({ + title: __('Edit Publishing Details'), + fields: [ + { + "label": "Item Code", + "fieldname": "item_code", + "fieldtype": "Data", + "read_only": 1 + }, + { + "label": "Hub Category", + "fieldname": "hub_category", + "fieldtype": "Autocomplete", + "options": ["Agriculture", "Books", "Chemicals", "Clothing", + "Electrical", "Electronics", "Energy", "Fashion", "Food and Beverage", + "Health", "Home", "Industrial", "Machinery", "Packaging and Printing", + "Sports", "Transportation" + ], + "reqd": 1 + } + ], + primary_action_label: __('Set Details'), + primary_action: () => { + const values = this.publishing_dialog.get_values(true); + this.items_to_publish[values.item_code] = values; + + this.$current_selected_card.appendTo(this.selected_items_container); + this.$current_selected_card.find('.hub-card').toggleClass('active'); + + this.publishing_dialog.hide(); + }, + secondary_action: () => { + const values = this.publishing_dialog.get_values(true); + this.items_to_publish[values.item_code] = values; + } + }); + } + + show_publishing_dialog_for_item(item_code) { + let item_data = this.items_to_publish[item_code]; + + if(!item_data) { item_data = { item_code }; } + + this.publishing_dialog.clear(); + this.publishing_dialog.set_values(item_data); + this.publishing_dialog.show(); + } + + update_selected_items_count() { + const total_items = this.$wrapper.find('.hub-card.active').length; + + let button_label; + if (total_items > 0) { + const more_than_one = total_items > 1; + button_label = __('Publish {0} item{1}', [total_items, more_than_one ? 's' : '']); + } else { + button_label = __('Publish'); + } + + this.$wrapper.find('.publish-items') + .text(button_label) + .prop('disabled', total_items === 0); + } + + add_item_to_publish() { + // + } + + remove_item_from_publish() { + // + } + show_message(message) { const $message = $(`

@@ -211,19 +288,22 @@ erpnext.hub.Publish = class Publish extends SubPage { item_codes_to_publish.push($(this).attr("data-id")); }); - this.unpublished_items = this.fetched_items.filter(item => { - return !item_codes_to_publish.includes(item.item_code); - }); + // this.unpublished_items = this.fetched_items.filter(item => { + // return !item_codes_to_publish.includes(item.item_code); + // }); - const items_to_publish = this.fetched_items.filter(item => { - return item_codes_to_publish.includes(item.item_code); - }); - this.items_to_publish = items_to_publish; + // const items_to_publish = this.fetched_items.filter(item => { + // return item_codes_to_publish.includes(item.item_code); + // }); + + // this.items_to_publish = items_to_publish; + + const items_data_to_publish = item_codes_to_publish.map(item_code => this.items_to_publish[item_code]) return frappe.call( 'erpnext.hub_node.api.publish_selected_items', { - items_to_publish: item_codes_to_publish + items_to_publish: items_data_to_publish } ) } From a525d12f695a0b047955307a4affe700603055ea Mon Sep 17 00:00:00 2001 From: Prateeksha Singh Date: Sun, 19 Aug 2018 22:31:33 +0530 Subject: [PATCH 2/9] [hub] sync multiple image urls - using a simple multiselect currently --- erpnext/hub_node/api.py | 9 +++++--- .../item_to_hub_item/__init__.py | 1 + .../item_to_hub_item/item_to_hub_item.json | 12 +++++++++- .../hub_sync/hub_sync.json | 2 +- .../hub_tracked_item/hub_tracked_item.json | 6 ++--- erpnext/public/js/hub/pages/publish.js | 22 ++++++++++++++++++- 6 files changed, 43 insertions(+), 9 deletions(-) diff --git a/erpnext/hub_node/api.py b/erpnext/hub_node/api.py index 86ad031b0c..0c9af1abc1 100644 --- a/erpnext/hub_node/api.py +++ b/erpnext/hub_node/api.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals import frappe, requests, json from frappe.utils import now from frappe.frappeclient import FrappeClient +from frappe.desk.form.load import get_attachments @frappe.whitelist() def call_hub_method(method, params=None): @@ -31,11 +32,13 @@ def get_valid_items(search_value=''): valid_items = filter(lambda x: x.image and x.description, items) - def attach_source_type(item): + def prepare_item(item): item.source_type = "local" + item.attachments = get_attachments('Item', item.item_code) return item - valid_items = map(lambda x: attach_source_type(x), valid_items) + valid_items = map(lambda x: prepare_item(x), valid_items) + return valid_items @frappe.whitelist() @@ -52,7 +55,7 @@ def publish_selected_items(items_to_publish): 'doctype': 'Hub Tracked Item', 'item_code': item_code, 'hub_category': item.get('hub_category'), - # 'images': item.get('images') + 'image_list': item.get('image_list') }).insert() try: diff --git a/erpnext/hub_node/data_migration_mapping/item_to_hub_item/__init__.py b/erpnext/hub_node/data_migration_mapping/item_to_hub_item/__init__.py index 3f1352099c..0b6b2bc8a8 100644 --- a/erpnext/hub_node/data_migration_mapping/item_to_hub_item/__init__.py +++ b/erpnext/hub_node/data_migration_mapping/item_to_hub_item/__init__.py @@ -19,6 +19,7 @@ def pre_process(doc): if cached_details: doc.hub_category = cached_details.hub_category + doc.image_list = cached_details.image_list return doc diff --git a/erpnext/hub_node/data_migration_mapping/item_to_hub_item/item_to_hub_item.json b/erpnext/hub_node/data_migration_mapping/item_to_hub_item/item_to_hub_item.json index 3ace088a80..bcece69b38 100644 --- a/erpnext/hub_node/data_migration_mapping/item_to_hub_item/item_to_hub_item.json +++ b/erpnext/hub_node/data_migration_mapping/item_to_hub_item/item_to_hub_item.json @@ -24,10 +24,20 @@ "local_fieldname": "image", "remote_fieldname": "image" }, + { + "is_child_table": 0, + "local_fieldname": "image_list", + "remote_fieldname": "image_list" + }, { "is_child_table": 0, "local_fieldname": "item_group", "remote_fieldname": "item_group" + }, + { + "is_child_table": 0, + "local_fieldname": "hub_category", + "remote_fieldname": "hub_category" } ], "idx": 1, @@ -35,7 +45,7 @@ "mapping_name": "Item to Hub Item", "mapping_type": "Push", "migration_id_field": "hub_sync_id", - "modified": "2018-08-01 16:37:09.170546", + "modified": "2018-08-19 22:20:25.727581", "modified_by": "Administrator", "name": "Item to Hub Item", "owner": "Administrator", diff --git a/erpnext/hub_node/data_migration_plan/hub_sync/hub_sync.json b/erpnext/hub_node/data_migration_plan/hub_sync/hub_sync.json index 1f772b68f0..e90b1dd1e8 100644 --- a/erpnext/hub_node/data_migration_plan/hub_sync/hub_sync.json +++ b/erpnext/hub_node/data_migration_plan/hub_sync/hub_sync.json @@ -9,7 +9,7 @@ "mapping": "Item to Hub Item" } ], - "modified": "2018-08-01 16:37:09.027512", + "modified": "2018-08-19 22:20:25.644602", "modified_by": "Administrator", "module": "Hub Node", "name": "Hub Sync", diff --git a/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.json b/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.json index 7a0bc2a251..9384adbd1d 100644 --- a/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.json +++ b/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.json @@ -84,7 +84,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "images", + "fieldname": "image_list", "fieldtype": "Long Text", "hidden": 0, "ignore_user_permissions": 0, @@ -93,7 +93,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Images", + "label": "Image List", "length": 0, "no_copy": 0, "permlevel": 0, @@ -120,7 +120,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-08-19 19:30:01.449904", + "modified": "2018-08-19 22:24:06.207307", "modified_by": "Administrator", "module": "Hub Node", "name": "Hub Tracked Item", diff --git a/erpnext/public/js/hub/pages/publish.js b/erpnext/public/js/hub/pages/publish.js index 035278bbcd..fcbd0f8b8a 100644 --- a/erpnext/public/js/hub/pages/publish.js +++ b/erpnext/public/js/hub/pages/publish.js @@ -10,6 +10,7 @@ erpnext.hub.Publish = class Publish extends SubPage { this.items_to_publish = {}; this.unpublished_items = []; this.fetched_items = []; + this.fetched_items_dict = {}; this.cache = erpnext.hub.cache.items_to_publish; this.cache = []; @@ -132,6 +133,13 @@ erpnext.hub.Publish = class Publish extends SubPage { "Sports", "Transportation" ], "reqd": 1 + }, + { + "label": "Images", + "fieldname": "image_list", + "fieldtype": "MultiSelect", + "options": [], + "reqd": 1 } ], primary_action_label: __('Set Details'), @@ -154,9 +162,17 @@ erpnext.hub.Publish = class Publish extends SubPage { show_publishing_dialog_for_item(item_code) { let item_data = this.items_to_publish[item_code]; - if(!item_data) { item_data = { item_code }; } + if(!item_data) { item_data = { item_code }; }; this.publishing_dialog.clear(); + + const item_doc = this.fetched_items_dict[item_code]; + if(item_doc) { + this.publishing_dialog.fields_dict.image_list.set_data( + item_doc.attachments.map(attachment => attachment.file_url) + ); + } + this.publishing_dialog.set_values(item_data); this.publishing_dialog.show(); } @@ -268,6 +284,10 @@ erpnext.hub.Publish = class Publish extends SubPage { const items_container = $(get_item_card_container_html(items, '', get_local_item_card_html)); items_container.addClass('results'); wrapper.append(items_container); + + items.map(item => { + this.fetched_items_dict[item.item_code] = item; + }) } get_valid_items() { From 305f7375d16c541da9ea0752520e0b566ce31bef Mon Sep 17 00:00:00 2001 From: Prateeksha Singh Date: Mon, 20 Aug 2018 00:25:26 +0530 Subject: [PATCH 3/9] [hub] Register in a dialog instead of Page - in order to recycle it for Edit Profile - Also, the register page had too much custom code --- .../js/hub/components/profile_dialog.js | 75 +++++++++++++++++++ erpnext/public/js/hub/marketplace.js | 38 +++++++++- erpnext/public/js/hub/pages/profile.js | 29 ++++++- erpnext/public/js/hub/pages/subpage.js | 10 --- erpnext/public/less/hub.less | 2 +- 5 files changed, 140 insertions(+), 14 deletions(-) create mode 100644 erpnext/public/js/hub/components/profile_dialog.js diff --git a/erpnext/public/js/hub/components/profile_dialog.js b/erpnext/public/js/hub/components/profile_dialog.js new file mode 100644 index 0000000000..0800b8a287 --- /dev/null +++ b/erpnext/public/js/hub/components/profile_dialog.js @@ -0,0 +1,75 @@ +const ProfileDialog = (title = __('Edit Profile'), action={}) => { + const fields = [ + { + fieldtype: 'Link', + fieldname: 'company', + label: __('Company'), + options: 'Company', + onchange: () => { + const value = dialog.get_value('company'); + + if (value) { + frappe.db.get_doc('Company', value) + .then(company => { + dialog.set_values({ + country: company.country, + company_email: company.email, + currency: company.default_currency + }); + }); + } + } + }, + { + fieldname: 'company_email', + label: __('Email'), + fieldtype: 'Data' + }, + { + fieldname: 'country', + label: __('Country'), + fieldtype: 'Read Only' + }, + { + fieldname: 'currency', + label: __('Currency'), + fieldtype: 'Read Only' + }, + { + fieldtype: 'Text', + label: __('About your Company'), + fieldname: 'company_description' + } + ]; + + let dialog = new frappe.ui.Dialog({ + title: title, + fields: fields, + primary_action_label: action.label || __('Update'), + primary_action: () => { + const form_values = dialog.get_values(); + let values_filled = true; + const mandatory_fields = ['company', 'company_email', 'company_description']; + mandatory_fields.forEach(field => { + const value = form_values[field]; + if (!value) { + dialog.set_df_property(field, 'reqd', 1); + values_filled = false; + } + }); + if (!values_filled) return; + + action.on_submit(form_values); + } + }); + + // Post create + const default_company = frappe.defaults.get_default('company'); + dialog.set_value('company', default_company); + + return dialog; +} + +export { + ProfileDialog +} diff --git a/erpnext/public/js/hub/marketplace.js b/erpnext/public/js/hub/marketplace.js index 154324338d..cadaea0791 100644 --- a/erpnext/public/js/hub/marketplace.js +++ b/erpnext/public/js/hub/marketplace.js @@ -12,6 +12,9 @@ import './pages/published_products'; import './pages/messages'; import './pages/not_found'; +// components +import { ProfileDialog } from './components/profile_dialog'; + // helpers import './hub_call'; @@ -46,6 +49,16 @@ erpnext.hub.Marketplace = class Marketplace { const route = $target.data().route; frappe.set_route(route); }); + + // generic action handler + this.$parent.on('click', '[data-action]', e => { + const $target = $(e.currentTarget); + const action = $target.data().action; + + if (action && this[action]) { + this[action].apply(this, $target); + } + }) } make_sidebar() { @@ -76,7 +89,7 @@ erpnext.hub.Marketplace = class Marketplace { ${__('Messages')} ` - : `

  • + : `
  • ${__('Become a seller')}
  • `; @@ -215,4 +228,27 @@ erpnext.hub.Marketplace = class Marketplace { frappe.utils.scroll_to(0); this.subpages[route[1]].show(); } + + show_register_dialog() { + this.profile_dialog = ProfileDialog(__('Become a Seller'), { + label: __('Register'), + on_submit: this.register_seller.bind(this) + }); + + this.profile_dialog.show(); + } + + register_seller(form_values) { + frappe.call({ + method: 'erpnext.hub_node.doctype.hub_settings.hub_settings.register_seller', + args: form_values, + btn: $(e.currentTarget) + }).then(() => { + this.profile_dialog.hide(); + frappe.set_route('marketplace', 'publish'); + + // custom jquery event + this.$body.trigger('seller-registered'); + }); + } } diff --git a/erpnext/public/js/hub/pages/profile.js b/erpnext/public/js/hub/pages/profile.js index a38cde4276..637e7b9c60 100644 --- a/erpnext/public/js/hub/pages/profile.js +++ b/erpnext/public/js/hub/pages/profile.js @@ -1,11 +1,14 @@ import SubPage from './subpage'; +import { get_detail_skeleton_html } from '../components/skeleton_state'; erpnext.hub.Profile = class Profile extends SubPage { make_wrapper() { super.make_wrapper(); + this.make_edit_profile_dialog(); } refresh() { + this.show_skeleton(); this.get_hub_seller_profile(this.keyword) .then(profile => this.render(profile)); } @@ -14,6 +17,18 @@ erpnext.hub.Profile = class Profile extends SubPage { return hub.call('get_hub_seller_profile', { hub_seller: hub.settings.company_email }); } + make_edit_profile_dialog() { + // this.edit_profile_dialog = new + } + + edit_profile() { + // + } + + show_skeleton() { + this.$wrapper.html(get_detail_skeleton_html()); + } + render(profile) { const p = profile; const content_by_log_type = this.get_content_by_log_type(); @@ -46,7 +61,7 @@ erpnext.hub.Profile = class Profile extends SubPage {
    -
    +

    ${p.company}

    ${p.country}

    @@ -60,6 +75,16 @@ erpnext.hub.Profile = class Profile extends SubPage { }
    +
    @@ -95,4 +120,4 @@ erpnext.hub.Profile = class Profile extends SubPage { } } } -} \ No newline at end of file +} diff --git a/erpnext/public/js/hub/pages/subpage.js b/erpnext/public/js/hub/pages/subpage.js index 7c75b1379e..3f4ed07171 100644 --- a/erpnext/public/js/hub/pages/subpage.js +++ b/erpnext/public/js/hub/pages/subpage.js @@ -3,16 +3,6 @@ export default class SubPage { this.$parent = $(parent); this.make_wrapper(options); - // generic action handler - this.$wrapper.on('click', '[data-action]', e => { - const $target = $(e.currentTarget); - const action = $target.data().action; - - if (action && this[action]) { - this[action].apply(this, $target); - } - }) - // handle broken images after every render if (this.render) { this._render = this.render.bind(this); diff --git a/erpnext/public/less/hub.less b/erpnext/public/less/hub.less index ac0aa42ae1..0859ae6a30 100644 --- a/erpnext/public/less/hub.less +++ b/erpnext/public/less/hub.less @@ -6,7 +6,7 @@ body[data-route^="marketplace/"] { padding-right: 25px; } - [data-route] { + [data-route], [data-action] { cursor: pointer; } From fe67508d609c86dca1025ccb4d069896844f56a5 Mon Sep 17 00:00:00 2001 From: Prateeksha Singh Date: Mon, 20 Aug 2018 01:18:41 +0530 Subject: [PATCH 4/9] [hub][feat] Edit your Profile, recycle profile dialog --- .../js/hub/components/profile_dialog.js | 4 +- erpnext/public/js/hub/marketplace.js | 15 ++++--- erpnext/public/js/hub/pages/profile.js | 41 +++++++++++++++---- erpnext/public/js/hub/pages/subpage.js | 10 +++++ 4 files changed, 54 insertions(+), 16 deletions(-) diff --git a/erpnext/public/js/hub/components/profile_dialog.js b/erpnext/public/js/hub/components/profile_dialog.js index 0800b8a287..800e8c66f0 100644 --- a/erpnext/public/js/hub/components/profile_dialog.js +++ b/erpnext/public/js/hub/components/profile_dialog.js @@ -1,4 +1,4 @@ -const ProfileDialog = (title = __('Edit Profile'), action={}) => { +const ProfileDialog = (title = __('Edit Profile'), action={}, initial_values={}) => { const fields = [ { fieldtype: 'Link', @@ -63,6 +63,8 @@ const ProfileDialog = (title = __('Edit Profile'), action={}) => { } }); + dialog.set_values(initial_values); + // Post create const default_company = frappe.defaults.get_default('company'); dialog.set_value('company', default_company); diff --git a/erpnext/public/js/hub/marketplace.js b/erpnext/public/js/hub/marketplace.js index cadaea0791..1986cfb441 100644 --- a/erpnext/public/js/hub/marketplace.js +++ b/erpnext/public/js/hub/marketplace.js @@ -230,12 +230,15 @@ erpnext.hub.Marketplace = class Marketplace { } show_register_dialog() { - this.profile_dialog = ProfileDialog(__('Become a Seller'), { - label: __('Register'), - on_submit: this.register_seller.bind(this) - }); + this.register_dialog = ProfileDialog( + __('Become a Seller'), + { + label: __('Register'), + on_submit: this.register_seller.bind(this) + } + ); - this.profile_dialog.show(); + this.register_dialog.show(); } register_seller(form_values) { @@ -244,7 +247,7 @@ erpnext.hub.Marketplace = class Marketplace { args: form_values, btn: $(e.currentTarget) }).then(() => { - this.profile_dialog.hide(); + this.register_dialog.hide(); frappe.set_route('marketplace', 'publish'); // custom jquery event diff --git a/erpnext/public/js/hub/pages/profile.js b/erpnext/public/js/hub/pages/profile.js index 637e7b9c60..a57bc7ceec 100644 --- a/erpnext/public/js/hub/pages/profile.js +++ b/erpnext/public/js/hub/pages/profile.js @@ -1,5 +1,6 @@ import SubPage from './subpage'; import { get_detail_skeleton_html } from '../components/skeleton_state'; +import { ProfileDialog } from '../components/profile_dialog'; erpnext.hub.Profile = class Profile extends SubPage { make_wrapper() { @@ -10,21 +11,16 @@ erpnext.hub.Profile = class Profile extends SubPage { refresh() { this.show_skeleton(); this.get_hub_seller_profile(this.keyword) - .then(profile => this.render(profile)); + .then(profile => { + this.edit_profile_dialog.set_values(profile); + this.render(profile); + }); } get_hub_seller_profile() { return hub.call('get_hub_seller_profile', { hub_seller: hub.settings.company_email }); } - make_edit_profile_dialog() { - // this.edit_profile_dialog = new - } - - edit_profile() { - // - } - show_skeleton() { this.$wrapper.html(get_detail_skeleton_html()); } @@ -98,6 +94,33 @@ erpnext.hub.Profile = class Profile extends SubPage { this.$wrapper.html(profile_html); } + make_edit_profile_dialog() { + this.edit_profile_dialog = ProfileDialog( + __('Edit Profile'), + { + label: __('Update'), + on_submit: this.update_profile.bind(this) + } + ); + } + + edit_profile() { + this.edit_profile_dialog.set_values({ + company_email: hub.settings.company_email + }); + this.edit_profile_dialog.show(); + } + + update_profile(new_values) { + hub.call('update_profile', { + hub_seller: hub.settings.company_email, + updated_profile: new_values + }).then(new_profile => { + this.edit_profile_dialog.hide(); + this.render(new_profile); + }); + } + get_timeline_log_item(pretty_date, message, icon) { return `
    diff --git a/erpnext/public/js/hub/pages/subpage.js b/erpnext/public/js/hub/pages/subpage.js index 3f4ed07171..7c75b1379e 100644 --- a/erpnext/public/js/hub/pages/subpage.js +++ b/erpnext/public/js/hub/pages/subpage.js @@ -3,6 +3,16 @@ export default class SubPage { this.$parent = $(parent); this.make_wrapper(options); + // generic action handler + this.$wrapper.on('click', '[data-action]', e => { + const $target = $(e.currentTarget); + const action = $target.data().action; + + if (action && this[action]) { + this[action].apply(this, $target); + } + }) + // handle broken images after every render if (this.render) { this._render = this.render.bind(this); From 96fdbd467daf50c74d03e114725f685413c4e15a Mon Sep 17 00:00:00 2001 From: Prateeksha Singh Date: Mon, 20 Aug 2018 10:07:56 +0530 Subject: [PATCH 5/9] [hub][feat] stateful publishing area --- erpnext/public/js/hub/pages/publish.js | 29 ++++++++++++++++++-------- erpnext/public/less/hub.less | 19 +++++++++++++++++ 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/erpnext/public/js/hub/pages/publish.js b/erpnext/public/js/hub/pages/publish.js index fcbd0f8b8a..46e4545d9b 100644 --- a/erpnext/public/js/hub/pages/publish.js +++ b/erpnext/public/js/hub/pages/publish.js @@ -70,21 +70,27 @@ erpnext.hub.Publish = class Publish extends SubPage { Please update them if an item in your inventory does not appear.`)}

    `; - const publish_button_html = ``; return $(` -
    ${__('Selected Products')}
    -
    +
    +
    + ${title_html} + ${publish_button_html} +
    +
    +

    ${__('No Items Selected')}

    +
    +
    +
    - ${title_html} ${subtitle_html}
    - ${publish_button_html}
    `); } @@ -108,8 +114,6 @@ erpnext.hub.Publish = class Publish extends SubPage { this.$current_selected_card = $target.parent(); - this.update_selected_items_count() - }); } @@ -150,6 +154,8 @@ erpnext.hub.Publish = class Publish extends SubPage { this.$current_selected_card.appendTo(this.selected_items_container); this.$current_selected_card.find('.hub-card').toggleClass('active'); + this.update_selected_items_count(); + this.publishing_dialog.hide(); }, secondary_action: () => { @@ -180,6 +186,8 @@ erpnext.hub.Publish = class Publish extends SubPage { update_selected_items_count() { const total_items = this.$wrapper.find('.hub-card.active').length; + const is_empty = total_items === 0; + let button_label; if (total_items > 0) { const more_than_one = total_items > 1; @@ -190,7 +198,10 @@ erpnext.hub.Publish = class Publish extends SubPage { this.$wrapper.find('.publish-items') .text(button_label) - .prop('disabled', total_items === 0); + .prop('disabled', is_empty); + + this.$wrapper.find('.publish-area').toggleClass('empty', is_empty); + this.$wrapper.find('.publish-area').toggleClass('filled', !is_empty); } add_item_to_publish() { @@ -230,7 +241,7 @@ erpnext.hub.Publish = class Publish extends SubPage { this.$wrapper.append(subtitle_html); - // Show search list with only desctiption, and don't set any events + // Show search list with only description, and don't set any events make_search_bar({ wrapper: this.$wrapper, on_search: keyword => { diff --git a/erpnext/public/less/hub.less b/erpnext/public/less/hub.less index 0859ae6a30..2bfb1094a0 100644 --- a/erpnext/public/less/hub.less +++ b/erpnext/public/less/hub.less @@ -211,6 +211,25 @@ body[data-route^="marketplace/"] { height: 500px; } + .empty-items-container { + height: 80px; + border-radius: 4px; + border: 1px solid @border-color; + margin: 15px 0px; + } + + .publish-area.filled { + .empty-items-container { + display: none; + } + } + + .publish-area.empty { + .hub-items-container { + display: none; + } + } + .form-container { .frappe-control { max-width: 100% !important; From 4ce54b001100097611d3a6e236b4f0a6df3acade Mon Sep 17 00:00:00 2001 From: Prateeksha Singh Date: Mon, 20 Aug 2018 13:07:23 +0530 Subject: [PATCH 6/9] [feat] new component: NotificationMessage --- .../js/hub/components/notification_message.js | 20 +++++++++++++++++++ erpnext/public/js/hub/pages/publish.js | 17 ---------------- erpnext/public/js/hub/pages/subpage.js | 6 ++++++ 3 files changed, 26 insertions(+), 17 deletions(-) create mode 100644 erpnext/public/js/hub/components/notification_message.js diff --git a/erpnext/public/js/hub/components/notification_message.js b/erpnext/public/js/hub/components/notification_message.js new file mode 100644 index 0000000000..890c298674 --- /dev/null +++ b/erpnext/public/js/hub/components/notification_message.js @@ -0,0 +1,20 @@ +const NotificationMessage = (message) => { + const $message = $(`
    +

    + + ${message} + + +

    +
    `); + + $message.find('.octicon-x').on('click', () => { + $message.remove(); + }); + + return $message; +} + +export { + NotificationMessage +} diff --git a/erpnext/public/js/hub/pages/publish.js b/erpnext/public/js/hub/pages/publish.js index 46e4545d9b..8de7b3844c 100644 --- a/erpnext/public/js/hub/pages/publish.js +++ b/erpnext/public/js/hub/pages/publish.js @@ -212,23 +212,6 @@ erpnext.hub.Publish = class Publish extends SubPage { // } - show_message(message) { - const $message = $(`
    -

    - - ${message} - - -

    -
    `); - - $message.find('.octicon-x').on('click', () => { - $message.remove(); - }); - - this.$wrapper.prepend($message); - } - make_publish_in_progress_state() { this.$wrapper.empty(); diff --git a/erpnext/public/js/hub/pages/subpage.js b/erpnext/public/js/hub/pages/subpage.js index 7c75b1379e..fd058387a0 100644 --- a/erpnext/public/js/hub/pages/subpage.js +++ b/erpnext/public/js/hub/pages/subpage.js @@ -1,3 +1,5 @@ +import { NotificationMessage } from '../components/notification_message'; + export default class SubPage { constructor(parent, options) { this.$parent = $(parent); @@ -42,4 +44,8 @@ export default class SubPage { hide() { this.$wrapper.hide(); } + + show_message(message) { + this.$wrapper.prepend(NotificationMessage(message)); + } } From 6faffa5007764e732912d030dd95e711c37b4605 Mon Sep 17 00:00:00 2001 From: Prateeksha Singh Date: Mon, 20 Aug 2018 14:02:33 +0530 Subject: [PATCH 7/9] [feat] new component: ItemPublishDialog --- .../js/hub/components/item_publish_dialog.js | 39 +++++ .../js/hub/components/publishing_area.js | 36 +++++ erpnext/public/js/hub/pages/publish.js | 149 +++++------------- 3 files changed, 118 insertions(+), 106 deletions(-) create mode 100644 erpnext/public/js/hub/components/item_publish_dialog.js create mode 100644 erpnext/public/js/hub/components/publishing_area.js diff --git a/erpnext/public/js/hub/components/item_publish_dialog.js b/erpnext/public/js/hub/components/item_publish_dialog.js new file mode 100644 index 0000000000..f751be0145 --- /dev/null +++ b/erpnext/public/js/hub/components/item_publish_dialog.js @@ -0,0 +1,39 @@ +function ItemPublishDialog(primary_action, secondary_action) { + let dialog = new frappe.ui.Dialog({ + title: __('Edit Publishing Details'), + fields: [ + { + "label": "Item Code", + "fieldname": "item_code", + "fieldtype": "Data", + "read_only": 1 + }, + { + "label": "Hub Category", + "fieldname": "hub_category", + "fieldtype": "Autocomplete", + "options": ["Agriculture", "Books", "Chemicals", "Clothing", + "Electrical", "Electronics", "Energy", "Fashion", "Food and Beverage", + "Health", "Home", "Industrial", "Machinery", "Packaging and Printing", + "Sports", "Transportation" + ], + "reqd": 1 + }, + { + "label": "Images", + "fieldname": "image_list", + "fieldtype": "MultiSelect", + "options": [], + "reqd": 1 + } + ], + primary_action_label: primary_action.label || __('Set Details'), + primary_action: primary_action.fn, + secondary_action: secondary_action.fn + }); + return dialog; +} + +export { + ItemPublishDialog +} diff --git a/erpnext/public/js/hub/components/publishing_area.js b/erpnext/public/js/hub/components/publishing_area.js new file mode 100644 index 0000000000..4775c3b16e --- /dev/null +++ b/erpnext/public/js/hub/components/publishing_area.js @@ -0,0 +1,36 @@ +function get_publishing_header() { + const title_html = `
    ${__('Select Products to Publish')}
    `; + + const subtitle_html = `

    + ${__(`Only products with an image, description and category can be published. + Please update them if an item in your inventory does not appear.`)} +

    `; + + const publish_button_html = ``; + + return $(` +
    +
    + ${title_html} + ${publish_button_html} +
    +
    +

    ${__('No Items Selected')}

    +
    +
    +
    + +
    +
    + ${subtitle_html} +
    +
    + `); +} + +export { + get_publishing_header +} diff --git a/erpnext/public/js/hub/pages/publish.js b/erpnext/public/js/hub/pages/publish.js index 8de7b3844c..98b0a61845 100644 --- a/erpnext/public/js/hub/pages/publish.js +++ b/erpnext/public/js/hub/pages/publish.js @@ -2,12 +2,13 @@ import SubPage from './subpage'; import { get_item_card_container_html } from '../components/items_container'; import { get_local_item_card_html } from '../components/item_card'; import { make_search_bar } from '../components/search_bar'; - +import { get_publishing_header } from '../components/publishing_area'; +import { ItemPublishDialog } from '../components/item_publish_dialog'; erpnext.hub.Publish = class Publish extends SubPage { make_wrapper() { super.make_wrapper(); - this.items_to_publish = {}; + this.items_data_to_publish = {}; this.unpublished_items = []; this.fetched_items = []; this.fetched_items_dict = {}; @@ -41,7 +42,7 @@ erpnext.hub.Publish = class Publish extends SubPage { make_publish_ready_state() { this.$wrapper.empty(); - this.$wrapper.append(this.get_publishing_header()); + this.$wrapper.append(get_publishing_header()); make_search_bar({ wrapper: this.$wrapper, @@ -53,46 +54,15 @@ erpnext.hub.Publish = class Publish extends SubPage { }); this.setup_publishing_events(); + this.show_last_sync_message(); + this.get_items_and_render(); + } + show_last_sync_message() { if(hub.settings.last_sync_datetime) { this.show_message(`Last sync was ${comment_when(hub.settings.last_sync_datetime)}. See your Published Products.`); } - - this.get_items_and_render(); - } - - get_publishing_header() { - const title_html = `
    ${__('Select Products to Publish')}
    `; - - const subtitle_html = `

    - ${__(`Only products with an image, description and category can be published. - Please update them if an item in your inventory does not appear.`)} -

    `; - - const publish_button_html = ``; - - return $(` -
    -
    - ${title_html} - ${publish_button_html} -
    -
    -

    ${__('No Items Selected')}

    -
    -
    -
    - -
    -
    - ${subtitle_html} -
    -
    - `); } setup_publishing_events() { @@ -118,69 +88,54 @@ erpnext.hub.Publish = class Publish extends SubPage { } make_publishing_dialog() { - this.publishing_dialog = new frappe.ui.Dialog({ - title: __('Edit Publishing Details'), - fields: [ - { - "label": "Item Code", - "fieldname": "item_code", - "fieldtype": "Data", - "read_only": 1 - }, - { - "label": "Hub Category", - "fieldname": "hub_category", - "fieldtype": "Autocomplete", - "options": ["Agriculture", "Books", "Chemicals", "Clothing", - "Electrical", "Electronics", "Energy", "Fashion", "Food and Beverage", - "Health", "Home", "Industrial", "Machinery", "Packaging and Printing", - "Sports", "Transportation" - ], - "reqd": 1 - }, - { - "label": "Images", - "fieldname": "image_list", - "fieldtype": "MultiSelect", - "options": [], - "reqd": 1 + this.item_publish_dialog = ItemPublishDialog( + { + fn: (values) => { + this.add_item_to_publish(values); + this.item_publish_dialog.hide(); } - ], - primary_action_label: __('Set Details'), - primary_action: () => { - const values = this.publishing_dialog.get_values(true); - this.items_to_publish[values.item_code] = values; - - this.$current_selected_card.appendTo(this.selected_items_container); - this.$current_selected_card.find('.hub-card').toggleClass('active'); - - this.update_selected_items_count(); - - this.publishing_dialog.hide(); }, - secondary_action: () => { - const values = this.publishing_dialog.get_values(true); - this.items_to_publish[values.item_code] = values; + { + fn: () => { + const values = this.item_publish_dialog.get_values(true); + this.update_items_data_to_publish(values); + } } - }); + ); + } + + add_item_to_publish(values) { + this.update_items_data_to_publish(values); + this.select_current_card() + } + + update_items_data_to_publish(values) { + this.items_data_to_publish[values.item_code] = values; + } + + select_current_card() { + this.$current_selected_card.appendTo(this.selected_items_container); + this.$current_selected_card.find('.hub-card').toggleClass('active'); + + this.update_selected_items_count(); } show_publishing_dialog_for_item(item_code) { - let item_data = this.items_to_publish[item_code]; + let item_data = this.items_data_to_publish[item_code]; if(!item_data) { item_data = { item_code }; }; - this.publishing_dialog.clear(); + this.item_publish_dialog.clear(); const item_doc = this.fetched_items_dict[item_code]; if(item_doc) { - this.publishing_dialog.fields_dict.image_list.set_data( + this.item_publish_dialog.fields_dict.image_list.set_data( item_doc.attachments.map(attachment => attachment.file_url) ); } - this.publishing_dialog.set_values(item_data); - this.publishing_dialog.show(); + this.item_publish_dialog.set_values(item_data); + this.item_publish_dialog.show(); } update_selected_items_count() { @@ -204,14 +159,6 @@ erpnext.hub.Publish = class Publish extends SubPage { this.$wrapper.find('.publish-area').toggleClass('filled', !is_empty); } - add_item_to_publish() { - // - } - - remove_item_from_publish() { - // - } - make_publish_in_progress_state() { this.$wrapper.empty(); @@ -238,8 +185,8 @@ erpnext.hub.Publish = class Publish extends SubPage { } show_publish_progress() { - const items_to_publish = this.items_to_publish.length - ? this.items_to_publish + const items_to_publish = this.items_data_to_publish.length + ? this.items_data_to_publish : JSON.parse(hub.settings.custom_data); const $publish_progress = $(`
    @@ -302,17 +249,7 @@ erpnext.hub.Publish = class Publish extends SubPage { item_codes_to_publish.push($(this).attr("data-id")); }); - // this.unpublished_items = this.fetched_items.filter(item => { - // return !item_codes_to_publish.includes(item.item_code); - // }); - - // const items_to_publish = this.fetched_items.filter(item => { - // return item_codes_to_publish.includes(item.item_code); - // }); - - // this.items_to_publish = items_to_publish; - - const items_data_to_publish = item_codes_to_publish.map(item_code => this.items_to_publish[item_code]) + const items_data_to_publish = item_codes_to_publish.map(item_code => this.items_data_to_publish[item_code]) return frappe.call( 'erpnext.hub_node.api.publish_selected_items', From e72a2fa9dea215aa3249719879ad6ab8ed4d6207 Mon Sep 17 00:00:00 2001 From: Prateeksha Singh Date: Mon, 20 Aug 2018 14:18:07 +0530 Subject: [PATCH 8/9] [hub] emit hub call event to set category options while publishing --- .../js/hub/components/item_publish_dialog.js | 15 ++++++++++----- erpnext/public/js/hub/hub_call.js | 1 + 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/erpnext/public/js/hub/components/item_publish_dialog.js b/erpnext/public/js/hub/components/item_publish_dialog.js index f751be0145..2c215799a4 100644 --- a/erpnext/public/js/hub/components/item_publish_dialog.js +++ b/erpnext/public/js/hub/components/item_publish_dialog.js @@ -12,11 +12,7 @@ function ItemPublishDialog(primary_action, secondary_action) { "label": "Hub Category", "fieldname": "hub_category", "fieldtype": "Autocomplete", - "options": ["Agriculture", "Books", "Chemicals", "Clothing", - "Electrical", "Electronics", "Energy", "Fashion", "Food and Beverage", - "Health", "Home", "Industrial", "Machinery", "Packaging and Printing", - "Sports", "Transportation" - ], + "options": [], "reqd": 1 }, { @@ -31,6 +27,15 @@ function ItemPublishDialog(primary_action, secondary_action) { primary_action: primary_action.fn, secondary_action: secondary_action.fn }); + + const hub_call_key = 'get_categories{}'; + + erpnext.hub.on(`response:${hub_call_key}`, () => { + dialog.fields_dict.hub_category.set_data( + erpnext.hub.cache[hub_call_key].map(d => d.name) + ); + }); + return dialog; } diff --git a/erpnext/public/js/hub/hub_call.js b/erpnext/public/js/hub/hub_call.js index d2eaab31b4..2ed19f2739 100644 --- a/erpnext/public/js/hub/hub_call.js +++ b/erpnext/public/js/hub/hub_call.js @@ -32,6 +32,7 @@ hub.call = function call_hub_method(method, args={}, setup_cache_invalidation = } erpnext.hub.cache[key] = r.message; + erpnext.hub.trigger(`response:${key}`); resolve(r.message); } reject(r); From 71b41b47713a4617fb4bc93e1c0a203648866d85 Mon Sep 17 00:00:00 2001 From: Prateeksha Singh Date: Mon, 20 Aug 2018 15:36:13 +0530 Subject: [PATCH 9/9] [hub] response data in hub call event trigger --- .../js/hub/components/item_publish_dialog.js | 16 +++++++++++++--- erpnext/public/js/hub/hub_call.js | 11 ++++++----- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/erpnext/public/js/hub/components/item_publish_dialog.js b/erpnext/public/js/hub/components/item_publish_dialog.js index 2c215799a4..a5d312c7b8 100644 --- a/erpnext/public/js/hub/components/item_publish_dialog.js +++ b/erpnext/public/js/hub/components/item_publish_dialog.js @@ -28,12 +28,22 @@ function ItemPublishDialog(primary_action, secondary_action) { secondary_action: secondary_action.fn }); - const hub_call_key = 'get_categories{}'; - erpnext.hub.on(`response:${hub_call_key}`, () => { + function set_hub_category_options(data) { dialog.fields_dict.hub_category.set_data( - erpnext.hub.cache[hub_call_key].map(d => d.name) + data.map(d => d.name) ); + } + + const hub_call_key = 'get_categories{}'; + const categories_cache = erpnext.hub.cache[hub_call_key]; + + if(categories_cache) { + set_hub_category_options(categories_cache); + } + + erpnext.hub.on(`response:${hub_call_key}`, (data) => { + set_hub_category_options(data.response); }); return dialog; diff --git a/erpnext/public/js/hub/hub_call.js b/erpnext/public/js/hub/hub_call.js index 2ed19f2739..d83aeeb6e4 100644 --- a/erpnext/public/js/hub/hub_call.js +++ b/erpnext/public/js/hub/hub_call.js @@ -24,16 +24,17 @@ hub.call = function call_hub_method(method, args={}, setup_cache_invalidation = }) .then(r => { if (r.message) { - if (r.message.error) { + const response = r.message; + if (response.error) { frappe.throw({ title: __('Marketplace Error'), - message: r.message.error + message: response.error }); } - erpnext.hub.cache[key] = r.message; - erpnext.hub.trigger(`response:${key}`); - resolve(r.message); + erpnext.hub.cache[key] = response; + erpnext.hub.trigger(`response:${key}`, { response }); + resolve(response); } reject(r); })