mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	topic_list: Filter topics by resolved state in "more topics" view.
Fixes: #24200.
This commit is contained in:
		
				
					committed by
					
						
						Tim Abbott
					
				
			
			
				
	
			
			
			
						parent
						
							2a325b4530
						
					
				
				
					commit
					52b83f7b58
				
			@@ -424,6 +424,7 @@ export function zoom_in_topics(options: {stream_id: number | undefined}): void {
 | 
			
		||||
            // Add search box for topics list.
 | 
			
		||||
            $elt.children("div.bottom_left_row").append($(render_filter_topics()));
 | 
			
		||||
            $("#left-sidebar-filter-topic-input").trigger("focus");
 | 
			
		||||
            topic_list.setup_topic_search_typeahead();
 | 
			
		||||
        } else {
 | 
			
		||||
            $elt.hide();
 | 
			
		||||
        }
 | 
			
		||||
@@ -769,7 +770,7 @@ export function update_stream_sidebar_for_narrow(filter: Filter): JQuery | undef
 | 
			
		||||
    // we want to the topics list here.
 | 
			
		||||
    update_inbox_channel_view_callback(stream_id);
 | 
			
		||||
    topic_list.rebuild_left_sidebar($stream_li, stream_id);
 | 
			
		||||
 | 
			
		||||
    topic_list.topic_state_typeahead?.lookup(true);
 | 
			
		||||
    return $stream_li;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
import assert from "minimalistic-assert";
 | 
			
		||||
 | 
			
		||||
import * as resolved_topics from "../shared/src/resolved_topic.ts";
 | 
			
		||||
 | 
			
		||||
import * as echo_state from "./echo_state.ts";
 | 
			
		||||
import {FoldDict} from "./fold_dict.ts";
 | 
			
		||||
import * as message_util from "./message_util.ts";
 | 
			
		||||
