search suggestion: Consistently show user pills in typeahead.

Fixes #23365.
This commit is contained in:
evykassirer
2024-06-13 15:10:26 -07:00
committed by Tim Abbott
parent 0899b621d3
commit ee2852ede1
3 changed files with 69 additions and 17 deletions

View File

@@ -1,3 +1,4 @@
import Handlebars from "handlebars/runtime";
import _ from "lodash";
import assert from "minimalistic-assert";
@@ -10,7 +11,9 @@ import * as message_parser from "./message_parser";
import * as message_store from "./message_store";
import type {Message} from "./message_store";
import {page_params} from "./page_params";
import type {User} from "./people";
import * as people from "./people";
import type {UserPillItem} from "./search_suggestion";
import {realm} from "./state_data";
import type {NarrowTerm} from "./state_data";
import * as stream_data from "./stream_data";
@@ -54,8 +57,17 @@ type Part =
type: "prefix_for_operator";
prefix_for_operator: string;
operand: string;
}
| {
type: "user_pill";
operator: string;
users: ValidOrInvalidUser[];
};
type ValidOrInvalidUser =
| {valid_user: true; user_pill_context: UserPillItem}
| {valid_user: false; operand: string};
// TODO: When "stream" is renamed to "channel", these placeholders
// should be removed, or replaced with helper functions similar
// to util.is_topic_synonym.
@@ -254,6 +266,28 @@ function message_matches_search_term(message: Message, operator: string, operand
return true; // unknown operators return true (effectively ignored)
}
// For when we don't need to do highlighting
export function create_user_pill_context(user: User): UserPillItem {
const avatar_url = people.small_avatar_url_for_person(user);
return {
id: user.user_id,
display_value: new Handlebars.SafeString(user.full_name),
has_image: true,
img_src: avatar_url,
should_add_guest_user_indicator: people.should_add_guest_user_indicator(user.user_id),
};
}
const USER_OPERATORS = new Set([
"dm-including",
"dm",
"sender",
"from",
"pm-with",
"group-pm-with",
]);
export class Filter {
_terms: NarrowTerm[];
_sub?: StreamSubscription | undefined;
@@ -371,9 +405,7 @@ export class Filter {
static decodeOperand(encoded: string, operator: string): string {
encoded = encoded.replaceAll('"', "");
if (
!["dm-including", "dm", "sender", "from", "pm-with", "group-pm-with"].includes(operator)
) {
if (!USER_OPERATORS.has(operator)) {
encoded = encoded.replaceAll("+", " ");
}
return util.robust_url_decode(encoded).trim();
@@ -640,6 +672,27 @@ export class Filter {
canonicalized_operator,
term.negated,
);
if (USER_OPERATORS.has(canonicalized_operator)) {
const user_emails = operand.split(",");
const users: ValidOrInvalidUser[] = user_emails.map((email) => {
const person = people.get_by_email(email);
if (person === undefined) {
return {
valid_user: false,
operand: email,
};
}
return {
valid_user: true,
user_pill_context: create_user_pill_context(person),
};
});
return {
type: "user_pill",
operator: prefix_for_operator,
users,
};
}
if (prefix_for_operator !== "") {
return {
type: "prefix_for_operator",

View File

@@ -5,7 +5,7 @@ import render_user_pill from "../templates/user_pill.hbs";
import * as common from "./common";
import * as direct_message_group_data from "./direct_message_group_data";
import {Filter} from "./filter";
import {Filter, create_user_pill_context} from "./filter";
import * as narrow_state from "./narrow_state";
import {page_params} from "./page_params";
import * as people from "./people";
@@ -16,7 +16,7 @@ import * as stream_topic_history from "./stream_topic_history";
import * as stream_topic_history_util from "./stream_topic_history_util";
import * as typeahead_helper from "./typeahead_helper";
type UserPillItem = {
export type UserPillItem = {
id: number;
display_value: Handlebars.SafeString;
has_image: boolean;
@@ -41,18 +41,6 @@ export type Suggestion = {
}
);
function create_user_pill_context(user: User): UserPillItem {
const avatar_url = people.small_avatar_url_for_person(user);
return {
id: user.user_id,
display_value: new Handlebars.SafeString(user.full_name),
has_image: true,
img_src: avatar_url,
should_add_guest_user_indicator: people.should_add_guest_user_indicator(user.user_id),
};
}
export const max_num_of_search_results = 12;
function channel_matches_query(channel_name: string, q: string): boolean {

View File

@@ -14,6 +14,17 @@
{{~!-- squash whitespace --~}}
{{this.prefix_for_operator}} {{this.operand}}
{{~!-- squash whitespace --~}}
{{else if (eq this.type "user_pill")}}
{{~!-- squash whitespace --~}}
{{this.operator}}
{{~#each this.users}}
{{#if this.valid_user}}
{{> user_pill}}
{{else}}
{{this.operand}}
{{/if}}
{{~/each~}}
{{~!-- squash whitespace --~}}
{{else if (eq this.type "is_operator")}}
{{#if (eq this.operand "mentioned")}}
{{~!-- squash whitespace --~}}