user_group_settings_ui: Merge into user_group_edit.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg 2023-10-07 00:30:27 -07:00 committed by Tim Abbott
parent 63b4e74cea
commit 5327bcc5ac
7 changed files with 381 additions and 404 deletions

View File

@ -257,7 +257,6 @@ EXEMPT_FILES = make_set(
"web/src/user_group_popover.js", "web/src/user_group_popover.js",
"web/src/user_group_ui_updates.js", "web/src/user_group_ui_updates.js",
"web/src/user_groups.ts", "web/src/user_groups.ts",
"web/src/user_groups_settings_ui.js",
"web/src/user_profile.js", "web/src/user_profile.js",
"web/src/user_settings.ts", "web/src/user_settings.ts",
"web/src/user_sort.js", "web/src/user_sort.js",

View File

@ -29,7 +29,7 @@ import * as sidebar_ui from "./sidebar_ui";
import * as spectators from "./spectators"; import * as spectators from "./spectators";
import * as stream_settings_ui from "./stream_settings_ui"; import * as stream_settings_ui from "./stream_settings_ui";
import * as ui_report from "./ui_report"; import * as ui_report from "./ui_report";
import * as user_groups_settings_ui from "./user_groups_settings_ui"; import * as user_group_edit from "./user_group_edit";
import {user_settings} from "./user_settings"; import {user_settings} from "./user_settings";
// Read https://zulip.readthedocs.io/en/latest/subsystems/hashchange-system.html // Read https://zulip.readthedocs.io/en/latest/subsystems/hashchange-system.html
@ -263,7 +263,7 @@ function do_hashchange_overlay(old_hash) {
} }
if (base === "groups") { if (base === "groups") {
user_groups_settings_ui.change_state(section); user_group_edit.change_state(section);
} }
if (base === "settings") { if (base === "settings") {
@ -328,7 +328,7 @@ function do_hashchange_overlay(old_hash) {
} }
if (base === "groups") { if (base === "groups") {
user_groups_settings_ui.launch(section); user_group_edit.launch(section);
return; return;
} }

View File

@ -81,7 +81,6 @@ import * as unread_ui from "./unread_ui";
import * as user_events from "./user_events"; import * as user_events from "./user_events";
import * as user_group_edit from "./user_group_edit"; import * as user_group_edit from "./user_group_edit";
import * as user_groups from "./user_groups"; import * as user_groups from "./user_groups";
import * as user_groups_settings_ui from "./user_groups_settings_ui";
import {user_settings} from "./user_settings"; import {user_settings} from "./user_settings";
import * as user_status from "./user_status"; import * as user_status from "./user_status";
import * as user_topics_ui from "./user_topics_ui"; import * as user_topics_ui from "./user_topics_ui";
@ -862,7 +861,7 @@ export function dispatch_normal_event(event) {
case "add": case "add":
user_groups.add(event.group); user_groups.add(event.group);
if (overlays.groups_open()) { if (overlays.groups_open()) {
user_groups_settings_ui.add_group_to_table(event.group); user_group_edit.add_group_to_table(event.group);
} }
break; break;
case "remove": case "remove":
@ -885,7 +884,7 @@ export function dispatch_normal_event(event) {
break; break;
case "update": case "update":
user_groups.update(event); user_groups.update(event);
user_groups_settings_ui.update_group(event.group_id); user_group_edit.update_group(event.group_id);
break; break;
default: default:
blueslip.error("Unexpected event type user_group/" + event.op); blueslip.error("Unexpected event type user_group/" + event.op);

View File

@ -137,7 +137,6 @@ import * as user_group_edit from "./user_group_edit";
import * as user_group_edit_members from "./user_group_edit_members"; import * as user_group_edit_members from "./user_group_edit_members";
import * as user_group_popover from "./user_group_popover"; import * as user_group_popover from "./user_group_popover";
import * as user_groups from "./user_groups"; import * as user_groups from "./user_groups";
import * as user_groups_settings_ui from "./user_groups_settings_ui";
import * as user_profile from "./user_profile"; import * as user_profile from "./user_profile";
import {initialize_user_settings, user_settings} from "./user_settings"; import {initialize_user_settings, user_settings} from "./user_settings";
import * as user_status from "./user_status"; import * as user_status from "./user_status";
@ -619,7 +618,6 @@ export function initialize_everything() {
user_topics.initialize(user_topics_params); user_topics.initialize(user_topics_params);
muted_users.initialize(muted_users_params); muted_users.initialize(muted_users_params);
stream_settings_ui.initialize(); stream_settings_ui.initialize();
user_groups_settings_ui.initialize();
left_sidebar_navigation_area.initialize(); left_sidebar_navigation_area.initialize();
stream_list.initialize({ stream_list.initialize({
on_stream_click(stream_id, trigger) { on_stream_click(stream_id, trigger) {

View File

@ -1,8 +1,10 @@
import $ from "jquery"; import $ from "jquery";
import render_confirm_delete_user from "../templates/confirm_dialog/confirm_delete_user.hbs"; import render_confirm_delete_user from "../templates/confirm_dialog/confirm_delete_user.hbs";
import render_browse_user_groups_list_item from "../templates/user_group_settings/browse_user_groups_list_item.hbs";
import render_change_user_group_info_modal from "../templates/user_group_settings/change_user_group_info_modal.hbs"; import render_change_user_group_info_modal from "../templates/user_group_settings/change_user_group_info_modal.hbs";
import render_user_group_settings from "../templates/user_group_settings/user_group_settings.hbs"; import render_user_group_settings from "../templates/user_group_settings/user_group_settings.hbs";
import render_user_group_settings_overlay from "../templates/user_group_settings/user_group_settings_overlay.hbs";
import * as blueslip from "./blueslip"; import * as blueslip from "./blueslip";
import * as browser_history from "./browser_history"; import * as browser_history from "./browser_history";
@ -12,6 +14,7 @@ import * as confirm_dialog from "./confirm_dialog";
import * as dialog_widget from "./dialog_widget"; import * as dialog_widget from "./dialog_widget";
import * as hash_util from "./hash_util"; import * as hash_util from "./hash_util";
import {$t, $t_html} from "./i18n"; import {$t, $t_html} from "./i18n";
import * as ListWidget from "./list_widget";
import * as overlays from "./overlays"; import * as overlays from "./overlays";
import {page_params} from "./page_params"; import {page_params} from "./page_params";
import * as people from "./people"; import * as people from "./people";
@ -19,13 +22,18 @@ import * as scroll_util from "./scroll_util";
import * as settings_data from "./settings_data"; import * as settings_data from "./settings_data";
import * as stream_ui_updates from "./stream_ui_updates"; import * as stream_ui_updates from "./stream_ui_updates";
import * as ui_report from "./ui_report"; import * as ui_report from "./ui_report";
import * as user_group_create from "./user_group_create";
import * as user_group_edit_members from "./user_group_edit_members"; import * as user_group_edit_members from "./user_group_edit_members";
import * as user_groups from "./user_groups"; import * as user_groups from "./user_groups";
import * as user_groups_settings_ui from "./user_groups_settings_ui"; import * as util from "./util";
export let toggler; export let toggler;
export let select_tab = "group_general_settings"; export let select_tab = "group_general_settings";
let group_list_widget;
let group_list_toggler;
let active_group_id;
function setup_group_edit_hash(group) { function setup_group_edit_hash(group) {
const hash = hash_util.group_edit_url(group); const hash = hash_util.group_edit_url(group);
browser_history.update(hash); browser_history.update(hash);
@ -142,17 +150,15 @@ export function handle_member_edit_event(group_id, user_ids) {
// and current user is among the affect users as in that // and current user is among the affect users as in that
// case the group widget list need to be updated and show // case the group widget list need to be updated and show
// or remove the group-row on the left panel accordingly. // or remove the group-row on the left panel accordingly.
const tab_key = user_groups_settings_ui.get_active_data().$tabs.first().attr("data-tab-key"); const tab_key = get_active_data().$tabs.first().attr("data-tab-key");
if (tab_key === "your-groups" && user_ids.includes(people.my_current_user_id())) { if (tab_key === "your-groups" && user_ids.includes(people.my_current_user_id())) {
user_groups_settings_ui.redraw_user_group_list(); redraw_user_group_list();
} }
// update display of check-mark. // update display of check-mark.
if (user_groups_settings_ui.is_group_already_present(group)) { if (is_group_already_present(group)) {
const is_member = user_groups.is_user_in_group(group_id, people.my_current_user_id()); const is_member = user_groups.is_user_in_group(group_id, people.my_current_user_id());
const $sub_unsub_button = user_groups_settings_ui const $sub_unsub_button = row_for_group_id(group_id).find(".sub_unsub_button");
.row_for_group_id(group_id)
.find(".sub_unsub_button");
if (is_member) { if (is_member) {
$sub_unsub_button.removeClass("disabled"); $sub_unsub_button.removeClass("disabled");
$sub_unsub_button.addClass("checked"); $sub_unsub_button.addClass("checked");
@ -219,7 +225,7 @@ export function setup_group_list_tab_hash(tab_key_value) {
We do not update the hash based on tab switches if We do not update the hash based on tab switches if
a group is currently being edited. a group is currently being edited.
*/ */
if (user_groups_settings_ui.get_active_data().id !== undefined) { if (get_active_data().id !== undefined) {
return; return;
} }
@ -232,9 +238,32 @@ export function setup_group_list_tab_hash(tab_key_value) {
} }
} }
export const show_user_group_settings_pane = {
nothing_selected() {
$("#groups_overlay .settings, #user-group-creation").hide();
reset_active_group_id();
$("#groups_overlay .nothing-selected").show();
$("#groups_overlay .user-group-info-title").text(
$t({defaultMessage: "User group settings"}),
);
},
settings(group) {
$("#groups_overlay .nothing-selected, #user-group-creation").hide();
$("#groups_overlay .settings").show();
set_active_group_id(group.id);
$("#groups_overlay .user-group-info-title").text(group.name);
},
create_user_group() {
$("#groups_overlay .nothing-selected, #groups_overlay .settings").hide();
reset_active_group_id();
$("#user-group-creation").show();
$("#groups_overlay .user-group-info-title").text($t({defaultMessage: "Create user group"}));
},
};
function open_right_panel_empty() { function open_right_panel_empty() {
$(".group-row.active").removeClass("active"); $(".group-row.active").removeClass("active");
user_groups_settings_ui.show_user_group_settings_pane.nothing_selected(); show_user_group_settings_pane.nothing_selected();
const tab_key = $(".user-groups-container") const tab_key = $(".user-groups-container")
.find("div.ind-tab.selected") .find("div.ind-tab.selected")
.first() .first()
@ -246,7 +275,7 @@ export function is_editing_group(desired_group_id) {
if (!overlays.groups_open()) { if (!overlays.groups_open()) {
return false; return false;
} }
return user_groups_settings_ui.get_active_data().id === desired_group_id; return get_active_data().id === desired_group_id;
} }
export function handle_deleted_group(group_id) { export function handle_deleted_group(group_id) {
@ -257,13 +286,13 @@ export function handle_deleted_group(group_id) {
if (is_editing_group(group_id)) { if (is_editing_group(group_id)) {
open_right_panel_empty(); open_right_panel_empty();
} }
user_groups_settings_ui.redraw_user_group_list(); redraw_user_group_list();
} }
export function show_group_settings(group) { export function show_group_settings(group) {
$(".group-row.active").removeClass("active"); $(".group-row.active").removeClass("active");
user_groups_settings_ui.show_user_group_settings_pane.settings(group); show_user_group_settings_pane.settings(group);
user_groups_settings_ui.row_for_group_id(group.id).addClass("active"); row_for_group_id(group.id).addClass("active");
setup_group_edit_hash(group); setup_group_edit_hash(group);
setup_group_settings(group); setup_group_settings(group);
} }
@ -273,6 +302,304 @@ export function open_group_edit_panel_for_row(group_row) {
show_group_settings(group); show_group_settings(group);
} }
export function set_active_group_id(group_id) {
active_group_id = group_id;
}
export function reset_active_group_id() {
active_group_id = undefined;
}
// Ideally this should be included in page params.
// Like we have page_params.max_stream_name_length` and
// `page_params.max_stream_description_length` for streams.
export const max_user_group_name_length = 100;
export function set_up_click_handlers() {
$("#groups_overlay").on("click", ".left #clear_search_group_name", (e) => {
const $input = $("#groups_overlay .left #search_group_name");
$input.val("");
// This is a hack to rerender complete
// stream list once the text is cleared.
$input.trigger("input");
e.stopPropagation();
e.preventDefault();
});
}
function create_user_group_clicked() {
// this changes the tab switcher (settings/preview) which isn't necessary
// to a add new stream title.
show_user_group_settings_pane.create_user_group();
$(".group-row.active").removeClass("active");
user_group_create.show_new_user_group_modal();
$("#create_user_group_name").trigger("focus");
}
export function do_open_create_user_group() {
// Only call this directly for hash changes.
// Prefer open_create_user_group().
show_right_section();
create_user_group_clicked();
}
export function open_create_user_group() {
do_open_create_user_group();
browser_history.update("#groups/new");
}
export function row_for_group_id(group_id) {
return $(`.group-row[data-group-id='${CSS.escape(group_id)}']`);
}
export function is_group_already_present(group) {
return row_for_group_id(group.id).length > 0;
}
export function get_active_data() {
const $active_tabs = $(".user-groups-container").find("div.ind-tab.selected");
return {
$row: row_for_group_id(active_group_id),
id: active_group_id,
$tabs: $active_tabs,
};
}
export function switch_to_group_row(group) {
if (is_group_already_present(group)) {
/*
It is possible that this function may be called at times
when group-row for concerned group may not be present this
might occur when user manually edits the url for a group
that user is not member of and #groups overlay is open with
your-groups tab active.
To handle such cases we perform these steps only if the group
is listed in the left panel else we simply open the settings
for the concerned group.
*/
const $group_row = row_for_group_id(group.id);
const $container = $(".user-groups-list");
get_active_data().$row.removeClass("active");
$group_row.addClass("active");
scroll_util.scroll_element_into_container($group_row, $container);
}
show_group_settings(group);
}
function show_right_section() {
$(".right").addClass("show");
$(".user-groups-header").addClass("slide-left");
}
export function add_group_to_table(group) {
if (is_group_already_present(group)) {
// If a group is already listed/added in groups modal,
// then we simply return.
// This can happen in some corner cases (which might
// be backend bugs) where a realm administrator may
// get two user_group-add events.
return;
}
redraw_user_group_list();
if (user_group_create.get_name() === group.name) {
// This `user_group_create.get_name()` check tells us whether the
// group was just created in this browser window; it's a hack
// to work around the server_events code flow not having a
// good way to associate with this request because the group
// ID isn't known yet.
show_group_settings(group);
user_group_create.reset_name();
}
}
export function update_group(group_id) {
if (!overlays.groups_open()) {
return;
}
const group = user_groups.get_user_group_from_id(group_id);
const $group_row = row_for_group_id(group_id);
// update left side pane
$group_row.find(".group-name").text(group.name);
$group_row.find(".description").text(group.description);
if (get_active_data().id === group.id) {
// update right side pane
update_settings_pane(group);
// update settings title
$("#groups_overlay .user-group-info-title").text(group.name);
}
}
export function change_state(section) {
if (section === "new") {
do_open_create_user_group();
redraw_user_group_list();
return;
}
if (section === "all") {
group_list_toggler.goto("all-groups");
return;
}
if (section === "your") {
group_list_toggler.goto("your-groups");
return;
}
// if the section is a valid number.
if (/\d+/.test(section)) {
const group_id = Number.parseInt(section, 10);
const group = user_groups.get_user_group_from_id(group_id);
if (!group) {
// Some users can type random url of the form
// /#groups/<random-group-id> we need to handle that.
group_list_toggler.goto("your-groups");
} else {
show_right_section();
// We show the list of user groups in the left panel
// based on the tab that is active. It is `your-groups`
// tab by default.
redraw_user_group_list();
switch_to_group_row(group);
}
return;
}
blueslip.info("invalid section for groups: " + section);
group_list_toggler.goto("your-groups");
}
function compare_by_name(a, b) {
return util.strcmp(a.name, b.name);
}
function redraw_left_panel(tab_name) {
let groups_list_data;
if (tab_name === "all-groups") {
groups_list_data = user_groups.get_realm_user_groups();
} else if (tab_name === "your-groups") {
groups_list_data = user_groups.get_user_groups_of_user(people.my_current_user_id());
}
groups_list_data.sort(compare_by_name);
group_list_widget.replace_list_data(groups_list_data);
}
export function redraw_user_group_list() {
const tab_name = get_active_data().$tabs.first().attr("data-tab-key");
redraw_left_panel(tab_name);
}
export function switch_group_tab(tab_name) {
/*
This switches the groups list tab, but it doesn't update
the group_list_toggler widget. You may instead want to
use `group_list_toggler.goto`.
*/
redraw_left_panel(tab_name);
setup_group_list_tab_hash(tab_name);
}
export function setup_page(callback) {
function initialize_components() {
group_list_toggler = components.toggle({
child_wants_focus: true,
values: [
{label: $t({defaultMessage: "Your groups"}), key: "your-groups"},
{label: $t({defaultMessage: "All groups"}), key: "all-groups"},
],
callback(_label, key) {
switch_group_tab(key);
},
});
$("#groups_overlay_container .list-toggler-container").prepend(group_list_toggler.get());
}
function populate_and_fill() {
const template_data = {
can_create_or_edit_user_groups: settings_data.user_can_edit_user_groups(),
max_user_group_name_length,
};
const rendered = render_user_group_settings_overlay(template_data);
const $groups_overlay_container = scroll_util.get_content_element(
$("#groups_overlay_container"),
);
$groups_overlay_container.empty();
$groups_overlay_container.append(rendered);
// Initially as the overlay is build with empty right panel,
// active_group_id is undefined.
reset_active_group_id();
const $container = $("#groups_overlay_container .user-groups-list");
/*
As change_state function called after this initial build up
redraws left panel based on active tab we avoid building extra dom
here as the required group-rows are anyway going to be created
immediately after this due to call to change_state. So we call
`ListWidget.create` with empty user groups list.
*/
group_list_widget = ListWidget.create($container, [], {
name: "user-groups-overlay",
get_item: ListWidget.default_get_item,
modifier_html(item) {
item.is_member = user_groups.is_direct_member_of(
people.my_current_user_id(),
item.id,
);
return render_browse_user_groups_list_item(item);
},
filter: {
$element: $("#groups_overlay_container .left #search_group_name"),
predicate(item, value) {
return (
item &&
(item.name.toLocaleLowerCase().includes(value) ||
item.description.toLocaleLowerCase().includes(value))
);
},
onupdate() {
if (active_group_id !== undefined) {
const active_group = user_groups.get_user_group_from_id(active_group_id);
if (is_group_already_present(active_group)) {
row_for_group_id(active_group_id).addClass("active");
}
}
},
},
init_sort: ["alphabetic", "name"],
$simplebar_container: $container,
});
initialize_components();
set_up_click_handlers();
user_group_create.set_up_handlers();
// show the "User group settings" header by default.
$(".display-type #user_group_settings_title").show();
if (callback) {
callback();
}
}
populate_and_fill();
}
export function initialize() { export function initialize() {
$("#groups_overlay_container").on("click", ".group-row", function (e) { $("#groups_overlay_container").on("click", ".group-row", function (e) {
if ($(e.target).closest(".check, .user_group_settings_wrapper").length === 0) { if ($(e.target).closest(".check, .user_group_settings_wrapper").length === 0) {
@ -288,7 +615,7 @@ export function initialize() {
const template_data = { const template_data = {
group_name: user_group.name, group_name: user_group.name,
group_description: user_group.description, group_description: user_group.description,
max_user_group_name_length: user_groups_settings_ui.max_user_group_name_length, max_user_group_name_length,
}; };
const change_user_group_info_modal = render_change_user_group_info_modal(template_data); const change_user_group_info_modal = render_change_user_group_info_modal(template_data);
dialog_widget.launch({ dialog_widget.launch({
@ -310,7 +637,7 @@ export function initialize() {
}); });
$("#groups_overlay_container").on("click", ".group_settings_header .btn-danger", () => { $("#groups_overlay_container").on("click", ".group_settings_header .btn-danger", () => {
const active_group_data = user_groups_settings_ui.get_active_data(); const active_group_data = get_active_data();
const group_id = active_group_data.id; const group_id = active_group_data.id;
const user_group = user_groups.get_user_group_from_id(group_id); const user_group = user_groups.get_user_group_from_id(group_id);
@ -366,4 +693,36 @@ export function initialize() {
dialog_widget.submit_api_request(channel.patch, url, data); dialog_widget.submit_api_request(channel.patch, url, data);
} }
$("#groups_overlay_container").on("click", ".create_user_group_button", (e) => {
e.preventDefault();
open_create_user_group();
});
$("#groups_overlay_container").on("click", ".group-row", show_right_section);
$("#groups_overlay_container").on("click", ".fa-chevron-left", () => {
$(".right").removeClass("show");
$(".user-groups-header").removeClass("slide-left");
});
}
export function launch(section) {
setup_page(() => {
overlays.open_overlay({
name: "group_subscriptions",
$overlay: $("#groups_overlay"),
on_close() {
browser_history.exit_overlay();
},
});
change_state(section);
});
if (!get_active_data().id) {
if (section === "new") {
$("#create_user_group_name").trigger("focus");
} else {
$("#search_group_name").trigger("focus");
}
}
} }

View File

@ -1,377 +0,0 @@
import $ from "jquery";
import render_browse_user_groups_list_item from "../templates/user_group_settings/browse_user_groups_list_item.hbs";
import render_user_group_settings_overlay from "../templates/user_group_settings/user_group_settings_overlay.hbs";
import * as blueslip from "./blueslip";
import * as browser_history from "./browser_history";
import * as components from "./components";
import {$t} from "./i18n";
import * as ListWidget from "./list_widget";
import * as overlays from "./overlays";
import * as people from "./people";
import * as scroll_util from "./scroll_util";
import * as settings_data from "./settings_data";
import * as user_group_create from "./user_group_create";
import * as user_group_edit from "./user_group_edit";
import * as user_groups from "./user_groups";
import * as util from "./util";
let group_list_widget;
let group_list_toggler;
let active_group_id;
export function set_active_group_id(group_id) {
active_group_id = group_id;
}
export function reset_active_group_id() {
active_group_id = undefined;
}
// Ideally this should be included in page params.
// Like we have page_params.max_stream_name_length` and
// `page_params.max_stream_description_length` for streams.
export const max_user_group_name_length = 100;
export function set_up_click_handlers() {
$("#groups_overlay").on("click", ".left #clear_search_group_name", (e) => {
const $input = $("#groups_overlay .left #search_group_name");
$input.val("");
// This is a hack to rerender complete
// stream list once the text is cleared.
$input.trigger("input");
e.stopPropagation();
e.preventDefault();
});
}
export const show_user_group_settings_pane = {
nothing_selected() {
$("#groups_overlay .settings, #user-group-creation").hide();
reset_active_group_id();
$("#groups_overlay .nothing-selected").show();
$("#groups_overlay .user-group-info-title").text(
$t({defaultMessage: "User group settings"}),
);
},
settings(group) {
$("#groups_overlay .nothing-selected, #user-group-creation").hide();
$("#groups_overlay .settings").show();
set_active_group_id(group.id);
$("#groups_overlay .user-group-info-title").text(group.name);
},
create_user_group() {
$("#groups_overlay .nothing-selected, #groups_overlay .settings").hide();
reset_active_group_id();
$("#user-group-creation").show();
$("#groups_overlay .user-group-info-title").text($t({defaultMessage: "Create user group"}));
},
};
function create_user_group_clicked() {
// this changes the tab switcher (settings/preview) which isn't necessary
// to a add new stream title.
show_user_group_settings_pane.create_user_group();
$(".group-row.active").removeClass("active");
user_group_create.show_new_user_group_modal();
$("#create_user_group_name").trigger("focus");
}
export function do_open_create_user_group() {
// Only call this directly for hash changes.
// Prefer open_create_user_group().
show_right_section();
create_user_group_clicked();
}
export function open_create_user_group() {
do_open_create_user_group();
browser_history.update("#groups/new");
}
export function row_for_group_id(group_id) {
return $(`.group-row[data-group-id='${CSS.escape(group_id)}']`);
}
export function is_group_already_present(group) {
return row_for_group_id(group.id).length > 0;
}
export function get_active_data() {
const $active_tabs = $(".user-groups-container").find("div.ind-tab.selected");
return {
$row: row_for_group_id(active_group_id),
id: active_group_id,
$tabs: $active_tabs,
};
}
export function switch_to_group_row(group) {
if (is_group_already_present(group)) {
/*
It is possible that this function may be called at times
when group-row for concerned group may not be present this
might occur when user manually edits the url for a group
that user is not member of and #groups overlay is open with
your-groups tab active.
To handle such cases we perform these steps only if the group
is listed in the left panel else we simply open the settings
for the concerned group.
*/
const $group_row = row_for_group_id(group.id);
const $container = $(".user-groups-list");
get_active_data().$row.removeClass("active");
$group_row.addClass("active");
scroll_util.scroll_element_into_container($group_row, $container);
}
user_group_edit.show_group_settings(group);
}
function show_right_section() {
$(".right").addClass("show");
$(".user-groups-header").addClass("slide-left");
}
export function add_group_to_table(group) {
if (is_group_already_present(group)) {
// If a group is already listed/added in groups modal,
// then we simply return.
// This can happen in some corner cases (which might
// be backend bugs) where a realm administrator may
// get two user_group-add events.
return;
}
redraw_user_group_list();
if (user_group_create.get_name() === group.name) {
// This `user_group_create.get_name()` check tells us whether the
// group was just created in this browser window; it's a hack
// to work around the server_events code flow not having a
// good way to associate with this request because the group
// ID isn't known yet.
user_group_edit.show_group_settings(group);
user_group_create.reset_name();
}
}
export function update_group(group_id) {
if (!overlays.groups_open()) {
return;
}
const group = user_groups.get_user_group_from_id(group_id);
const $group_row = row_for_group_id(group_id);
// update left side pane
$group_row.find(".group-name").text(group.name);
$group_row.find(".description").text(group.description);
if (get_active_data().id === group.id) {
// update right side pane
user_group_edit.update_settings_pane(group);
// update settings title
$("#groups_overlay .user-group-info-title").text(group.name);
}
}
export function change_state(section) {
if (section === "new") {
do_open_create_user_group();
redraw_user_group_list();
return;
}
if (section === "all") {
group_list_toggler.goto("all-groups");
return;
}
if (section === "your") {
group_list_toggler.goto("your-groups");
return;
}
// if the section is a valid number.
if (/\d+/.test(section)) {
const group_id = Number.parseInt(section, 10);
const group = user_groups.get_user_group_from_id(group_id);
if (!group) {
// Some users can type random url of the form
// /#groups/<random-group-id> we need to handle that.
group_list_toggler.goto("your-groups");
} else {
show_right_section();
// We show the list of user groups in the left panel
// based on the tab that is active. It is `your-groups`
// tab by default.
redraw_user_group_list();
switch_to_group_row(group);
}
return;
}
blueslip.info("invalid section for groups: " + section);
group_list_toggler.goto("your-groups");
}
function compare_by_name(a, b) {
return util.strcmp(a.name, b.name);
}
function redraw_left_panel(tab_name) {
let groups_list_data;
if (tab_name === "all-groups") {
groups_list_data = user_groups.get_realm_user_groups();
} else if (tab_name === "your-groups") {
groups_list_data = user_groups.get_user_groups_of_user(people.my_current_user_id());
}
groups_list_data.sort(compare_by_name);
group_list_widget.replace_list_data(groups_list_data);
}
export function redraw_user_group_list() {
const tab_name = get_active_data().$tabs.first().attr("data-tab-key");
redraw_left_panel(tab_name);
}
export function switch_group_tab(tab_name) {
/*
This switches the groups list tab, but it doesn't update
the group_list_toggler widget. You may instead want to
use `group_list_toggler.goto`.
*/
redraw_left_panel(tab_name);
user_group_edit.setup_group_list_tab_hash(tab_name);
}
export function setup_page(callback) {
function initialize_components() {
group_list_toggler = components.toggle({
child_wants_focus: true,
values: [
{label: $t({defaultMessage: "Your groups"}), key: "your-groups"},
{label: $t({defaultMessage: "All groups"}), key: "all-groups"},
],
callback(_label, key) {
switch_group_tab(key);
},
});
$("#groups_overlay_container .list-toggler-container").prepend(group_list_toggler.get());
}
function populate_and_fill() {
const template_data = {
can_create_or_edit_user_groups: settings_data.user_can_edit_user_groups(),
max_user_group_name_length,
};
const rendered = render_user_group_settings_overlay(template_data);
const $groups_overlay_container = scroll_util.get_content_element(
$("#groups_overlay_container"),
);
$groups_overlay_container.empty();
$groups_overlay_container.append(rendered);
// Initially as the overlay is build with empty right panel,
// active_group_id is undefined.
reset_active_group_id();
const $container = $("#groups_overlay_container .user-groups-list");
/*
As change_state function called after this initial build up
redraws left panel based on active tab we avoid building extra dom
here as the required group-rows are anyway going to be created
immediately after this due to call to change_state. So we call
`ListWidget.create` with empty user groups list.
*/
group_list_widget = ListWidget.create($container, [], {
name: "user-groups-overlay",
get_item: ListWidget.default_get_item,
modifier_html(item) {
item.is_member = user_groups.is_direct_member_of(
people.my_current_user_id(),
item.id,
);
return render_browse_user_groups_list_item(item);
},
filter: {
$element: $("#groups_overlay_container .left #search_group_name"),
predicate(item, value) {
return (
item &&
(item.name.toLocaleLowerCase().includes(value) ||
item.description.toLocaleLowerCase().includes(value))
);
},
onupdate() {
if (active_group_id !== undefined) {
const active_group = user_groups.get_user_group_from_id(active_group_id);
if (is_group_already_present(active_group)) {
row_for_group_id(active_group_id).addClass("active");
}
}
},
},
init_sort: ["alphabetic", "name"],
$simplebar_container: $container,
});
initialize_components();
set_up_click_handlers();
user_group_create.set_up_handlers();
// show the "User group settings" header by default.
$(".display-type #user_group_settings_title").show();
if (callback) {
callback();
}
}
populate_and_fill();
}
export function initialize() {
$("#groups_overlay_container").on("click", ".create_user_group_button", (e) => {
e.preventDefault();
open_create_user_group();
});
$("#groups_overlay_container").on("click", ".group-row", show_right_section);
$("#groups_overlay_container").on("click", ".fa-chevron-left", () => {
$(".right").removeClass("show");
$(".user-groups-header").removeClass("slide-left");
});
}
export function launch(section) {
setup_page(() => {
overlays.open_overlay({
name: "group_subscriptions",
$overlay: $("#groups_overlay"),
on_close() {
browser_history.exit_overlay();
},
});
change_state(section);
});
if (!get_active_data().id) {
if (section === "new") {
$("#create_user_group_name").trigger("focus");
} else {
$("#search_group_name").trigger("focus");
}
}
}

View File

@ -85,7 +85,6 @@ const user_events = mock_esm("../src/user_events");
const user_groups = mock_esm("../src/user_groups"); const user_groups = mock_esm("../src/user_groups");
const user_group_edit = mock_esm("../src/user_group_edit"); const user_group_edit = mock_esm("../src/user_group_edit");
const overlays = mock_esm("../src/overlays"); const overlays = mock_esm("../src/overlays");
const user_groups_settings_ui = mock_esm("../src/user_groups_settings_ui");
mock_esm("../src/giphy"); mock_esm("../src/giphy");
const electron_bridge = set_global("electron_bridge", {}); const electron_bridge = set_global("electron_bridge", {});
@ -177,7 +176,7 @@ run_test("user groups", ({override}) => {
override(user_groups, "add", stub.f); override(user_groups, "add", stub.f);
override(overlays, "groups_open", () => true); override(overlays, "groups_open", () => true);
override(user_groups_settings_ui, "add_group_to_table", user_group_settings_ui_stub.f); override(user_group_edit, "add_group_to_table", user_group_settings_ui_stub.f);
dispatch(event); dispatch(event);
@ -269,7 +268,7 @@ run_test("user groups", ({override}) => {
const user_group_settings_ui_stub = make_stub(); const user_group_settings_ui_stub = make_stub();
override(user_groups, "update", stub.f); override(user_groups, "update", stub.f);
override(user_groups_settings_ui, "update_group", user_group_settings_ui_stub.f); override(user_group_edit, "update_group", user_group_settings_ui_stub.f);
dispatch(event); dispatch(event);
assert.equal(stub.num_calls, 1); assert.equal(stub.num_calls, 1);