Merge branch 'hub-redesign' of https://github.com/frappe/erpnext into hub-redesign
This commit is contained in:
commit
8de6380648
@ -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,22 +32,32 @@ 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()
|
||||
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'),
|
||||
'image_list': item.get('image_list')
|
||||
}).insert()
|
||||
|
||||
try:
|
||||
hub_settings = frappe.get_doc('Hub Settings')
|
||||
item_sync_preprocess()
|
||||
|
@ -1,19 +1,25 @@
|
||||
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
|
||||
doc.image_list = cached_details.image_list
|
||||
|
||||
return doc
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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": "image_list",
|
||||
"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": "Image List",
|
||||
"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 22:24:06.207307",
|
||||
"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
|
||||
}
|
54
erpnext/public/js/hub/components/item_publish_dialog.js
Normal file
54
erpnext/public/js/hub/components/item_publish_dialog.js
Normal file
@ -0,0 +1,54 @@
|
||||
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": [],
|
||||
"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
|
||||
});
|
||||
|
||||
|
||||
function set_hub_category_options(data) {
|
||||
dialog.fields_dict.hub_category.set_data(
|
||||
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;
|
||||
}
|
||||
|
||||
export {
|
||||
ItemPublishDialog
|
||||
}
|
20
erpnext/public/js/hub/components/notification_message.js
Normal file
20
erpnext/public/js/hub/components/notification_message.js
Normal file
@ -0,0 +1,20 @@
|
||||
const NotificationMessage = (message) => {
|
||||
const $message = $(`<div class="subpage-message">
|
||||
<p class="text-muted flex">
|
||||
<span>
|
||||
${message}
|
||||
</span>
|
||||
<i class="octicon octicon-x text-extra-muted"></i>
|
||||
</p>
|
||||
</div>`);
|
||||
|
||||
$message.find('.octicon-x').on('click', () => {
|
||||
$message.remove();
|
||||
});
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
export {
|
||||
NotificationMessage
|
||||
}
|
77
erpnext/public/js/hub/components/profile_dialog.js
Normal file
77
erpnext/public/js/hub/components/profile_dialog.js
Normal file
@ -0,0 +1,77 @@
|
||||
const ProfileDialog = (title = __('Edit Profile'), action={}, initial_values={}) => {
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
dialog.set_values(initial_values);
|
||||
|
||||
// Post create
|
||||
const default_company = frappe.defaults.get_default('company');
|
||||
dialog.set_value('company', default_company);
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
export {
|
||||
ProfileDialog
|
||||
}
|
36
erpnext/public/js/hub/components/publishing_area.js
Normal file
36
erpnext/public/js/hub/components/publishing_area.js
Normal file
@ -0,0 +1,36 @@
|
||||
function get_publishing_header() {
|
||||
const title_html = `<h5>${__('Select Products to Publish')}</h5>`;
|
||||
|
||||
const subtitle_html = `<p class="text-muted">
|
||||
${__(`Only products with an image, description and category can be published.
|
||||
Please update them if an item in your inventory does not appear.`)}
|
||||
</p>`;
|
||||
|
||||
const publish_button_html = `<button class="btn btn-primary btn-sm publish-items" disabled>
|
||||
<i class="visible-xs octicon octicon-check"></i>
|
||||
<span class="hidden-xs">${__('Publish')}</span>
|
||||
</button>`;
|
||||
|
||||
return $(`
|
||||
<div class="publish-area empty">
|
||||
<div class="flex justify-between align-flex-end">
|
||||
${title_html}
|
||||
${publish_button_html}
|
||||
</div>
|
||||
<div class="empty-items-container flex align-center flex-column justify-center">
|
||||
<p class="text-muted">${__('No Items Selected')}</p>
|
||||
</div>
|
||||
<div class="row hub-items-container selected-items"></div>
|
||||
</div>
|
||||
|
||||
<div class='subpage-title flex'>
|
||||
<div>
|
||||
${subtitle_html}
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
|
||||
export {
|
||||
get_publishing_header
|
||||
}
|
@ -31,15 +31,17 @@ hub.call = function call_hub_method(method, args={}, clear_cache_on_event) {
|
||||
})
|
||||
.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;
|
||||
resolve(r.message);
|
||||
erpnext.hub.cache[key] = response;
|
||||
erpnext.hub.trigger(`response:${key}`, { response });
|
||||
resolve(response);
|
||||
}
|
||||
reject(r);
|
||||
})
|
||||
|
@ -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';
|
||||
import EventEmitter from './event_emitter';
|
||||
@ -49,6 +52,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() {
|
||||
@ -79,7 +92,7 @@ erpnext.hub.Marketplace = class Marketplace {
|
||||
${__('Messages')}
|
||||
</li>`
|
||||
|
||||
: `<li class="hub-sidebar-item text-muted" data-route="marketplace/register">
|
||||
: `<li class="hub-sidebar-item text-muted" data-action="show_register_dialog">
|
||||
${__('Become a seller')}
|
||||
</li>`;
|
||||
|
||||
@ -218,4 +231,30 @@ erpnext.hub.Marketplace = class Marketplace {
|
||||
frappe.utils.scroll_to(0);
|
||||
this.subpages[route[1]].show();
|
||||
}
|
||||
|
||||
show_register_dialog() {
|
||||
this.register_dialog = ProfileDialog(
|
||||
__('Become a Seller'),
|
||||
{
|
||||
label: __('Register'),
|
||||
on_submit: this.register_seller.bind(this)
|
||||
}
|
||||
);
|
||||
|
||||
this.register_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.register_dialog.hide();
|
||||
frappe.set_route('marketplace', 'publish');
|
||||
|
||||
// custom jquery event
|
||||
this.$body.trigger('seller-registered');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,30 @@
|
||||
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() {
|
||||
super.make_wrapper();
|
||||
this.make_edit_profile_dialog();
|
||||
}
|
||||
|
||||
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 });
|
||||
}
|
||||
|
||||
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 +57,7 @@ erpnext.hub.Profile = class Profile extends SubPage {
|
||||
<img src="${p.logo}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-8">
|
||||
<h2>${p.company}</h2>
|
||||
<div class="text-muted">
|
||||
<p>${p.country}</p>
|
||||
@ -60,6 +71,16 @@ erpnext.hub.Profile = class Profile extends SubPage {
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-1">
|
||||
<div class="dropdown pull-right hub-item-dropdown">
|
||||
<a class="dropdown-toggle btn btn-xs btn-default" data-toggle="dropdown">
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-right" role="menu">
|
||||
<li><a data-action="edit_profile">${__('Edit Profile')}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="timeline">
|
||||
@ -73,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 `<div class="media timeline-item notification-content">
|
||||
<div class="small">
|
||||
@ -95,4 +143,4 @@ erpnext.hub.Profile = class Profile extends SubPage {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,13 +2,19 @@ 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 = {};
|
||||
|
||||
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+'%');
|
||||
@ -36,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,
|
||||
@ -48,37 +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 <a href="#marketplace/profile">${comment_when(hub.settings.last_sync_datetime)}</a>.
|
||||
<a href="#marketplace/my-products">See your Published Products</a>.`);
|
||||
}
|
||||
|
||||
this.get_items_and_render();
|
||||
}
|
||||
|
||||
get_publishing_header() {
|
||||
const title_html = `<b>${__('Select Products to Publish')}</b>`;
|
||||
|
||||
const subtitle_html = `<p class="text-muted">
|
||||
${__(`Only products with an image, description and category can be published.
|
||||
Please update them if an item in your inventory does not appear.`)}
|
||||
</p>`;
|
||||
|
||||
const publish_button_html = `<button class="btn btn-primary btn-sm publish-items">
|
||||
<i class="visible-xs octicon octicon-check"></i>
|
||||
<span class="hidden-xs">${__('Publish')}</span>
|
||||
</button>`;
|
||||
|
||||
return $(`
|
||||
<div class='subpage-title flex'>
|
||||
<div>
|
||||
${title_html}
|
||||
${subtitle_html}
|
||||
</div>
|
||||
${publish_button_html}
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
|
||||
setup_publishing_events() {
|
||||
@ -87,42 +71,92 @@ 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.$wrapper.find('.publish-items')
|
||||
.text(button_label)
|
||||
.prop('disabled', total_items === 0);
|
||||
});
|
||||
}
|
||||
|
||||
show_message(message) {
|
||||
const $message = $(`<div class="subpage-message">
|
||||
<p class="text-muted flex">
|
||||
<span>
|
||||
${message}
|
||||
</span>
|
||||
<i class="octicon octicon-x text-extra-muted"></i>
|
||||
</p>
|
||||
</div>`);
|
||||
make_publishing_dialog() {
|
||||
this.item_publish_dialog = ItemPublishDialog(
|
||||
{
|
||||
fn: (values) => {
|
||||
this.add_item_to_publish(values);
|
||||
this.item_publish_dialog.hide();
|
||||
}
|
||||
},
|
||||
{
|
||||
fn: () => {
|
||||
const values = this.item_publish_dialog.get_values(true);
|
||||
this.update_items_data_to_publish(values);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
$message.find('.octicon-x').on('click', () => {
|
||||
$message.remove();
|
||||
});
|
||||
add_item_to_publish(values) {
|
||||
this.update_items_data_to_publish(values);
|
||||
this.select_current_card()
|
||||
}
|
||||
|
||||
this.$wrapper.prepend($message);
|
||||
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_data_to_publish[item_code];
|
||||
|
||||
if(!item_data) { item_data = { item_code }; };
|
||||
|
||||
this.item_publish_dialog.clear();
|
||||
|
||||
const item_doc = this.fetched_items_dict[item_code];
|
||||
if(item_doc) {
|
||||
this.item_publish_dialog.fields_dict.image_list.set_data(
|
||||
item_doc.attachments.map(attachment => attachment.file_url)
|
||||
);
|
||||
}
|
||||
|
||||
this.item_publish_dialog.set_values(item_data);
|
||||
this.item_publish_dialog.show();
|
||||
}
|
||||
|
||||
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;
|
||||
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', is_empty);
|
||||
|
||||
this.$wrapper.find('.publish-area').toggleClass('empty', is_empty);
|
||||
this.$wrapper.find('.publish-area').toggleClass('filled', !is_empty);
|
||||
}
|
||||
|
||||
make_publish_in_progress_state() {
|
||||
@ -137,7 +171,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 => {
|
||||
@ -151,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 = $(`<div class="sync-progress">
|
||||
@ -191,6 +225,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() {
|
||||
@ -211,19 +249,12 @@ 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_data_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
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ body[data-route^="marketplace/"] {
|
||||
padding-right: 25px;
|
||||
}
|
||||
|
||||
[data-route] {
|
||||
[data-route], [data-action] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user