mirror of
https://github.com/zulip/zulip.git
synced 2025-11-11 17:36:27 +00:00
We used html_submit_button to pass text to be present in the modal submit button. There are only two possible options as of now - "Confirm" and "Save changes" and the correct one can be determined using is_confirm_modal parameter. So, we remove this paramter for now and we can add it later if we have more type of modals using this widget.
380 lines
13 KiB
JavaScript
380 lines
13 KiB
JavaScript
import $ from "jquery";
|
|
import _ from "lodash";
|
|
|
|
import render_confirm_delete_user from "../templates/confirm_dialog/confirm_delete_user.hbs";
|
|
import render_admin_user_group_list from "../templates/settings/admin_user_group_list.hbs";
|
|
|
|
import * as channel from "./channel";
|
|
import * as confirm_dialog from "./confirm_dialog";
|
|
import {$t, $t_html} from "./i18n";
|
|
import {page_params} from "./page_params";
|
|
import * as people from "./people";
|
|
import * as pill_typeahead from "./pill_typeahead";
|
|
import * as ui_report from "./ui_report";
|
|
import * as user_groups from "./user_groups";
|
|
import * as user_pill from "./user_pill";
|
|
|
|
const meta = {
|
|
loaded: false,
|
|
};
|
|
|
|
export function reset() {
|
|
meta.loaded = false;
|
|
}
|
|
|
|
export function reload() {
|
|
if (!meta.loaded) {
|
|
return;
|
|
}
|
|
|
|
const user_groups_section = $("#user-groups").expectOne();
|
|
user_groups_section.html("");
|
|
populate_user_groups();
|
|
}
|
|
|
|
const USER_GROUP_EDIT_POLICY_MEMBERS = 1;
|
|
|
|
export function can_edit(group_id) {
|
|
if (page_params.is_admin) {
|
|
return true;
|
|
}
|
|
|
|
if (page_params.is_guest) {
|
|
return false;
|
|
}
|
|
|
|
if (page_params.realm_user_group_edit_policy !== USER_GROUP_EDIT_POLICY_MEMBERS) {
|
|
return false;
|
|
}
|
|
|
|
return user_groups.is_member_of(group_id, people.my_current_user_id());
|
|
}
|
|
|
|
export function populate_user_groups() {
|
|
const user_groups_section = $("#user-groups").expectOne();
|
|
const user_groups_array = user_groups.get_realm_user_groups();
|
|
|
|
for (const data of user_groups_array) {
|
|
user_groups_section.append(
|
|
render_admin_user_group_list({
|
|
user_group: {
|
|
name: data.name,
|
|
id: data.id,
|
|
description: data.description,
|
|
},
|
|
}),
|
|
);
|
|
const pill_container = $(`.pill-container[data-group-pills="${CSS.escape(data.id)}"]`);
|
|
const pills = user_pill.create_pills(pill_container);
|
|
|
|
function get_pill_user_ids() {
|
|
return user_pill.get_user_ids(pills);
|
|
}
|
|
|
|
const userg = $(`div.user-group[id="${CSS.escape(data.id)}"]`);
|
|
for (const user_id of data.members) {
|
|
const user = people.get_by_user_id(user_id);
|
|
user_pill.append_user(user, pills);
|
|
}
|
|
|
|
function update_membership(group_id) {
|
|
if (can_edit(group_id)) {
|
|
return;
|
|
}
|
|
userg.find(".name").attr("contenteditable", "false");
|
|
userg.find(".description").attr("contenteditable", "false");
|
|
userg.addClass("ntm");
|
|
pill_container.find(".input").attr("contenteditable", "false");
|
|
pill_container.find(".input").css("display", "none");
|
|
pill_container.addClass("not-editable");
|
|
pill_container.off("keydown", ".pill");
|
|
pill_container.off("keydown", ".input");
|
|
pill_container.off("click");
|
|
pill_container.on("click", (e) => {
|
|
e.stopPropagation();
|
|
});
|
|
pill_container.find(".pill").on("mouseenter", () => {
|
|
pill_container.find(".pill").find(".exit").css("opacity", "0.5");
|
|
});
|
|
}
|
|
update_membership(data.id);
|
|
|
|
function is_user_group_changed() {
|
|
const draft_group = get_pill_user_ids();
|
|
const group_data = user_groups.get_user_group_from_id(data.id);
|
|
const original_group = Array.from(group_data.members);
|
|
const same_groups = _.isEqual(_.sortBy(draft_group), _.sortBy(original_group));
|
|
const description = $(`#user-groups #${CSS.escape(data.id)} .description`)
|
|
.text()
|
|
.trim();
|
|
const name = $(`#user-groups #${CSS.escape(data.id)} .name`)
|
|
.text()
|
|
.trim();
|
|
const user_group_status = $(`#user-groups #${CSS.escape(data.id)} .user-group-status`);
|
|
|
|
if (user_group_status.is(":visible")) {
|
|
return false;
|
|
}
|
|
|
|
if (
|
|
group_data.description === description &&
|
|
group_data.name === name &&
|
|
(!draft_group.length || same_groups)
|
|
) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function update_cancel_button() {
|
|
if (!can_edit(data.id)) {
|
|
return;
|
|
}
|
|
const cancel_button = $(`#user-groups #${CSS.escape(data.id)} .save-status.btn-danger`);
|
|
const saved_button = $(`#user-groups #${CSS.escape(data.id)} .save-status.sea-green`);
|
|
const save_instructions = $(`#user-groups #${CSS.escape(data.id)} .save-instructions`);
|
|
|
|
if (is_user_group_changed() && !cancel_button.is(":visible")) {
|
|
saved_button.fadeOut(0);
|
|
cancel_button.css({display: "inline-block", opacity: "0"}).fadeTo(400, 1);
|
|
save_instructions.css({display: "block", opacity: "0"}).fadeTo(400, 1);
|
|
} else if (!is_user_group_changed() && cancel_button.is(":visible")) {
|
|
cancel_button.fadeOut();
|
|
save_instructions.fadeOut();
|
|
}
|
|
}
|
|
|
|
function show_saved_button() {
|
|
const cancel_button = $(`#user-groups #${CSS.escape(data.id)} .save-status.btn-danger`);
|
|
const saved_button = $(`#user-groups #${CSS.escape(data.id)} .save-status.sea-green`);
|
|
const save_instructions = $(`#user-groups #${CSS.escape(data.id)} .save-instructions`);
|
|
if (!saved_button.is(":visible")) {
|
|
cancel_button.fadeOut(0);
|
|
save_instructions.fadeOut(0);
|
|
saved_button
|
|
.css({display: "inline-block", opacity: "0"})
|
|
.fadeTo(400, 1)
|
|
.delay(2000)
|
|
.fadeTo(400, 0);
|
|
}
|
|
}
|
|
|
|
function save_members() {
|
|
const draft_group = get_pill_user_ids();
|
|
const group_data = user_groups.get_user_group_from_id(data.id);
|
|
const original_group = Array.from(group_data.members);
|
|
const same_groups = _.isEqual(_.sortBy(draft_group), _.sortBy(original_group));
|
|
if (!draft_group.length || same_groups) {
|
|
return;
|
|
}
|
|
const added = _.difference(draft_group, original_group);
|
|
const removed = _.difference(original_group, draft_group);
|
|
channel.post({
|
|
url: "/json/user_groups/" + data.id + "/members",
|
|
data: {
|
|
add: JSON.stringify(added),
|
|
delete: JSON.stringify(removed),
|
|
},
|
|
success() {
|
|
setTimeout(show_saved_button, 200);
|
|
},
|
|
});
|
|
}
|
|
|
|
function save_name_desc() {
|
|
const user_group_status = $(`#user-groups #${CSS.escape(data.id)} .user-group-status`);
|
|
const group_data = user_groups.get_user_group_from_id(data.id);
|
|
const description = $(`#user-groups #${CSS.escape(data.id)} .description`)
|
|
.text()
|
|
.trim();
|
|
const name = $(`#user-groups #${CSS.escape(data.id)} .name`)
|
|
.text()
|
|
.trim();
|
|
|
|
if (group_data.description === description && group_data.name === name) {
|
|
return;
|
|
}
|
|
|
|
channel.patch({
|
|
url: "/json/user_groups/" + data.id,
|
|
data: {
|
|
name,
|
|
description,
|
|
},
|
|
success() {
|
|
user_group_status.hide();
|
|
setTimeout(show_saved_button, 200);
|
|
},
|
|
error(xhr) {
|
|
const errors = JSON.parse(xhr.responseText).msg;
|
|
xhr.responseText = JSON.stringify({msg: errors});
|
|
ui_report.error($t_html({defaultMessage: "Failed"}), xhr, user_group_status);
|
|
update_cancel_button();
|
|
$(`#user-groups #${CSS.escape(data.id)} .name`).text(group_data.name);
|
|
$(`#user-groups #${CSS.escape(data.id)} .description`).text(
|
|
group_data.description,
|
|
);
|
|
},
|
|
});
|
|
}
|
|
|
|
function do_not_blur(except_class, event) {
|
|
// Event generated from or inside the typeahead.
|
|
if ($(event.relatedTarget).closest(".typeahead").length) {
|
|
return true;
|
|
}
|
|
|
|
const blur_exceptions = _.without(
|
|
[".pill-container", ".name", ".description", ".input", ".delete"],
|
|
except_class,
|
|
);
|
|
if ($(event.relatedTarget).closest(`#user-groups #${CSS.escape(data.id)}`).length) {
|
|
return blur_exceptions.some(
|
|
(class_name) => $(event.relatedTarget).closest(class_name).length,
|
|
);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function auto_save(class_name, event) {
|
|
if (!can_edit(data.id)) {
|
|
return;
|
|
}
|
|
|
|
if (do_not_blur(class_name, event)) {
|
|
return;
|
|
}
|
|
if (
|
|
$(event.relatedTarget).closest(`#user-groups #${CSS.escape(data.id)}`) &&
|
|
$(event.relatedTarget).closest(".save-status.btn-danger").length
|
|
) {
|
|
reload();
|
|
return;
|
|
}
|
|
save_name_desc();
|
|
save_members();
|
|
}
|
|
|
|
$(`#user-groups #${CSS.escape(data.id)}`).on("blur", ".input", (event) => {
|
|
auto_save(".input", event);
|
|
});
|
|
|
|
$(`#user-groups #${CSS.escape(data.id)}`).on("blur", ".name", (event) => {
|
|
auto_save(".name", event);
|
|
});
|
|
$(`#user-groups #${CSS.escape(data.id)}`).on("input", ".name", () => {
|
|
update_cancel_button();
|
|
});
|
|
|
|
$(`#user-groups #${CSS.escape(data.id)}`).on("blur", ".description", (event) => {
|
|
auto_save(".description", event);
|
|
});
|
|
$(`#user-groups #${CSS.escape(data.id)}`).on("input", ".description", () => {
|
|
update_cancel_button();
|
|
});
|
|
|
|
const input = pill_container.children(".input");
|
|
if (can_edit(data.id)) {
|
|
const opts = {update_func: update_cancel_button, user: true};
|
|
pill_typeahead.set_up(input, pills, opts);
|
|
}
|
|
|
|
if (can_edit(data.id)) {
|
|
pills.onPillRemove(() => {
|
|
// onPillRemove is fired before the pill is removed from
|
|
// the DOM.
|
|
update_cancel_button();
|
|
setTimeout(() => {
|
|
input.trigger("focus");
|
|
}, 100);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
export function set_up() {
|
|
meta.loaded = true;
|
|
populate_user_groups();
|
|
|
|
$(".organization form.admin-user-group-form")
|
|
.off("submit")
|
|
.on("submit", function (e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
const user_group_status = $("#admin-user-group-status");
|
|
|
|
const group = {
|
|
members: JSON.stringify([people.my_current_user_id()]),
|
|
};
|
|
|
|
for (const obj of $(this).serializeArray()) {
|
|
if (obj.value.trim() === "") {
|
|
continue;
|
|
}
|
|
group[obj.name] = obj.value;
|
|
}
|
|
|
|
channel.post({
|
|
url: "/json/user_groups/create",
|
|
data: group,
|
|
success() {
|
|
user_group_status.hide();
|
|
ui_report.success(
|
|
$t_html({defaultMessage: "User group added!"}),
|
|
user_group_status,
|
|
);
|
|
$("form.admin-user-group-form input[type='text']").val("");
|
|
},
|
|
error(xhr) {
|
|
user_group_status.hide();
|
|
const errors = JSON.parse(xhr.responseText).msg;
|
|
xhr.responseText = JSON.stringify({msg: errors});
|
|
ui_report.error($t_html({defaultMessage: "Failed"}), xhr, user_group_status);
|
|
},
|
|
});
|
|
});
|
|
|
|
$("#user-groups").on("click", ".delete", function () {
|
|
const group_id = Number.parseInt($(this).parents(".user-group").attr("id"), 10);
|
|
if (!can_edit(group_id)) {
|
|
return;
|
|
}
|
|
const user_group = user_groups.get_user_group_from_id(group_id);
|
|
const btn = $(this);
|
|
|
|
function delete_user_group() {
|
|
channel.del({
|
|
url: "/json/user_groups/" + group_id,
|
|
data: {
|
|
id: group_id,
|
|
},
|
|
error() {
|
|
btn.text($t({defaultMessage: "Failed!"}));
|
|
},
|
|
});
|
|
}
|
|
|
|
// This is mostly important for styling concerns.
|
|
const modal_parent = $("#settings_content");
|
|
|
|
const html_body = render_confirm_delete_user({
|
|
group_name: user_group.name,
|
|
});
|
|
|
|
confirm_dialog.launch({
|
|
parent: modal_parent,
|
|
html_heading: $t_html({defaultMessage: "Delete user group"}),
|
|
html_body,
|
|
on_click: delete_user_group,
|
|
fade: true,
|
|
});
|
|
});
|
|
|
|
$("#user-groups").on("keypress", ".user-group h4 > span", (e) => {
|
|
if (e.key === "Enter") {
|
|
e.preventDefault();
|
|
}
|
|
});
|
|
}
|