mirror of
https://github.com/zulip/zulip.git
synced 2025-11-09 16:37:23 +00:00
user_group: Disable leave checkmark if user isn't a direct member.
If the user is not a direct member, but a member via a subgroup, we will show the list of subgroups beloging to that group which the current user is a direct member of in a tooltip. The cursor on the checkmark will be default in this case instead of a pointer.
This commit is contained in:
committed by
Tim Abbott
parent
8a28b31be3
commit
bf73e1711d
@@ -324,6 +324,16 @@ export function handle_member_edit_event(group_id, user_ids) {
|
|||||||
item.is_member = user_groups.is_user_in_group(group_id, people.my_current_user_id());
|
item.is_member = user_groups.is_user_in_group(group_id, people.my_current_user_id());
|
||||||
item.can_join = settings_data.can_join_user_group(item.id);
|
item.can_join = settings_data.can_join_user_group(item.id);
|
||||||
item.can_leave = settings_data.can_leave_user_group(item.id);
|
item.can_leave = settings_data.can_leave_user_group(item.id);
|
||||||
|
item.is_direct_member = user_groups.is_direct_member_of(
|
||||||
|
people.my_current_user_id(),
|
||||||
|
item.id,
|
||||||
|
);
|
||||||
|
const associated_subgroups = user_groups.get_associated_subgroups(
|
||||||
|
item,
|
||||||
|
people.my_current_user_id(),
|
||||||
|
);
|
||||||
|
item.associated_subgroup_names =
|
||||||
|
user_groups.group_list_to_comma_seperated_name(associated_subgroups);
|
||||||
const html = render_browse_user_groups_list_item(item);
|
const html = render_browse_user_groups_list_item(item);
|
||||||
const $new_row = $(html);
|
const $new_row = $(html);
|
||||||
|
|
||||||
@@ -890,6 +900,16 @@ export function setup_page(callback) {
|
|||||||
get_item: ListWidget.default_get_item,
|
get_item: ListWidget.default_get_item,
|
||||||
modifier_html(item) {
|
modifier_html(item) {
|
||||||
item.is_member = user_groups.is_user_in_group(item.id, people.my_current_user_id());
|
item.is_member = user_groups.is_user_in_group(item.id, people.my_current_user_id());
|
||||||
|
item.is_direct_member = user_groups.is_direct_member_of(
|
||||||
|
people.my_current_user_id(),
|
||||||
|
item.id,
|
||||||
|
);
|
||||||
|
const associated_subgroups = user_groups.get_associated_subgroups(
|
||||||
|
item,
|
||||||
|
people.my_current_user_id(),
|
||||||
|
);
|
||||||
|
item.associated_subgroup_names =
|
||||||
|
user_groups.group_list_to_comma_seperated_name(associated_subgroups);
|
||||||
item.can_join = settings_data.can_join_user_group(item.id);
|
item.can_join = settings_data.can_join_user_group(item.id);
|
||||||
item.can_leave = settings_data.can_leave_user_group(item.id);
|
item.can_leave = settings_data.can_leave_user_group(item.id);
|
||||||
return render_browse_user_groups_list_item(item);
|
return render_browse_user_groups_list_item(item);
|
||||||
@@ -1109,7 +1129,10 @@ export function initialize() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$("#groups_overlay_container").on("click", ".join_leave_button", (e) => {
|
$("#groups_overlay_container").on("click", ".join_leave_button", (e) => {
|
||||||
if ($(e.currentTarget).hasClass("disabled")) {
|
if (
|
||||||
|
$(e.currentTarget).hasClass("disabled") ||
|
||||||
|
$(e.currentTarget).hasClass("not-direct-member")
|
||||||
|
) {
|
||||||
// We return early if user is not allowed to join or leave a group.
|
// We return early if user is not allowed to join or leave a group.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -418,6 +418,25 @@ export function is_user_in_group(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function get_associated_subgroups(user_group: UserGroup, user_id: number): UserGroup[] {
|
||||||
|
const subgroup_ids = get_recursive_subgroups(user_group)!;
|
||||||
|
if (subgroup_ids === undefined) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const subgroups = [];
|
||||||
|
for (const group_id of subgroup_ids) {
|
||||||
|
if (is_direct_member_of(user_id, group_id)) {
|
||||||
|
subgroups.push(user_group_by_id_dict.get(group_id)!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return subgroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function group_list_to_comma_seperated_name(user_groups: UserGroup[]): string {
|
||||||
|
return user_groups.map((user_group) => user_group.name).join(", ");
|
||||||
|
}
|
||||||
|
|
||||||
export function is_user_in_setting_group(
|
export function is_user_in_setting_group(
|
||||||
setting_group: GroupSettingValue,
|
setting_group: GroupSettingValue,
|
||||||
user_id: number,
|
user_id: number,
|
||||||
|
|||||||
@@ -600,6 +600,12 @@ h4.user_group_setting_subsection_title {
|
|||||||
fill: hsl(240deg 41% 50%);
|
fill: hsl(240deg 41% 50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.not-direct-member {
|
||||||
|
svg {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.disabled {
|
&.disabled {
|
||||||
&:not(.checked) svg {
|
&:not(.checked) svg {
|
||||||
fill: hsl(0deg 0% 87%);
|
fill: hsl(0deg 0% 87%);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<div class="group-row" data-group-id="{{id}}" data-group-name="{{name}}">
|
<div class="group-row" data-group-id="{{id}}" data-group-name="{{name}}">
|
||||||
{{#if is_member}}
|
{{#if is_member}}
|
||||||
<div class="check checked join_leave_button tippy-zulip-tooltip {{#unless can_leave}}disabled{{/unless}}" data-tooltip-template-id="{{#if can_leave}}leave-{{name}}-group-tooltip-template{{else}}cannot-leave-{{name}}-group-tooltip-template{{/if}}">
|
<div class="check checked join_leave_button tippy-zulip-tooltip {{#unless can_leave}}disabled{{/unless}} {{#unless is_direct_member}}not-direct-member{{/unless}}" data-tooltip-template-id="{{#if can_leave}}{{#if is_direct_member}}leave-{{name}}-group-tooltip-template{{else}}cannot-leave-{{name}}-because-of-subgroup-tooltip-template{{/if}}{{else}}cannot-leave-{{name}}-group-tooltip-template{{/if}}">
|
||||||
<template id="leave-{{name}}-group-tooltip-template">
|
<template id="leave-{{name}}-group-tooltip-template">
|
||||||
<span>
|
<span>
|
||||||
{{#tr}}
|
{{#tr}}
|
||||||
@@ -9,6 +9,14 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template id="cannot-leave-{{name}}-because-of-subgroup-tooltip-template">
|
||||||
|
<span>
|
||||||
|
{{#tr}}
|
||||||
|
You are a member of this group because you are a member of a subgroup (<b>{associated_subgroup_names}</b>).
|
||||||
|
{{/tr}}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template id="cannot-leave-{{name}}-group-tooltip-template">
|
<template id="cannot-leave-{{name}}-group-tooltip-template">
|
||||||
<span>
|
<span>
|
||||||
{{#tr}}
|
{{#tr}}
|
||||||
|
|||||||
@@ -326,6 +326,60 @@ run_test("get_recursive_group_members", () => {
|
|||||||
assert.deepEqual([...user_groups.get_recursive_group_members(test)].sort(), [3, 4, 5]);
|
assert.deepEqual([...user_groups.get_recursive_group_members(test)].sort(), [3, 4, 5]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
run_test("get_associated_subgroups", () => {
|
||||||
|
const admins = {
|
||||||
|
name: "Admins",
|
||||||
|
description: "foo",
|
||||||
|
id: 1,
|
||||||
|
members: new Set([1]),
|
||||||
|
is_system_group: false,
|
||||||
|
direct_subgroup_ids: new Set([4]),
|
||||||
|
};
|
||||||
|
const all = {
|
||||||
|
name: "Everyone",
|
||||||
|
id: 2,
|
||||||
|
members: new Set([2, 3]),
|
||||||
|
is_system_group: false,
|
||||||
|
direct_subgroup_ids: new Set([1, 3]),
|
||||||
|
};
|
||||||
|
const test = {
|
||||||
|
name: "Test",
|
||||||
|
id: 3,
|
||||||
|
members: new Set([1, 4, 5]),
|
||||||
|
is_system_group: false,
|
||||||
|
direct_subgroup_ids: new Set([2]),
|
||||||
|
};
|
||||||
|
const foo = {
|
||||||
|
name: "Foo",
|
||||||
|
id: 4,
|
||||||
|
members: new Set([6, 7]),
|
||||||
|
is_system_group: false,
|
||||||
|
direct_subgroup_ids: new Set([]),
|
||||||
|
};
|
||||||
|
|
||||||
|
const admins_group = user_groups.add(admins);
|
||||||
|
const all_group = user_groups.add(all);
|
||||||
|
user_groups.add(test);
|
||||||
|
user_groups.add(foo);
|
||||||
|
|
||||||
|
// This test setup has a state that won't appear in real data: Groups 2 and 3
|
||||||
|
// each contain the other. We test this corner case because it is a simple way
|
||||||
|
// to verify whether our algorithm correctly avoids visiting groups multiple times
|
||||||
|
// when determining recursive subgroups.
|
||||||
|
// A test case that can occur in practice and would be problematic without this
|
||||||
|
// optimization is a tree where each layer connects to every node in the next layer.
|
||||||
|
let associated_subgroups = user_groups.get_associated_subgroups(admins_group, 6);
|
||||||
|
assert.deepEqual(associated_subgroups.length, 1);
|
||||||
|
assert.equal(associated_subgroups[0].id, 4);
|
||||||
|
|
||||||
|
associated_subgroups = user_groups.get_associated_subgroups(all_group, 1);
|
||||||
|
assert.deepEqual(associated_subgroups.length, 2);
|
||||||
|
assert.deepEqual(associated_subgroups.map((group) => group.id).sort(), [1, 3]);
|
||||||
|
|
||||||
|
associated_subgroups = user_groups.get_associated_subgroups(admins, 2);
|
||||||
|
assert.deepEqual(associated_subgroups.length, 0);
|
||||||
|
});
|
||||||
|
|
||||||
run_test("is_user_in_group", () => {
|
run_test("is_user_in_group", () => {
|
||||||
const admins = {
|
const admins = {
|
||||||
name: "Admins",
|
name: "Admins",
|
||||||
|
|||||||
Reference in New Issue
Block a user