user_settings: Add option to disable escape key navigation to default view.

Add `escape_navigates_to_default_view` as a bool setting in
UserBaseSettings model and implement it as a checkbox that toggles
the hotkey implementation of escape to the default view in the
advanced user display settings.

With /help/ documentation edits from Alya Abbott.

Fixes #20043.
This commit is contained in:
Lauryn Menard 2021-10-25 19:17:19 +02:00 committed by Tim Abbott
parent 8b2db48da5
commit 73710e1cf0
23 changed files with 210 additions and 49 deletions

View File

@ -667,6 +667,16 @@ run_test("user_settings", ({override}) => {
dispatch(event);
assert_same(user_settings.left_side_userlist, true);
event = event_fixtures.user_settings__escape_navigates_to_default_view;
user_settings.escape_navigates_to_default_view = false;
let toggled = [];
$("#go-to-default-view-hotkey-help").toggleClass = (cls) => {
toggled.push(cls);
};
dispatch(event);
assert_same(user_settings.escape_navigates_to_default_view, true);
assert_same(toggled, ["notdisplayed"]);
// We alias message_list.narrowed to message_lists.current
// to make sure we get line coverage on re-rendering
// the current message list. The actual code tests
@ -694,7 +704,7 @@ run_test("user_settings", ({override}) => {
event = event_fixtures.user_settings__high_contrast_mode;
user_settings.high_contrast_mode = false;
let toggled = [];
toggled = [];
$("body").toggleClass = (cls) => {
toggled.push(cls);
};

View File

@ -797,6 +797,13 @@ exports.fixtures = {
value: true,
},
user_settings__escape_navigates_to_default_view: {
type: "user_settings",
op: "update",
property: "escape_navigates_to_default_view",
value: true,
},
user_settings__fluid_layout_width: {
type: "user_settings",
op: "update",

View File

@ -40,6 +40,7 @@ import * as stream_popover from "./stream_popover";
import * as stream_settings_ui from "./stream_settings_ui";
import * as topic_zoom from "./topic_zoom";
import * as ui from "./ui";
import {user_settings} from "./user_settings";
function do_narrow_action(action) {
action(message_lists.current.selected_id(), {trigger: "hotkey"});
@ -329,10 +330,16 @@ export function process_escape_key(e) {
return true;
}
/* The Ctrl+[ hotkey navigates to the default view
* unconditionally; Esc's behavior depends on a setting. */
if (user_settings.escape_navigates_to_default_view || e.which === 219) {
hashchange.set_hash_to_default_view();
return true;
}
return false;
}
function handle_popover_events(event_name) {
if (popovers.actions_popped()) {
popovers.actions_menu_handle_keyboard(event_name);

View File

@ -13,6 +13,7 @@ import * as markdown from "./markdown";
import * as overlays from "./overlays";
import * as rendered_markdown from "./rendered_markdown";
import * as ui from "./ui";
import {user_settings} from "./user_settings";
import * as util from "./util";
// Make it explicit that our toggler is undefined until
@ -210,6 +211,10 @@ export function set_up_toggler() {
$(".informational-overlays .overlay-tabs").append(elem);
$("#go-to-default-view-hotkey-help").toggleClass(
"notdisplayed",
!user_settings.escape_navigates_to_default_view,
);
common.adjust_mac_shortcuts(".hotkeys_table .hotkey kbd");
common.adjust_mac_shortcuts("#markdown-instructions kbd");
}

View File

@ -21,6 +21,7 @@ export type RealmDefaultSettingsType = {
enable_stream_email_notifications: boolean;
enable_stream_push_notifications: boolean;
enter_sends: boolean;
escape_navigates_to_default_view: boolean;
fluid_layout_width: boolean;
high_contrast_mode: boolean;
left_side_userlist: boolean;

View File

@ -576,6 +576,7 @@ export function dispatch_normal_event(event) {
"demote_inactive_streams",
"dense_mode",
"emojiset",
"escape_navigates_to_default_view",
"fluid_layout_width",
"high_contrast_mode",
"left_side_userlist",
@ -673,6 +674,10 @@ export function dispatch_normal_event(event) {
$("#user_presence_enabled").prop("checked", user_settings.presence_enabled);
break;
}
if (event.property === "escape_navigates_to_default_view") {
$("#go-to-default-view-hotkey-help").toggleClass("notdisplayed", !event.value);
break;
}
settings_display.update_page(settings_display.user_settings_panel);
break;
}

View File

@ -434,6 +434,7 @@ export const display_settings_labels = {
defaultMessage: "Convert emoticons before sending (<code>:)</code> becomes 😃)",
}),
),
escape_navigates_to_default_view: $t({defaultMessage: "Escape key navigates to default view"}),
};
export const notification_settings_labels = {

View File

@ -47,16 +47,14 @@ export function set_up(settings_panel) {
container.find(".advanced-settings-status").hide();
// Select current values for enum/select type fields. For boolean
// fields, the current value is set automatically in the template.
container.find(".setting_demote_inactive_streams").val(settings_object.demote_inactive_streams);
container.find(".setting_color_scheme").val(settings_object.color_scheme);
container.find(".setting_default_view").val(settings_object.default_view);
container
.find(".setting_twenty_four_hour_time")
.val(JSON.stringify(settings_object.twenty_four_hour_time));
container
.find(`.setting_emojiset_choice[value="${CSS.escape(settings_object.emojiset)}"]`)
.prop("checked", true);
@ -186,9 +184,15 @@ export function update_page(settings_panel) {
const container = $(settings_panel.container);
const settings_object = settings_panel.settings_object;
// Boolean fields
container.find(".left_side_userlist").prop("checked", settings_object.left_side_userlist);
container.find(".default_language_name").text(default_language_name);
container.find(".translate_emoticons").prop("checked", settings_object.translate_emoticons);
container
.find(".escape_navigates_to_default_view")
.prop("checked", settings_object.escape_navigates_to_default_view);
// Enum/select fields
container.find(".default_language_name").text(default_language_name);
container
.find(".setting_twenty_four_hour_time")
.val(JSON.stringify(settings_object.twenty_four_hour_time));

View File

@ -21,6 +21,7 @@ export type UserSettingsType = {
enable_stream_email_notifications: boolean;
enable_stream_push_notifications: boolean;
enter_sends: boolean;
escape_navigates_to_default_view: boolean;
fluid_layout_width: boolean;
high_contrast_mode: boolean;
left_side_userlist: boolean;

View File

@ -430,8 +430,10 @@ td .button {
}
.input-group {
.thinner {
margin: 10px 0;
/* Class to use when the following input-group is related and should
appear just after this element. */
&.thinner {
margin: 0;
}
label.checkbox + label {

View File

@ -54,7 +54,7 @@
</tr>
<tr>
<td class="definition">{{t 'Go to default view' }}</td>
<td><span class="hotkey"><kbd>Esc</kbd> or <kbd>Ctrl</kbd> + <kbd>[</kbd></span></td>
<td><span class="hotkey"><kbd>Ctrl</kbd> + <kbd>[</kbd><span id="go-to-default-view-hotkey-help"> or <kbd>Esc</kbd></span></span></td>
</tr>
</table>
</div>

View File

@ -80,15 +80,21 @@
{{> settings_save_discard_widget section_name="advanced-settings" show_only_indicator=(not for_realm_settings) }}
</div>
<div class="input-group inline-block">
<div class="input-group thinner setting-next-is-related">
<label for="default_view" class="dropdown-title">{{t "Default view" }}
{{> ../help_link_widget link="/help/change-default-view" }}
{{> ../help_link_widget link="/help/configure-default-view" }}
</label>
<select name="default_view" class="setting_default_view prop-element" data-setting-widget-type="string">
{{> dropdown_options_widget option_values=default_view_values}}
</select>
</div>
{{> settings_checkbox
setting_name="escape_navigates_to_default_view"
is_checked=settings_object.escape_navigates_to_default_view
label=settings_label.escape_navigates_to_default_view
prefix=prefix}}
<div class="input-group">
<label for="demote_inactive_streams" class="dropdown-title">{{t "Demote inactive streams" }}
{{> ../help_link_widget link="/help/manage-inactive-streams" }}

View File

@ -11,6 +11,13 @@ below features are supported.
## Changes in Zulip 5.0
**Feature level 107**
* [`POST /register`](/api/register-queue), [`PATCH /settings`](/api/update-settings),
[`PATCH /realm/user_settings_defaults`](/api/update-realm-user-settings-defaults):
Added user setting `escape_navigates_to_default_view` to allow users to
[disable the keyboard shortcut](/help/configure-default-view) for the `Esc` key that
navigates the app to the default view.
**Feature level 106**
* [`PATCH /user/{user_id}`](/api/update-user): Removed unnecessary JSON-encoding of string
@ -503,7 +510,7 @@ field with an integer field `invite_to_realm_policy`.
**Feature level 42**
* `PATCH /settings/display`: Added a new `default_view` setting allowing
the user to [set the default view](/help/change-default-view).
the user to [set the default view](/help/configure-default-view).
**Feature level 41**

View File

@ -1,26 +0,0 @@
# Change default view
The default view in Zulip (i.e. what view you reach after logging in
to the Zulip web app or hitting the `Esc` keyboard shortcut repeatedly)
can be configured. By default, **Recent topics** is the default view;
the previous default, **All messages**, is also supported.
[Contact us](/help/contact-support) if you'd like to be able to
configure a different view as the default.
### Change default view
{start_tabs}
{settings_tab|display-settings}
2. Under **Advanced**, click on the **Default view** dropdown.
3. Select a view.
4. Open a new Zulip tab or press `Esc` twice (first to exit the
settings overlay, and again to return to the default view) to see
your changes in action.
{end_tabs}

View File

@ -0,0 +1,68 @@
# Configure default view
The default view in Zulip is the view you reach after logging in
to the Zulip web app. You can also navigate to the default view via
keyboard shortcuts.
The default views available in Zulip are
[Recent topics](/help/recent-topics) and
[All messages](/help/reading-strategies#all-messages). See
[Reading strategies](/help/reading-strategies) for recommendations
on how to use these views.
You can configure which view is set as your default, and whether
the `Esc` key navigates to the default view. Also, you can always reach
the default view by using the `Ctrl + [` shortcut.
## Change default view
Organization administrators can [set the default view for their
organization](/help/configure-default-new-user-settings) to
[**Recent topics**](/help/recent-topics) or
[**All messages**](/help/reading-strategies#all-messages).
**Recent topics** is especially recommended for high-traffic
organizations, and is configured by default.
You can customize your personal default view regardless of
organization settings:
{start_tabs}
{settings_tab|display-settings}
2. Under **Advanced**, click on the **Default view** dropdown
and select a view.
1. To see your changes in action, open a new Zulip tab, or use a keyboard
shortcut twice to exit the settings and navigate to your default view
(`Ctrl + [` or `Esc` if enabled).
[configure-esc]: /help/configure-default-view#set-whether-esc-navigates-to-the-default-view
{end_tabs}
## Set whether `Esc` navigates to the default view
Zulip has a number of [keyboard shortcuts](/help/keyboard-shortcuts)
designed to enhance the user experience in the app.
By default, the `Esc` key shortcut will ultimately navigate to your
default view. You can disable this keybinding if you would prefer.
This will not disable other `Esc` key shortcuts used in Zulip,
and will not affect the behavior of the `Ctrl+[` shortcut.
### Toggle whether `Esc` navigates to the default view
{start_tabs}
{settings_tab|display-settings}
1. Under **Advanced**, check or uncheck **Escape key navigates to
default view**, as desired.
{end_tabs}
## Related articles
* [Reading strategies](/help/reading-strategies)
* [Recent topics](/help/recent-topics)
* [Keyboard shortcuts](/help/keyboard-shortcuts)

View File

@ -46,10 +46,10 @@
* [Review your settings](/help/review-your-settings)
* [Night mode](/help/night-mode)
* [Change your language](/help/change-your-language)
* [Change default view](/help/change-default-view)
* [Change your timezone](/help/change-your-timezone)
* [Use 24-hour time](/help/change-the-time-format)
* [Enable emoticon translations](/help/enable-emoticon-translations)
* [Configure default view](/help/configure-default-view)
* [Enable full width display](/help/enable-full-width-display)
* [Display the buddy list on narrow screens](/help/move-the-users-list-to-the-left-sidebar)
* [Manage your uploaded files](/help/manage-your-uploaded-files)

View File

@ -41,9 +41,11 @@ below, and add more to your repertoire as needed.
* **Toggle keyboard shortcuts view**: `?`
* **Go to default view**: Press `Esc` or `Ctrl + [` until you are in
the [default view](/help/change-default-view).
* **Go to default view**: Press `Ctrl + [` (or `Esc`,
[if enabled][disable-escape])
until you are in the [default view](/help/configure-default-view).
[disable-escape]: /help/configure-default-view#set-whether-esc-navigates-to-the-default-view
## Navigation
* **Search messages**: `/` or `Ctrl+k`

View File

@ -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 = 106
API_FEATURE_LEVEL = 107
# 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

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.8 on 2021-10-25 12:12
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("zerver", "0368_alter_realmfilter_url_format_string"),
]
operations = [
migrations.AddField(
model_name="realmuserdefault",
name="escape_navigates_to_default_view",
field=models.BooleanField(default=True),
),
migrations.AddField(
model_name="userprofile",
name="escape_navigates_to_default_view",
field=models.BooleanField(default=True),
),
]

View File

@ -1379,6 +1379,7 @@ class UserBaseSettings(models.Model):
# This setting controls which view is rendered first when Zulip loads.
# Values for it are URL suffix after `#`.
default_view: str = models.TextField(default="recent_topics")
escape_navigates_to_default_view: bool = models.BooleanField(default=True)
dense_mode: bool = models.BooleanField(default=True)
fluid_layout_width: bool = models.BooleanField(default=False)
high_contrast_mode: bool = models.BooleanField(default=False)
@ -1522,6 +1523,7 @@ class UserBaseSettings(models.Model):
send_stream_typing_notifications=bool,
send_private_typing_notifications=bool,
send_read_receipts=bool,
escape_navigates_to_default_view=bool,
),
}

View File

@ -7715,7 +7715,7 @@ paths:
- name: default_view
in: query
description: |
The [default view](/help/change-default-view) used when opening a new
The [default view](/help/configure-default-view) used when opening a new
Zulip web app window or hitting the `Esc` keyboard shortcut repeatedly.
- "recent_topics" - Recent topics view
@ -7723,6 +7723,16 @@ paths:
schema:
type: string
example: all_messages
- name: escape_navigates_to_default_view
in: query
description: |
Whether the escape key navigates to the
[configured default view](/help/configure-default-view).
**Changes**: New in Zulip 5.0 (feature level 107).
schema:
type: boolean
example: true
- name: left_side_userlist
in: query
description: |
@ -9629,11 +9639,18 @@ paths:
default_view:
type: string
description: |
The [default view](/help/change-default-view) used when opening a new
The [default view](/help/configure-default-view) used when opening a new
Zulip web app window or hitting the `Esc` keyboard shortcut repeatedly.
- "recent_topics" - Recent topics view
- "all_messages" - All messages view
escape_navigates_to_default_view:
type: boolean
description: |
Whether the escape key navigates to the
[configured default view](/help/configure-default-view).
**Changes**: New in Zulip 5.0 (feature level 107).
left_side_userlist:
type: boolean
description: |
@ -10290,7 +10307,7 @@ paths:
and only for clients that did not include `user_settings_object` in
their client_capabilities` when registering the event queue.
The [default view](/help/change-default-view) in Zulip, represented
The [default view](/help/configure-default-view) in Zulip, represented
as the URL suffix after `#` to be rendered when Zulip loads.
Currently supported values are `all_messages` and `recent_topics`.
@ -11315,11 +11332,18 @@ paths:
default_view:
type: string
description: |
The [default view](/help/change-default-view) used when opening a new
The [default view](/help/configure-default-view) used when opening a new
Zulip web app window or hitting the `Esc` keyboard shortcut repeatedly.
- "recent_topics" - Recent topics view
- "all_messages" - All messages view
escape_navigates_to_default_view:
type: boolean
description: |
Whether the escape key navigates to the
[configured default view](/help/configure-default-view).
**Changes**: New in Zulip 5.0 (feature level 107).
left_side_userlist:
type: boolean
description: |
@ -12244,7 +12268,7 @@ paths:
- name: default_view
in: query
description: |
The [default view](/help/change-default-view) used when opening a new
The [default view](/help/configure-default-view) used when opening a new
Zulip web app window or hitting the `Esc` keyboard shortcut repeatedly.
- "recent_topics" - Recent topics view
@ -12257,6 +12281,16 @@ paths:
schema:
type: string
example: all_messages
- name: escape_navigates_to_default_view
in: query
description: |
Whether the escape key navigates to the
[configured default view](/help/configure-default-view).
**Changes**: New in Zulip 5.0 (feature level 107).
schema:
type: boolean
example: true
- name: left_side_userlist
in: query
description: |

View File

@ -343,6 +343,7 @@ def update_realm_user_settings_defaults(
default_view: Optional[str] = REQ(
str_validator=check_string_in(default_view_options), default=None
),
escape_navigates_to_default_view: Optional[bool] = REQ(json_validator=check_bool, default=None),
left_side_userlist: Optional[bool] = REQ(json_validator=check_bool, default=None),
emojiset: Optional[str] = REQ(str_validator=check_string_in(emojiset_choices), default=None),
demote_inactive_streams: Optional[int] = REQ(

View File

@ -141,6 +141,7 @@ def json_change_settings(
default_view: Optional[str] = REQ(
str_validator=check_string_in(default_view_options), default=None
),
escape_navigates_to_default_view: Optional[bool] = REQ(json_validator=check_bool, default=None),
left_side_userlist: Optional[bool] = REQ(json_validator=check_bool, default=None),
emojiset: Optional[str] = REQ(str_validator=check_string_in(emojiset_choices), default=None),
demote_inactive_streams: Optional[int] = REQ(