diff --git a/tools/test-js-with-node b/tools/test-js-with-node index 149c1e3f07..4f36f3e7fb 100755 --- a/tools/test-js-with-node +++ b/tools/test-js-with-node @@ -114,6 +114,7 @@ EXEMPT_FILES = make_set( "web/src/giphy.js", "web/src/giphy_state.ts", "web/src/global.ts", + "web/src/group_setting_pill.ts", "web/src/hash_util.ts", "web/src/hashchange.js", "web/src/hbs.d.ts", diff --git a/web/src/group_setting_pill.ts b/web/src/group_setting_pill.ts new file mode 100644 index 0000000000..67ecb103ed --- /dev/null +++ b/web/src/group_setting_pill.ts @@ -0,0 +1,104 @@ +import assert from "minimalistic-assert"; + +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 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 * as user_pill from "./user_pill"; + +function check_group_allowed_for_setting(group_item: UserGroupPill, setting_name: string): boolean { + const group_setting_config = group_permission_settings.get_group_permission_setting_config( + setting_name, + "group", + ); + + assert(group_setting_config !== undefined); + + const group = user_groups.get_user_group_from_id(group_item.group_id); + if (!group.is_system_group) { + if (group_setting_config.require_system_group) { + return false; + } + + return true; + } + + return user_groups.check_system_user_group_allowed_for_setting( + group.name, + group_setting_config, + true, + ); +} + +export function create_item_from_text( + text: string, + current_items: GroupSettingPill[], + pill_config?: InputPillConfig, +): GroupSettingPill | undefined { + const group_item = user_group_pill.create_item_from_group_name(text, current_items); + if (group_item) { + const setting_name = pill_config?.setting_name; + assert(setting_name !== undefined); + if (check_group_allowed_for_setting(group_item, setting_name)) { + return group_item; + } + + return undefined; + } + + return user_pill.create_item_from_email(text, current_items); +} + +export function get_text_from_item(item: GroupSettingPill): string { + let text: string; + switch (item.type) { + case "user_group": + text = user_group_pill.get_group_name_from_item(item); + break; + case "user": + text = user_pill.get_email_from_item(item); + break; + } + return text; +} + +export function get_display_value_from_item(item: GroupSettingPill): string { + if (item.type === "user_group") { + return user_group_pill.display_pill(user_groups.get_user_group_from_id(item.group_id)); + } + assert(item.type === "user"); + return user_pill.get_display_value_from_item(item); +} + +export function generate_pill_html(item: GroupSettingPill): string { + if (item.type === "user_group") { + return render_input_pill({ + display_value: get_display_value_from_item(item), + group_id: item.group_id, + }); + } + assert(item.type === "user"); + return user_pill.generate_pill_html(item); +} + +export function create_pills( + $pill_container: JQuery, + setting_name: string, +): GroupSettingPillContainer { + const pill_widget = input_pill.create({ + $container: $pill_container, + create_item_from_text, + get_text_from_item, + get_display_value_from_item, + generate_pill_html, + pill_config: { + setting_name, + }, + }); + return pill_widget; +} diff --git a/web/src/input_pill.ts b/web/src/input_pill.ts index faae34c061..428192a8c3 100644 --- a/web/src/input_pill.ts +++ b/web/src/input_pill.ts @@ -13,6 +13,7 @@ import * as util from "./util"; export type InputPillConfig = { exclude_inaccessible_users?: boolean; + setting_name?: string; }; type InputPillCreateOptions = { diff --git a/web/src/typeahead_helper.ts b/web/src/typeahead_helper.ts index 8056a3a4f7..f22c76cd0d 100644 --- a/web/src/typeahead_helper.ts +++ b/web/src/typeahead_helper.ts @@ -37,6 +37,9 @@ export type UserOrMentionPillData = UserOrMention & { export type CombinedPill = StreamPill | UserGroupPill | UserPill; export type CombinedPillContainer = InputPillContainer; +export type GroupSettingPill = UserGroupPill | UserPill; +export type GroupSettingPillContainer = InputPillContainer; + export function build_highlight_regex(query: string): RegExp { const regex = new RegExp("(" + _.escapeRegExp(query) + ")", "ig"); return regex; diff --git a/web/src/user_groups.ts b/web/src/user_groups.ts index 9408e0a33a..0a03ef0285 100644 --- a/web/src/user_groups.ts +++ b/web/src/user_groups.ts @@ -13,7 +13,7 @@ import type { StateData, user_group_schema, } from "./state_data"; -import {current_user} from "./state_data"; +import {current_user, realm} from "./state_data"; import type {UserOrMention} from "./typeahead_helper"; import type {UserGroupUpdateEvent} from "./types"; @@ -342,6 +342,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, ): boolean { const { allow_internet_group, @@ -359,7 +360,7 @@ export function check_system_user_group_allowed_for_setting( return false; } - if (!allow_nobody_group && group_name === "role:nobody") { + if ((!allow_nobody_group || for_new_settings_ui) && group_name === "role:nobody") { return false; } @@ -371,6 +372,18 @@ export function check_system_user_group_allowed_for_setting( return false; } + if ( + group_name === "role:fullmembers" && + for_new_settings_ui && + realm.realm_waiting_period_threshold === 0 + ) { + // We hide the full members group in the typeahead when + // there is no separation between member and full member + // users due to organization not having set a waiting + // period for member users to become full members. + return false; + } + return true; }