From 2968eb2b045dfcd69e16ce5c30c4d27f706c8c77 Mon Sep 17 00:00:00 2001 From: Sahil Batra Date: Mon, 27 Nov 2023 16:06:07 +0530 Subject: [PATCH] user_groups: Add UI to set and update can_mention_group setting. This commit adds support to set can_mention_group setting when creating user group and also update the setting for existing user groups. --- tools/test-js-with-node | 1 + web/src/settings_components.js | 32 +++++++++-- web/src/settings_org.js | 15 +++-- web/src/types.ts | 1 + web/src/user_group_components.js | 55 +++++++++++++++++++ web/src/user_group_create.js | 8 +++ web/src/user_group_edit.js | 55 +++++++++++++++++++ web/src/user_groups.ts | 6 ++ web/styles/app_components.css | 3 +- web/styles/subscriptions.css | 3 +- .../user_group_settings/group_permissions.hbs | 4 ++ .../user_group_creation_form.hbs | 10 ++++ .../user_group_settings.hbs | 10 ++++ 13 files changed, 192 insertions(+), 11 deletions(-) create mode 100644 web/src/user_group_components.js create mode 100644 web/templates/user_group_settings/group_permissions.hbs diff --git a/tools/test-js-with-node b/tools/test-js-with-node index 7e6334bc68..7e7b804f7f 100755 --- a/tools/test-js-with-node +++ b/tools/test-js-with-node @@ -259,6 +259,7 @@ EXEMPT_FILES = make_set( "web/src/url-template.d.ts", "web/src/user_card_popover.js", "web/src/user_deactivation_ui.ts", + "web/src/user_group_components.js", "web/src/user_group_create.js", "web/src/user_group_create_members.js", "web/src/user_group_create_members_data.ts", diff --git a/web/src/settings_components.js b/web/src/settings_components.js index c12b9ec1c0..01e137c1cf 100644 --- a/web/src/settings_components.js +++ b/web/src/settings_components.js @@ -48,7 +48,7 @@ export function get_realm_time_limits_in_minutes(property) { return val.toString(); } -export function get_property_value(property_name, for_realm_default_settings, sub) { +export function get_property_value(property_name, for_realm_default_settings, sub, group) { if (for_realm_default_settings) { // realm_user_default_settings are stored in a separate object. if (property_name === "twenty_four_hour_time") { @@ -74,6 +74,10 @@ export function get_property_value(property_name, for_realm_default_settings, su return sub[property_name]; } + if (group) { + return group[property_name]; + } + if (property_name === "realm_org_join_restrictions") { if (page_params.realm_emails_restricted_to_domains) { return "only_selected_domain"; @@ -240,6 +244,8 @@ export let signup_notifications_stream_widget = null; export let create_multiuse_invite_group_widget = null; export let can_remove_subscribers_group_widget = null; export let can_access_all_users_group_widget = null; +export let can_mention_group_widget = null; +export let new_group_can_mention_group_widget = null; export function get_widget_for_dropdown_list_settings(property_name) { switch (property_name) { @@ -255,6 +261,8 @@ export function get_widget_for_dropdown_list_settings(property_name) { return can_remove_subscribers_group_widget; case "realm_can_access_all_users_group": return can_access_all_users_group_widget; + case "can_mention_group": + return can_mention_group_widget; default: blueslip.error("No dropdown list widget for property", {property_name}); return null; @@ -285,6 +293,14 @@ export function set_can_access_all_users_group_widget(widget) { can_access_all_users_group_widget = widget; } +export function set_can_mention_group_widget(widget) { + can_mention_group_widget = widget; +} + +export function set_new_group_can_mention_group_widget(widget) { + new_group_can_mention_group_widget = widget; +} + export function set_dropdown_list_widget_setting_value(property_name, value) { const widget = get_widget_for_dropdown_list_settings(property_name); widget.render(value); @@ -475,10 +491,10 @@ function get_time_limit_setting_value($input_elem, for_api_data = true) { return parse_time_limit($custom_input_elem); } -export function check_property_changed(elem, for_realm_default_settings, sub) { +export function check_property_changed(elem, for_realm_default_settings, sub, group) { const $elem = $(elem); const property_name = extract_property_name($elem, for_realm_default_settings); - let current_val = get_property_value(property_name, for_realm_default_settings, sub); + let current_val = get_property_value(property_name, for_realm_default_settings, sub, group); let proposed_val; switch (property_name) { @@ -493,6 +509,7 @@ export function check_property_changed(elem, for_realm_default_settings, sub) { case "realm_default_code_block_language": case "can_remove_subscribers_group": case "realm_create_multiuse_invite_group": + case "can_mention_group": proposed_val = get_dropdown_list_widget_setting_value($elem); break; case "email_notifications_batching_period_seconds": @@ -545,12 +562,17 @@ function switching_to_private(properties_elements, for_realm_default_settings) { return false; } -export function save_discard_widget_status_handler($subsection, for_realm_default_settings, sub) { +export function save_discard_widget_status_handler( + $subsection, + for_realm_default_settings, + sub, + group, +) { $subsection.find(".subsection-failed-status p").hide(); $subsection.find(".save-button").show(); const properties_elements = get_subsection_property_elements($subsection); const show_change_process_button = properties_elements.some((elem) => - check_property_changed(elem, for_realm_default_settings, sub), + check_property_changed(elem, for_realm_default_settings, sub, group), ); const $save_btn_controls = $subsection.find(".subsection-header .save-button-controls"); diff --git a/web/src/settings_org.js b/web/src/settings_org.js index 75781f0e27..f4b30ba7a4 100644 --- a/web/src/settings_org.js +++ b/web/src/settings_org.js @@ -447,7 +447,7 @@ function update_dependent_subsettings(property_name) { } } -export function discard_property_element_changes(elem, for_realm_default_settings, sub) { +export function discard_property_element_changes(elem, for_realm_default_settings, sub, group) { const $elem = $(elem); const property_name = settings_components.extract_property_name( $elem, @@ -457,6 +457,7 @@ export function discard_property_element_changes(elem, for_realm_default_setting property_name, for_realm_default_settings, sub, + group, ); switch (property_name) { @@ -478,6 +479,7 @@ export function discard_property_element_changes(elem, for_realm_default_setting case "can_remove_subscribers_group": case "realm_create_multiuse_invite_group": case "realm_can_access_all_users_group": + case "can_mention_group": settings_components.set_dropdown_list_widget_setting_value( property_name, property_value, @@ -767,19 +769,24 @@ export function init_dropdown_widgets() { can_access_all_users_group_widget.setup(); } -export function populate_data_for_request(subsection, for_realm_default_settings, sub) { +export function populate_data_for_request(subsection, for_realm_default_settings, sub, group) { let data = {}; const properties_elements = settings_components.get_subsection_property_elements(subsection); for (const input_elem of properties_elements) { const $input_elem = $(input_elem); if ( - settings_components.check_property_changed($input_elem, for_realm_default_settings, sub) + settings_components.check_property_changed( + $input_elem, + for_realm_default_settings, + sub, + group, + ) ) { const input_value = settings_components.get_input_element_value($input_elem); if (input_value !== undefined) { let property_name; - if (for_realm_default_settings || sub) { + if (for_realm_default_settings || sub || group) { property_name = settings_components.extract_property_name( $input_elem, for_realm_default_settings, diff --git a/web/src/types.ts b/web/src/types.ts index 462b4f8ab0..36145ed66e 100644 --- a/web/src/types.ts +++ b/web/src/types.ts @@ -159,6 +159,7 @@ export type UserGroupUpdateEvent = { data: { name?: string; description?: string; + can_mention_group?: number; }; }; diff --git a/web/src/user_group_components.js b/web/src/user_group_components.js new file mode 100644 index 0000000000..8c99dba768 --- /dev/null +++ b/web/src/user_group_components.js @@ -0,0 +1,55 @@ +import $ from "jquery"; + +import * as dropdown_widget from "./dropdown_widget"; +import * as settings_components from "./settings_components"; +import * as user_groups from "./user_groups"; + +export function setup_permissions_dropdown(group, for_group_creation) { + let widget_name; + let default_id; + if (for_group_creation) { + widget_name = "new_group_can_mention_group"; + default_id = user_groups.get_user_group_from_name("role:everyone").id; + } else { + widget_name = "can_mention_group"; + default_id = group.can_mention_group; + } + + const can_mention_group_widget = new dropdown_widget.DropdownWidget({ + widget_name, + get_options: () => + user_groups.get_realm_user_groups_for_dropdown_list_widget( + "can_mention_group", + "group", + ), + item_click_callback(event, dropdown) { + dropdown.hide(); + event.preventDefault(); + event.stopPropagation(); + can_mention_group_widget.render(); + if (!for_group_creation) { + settings_components.save_discard_widget_status_handler( + $("#group_permission_settings"), + false, + undefined, + group, + ); + } + }, + $events_container: $("#groups_overlay .group-permissions"), + tippy_props: { + placement: "bottom-start", + }, + default_id, + unique_id_type: dropdown_widget.DATA_TYPES.NUMBER, + on_mount_callback(dropdown) { + $(dropdown.popper).css("min-width", "300px"); + }, + }); + if (for_group_creation) { + settings_components.set_new_group_can_mention_group_widget(can_mention_group_widget); + } else { + settings_components.set_can_mention_group_widget(can_mention_group_widget); + } + can_mention_group_widget.setup(); +} diff --git a/web/src/user_group_create.js b/web/src/user_group_create.js index 0d8e9e9081..9529488428 100644 --- a/web/src/user_group_create.js +++ b/web/src/user_group_create.js @@ -4,7 +4,9 @@ import * as channel from "./channel"; import {$t, $t_html} from "./i18n"; import * as keydown_util from "./keydown_util"; import * as loading from "./loading"; +import * as settings_components from "./settings_components"; import * as ui_report from "./ui_report"; +import * as user_group_components from "./user_group_components"; import * as user_group_create_members from "./user_group_create_members"; import * as user_group_create_members_data from "./user_group_create_members_data"; import * as user_groups from "./user_groups"; @@ -122,6 +124,10 @@ function create_user_group() { const user_ids = user_group_create_members.get_principals(); data.members = JSON.stringify(user_ids); + data.can_mention_group = Number.parseInt( + settings_components.new_group_can_mention_group_widget.value(), + 10, + ); loading.make_indicator($("#user_group_creating_indicator"), { text: $t({defaultMessage: "Creating group..."}), }); @@ -192,4 +198,6 @@ export function set_up_handlers() { e.preventDefault(); } }); + + user_group_components.setup_permissions_dropdown(undefined, true); } diff --git a/web/src/user_group_edit.js b/web/src/user_group_edit.js index 419705c06a..863c88ebb8 100644 --- a/web/src/user_group_edit.js +++ b/web/src/user_group_edit.js @@ -20,9 +20,12 @@ import * as overlays from "./overlays"; import {page_params} from "./page_params"; import * as people from "./people"; import * as scroll_util from "./scroll_util"; +import * as settings_components from "./settings_components"; import * as settings_data from "./settings_data"; +import * as settings_org from "./settings_org"; import * as stream_ui_updates from "./stream_ui_updates"; import * as ui_report from "./ui_report"; +import * as user_group_components from "./user_group_components"; import * as user_group_create from "./user_group_create"; import * as user_group_edit_members from "./user_group_edit_members"; import * as user_groups from "./user_groups"; @@ -241,6 +244,13 @@ export function update_settings_pane(group) { const $edit_container = get_edit_container(group); $edit_container.find(".group-name").text(group.name); $edit_container.find(".group-description").text(group.description); + + settings_org.discard_property_element_changes( + $("#id_can_mention_group"), + false, + undefined, + group, + ); } function update_toggler_for_group_setting() { @@ -267,6 +277,9 @@ export function show_settings_for(group) { $edit_container.show(); show_membership_settings(group); + user_group_components.setup_permissions_dropdown(group, false); + + $edit_container.find("button").prop("disabled", !settings_data.can_edit_user_group(group.id)); } export function setup_group_settings(group) { @@ -879,6 +892,48 @@ export function initialize() { const $group_row = row_for_group_id(user_group_id); add_or_remove_from_group(user_group, $group_row); }); + + $("#groups_overlay_container").on( + "click", + ".subsection-header .subsection-changes-save button", + (e) => { + e.preventDefault(); + e.stopPropagation(); + const $save_button = $(e.currentTarget); + const $subsection_elem = $save_button.closest(".settings-subsection-parent"); + + const group_id = $save_button.closest(".user_group_settings_wrapper").data("group-id"); + const group = user_groups.get_user_group_from_id(group_id); + const data = settings_org.populate_data_for_request( + $subsection_elem, + false, + undefined, + group, + ); + + const url = "/json/user_groups/" + group_id; + settings_org.save_organization_settings(data, $save_button, url); + }, + ); + + $("#groups_overlay_container").on( + "click", + ".subsection-header .subsection-changes-discard button", + (e) => { + e.preventDefault(); + e.stopPropagation(); + + const group_id = $(e.target).closest(".user_group_settings_wrapper").data("group-id"); + const group = user_groups.get_user_group_from_id(group_id); + + const $subsection = $(e.target).closest(".settings-subsection-parent"); + for (const elem of settings_components.get_subsection_property_elements($subsection)) { + settings_org.discard_property_element_changes(elem, false, undefined, group); + } + const $save_btn_controls = $(e.target).closest(".save-button-controls"); + settings_components.change_save_button_state($save_btn_controls, "discarded"); + }, + ); } export function launch(section) { diff --git a/web/src/user_groups.ts b/web/src/user_groups.ts index 84f7e6e461..1c3e8c3e97 100644 --- a/web/src/user_groups.ts +++ b/web/src/user_groups.ts @@ -78,6 +78,12 @@ export function update(event: UserGroupUpdateEvent): void { user_group_name_dict.delete(group.name); user_group_name_dict.set(group.name, group); } + + if (event.data.can_mention_group !== undefined) { + group.can_mention_group = event.data.can_mention_group; + user_group_name_dict.delete(group.name); + user_group_name_dict.set(group.name, group); + } } export function get_user_group_from_name(name: string): UserGroup | undefined { diff --git a/web/styles/app_components.css b/web/styles/app_components.css index 9c9782dfb2..e1960f86a0 100644 --- a/web/styles/app_components.css +++ b/web/styles/app_components.css @@ -835,7 +835,8 @@ div.overlay { } #stream_settings .save-button-controls, -#settings_page .save-button-controls { +#settings_page .save-button-controls, +#user_group_settings .save-button-controls { display: inline; margin-left: 15px; diff --git a/web/styles/subscriptions.css b/web/styles/subscriptions.css index a0d7711992..36839598f2 100644 --- a/web/styles/subscriptions.css +++ b/web/styles/subscriptions.css @@ -1008,7 +1008,8 @@ div.settings-radio-input-parent { } .stream-permissions, -.stream-creation-body { +.stream-creation-body, +.group-permissions { .input-group { margin-bottom: 10px; diff --git a/web/templates/user_group_settings/group_permissions.hbs b/web/templates/user_group_settings/group_permissions.hbs new file mode 100644 index 0000000000..e9c47ef464 --- /dev/null +++ b/web/templates/user_group_settings/group_permissions.hbs @@ -0,0 +1,4 @@ +{{> ../dropdown_widget_with_label + widget_name=can_mention_group_widget_name + label=(t 'Who can mention this group?') + value_type="number"}} diff --git a/web/templates/user_group_settings/user_group_creation_form.hbs b/web/templates/user_group_settings/user_group_creation_form.hbs index c838de2f7c..aabba6a87a 100644 --- a/web/templates/user_group_settings/user_group_creation_form.hbs +++ b/web/templates/user_group_settings/user_group_creation_form.hbs @@ -20,6 +20,16 @@ +
+
+
+

{{t "Group permissions" }} +

+
+ + {{> group_permissions can_mention_group_widget_name="new_group_can_mention_group"}} +
+