diff --git a/addons/crm/static/src/js/tour.js b/addons/crm/static/src/js/tour.js
index 66db8f9d43e..5895c8f14b9 100644
--- a/addons/crm/static/src/js/tour.js
+++ b/addons/crm/static/src/js/tour.js
@@ -71,7 +71,7 @@ tour.STEPS.MENU_MORE, {
content: _t("Configuration options are available in the Settings app."),
position: "bottom"
}, {
- trigger: ".o_web_settings_dashboard textarea#user_emails",
+ trigger: ".o_web_settings_dashboard .o_user_emails",
content: _t("Invite coworkers via email.
Enter one email per line."),
position: "right"
}, tour.STEPS.TOGGLE_HOME_MENU,
diff --git a/addons/project/static/src/js/tour.js b/addons/project/static/src/js/tour.js
index 270206c80d7..c0aeaa15924 100644
--- a/addons/project/static/src/js/tour.js
+++ b/addons/project/static/src/js/tour.js
@@ -94,7 +94,7 @@ tour.STEPS.MENU_MORE, {
content: _t("Configuration options are available in the Settings app."),
position: "bottom"
}, {
- trigger: ".o_web_settings_dashboard textarea#user_emails",
+ trigger: ".o_web_settings_dashboard .o_user_emails",
content: _t("Invite coworkers via email.
Enter one email per line."),
position: "right"
}, tour.STEPS.TOGGLE_HOME_MENU,
diff --git a/addons/web_settings_dashboard/controllers/main.py b/addons/web_settings_dashboard/controllers/main.py
index fdda07c5090..21423ec902d 100644
--- a/addons/web_settings_dashboard/controllers/main.py
+++ b/addons/web_settings_dashboard/controllers/main.py
@@ -32,6 +32,7 @@ class WebSettingsDashboard(http.Controller):
SELECT count(u.*)
FROM res_users u
WHERE active=true AND
+ share=false AND
NOT exists(SELECT 1 FROM res_users_log WHERE create_uid=u.id)
""")
pending_count = cr.dictfetchall()[0].get('count')
@@ -39,8 +40,9 @@ class WebSettingsDashboard(http.Controller):
cr.execute("""
SELECT id, login
FROM res_users u
- WHERE active=true
- AND NOT exists(SELECT 1 FROM res_users_log WHERE create_uid=u.id)
+ WHERE active=true AND
+ share=false AND
+ NOT exists(SELECT 1 FROM res_users_log WHERE create_uid=u.id)
ORDER BY id desc
LIMIT 10
""")
diff --git a/addons/web_settings_dashboard/static/src/js/dashboard.js b/addons/web_settings_dashboard/static/src/js/dashboard.js
index 06f24ab8735..d5705c80e42 100644
--- a/addons/web_settings_dashboard/static/src/js/dashboard.js
+++ b/addons/web_settings_dashboard/static/src/js/dashboard.js
@@ -61,55 +61,86 @@ var Dashboard = AbstractAction.extend({
load_company: function (data) {
return new DashboardCompany(this, data.company).replace(this.$('.o_web_settings_dashboard_company'));
- }
+ },
});
var DashboardInvitations = Widget.extend({
template: 'DashboardInvitations',
events: {
- 'click .o_web_settings_dashboard_invitations': 'send_invitations',
+ 'click .o_web_settings_dashboard_invite': '_onClickInvite',
'click .o_web_settings_dashboard_access_rights': 'on_access_rights_clicked',
'click .o_web_settings_dashboard_user': 'on_user_clicked',
'click .o_web_settings_dashboard_more': 'on_more',
+ 'click .o_badge_remove': '_onClickBadgeRemove',
+ 'keydown .o_user_emails': '_onKeydownUserEmails',
},
- init: function(parent, data){
+ init: function(parent, data) {
this.data = data;
this.parent = parent;
+ this.emails = [];
return this._super.apply(this, arguments);
},
- send_invitations: function(e){
- var self = this;
- var $target = $(e.currentTarget);
- var user_emails = _.filter($(e.delegateTarget).find('#user_emails').val().split(/[\n, ]/), function(email){
- return email !== "";
- });
- var re = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,63}(?:\.[a-z]{2})?)$/i;
- var is_valid_emails = _.every(user_emails, function(email) {
- return re.test(email);
- });
- if (is_valid_emails) {
- // Disable button
- $target.prop('disabled', true);
- $target.find('i.fa-cog').removeClass('hidden');
- // Try to create user accountst
- this._rpc({
- model: 'res.users',
- method: 'web_dashboard_create_users',
- args: [user_emails],
- })
- .then(function() {
- self.reload();
- })
- .always(function() {
- // Re-enable button
- $(e.delegateTarget).find('.o_web_settings_dashboard_invitations').prop('disabled', false);
- $(e.delegateTarget).find('i.fa-cog').addClass('hidden');
- });
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * Creates and appends badges for valid and unique email addresses
+ *
+ * @private
+ */
+ _createBadges: function () {
+ var $userEmails = this.$('.o_user_emails');
+ var value = $userEmails.val().trim();
+ if (value) {
+ // filter out duplicates
+ var emails = _.uniq(value.split(/[ ,;\n]+/));
+
+ // filter out invalid email addresses
+ var invalidEmails = _.reject(emails, this._validateEmail.bind(this));
+ if (invalidEmails.length) {
+ this.do_warn(_.str.sprintf(_t('The following email addresses are invalid: %s.'), invalidEmails.join(', ')));
+ }
+ emails = _.difference(emails, invalidEmails);
+
+ // filter out already processed or pending addresses
+ var pendingEmails = _.map(this.data.pending_users, function (info) {
+ return info[1];
+ });
+ var existingEmails = _.intersection(emails, this.emails.concat(pendingEmails));
+ if (existingEmails.length) {
+ this.do_warn(_.str.sprintf(_t('The following email addresses already exist: %s.'), existingEmails.join(', ')));
+ }
+ emails = _.difference(emails, existingEmails);
+
+ // add valid email addresses, if any
+ if (emails.length) {
+ this.emails = this.emails.concat(emails);
+ $userEmails.before(QWeb.render('EmailBadge', {emails: emails}));
+ $userEmails.val('');
+ }
}
- else {
- this.do_warn(_t("Please provide valid email addresses"), "");
- }
+ },
+ /**
+ * Removes a given badge from the DOM, and its associated email address
+ *
+ * @private
+ * @param {jQueryElement} $badge
+ */
+ _removeBadge: function ($badge) {
+ var email = $badge.text().trim();
+ this.emails = _.without(this.emails, email);
+ $badge.remove();
+ },
+ /**
+ * @private
+ * @param {string} email
+ * @returns {boolean} true iff the given email address is valid
+ */
+ _validateEmail: function (email) {
+ var re = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,63}(?:\.[a-z]{2})?)$/i;
+ return re.test(email);
},
on_access_rights_clicked: function (e) {
var self = this;
@@ -138,11 +169,13 @@ var DashboardInvitations = Widget.extend({
var self = this;
e.preventDefault();
var action = {
+ name: _t('Users'),
type: 'ir.actions.act_window',
view_type: 'form',
view_mode: 'tree,form',
res_model: 'res.users',
domain: [['log_ids', '=', false]],
+ context: {search_default_no_share: true},
views: [[false, 'list'], [false, 'form']],
};
this.do_action(action,{
@@ -152,6 +185,58 @@ var DashboardInvitations = Widget.extend({
reload:function(){
return this.parent.load(['invitations']);
},
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * @param {MouseEvent} ev
+ */
+ _onClickBadgeRemove: function (ev) {
+ var $badge = $(ev.target).closest('.badge');
+ this._removeBadge($badge);
+ },
+ /**
+ * @private
+ * @param {MouseEvent} ev
+ */
+ _onClickInvite: function (ev) {
+ var self = this;
+ this._createBadges();
+ if (this.emails.length) {
+ var $button = $(ev.target);
+ $button.button('loading');
+ this._rpc({
+ model: 'res.users',
+ method: 'web_dashboard_create_users',
+ args: [this.emails],
+ })
+ .then(function () {
+ self.reload();
+ })
+ .fail(function () {
+ $button.button('reset');
+ });
+ }
+ },
+ /**
+ * @private
+ * @param {KeyboardEvent} ev
+ */
+ _onKeydownUserEmails: function (ev) {
+ var $userEmails = this.$('.o_user_emails');
+ var keyCodes = [$.ui.keyCode.TAB, $.ui.keyCode.COMMA, $.ui.keyCode.ENTER, $.ui.keyCode.SPACE];
+ if (_.contains(keyCodes, ev.which)) {
+ ev.preventDefault();
+ this._createBadges();
+ }
+ // remove last badge on backspace
+ if (ev.which === $.ui.keyCode.BACKSPACE && this.emails.length && !$userEmails.val()) {
+ this._removeBadge(this.$('.o_web_settings_dashboard_invitation_form .badge:last'));
+ }
+ },
});
var DashboardApps = Widget.extend({
diff --git a/addons/web_settings_dashboard/static/src/less/dashboard.less b/addons/web_settings_dashboard/static/src/less/dashboard.less
index f14b7164197..06e19f02095 100644
--- a/addons/web_settings_dashboard/static/src/less/dashboard.less
+++ b/addons/web_settings_dashboard/static/src/less/dashboard.less
@@ -68,9 +68,6 @@
width: 100%;
}
}
- a.o_web_settings_dashboard_user {
- line-height: 24px;
- }
}
.o_web_settings_dashboard_planner {
.progress {
diff --git a/addons/web_settings_dashboard/static/src/xml/dashboard.xml b/addons/web_settings_dashboard/static/src/xml/dashboard.xml
index 8c90f99de8a..f7ccf053e8d 100644
--- a/addons/web_settings_dashboard/static/src/xml/dashboard.xml
+++ b/addons/web_settings_dashboard/static/src/xml/dashboard.xml
@@ -46,6 +46,16 @@
Invite new users:
+ +