diff --git a/.eslintrc b/.eslintrc
index adc4aebb28..dd9e350b1b 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -134,7 +134,6 @@
"Webcam": true,
"PhotoSwipe": true,
"PhotoSwipeUI_Default": true,
- "fluxify": true,
"io": true,
"JsBarcode": true,
"L": true,
diff --git a/attributions.md b/attributions.md
index 43c6b14912..5afc9f9d46 100644
--- a/attributions.md
+++ b/attributions.md
@@ -11,7 +11,6 @@ The following 3rd-party software packages may be used by or distributed with
### Icon Fonts
diff --git a/frappe/public/js/frappe/views/kanban/kanban_board.js b/frappe/public/js/frappe/views/kanban/kanban_board.bundle.js
similarity index 84%
rename from frappe/public/js/frappe/views/kanban/kanban_board.js
rename to frappe/public/js/frappe/views/kanban/kanban_board.bundle.js
index 64e90f5326..c9793d6eb4 100644
--- a/frappe/public/js/frappe/views/kanban/kanban_board.js
+++ b/frappe/public/js/frappe/views/kanban/kanban_board.bundle.js
@@ -1,14 +1,17 @@
// TODO: Refactor for better UX
+import Vuex from 'vuex';
+
frappe.provide("frappe.views");
(function() {
var method_prefix = 'frappe.desk.doctype.kanban_board.kanban_board.';
- var store = fluxify.createStore({
- id: 'store',
- initialState: {
+ let columns_unwatcher = null;
+
+ var store = new Vuex.Store({
+ state: {
doctype: '',
board: {},
card_meta: {},
@@ -18,12 +21,16 @@ frappe.provide("frappe.views");
cur_list: {},
empty_state: true
},
- actionCallbacks: {
- init: function(updater, opts) {
- updater.set({
+ mutations: {
+ update_state(state, obj) {
+ Object.assign(state, obj);
+ }
+ },
+ actions: {
+ init: function(context, opts) {
+ context.commit("update_state", {
empty_state: true
});
-
var board = opts.board;
var card_meta = opts.card_meta;
opts.card_meta = card_meta;
@@ -32,8 +39,7 @@ frappe.provide("frappe.views");
return prepare_card(card, opts);
});
var columns = prepare_columns(board.columns);
-
- updater.set({
+ context.commit("update_state", {
doctype: opts.doctype,
board: board,
card_meta: card_meta,
@@ -44,20 +50,20 @@ frappe.provide("frappe.views");
wrapper: opts.wrapper
});
},
- update_cards: function(updater, cards) {
- var state = this;
+ update_cards: function(context, cards) {
+ var state = context.state;
var _cards = cards
.map(card => prepare_card(card, state))
- .concat(this.cards)
+ .concat(state.cards)
.uniqBy(card => card.name);
- updater.set({
+ context.commit("update_state", {
cards: _cards
});
},
- add_column: function(updater, col) {
+ add_column: function(context, col) {
if(frappe.model.can_create('Custom Field')) {
- fluxify.doAction('update_column', col, 'add');
+ store.dispatch('update_column', col, 'add');
} else {
frappe.msgprint({
title: __('Not permitted'),
@@ -66,15 +72,15 @@ frappe.provide("frappe.views");
});
}
},
- archive_column: function(updater, col) {
- fluxify.doAction('update_column', col, 'archive');
+ archive_column: function(context, col) {
+ store.dispatch('update_column', col, 'archive');
},
- restore_column: function(updater, col) {
- fluxify.doAction('update_column', col, 'restore');
+ restore_column: function(context, col) {
+ store.dispatch('update_column', col, 'restore');
},
- update_column: function(updater, col, action) {
- var doctype = this.doctype;
- var board = this.board;
+ update_column: function(context, col, action) {
+ var doctype = context.state.doctype;
+ var board = context.state.board;
fetch_customization(doctype)
.then(function(doc) {
return modify_column_field_in_c11n(doc, board, col.title, action);
@@ -84,23 +90,23 @@ frappe.provide("frappe.views");
return update_kanban_board(board.name, col.title, action);
}).then(function(r) {
var cols = r.message;
- updater.set({
+ context.commit("update_state", {
columns: prepare_columns(cols)
});
}, function(err) {
console.error(err); // eslint-disable-line
});
},
- add_card: function(updater, card_title, column_title) {
- var doc = frappe.model.get_new_doc(this.doctype);
- var field = this.card_meta.title_field;
- var quick_entry = this.card_meta.quick_entry;
- var state = this;
+ add_card: function(context, card_title, column_title) {
+ var state = context.state;
+ var doc = frappe.model.get_new_doc(state.doctype);
+ var field = state.card_meta.title_field;
+ var quick_entry = state.card_meta.quick_entry;
var doc_fields = {};
doc_fields[field.fieldname] = card_title;
- doc_fields[this.board.field_name] = column_title;
- this.cur_list.filter_area.get().forEach(function(f) {
+ doc_fields[state.board.field_name] = column_title;
+ state.cur_list.filter_area.get().forEach(function(f) {
if (f[2] !== "=") return;
doc_fields[f[1]] = f[3];
});
@@ -114,7 +120,7 @@ frappe.provide("frappe.views");
const cards = [...state.cards, card];
// remember the name which we will override later
const old_name = doc.name;
- updater.set({ cards });
+ context.commit("update_state", { cards });
if (field && !quick_entry) {
return insert_doc(doc)
@@ -125,49 +131,49 @@ frappe.provide("frappe.views");
const card = prepare_card(updated_doc, state);
const new_cards = state.cards.slice();
new_cards[index] = card;
- updater.set({ cards: new_cards });
+ context.commit("update_state", { cards: new_cards });
const args = {
new: 1,
name: card.name,
colname: updated_doc[state.board.field_name],
};
- fluxify.doAction('update_order_for_single_card', args);
+ store.dispatch('update_order_for_single_card', args);
});
} else {
- frappe.new_doc(this.doctype, doc);
+ frappe.new_doc(state.doctype, doc);
}
},
- update_card: function(updater, card) {
+ update_card: function(context, card) {
var index = -1;
- this.cards.forEach(function(c, i) {
+ context.state.cards.forEach(function(c, i) {
if (c.name === card.name) {
index = i;
}
});
- var cards = this.cards.slice();
+ var cards = context.state.cards.slice();
if (index !== -1) {
cards.splice(index, 1, card);
}
- updater.set({ cards: cards });
+ context.commit("update_state", { cards: cards });
},
- update_order_for_single_card: function(updater, card) {
+ update_order_for_single_card: function(context, card) {
// cache original order
- const _cards = this.cards.slice();
- const _columns = this.columns.slice();
+ const _cards = context.state.cards.slice();
+ const _columns = context.state.columns.slice();
let args = {};
let method_name = "";
if (card.new) {
method_name = "add_card";
args = {
- board_name: this.board.name,
+ board_name: context.state.board.name,
docname: card.name,
colname: card.colname,
};
} else {
method_name = "update_order_for_single_card";
args = {
- board_name: this.board.name,
+ board_name: context.state.board.name,
docname: card.name,
from_colname: card.from_colname,
to_colname: card.to_colname,
@@ -184,7 +190,7 @@ frappe.provide("frappe.views");
let updated_cards = [{'name': card.name, 'column': card.to_colname || card.colname}];
let cards = update_cards_column(updated_cards);
let columns = prepare_columns(board.columns);
- updater.set({
+ context.commit("update_state", {
cards: cards,
columns: columns
});
@@ -192,20 +198,20 @@ frappe.provide("frappe.views");
}
}).fail(function() {
// revert original order
- updater.set({
+ context.commit("update_state", {
cards: _cards,
columns: _columns
});
frappe.dom.unfreeze();
});
},
- update_order: function(updater) {
+ update_order: function(context) {
// cache original order
- const _cards = this.cards.slice();
- const _columns = this.columns.slice();
+ const _cards = context.state.cards.slice();
+ const _columns = context.state.columns.slice();
const order = {};
- this.wrapper.find('.kanban-column[data-column-value]')
+ context.state.wrapper.find('.kanban-column[data-column-value]')
.each(function() {
var col_name = $(this).data().columnValue;
order[col_name] = [];
@@ -218,7 +224,7 @@ frappe.provide("frappe.views");
frappe.call({
method: method_prefix + "update_order",
args: {
- board_name: this.board.name,
+ board_name: context.state.board.name,
order: order
},
callback: (r) => {
@@ -226,46 +232,46 @@ frappe.provide("frappe.views");
var updated_cards = r.message[1];
var cards = update_cards_column(updated_cards);
var columns = prepare_columns(board.columns);
- updater.set({
+ context.commit("update_state", {
cards: cards,
columns: columns
});
}
}).fail(function() {
// revert original order
- updater.set({
+ context.commit("update_state", {
cards: _cards,
columns: _columns
});
});
},
- update_column_order: function(updater, order) {
+ update_column_order: function(context, order) {
return frappe.call({
method: method_prefix + "update_column_order",
args: {
- board_name: this.board.name,
+ board_name: context.state.board.name,
order: order
}
}).then(function(r) {
var board = r.message;
var columns = prepare_columns(board.columns);
- updater.set({
+ context.commit("update_state", {
columns: columns
});
});
},
- set_indicator: function(updater, column, color) {
+ set_indicator: function(context, column, color) {
return frappe.call({
method: method_prefix + "set_indicator",
args: {
- board_name: this.board.name,
+ board_name: context.state.board.name,
column_name: column.title,
indicator: color
}
}).then(function(r) {
var board = r.message;
var columns = prepare_columns(board.columns);
- updater.set({
+ context.commit("update_state", {
columns: columns
});
});
@@ -285,20 +291,29 @@ frappe.provide("frappe.views");
opts.cards = cards;
if(self.wrapper.find('.kanban').length > 0 && self.cur_list.start !== 0) {
- fluxify.doAction('update_cards', cards);
+ store.dispatch('update_cards', cards);
} else {
init();
}
};
function init() {
- fluxify.doAction('init', opts);
- store.off('change:columns').on('change:columns', make_columns);
+ store.dispatch('init', opts);
+ columns_unwatcher && columns_unwatcher();
+ store.watch((state, getters) => {
+ return state.columns;
+ }, make_columns);
prepare();
- store.on('change:cur_list', setup_restore_columns);
- store.on('change:columns', setup_restore_columns);
- store.on('change:empty_state', show_empty_state);
- fluxify.doAction('update_order');
+ store.watch((state, getters) => {
+ return state.cur_list;
+ }, setup_restore_columns);
+ columns_unwatcher = store.watch((state, getters) => {
+ return state.columns;
+ }, setup_restore_columns);
+ store.watch((state, getters) => {
+ return state.empty_state;
+ }, show_empty_state);
+ store.dispatch('update_order');
}
function prepare() {
@@ -316,7 +331,7 @@ frappe.provide("frappe.views");
function make_columns() {
self.$kanban_board.find(".kanban-column").not(".add-new-column").remove();
- var columns = store.getState().columns;
+ var columns = store.state.columns;
columns.filter(is_active_column).map(function(col) {
frappe.views.KanbanBoardColumn(col, self.$kanban_board);
@@ -338,7 +353,7 @@ frappe.provide("frappe.views");
onEnd: function() {
var order = sortable.toArray();
order = order.slice(1);
- fluxify.doAction('update_column_order', order);
+ store.dispatch('update_column_order', order);
}
});
}
@@ -365,7 +380,7 @@ frappe.provide("frappe.views");
var col = {
title: title.trim()
};
- fluxify.doAction('add_column', col);
+ store.dispatch('add_column', col);
$compose_column_form.find('input').val('');
$compose_column.show();
$compose_column_form.hide();
@@ -421,8 +436,8 @@ frappe.provide("frappe.views");
}
function setup_restore_columns() {
- var cur_list = store.getState().cur_list;
- var columns = store.getState().columns;
+ var cur_list = store.state.cur_list;
+ var columns = store.state.columns;
var list_row_right = cur_list.$page
.find(`[data-list-renderer='Kanban'] .list-row-right`)
.css('margin-right', '15px');
@@ -456,12 +471,12 @@ frappe.provide("frappe.views");
title: column_title,
status: 'Archived'
};
- fluxify.doAction('restore_column', col);
+ store.dispatch('restore_column', col);
});
}
function show_empty_state() {
- var empty_state = store.getState().empty_state;
+ var empty_state = store.state.empty_state;
if(empty_state) {
self.$kanban_board.find('.kanban-column').hide();
@@ -485,7 +500,9 @@ frappe.provide("frappe.views");
make_dom();
setup_sortable();
make_cards();
- store.on('change:cards', make_cards);
+ store.watch((state, getters) => {
+ return state.cards;
+ }, make_cards);
bind_add_card();
bind_options();
}
@@ -494,7 +511,7 @@ frappe.provide("frappe.views");
self.$kanban_column = $(frappe.render_template(
'kanban_column', {
title: column.title,
- doctype: store.getState().doctype,
+ doctype: store.state.doctype,
indicator: frappe.scrub(column.indicator, '-')
})).appendTo(wrapper);
self.$kanban_cards = self.$kanban_column.find('.kanban-cards');
@@ -502,7 +519,7 @@ frappe.provide("frappe.views");
function make_cards() {
self.$kanban_cards.empty();
- var cards = store.getState().cards;
+ var cards = store.state.cards;
filtered_cards = get_cards_for_column(cards, column);
var filtered_cards_names = filtered_cards.map(card => card.name);
@@ -548,7 +565,7 @@ frappe.provide("frappe.views");
old_index: e.oldIndex,
new_index: e.newIndex,
};
- fluxify.doAction('update_order_for_single_card', args);
+ store.dispatch('update_order_for_single_card', args);
},
onAdd: function() {
},
@@ -579,7 +596,7 @@ frappe.provide("frappe.views");
var card_title = $textarea.val();
$new_card_area.hide();
$textarea.val('');
- fluxify.doAction('add_card', card_title, column.title)
+ store.dispatch('add_card', card_title, column.title)
.then(() => {
$btn_add.show();
});
@@ -602,10 +619,10 @@ frappe.provide("frappe.views");
var action = $btn.data().action;
if (action === "archive") {
- fluxify.doAction('archive_column', column);
+ store.dispatch('archive_column', column);
} else if (action === "indicator") {
var color = $btn.data().indicator;
- fluxify.doAction('set_indicator', column, color);
+ store.dispatch('set_indicator', column, color);
}
});
get_column_indicators(function(indicators) {
@@ -728,7 +745,7 @@ frappe.provide("frappe.views");
callback: function() {
const users = self.assign_to_dialog.get_values().assign_to;
card.assigned_list = [...new Set(card.assigned_list.concat(users))];
- fluxify.doAction('update_card', card);
+ store.dispatch('update_card', card);
}
});
self.assign_to_dialog = self.assign_to.dialog;
@@ -850,21 +867,6 @@ frappe.provide("frappe.views");
});
}
- function is_filters_modified(board, cur_list) {
- return new Promise(function(resolve) {
- setTimeout(function() {
- try {
- var list_filters = JSON.stringify(cur_list.filter_area.get());
- resolve(list_filters !== board.filters);
- } catch(e) {
- // sometimes the filter_list is not initiated
- resolve(false);
- }
-
- }, 2000);
- });
- }
-
function is_active_column(col) {
return col.status !== 'Archived';
}
@@ -876,13 +878,13 @@ frappe.provide("frappe.views");
}
function get_card(name) {
- return store.getState().cards.find(function(c) {
+ return store.state.cards.find(function(c) {
return c.name === name;
});
}
function update_cards_column(updated_cards) {
- var cards = store.getState().cards;
+ var cards = store.state.cards;
cards.forEach(function(c) {
updated_cards.forEach(function(uc) {
if(uc.name === c.name) {
@@ -909,22 +911,4 @@ frappe.provide("frappe.views");
callback(indicators);
});
}
-
- function isBound(el, event, fn) {
- var events = $._data(el[0], 'events');
- if(!events) return false;
- var handlers = events[event];
- var flag = false;
- handlers.forEach(function(h) {
- if(h.handler.name === fn.name)
- flag = true;
- });
- return flag;
- }
-
- function remove_img_tags(html) {
- const $temp = $(`
${html}
`);
- $temp.find('img').remove();
- return $temp.html();
- }
})();
diff --git a/frappe/public/js/frappe/views/kanban/kanban_view.js b/frappe/public/js/frappe/views/kanban/kanban_view.js
index 129db13b07..f38cb906a2 100644
--- a/frappe/public/js/frappe/views/kanban/kanban_view.js
+++ b/frappe/public/js/frappe/views/kanban/kanban_view.js
@@ -209,10 +209,7 @@ frappe.views.KanbanView = class KanbanView extends frappe.views.ListView {
}
get required_libs() {
- return [
- 'assets/frappe/js/lib/fluxify.min.js',
- 'assets/frappe/js/frappe/views/kanban/kanban_board.js'
- ];
+ return 'kanban_board.bundle.js';
}
};
diff --git a/frappe/public/js/lib/fluxify.min.js b/frappe/public/js/lib/fluxify.min.js
deleted file mode 100644
index 586630486a..0000000000
--- a/frappe/public/js/lib/fluxify.min.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/*
-fluxify v0.2.3
-https://github.com/arqex/fluxify
-GNU-2: https://github.com/arqex/fluxify/raw/master/LICENSE
-*/
-!function(t,e){"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?module.exports=e():t.fluxify=e()}(this,function(){"use strict";var t={_extend:function(t){for(var e,i,r=0;r=0;i--)r[i].callback===e&&r.splice(i,1)}return this},trigger:function(t){var e,i,r=[].slice.call(arguments,1),n=this._events[t]||[],s=[];for(e=0;e=0;e--)n.splice(s[e],1);return this}};t._extend(i,{addListener:i.on,removeListener:i.off,removeAllListeners:i.off,emit:i.trigger}),e.prototype={};for(var r in i)Object.defineProperty(e.prototype,r,{value:i[r]});Object.defineProperty(e,"_extend",{value:function(e){var i,r=this;i=e&&e.hasOwnProperty(constructor)?e.constructor:function(){return r.apply(this,arguments)},t._extend(i,r);var n=function(){Object.defineProperty(this,"constructor",{value:i})};if(n.prototype=r.prototype,i.prototype=new n,e)for(var s in e)"constructor"!=s&&Object.defineProperty(i.prototype,s,{value:e[s]});return i.__super__=r.prototype,i}});var n=e._extend({initialize:function(t){if(!t)return this.props={};this.props={};for(var e in t)this.props[e]=t[e]},get:function(t){return this.props[t]},set:function(t,e){var i,r,n=t,s=[];"undefined"!=typeof e&&(n={},n[t]=e);for(r in n)this.props[r]!=n[r]&&(i=this.props[r],this.props[r]=n[r],s.push({prop:r,previousValue:i,value:n[r]}));s.length&&this.emit("change",s)}}),s=e._extend({initialize:function(t){var e,i,r=this,s=t||{},o=new n(s.initialState);t.id&&Object.defineProperty(this,"_id",{value:t.id}),Object.defineProperties(this,{_callbacks:{writable:!0,configurable:!0,value:{}},addActionCallbacks:{value:function(t){for(e in t)r._callbacks[e]=t[e].bind(this,o)}},callback:{value:function(){var t=arguments[0],e=[].slice.call(arguments,1);return this._callbacks[t]?this._callbacks[t].apply(this,e):!0}.bind(this)}}),this.addActionCallbacks(s.actionCallbacks||{});var a=function(t){Object.defineProperty(r,t,{enumerable:!0,configurable:!1,get:function(){return o.get(t)}})};if(s.initialState)for(i in s.initialState)a(i,s.initialState[i]);o.on("change",function(t){var e,i,n=t.length;for(i=0;n>i;i++)e=t[i],r.hasOwnProperty(e.prop)||a(e.prop,e.value),r.emit("change:"+e.prop,e.value,e.previousValue);r.emit("change",t)})},getState:function(){return t._extend({},this)},waitFor:function(t){return this._dispatcher.waitFor(t)}}),o=function(){this._callbacks={},this._dispatchQueue=[],this._currentDispatch=!1,this._ID=1,"undefined"!=typeof Promise&&(this._Promise=Promise)};o.prototype={register:function(t,e){var i=t;return"function"==typeof t&&(i="ID_"+this._ID,e=t),this._callbacks[i]=e,this._ID++,i},registerStore:function(t,e){return Object.defineProperty(e,"_dispatcher",{value:this}),this.register(t,e.callback)},unregister:function(t){delete this._callbacks[t]},waitFor:function(t){var e=[],i=0;for(Array.isArray(t)||(t=[t]);i