mirror of https://github.com/zulip/zulip.git
user_settings: Add user setting to control the user list style.
Added a user_list_style personal user setting to the bottom of Settings > Display settings > Theme section which controls the look of the right sidebar user list. The radio button UI includes a preview of what the styles look like. The setting is intended to eventually have 3 possible values: COMPACT, WITH_STATUS and WITH_AVATAR; the final value is not yet implemented. Co-authored-by: Tim Abbott <tabbott@zulip.com>
This commit is contained in:
parent
5f626428de
commit
4dad9fa158
|
@ -376,6 +376,7 @@ test("handlers", ({override, mock_template}) => {
|
|||
test("first/prev/next", ({override, mock_template}) => {
|
||||
let rendered_alice;
|
||||
let rendered_fred;
|
||||
user_settings.user_list_style = 2;
|
||||
|
||||
mock_template("presence_row.hbs", false, (data) => {
|
||||
switch (data.user_id) {
|
||||
|
@ -392,6 +393,12 @@ test("first/prev/next", ({override, mock_template}) => {
|
|||
user_circle_status: "translated: Active",
|
||||
user_id: alice.user_id,
|
||||
status_emoji_info: undefined,
|
||||
status_text: undefined,
|
||||
user_list_style: {
|
||||
COMPACT: false,
|
||||
WITH_STATUS: true,
|
||||
WITH_AVATAR: false,
|
||||
},
|
||||
});
|
||||
break;
|
||||
case fred.user_id:
|
||||
|
@ -407,6 +414,12 @@ test("first/prev/next", ({override, mock_template}) => {
|
|||
user_circle_status: "translated: Active",
|
||||
faded: false,
|
||||
status_emoji_info: undefined,
|
||||
status_text: undefined,
|
||||
user_list_style: {
|
||||
COMPACT: false,
|
||||
WITH_STATUS: true,
|
||||
WITH_AVATAR: false,
|
||||
},
|
||||
});
|
||||
break;
|
||||
/* istanbul ignore next */
|
||||
|
@ -438,6 +451,7 @@ test("first/prev/next", ({override, mock_template}) => {
|
|||
});
|
||||
|
||||
test("insert_one_user_into_empty_list", ({override, mock_template}) => {
|
||||
user_settings.user_list_style = 2;
|
||||
mock_template("presence_row.hbs", true, (data, html) => {
|
||||
assert.deepEqual(data, {
|
||||
href: "#narrow/pm-with/1-alice",
|
||||
|
@ -450,6 +464,12 @@ test("insert_one_user_into_empty_list", ({override, mock_template}) => {
|
|||
user_circle_status: "translated: Active",
|
||||
faded: true,
|
||||
status_emoji_info: undefined,
|
||||
status_text: undefined,
|
||||
user_list_style: {
|
||||
COMPACT: false,
|
||||
WITH_STATUS: true,
|
||||
WITH_AVATAR: false,
|
||||
},
|
||||
});
|
||||
assert.ok(html.startsWith("<li data-user-id="));
|
||||
return html;
|
||||
|
|
|
@ -509,6 +509,7 @@ test("get_items_for_users", () => {
|
|||
people.add_active_user(fred);
|
||||
user_status.set_away(alice.user_id);
|
||||
user_settings.emojiset = "google";
|
||||
user_settings.user_list_style = 2;
|
||||
const status_emoji_info = {
|
||||
emoji_alt_code: false,
|
||||
emoji_name: "car",
|
||||
|
@ -521,6 +522,12 @@ test("get_items_for_users", () => {
|
|||
user_status.set_status_emoji({user_id, ...status_emoji_info});
|
||||
}
|
||||
|
||||
const user_list_style = {
|
||||
COMPACT: false,
|
||||
WITH_STATUS: true,
|
||||
WITH_AVATAR: false,
|
||||
};
|
||||
|
||||
assert.deepEqual(buddy_data.get_items_for_users(user_ids), [
|
||||
{
|
||||
faded: false,
|
||||
|
@ -530,9 +537,11 @@ test("get_items_for_users", () => {
|
|||
name: "Human Myself",
|
||||
num_unread: 0,
|
||||
status_emoji_info,
|
||||
status_text: undefined,
|
||||
user_circle_class: "user_circle_green",
|
||||
user_circle_status: "translated: Active",
|
||||
user_id: 1001,
|
||||
user_list_style,
|
||||
},
|
||||
{
|
||||
faded: false,
|
||||
|
@ -542,9 +551,11 @@ test("get_items_for_users", () => {
|
|||
name: "Alice Smith",
|
||||
num_unread: 0,
|
||||
status_emoji_info,
|
||||
status_text: undefined,
|
||||
user_circle_class: "user_circle_empty_line",
|
||||
user_circle_status: "translated: Unavailable",
|
||||
user_id: 1002,
|
||||
user_list_style,
|
||||
},
|
||||
{
|
||||
faded: false,
|
||||
|
@ -554,9 +565,11 @@ test("get_items_for_users", () => {
|
|||
name: "Fred Flintstone",
|
||||
num_unread: 0,
|
||||
status_emoji_info,
|
||||
status_text: undefined,
|
||||
user_circle_class: "user_circle_empty",
|
||||
user_circle_status: "translated: Offline",
|
||||
user_id: 1003,
|
||||
user_list_style,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
|
|
@ -885,6 +885,17 @@ run_test("user_settings", ({override}) => {
|
|||
assert_same(user_settings.demote_inactive_streams, 2);
|
||||
}
|
||||
|
||||
{
|
||||
const stub = make_stub();
|
||||
event = event_fixtures.user_settings__user_list_style;
|
||||
override(settings_display, "report_user_list_style_change", stub.f);
|
||||
user_settings.user_list_style = 1;
|
||||
override(activity, "build_user_sidebar", stub.f);
|
||||
dispatch(event);
|
||||
assert.equal(stub.num_calls, 2);
|
||||
assert_same(user_settings.user_list_style, 2);
|
||||
}
|
||||
|
||||
event = event_fixtures.user_settings__enter_sends;
|
||||
user_settings.enter_sends = false;
|
||||
dispatch(event);
|
||||
|
|
|
@ -915,6 +915,13 @@ exports.fixtures = {
|
|||
value: true,
|
||||
},
|
||||
|
||||
user_settings__user_list_style: {
|
||||
type: "user_settings",
|
||||
op: "update",
|
||||
property: "user_list_style",
|
||||
value: 2,
|
||||
},
|
||||
|
||||
user_status__revoke_away: {
|
||||
type: "user_status",
|
||||
user_id: 63,
|
||||
|
|
|
@ -89,6 +89,7 @@ function get_realm_level_notification_settings(options) {
|
|||
export function build_page() {
|
||||
const options = {
|
||||
custom_profile_field_types: page_params.custom_profile_field_types,
|
||||
full_name: page_params.full_name,
|
||||
realm_name: page_params.realm_name,
|
||||
realm_org_type: page_params.realm_org_type,
|
||||
realm_available_video_chat_providers: page_params.realm_available_video_chat_providers,
|
||||
|
@ -158,6 +159,7 @@ export function build_page() {
|
|||
settings_config.common_message_policy_values.by_admins_only.code,
|
||||
...settings_org.get_organization_settings_options(),
|
||||
demote_inactive_streams_values: settings_config.demote_inactive_streams_values,
|
||||
user_list_style_values: settings_config.user_list_style_values,
|
||||
color_scheme_values: settings_config.color_scheme_values,
|
||||
default_view_values: settings_config.default_view_values,
|
||||
settings_object: realm_user_settings_defaults,
|
||||
|
|
|
@ -8,6 +8,7 @@ import * as people from "./people";
|
|||
import * as presence from "./presence";
|
||||
import * as timerender from "./timerender";
|
||||
import * as unread from "./unread";
|
||||
import {user_settings} from "./user_settings";
|
||||
import * as user_status from "./user_status";
|
||||
import * as util from "./util";
|
||||
|
||||
|
@ -179,6 +180,13 @@ export function info_for(user_id) {
|
|||
|
||||
const status_emoji_info = user_status.get_status_emoji(user_id);
|
||||
const user_circle_status = status_description(user_id);
|
||||
const status_text = user_status.get_status_text(user_id);
|
||||
const user_list_style_value = user_settings.user_list_style;
|
||||
const user_list_style = {
|
||||
COMPACT: user_list_style_value === 1,
|
||||
WITH_STATUS: user_list_style_value === 2,
|
||||
WITH_AVATAR: user_list_style_value === 3,
|
||||
};
|
||||
|
||||
return {
|
||||
href: hash_util.pm_with_url(person.email),
|
||||
|
@ -190,6 +198,8 @@ export function info_for(user_id) {
|
|||
num_unread: get_num_unread(user_id),
|
||||
user_circle_class,
|
||||
user_circle_status,
|
||||
status_text,
|
||||
user_list_style,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ export type RealmDefaultSettings = {
|
|||
starred_message_counts: boolean;
|
||||
translate_emoticons: boolean;
|
||||
twenty_four_hour_time: boolean;
|
||||
user_list_style: boolean;
|
||||
wildcard_mentions_notify: boolean;
|
||||
};
|
||||
|
||||
|
|
|
@ -621,6 +621,7 @@ export function dispatch_normal_event(event) {
|
|||
"twenty_four_hour_time",
|
||||
"translate_emoticons",
|
||||
"display_emoji_reaction_users",
|
||||
"user_list_style",
|
||||
"starred_message_counts",
|
||||
"send_stream_typing_notifications",
|
||||
"send_private_typing_notifications",
|
||||
|
@ -652,6 +653,12 @@ export function dispatch_normal_event(event) {
|
|||
stream_list.update_streams_sidebar();
|
||||
stream_data.set_filter_out_inactives();
|
||||
}
|
||||
if (event.property === "user_list_style") {
|
||||
settings_display.report_user_list_style_change(
|
||||
settings_display.user_settings_panel,
|
||||
);
|
||||
activity.build_user_sidebar();
|
||||
}
|
||||
if (event.property === "dense_mode") {
|
||||
$("body").toggleClass("less_dense_mode");
|
||||
$("body").toggleClass("more_dense_mode");
|
||||
|
|
|
@ -83,6 +83,7 @@ export function build_page() {
|
|||
can_create_new_bots: settings_bots.can_create_new_bots(),
|
||||
settings_label,
|
||||
demote_inactive_streams_values: settings_config.demote_inactive_streams_values,
|
||||
user_list_style_values: settings_config.user_list_style_values,
|
||||
color_scheme_values: settings_config.color_scheme_values,
|
||||
default_view_values: settings_config.default_view_values,
|
||||
twenty_four_hour_time_values: settings_config.twenty_four_hour_time_values,
|
||||
|
|
|
@ -39,6 +39,22 @@ export const demote_inactive_streams_values = {
|
|||
},
|
||||
};
|
||||
|
||||
export const user_list_style_values = {
|
||||
compact: {
|
||||
code: 1,
|
||||
description: $t({defaultMessage: "Compact"}),
|
||||
},
|
||||
with_status: {
|
||||
code: 2,
|
||||
description: $t({defaultMessage: "Show status text"}),
|
||||
},
|
||||
// The `with_avatar` design in still in discussion.
|
||||
// with_avatar: {
|
||||
// code: 3,
|
||||
// description: $t({defaultMessage: "Show status text and avatar"}),
|
||||
// },
|
||||
};
|
||||
|
||||
export const default_view_values = {
|
||||
recent_topics: {
|
||||
code: "recent_topics",
|
||||
|
|
|
@ -166,6 +166,9 @@ export function set_up(settings_panel) {
|
|||
$container
|
||||
.find(`.setting_emojiset_choice[value="${CSS.escape(settings_object.emojiset)}"]`)
|
||||
.prop("checked", true);
|
||||
$container
|
||||
.find(`.setting_user_list_style_choice[value=${settings_object.user_list_style}]`)
|
||||
.prop("checked", true);
|
||||
|
||||
if (for_realm_settings) {
|
||||
// For the realm-level defaults page, we use the common
|
||||
|
@ -224,6 +227,29 @@ export function set_up(settings_panel) {
|
|||
},
|
||||
});
|
||||
});
|
||||
|
||||
$container.find(".setting_user_list_style_choice").on("click", function () {
|
||||
const data = {user_list_style: $(this).val()};
|
||||
const current_user_list_style = settings_object.user_list_style;
|
||||
if (current_user_list_style === data.user_list_style) {
|
||||
return;
|
||||
}
|
||||
const $spinner = $container.find(".theme-settings-status").expectOne();
|
||||
loading.make_indicator($spinner, {text: settings_ui.strings.saving});
|
||||
|
||||
channel.patch({
|
||||
url: "/json/settings",
|
||||
data,
|
||||
success() {},
|
||||
error(xhr) {
|
||||
ui_report.error(
|
||||
settings_ui.strings.failure_html,
|
||||
xhr,
|
||||
$container.find(".theme-settings-status").expectOne(),
|
||||
);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function report_emojiset_change(settings_panel) {
|
||||
|
@ -247,6 +273,25 @@ export async function report_emojiset_change(settings_panel) {
|
|||
}
|
||||
}
|
||||
|
||||
export async function report_user_list_style_change(settings_panel) {
|
||||
// TODO: Clean up how this works so we can use
|
||||
// change_display_setting. The challenge is that we don't want to
|
||||
// report success before the server_events request returns that
|
||||
// causes the actual sprite sheet to change. The current
|
||||
// implementation is wrong, though, in that it displays the UI
|
||||
// update in all active browser windows.
|
||||
const $spinner = $(settings_panel.container).find(".theme-settings-status");
|
||||
if ($spinner.length) {
|
||||
loading.destroy_indicator($spinner);
|
||||
ui_report.success(
|
||||
$t_html({defaultMessage: "User list style changed successfully!"}),
|
||||
$spinner.expectOne(),
|
||||
);
|
||||
$spinner.expectOne();
|
||||
settings_ui.display_checkmark($spinner);
|
||||
}
|
||||
}
|
||||
|
||||
export function update_page(property) {
|
||||
if (!overlays.settings_open()) {
|
||||
return;
|
||||
|
@ -262,8 +307,8 @@ export function update_page(property) {
|
|||
}
|
||||
|
||||
// settings_org.set_input_element_value doesn't support radio
|
||||
// button widgets like this one.
|
||||
if (property === "emojiset") {
|
||||
// button widgets like these.
|
||||
if (property === "emojiset" || property === "user_list_style") {
|
||||
$container.find(`input[value=${CSS.escape(value)}]`).prop("checked", true);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -244,8 +244,14 @@ function get_subsection_property_elements(element) {
|
|||
// structure, it needs custom code.
|
||||
const $color_scheme_elem = $subsection.find(".setting_color_scheme");
|
||||
const $emojiset_elem = $subsection.find("input[name='emojiset']:checked");
|
||||
const $user_list_style_elem = $subsection.find("input[name='user_list_style']:checked");
|
||||
const $translate_emoticons_elem = $subsection.find(".translate_emoticons");
|
||||
return [$color_scheme_elem, $emojiset_elem, $translate_emoticons_elem];
|
||||
return [
|
||||
$color_scheme_elem,
|
||||
$emojiset_elem,
|
||||
$user_list_style_elem,
|
||||
$translate_emoticons_elem,
|
||||
];
|
||||
}
|
||||
return Array.from($subsection.find(".prop-element"));
|
||||
}
|
||||
|
@ -533,13 +539,21 @@ function discard_property_element_changes(elem, for_realm_default_settings) {
|
|||
);
|
||||
break;
|
||||
case "emojiset":
|
||||
// Because the emojiset widget has a unique radio button
|
||||
// structure, it needs custom reset code.
|
||||
// Because this widget has a radio button structure, it
|
||||
// needs custom reset code.
|
||||
$elem
|
||||
.closest(".org-subsection-parent")
|
||||
.find(`.setting_emojiset_choice[value='${CSS.escape(property_value)}'`)
|
||||
.prop("checked", true);
|
||||
break;
|
||||
case "user_list_style":
|
||||
// Because this widget has a radio button structure, it
|
||||
// needs custom reset code.
|
||||
$elem
|
||||
.closest(".org-subsection-parent")
|
||||
.find(`.setting_user_list_style_choice[value='${CSS.escape(property_value)}'`)
|
||||
.prop("checked", true);
|
||||
break;
|
||||
case "email_notifications_batching_period_seconds":
|
||||
case "email_notification_batching_period_edit_minutes":
|
||||
settings_notifications.set_notification_batching_ui(
|
||||
|
|
|
@ -29,8 +29,8 @@ export function update_page(property) {
|
|||
let value = realm_user_settings_defaults[property];
|
||||
|
||||
// settings_org.set_input_element_value doesn't support radio
|
||||
// button widgets like this one.
|
||||
if (property === "emojiset") {
|
||||
// button widgets like these.
|
||||
if (property === "emojiset" || property === "user_list_style") {
|
||||
$container.find(`input[value=${CSS.escape(value)}]`).prop("checked", true);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ export type UserSettings = (StreamNotificationSettings & PmNotificationSettings)
|
|||
pm_content_in_desktop_notifications: boolean;
|
||||
presence_enabled: boolean;
|
||||
realm_name_in_notifications: boolean;
|
||||
user_list_style: number;
|
||||
starred_message_counts: boolean;
|
||||
translate_emoticons: boolean;
|
||||
display_emoji_reaction_users: boolean;
|
||||
|
|
|
@ -130,6 +130,24 @@
|
|||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
|
||||
.user-name-and-status-emoji {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
display: block;
|
||||
width: 170px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
opacity: 0.75;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
span.status-text:not(:empty) {
|
||||
margin-top: -3px;
|
||||
}
|
||||
|
||||
.unread_count {
|
||||
display: none;
|
||||
margin-top: 2.5px;
|
||||
|
|
|
@ -918,15 +918,10 @@ input[type="checkbox"] {
|
|||
}
|
||||
}
|
||||
|
||||
.emojiset_choices {
|
||||
width: 250px;
|
||||
.emojiset_choices,
|
||||
.user_list_style_values {
|
||||
padding: 0 10px;
|
||||
|
||||
.emoji {
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
}
|
||||
|
||||
label {
|
||||
border-bottom: 1px solid hsla(0, 0%, 0%, 0.2);
|
||||
padding: 8px 0 10px;
|
||||
|
@ -944,10 +939,56 @@ input[type="checkbox"] {
|
|||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
float: right;
|
||||
.right {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.emojiset_choices {
|
||||
width: 250px;
|
||||
|
||||
.emoji {
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
$right_sidebar_width: 170px;
|
||||
$option_title_width: 180px;
|
||||
|
||||
.user_list_style_values {
|
||||
max-width: calc($right_sidebar_width + $option_title_width);
|
||||
|
||||
.preview {
|
||||
background-color: inherit !important;
|
||||
/* Match the 170px width of the right sidebar region for the name/status,
|
||||
doing something reasonable if the window shrinks. */
|
||||
width: calc(100% - $option_title_width);
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow-x: hidden;
|
||||
overflow-y: visible;
|
||||
position: relative;
|
||||
height: 36px;
|
||||
|
||||
.user-name-and-status-text {
|
||||
margin-top: -4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
display: inline-block;
|
||||
opacity: 0.75;
|
||||
font-size: 90%;
|
||||
|
||||
&:not(:empty) {
|
||||
margin-top: -3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,8 +5,18 @@
|
|||
href="{{href}}"
|
||||
data-user-id="{{user_id}}"
|
||||
data-name="{{name}}">
|
||||
<span class="user-name">{{name}}</span>
|
||||
{{> status_emoji status_emoji_info}}
|
||||
{{#if user_list_style.WITH_STATUS}}
|
||||
<div>
|
||||
<div class="user-name-and-status-emoji">
|
||||
<span class="user-name">{{name}}</span>
|
||||
{{> status_emoji status_emoji_info}}
|
||||
</div>
|
||||
<span class="status-text">{{status_text}}</span>
|
||||
</div>
|
||||
{{else}}
|
||||
<span class="user-name">{{name}}</span>
|
||||
{{> status_emoji status_emoji_info}}
|
||||
{{/if}}
|
||||
</a>
|
||||
<span class="unread_count">{{#if num_unread}}{{num_unread}}{{/if}}</span>
|
||||
</div>
|
||||
|
|
|
@ -77,6 +77,33 @@
|
|||
label=settings_label.display_emoji_reaction_users
|
||||
prefix=prefix}}
|
||||
{{/if}}
|
||||
|
||||
<div class="input-group">
|
||||
<label class="title">{{t "User list style" }}</label>
|
||||
<div class="user_list_style_values grey-box">
|
||||
{{#each user_list_style_values}}
|
||||
<label>
|
||||
<input type="radio" class="setting_user_list_style_choice prop-element" name="user_list_style" value="{{this.code}}" data-setting-widget-type="radio-group"/>
|
||||
<span>{{this.description}}</span>
|
||||
<span class="right preview">
|
||||
{{#if (eq this.code 1)}}
|
||||
<span class="user-name">{{../full_name}}</span>
|
||||
<div class="emoji status_emoji emoji-1f3e0"></div>
|
||||
{{/if}}
|
||||
{{#if (eq this.code 2)}}
|
||||
<div class="user-name-and-status-text">
|
||||
<div class="user-name-and-status-emoji">
|
||||
<span class="user-name">{{../full_name}}</span>
|
||||
{{> ../status_emoji emoji_code="1f3e0"}}
|
||||
</div>
|
||||
<span class="status-text">{{t "Working remotely" }}</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
</span>
|
||||
</label>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="advanced-settings {{#if for_realm_settings}}org-subsection-parent{{else}}subsection-parent{{/if}}">
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
{{#*inline "z-link"}}<a href="/help/configure-default-new-user-settings" target="_blank" rel="noopener noreferrer">{{> @partial-block }}</a>{{/inline}}
|
||||
{{/tr}}
|
||||
</div>
|
||||
{{> display_settings prefix="realm_" for_realm_settings=true}}
|
||||
{{> display_settings prefix="realm_" for_realm_settings=true full_name=full_name}}
|
||||
|
||||
{{> notification_settings prefix="realm_" for_realm_settings=true}}
|
||||
|
||||
|
|
|
@ -20,6 +20,14 @@ format used by the Zulip server that they are interacting with.
|
|||
|
||||
## Changes in Zulip 6.0
|
||||
|
||||
**Feature level 141**
|
||||
|
||||
* [`POST /register`](/api/register-queue), [`PATCH
|
||||
/settings`](/api/update-settings), [`PATCH
|
||||
/realm/user_settings_defaults`](/api/update-realm-user-settings-defaults):
|
||||
Added new `user_list_style` display setting, which controls the
|
||||
layout of the right sidebar.
|
||||
|
||||
**Feature level 140**
|
||||
|
||||
* [`POST /register`](/api/register-queue): Added string field `server_emoji_data_url`
|
||||
|
|
|
@ -33,7 +33,7 @@ DESKTOP_WARNING_VERSION = "5.4.3"
|
|||
# Changes should be accompanied by documentation explaining what the
|
||||
# new level means in templates/zerver/api/changelog.md, as well as
|
||||
# "**Changes**" entries in the endpoint's documentation in `zulip.yaml`.
|
||||
API_FEATURE_LEVEL = 140
|
||||
API_FEATURE_LEVEL = 141
|
||||
|
||||
# Bump the minor PROVISION_VERSION to indicate that folks should provision
|
||||
# only when going from an old version of the code to a newer version. Bump
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 4.0.6 on 2022-08-14 18:23
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("zerver", "0406_alter_realm_message_content_edit_limit_seconds"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="realmuserdefault",
|
||||
name="user_list_style",
|
||||
field=models.PositiveSmallIntegerField(default=2),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="userprofile",
|
||||
name="user_list_style",
|
||||
field=models.PositiveSmallIntegerField(default=2),
|
||||
),
|
||||
]
|
|
@ -1523,6 +1523,17 @@ class UserBaseSettings(models.Model):
|
|||
default=GOOGLE_EMOJISET, choices=EMOJISET_CHOICES, max_length=20
|
||||
)
|
||||
|
||||
# User list style
|
||||
USER_LIST_STYLE_COMPACT = 1
|
||||
USER_LIST_STYLE_WITH_STATUS = 2
|
||||
USER_LIST_STYLE_WITH_AVATAR = 3
|
||||
USER_LIST_STYLE_CHOICES = [
|
||||
USER_LIST_STYLE_COMPACT,
|
||||
USER_LIST_STYLE_WITH_STATUS,
|
||||
USER_LIST_STYLE_WITH_AVATAR,
|
||||
]
|
||||
user_list_style: int = models.PositiveSmallIntegerField(default=USER_LIST_STYLE_WITH_STATUS)
|
||||
|
||||
### Notifications settings. ###
|
||||
|
||||
email_notifications_batching_period_seconds: int = models.IntegerField(default=120)
|
||||
|
@ -1621,6 +1632,7 @@ class UserBaseSettings(models.Model):
|
|||
send_private_typing_notifications=bool,
|
||||
send_read_receipts=bool,
|
||||
send_stream_typing_notifications=bool,
|
||||
user_list_style=int,
|
||||
)
|
||||
|
||||
modern_notification_settings: Dict[str, Any] = dict(
|
||||
|
|
|
@ -8516,6 +8516,23 @@ paths:
|
|||
- 2
|
||||
- 3
|
||||
example: 1
|
||||
- name: user_list_style
|
||||
in: query
|
||||
description: |
|
||||
The style selected by the user for the right sidebar user list.
|
||||
|
||||
- 1 - Compact
|
||||
- 2 - With status
|
||||
- 3 - With avatar and status
|
||||
|
||||
**Changes**: New in Zulip 6.0 (feature level 141).
|
||||
schema:
|
||||
type: integer
|
||||
enum:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
example: 1
|
||||
- name: enable_stream_desktop_notifications
|
||||
in: query
|
||||
description: |
|
||||
|
@ -10431,6 +10448,16 @@ paths:
|
|||
- 1 - Automatic
|
||||
- 2 - Always
|
||||
- 3 - Never
|
||||
user_list_style:
|
||||
type: integer
|
||||
description: |
|
||||
The style selected by the user for the right sidebar user list.
|
||||
|
||||
- 1 - Compact
|
||||
- 2 - With status
|
||||
- 3 - With avatar and status
|
||||
|
||||
**Changes**: New in Zulip 6.0 (feature level 141).
|
||||
timezone:
|
||||
type: string
|
||||
description: |
|
||||
|
@ -12344,6 +12371,16 @@ paths:
|
|||
- 1 - Automatic
|
||||
- 2 - Always
|
||||
- 3 - Never
|
||||
user_list_style:
|
||||
type: integer
|
||||
description: |
|
||||
The style selected by the user for the right sidebar user list.
|
||||
|
||||
- 1 - Compact
|
||||
- 2 - With status
|
||||
- 3 - With avatar and status
|
||||
|
||||
**Changes**: New in Zulip 6.0 (feature level 141).
|
||||
enable_stream_desktop_notifications:
|
||||
type: boolean
|
||||
description: |
|
||||
|
@ -13350,6 +13387,23 @@ paths:
|
|||
- 2
|
||||
- 3
|
||||
example: 1
|
||||
- name: user_list_style
|
||||
in: query
|
||||
description: |
|
||||
The style selected by the user for the right sidebar user list.
|
||||
|
||||
- 1 - Compact
|
||||
- 2 - With status
|
||||
- 3 - With avatar and status
|
||||
|
||||
**Changes**: New in Zulip 6.0 (feature level 141).
|
||||
schema:
|
||||
type: integer
|
||||
enum:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
example: 1
|
||||
- name: timezone
|
||||
in: query
|
||||
description: |
|
||||
|
|
|
@ -2583,6 +2583,7 @@ class RealmPropertyActionTest(BaseAction):
|
|||
default_view=["recent_topics", "all_messages"],
|
||||
emojiset=[emojiset["key"] for emojiset in RealmUserDefault.emojiset_choices()],
|
||||
demote_inactive_streams=UserProfile.DEMOTE_STREAMS_CHOICES,
|
||||
user_list_style=UserProfile.USER_LIST_STYLE_CHOICES,
|
||||
desktop_icon_count_display=[1, 2, 3],
|
||||
notification_sound=["zulip", "ding"],
|
||||
email_notifications_batching_period_seconds=[120, 300],
|
||||
|
@ -2656,6 +2657,7 @@ class UserDisplayActionTest(BaseAction):
|
|||
default_language=["es", "de", "en"],
|
||||
default_view=["all_messages", "recent_topics"],
|
||||
demote_inactive_streams=[2, 3, 1],
|
||||
user_list_style=[1, 2, 3],
|
||||
color_scheme=[2, 3, 1],
|
||||
)
|
||||
|
||||
|
|
|
@ -1202,6 +1202,7 @@ class RealmAPITest(ZulipTestCase):
|
|||
default_view=["recent_topics", "all_messages"],
|
||||
emojiset=[emojiset["key"] for emojiset in RealmUserDefault.emojiset_choices()],
|
||||
demote_inactive_streams=UserProfile.DEMOTE_STREAMS_CHOICES,
|
||||
user_list_style=UserProfile.USER_LIST_STYLE_CHOICES,
|
||||
desktop_icon_count_display=[1, 2, 3],
|
||||
notification_sound=["zulip", "ding"],
|
||||
email_notifications_batching_period_seconds=[120, 300],
|
||||
|
|
|
@ -357,6 +357,7 @@ class ChangeSettingsTest(ZulipTestCase):
|
|||
emojiset="google",
|
||||
timezone="America/Denver",
|
||||
demote_inactive_streams=2,
|
||||
user_list_style=2,
|
||||
color_scheme=2,
|
||||
email_notifications_batching_period_seconds=100,
|
||||
notification_sound="ding",
|
||||
|
@ -369,7 +370,7 @@ class ChangeSettingsTest(ZulipTestCase):
|
|||
if test_value is None:
|
||||
raise AssertionError(f"No test created for {setting_name}")
|
||||
|
||||
if setting_name not in ["demote_inactive_streams", "color_scheme"]:
|
||||
if setting_name not in ["demote_inactive_streams", "user_list_style", "color_scheme"]:
|
||||
data = {setting_name: test_value}
|
||||
else:
|
||||
data = {setting_name: orjson.dumps(test_value).decode()}
|
||||
|
@ -395,6 +396,7 @@ class ChangeSettingsTest(ZulipTestCase):
|
|||
emojiset="apple",
|
||||
timezone="invalid_US/Mountain",
|
||||
demote_inactive_streams=10,
|
||||
user_list_style=10,
|
||||
color_scheme=10,
|
||||
notification_sound="invalid_sound",
|
||||
desktop_icon_count_display=10,
|
||||
|
|
|
@ -440,6 +440,9 @@ def update_realm_user_settings_defaults(
|
|||
json_validator=check_bool, default=None
|
||||
),
|
||||
send_read_receipts: Optional[bool] = REQ(json_validator=check_bool, default=None),
|
||||
user_list_style: Optional[int] = REQ(
|
||||
json_validator=check_int_in(UserProfile.USER_LIST_STYLE_CHOICES), default=None
|
||||
),
|
||||
) -> HttpResponse:
|
||||
if notification_sound is not None or email_notifications_batching_period_seconds is not None:
|
||||
check_settings_values(notification_sound, email_notifications_batching_period_seconds)
|
||||
|
|
|
@ -217,6 +217,9 @@ def json_change_settings(
|
|||
),
|
||||
send_stream_typing_notifications: Optional[bool] = REQ(json_validator=check_bool, default=None),
|
||||
send_read_receipts: Optional[bool] = REQ(json_validator=check_bool, default=None),
|
||||
user_list_style: Optional[int] = REQ(
|
||||
json_validator=check_int_in(UserProfile.USER_LIST_STYLE_CHOICES), default=None
|
||||
),
|
||||
) -> HttpResponse:
|
||||
if (
|
||||
default_language is not None
|
||||
|
|
Loading…
Reference in New Issue