mirror of
https://github.com/zulip/zulip.git
synced 2025-10-23 16:14:02 +00:00
left_sidebar: Refactor to support user's navigation view preference.
Co-authored-by: Aditya Chaudhary <aditya.chaudhary1558@gmail.com>
This commit is contained in:
@@ -95,12 +95,12 @@ async function navigation_tests(page: Page): Promise<void> {
|
|||||||
|
|
||||||
await navigate_using_left_sidebar(page, "Verona");
|
await navigate_using_left_sidebar(page, "Verona");
|
||||||
|
|
||||||
await page.click("#left-sidebar-navigation-list .home-link");
|
await page.click("#left-sidebar-navigation-list .top_left_all_messages");
|
||||||
await page.waitForSelector("#message_view_header .zulip-icon-all-messages", {visible: true});
|
await page.waitForSelector("#message_view_header .zulip-icon-all-messages", {visible: true});
|
||||||
|
|
||||||
await navigate_to_subscriptions(page);
|
await navigate_to_subscriptions(page);
|
||||||
|
|
||||||
await page.click("#left-sidebar-navigation-list .home-link");
|
await page.click("#left-sidebar-navigation-list .top_left_all_messages");
|
||||||
await page.waitForSelector("#message_view_header .zulip-icon-all-messages", {visible: true});
|
await page.waitForSelector("#message_view_header .zulip-icon-all-messages", {visible: true});
|
||||||
|
|
||||||
await navigate_to_settings(page);
|
await navigate_to_settings(page);
|
||||||
|
@@ -61,7 +61,7 @@ async function stars_test(page: Page): Promise<void> {
|
|||||||
|
|
||||||
await toggle_test_star_message(page);
|
await toggle_test_star_message(page);
|
||||||
await page.click("#left-sidebar-navigation-list .top_left_all_messages");
|
await page.click("#left-sidebar-navigation-list .top_left_all_messages");
|
||||||
message_list_id = await common.get_current_msg_list_id(page, false);
|
message_list_id = await common.get_current_msg_list_id(page, true);
|
||||||
await page.waitForSelector(
|
await page.waitForSelector(
|
||||||
`.message-list[data-message-list-id='${message_list_id}'] .zulip-icon-star-filled`,
|
`.message-list[data-message-list-id='${message_list_id}'] .zulip-icon-star-filled`,
|
||||||
{visible: true},
|
{visible: true},
|
||||||
|
@@ -3,9 +3,11 @@ import _ from "lodash";
|
|||||||
import assert from "minimalistic-assert";
|
import assert from "minimalistic-assert";
|
||||||
|
|
||||||
import * as channel_folders from "./channel_folders.ts";
|
import * as channel_folders from "./channel_folders.ts";
|
||||||
|
import * as drafts from "./drafts.ts";
|
||||||
import type {Filter} from "./filter.ts";
|
import type {Filter} from "./filter.ts";
|
||||||
import {localstorage} from "./localstorage.ts";
|
import {localstorage} from "./localstorage.ts";
|
||||||
import * as message_reminder from "./message_reminder.ts";
|
import * as message_reminder from "./message_reminder.ts";
|
||||||
|
import * as navigation_views from "./navigation_views.ts";
|
||||||
import {page_params} from "./page_params.ts";
|
import {page_params} from "./page_params.ts";
|
||||||
import * as people from "./people.ts";
|
import * as people from "./people.ts";
|
||||||
import * as resize from "./resize.ts";
|
import * as resize from "./resize.ts";
|
||||||
@@ -371,6 +373,55 @@ export function handle_home_view_changed(new_home_view: string): void {
|
|||||||
update_dom_with_unread_counts(res, true);
|
update_dom_with_unread_counts(res, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function get_built_in_primary_condensed_views(): navigation_views.BuiltInViewMetadata[] {
|
||||||
|
function score(view: navigation_views.BuiltInViewMetadata): number {
|
||||||
|
if (view.prioritize_in_condensed_view) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Get the top 5 prioritized views.
|
||||||
|
return navigation_views
|
||||||
|
.get_built_in_views()
|
||||||
|
.sort((view1, view2) => score(view2) - score(view1))
|
||||||
|
.slice(0, 5);
|
||||||
|
// TODO: Think about filtering out scheduled message and reminders views with UI to support less than 5 views.
|
||||||
|
}
|
||||||
|
|
||||||
|
export function get_built_in_popover_condensed_views(): navigation_views.BuiltInViewMetadata[] {
|
||||||
|
const visible_condensed_views = get_built_in_primary_condensed_views();
|
||||||
|
const all_views = navigation_views.get_built_in_views();
|
||||||
|
return all_views.filter((view) => {
|
||||||
|
if (view.fragment === "scheduled") {
|
||||||
|
const scheduled_message_count = scheduled_messages.get_count();
|
||||||
|
if (scheduled_message_count === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
view.unread_count = scheduled_message_count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (view.fragment === "reminders") {
|
||||||
|
const reminders_count = message_reminder.get_count();
|
||||||
|
if (reminders_count === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
view.unread_count = reminders_count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (view.fragment === "drafts") {
|
||||||
|
view.unread_count = drafts.draft_model.getDraftCount();
|
||||||
|
}
|
||||||
|
// Remove views that are already visible.
|
||||||
|
return !visible_condensed_views.some(
|
||||||
|
(visible_view) => visible_view.fragment === view.fragment,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function get_built_in_views(): navigation_views.BuiltInViewMetadata[] {
|
||||||
|
return navigation_views.get_built_in_views();
|
||||||
|
}
|
||||||
|
|
||||||
export function initialize(): void {
|
export function initialize(): void {
|
||||||
update_reminders_row();
|
update_reminders_row();
|
||||||
update_scheduled_messages_row();
|
update_scheduled_messages_row();
|
||||||
|
@@ -3,17 +3,17 @@ import assert from "minimalistic-assert";
|
|||||||
import type * as tippy from "tippy.js";
|
import type * as tippy from "tippy.js";
|
||||||
|
|
||||||
import render_left_sidebar_all_messages_popover from "../templates/popovers/left_sidebar/left_sidebar_all_messages_popover.hbs";
|
import render_left_sidebar_all_messages_popover from "../templates/popovers/left_sidebar/left_sidebar_all_messages_popover.hbs";
|
||||||
import render_left_sidebar_condensed_views_popover from "../templates/popovers/left_sidebar/left_sidebar_condensed_views_popover.hbs";
|
|
||||||
import render_left_sidebar_drafts_popover from "../templates/popovers/left_sidebar/left_sidebar_drafts_popover.hbs";
|
import render_left_sidebar_drafts_popover from "../templates/popovers/left_sidebar/left_sidebar_drafts_popover.hbs";
|
||||||
import render_left_sidebar_inbox_popover from "../templates/popovers/left_sidebar/left_sidebar_inbox_popover.hbs";
|
import render_left_sidebar_inbox_popover from "../templates/popovers/left_sidebar/left_sidebar_inbox_popover.hbs";
|
||||||
import render_left_sidebar_recent_view_popover from "../templates/popovers/left_sidebar/left_sidebar_recent_view_popover.hbs";
|
import render_left_sidebar_recent_view_popover from "../templates/popovers/left_sidebar/left_sidebar_recent_view_popover.hbs";
|
||||||
import render_left_sidebar_starred_messages_popover from "../templates/popovers/left_sidebar/left_sidebar_starred_messages_popover.hbs";
|
import render_left_sidebar_starred_messages_popover from "../templates/popovers/left_sidebar/left_sidebar_starred_messages_popover.hbs";
|
||||||
|
import render_left_sidebar_views_popover from "../templates/popovers/left_sidebar/left_sidebar_views_popover.hbs";
|
||||||
|
|
||||||
import * as channel from "./channel.ts";
|
import * as channel from "./channel.ts";
|
||||||
import * as drafts from "./drafts.ts";
|
import * as drafts from "./drafts.ts";
|
||||||
|
import * as left_sidebar_navigation_area from "./left_sidebar_navigation_area.ts";
|
||||||
import * as popover_menus from "./popover_menus.ts";
|
import * as popover_menus from "./popover_menus.ts";
|
||||||
import * as popovers from "./popovers.ts";
|
import * as popovers from "./popovers.ts";
|
||||||
import * as scheduled_messages from "./scheduled_messages.ts";
|
|
||||||
import * as settings_config from "./settings_config.ts";
|
import * as settings_config from "./settings_config.ts";
|
||||||
import * as starred_messages from "./starred_messages.ts";
|
import * as starred_messages from "./starred_messages.ts";
|
||||||
import * as starred_messages_ui from "./starred_messages_ui.ts";
|
import * as starred_messages_ui from "./starred_messages_ui.ts";
|
||||||
@@ -286,30 +286,18 @@ export function initialize(): void {
|
|||||||
popover_menus.register_popover_menu(".left-sidebar-navigation-menu-icon", {
|
popover_menus.register_popover_menu(".left-sidebar-navigation-menu-icon", {
|
||||||
...popover_menus.left_sidebar_tippy_options,
|
...popover_menus.left_sidebar_tippy_options,
|
||||||
onShow(instance) {
|
onShow(instance) {
|
||||||
// Determine at show time whether there are scheduled messages,
|
const built_in_popover_condensed_views =
|
||||||
// so that Tippy properly calculates the height of the popover
|
left_sidebar_navigation_area.get_built_in_popover_condensed_views();
|
||||||
const scheduled_message_count = scheduled_messages.get_count();
|
|
||||||
let has_scheduled_messages = false;
|
|
||||||
if (scheduled_message_count > 0) {
|
|
||||||
has_scheduled_messages = true;
|
|
||||||
}
|
|
||||||
popovers.hide_all();
|
popovers.hide_all();
|
||||||
instance.setContent(
|
instance.setContent(
|
||||||
ui_util.parse_html(
|
ui_util.parse_html(
|
||||||
render_left_sidebar_condensed_views_popover({has_scheduled_messages}),
|
render_left_sidebar_views_popover({
|
||||||
|
views: built_in_popover_condensed_views,
|
||||||
|
}),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onMount() {
|
|
||||||
ui_util.update_unread_count_in_dom(
|
|
||||||
$(".condensed-views-popover-menu-drafts"),
|
|
||||||
drafts.draft_model.getDraftCount(),
|
|
||||||
);
|
|
||||||
ui_util.update_unread_count_in_dom(
|
|
||||||
$(".condensed-views-popover-menu-scheduled-messages"),
|
|
||||||
scheduled_messages.get_count(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
onHidden(instance) {
|
onHidden(instance) {
|
||||||
instance.destroy();
|
instance.destroy();
|
||||||
popover_menus.popover_instances.top_left_sidebar = null;
|
popover_menus.popover_instances.top_left_sidebar = null;
|
||||||
|
236
web/src/navigation_views.ts
Normal file
236
web/src/navigation_views.ts
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
import * as blueslip from "./blueslip.ts";
|
||||||
|
import {$t} from "./i18n.ts";
|
||||||
|
import type {StateData} from "./state_data.ts";
|
||||||
|
import {user_settings} from "./user_settings.ts";
|
||||||
|
|
||||||
|
export type BuiltInViewBasicMetadata = {
|
||||||
|
fragment: string;
|
||||||
|
name: string;
|
||||||
|
is_pinned: boolean;
|
||||||
|
icon: string;
|
||||||
|
css_class_suffix: string;
|
||||||
|
tooltip_template_id: string;
|
||||||
|
has_unread_count: boolean;
|
||||||
|
unread_count_type: "normal-count" | "quiet-count" | "";
|
||||||
|
supports_masked_unread: boolean;
|
||||||
|
hidden_for_spectators: boolean;
|
||||||
|
menu_icon_class: string;
|
||||||
|
menu_aria_label: string;
|
||||||
|
home_view_code: string;
|
||||||
|
prioritize_in_condensed_view: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const built_in_views_meta_data: Record<string, BuiltInViewBasicMetadata> = {
|
||||||
|
inbox: {
|
||||||
|
fragment: "inbox",
|
||||||
|
name: $t({defaultMessage: "Inbox"}),
|
||||||
|
is_pinned: true,
|
||||||
|
icon: "zulip-icon-inbox",
|
||||||
|
css_class_suffix: "inbox",
|
||||||
|
tooltip_template_id: "inbox-tooltip-template",
|
||||||
|
has_unread_count: true,
|
||||||
|
unread_count_type: "normal-count",
|
||||||
|
supports_masked_unread: true,
|
||||||
|
hidden_for_spectators: true,
|
||||||
|
menu_icon_class: "inbox-sidebar-menu-icon",
|
||||||
|
menu_aria_label: $t({defaultMessage: "Inbox options"}),
|
||||||
|
home_view_code: "inbox",
|
||||||
|
prioritize_in_condensed_view: true,
|
||||||
|
},
|
||||||
|
recent_view: {
|
||||||
|
fragment: "recent",
|
||||||
|
name: $t({defaultMessage: "Recent conversations"}),
|
||||||
|
is_pinned: true,
|
||||||
|
icon: "zulip-icon-recent",
|
||||||
|
css_class_suffix: "recent_view",
|
||||||
|
tooltip_template_id: "recent-conversations-tooltip-template",
|
||||||
|
has_unread_count: true,
|
||||||
|
unread_count_type: "normal-count",
|
||||||
|
supports_masked_unread: true,
|
||||||
|
hidden_for_spectators: false,
|
||||||
|
menu_icon_class: "recent-view-sidebar-menu-icon",
|
||||||
|
menu_aria_label: $t({defaultMessage: "Recent conversations options"}),
|
||||||
|
home_view_code: "recent_topics",
|
||||||
|
prioritize_in_condensed_view: true,
|
||||||
|
},
|
||||||
|
all_messages: {
|
||||||
|
fragment: "feed",
|
||||||
|
name: $t({defaultMessage: "Combined feed"}),
|
||||||
|
is_pinned: true,
|
||||||
|
icon: "zulip-icon-all-messages",
|
||||||
|
css_class_suffix: "all_messages",
|
||||||
|
tooltip_template_id: "all-message-tooltip-template",
|
||||||
|
has_unread_count: true,
|
||||||
|
unread_count_type: "normal-count",
|
||||||
|
supports_masked_unread: true,
|
||||||
|
hidden_for_spectators: false,
|
||||||
|
menu_icon_class: "all-messages-sidebar-menu-icon",
|
||||||
|
menu_aria_label: $t({defaultMessage: "Combined feed options"}),
|
||||||
|
home_view_code: "all_messages",
|
||||||
|
prioritize_in_condensed_view: true,
|
||||||
|
},
|
||||||
|
mentions: {
|
||||||
|
fragment: "narrow/is/mentioned",
|
||||||
|
name: $t({defaultMessage: "Mentions"}),
|
||||||
|
is_pinned: true,
|
||||||
|
icon: "zulip-icon-at-sign",
|
||||||
|
css_class_suffix: "mentions",
|
||||||
|
tooltip_template_id: "mentions-tooltip-template",
|
||||||
|
has_unread_count: true,
|
||||||
|
unread_count_type: "normal-count",
|
||||||
|
supports_masked_unread: false,
|
||||||
|
hidden_for_spectators: true,
|
||||||
|
menu_icon_class: "",
|
||||||
|
menu_aria_label: "",
|
||||||
|
home_view_code: "",
|
||||||
|
prioritize_in_condensed_view: true,
|
||||||
|
},
|
||||||
|
my_reactions: {
|
||||||
|
fragment: "narrow/has/reaction/sender/me",
|
||||||
|
name: $t({defaultMessage: "Reactions"}),
|
||||||
|
is_pinned: true,
|
||||||
|
icon: "zulip-icon-smile",
|
||||||
|
css_class_suffix: "my_reactions",
|
||||||
|
tooltip_template_id: "my-reactions-tooltip-template",
|
||||||
|
has_unread_count: false,
|
||||||
|
unread_count_type: "",
|
||||||
|
supports_masked_unread: false,
|
||||||
|
hidden_for_spectators: true,
|
||||||
|
menu_icon_class: "",
|
||||||
|
menu_aria_label: "",
|
||||||
|
home_view_code: "",
|
||||||
|
prioritize_in_condensed_view: false,
|
||||||
|
},
|
||||||
|
starred_messages: {
|
||||||
|
fragment: "narrow/is/starred",
|
||||||
|
name: $t({defaultMessage: "Starred messages"}),
|
||||||
|
is_pinned: true,
|
||||||
|
icon: "zulip-icon-star",
|
||||||
|
css_class_suffix: "starred_messages",
|
||||||
|
tooltip_template_id: "starred-message-tooltip-template",
|
||||||
|
has_unread_count: true,
|
||||||
|
unread_count_type: "quiet-count",
|
||||||
|
supports_masked_unread: true,
|
||||||
|
hidden_for_spectators: true,
|
||||||
|
menu_icon_class: "starred-messages-sidebar-menu-icon",
|
||||||
|
menu_aria_label: $t({defaultMessage: "Starred messages options"}),
|
||||||
|
home_view_code: "",
|
||||||
|
prioritize_in_condensed_view: true,
|
||||||
|
},
|
||||||
|
drafts: {
|
||||||
|
fragment: "drafts",
|
||||||
|
name: $t({defaultMessage: "Drafts"}),
|
||||||
|
is_pinned: true,
|
||||||
|
icon: "zulip-icon-drafts",
|
||||||
|
css_class_suffix: "drafts",
|
||||||
|
tooltip_template_id: "drafts-tooltip-template",
|
||||||
|
has_unread_count: true,
|
||||||
|
unread_count_type: "quiet-count",
|
||||||
|
supports_masked_unread: false,
|
||||||
|
hidden_for_spectators: true,
|
||||||
|
menu_icon_class: "drafts-sidebar-menu-icon",
|
||||||
|
menu_aria_label: $t({defaultMessage: "Drafts options"}),
|
||||||
|
home_view_code: "",
|
||||||
|
prioritize_in_condensed_view: false,
|
||||||
|
},
|
||||||
|
scheduled_messages: {
|
||||||
|
fragment: "scheduled",
|
||||||
|
name: $t({defaultMessage: "Scheduled messages"}),
|
||||||
|
is_pinned: true,
|
||||||
|
icon: "zulip-icon-calendar-days",
|
||||||
|
css_class_suffix: "scheduled_messages",
|
||||||
|
tooltip_template_id: "scheduled-tooltip-template",
|
||||||
|
has_unread_count: true,
|
||||||
|
unread_count_type: "quiet-count",
|
||||||
|
supports_masked_unread: false,
|
||||||
|
hidden_for_spectators: true,
|
||||||
|
menu_icon_class: "",
|
||||||
|
menu_aria_label: "",
|
||||||
|
home_view_code: "",
|
||||||
|
prioritize_in_condensed_view: false,
|
||||||
|
},
|
||||||
|
reminders: {
|
||||||
|
fragment: "reminders",
|
||||||
|
name: $t({defaultMessage: "Reminders"}),
|
||||||
|
is_pinned: true,
|
||||||
|
icon: "zulip-icon-alarm-clock",
|
||||||
|
css_class_suffix: "reminders",
|
||||||
|
tooltip_template_id: "reminders-tooltip-template",
|
||||||
|
has_unread_count: true,
|
||||||
|
unread_count_type: "quiet-count",
|
||||||
|
supports_masked_unread: false,
|
||||||
|
hidden_for_spectators: true,
|
||||||
|
menu_icon_class: "",
|
||||||
|
menu_aria_label: "",
|
||||||
|
home_view_code: "",
|
||||||
|
prioritize_in_condensed_view: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export type NavigationView = {
|
||||||
|
fragment: string;
|
||||||
|
is_pinned: boolean;
|
||||||
|
name: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
let navigation_views_dict: Map<string, NavigationView>;
|
||||||
|
|
||||||
|
export function add_navigation_view(navigation_view: NavigationView): void {
|
||||||
|
navigation_views_dict.set(navigation_view.fragment, navigation_view);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function update_navigation_view(fragment: string, data: Partial<NavigationView>): void {
|
||||||
|
const view = get_navigation_view_by_fragment(fragment);
|
||||||
|
if (view) {
|
||||||
|
navigation_views_dict.set(fragment, {
|
||||||
|
...view,
|
||||||
|
...data,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
blueslip.error("Cannot find navigation view to update");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function remove_navigation_view(fragment: string): void {
|
||||||
|
navigation_views_dict.delete(fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function get_navigation_view_by_fragment(fragment: string): NavigationView | undefined {
|
||||||
|
return navigation_views_dict.get(fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BuiltInViewMetadata = BuiltInViewBasicMetadata & {
|
||||||
|
is_home_view: boolean;
|
||||||
|
unread_count?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function get_built_in_views(): BuiltInViewMetadata[] {
|
||||||
|
return Object.values(built_in_views_meta_data).map((view) => {
|
||||||
|
const view_current_data = get_navigation_view_by_fragment(view.fragment);
|
||||||
|
return {
|
||||||
|
...view,
|
||||||
|
is_pinned: view_current_data?.is_pinned ?? view.is_pinned,
|
||||||
|
is_home_view: view.home_view_code === user_settings.web_home_view,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function get_all_navigation_views(): NavigationView[] {
|
||||||
|
const built_in_views = get_built_in_views().map((view) => ({
|
||||||
|
fragment: view.fragment,
|
||||||
|
is_pinned: view.is_pinned,
|
||||||
|
name: view.name,
|
||||||
|
}));
|
||||||
|
const built_in_fragments = new Set(built_in_views.map((view) => view.fragment));
|
||||||
|
const custom_views = [...navigation_views_dict.values()].filter(
|
||||||
|
(view) => !built_in_fragments.has(view.fragment),
|
||||||
|
);
|
||||||
|
|
||||||
|
return [...built_in_views, ...custom_views];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const initialize = (params: StateData["navigation_views"]): void => {
|
||||||
|
navigation_views_dict = new Map<string, NavigationView>(
|
||||||
|
params.navigation_views.map((view) => [view.fragment, view]),
|
||||||
|
);
|
||||||
|
};
|
@@ -36,6 +36,7 @@ import * as message_view from "./message_view.ts";
|
|||||||
import * as muted_users_ui from "./muted_users_ui.ts";
|
import * as muted_users_ui from "./muted_users_ui.ts";
|
||||||
import * as narrow_title from "./narrow_title.ts";
|
import * as narrow_title from "./narrow_title.ts";
|
||||||
import * as navbar_alerts from "./navbar_alerts.ts";
|
import * as navbar_alerts from "./navbar_alerts.ts";
|
||||||
|
import * as navigation_views from "./navigation_views.ts";
|
||||||
import * as onboarding_steps from "./onboarding_steps.ts";
|
import * as onboarding_steps from "./onboarding_steps.ts";
|
||||||
import * as overlays from "./overlays.ts";
|
import * as overlays from "./overlays.ts";
|
||||||
import * as peer_data from "./peer_data.ts";
|
import * as peer_data from "./peer_data.ts";
|
||||||
@@ -203,6 +204,20 @@ export function dispatch_normal_event(event) {
|
|||||||
muted_users_ui.handle_user_updates(event.muted_users);
|
muted_users_ui.handle_user_updates(event.muted_users);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "navigation_view":
|
||||||
|
switch (event.op) {
|
||||||
|
case "add":
|
||||||
|
navigation_views.add_navigation_view(event.navigation_view);
|
||||||
|
break;
|
||||||
|
case "update":
|
||||||
|
navigation_views.update_navigation_view(event.fragment, event.data);
|
||||||
|
break;
|
||||||
|
case "remove":
|
||||||
|
navigation_views.remove_navigation_view(event.fragment);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case "presence":
|
case "presence":
|
||||||
activity_ui.update_presence_info(event.user_id, event.presence, event.server_timestamp);
|
activity_ui.update_presence_info(event.user_id, event.presence, event.server_timestamp);
|
||||||
break;
|
break;
|
||||||
|
@@ -288,6 +288,10 @@ export function initialize(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function initialize_left_sidebar(): void {
|
export function initialize_left_sidebar(): void {
|
||||||
|
const primary_condensed_views =
|
||||||
|
left_sidebar_navigation_area.get_built_in_primary_condensed_views();
|
||||||
|
const expanded_views = left_sidebar_navigation_area.get_built_in_views();
|
||||||
|
|
||||||
const rendered_sidebar = render_left_sidebar({
|
const rendered_sidebar = render_left_sidebar({
|
||||||
is_guest: current_user.is_guest,
|
is_guest: current_user.is_guest,
|
||||||
development_environment: page_params.development_environment,
|
development_environment: page_params.development_environment,
|
||||||
@@ -298,6 +302,8 @@ export function initialize_left_sidebar(): void {
|
|||||||
is_recent_view_home_view:
|
is_recent_view_home_view:
|
||||||
user_settings.web_home_view === settings_config.web_home_view_values.recent_topics.code,
|
user_settings.web_home_view === settings_config.web_home_view_values.recent_topics.code,
|
||||||
is_spectator: page_params.is_spectator,
|
is_spectator: page_params.is_spectator,
|
||||||
|
primary_condensed_views,
|
||||||
|
expanded_views,
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#left-sidebar-container").html(rendered_sidebar);
|
$("#left-sidebar-container").html(rendered_sidebar);
|
||||||
|
@@ -160,6 +160,12 @@ export const channel_folder_schema = z.object({
|
|||||||
is_archived: z.boolean(),
|
is_archived: z.boolean(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const navigation_view_schema = z.object({
|
||||||
|
fragment: z.string(),
|
||||||
|
name: z.string(),
|
||||||
|
is_pinned: z.boolean(),
|
||||||
|
});
|
||||||
|
|
||||||
export const user_topic_schema = z.object({
|
export const user_topic_schema = z.object({
|
||||||
stream_id: z.number(),
|
stream_id: z.number(),
|
||||||
topic_name: z.string(),
|
topic_name: z.string(),
|
||||||
@@ -537,6 +543,7 @@ export const split_state_data_schema = z.object({
|
|||||||
}),
|
}),
|
||||||
current_user: current_user_schema,
|
current_user: current_user_schema,
|
||||||
realm: realm_schema,
|
realm: realm_schema,
|
||||||
|
navigation_views: z.object({navigation_views: z.array(navigation_view_schema)}),
|
||||||
});
|
});
|
||||||
type SplitStateDataInput = z.input<typeof split_state_data_schema>;
|
type SplitStateDataInput = z.input<typeof split_state_data_schema>;
|
||||||
|
|
||||||
|
@@ -86,6 +86,7 @@ import * as narrow_title from "./narrow_title.ts";
|
|||||||
import * as navbar_alerts from "./navbar_alerts.ts";
|
import * as navbar_alerts from "./navbar_alerts.ts";
|
||||||
import * as navbar_help_menu from "./navbar_help_menu.ts";
|
import * as navbar_help_menu from "./navbar_help_menu.ts";
|
||||||
import * as navigate from "./navigate.ts";
|
import * as navigate from "./navigate.ts";
|
||||||
|
import * as navigation_views from "./navigation_views.ts";
|
||||||
import * as onboarding_steps from "./onboarding_steps.ts";
|
import * as onboarding_steps from "./onboarding_steps.ts";
|
||||||
import * as overlays from "./overlays.ts";
|
import * as overlays from "./overlays.ts";
|
||||||
import {page_params} from "./page_params.ts";
|
import {page_params} from "./page_params.ts";
|
||||||
@@ -455,6 +456,7 @@ export async function initialize_everything(state_data) {
|
|||||||
// This populates data for scheduled messages.
|
// This populates data for scheduled messages.
|
||||||
scheduled_messages.initialize(state_data.scheduled_messages);
|
scheduled_messages.initialize(state_data.scheduled_messages);
|
||||||
message_reminder.initialize(state_data.reminders);
|
message_reminder.initialize(state_data.reminders);
|
||||||
|
navigation_views.initialize(state_data.navigation_views);
|
||||||
scheduled_messages_ui.initialize();
|
scheduled_messages_ui.initialize();
|
||||||
reminders_overlay_ui.initialize();
|
reminders_overlay_ui.initialize();
|
||||||
popover_menus.initialize();
|
popover_menus.initialize();
|
||||||
|
@@ -1,167 +1,22 @@
|
|||||||
<div class="left-sidebar" id="left-sidebar" role="navigation">
|
<div class="left-sidebar" id="left-sidebar" role="navigation">
|
||||||
<div id="left-sidebar-navigation-area" class="left-sidebar-navigation-area">
|
<div id="left-sidebar-navigation-area" class="left-sidebar-navigation-area">
|
||||||
<div id="views-label-container" class="showing-expanded-navigation {{#if is_spectator}}remove-pointer-for-spectator{{/if}}">
|
<div id="views-label-container" class="showing-expanded-navigation{{#if is_spectator}} remove-pointer-for-spectator{{/if}}">
|
||||||
<i id="toggle-top-left-navigation-area-icon" class="zulip-icon zulip-icon-heading-triangle-right sidebar-heading-icon rotate-icon-down views-tooltip-target hidden-for-spectators" aria-hidden="true" tabindex="0" role="button"></i>
|
<i id="toggle-top-left-navigation-area-icon" class="zulip-icon zulip-icon-heading-triangle-right sidebar-heading-icon rotate-icon-down views-tooltip-target hidden-for-spectators" aria-hidden="true" tabindex="0" role="button"></i>
|
||||||
{{~!-- squash whitespace --~}}
|
{{~!-- squash whitespace --~}}
|
||||||
<h4 class="left-sidebar-title"><span class="views-tooltip-target">{{t 'VIEWS' }}</span></h4>
|
<h4 class="left-sidebar-title"><span class="views-tooltip-target">{{t 'VIEWS' }}</span></h4>
|
||||||
<ul id="left-sidebar-navigation-list-condensed" class="filters">
|
<ul id="left-sidebar-navigation-list-condensed" class="filters">
|
||||||
<li class="top_left_inbox left-sidebar-navigation-condensed-item {{#if is_inbox_home_view}}selected-home-view{{/if}}">
|
{{#each primary_condensed_views}}
|
||||||
<a href="#inbox" class="tippy-left-sidebar-tooltip left-sidebar-navigation-icon-container" data-tooltip-template-id="inbox-tooltip-template">
|
{{> left_sidebar_primary_condensed_view_item . }}
|
||||||
<span class="filter-icon">
|
{{/each}}
|
||||||
<i class="zulip-icon zulip-icon-inbox" aria-hidden="true"></i>
|
|
||||||
</span>
|
|
||||||
<span class="unread_count"></span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="top_left_recent_view left-sidebar-navigation-condensed-item {{#if is_recent_view_home_view}}selected-home-view{{/if}}">
|
|
||||||
<a href="#recent" class="tippy-left-sidebar-tooltip left-sidebar-navigation-icon-container" data-tooltip-template-id="recent-conversations-tooltip-template">
|
|
||||||
<span class="filter-icon">
|
|
||||||
<i class="zulip-icon zulip-icon-recent" aria-hidden="true"></i>
|
|
||||||
</span>
|
|
||||||
<span class="unread_count"></span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="top_left_all_messages left-sidebar-navigation-condensed-item {{#if is_all_messages_home_view}}selected-home-view{{/if}}">
|
|
||||||
<a href="#feed" class="tippy-left-sidebar-tooltip left-sidebar-navigation-icon-container" data-tooltip-template-id="all-message-tooltip-template">
|
|
||||||
<span class="filter-icon">
|
|
||||||
<i class="zulip-icon zulip-icon-all-messages" aria-hidden="true"></i>
|
|
||||||
</span>
|
|
||||||
<span class="unread_count"></span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="top_left_mentions left-sidebar-navigation-condensed-item">
|
|
||||||
<a href="#narrow/is/mentioned" class="tippy-left-sidebar-tooltip left-sidebar-navigation-icon-container" data-tooltip-template-id="mentions-tooltip-template">
|
|
||||||
<span class="filter-icon">
|
|
||||||
<i class="zulip-icon zulip-icon-at-sign" aria-hidden="true"></i>
|
|
||||||
</span>
|
|
||||||
<span class="unread_count"></span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="top_left_starred_messages left-sidebar-navigation-condensed-item">
|
|
||||||
<a href="#narrow/is/starred" class="tippy-left-sidebar-tooltip left-sidebar-navigation-icon-container" data-tooltip-template-id="starred-message-tooltip-template">
|
|
||||||
<span class="filter-icon">
|
|
||||||
<i class="zulip-icon zulip-icon-star" aria-hidden="true"></i>
|
|
||||||
</span>
|
|
||||||
<span class="unread_count quiet-count"></span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
<div class="left-sidebar-navigation-menu-icon">
|
<div class="left-sidebar-navigation-menu-icon">
|
||||||
<i class="zulip-icon zulip-icon-more-vertical" aria-label="{{t 'Other views'}}"></i>
|
<i class="zulip-icon zulip-icon-more-vertical" aria-label="{{t 'Other views'}}"></i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ul id="left-sidebar-navigation-list" class="left-sidebar-navigation-list filters">
|
<ul id="left-sidebar-navigation-list" class="left-sidebar-navigation-list filters">
|
||||||
<li class="top_left_inbox top_left_row hidden-for-spectators {{#if is_inbox_home_view}}selected-home-view{{/if}}">
|
{{#each expanded_views}}
|
||||||
<a href="#inbox" class="left-sidebar-navigation-label-container tippy-left-sidebar-tooltip" data-tooltip-template-id="inbox-tooltip-template">
|
{{> left_sidebar_expanded_view_item . }}
|
||||||
<span class="filter-icon">
|
{{/each}}
|
||||||
<i class="zulip-icon zulip-icon-inbox" aria-hidden="true"></i>
|
|
||||||
</span>
|
|
||||||
{{~!-- squash whitespace --~}}
|
|
||||||
<span class="left-sidebar-navigation-label">{{t 'Inbox' }}</span>
|
|
||||||
<span class="unread_count normal-count"></span>
|
|
||||||
<span class="masked_unread_count">
|
|
||||||
<i class="zulip-icon zulip-icon-masked-unread"></i>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
<span class="arrow sidebar-menu-icon inbox-sidebar-menu-icon hidden-for-spectators"><i class="zulip-icon zulip-icon-more-vertical" aria-label="{{t 'Inbox options'}}"></i></span>
|
|
||||||
</li>
|
|
||||||
<li class="top_left_recent_view top_left_row {{#if is_recent_view_home_view}}selected-home-view{{/if}}">
|
|
||||||
<a href="#recent" class="left-sidebar-navigation-label-container tippy-left-sidebar-tooltip" data-tooltip-template-id="recent-conversations-tooltip-template">
|
|
||||||
<span class="filter-icon">
|
|
||||||
<i class="zulip-icon zulip-icon-recent" aria-hidden="true"></i>
|
|
||||||
</span>
|
|
||||||
{{~!-- squash whitespace --~}}
|
|
||||||
<span class="left-sidebar-navigation-label">{{t 'Recent conversations' }}</span>
|
|
||||||
<span class="unread_count normal-count"></span>
|
|
||||||
<span class="masked_unread_count">
|
|
||||||
<i class="zulip-icon zulip-icon-masked-unread"></i>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
<span class="arrow sidebar-menu-icon recent-view-sidebar-menu-icon hidden-for-spectators">
|
|
||||||
<i class="zulip-icon zulip-icon-more-vertical" aria-label="{{t 'Recent conversations options'}}"></i>
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
<li class="top_left_all_messages top_left_row {{#if is_all_messages_home_view}}selected-home-view{{/if}}">
|
|
||||||
<a href="#feed" class="left-sidebar-navigation-label-container tippy-left-sidebar-tooltip" data-tooltip-template-id="all-message-tooltip-template">
|
|
||||||
<span class="filter-icon">
|
|
||||||
<i class="zulip-icon zulip-icon-all-messages" aria-hidden="true"></i>
|
|
||||||
</span>
|
|
||||||
{{~!-- squash whitespace --~}}
|
|
||||||
<span class="left-sidebar-navigation-label">{{t 'Combined feed' }}</span>
|
|
||||||
<span class="unread_count normal-count"></span>
|
|
||||||
<span class="masked_unread_count">
|
|
||||||
<i class="zulip-icon zulip-icon-masked-unread"></i>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
<span class="arrow sidebar-menu-icon all-messages-sidebar-menu-icon hidden-for-spectators">
|
|
||||||
<i class="zulip-icon zulip-icon-more-vertical" aria-label="{{t 'Combined feed options'}}"></i>
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
<li class="top_left_mentions top_left_row hidden-for-spectators">
|
|
||||||
<a class="left-sidebar-navigation-label-container tippy-left-sidebar-tooltip" href="#narrow/is/mentioned" data-tooltip-template-id="mentions-tooltip-template">
|
|
||||||
<span class="filter-icon">
|
|
||||||
<i class="zulip-icon zulip-icon-at-sign" aria-hidden="true"></i>
|
|
||||||
</span>
|
|
||||||
{{~!-- squash whitespace --~}}
|
|
||||||
<span class="left-sidebar-navigation-label">{{t 'Mentions' }}</span>
|
|
||||||
<span class="unread_count"></span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="top_left_my_reactions top_left_row hidden-for-spectators">
|
|
||||||
<a class="left-sidebar-navigation-label-container tippy-left-sidebar-tooltip" href="#narrow/has/reaction/sender/me" data-tooltip-template-id="my-reactions-tooltip-template">
|
|
||||||
<span class="filter-icon">
|
|
||||||
<i class="zulip-icon zulip-icon-smile" aria-hidden="true"></i>
|
|
||||||
</span>
|
|
||||||
{{~!-- squash whitespace --~}}
|
|
||||||
<span class="left-sidebar-navigation-label">{{t 'Reactions' }}</span>
|
|
||||||
<span class="unread_count"></span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="top_left_starred_messages top_left_row hidden-for-spectators">
|
|
||||||
<a class="left-sidebar-navigation-label-container tippy-left-sidebar-tooltip" href="#narrow/is/starred" data-tooltip-template-id="starred-message-tooltip-template">
|
|
||||||
<span class="filter-icon">
|
|
||||||
<i class="zulip-icon zulip-icon-star" aria-hidden="true"></i>
|
|
||||||
</span>
|
|
||||||
{{~!-- squash whitespace --~}}
|
|
||||||
<span class="left-sidebar-navigation-label">{{t 'Starred messages' }}</span>
|
|
||||||
<span class="unread_count quiet-count"></span>
|
|
||||||
<span class="masked_unread_count">
|
|
||||||
<i class="zulip-icon zulip-icon-masked-unread"></i>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
<span class="arrow sidebar-menu-icon starred-messages-sidebar-menu-icon"><i class="zulip-icon zulip-icon-more-vertical" aria-label="{{t 'Starred messages options'}}"></i></span>
|
|
||||||
</li>
|
|
||||||
<li class="top_left_drafts top_left_row hidden-for-spectators">
|
|
||||||
<a href="#drafts" class="left-sidebar-navigation-label-container tippy-left-sidebar-tooltip" data-tooltip-template-id="drafts-tooltip-template">
|
|
||||||
<span class="filter-icon">
|
|
||||||
<i class="zulip-icon zulip-icon-drafts" aria-hidden="true"></i>
|
|
||||||
</span>
|
|
||||||
{{~!-- squash whitespace --~}}
|
|
||||||
<span class="left-sidebar-navigation-label">{{t 'Drafts' }}</span>
|
|
||||||
<span class="unread_count quiet-count"></span>
|
|
||||||
</a>
|
|
||||||
<span class="arrow sidebar-menu-icon drafts-sidebar-menu-icon"><i class="zulip-icon zulip-icon-more-vertical" aria-label="{{t 'Drafts options'}}"></i></span>
|
|
||||||
</li>
|
|
||||||
<li class="top_left_scheduled_messages top_left_row hidden-for-spectators">
|
|
||||||
<a class="left-sidebar-navigation-label-container tippy-left-sidebar-tooltip" href="#scheduled" data-tooltip-template-id="scheduled-tooltip-template">
|
|
||||||
<span class="filter-icon">
|
|
||||||
<i class="zulip-icon zulip-icon-calendar-days" aria-hidden="true"></i>
|
|
||||||
</span>
|
|
||||||
{{~!-- squash whitespace --~}}
|
|
||||||
<span class="left-sidebar-navigation-label">{{t 'Scheduled messages' }}</span>
|
|
||||||
<span class="unread_count quiet-count"></span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="top_left_reminders top_left_row hidden-for-spectators">
|
|
||||||
<a class="left-sidebar-navigation-label-container tippy-left-sidebar-tooltip" href="#reminders" data-tooltip-template-id="reminders-tooltip-template">
|
|
||||||
<span class="filter-icon">
|
|
||||||
<i class="zulip-icon zulip-icon-alarm-clock" aria-hidden="true"></i>
|
|
||||||
</span>
|
|
||||||
{{~!-- squash whitespace --~}}
|
|
||||||
<span class="left-sidebar-navigation-label">{{t 'Reminders' }}</span>
|
|
||||||
<span class="unread_count quiet-count"></span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
18
web/templates/left_sidebar_expanded_view_item.hbs
Normal file
18
web/templates/left_sidebar_expanded_view_item.hbs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<li class="top_left_{{css_class_suffix}} top_left_row {{#if hidden_for_spectators}}hidden-for-spectators{{/if}} {{#if is_home_view}}selected-home-view{{/if}}">
|
||||||
|
<a href="#{{fragment}}" class="left-sidebar-navigation-label-container tippy-left-sidebar-tooltip" data-tooltip-template-id="{{tooltip_template_id}}">
|
||||||
|
<span class="filter-icon">
|
||||||
|
<i class="zulip-icon {{icon}}" aria-hidden="true"></i>
|
||||||
|
</span>
|
||||||
|
{{~!-- squash whitespace --~}}
|
||||||
|
<span class="left-sidebar-navigation-label">{{name}}</span>
|
||||||
|
<span class="unread_count {{unread_count_type}}"></span>
|
||||||
|
{{#if supports_masked_unread}}
|
||||||
|
<span class="masked_unread_count">
|
||||||
|
<i class="zulip-icon zulip-icon-masked-unread"></i>
|
||||||
|
</span>
|
||||||
|
{{/if}}
|
||||||
|
</a>
|
||||||
|
{{#if menu_icon_class}}
|
||||||
|
<span class="arrow sidebar-menu-icon {{menu_icon_class}} hidden-for-spectators"><i class="zulip-icon zulip-icon-more-vertical" aria-label="{{menu_aria_label}}"></i></span>
|
||||||
|
{{/if}}
|
||||||
|
</li>
|
@@ -0,0 +1,8 @@
|
|||||||
|
<li class="top_left_{{css_class_suffix}} left-sidebar-navigation-condensed-item{{#if is_home_view}} selected-home-view{{/if}}">
|
||||||
|
<a href="#{{fragment}}" class="tippy-left-sidebar-tooltip left-sidebar-navigation-icon-container" data-tooltip-template-id="{{tooltip_template_id}}">
|
||||||
|
<span class="filter-icon">
|
||||||
|
<i class="zulip-icon {{icon}}" aria-hidden="true"></i>
|
||||||
|
</span>
|
||||||
|
<span class="unread_count {{unread_count_type}}"></span>
|
||||||
|
</a>
|
||||||
|
</li>
|
@@ -1,30 +0,0 @@
|
|||||||
<div class="popover-menu" data-simplebar data-simplebar-tab-index="-1">
|
|
||||||
<ul role="menu" class="popover-menu-list condensed-views-popover-menu">
|
|
||||||
<li role="none" class="link-item popover-menu-list-item condensed-views-popover-menu-reactions">
|
|
||||||
<a href="#narrow/has/reaction/sender/me" role="menuitem" class="popover-menu-link tippy-left-sidebar-tooltip" data-tooltip-template-id="my-reactions-tooltip-template" tabindex="0">
|
|
||||||
<i class="popover-menu-icon zulip-icon zulip-icon-smile" aria-hidden="true"></i>
|
|
||||||
<span class="popover-menu-label">{{t 'Reactions' }}</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li role="none" class="link-item popover-menu-list-item condensed-views-popover-menu-drafts">
|
|
||||||
<a href="#drafts" role="menuitem" class="popover-menu-link tippy-left-sidebar-tooltip" data-tooltip-template-id="drafts-tooltip-template" tabindex="0">
|
|
||||||
<i class="popover-menu-icon zulip-icon zulip-icon-drafts" aria-hidden="true"></i>
|
|
||||||
<span class="label-and-unread-wrapper">
|
|
||||||
<span class="popover-menu-label">{{t 'Drafts' }}</span>
|
|
||||||
<span class="unread_count quiet-count"></span>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{{#if has_scheduled_messages }}
|
|
||||||
<li role="none" class="link-item popover-menu-list-item condensed-views-popover-menu-scheduled-messages">
|
|
||||||
<a href="#scheduled" role="menuitem" class="popover-menu-link tippy-left-sidebar-tooltip" tabindex="0" data-tooltip-template-id="scheduled-tooltip-template">
|
|
||||||
<i class="popover-menu-icon zulip-icon zulip-icon-calendar-days" aria-hidden="true"></i>
|
|
||||||
<span class="label-and-unread-wrapper">
|
|
||||||
<span class="popover-menu-label">{{t 'Scheduled messages' }}</span>
|
|
||||||
<span class="unread_count quiet-count"></span>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{{/if}}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
@@ -0,0 +1,18 @@
|
|||||||
|
<li role="none" class="link-item popover-menu-list-item views-popover-menu-{{css_class_suffix}}">
|
||||||
|
<a href="#{{fragment}}" role="menuitem" class="popover-menu-link tippy-left-sidebar-tooltip" data-tooltip-template-id="{{tooltip_template_id}}" tabindex="0">
|
||||||
|
<i class="popover-menu-icon zulip-icon {{icon}}" aria-hidden="true"></i>
|
||||||
|
{{#if has_unread_count}}
|
||||||
|
<span class="label-and-unread-wrapper">
|
||||||
|
<span class="popover-menu-label">{{name}}</span>
|
||||||
|
<span class="unread_count {{unread_count_type}}">{{#if unread_count}}{{unread_count}}{{/if}}</span>
|
||||||
|
{{#if supports_masked_unread}}
|
||||||
|
<span class="masked_unread_count">
|
||||||
|
<i class="zulip-icon zulip-icon-masked-unread"></i>
|
||||||
|
</span>
|
||||||
|
{{/if}}
|
||||||
|
</span>
|
||||||
|
{{else}}
|
||||||
|
<span class="popover-menu-label">{{name}}</span>
|
||||||
|
{{/if}}
|
||||||
|
</a>
|
||||||
|
</li>
|
@@ -0,0 +1,7 @@
|
|||||||
|
<div class="popover-menu" data-simplebar data-simplebar-tab-index="-1">
|
||||||
|
<ul role="menu" class="popover-menu-list condensed-views-popover-menu">
|
||||||
|
{{#each views}}
|
||||||
|
{{> left_sidebar_view_popover_item .}}
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
@@ -51,6 +51,7 @@ const realm_playground = mock_esm("../src/realm_playground");
|
|||||||
const reload = mock_esm("../src/reload");
|
const reload = mock_esm("../src/reload");
|
||||||
const message_reminder = mock_esm("../src/message_reminder");
|
const message_reminder = mock_esm("../src/message_reminder");
|
||||||
const reminders_overlay_ui = mock_esm("../src/reminders_overlay_ui");
|
const reminders_overlay_ui = mock_esm("../src/reminders_overlay_ui");
|
||||||
|
const navigation_views = mock_esm("../src/navigation_views");
|
||||||
const saved_snippets = mock_esm("../src/saved_snippets");
|
const saved_snippets = mock_esm("../src/saved_snippets");
|
||||||
const saved_snippets_ui = mock_esm("../src/saved_snippets_ui");
|
const saved_snippets_ui = mock_esm("../src/saved_snippets_ui");
|
||||||
const scheduled_messages = mock_esm("../src/scheduled_messages");
|
const scheduled_messages = mock_esm("../src/scheduled_messages");
|
||||||
@@ -195,6 +196,37 @@ run_test("alert_words", ({override}) => {
|
|||||||
assert.ok(alert_words.has_alert_word("lunch"));
|
assert.ok(alert_words.has_alert_word("lunch"));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
run_test("navigation_views", ({override}) => {
|
||||||
|
const add_event = event_fixtures.navigation_view__add;
|
||||||
|
{
|
||||||
|
const stub = make_stub();
|
||||||
|
override(navigation_views, "add_navigation_view", stub.f);
|
||||||
|
|
||||||
|
dispatch(add_event);
|
||||||
|
assert.equal(stub.num_calls, 1);
|
||||||
|
assert_same(stub.get_args("event").event, add_event.navigation_view);
|
||||||
|
}
|
||||||
|
const update_event = event_fixtures.navigation_view__update;
|
||||||
|
{
|
||||||
|
const stub = make_stub();
|
||||||
|
override(navigation_views, "update_navigation_view", stub.f);
|
||||||
|
|
||||||
|
dispatch(update_event);
|
||||||
|
assert.equal(stub.num_calls, 1);
|
||||||
|
assert_same(stub.get_args("event").event, update_event.fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
const remove_event = event_fixtures.navigation_view__remove;
|
||||||
|
{
|
||||||
|
const stub = make_stub();
|
||||||
|
override(navigation_views, "remove_navigation_view", stub.f);
|
||||||
|
|
||||||
|
dispatch(remove_event);
|
||||||
|
assert.equal(stub.num_calls, 1);
|
||||||
|
assert_same(stub.get_args("event").event, remove_event.fragment);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
run_test("saved_snippets", ({override}) => {
|
run_test("saved_snippets", ({override}) => {
|
||||||
const add_event = event_fixtures.saved_snippets__add;
|
const add_event = event_fixtures.saved_snippets__add;
|
||||||
override(saved_snippets_ui, "rerender_dropdown_widget", noop);
|
override(saved_snippets_ui, "rerender_dropdown_widget", noop);
|
||||||
|
@@ -283,6 +283,29 @@ exports.fixtures = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
navigation_view__add: {
|
||||||
|
type: "navigation_view",
|
||||||
|
op: "add",
|
||||||
|
navigation_view: {
|
||||||
|
fragment: "narrow/is/alerted",
|
||||||
|
is_pinned: true,
|
||||||
|
name: "Watched phrases",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
navigation_view__remove: {
|
||||||
|
type: "navigation_view",
|
||||||
|
op: "remove",
|
||||||
|
fragment: "narrow/is/alerted",
|
||||||
|
},
|
||||||
|
|
||||||
|
navigation_view__update: {
|
||||||
|
type: "navigation_view",
|
||||||
|
op: "update",
|
||||||
|
fragment: "narrow/is/alerted",
|
||||||
|
data: {is_pinned: false},
|
||||||
|
},
|
||||||
|
|
||||||
onboarding_steps: {
|
onboarding_steps: {
|
||||||
type: "onboarding_steps",
|
type: "onboarding_steps",
|
||||||
onboarding_steps: [
|
onboarding_steps: [
|
||||||
|
131
web/tests/navigation_views.test.cjs
Normal file
131
web/tests/navigation_views.test.cjs
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const assert = require("node:assert/strict");
|
||||||
|
|
||||||
|
const {set_global, zrequire} = require("./lib/namespace.cjs");
|
||||||
|
const {run_test} = require("./lib/test.cjs");
|
||||||
|
|
||||||
|
set_global("page_params", {
|
||||||
|
is_spectator: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
navigation_views: [
|
||||||
|
{
|
||||||
|
fragment: "narrow/is/starred",
|
||||||
|
is_pinned: true,
|
||||||
|
name: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fragment: "narrow/is/mentioned",
|
||||||
|
is_pinned: false,
|
||||||
|
name: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fragment: "custom/view/1",
|
||||||
|
is_pinned: true,
|
||||||
|
name: "Custom View 1",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const blueslip = zrequire("blueslip");
|
||||||
|
const people = zrequire("people");
|
||||||
|
const navigation_views = zrequire("navigation_views");
|
||||||
|
const {built_in_views_meta_data} = zrequire("navigation_views");
|
||||||
|
const {initialize_user_settings} = zrequire("user_settings");
|
||||||
|
|
||||||
|
people.add_active_user({
|
||||||
|
email: "tester@zulip.com",
|
||||||
|
full_name: "Tester von Tester",
|
||||||
|
user_id: 42,
|
||||||
|
});
|
||||||
|
|
||||||
|
people.initialize_current_user(42);
|
||||||
|
|
||||||
|
const user_settings = {
|
||||||
|
web_home_view: "inbox",
|
||||||
|
};
|
||||||
|
initialize_user_settings({user_settings});
|
||||||
|
|
||||||
|
navigation_views.initialize(params);
|
||||||
|
|
||||||
|
run_test("initialize", () => {
|
||||||
|
assert.ok(navigation_views.get_navigation_view_by_fragment("narrow/is/starred"));
|
||||||
|
assert.ok(navigation_views.get_navigation_view_by_fragment("narrow/is/mentioned"));
|
||||||
|
assert.ok(navigation_views.get_navigation_view_by_fragment("custom/view/1"));
|
||||||
|
});
|
||||||
|
|
||||||
|
run_test("add_navigation_view", () => {
|
||||||
|
const view = {
|
||||||
|
fragment: "inbox",
|
||||||
|
is_pinned: true,
|
||||||
|
name: null,
|
||||||
|
};
|
||||||
|
navigation_views.add_navigation_view(view);
|
||||||
|
assert.equal(navigation_views.get_navigation_view_by_fragment(view.fragment), view);
|
||||||
|
});
|
||||||
|
|
||||||
|
run_test("update_navigation_view", () => {
|
||||||
|
const view = {
|
||||||
|
fragment: "inbox",
|
||||||
|
is_pinned: true,
|
||||||
|
name: null,
|
||||||
|
};
|
||||||
|
navigation_views.add_navigation_view(view);
|
||||||
|
assert.equal(navigation_views.get_navigation_view_by_fragment(view.fragment), view);
|
||||||
|
navigation_views.update_navigation_view(view.fragment, {is_pinned: false});
|
||||||
|
assert.equal(navigation_views.get_navigation_view_by_fragment(view.fragment).is_pinned, false);
|
||||||
|
blueslip.expect("error", "Cannot find navigation view to update");
|
||||||
|
navigation_views.update_navigation_view("nonexistent", {name: "Nonexistent"});
|
||||||
|
});
|
||||||
|
|
||||||
|
run_test("remove_navigation_view", () => {
|
||||||
|
const view = {
|
||||||
|
fragment: "inbox",
|
||||||
|
is_pinned: true,
|
||||||
|
name: null,
|
||||||
|
};
|
||||||
|
navigation_views.add_navigation_view(view);
|
||||||
|
assert.equal(navigation_views.get_navigation_view_by_fragment(view.fragment), view);
|
||||||
|
navigation_views.remove_navigation_view(view.fragment);
|
||||||
|
assert.equal(navigation_views.get_navigation_view_by_fragment(view.fragment), undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
run_test("get_built_in_views", () => {
|
||||||
|
const built_in_views = navigation_views.get_built_in_views();
|
||||||
|
|
||||||
|
assert.ok(built_in_views.length > 0);
|
||||||
|
|
||||||
|
const starred_view = built_in_views.find((view) => view.fragment === "narrow/is/starred");
|
||||||
|
assert.ok(starred_view);
|
||||||
|
assert.equal(starred_view.is_pinned, true);
|
||||||
|
|
||||||
|
const mentions_view = built_in_views.find((view) => view.fragment === "narrow/is/mentioned");
|
||||||
|
assert.ok(mentions_view);
|
||||||
|
assert.equal(mentions_view.is_pinned, false);
|
||||||
|
|
||||||
|
const inbox_view = built_in_views.find((view) => view.fragment === "inbox");
|
||||||
|
assert.ok(inbox_view);
|
||||||
|
assert.equal(inbox_view.is_pinned, built_in_views_meta_data.inbox.is_pinned);
|
||||||
|
});
|
||||||
|
|
||||||
|
run_test("get_all_navigation_views", () => {
|
||||||
|
const all_views = navigation_views.get_all_navigation_views();
|
||||||
|
|
||||||
|
assert.ok(all_views.length > 0);
|
||||||
|
|
||||||
|
const starred_view = all_views.find((view) => view.fragment === "narrow/is/starred");
|
||||||
|
assert.ok(starred_view);
|
||||||
|
assert.equal(starred_view.is_pinned, true);
|
||||||
|
assert.equal(starred_view.name, built_in_views_meta_data.starred_messages.name);
|
||||||
|
|
||||||
|
const custom_view = all_views.find((view) => view.fragment === "custom/view/1");
|
||||||
|
assert.ok(custom_view);
|
||||||
|
assert.equal(custom_view.is_pinned, true);
|
||||||
|
assert.equal(custom_view.name, "Custom View 1");
|
||||||
|
|
||||||
|
const fragments = all_views.map((view) => view.fragment);
|
||||||
|
const unique_fragments = [...new Set(fragments)];
|
||||||
|
assert.equal(fragments.length, unique_fragments.length);
|
||||||
|
});
|
Reference in New Issue
Block a user