diff --git a/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 b/app/assets/javascripts/admin/controllers/admin-user-index.js.es6
index 2fbac162ced..0020dae6ec8 100644
--- a/app/assets/javascripts/admin/controllers/admin-user-index.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-user-index.js.es6
@@ -11,6 +11,7 @@ export default Ember.Controller.extend(CanCheckEmails, {
editingName: false,
editingTitle: false,
originalPrimaryGroupId: null,
+ customGroupIdsBuffer: null,
availableGroups: null,
userTitleValue: null,
@@ -30,6 +31,20 @@ export default Ember.Controller.extend(CanCheckEmails, {
"model.can_disable_second_factor"
),
+ @computed("model.customGroups")
+ customGroupIds(customGroups) {
+ return customGroups.mapBy("id");
+ },
+
+ @computed("customGroupIdsBuffer", "customGroupIds")
+ customGroupsDirty(buffer, original) {
+ if (buffer === null) return false;
+
+ return buffer.length === original.length
+ ? buffer.any(id => !original.includes(id))
+ : true;
+ },
+
@computed("model.automaticGroups")
automaticGroups(automaticGroups) {
return automaticGroups
@@ -105,6 +120,27 @@ export default Ember.Controller.extend(CanCheckEmails, {
}
},
+ groupAdded(added) {
+ this.get("model")
+ .groupAdded(added)
+ .catch(function() {
+ bootbox.alert(I18n.t("generic_error"));
+ });
+ },
+
+ groupRemoved(groupId) {
+ this.get("model")
+ .groupRemoved(groupId)
+ .then(() => {
+ if (groupId === this.get("originalPrimaryGroupId")) {
+ this.set("originalPrimaryGroupId", null);
+ }
+ })
+ .catch(function() {
+ bootbox.alert(I18n.t("generic_error"));
+ });
+ },
+
actions: {
impersonate() {
return this.get("model").impersonate();
@@ -278,20 +314,22 @@ export default Ember.Controller.extend(CanCheckEmails, {
this.get("model").generateApiKey();
},
- groupAdded(added) {
- this.get("model")
- .groupAdded(added)
- .catch(function() {
- bootbox.alert(I18n.t("generic_error"));
- });
+ saveCustomGroups() {
+ const currentIds = this.get("customGroupIds");
+ const bufferedIds = this.get("customGroupIdsBuffer");
+ const availableGroups = this.get("availableGroups");
+
+ bufferedIds.filter(id => !currentIds.includes(id)).forEach(id => {
+ this.groupAdded(availableGroups.findBy("id", id));
+ });
+
+ currentIds
+ .filter(id => !bufferedIds.includes(id))
+ .forEach(id => this.groupRemoved(id));
},
- groupRemoved(groupId) {
- this.get("model")
- .groupRemoved(groupId)
- .catch(function() {
- bootbox.alert(I18n.t("generic_error"));
- });
+ resetCustomGroups() {
+ this.set("customGroupIdsBuffer", null);
},
savePrimaryGroup() {
diff --git a/app/assets/javascripts/admin/templates/user-index.hbs b/app/assets/javascripts/admin/templates/user-index.hbs
index 35daa9560d6..a02756d2e64 100644
--- a/app/assets/javascripts/admin/templates/user-index.hbs
+++ b/app/assets/javascripts/admin/templates/user-index.hbs
@@ -459,19 +459,29 @@
{{i18n 'admin.groups.custom'}}
- {{admin-group-selector selected=model.customGroups available=availableGroups}}
-
-
- {{#if model.customGroups}}
- {{i18n 'admin.groups.primary'}}
- {{combo-box content=model.customGroups value=model.primary_group_id none="admin.groups.no_primary"}}
- {{/if}}
- {{#if primaryGroupDirty}}
- {{d-button icon="check" class="ok" action="savePrimaryGroup"}}
- {{d-button icon="times" class="cancel" action="resetPrimaryGroup"}}
- {{/if}}
+ {{admin-group-selector selected=model.customGroups available=availableGroups buffer=customGroupIdsBuffer}}
+ {{#if customGroupsDirty}}
+
+ {{d-button icon="check" class="ok" action="saveCustomGroups"}}
+ {{d-button icon="times" class="cancel" action="resetCustomGroups"}}
+
+ {{/if}}
+ {{#if model.customGroups}}
+
+
{{i18n 'admin.groups.primary'}}
+
+ {{combo-box content=model.customGroups value=model.primary_group_id none="admin.groups.no_primary"}}
+
+ {{#if primaryGroupDirty}}
+
+ {{d-button icon="check" class="ok" action="savePrimaryGroup"}}
+ {{d-button icon="times" class="cancel" action="resetPrimaryGroup"}}
+
+ {{/if}}
+
+ {{/if}}
{{/if}}
diff --git a/app/assets/javascripts/select-kit/components/admin-group-selector.js.es6 b/app/assets/javascripts/select-kit/components/admin-group-selector.js.es6
index fa15690c088..0c79d92a4d5 100644
--- a/app/assets/javascripts/select-kit/components/admin-group-selector.js.es6
+++ b/app/assets/javascripts/select-kit/components/admin-group-selector.js.es6
@@ -1,4 +1,5 @@
import MultiSelectComponent from "select-kit/components/multi-select";
+import computed from "ember-addons/ember-computed-decorators";
const { makeArray } = Ember;
export default MultiSelectComponent.extend({
@@ -7,11 +8,13 @@ export default MultiSelectComponent.extend({
selected: null,
available: null,
allowAny: false,
+ buffer: null,
- computeValues() {
- return makeArray(this.get("selected")).map(s =>
- this.valueForContentItem(s)
- );
+ @computed("buffer")
+ values(buffer) {
+ return buffer === null
+ ? makeArray(this.get("selected")).map(s => this.valueForContentItem(s))
+ : buffer;
},
computeContent() {
@@ -25,33 +28,6 @@ export default MultiSelectComponent.extend({
},
mutateValues(values) {
- if (values.length > this.get("selected").length) {
- const newValues = values.filter(
- v =>
- !this.get("selected")
- .map(s => this.valueForContentItem(s))
- .includes(v)
- );
-
- newValues.forEach(value => {
- const actionContext = this.get("available").findBy(
- this.get("valueAttribute"),
- parseInt(value, 10)
- );
-
- this.triggerAction({ action: "groupAdded", actionContext });
- });
- } else if (values.length < this.get("selected").length) {
- const selected = this.get("selected").filter(
- s => !values.includes(this.valueForContentItem(s))
- );
-
- selected.forEach(s => {
- this.triggerAction({
- action: "groupRemoved",
- actionContext: this.valueForContentItem(s)
- });
- });
- }
+ this.set("buffer", values);
}
});