zulip/web/src/stream_create_subscribers.ts
Shubham Padia 87b3642b62 stream_create: Soft remove users on clicking the remove button.
Fixes #29825.
Clicking on remove button will not delete the row anymore. We will
add a strikethrough to the user pill and email text. `Remove` button
will change to `Add` on click to undo this action.
Re-adding a user explicitly should will not undo the soft remove on
their row. e.g If `Iago` was added as part of a group and crossed out.
Now, adding another group with Iago as part of it should not undo the
soft remove.
We maintain a seperate set of soft removed users, but we will not
remove those users from the main user list on clicking `Remove`.
That list can only be modified by actions with the input pills.
We will subtract the soft removed user ids from main user id list
when sending the request to add subscribers to the new channel.
I've not added extra puppetteer tests, since adding users was
not part of the existing tests.
2024-06-28 15:35:56 -07:00

138 lines
5.1 KiB
TypeScript

import $ from "jquery";
import render_new_stream_user from "../templates/stream_settings/new_stream_user.hbs";
import render_new_stream_users from "../templates/stream_settings/new_stream_users.hbs";
import * as add_subscribers_pill from "./add_subscribers_pill";
import * as ListWidget from "./list_widget";
import type {ListWidget as ListWidgetType} from "./list_widget";
import * as people from "./people";
import {current_user} from "./state_data";
import * as stream_create_subscribers_data from "./stream_create_subscribers_data";
import * as user_sort from "./user_sort";
let all_users_list_widget: ListWidgetType<number, people.User>;
export function get_principals(): number[] {
return stream_create_subscribers_data.get_principals();
}
function redraw_subscriber_list(): void {
all_users_list_widget.replace_list_data(stream_create_subscribers_data.sorted_user_ids());
}
function add_user_ids(user_ids: number[]): void {
stream_create_subscribers_data.add_user_ids(user_ids);
redraw_subscriber_list();
}
function add_all_users(): void {
const user_ids = stream_create_subscribers_data.get_all_user_ids();
add_user_ids(user_ids);
}
function soft_remove_user_id(user_id: number): void {
stream_create_subscribers_data.soft_remove_user_id(user_id);
redraw_subscriber_list();
}
function undo_soft_remove_user_id(user_id: number): void {
stream_create_subscribers_data.undo_soft_remove_user_id(user_id);
redraw_subscriber_list();
}
function sync_user_ids(user_ids: number[]): void {
stream_create_subscribers_data.sync_user_ids(user_ids);
redraw_subscriber_list();
}
function build_pill_widget({$parent_container}: {$parent_container: JQuery}): void {
const $pill_container = $parent_container.find(".pill-container");
const get_potential_subscribers = stream_create_subscribers_data.get_potential_subscribers;
add_subscribers_pill.create_without_add_button({
$pill_container,
get_potential_subscribers,
onPillCreateAction: add_user_ids,
// It is better to sync the current set of user ids in the input
// instead of removing user_ids from the user_ids_set, otherwise
// we'll have to have more complex logic of when to remove
// a user and when not to depending upon their group, channel
// and individual pills.
onPillRemoveAction: sync_user_ids,
});
}
export function create_handlers($container: JQuery): void {
$container.on("click", ".add_all_users_to_stream", (e) => {
e.preventDefault();
add_all_users();
$(".add-user-list-filter").trigger("focus");
});
$container.on("click", ".remove_potential_subscriber", (e) => {
e.preventDefault();
const $elem = $(e.target);
const user_id = Number.parseInt($elem.attr("data-user-id")!, 10);
soft_remove_user_id(user_id);
});
$container.on("click", ".undo_soft_removed_potential_subscriber", (e) => {
e.preventDefault();
const $elem = $(e.target);
const user_id = Number.parseInt($elem.attr("data-user-id")!, 10);
undo_soft_remove_user_id(user_id);
});
}
export function build_widgets(): void {
const $add_people_container = $("#people_to_add");
$add_people_container.html(render_new_stream_users({}));
const $simplebar_container = $add_people_container.find(".subscriber_list_container");
build_pill_widget({$parent_container: $add_people_container});
stream_create_subscribers_data.initialize_with_current_user();
const current_user_id = current_user.user_id;
all_users_list_widget = ListWidget.create($("#create_stream_subscribers"), [current_user_id], {
name: "new_stream_add_users",
get_item: people.get_by_user_id,
$parent_container: $add_people_container,
modifier_html(user) {
const item = {
email: user.delivery_email,
user_id: user.user_id,
full_name: user.full_name,
is_current_user: user.user_id === current_user_id,
disabled: stream_create_subscribers_data.must_be_subscribed(user.user_id),
img_src: people.small_avatar_url_for_person(user),
soft_removed: stream_create_subscribers_data.user_id_in_soft_remove_list(
user.user_id,
),
};
return render_new_stream_user(item);
},
sort_fields: {
email: user_sort.sort_email,
id: user_sort.sort_user_id,
...ListWidget.generic_sort_functions("alphabetic", ["full_name"]),
},
filter: {
$element: $("#people_to_add .add-user-list-filter"),
predicate(user, search_term) {
return people.build_person_matcher(search_term)(user);
},
},
$simplebar_container,
html_selector(user) {
return $(`#${CSS.escape("user_checkbox_" + user.user_id)}`);
},
});
}
export function add_user_id_to_new_stream(user_id: number): void {
// This is only used by puppeteer tests.
add_user_ids([user_id]);
}