mirror of
https://github.com/zulip/zulip.git
synced 2025-11-05 22:43:42 +00:00
A preparatory commit to have legacy user group settings logic as we move forward to redesign the user group settings. This is done so that current user group settings are functional while we are working on the redesign, and also to make it clear that most of the code in this file will be deleted and developers should avoid spending much time on it.
414 lines
14 KiB
JavaScript
414 lines
14 KiB
JavaScript
import $ from "jquery";
|
|
import _ from "lodash";
|
|
|
|
import render_confirm_delete_user from "../templates/confirm_dialog/confirm_delete_user.hbs";
|
|
import render_add_user_group_modal from "../templates/settings/add_user_group_modal.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 * as dialog_widget from "./dialog_widget";
|
|
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 settings_data from "./settings_data";
|
|
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.empty();
|
|
populate_user_groups();
|
|
}
|
|
|
|
export function can_edit(group_id) {
|
|
if (!settings_data.user_can_edit_user_groups()) {
|
|
return false;
|
|
}
|
|
|
|
// Admins and moderators are allowed to edit user groups even if they
|
|
// are not a member of that user group. Members can edit user groups
|
|
// only if they belong to that group.
|
|
if (page_params.is_admin || page_params.is_moderator) {
|
|
return true;
|
|
}
|
|
|
|
return user_groups.is_direct_member_of(people.my_current_user_id(), group_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_config = {
|
|
show_user_status_emoji: false,
|
|
};
|
|
|
|
const $pill_container = $(`.pill-container[data-group-pills="${CSS.escape(data.id)}"]`);
|
|
const pills = user_pill.create_pills($pill_container, pill_config);
|
|
|
|
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;
|
|
}
|
|
|
|
if ($(event.relatedTarget).closest(`#user-groups #${CSS.escape(data.id)}`).length) {
|
|
return [".pill-container", ".name", ".description", ".input", ".delete"].some(
|
|
(class_name) =>
|
|
class_name !== except_class &&
|
|
$(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 add_user_group(e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
const $user_group_status = $("#dialog_error");
|
|
|
|
const group = {
|
|
members: JSON.stringify([people.my_current_user_id()]),
|
|
};
|
|
|
|
for (const obj of $("#add-user-group-form").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);
|
|
dialog_widget.close_modal();
|
|
},
|
|
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);
|
|
},
|
|
});
|
|
}
|
|
|
|
function show_add_user_group_modal() {
|
|
const html_body = render_add_user_group_modal();
|
|
|
|
function add_user_group_post_render() {
|
|
const $add_user_group_input_element = $("#user_group_name");
|
|
const $add_user_group_submit_button = $("#add-user-group-modal .dialog_submit_button");
|
|
$add_user_group_submit_button.prop("disabled", true);
|
|
|
|
$add_user_group_input_element.on("input", () => {
|
|
$add_user_group_submit_button.prop(
|
|
"disabled",
|
|
$add_user_group_input_element.val() === "",
|
|
);
|
|
});
|
|
}
|
|
|
|
dialog_widget.launch({
|
|
html_heading: $t_html({defaultMessage: "Add new user group"}),
|
|
html_body,
|
|
html_submit_button: $t_html({defaultMessage: "Save"}),
|
|
help_link: "/help/user-groups",
|
|
form_id: "add-user-group-form",
|
|
id: "add-user-group-modal",
|
|
on_click: add_user_group,
|
|
on_shown: () => $("#user_group_name").trigger("focus"),
|
|
post_render: add_user_group_post_render,
|
|
});
|
|
}
|
|
|
|
export function set_up() {
|
|
meta.loaded = true;
|
|
populate_user_groups();
|
|
|
|
$("#show-add-user-group-modal").on("click", (e) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
show_add_user_group_modal();
|
|
});
|
|
|
|
$("#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!"}));
|
|
},
|
|
});
|
|
}
|
|
|
|
const html_body = render_confirm_delete_user({
|
|
group_name: user_group.name,
|
|
});
|
|
|
|
const user_group_name = user_group.name;
|
|
|
|
confirm_dialog.launch({
|
|
html_heading: $t_html({defaultMessage: "Delete {user_group_name}?"}, {user_group_name}),
|
|
html_body,
|
|
on_click: delete_user_group,
|
|
});
|
|
});
|
|
|
|
$("#user-groups").on("keypress", ".user-group h4 > span", (e) => {
|
|
if (e.key === "Enter") {
|
|
e.preventDefault();
|
|
}
|
|
});
|
|
}
|