stream_create: Remove add button and add to list on typeahead enter.

Clicking remove in the subscriber list table should strikethrough
according to the new behaviour but we will do that in the next
commit.
One additional detail to the specs described in #29825 is that we
will not have a pill for the current user. Discussion can be found
here: https://chat.zulip.org/#narrow/stream/6-frontend/topic/Disabled.2Fun-editable.20input.20pill/near/1838691
This commit is contained in:
Shubham Padia 2024-06-26 11:54:45 +00:00 committed by Tim Abbott
parent c10ff0bea8
commit 3e7be80656
7 changed files with 94 additions and 32 deletions

View File

@ -99,6 +99,39 @@ export function create({
return pill_widget;
}
export function create_without_add_button({
$pill_container,
get_potential_subscribers,
onPillCreateAction,
onPillRemoveAction,
}: {
$pill_container: JQuery;
get_potential_subscribers: () => User[];
onPillCreateAction: (pill_user_ids: number[]) => void;
onPillRemoveAction: (pill_user_ids: number[]) => void;
}): CombinedPillContainer {
const pill_widget = input_pill.create<CombinedPill>({
$container: $pill_container,
create_item_from_text,
get_text_from_item,
});
function get_users(): User[] {
const potential_subscribers = get_potential_subscribers();
return user_pill.filter_taken_users(potential_subscribers, pill_widget);
}
pill_widget.onPillCreate(() => {
onPillCreateAction(get_pill_user_ids(pill_widget));
});
pill_widget.onPillRemove(() => {
onPillRemoveAction(get_pill_user_ids(pill_widget));
});
set_up_pill_typeahead({pill_widget, $pill_container, get_users});
return pill_widget;
}
function get_pill_user_ids(pill_widget: CombinedPillContainer): number[] {
const user_ids = user_pill.get_user_ids(pill_widget);
const stream_user_ids = stream_pill.get_user_ids(pill_widget);

View File

@ -9,10 +9,8 @@ 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 type {CombinedPillContainer} from "./typeahead_helper";
import * as user_sort from "./user_sort";
let pill_widget: CombinedPillContainer;
let all_users_list_widget: ListWidgetType<number, people.User>;
export function get_principals(): number[] {
@ -38,11 +36,25 @@ function remove_user_ids(user_ids: number[]): void {
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;
pill_widget = add_subscribers_pill.create({$pill_container, 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 {
@ -58,23 +70,6 @@ export function create_handlers($container: JQuery): void {
const user_id = Number.parseInt($elem.attr("data-user-id")!, 10);
remove_user_ids([user_id]);
});
const button_selector = ".add_subscribers_container button.add-subscriber-button";
function add_users({pill_user_ids}: {pill_user_ids: number[]}): void {
add_user_ids(pill_user_ids);
// eslint-disable-next-line unicorn/no-array-callback-reference
const $pill_widget_button = $container.find(button_selector);
$pill_widget_button.prop("disabled", true);
pill_widget.clear();
}
add_subscribers_pill.set_up_handlers({
get_pill_widget: () => pill_widget,
$parent_container: $container,
pill_selector: ".add_subscribers_container .input",
button_selector,
action: add_users,
});
}
export function build_widgets(): void {

View File

@ -52,3 +52,13 @@ export function remove_user_ids(user_ids: number[]): void {
user_id_set.delete(user_id);
}
}
export function sync_user_ids(user_ids: number[]): void {
// Current user does not have their pill in their input
// box, so we need to make sure that we don't delete
// it unnecessarily while syncing.
if (user_id_set.has(current_user.user_id)) {
user_ids.push(current_user.user_id);
}
user_id_set = new Set(user_ids);
}

View File

@ -408,16 +408,11 @@ export function enable_or_disable_add_subscribers_elements(
stream_creation = false,
) {
const $input_element = $container_elem.find(".input").expectOne();
const $add_subscribers_button = $container_elem
.find('button[name="add_subscriber"]')
.expectOne();
const $add_subscribers_container = $(".edit_subscribers_for_stream .subscriber_list_settings");
$input_element.prop("contenteditable", enable_elem);
$add_subscribers_button.prop("disabled", !enable_elem);
if (enable_elem) {
$add_subscribers_button.css("pointer-events", "");
$add_subscribers_container[0]?._tippy?.destroy();
$container_elem.find(".add_subscribers_container").removeClass("add_subscribers_disabled");
} else {
@ -437,5 +432,13 @@ export function enable_or_disable_add_subscribers_elements(
.find(".add_all_users_to_stream_btn_container")
.addClass("add_subscribers_disabled");
}
} else {
const $add_subscribers_button = $container_elem
.find('button[name="add_subscriber"]')
.expectOne();
$add_subscribers_button.prop("disabled", !enable_elem);
if (enable_elem) {
$add_subscribers_button.css("pointer-events", "");
}
}
}

View File

@ -5,9 +5,11 @@
{{~! Squash whitespace so that placeholder is displayed when empty. ~}}
</div>
</div>
<div class="add_subscriber_btn_wrapper inline-block">
<button type="submit" name="add_subscriber" class="button add-subscriber-button add-users-button small rounded sea-green" tabindex="0">
{{t 'Add' }}
</button>
</div>
{{#if (not hide_add_button)}}
<div class="add_subscriber_btn_wrapper inline-block">
<button type="submit" name="add_subscriber" class="button add-subscriber-button add-users-button small rounded sea-green" tabindex="0">
{{t 'Add' }}
</button>
</div>
{{/if}}
</div>

View File

@ -1,6 +1,6 @@
<div class="subscriber_list_settings">
<div class="subscriber_list_add float-left">
{{> add_subscribers_form}}
{{> add_subscribers_form hide_add_button=true}}
</div>
<br />

View File

@ -78,3 +78,22 @@ test("must_be_subscribed", () => {
assert.ok(!stream_create_subscribers_data.must_be_subscribed(me.user_id));
assert.ok(!stream_create_subscribers_data.must_be_subscribed(test_user101.user_id));
});
test("sync_user_ids", () => {
// sync_user_ids should not remove current user if already present.
stream_create_subscribers_data.initialize_with_current_user();
stream_create_subscribers_data.sync_user_ids([test_user101.user_id, test_user102.user_id]);
assert.deepEqual(stream_create_subscribers_data.sorted_user_ids(), [
me.user_id,
test_user101.user_id,
test_user102.user_id,
]);
// sync_user_ids should not add current user if already not present.
stream_create_subscribers_data.remove_user_ids([me.user_id]);
stream_create_subscribers_data.sync_user_ids([test_user101.user_id, test_user102.user_id]);
assert.deepEqual(stream_create_subscribers_data.sorted_user_ids(), [
test_user101.user_id,
test_user102.user_id,
]);
});