@@ -31,6 +33,17 @@ export function stream_has_topics(stream_id: number): boolean {
 | 
			
		||||
    return history.has_topics();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function stream_has_locally_available_resolved_topics(stream_id: number): boolean {
 | 
			
		||||
    if (!stream_dict.has(stream_id)) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const history = stream_dict.get(stream_id);
 | 
			
		||||
    assert(history !== undefined);
 | 
			
		||||
 | 
			
		||||
    return history.has_resolved_topics();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type TopicHistoryEntry = {
 | 
			
		||||
    count: number;
 | 
			
		||||
    message_id: number;
 | 
			
		||||
@@ -67,6 +80,10 @@ export class PerStreamHistory {
 | 
			
		||||
        this.stream_id = stream_id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    has_resolved_topics(): boolean {
 | 
			
		||||
        return [...this.topics.keys()].some((topic) => resolved_topics.is_resolved(topic));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    has_topics(): boolean {
 | 
			
		||||
        return this.topics.size > 0;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -8,9 +8,14 @@ import render_topic_list_item from "../templates/topic_list_item.hbs";
 | 
			
		||||
 | 
			
		||||
import {all_messages_data} from "./all_messages_data.ts";
 | 
			
		||||
import * as blueslip from "./blueslip.ts";
 | 
			
		||||
import {Typeahead} from "./bootstrap_typeahead.ts";
 | 
			
		||||
import type {TypeaheadInputElement} from "./bootstrap_typeahead.ts";
 | 
			
		||||
import {$t} from "./i18n.ts";
 | 
			
		||||
import * as popover_menus from "./popover_menus.ts";
 | 
			
		||||
import * as popovers from "./popovers.ts";
 | 
			
		||||
import * as scroll_util from "./scroll_util.ts";
 | 
			
		||||
import type {SearchPillWidget} from "./search_pill.ts";
 | 
			
		||||
import * as search_pill from "./search_pill.ts";
 | 
			
		||||
import * as sidebar_ui from "./sidebar_ui.ts";
 | 
			
		||||
import * as stream_topic_history from "./stream_topic_history.ts";
 | 
			
		||||
import * as stream_topic_history_util from "./stream_topic_history_util.ts";
 | 
			
		||||
@@ -18,6 +23,7 @@ import type {StreamSubscription} from "./sub_store.ts";
 | 
			
		||||
import * as sub_store from "./sub_store.ts";
 | 
			
		||||
import * as topic_list_data from "./topic_list_data.ts";
 | 
			
		||||
import type {TopicInfo} from "./topic_list_data.ts";
 | 
			
		||||
import * as typeahead_helper from "./typeahead_helper.ts";
 | 
			
		||||
import * as vdom from "./vdom.ts";
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -29,6 +35,8 @@ import * as vdom from "./vdom.ts";
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
const active_widgets = new Map<number, LeftSidebarTopicListWidget>();
 | 
			
		||||
export let search_pill_widget: SearchPillWidget | null = null;
 | 
			
		||||
export let topic_state_typeahead: Typeahead<string> | undefined;
 | 
			
		||||
 | 
			
		||||
// We know whether we're zoomed or not.
 | 
			
		||||
let zoomed = false;
 | 
			
		||||
@@ -61,7 +69,7 @@ export function clear(): void {
 | 
			
		||||
export function focus_topic_search_filter(): void {
 | 
			
		||||
    popovers.hide_all();
 | 
			
		||||
    sidebar_ui.show_left_sidebar();
 | 
			
		||||
    const $filter = $("#left-sidebar-filter-topic-input").expectOne();
 | 
			
		||||
    const $filter = $("#topic_filter_query");
 | 
			
		||||
    $filter.trigger("focus");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -344,7 +352,11 @@ export class TopicListWidget {
 | 
			
		||||
 | 
			
		||||
function filter_topics_left_sidebar(topic_names: string[]): string[] {
 | 
			
		||||
    const search_term = get_left_sidebar_topic_search_term();
 | 
			
		||||
    return topic_list_data.filter_topics_by_search_term(topic_names, search_term);
 | 
			
		||||
    return topic_list_data.filter_topics_by_search_term(
 | 
			
		||||
        topic_names,
 | 
			
		||||
        search_term,
 | 
			
		||||
        get_typeahead_search_term(),
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class LeftSidebarTopicListWidget extends TopicListWidget {
 | 
			
		||||
@@ -362,11 +374,14 @@ export class LeftSidebarTopicListWidget extends TopicListWidget {
 | 
			
		||||
 | 
			
		||||
export function clear_topic_search(e: JQuery.Event): void {
 | 
			
		||||
    e.stopPropagation();
 | 
			
		||||
    const $input = $("#left-sidebar-filter-topic-input");
 | 
			
		||||
    const $input = $("#topic_filter_query");
 | 
			
		||||
    if ($input.length > 0) {
 | 
			
		||||
        $input.val("");
 | 
			
		||||
        $input.text("");
 | 
			
		||||
        $input.trigger("blur");
 | 
			
		||||
 | 
			
		||||
        search_pill_widget?.clear(true);
 | 
			
		||||
        update_clear_button();
 | 
			
		||||
 | 
			
		||||
        // Since this changes the contents of the search input, we
 | 
			
		||||
        // need to rerender the topic list.
 | 
			
		||||
        const stream_ids = [...active_widgets.keys()];
 | 
			
		||||
@@ -467,6 +482,7 @@ export function zoom_in(): void {
 | 
			
		||||
            // position since we just added some topics to the list which moved user
 | 
			
		||||
            // to a different position anyway.
 | 
			
		||||
            left_sidebar_scroll_zoomed_in_topic_into_view();
 | 
			
		||||
            topic_state_typeahead?.lookup(true);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -478,12 +494,123 @@ export function zoom_in(): void {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function get_left_sidebar_topic_search_term(): string {
 | 
			
		||||
    const $filter = $<HTMLInputElement>("input#left-sidebar-filter-topic-input");
 | 
			
		||||
    const filter_val = $filter.val();
 | 
			
		||||
    if (filter_val === undefined) {
 | 
			
		||||
        return "";
 | 
			
		||||
    return $("#left-sidebar-filter-topic-input .input").text().trim();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function get_typeahead_search_term(): string {
 | 
			
		||||
    const $pills = $("#left-sidebar-filter-topic-input .pill");
 | 
			
		||||
    const value = $pills.find(".pill-value").text().trim();
 | 
			
		||||
    return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function set_search_bar_text(text: string): void {
 | 
			
		||||
    const $input = $("#topic_filter_query");
 | 
			
		||||
    $input.text(text);
 | 
			
		||||
    $input.trigger("input");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const filter_options = new Map<string, string>([
 | 
			
		||||
    [$t({defaultMessage: "Unresolved topics"}), "-is:resolved"],
 | 
			
		||||
    [$t({defaultMessage: "Resolved topics"}), "is:resolved"],
 | 
			
		||||
    [$t({defaultMessage: "All topics"}), ""],
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
export function update_clear_button(): void {
 | 
			
		||||
    const $filter_query = $("#topic_filter_query");
 | 
			
		||||
    const $clear_button = $("#clear_search_topic_button");
 | 
			
		||||
    if (get_left_sidebar_topic_search_term() === "" && get_typeahead_search_term() === "") {
 | 
			
		||||
        $clear_button.css("visibility", "hidden");
 | 
			
		||||
        // When we use backspace to clear the content of the search box,
 | 
			
		||||
        // a <br> tag is left inside it, preventing the data-placeholder
 | 
			
		||||
        // value from reappearing as the element never becomes truly empty.
 | 
			
		||||
        // Therefore, we manually set the text to empty.
 | 
			
		||||
        $filter_query.empty();
 | 
			
		||||
    } else {
 | 
			
		||||
        $clear_button.css("visibility", "visible");
 | 
			
		||||
    }
 | 
			
		||||
    return filter_val.trim();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function setup_topic_search_typeahead(): void {
 | 
			
		||||
    const $input = $("#topic_filter_query");
 | 
			
		||||
    const $pill_container = $("#left-sidebar-filter-topic-input");
 | 
			
		||||
 | 
			
		||||
    if ($input.length === 0 || $pill_container.length === 0) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    search_pill_widget = search_pill.create_pills($pill_container);
 | 
			
		||||
 | 
			
		||||
    const typeahead_input: TypeaheadInputElement = {
 | 
			
		||||
        $element: $input,
 | 
			
		||||
        type: "contenteditable",
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const options = {
 | 
			
		||||
        items: filter_options.size,
 | 
			
		||||
        source() {
 | 
			
		||||
            const stream_id = active_stream_id();
 | 
			
		||||
            assert(stream_id !== undefined);
 | 
			
		||||
 | 
			
		||||
            if (!stream_topic_history.stream_has_locally_available_resolved_topics(stream_id)) {
 | 
			
		||||
                return [];
 | 
			
		||||
            }
 | 
			
		||||
            const $pills = $("#left-sidebar-filter-topic-input .pill");
 | 
			
		||||
            if ($pills.length > 0) {
 | 
			
		||||
                return [];
 | 
			
		||||
            }
 | 
			
		||||
            return [...filter_options.keys()];
 | 
			
		||||
        },
 | 
			
		||||
        highlighter_html(item: string) {
 | 
			
		||||
            return typeahead_helper.render_topic_state(item);
 | 
			
		||||
        },
 | 
			
		||||
        matcher(item: string, query: string) {
 | 
			
		||||
            return item.toLowerCase().includes(query.toLowerCase());
 | 
			
		||||
        },
 | 
			
		||||
        sorter(items: string[]) {
 | 
			
		||||
            return items;
 | 
			
		||||
        },
 | 
			
		||||
        updater(item: string) {
 | 
			
		||||
            const value = filter_options.get(item)!;
 | 
			
		||||
            assert(search_pill_widget !== null);
 | 
			
		||||
            search_pill_widget.clear(true);
 | 
			
		||||
            search_pill_widget.appendValue(value);
 | 
			
		||||
            set_search_bar_text("");
 | 
			
		||||
            $input.trigger("focus");
 | 
			
		||||
            return get_left_sidebar_topic_search_term();
 | 
			
		||||
        },
 | 
			
		||||
        // Prevents key events from propagating to other handlers or triggering default browser actions.
 | 
			
		||||
        stopAdvance: true,
 | 
			
		||||
        // Use dropup, to match compose typeahead.
 | 
			
		||||
        dropup: true,
 | 
			
		||||
        // Display typeahead menu when input gains focus and is empty.
 | 
			
		||||
        helpOnEmptyStrings: true,
 | 
			
		||||
        // Prevents displaying the typeahead menu when a pill is deleted via backspace.
 | 
			
		||||
        hideOnEmptyAfterBackspace: true,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    topic_state_typeahead = new Typeahead(typeahead_input, options);
 | 
			
		||||
 | 
			
		||||
    $input.on("keydown", (e: JQuery.KeyDownEvent) => {
 | 
			
		||||
        if (e.key === "Enter") {
 | 
			
		||||
            e.preventDefault();
 | 
			
		||||
            e.stopPropagation();
 | 
			
		||||
            $input.addClass("shake");
 | 
			
		||||
        } else if (e.key === ",") {
 | 
			
		||||
            e.stopPropagation();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    search_pill_widget.onPillRemove(() => {
 | 
			
		||||
        update_clear_button();
 | 
			
		||||
        const stream_id = active_stream_id();
 | 
			
		||||
        if (stream_id !== undefined) {
 | 
			
		||||
            const widget = active_widgets.get(stream_id);
 | 
			
		||||
            if (widget) {
 | 
			
		||||
                widget.build();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function initialize({
 | 
			
		||||
@@ -522,5 +649,8 @@ export function initialize({
 | 
			
		||||
        const stream_id = active_stream_id();
 | 
			
		||||
        assert(stream_id !== undefined);
 | 
			
		||||
        active_widgets.get(stream_id)?.build();
 | 
			
		||||
        update_clear_button();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    update_clear_button();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -156,19 +156,31 @@ type TopicListInfo = {
 | 
			
		||||
    more_topics_unread_count_muted: boolean;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function filter_topics_by_search_term(topic_names: string[], search_term: string): string[] {
 | 
			
		||||
    if (search_term === "") {
 | 
			
		||||
export function filter_topics_by_search_term(
 | 
			
		||||
    topic_names: string[],
 | 
			
		||||
    search_term: string,
 | 
			
		||||
    topics_state = "",
 | 
			
		||||
): string[] {
 | 
			
		||||
    if (search_term === "" && topics_state === "") {
 | 
			
		||||
        return topic_names;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const word_separator_regex = /[\s/:_-]/; // Use -, _, :, / as word separators in addition to spaces.
 | 
			
		||||
    const empty_string_topic_display_name = util.get_final_topic_display_name("");
 | 
			
		||||
    return util.filter_by_word_prefix_match(
 | 
			
		||||
    topic_names = util.filter_by_word_prefix_match(
 | 
			
		||||
        topic_names,
 | 
			
		||||
        search_term,
 | 
			
		||||
        (topic) => (topic === "" ? empty_string_topic_display_name : topic),
 | 
			
		||||
        word_separator_regex,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (topics_state === "is: resolved") {
 | 
			
		||||
        topic_names = topic_names.filter((name) => resolved_topic.is_resolved(name));
 | 
			
		||||
    } else if (topics_state === "-is: resolved") {
 | 
			
		||||
        topic_names = topic_names.filter((name) => !resolved_topic.is_resolved(name));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return topic_names;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function get_list_info(
 | 
			
		||||
 
 | 
			
		||||
@@ -176,6 +176,15 @@ export function rewire_render_person(value: typeof render_person): void {
 | 
			
		||||
    render_person = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export let render_topic_state = (state: string): string =>
 | 
			
		||||
    render_typeahead_item({
 | 
			
		||||
        primary: state,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
export function rewire_render_topic_state(value: typeof render_topic_state): void {
 | 
			
		||||
    render_topic_state = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export let render_user_group = (user_group: {name: string; description: string}): string =>
 | 
			
		||||
    render_typeahead_item({
 | 
			
		||||
        primary: user_groups.get_display_group_name(user_group.name),
 | 
			
		||||
 
 | 
			
		||||
@@ -1332,11 +1332,24 @@ li.top_left_scheduled_messages {
 | 
			
		||||
    white-space: nowrap;
 | 
			
		||||
    text-overflow: ellipsis;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    gap: 0.125em; /* 2px at 16px em */
 | 
			
		||||
    background-color: var(--color-background-active-narrow-filter);
 | 
			
		||||
    font-weight: 400;
 | 
			
		||||
 | 
			
		||||
    .input:empty::before {
 | 
			
		||||
        color: var(--color-text-placeholder);
 | 
			
		||||
        content: attr(data-placeholder);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .input {
 | 
			
		||||
        flex-grow: 1;
 | 
			
		||||
        min-width: 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#left-sidebar-filter-topic-input:placeholder-shown
 | 
			
		||||
    + #clear_search_topic_button {
 | 
			
		||||
#clear_search_topic_button {
 | 
			
		||||
    visibility: hidden;
 | 
			
		||||
    height: 2em; /* 32px at 16px/1em */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.searching-for-more-topics img {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,10 @@
 | 
			
		||||
<div class="topic_search_section filter-topics left-sidebar-filter-row">
 | 
			
		||||
    <input class="topic-list-filter home-page-input filter_text_input" id="left-sidebar-filter-topic-input" type="text" autocomplete="off" placeholder="{{t 'Filter topics'}}" />
 | 
			
		||||
    <div class="topic-list-filter home-page-input filter_text_input pill-container" id="left-sidebar-filter-topic-input">
 | 
			
		||||
        <div class="input" contenteditable="true" id="topic_filter_query"
 | 
			
		||||
          data-placeholder="{{t 'Filter topics' }}">
 | 
			
		||||
            {{~! Squash whitespace so that placeholder is displayed when empty. ~}}
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <button type="button" class="clear_search_button" id="clear_search_topic_button">
 | 
			
		||||
        <i class="zulip-icon zulip-icon-close" aria-hidden="true"></i>
 | 
			
		||||
    </button>
 | 
			
		||||
 
 | 
			
		||||
@@ -38,6 +38,7 @@ let sort_stream_or_group_members_options_called = false;
 | 
			
		||||
const $fake_rendered_person = $.create("fake-rendered-person");
 | 
			
		||||
const $fake_rendered_stream = $.create("fake-rendered-stream");
 | 
			
		||||
const $fake_rendered_group = $.create("fake-rendered-group");
 | 
			
		||||
const $fake_rendered_topic_state = $.create("fake-rendered-topic-state");
 | 
			
		||||
 | 
			
		||||
function override_typeahead_helper({mock_template, override_rewire}) {
 | 
			
		||||
    mock_template("typeahead_list_item.hbs", false, (args) => {
 | 
			
		||||
@@ -422,6 +423,21 @@ run_test("set_up_user_group", ({mock_template, override, override_rewire}) => {
 | 
			
		||||
    assert.ok(input_pill_typeahead_called);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
run_test("render_topic_state", ({override_rewire}) => {
 | 
			
		||||
    override_rewire(typeahead_helper, "render_typeahead_item", (args) => {
 | 
			
		||||
        assert.equal(args.primary, "Resolved");
 | 
			
		||||
        return $fake_rendered_topic_state;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const result = typeahead_helper.render_topic_state("Resolved");
 | 
			
		||||
    assert.equal(result, $fake_rendered_topic_state);
 | 
			
		||||
 | 
			
		||||
    override_rewire(typeahead_helper, "render_topic_state", (state) => `${state}`);
 | 
			
		||||
 | 
			
		||||
    const new_result = typeahead_helper.render_topic_state("Unresolved");
 | 
			
		||||
    assert.equal(new_result, "Unresolved");
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
run_test("set_up_combined", ({mock_template, override, override_rewire}) => {
 | 
			
		||||
    override_typeahead_helper({mock_template, override_rewire});
 | 
			
		||||
    mock_template("input_pill.hbs", true, (_data, html) => html);
 | 
			
		||||
 
 | 
			
		||||
@@ -389,6 +389,8 @@ function elem($obj) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
test_ui("zoom_in_and_zoom_out", ({mock_template}) => {
 | 
			
		||||
    topic_list.setup_topic_search_typeahead = noop;
 | 
			
		||||
 | 
			
		||||
    const $label1 = $.create("label1 stub");
 | 
			
		||||
    const $label2 = $.create("label2 stub");
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -279,6 +279,26 @@ test("test_stream_has_topics", () => {
 | 
			
		||||
    assert.equal(stream_topic_history.stream_has_topics(stream_id), true);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test("test_stream_has_resolved_topics", () => {
 | 
			
		||||
    const stream_id = 89;
 | 
			
		||||
 | 
			
		||||
    assert.equal(
 | 
			
		||||
        stream_topic_history.stream_has_locally_available_resolved_topics(stream_id),
 | 
			
		||||
        false,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    stream_topic_history.add_message({
 | 
			
		||||
        stream_id,
 | 
			
		||||
        message_id: 889,
 | 
			
		||||
        topic_name: "✔ whatever",
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    assert.equal(
 | 
			
		||||
        stream_topic_history.stream_has_locally_available_resolved_topics(stream_id),
 | 
			
		||||
        true,
 | 
			
		||||
    );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test("server_history_end_to_end", () => {
 | 
			
		||||
    stream_topic_history.reset();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -57,6 +57,28 @@ function get_list_info(zoom, search) {
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
test("filter_topics_by_search_term with resolved topics_state", () => {
 | 
			
		||||
    const topic_names = ["topic 1", "✔ resolved topic", "topic 2"];
 | 
			
		||||
    const search_term = "";
 | 
			
		||||
 | 
			
		||||
    // Filter for resolved topics.
 | 
			
		||||
    let topics_state = "is: resolved";
 | 
			
		||||
 | 
			
		||||
    let result = topic_list_data.filter_topics_by_search_term(
 | 
			
		||||
        topic_names,
 | 
			
		||||
        search_term,
 | 
			
		||||
        topics_state,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    assert.deepEqual(result, ["✔ resolved topic"]);
 | 
			
		||||
 | 
			
		||||
    // Filter for unresolved topics.
 | 
			
		||||
    topics_state = "-is: resolved";
 | 
			
		||||
    result = topic_list_data.filter_topics_by_search_term(topic_names, search_term, topics_state);
 | 
			
		||||
 | 
			
		||||
    assert.deepEqual(result, ["topic 1", "topic 2"]);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function test(label, f) {
 | 
			
		||||
    run_test(label, (helpers) => {
 | 
			
		||||
        stream_topic_history.reset();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user