mirror of https://github.com/zulip/zulip.git
group_setting_pill: Add code for showing typeahead.
This commit adds code to show typeahead for group setting pill container. We add a separate function as we only want to show groups and users in the typeahead and the options are also sorted in a different order compared to other typeaheads.
This commit is contained in:
parent
053686669a
commit
8068b6e55e
|
@ -5,10 +5,12 @@ import render_input_pill from "../templates/input_pill.hbs";
|
|||
import * as group_permission_settings from "./group_permission_settings";
|
||||
import * as input_pill from "./input_pill";
|
||||
import type {InputPillConfig} from "./input_pill";
|
||||
import * as pill_typeahead from "./pill_typeahead";
|
||||
import type {GroupSettingPill, GroupSettingPillContainer} from "./typeahead_helper";
|
||||
import * as user_group_pill from "./user_group_pill";
|
||||
import type {UserGroupPill} from "./user_group_pill";
|
||||
import * as user_groups from "./user_groups";
|
||||
import type {UserGroup} from "./user_groups";
|
||||
import * as user_pill from "./user_pill";
|
||||
|
||||
function check_group_allowed_for_setting(group_item: UserGroupPill, setting_name: string): boolean {
|
||||
|
@ -102,3 +104,22 @@ export function create_pills(
|
|||
});
|
||||
return pill_widget;
|
||||
}
|
||||
|
||||
export function set_up_pill_typeahead({
|
||||
pill_widget,
|
||||
$pill_container,
|
||||
opts,
|
||||
}: {
|
||||
pill_widget: GroupSettingPillContainer;
|
||||
$pill_container: JQuery;
|
||||
opts: {
|
||||
setting_name: string;
|
||||
group: UserGroup | undefined;
|
||||
};
|
||||
}): void {
|
||||
pill_typeahead.set_up_group_setting_typeahead(
|
||||
$pill_container.find(".input"),
|
||||
pill_widget,
|
||||
opts,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -8,9 +8,10 @@ import type {User} from "./people";
|
|||
import * as stream_pill from "./stream_pill";
|
||||
import type {StreamPillData, StreamPillWidget} from "./stream_pill";
|
||||
import * as typeahead_helper from "./typeahead_helper";
|
||||
import type {CombinedPillContainer} from "./typeahead_helper";
|
||||
import type {CombinedPillContainer, GroupSettingPillContainer} from "./typeahead_helper";
|
||||
import * as user_group_pill from "./user_group_pill";
|
||||
import type {UserGroupPillData} from "./user_group_pill";
|
||||
import type {UserGroup} from "./user_groups";
|
||||
import * as user_pill from "./user_pill";
|
||||
import type {UserPillData, UserPillWidget} from "./user_pill";
|
||||
|
||||
|
@ -26,6 +27,7 @@ function group_matcher(query: string, item: UserGroupPillData): boolean {
|
|||
}
|
||||
|
||||
type TypeaheadItem = UserGroupPillData | StreamPillData | UserPillData;
|
||||
type GroupSettingTypeaheadItem = UserGroupPillData | UserPillData;
|
||||
|
||||
export function set_up_user(
|
||||
$input: JQuery,
|
||||
|
@ -127,6 +129,87 @@ export function set_up_stream(
|
|||
});
|
||||
}
|
||||
|
||||
export function set_up_group_setting_typeahead(
|
||||
$input: JQuery,
|
||||
pills: GroupSettingPillContainer,
|
||||
opts: {
|
||||
setting_name: string;
|
||||
group: UserGroup | undefined;
|
||||
},
|
||||
): void {
|
||||
const bootstrap_typeahead_input: TypeaheadInputElement = {
|
||||
$element: $input,
|
||||
type: "contenteditable",
|
||||
};
|
||||
new Typeahead(bootstrap_typeahead_input, {
|
||||
dropup: true,
|
||||
source(_query: string): GroupSettingTypeaheadItem[] {
|
||||
let source: GroupSettingTypeaheadItem[] = [];
|
||||
|
||||
source = user_group_pill.typeahead_source(pills, opts.setting_name);
|
||||
source = [...source, ...user_pill.typeahead_source(pills, true)];
|
||||
|
||||
return source;
|
||||
},
|
||||
highlighter_html(item: GroupSettingTypeaheadItem, _query: string): string {
|
||||
if (item.type === "user_group") {
|
||||
return typeahead_helper.render_user_group(item);
|
||||
}
|
||||
|
||||
assert(item.type === "user");
|
||||
return typeahead_helper.render_person(item);
|
||||
},
|
||||
matcher(item: GroupSettingTypeaheadItem, query: string): boolean {
|
||||
query = query.toLowerCase();
|
||||
query = query.replaceAll("\u00A0", " ");
|
||||
|
||||
let matches = false;
|
||||
if (item.type === "user_group") {
|
||||
matches = matches || group_matcher(query, item);
|
||||
}
|
||||
|
||||
if (item.type === "user") {
|
||||
matches = matches || person_matcher(query, item);
|
||||
}
|
||||
return matches;
|
||||
},
|
||||
sorter(matches: GroupSettingTypeaheadItem[], query: string): GroupSettingTypeaheadItem[] {
|
||||
const users: UserPillData[] = [];
|
||||
for (const match of matches) {
|
||||
if (match.type === "user" && people.is_known_user_id(match.user.user_id)) {
|
||||
users.push(match);
|
||||
}
|
||||
}
|
||||
|
||||
const groups: UserGroupPillData[] = [];
|
||||
for (const match of matches) {
|
||||
if (match.type === "user_group") {
|
||||
groups.push(match);
|
||||
}
|
||||
}
|
||||
|
||||
return typeahead_helper.sort_group_setting_options({
|
||||
users,
|
||||
query,
|
||||
groups,
|
||||
target_group: opts.group,
|
||||
});
|
||||
},
|
||||
updater(item: GroupSettingTypeaheadItem, _query: string): undefined {
|
||||
if (item.type === "user_group") {
|
||||
user_group_pill.append_user_group(item, pills);
|
||||
} else if (item.type === "user" && people.is_known_user_id(item.user.user_id)) {
|
||||
user_pill.append_user(item.user, pills);
|
||||
}
|
||||
|
||||
$input.trigger("focus");
|
||||
},
|
||||
stopAdvance: true,
|
||||
helpOnEmptyStrings: true,
|
||||
hideOnEmptyAfterBackspace: true,
|
||||
});
|
||||
}
|
||||
|
||||
export function set_up_combined(
|
||||
$input: JQuery,
|
||||
pills: CombinedPillContainer,
|
||||
|
|
|
@ -23,6 +23,7 @@ import type {StreamPill, StreamPillData} from "./stream_pill";
|
|||
import type {StreamSubscription} from "./sub_store";
|
||||
import type {UserGroupPill, UserGroupPillData} from "./user_group_pill";
|
||||
import * as user_groups from "./user_groups";
|
||||
import type {UserGroup} from "./user_groups";
|
||||
import type {UserPill, UserPillData} from "./user_pill";
|
||||
import * as user_status from "./user_status";
|
||||
import type {UserStatusEmojiInfo} from "./user_status";
|
||||
|
@ -555,6 +556,153 @@ export function sort_recipients<UserType extends UserOrMentionPillData | UserPil
|
|||
return recipients.slice(0, max_num_items);
|
||||
}
|
||||
|
||||
export function compare_setting_options(
|
||||
option_a: UserPillData | UserGroupPillData,
|
||||
option_b: UserPillData | UserGroupPillData,
|
||||
target_group: UserGroup | undefined,
|
||||
): number {
|
||||
if (option_a.type === "user_group" && option_b.type === "user") {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (option_b.type === "user_group" && option_a.type === "user") {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (option_a.type === "user_group" && option_b.type === "user_group") {
|
||||
const user_group_a = user_groups.get_user_group_from_id(option_a.id);
|
||||
const user_group_b = user_groups.get_user_group_from_id(option_b.id);
|
||||
|
||||
if (user_group_a.is_system_group && !user_group_b.is_system_group) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (user_group_b.is_system_group && !user_group_a.is_system_group) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (user_group_a.name < user_group_b.name) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert(option_a.type === "user");
|
||||
assert(option_b.type === "user");
|
||||
|
||||
if (target_group !== undefined) {
|
||||
if (
|
||||
!target_group.members.has(option_a.user.user_id) &&
|
||||
target_group.members.has(option_b.user.user_id)
|
||||
) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (
|
||||
target_group.members.has(option_a.user.user_id) &&
|
||||
!target_group.members.has(option_b.user.user_id)
|
||||
) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (option_a.user.full_name < option_b.user.full_name) {
|
||||
return -1;
|
||||
} else if (option_a.user.full_name === option_b.user.full_name) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
export function sort_group_setting_options({
|
||||
users,
|
||||
query,
|
||||
groups,
|
||||
target_group,
|
||||
}: {
|
||||
users: UserPillData[];
|
||||
query: string;
|
||||
groups: UserGroupPillData[];
|
||||
target_group: UserGroup | undefined;
|
||||
}): (UserPillData | UserGroupPillData)[] {
|
||||
function sort_group_setting_items(
|
||||
objs: (UserPillData | UserGroupPillData)[],
|
||||
): (UserPillData | UserGroupPillData)[] {
|
||||
objs.sort((option_a, option_b) =>
|
||||
compare_setting_options(option_a, option_b, target_group),
|
||||
);
|
||||
return objs;
|
||||
}
|
||||
|
||||
const users_name_results = typeahead.triage_raw(query, users, (p) => p.user.full_name);
|
||||
const email_results = typeahead.triage_raw(
|
||||
query,
|
||||
users_name_results.no_matches,
|
||||
(p) => p.user.email,
|
||||
);
|
||||
const groups_results = typeahead.triage_raw(query, groups, (g) =>
|
||||
user_groups.get_display_group_name(g.name),
|
||||
);
|
||||
|
||||
const exact_matches = sort_group_setting_items([
|
||||
...groups_results.exact_matches,
|
||||
...users_name_results.exact_matches,
|
||||
...email_results.exact_matches,
|
||||
]);
|
||||
|
||||
const prefix_matches = sort_group_setting_items([
|
||||
...groups_results.begins_with_case_sensitive_matches,
|
||||
...groups_results.begins_with_case_insensitive_matches,
|
||||
...users_name_results.begins_with_case_sensitive_matches,
|
||||
...users_name_results.begins_with_case_insensitive_matches,
|
||||
...email_results.begins_with_case_sensitive_matches,
|
||||
...email_results.begins_with_case_insensitive_matches,
|
||||
]);
|
||||
|
||||
const word_boundary_matches = sort_group_setting_items([
|
||||
...groups_results.word_boundary_matches,
|
||||
...users_name_results.word_boundary_matches,
|
||||
...email_results.word_boundary_matches,
|
||||
]);
|
||||
|
||||
const no_matches = sort_group_setting_items([
|
||||
...groups_results.no_matches,
|
||||
...email_results.no_matches,
|
||||
]);
|
||||
|
||||
const getters: {
|
||||
getter: (UserPillData | UserGroupPillData)[];
|
||||
}[] = [
|
||||
{
|
||||
getter: exact_matches,
|
||||
},
|
||||
{
|
||||
getter: prefix_matches,
|
||||
},
|
||||
{
|
||||
getter: word_boundary_matches,
|
||||
},
|
||||
{
|
||||
getter: no_matches,
|
||||
},
|
||||
];
|
||||
|
||||
const setting_options: (UserPillData | UserGroupPillData)[] = [];
|
||||
|
||||
for (const getter of getters) {
|
||||
if (setting_options.length >= MAX_ITEMS) {
|
||||
break;
|
||||
}
|
||||
for (const item of getter.getter) {
|
||||
setting_options.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
return setting_options.slice(0, MAX_ITEMS);
|
||||
}
|
||||
|
||||
type SlashCommand = {
|
||||
name: string;
|
||||
};
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import {$t_html} from "./i18n";
|
||||
import type {InputPillContainer} from "./input_pill";
|
||||
import * as people from "./people";
|
||||
import type {CombinedPill, CombinedPillContainer} from "./typeahead_helper";
|
||||
import type {
|
||||
CombinedPill,
|
||||
CombinedPillContainer,
|
||||
GroupSettingPillContainer,
|
||||
} from "./typeahead_helper";
|
||||
import type {UserGroup} from "./user_groups";
|
||||
import * as user_groups from "./user_groups";
|
||||
|
||||
|
@ -75,7 +79,10 @@ function get_group_members(user_group: UserGroup): number[] {
|
|||
return user_ids.filter((user_id) => people.is_person_active(user_id));
|
||||
}
|
||||
|
||||
export function append_user_group(group: UserGroup, pill_widget: CombinedPillContainer): void {
|
||||
export function append_user_group(
|
||||
group: UserGroup,
|
||||
pill_widget: CombinedPillContainer | GroupSettingPillContainer,
|
||||
): void {
|
||||
pill_widget.appendValidatedData({
|
||||
type: "user_group",
|
||||
group_id: group.id,
|
||||
|
@ -84,22 +91,32 @@ export function append_user_group(group: UserGroup, pill_widget: CombinedPillCon
|
|||
pill_widget.clear_text();
|
||||
}
|
||||
|
||||
export function get_group_ids(pill_widget: CombinedPillContainer): number[] {
|
||||
export function get_group_ids(
|
||||
pill_widget: CombinedPillContainer | GroupSettingPillContainer,
|
||||
): number[] {
|
||||
const items = pill_widget.items();
|
||||
return items.flatMap((item) => (item.type === "user_group" ? item.group_id : []));
|
||||
}
|
||||
|
||||
export function filter_taken_groups(
|
||||
items: UserGroup[],
|
||||
pill_widget: CombinedPillContainer,
|
||||
pill_widget: CombinedPillContainer | GroupSettingPillContainer,
|
||||
): UserGroup[] {
|
||||
const taken_group_ids = get_group_ids(pill_widget);
|
||||
items = items.filter((item) => !taken_group_ids.includes(item.id));
|
||||
return items;
|
||||
}
|
||||
|
||||
export function typeahead_source(pill_widget: CombinedPillContainer): UserGroupPillData[] {
|
||||
const groups = user_groups.get_realm_user_groups();
|
||||
export function typeahead_source(
|
||||
pill_widget: CombinedPillContainer | GroupSettingPillContainer,
|
||||
setting_name?: string,
|
||||
): UserGroupPillData[] {
|
||||
let groups;
|
||||
if (setting_name !== undefined) {
|
||||
groups = user_groups.get_realm_user_groups_for_setting(setting_name, "group", true);
|
||||
} else {
|
||||
groups = user_groups.get_realm_user_groups();
|
||||
}
|
||||
return filter_taken_groups(groups, pill_widget).map((user_group) => ({
|
||||
...user_group,
|
||||
type: "user_group",
|
||||
|
|
|
@ -133,6 +133,14 @@ export function get_realm_user_groups(include_deactivated = false): UserGroup[]
|
|||
});
|
||||
}
|
||||
|
||||
// This is only used for testing currently, but would be used in
|
||||
// future when we use system groups more and probably show them
|
||||
// in the UI as well.
|
||||
export function get_all_realm_user_groups(): UserGroup[] {
|
||||
const user_groups = [...user_group_by_id_dict.values()].sort((a, b) => a.id - b.id);
|
||||
return user_groups;
|
||||
}
|
||||
|
||||
export function get_user_groups_allowed_to_mention(): UserGroup[] {
|
||||
const user_groups = get_realm_user_groups();
|
||||
return user_groups.filter((group) => {
|
||||
|
@ -342,7 +350,7 @@ function get_display_name_for_system_group_option(setting_name: string, name: st
|
|||
export function check_system_user_group_allowed_for_setting(
|
||||
group_name: string,
|
||||
group_setting_config: GroupPermissionSetting,
|
||||
for_new_settings_ui = false,
|
||||
for_new_settings_ui: boolean,
|
||||
): boolean {
|
||||
const {
|
||||
allow_internet_group,
|
||||
|
@ -390,6 +398,7 @@ export function check_system_user_group_allowed_for_setting(
|
|||
export function get_realm_user_groups_for_setting(
|
||||
setting_name: string,
|
||||
setting_type: "realm" | "stream" | "group",
|
||||
for_new_settings_ui = false,
|
||||
): UserGroup[] {
|
||||
const group_setting_config = group_permission_settings.get_group_permission_setting_config(
|
||||
setting_name,
|
||||
|
@ -402,7 +411,11 @@ export function get_realm_user_groups_for_setting(
|
|||
|
||||
const system_user_groups = settings_config.system_user_groups_list
|
||||
.filter((group) =>
|
||||
check_system_user_group_allowed_for_setting(group.name, group_setting_config),
|
||||
check_system_user_group_allowed_for_setting(
|
||||
group.name,
|
||||
group_setting_config,
|
||||
for_new_settings_ui,
|
||||
),
|
||||
)
|
||||
.map((group) => {
|
||||
const user_group = get_user_group_from_name(group.name);
|
||||
|
|
|
@ -7,7 +7,11 @@ import * as input_pill from "./input_pill";
|
|||
import type {User} from "./people";
|
||||
import * as people from "./people";
|
||||
import {realm} from "./state_data";
|
||||
import type {CombinedPill, CombinedPillContainer} from "./typeahead_helper";
|
||||
import type {
|
||||
CombinedPill,
|
||||
CombinedPillContainer,
|
||||
GroupSettingPillContainer,
|
||||
} from "./typeahead_helper";
|
||||
import * as user_status from "./user_status";
|
||||
|
||||
// This will be used for pills for things like composing
|
||||
|
@ -98,7 +102,7 @@ export function get_email_from_item(item: UserPill): string {
|
|||
|
||||
export function append_person(opts: {
|
||||
person: User;
|
||||
pill_widget: UserPillWidget | CombinedPillContainer;
|
||||
pill_widget: UserPillWidget | CombinedPillContainer | GroupSettingPillContainer;
|
||||
}): void {
|
||||
const person = opts.person;
|
||||
const pill_widget = opts.pill_widget;
|
||||
|
@ -119,7 +123,9 @@ export function append_person(opts: {
|
|||
pill_widget.clear_text();
|
||||
}
|
||||
|
||||
export function get_user_ids(pill_widget: UserPillWidget | CombinedPillContainer): number[] {
|
||||
export function get_user_ids(
|
||||
pill_widget: UserPillWidget | CombinedPillContainer | GroupSettingPillContainer,
|
||||
): number[] {
|
||||
const items = pill_widget.items();
|
||||
return items.flatMap((item) => (item.type === "user" ? (item.user_id ?? []) : [])); // be defensive about undefined users
|
||||
}
|
||||
|
@ -138,7 +144,7 @@ export function has_unconverted_data(pill_widget: UserPillWidget): boolean {
|
|||
}
|
||||
|
||||
export function typeahead_source(
|
||||
pill_widget: UserPillWidget | CombinedPillContainer,
|
||||
pill_widget: UserPillWidget | CombinedPillContainer | GroupSettingPillContainer,
|
||||
exclude_bots?: boolean,
|
||||
): UserPillData[] {
|
||||
const users = exclude_bots ? people.get_realm_active_human_users() : people.get_realm_users();
|
||||
|
@ -147,14 +153,17 @@ export function typeahead_source(
|
|||
|
||||
export function filter_taken_users(
|
||||
items: User[],
|
||||
pill_widget: UserPillWidget | CombinedPillContainer,
|
||||
pill_widget: UserPillWidget | CombinedPillContainer | GroupSettingPillContainer,
|
||||
): User[] {
|
||||
const taken_user_ids = get_user_ids(pill_widget);
|
||||
items = items.filter((item) => !taken_user_ids.includes(item.user_id));
|
||||
return items;
|
||||
}
|
||||
|
||||
export function append_user(user: User, pills: UserPillWidget | CombinedPillContainer): void {
|
||||
export function append_user(
|
||||
user: User,
|
||||
pills: UserPillWidget | CombinedPillContainer | GroupSettingPillContainer,
|
||||
): void {
|
||||
if (user) {
|
||||
append_person({
|
||||
pill_widget: pills,
|
||||
|
|
|
@ -6,10 +6,12 @@ const {zrequire, mock_esm} = require("./lib/namespace");
|
|||
const {run_test} = require("./lib/test");
|
||||
const blueslip = require("./lib/zblueslip");
|
||||
const $ = require("./lib/zjquery");
|
||||
const {page_params, realm} = require("./lib/zpage_params");
|
||||
|
||||
const noop = function () {};
|
||||
|
||||
const bootstrap_typeahead = mock_esm("../src/bootstrap_typeahead");
|
||||
const group_permission_setting = mock_esm("../src/group_permission_settings");
|
||||
|
||||
const input_pill = zrequire("input_pill");
|
||||
const pill_typeahead = zrequire("pill_typeahead");
|
||||
|
@ -22,6 +24,7 @@ const typeahead_helper = zrequire("typeahead_helper");
|
|||
// set global test variables.
|
||||
let sort_recipients_called = false;
|
||||
let sort_streams_called = false;
|
||||
let sort_group_setting_options_called = false;
|
||||
const $fake_rendered_person = $.create("fake-rendered-person");
|
||||
const $fake_rendered_stream = $.create("fake-rendered-stream");
|
||||
const $fake_rendered_group = $.create("fake-rendered-group");
|
||||
|
@ -543,3 +546,170 @@ run_test("set_up_combined", ({mock_template, override, override_rewire}) => {
|
|||
pill_typeahead.set_up_combined($fake_input, $pill_widget, {});
|
||||
assert.ok(!input_pill_typeahead_called);
|
||||
});
|
||||
|
||||
run_test("set_up_group_setting_typeahead", ({mock_template, override, override_rewire}) => {
|
||||
override_rewire(typeahead_helper, "render_person", () => $fake_rendered_person);
|
||||
override_rewire(typeahead_helper, "render_user_group", () => $fake_rendered_group);
|
||||
override_rewire(typeahead_helper, "sort_group_setting_options", () => {
|
||||
sort_group_setting_options_called = true;
|
||||
});
|
||||
mock_template("input_pill.hbs", true, (_data, html) => html);
|
||||
|
||||
let input_pill_typeahead_called = false;
|
||||
const $fake_input = $.create(".input");
|
||||
$fake_input.before = noop;
|
||||
|
||||
const $container = $.create(".pill-container");
|
||||
$container.find = () => $fake_input;
|
||||
|
||||
const $pill_widget = input_pill.create({
|
||||
$container,
|
||||
create_item_from_text: noop,
|
||||
get_text_from_item: noop,
|
||||
get_display_value_from_item: noop,
|
||||
});
|
||||
|
||||
group_permission_setting.get_group_permission_setting_config = (setting_name, setting_type) => {
|
||||
assert.equal(setting_name, "can_manage_group");
|
||||
assert.equal(setting_type, "group");
|
||||
// This is not same as the original config for can_manage_group
|
||||
// setting, but is set in such a way that we need to create minimum
|
||||
// system groups.
|
||||
return {
|
||||
require_system_group: false,
|
||||
allow_internet_group: false,
|
||||
allow_owners_group: false,
|
||||
allow_nobody_group: true,
|
||||
allow_everyone_group: false,
|
||||
allowed_system_groups: ["role:moderators", "role:nobody", "role:fullmembers"],
|
||||
};
|
||||
};
|
||||
|
||||
const moderators_system_group = {
|
||||
name: "role:moderators",
|
||||
id: 3,
|
||||
description: "Moderators",
|
||||
members: [],
|
||||
is_system_group: true,
|
||||
};
|
||||
const nobody_system_group = {
|
||||
name: "role:nobody",
|
||||
id: 4,
|
||||
description: "Nobody",
|
||||
members: [],
|
||||
is_system_group: true,
|
||||
};
|
||||
const full_members_system_group = {
|
||||
name: "role:fullmembers",
|
||||
id: 5,
|
||||
description: "Full members",
|
||||
members: [],
|
||||
is_system_group: true,
|
||||
};
|
||||
user_groups.add(moderators_system_group);
|
||||
user_groups.add(nobody_system_group);
|
||||
user_groups.add(full_members_system_group);
|
||||
|
||||
const moderators_item = user_group_item(moderators_system_group);
|
||||
const system_group_items = [moderators_item];
|
||||
|
||||
page_params.development_environment = true;
|
||||
realm.realm_waiting_period_threshold = 0;
|
||||
|
||||
override(bootstrap_typeahead, "Typeahead", (input_element, config) => {
|
||||
assert.equal(input_element.$element, $fake_input);
|
||||
assert.ok(config.dropup);
|
||||
assert.ok(config.stopAdvance);
|
||||
|
||||
assert.equal(typeof config.source, "function");
|
||||
assert.equal(typeof config.highlighter_html, "function");
|
||||
assert.equal(typeof config.matcher, "function");
|
||||
assert.equal(typeof config.sorter, "function");
|
||||
assert.equal(typeof config.updater, "function");
|
||||
|
||||
// test queries
|
||||
const person_query = "me";
|
||||
const group_query = "test";
|
||||
|
||||
(function test_highlighter() {
|
||||
// If user is also allowed along with user_group
|
||||
// then we should check that each of them rendered correctly.
|
||||
assert.equal(config.highlighter_html(testers_item, group_query), $fake_rendered_group);
|
||||
assert.equal(config.highlighter_html(me_item, person_query), $fake_rendered_person);
|
||||
})();
|
||||
|
||||
(function test_matcher() {
|
||||
let result;
|
||||
// group query, with correct item.
|
||||
result = config.matcher(testers_item, group_query);
|
||||
assert.ok(result);
|
||||
// group query, with wrong item.
|
||||
result = config.matcher(admins_item, group_query);
|
||||
assert.ok(!result);
|
||||
// person query with correct item.
|
||||
result = config.matcher(me_item, person_query);
|
||||
assert.ok(result);
|
||||
// person query with wrong item.
|
||||
result = config.matcher(jill_item, person_query);
|
||||
assert.ok(!result);
|
||||
})();
|
||||
|
||||
(function test_sorter() {
|
||||
sort_group_setting_options_called = false;
|
||||
config.sorter([testers_item], group_query);
|
||||
assert.ok(sort_group_setting_options_called);
|
||||
sort_group_setting_options_called = false;
|
||||
config.sorter([me_item], person_query);
|
||||
assert.ok(sort_group_setting_options_called);
|
||||
})();
|
||||
|
||||
(function test_source() {
|
||||
let expected_result = [];
|
||||
let actual_result = [];
|
||||
function is_group(item) {
|
||||
return item.members;
|
||||
}
|
||||
const result = config.source(person_query);
|
||||
actual_result = result
|
||||
.map((item) => {
|
||||
if (is_group(item)) {
|
||||
return item.id;
|
||||
}
|
||||
return item.user_id;
|
||||
})
|
||||
.filter(Boolean);
|
||||
expected_result = [...expected_result, ...system_group_items, ...group_items];
|
||||
expected_result = [...expected_result, ...person_items];
|
||||
expected_result = expected_result
|
||||
.map((item) => {
|
||||
if (is_group(item)) {
|
||||
return item.id;
|
||||
}
|
||||
return item.user_id;
|
||||
})
|
||||
.filter(Boolean);
|
||||
assert.deepEqual(actual_result, expected_result);
|
||||
})();
|
||||
|
||||
(function test_updater() {
|
||||
function number_of_pills() {
|
||||
const pills = $pill_widget.items();
|
||||
return pills.length;
|
||||
}
|
||||
assert.equal(number_of_pills(), 0);
|
||||
config.updater(me_item, person_query);
|
||||
assert.equal(number_of_pills(), 1);
|
||||
config.updater(testers_item, group_query);
|
||||
assert.equal(number_of_pills(), 2);
|
||||
})();
|
||||
|
||||
input_pill_typeahead_called = true;
|
||||
});
|
||||
|
||||
const opts = {
|
||||
setting_name: "can_manage_group",
|
||||
group: testers,
|
||||
};
|
||||
pill_typeahead.set_up_group_setting_typeahead($fake_input, $pill_widget, opts);
|
||||
assert.ok(input_pill_typeahead_called);
|
||||
});
|
||||
|
|
|
@ -22,6 +22,7 @@ const pygments_data = zrequire("pygments_data");
|
|||
const util = zrequire("util");
|
||||
const ct = zrequire("composebox_typeahead");
|
||||
const th = zrequire("typeahead_helper");
|
||||
const user_groups = zrequire("user_groups");
|
||||
|
||||
let next_id = 0;
|
||||
|
||||
|
@ -40,6 +41,10 @@ function broadcast_item(user) {
|
|||
return {type: "broadcast", user};
|
||||
}
|
||||
|
||||
function user_group_item(user_group) {
|
||||
return {type: "user_group", ...user_group};
|
||||
}
|
||||
|
||||
const a_bot = {
|
||||
email: "a_bot@zulip.com",
|
||||
full_name: "A Zulip test bot",
|
||||
|
@ -124,6 +129,45 @@ stream_data.create_streams([dev_sub, linux_sub]);
|
|||
stream_data.add_sub(dev_sub);
|
||||
stream_data.add_sub(linux_sub);
|
||||
|
||||
const bob_system_group = {
|
||||
id: 1,
|
||||
name: "Bob system group",
|
||||
description: "",
|
||||
members: new Set([]),
|
||||
is_system_group: true,
|
||||
};
|
||||
const bob_system_group_item = user_group_item(bob_system_group);
|
||||
|
||||
const bob_group = {
|
||||
id: 2,
|
||||
name: "Bob group",
|
||||
description: "",
|
||||
members: new Set([]),
|
||||
is_system_group: false,
|
||||
};
|
||||
const bob_group_item = user_group_item(bob_group);
|
||||
|
||||
const second_bob_group = {
|
||||
id: 3,
|
||||
name: "bob 2 group",
|
||||
description: "",
|
||||
members: new Set([b_user_2.user_id]),
|
||||
is_system_group: false,
|
||||
};
|
||||
|
||||
const admins_group = {
|
||||
id: 4,
|
||||
name: "Admins of zulip",
|
||||
description: "",
|
||||
members: new Set([]),
|
||||
is_system_group: false,
|
||||
};
|
||||
const admins_group_item = user_group_item(admins_group);
|
||||
|
||||
user_groups.initialize({
|
||||
realm_user_groups: [bob_system_group, bob_group, second_bob_group, admins_group],
|
||||
});
|
||||
|
||||
function test(label, f) {
|
||||
run_test(label, (helpers) => {
|
||||
pm_conversations.clear_for_testing();
|
||||
|
@ -942,3 +986,100 @@ test("compare_language", () => {
|
|||
test("compare_by_pms", () => {
|
||||
assert.equal(th.compare_by_pms(a_user, a_user), 0);
|
||||
});
|
||||
|
||||
test("sort_group_setting_options", ({override_rewire}) => {
|
||||
function get_group_setting_typeahead_result(query, target_group) {
|
||||
const users = people.get_realm_active_human_users().map((user) => ({type: "user", user}));
|
||||
const groups = user_groups.get_all_realm_user_groups().map((group) => ({
|
||||
type: "user_group",
|
||||
...group,
|
||||
}));
|
||||
const result = th.sort_group_setting_options({
|
||||
users,
|
||||
query,
|
||||
groups,
|
||||
target_group,
|
||||
});
|
||||
return result.map((item) => {
|
||||
if (item.type === "user") {
|
||||
return item.user.full_name;
|
||||
}
|
||||
|
||||
return item.name;
|
||||
});
|
||||
}
|
||||
|
||||
assert.deepEqual(get_group_setting_typeahead_result("Bo", second_bob_group), [
|
||||
bob_system_group.name,
|
||||
bob_group.name,
|
||||
second_bob_group.name,
|
||||
b_user_2.full_name,
|
||||
b_user_1.full_name,
|
||||
b_user_3.full_name,
|
||||
admins_group.name,
|
||||
a_user.full_name,
|
||||
zman.full_name,
|
||||
]);
|
||||
|
||||
assert.deepEqual(get_group_setting_typeahead_result("bo", second_bob_group), [
|
||||
bob_system_group.name,
|
||||
bob_group.name,
|
||||
second_bob_group.name,
|
||||
b_user_2.full_name,
|
||||
b_user_1.full_name,
|
||||
b_user_3.full_name,
|
||||
admins_group.name,
|
||||
a_user.full_name,
|
||||
zman.full_name,
|
||||
]);
|
||||
|
||||
assert.deepEqual(get_group_setting_typeahead_result("Z", second_bob_group), [
|
||||
zman.full_name,
|
||||
admins_group.name,
|
||||
a_user.full_name,
|
||||
bob_system_group.name,
|
||||
bob_group.name,
|
||||
second_bob_group.name,
|
||||
b_user_2.full_name,
|
||||
b_user_1.full_name,
|
||||
b_user_3.full_name,
|
||||
]);
|
||||
|
||||
override_rewire(th, "MAX_ITEMS", 6);
|
||||
assert.deepEqual(get_group_setting_typeahead_result("Bo", second_bob_group), [
|
||||
bob_system_group.name,
|
||||
bob_group.name,
|
||||
second_bob_group.name,
|
||||
b_user_2.full_name,
|
||||
b_user_1.full_name,
|
||||
b_user_3.full_name,
|
||||
]);
|
||||
});
|
||||
|
||||
test("compare_setting_options", () => {
|
||||
// User group has higher priority than user.
|
||||
assert.equal(th.compare_setting_options(a_user_item, bob_group_item, bob_group), 1);
|
||||
assert.equal(th.compare_setting_options(bob_group_item, a_user_item, bob_group), -1);
|
||||
|
||||
// System user group has higher priority than other user groups.
|
||||
assert.equal(th.compare_setting_options(bob_group_item, bob_system_group_item, bob_group), 1);
|
||||
assert.equal(th.compare_setting_options(bob_system_group_item, bob_group_item, bob_group), -1);
|
||||
assert.equal(
|
||||
th.compare_setting_options(admins_group_item, bob_system_group_item, bob_group),
|
||||
1,
|
||||
);
|
||||
|
||||
// In case both groups are not system groups, alphabetical order is used to decide priority.
|
||||
assert.equal(th.compare_setting_options(bob_group_item, admins_group_item, bob_group), 1);
|
||||
assert.equal(th.compare_setting_options(admins_group_item, bob_group_item, bob_group), -1);
|
||||
|
||||
// A user who is a member of the group being changed has higher priority.
|
||||
// If both the users are not members of the group being changed, alphabetical order
|
||||
// is used to decide priority.
|
||||
assert.equal(th.compare_setting_options(b_user_1_item, b_user_2_item, bob_group), -1);
|
||||
assert.equal(th.compare_setting_options(b_user_1_item, b_user_2_item, second_bob_group), 1);
|
||||
|
||||
// Get coverage for case where two users have same names. Original order is preserved
|
||||
// in such cases.
|
||||
assert.equal(th.compare_setting_options(b_user_1_item, b_user_1_item, bob_group), 0);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue