mirror of
https://github.com/zulip/zulip.git
synced 2025-10-22 20:42:14 +00:00
topic-filter: Replace usage of search_pill.
Add topic_filter_pill to use for topic filtering instead of search_pill. Fixes part of #35284.
This commit is contained in:
committed by
Tim Abbott
parent
15f2c65986
commit
6e43d34a34
@@ -176,6 +176,10 @@ IGNORED_PHRASES = [
|
||||
r"archived",
|
||||
# Used in pills for deactivated users.
|
||||
r"deactivated",
|
||||
# Used in pills for resolved topics.
|
||||
r"resolved",
|
||||
# Used in pills for unresolved topics.
|
||||
r"unresolved",
|
||||
# This is a reference to a setting/secret and should be lowercase.
|
||||
r"zulip_org_id",
|
||||
# These are custom time unit options for modal dropdowns
|
||||
|
@@ -271,6 +271,7 @@ EXEMPT_FILES = make_set(
|
||||
"web/src/timerender.ts",
|
||||
"web/src/tippyjs.ts",
|
||||
"web/src/todo_widget.ts",
|
||||
"web/src/topic_filter_pill.ts",
|
||||
"web/src/topic_list.ts",
|
||||
"web/src/topic_popover.ts",
|
||||
"web/src/typing.ts",
|
||||
|
68
web/src/topic_filter_pill.ts
Normal file
68
web/src/topic_filter_pill.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import render_input_pill from "../templates/input_pill.hbs";
|
||||
|
||||
import {$t} from "./i18n.ts";
|
||||
import type {InputPillConfig, InputPillContainer} from "./input_pill.ts";
|
||||
import * as input_pill from "./input_pill.ts";
|
||||
|
||||
export type TopicFilterPill = {
|
||||
type: "topic_filter";
|
||||
label: string;
|
||||
syntax: string;
|
||||
};
|
||||
|
||||
export type TopicFilterPillWidget = InputPillContainer<TopicFilterPill>;
|
||||
|
||||
export const filter_options: TopicFilterPill[] = [
|
||||
{
|
||||
type: "topic_filter",
|
||||
label: $t({defaultMessage: "unresolved"}),
|
||||
syntax: "-is:resolved",
|
||||
},
|
||||
{
|
||||
type: "topic_filter",
|
||||
label: $t({defaultMessage: "resolved"}),
|
||||
syntax: "is:resolved",
|
||||
},
|
||||
];
|
||||
|
||||
export function create_item_from_syntax(
|
||||
syntax: string,
|
||||
current_items: TopicFilterPill[],
|
||||
): TopicFilterPill | undefined {
|
||||
const existing_syntaxes = current_items.map((item) => item.syntax);
|
||||
if (existing_syntaxes.includes(syntax)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Find the matching filter option
|
||||
const filter_option = filter_options.find((option) => option.syntax === syntax);
|
||||
if (!filter_option) {
|
||||
return undefined;
|
||||
}
|
||||
return filter_option;
|
||||
}
|
||||
|
||||
export function get_syntax_from_item(item: TopicFilterPill): string {
|
||||
return item.syntax;
|
||||
}
|
||||
|
||||
export function create_pills(
|
||||
$pill_container: JQuery,
|
||||
pill_config?: InputPillConfig,
|
||||
): TopicFilterPillWidget {
|
||||
const pill_container = input_pill.create({
|
||||
$container: $pill_container,
|
||||
pill_config,
|
||||
create_item_from_text: create_item_from_syntax,
|
||||
get_text_from_item: get_syntax_from_item,
|
||||
get_display_value_from_item: get_syntax_from_item,
|
||||
generate_pill_html(item: TopicFilterPill, disabled?: boolean) {
|
||||
return render_input_pill({
|
||||
display_value: item.label,
|
||||
disabled,
|
||||
});
|
||||
},
|
||||
});
|
||||
pill_container.createPillonPaste(() => false);
|
||||
return pill_container;
|
||||
}
|
@@ -10,43 +10,26 @@ 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";
|
||||
import type {StreamSubscription} from "./sub_store.ts";
|
||||
import * as sub_store from "./sub_store.ts";
|
||||
import * as topic_filter_pill from "./topic_filter_pill.ts";
|
||||
import type {TopicFilterPill, TopicFilterPillWidget} from "./topic_filter_pill.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";
|
||||
|
||||
type TopicFilterPill = {
|
||||
label: string;
|
||||
syntax: string;
|
||||
};
|
||||
|
||||
const filter_options: TopicFilterPill[] = [
|
||||
{
|
||||
label: $t({defaultMessage: "Unresolved topics"}),
|
||||
syntax: "-is:resolved",
|
||||
},
|
||||
{
|
||||
label: $t({defaultMessage: "Resolved topics"}),
|
||||
syntax: "is:resolved",
|
||||
},
|
||||
];
|
||||
|
||||
/* Track all active widgets with a Map by stream_id. We have at max
|
||||
one for now, but we may eventually allow multiple streams to be
|
||||
expanded. */
|
||||
const active_widgets = new Map<number, LeftSidebarTopicListWidget>();
|
||||
export let search_pill_widget: SearchPillWidget | null = null;
|
||||
export let topic_filter_pill_widget: TopicFilterPillWidget | null = null;
|
||||
export let topic_state_typeahead: Typeahead<TopicFilterPill> | undefined;
|
||||
|
||||
// We know whether we're zoomed or not.
|
||||
@@ -366,7 +349,7 @@ function filter_topics_left_sidebar(topic_names: string[]): string[] {
|
||||
return topic_list_data.filter_topics_by_search_term(
|
||||
topic_names,
|
||||
search_term,
|
||||
get_typeahead_search_term(),
|
||||
get_typeahead_search_pills_syntax(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -386,10 +369,10 @@ export class LeftSidebarTopicListWidget extends TopicListWidget {
|
||||
export function clear_topic_search(e: JQuery.Event): void {
|
||||
e.stopPropagation();
|
||||
|
||||
search_pill_widget?.clear(true);
|
||||
topic_filter_pill_widget?.clear(true);
|
||||
|
||||
const $input = $("#topic_filter_query");
|
||||
// Since the `clear` function of the search_pill_widget
|
||||
// Since the `clear` function of the topic_filter_pill_widget
|
||||
// takes care of clearing both the text content and the
|
||||
// pills, we just need to trigger an input event on the
|
||||
// contenteditable element to reset the topic list via
|
||||
@@ -499,10 +482,24 @@ export function get_left_sidebar_topic_search_term(): string {
|
||||
return $("#topic_filter_query").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;
|
||||
export function get_typeahead_search_pills_syntax(): string {
|
||||
const pills = topic_filter_pill_widget?.items() ?? [];
|
||||
|
||||
if (pills.length === 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// For now, there is only one pill in the left sidebar topic search input.
|
||||
// This is because we only allow one topic filter pill at a time.
|
||||
// If we allow multiple pills in the future, we may need to
|
||||
// change this logic to return the syntax of all pills.
|
||||
if (pills.length > 1) {
|
||||
blueslip.warn("Multiple pills found in left sidebar topic search input.");
|
||||
}
|
||||
|
||||
// We can remove this assumption once we allow multiple pills and hence update the
|
||||
// callers of this function to handle multiple pills and implement the search accordingly.
|
||||
return pills[0]!.syntax;
|
||||
}
|
||||
|
||||
function set_search_bar_text(text: string): void {
|
||||
@@ -519,7 +516,7 @@ export function setup_topic_search_typeahead(): void {
|
||||
return;
|
||||
}
|
||||
|
||||
search_pill_widget = search_pill.create_pills($pill_container);
|
||||
topic_filter_pill_widget = topic_filter_pill.create_pills($pill_container);
|
||||
|
||||
const typeahead_input: TypeaheadInputElement = {
|
||||
$element: $input,
|
||||
@@ -538,7 +535,7 @@ export function setup_topic_search_typeahead(): void {
|
||||
if ($pills.length > 0) {
|
||||
return [];
|
||||
}
|
||||
return [...filter_options];
|
||||
return [...topic_filter_pill.filter_options];
|
||||
},
|
||||
item_html(item: TopicFilterPill) {
|
||||
return typeahead_helper.render_topic_state(item.label);
|
||||
@@ -559,9 +556,9 @@ export function setup_topic_search_typeahead(): void {
|
||||
return items;
|
||||
},
|
||||
updater(item: TopicFilterPill) {
|
||||
assert(search_pill_widget !== null);
|
||||
search_pill_widget.clear(true);
|
||||
search_pill_widget.appendValue(item.syntax);
|
||||
assert(topic_filter_pill_widget !== null);
|
||||
topic_filter_pill_widget.clear(true);
|
||||
topic_filter_pill_widget.appendValue(item.syntax);
|
||||
set_search_bar_text("");
|
||||
$input.trigger("focus");
|
||||
return get_left_sidebar_topic_search_term();
|
||||
@@ -585,7 +582,7 @@ export function setup_topic_search_typeahead(): void {
|
||||
}
|
||||
});
|
||||
|
||||
search_pill_widget.onPillRemove(() => {
|
||||
topic_filter_pill_widget.onPillRemove(() => {
|
||||
const stream_id = active_stream_id();
|
||||
if (stream_id !== undefined) {
|
||||
const widget = active_widgets.get(stream_id);
|
||||
|
@@ -174,9 +174,9 @@ export function filter_topics_by_search_term(
|
||||
word_separator_regex,
|
||||
);
|
||||
|
||||
if (topics_state === "is: resolved") {
|
||||
if (topics_state === "is:resolved") {
|
||||
topic_names = topic_names.filter((name) => resolved_topic.is_resolved(name));
|
||||
} else if (topics_state === "-is: resolved") {
|
||||
} else if (topics_state === "-is:resolved") {
|
||||
topic_names = topic_names.filter((name) => !resolved_topic.is_resolved(name));
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,8 @@
|
||||
<div class='pill {{#if deactivated}} deactivated-pill {{/if}}'{{#if user_id}}data-user-id="{{user_id}}"{{/if}}{{#if group_id}}data-user-group-id="{{group_id}}"{{/if}}{{#if stream_id}}data-stream-id="{{stream_id}}"{{/if}} tabindex=0>
|
||||
<div class='pill {{#if deactivated}} deactivated-pill {{/if~}}'
|
||||
{{~#if user_id}}data-user-id="{{user_id}}"{{/if~}}
|
||||
{{~#if group_id}}data-user-group-id="{{group_id}}"{{/if~}}
|
||||
{{~#if stream_id}}data-stream-id="{{stream_id}}"{{/if~}}
|
||||
{{~#if data_syntax}}data-syntax="{{data_syntax}}"{{/if}} tabindex=0>
|
||||
{{#if has_image}}
|
||||
<img class="pill-image" src="{{img_src}}" />
|
||||
<div class="pill-image-border"></div>
|
||||
|
@@ -62,7 +62,7 @@ test("filter_topics_by_search_term with resolved topics_state", () => {
|
||||
const search_term = "";
|
||||
|
||||
// Filter for resolved topics.
|
||||
let topics_state = "is: resolved";
|
||||
let topics_state = "is:resolved";
|
||||
|
||||
let result = topic_list_data.filter_topics_by_search_term(
|
||||
topic_names,
|
||||
@@ -73,7 +73,7 @@ test("filter_topics_by_search_term with resolved topics_state", () => {
|
||||
assert.deepEqual(result, ["✔ resolved topic"]);
|
||||
|
||||
// Filter for unresolved topics.
|
||||
topics_state = "-is: resolved";
|
||||
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"]);
|
||||
|
Reference in New Issue
Block a user