mirror of https://github.com/zulip/zulip.git
search: Create a template for search descriptions.
This commit is contained in:
parent
6346110b56
commit
8f5305a4ce
|
@ -1,7 +1,7 @@
|
|||
import Handlebars from "handlebars/runtime";
|
||||
import _ from "lodash";
|
||||
|
||||
import * as resolved_topic from "../shared/src/resolved_topic";
|
||||
import render_search_description from "../templates/search_description.hbs";
|
||||
|
||||
import * as hash_util from "./hash_util";
|
||||
import {$t} from "./i18n";
|
||||
|
@ -1030,34 +1030,14 @@ export class Filter {
|
|||
return "";
|
||||
}
|
||||
|
||||
static describe_is_operator(operator) {
|
||||
const verb = operator.negated ? "exclude " : "";
|
||||
const operand = operator.operand;
|
||||
|
||||
switch (operand) {
|
||||
case "starred":
|
||||
case "alerted":
|
||||
case "unread":
|
||||
return verb + operand + " messages";
|
||||
case "mentioned":
|
||||
return verb + "@-mentions";
|
||||
case "dm":
|
||||
case "private":
|
||||
return verb + "direct messages";
|
||||
case "resolved":
|
||||
return verb + "topics marked as resolved";
|
||||
}
|
||||
|
||||
return "invalid " + operand + " operand for is operator";
|
||||
}
|
||||
|
||||
// Convert a list of operators to a human-readable description.
|
||||
static describe_unescaped(operators) {
|
||||
if (operators.length === 0) {
|
||||
return "all messages";
|
||||
}
|
||||
static parts_for_describe(operators) {
|
||||
const parts = [];
|
||||
|
||||
let parts = [];
|
||||
if (operators.length === 0) {
|
||||
parts.push({type: "plain_text", content: "all messages"});
|
||||
return parts;
|
||||
}
|
||||
|
||||
if (operators.length >= 2) {
|
||||
const is = (term, expected) => term.operator === expected && !term.negated;
|
||||
|
@ -1065,8 +1045,11 @@ export class Filter {
|
|||
if (is(operators[0], "stream") && is(operators[1], "topic")) {
|
||||
const stream = operators[0].operand;
|
||||
const topic = operators[1].operand;
|
||||
const part = "stream " + stream + " > " + topic;
|
||||
parts = [part];
|
||||
parts.push({
|
||||
type: "stream_topic",
|
||||
stream,
|
||||
topic,
|
||||
});
|
||||
operators = operators.slice(2);
|
||||
}
|
||||
}
|
||||
|
@ -1075,7 +1058,12 @@ export class Filter {
|
|||
const operand = elem.operand;
|
||||
const canonicalized_operator = Filter.canonicalize_operator(elem.operator);
|
||||
if (canonicalized_operator === "is") {
|
||||
return Filter.describe_is_operator(elem);
|
||||
const verb = elem.negated ? "exclude " : "";
|
||||
return {
|
||||
type: "is_operator",
|
||||
verb,
|
||||
operand,
|
||||
};
|
||||
}
|
||||
if (canonicalized_operator === "has") {
|
||||
// search_suggestion.get_suggestions takes care that this message will
|
||||
|
@ -1089,7 +1077,10 @@ export class Filter {
|
|||
"attachments",
|
||||
];
|
||||
if (!valid_has_operands.includes(operand)) {
|
||||
return "invalid " + operand + " operand for has operator";
|
||||
return {
|
||||
type: "invalid_has",
|
||||
operand,
|
||||
};
|
||||
}
|
||||
}
|
||||
const prefix_for_operator = Filter.operator_to_prefix(
|
||||
|
@ -1097,15 +1088,24 @@ export class Filter {
|
|||
elem.negated,
|
||||
);
|
||||
if (prefix_for_operator !== "") {
|
||||
return prefix_for_operator + " " + operand;
|
||||
return {
|
||||
type: "prefix_for_operator",
|
||||
prefix_for_operator,
|
||||
operand,
|
||||
};
|
||||
}
|
||||
return "unknown operator";
|
||||
return {
|
||||
type: "plain_text",
|
||||
content: "unknown operator",
|
||||
};
|
||||
});
|
||||
return [...parts, ...more_parts].join(", ");
|
||||
return [...parts, ...more_parts];
|
||||
}
|
||||
|
||||
static search_description_as_html(operators) {
|
||||
return Handlebars.Utils.escapeExpression(Filter.describe_unescaped(operators));
|
||||
return render_search_description({
|
||||
parts: Filter.parts_for_describe(operators),
|
||||
});
|
||||
}
|
||||
|
||||
static is_spectator_compatible(ops) {
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
{{~#each parts ~}}
|
||||
|
||||
{{#if (eq this.type "plain_text")~}}
|
||||
{{~this.content~}}
|
||||
{{else if (eq this.type "stream_topic")}}
|
||||
{{~!-- squash whitespace --~}}
|
||||
stream {{this.stream}} > {{this.topic}}
|
||||
{{~!-- squash whitespace --~}}
|
||||
{{else if (eq this.type "invalid_has")}}
|
||||
{{~!-- squash whitespace --~}}
|
||||
invalid {{this.operand}} operand for has operator
|
||||
{{~!-- squash whitespace --~}}
|
||||
{{else if (eq this.type "prefix_for_operator")}}
|
||||
{{~!-- squash whitespace --~}}
|
||||
{{this.prefix_for_operator}} {{this.operand}}
|
||||
{{~!-- squash whitespace --~}}
|
||||
{{else if (eq this.type "is_operator")}}
|
||||
{{#if (eq this.operand "mentioned")}}
|
||||
{{~!-- squash whitespace --~}}
|
||||
{{this.verb}}@-mentions
|
||||
{{~!-- squash whitespace --~}}
|
||||
{{else if (or (eq this.operand "starred") (eq this.operand "alerted") (eq this.operand "unread"))}}
|
||||
{{~!-- squash whitespace --~}}
|
||||
{{this.verb}}{{this.operand}} messages
|
||||
{{~!-- squash whitespace --~}}
|
||||
{{else if (or (eq this.operand "dm") (eq this.operand "private"))}}
|
||||
{{~!-- squash whitespace --~}}
|
||||
{{this.verb}}direct messages
|
||||
{{~!-- squash whitespace --~}}
|
||||
{{else if (eq this.operand "resolved")}}
|
||||
{{~!-- squash whitespace --~}}
|
||||
{{this.verb}}topics marked as resolved
|
||||
{{~!-- squash whitespace --~}}
|
||||
{{else}}
|
||||
{{~!-- squash whitespace --~}}
|
||||
invalid {{this.operand}} operand for is operator
|
||||
{{~!-- squash whitespace --~}}
|
||||
{{~/if~}}
|
||||
{{~/if~}}
|
||||
{{~#if (not @last)~}}, {{/if~}}
|
||||
|
||||
{{~/each~}}
|
|
@ -1156,9 +1156,10 @@ test("unparse", () => {
|
|||
assert.deepEqual(Filter.unparse(operators), string);
|
||||
});
|
||||
|
||||
test("describe", () => {
|
||||
test("describe", ({mock_template}) => {
|
||||
let narrow;
|
||||
let string;
|
||||
mock_template("search_description.hbs", true, (_data, html) => html);
|
||||
|
||||
narrow = [{operator: "streams", operand: "public"}];
|
||||
string = "streams public";
|
||||
|
@ -1186,7 +1187,7 @@ test("describe", () => {
|
|||
{operator: "stream", operand: "devel"},
|
||||
{operator: "topic", operand: "JS"},
|
||||
];
|
||||
string = "stream devel > JS";
|
||||
string = "stream devel > JS";
|
||||
assert.equal(Filter.search_description_as_html(narrow), string);
|
||||
|
||||
narrow = [
|
||||
|
|
|
@ -79,7 +79,9 @@ function test(label, f) {
|
|||
});
|
||||
}
|
||||
|
||||
test("basic_get_suggestions", ({override}) => {
|
||||
test("basic_get_suggestions", ({override, mock_template}) => {
|
||||
mock_template("search_description.hbs", true, (data, html) => html);
|
||||
|
||||
const query = "fred";
|
||||
|
||||
override(narrow_state, "stream", () => "office");
|
||||
|
@ -99,7 +101,9 @@ test("basic_get_suggestions_for_spectator", () => {
|
|||
page_params.is_spectator = false;
|
||||
});
|
||||
|
||||
test("subset_suggestions", () => {
|
||||
test("subset_suggestions", ({mock_template}) => {
|
||||
mock_template("search_description.hbs", true, (_data, html) => html);
|
||||
|
||||
const query = "stream:Denmark topic:Hamlet shakespeare";
|
||||
|
||||
const suggestions = get_suggestions(query);
|
||||
|
@ -113,7 +117,9 @@ test("subset_suggestions", () => {
|
|||
assert.deepEqual(suggestions.strings, expected);
|
||||
});
|
||||
|
||||
test("dm_suggestions", ({override}) => {
|
||||
test("dm_suggestions", ({override, mock_template}) => {
|
||||
mock_template("search_description.hbs", true, (_data, html) => html);
|
||||
|
||||
let query = "is:dm";
|
||||
let suggestions = get_suggestions(query);
|
||||
let expected = [
|
||||
|
@ -248,7 +254,9 @@ test("dm_suggestions", ({override}) => {
|
|||
assert.deepEqual(suggestions.strings, expected);
|
||||
});
|
||||
|
||||
test("group_suggestions", () => {
|
||||
test("group_suggestions", ({mock_template}) => {
|
||||
mock_template("search_description.hbs", true, (_data, html) => html);
|
||||
|
||||
// Entering a comma in a "dm:" query should immediately
|
||||
// generate suggestions for the next person.
|
||||
let query = "dm:bob@zulip.com,";
|
||||
|
@ -446,7 +454,9 @@ test("empty_query_suggestions", () => {
|
|||
assert.equal(describe("has:attachment"), "Messages that contain attachments");
|
||||
});
|
||||
|
||||
test("has_suggestions", ({override}) => {
|
||||
test("has_suggestions", ({override, mock_template}) => {
|
||||
mock_template("search_description.hbs", true, (_data, html) => html);
|
||||
|
||||
// Checks that category wise suggestions are displayed instead of a single
|
||||
// default suggestion when suggesting `has` operator.
|
||||
let query = "h";
|
||||
|
@ -506,7 +516,9 @@ test("has_suggestions", ({override}) => {
|
|||
assert.deepEqual(suggestions.strings, expected);
|
||||
});
|
||||
|
||||
test("check_is_suggestions", ({override}) => {
|
||||
test("check_is_suggestions", ({override, mock_template}) => {
|
||||
mock_template("search_description.hbs", true, (_data, html) => html);
|
||||
|
||||
stream_data.add_sub({stream_id: 44, name: "devel", subscribed: true});
|
||||
stream_data.add_sub({stream_id: 77, name: "office", subscribed: true});
|
||||
override(narrow_state, "stream", () => {});
|
||||
|
@ -587,7 +599,9 @@ test("check_is_suggestions", ({override}) => {
|
|||
assert.deepEqual(suggestions.strings, expected);
|
||||
});
|
||||
|
||||
test("sent_by_me_suggestions", ({override}) => {
|
||||
test("sent_by_me_suggestions", ({override, mock_template}) => {
|
||||
mock_template("search_description.hbs", true, (_data, html) => html);
|
||||
|
||||
override(narrow_state, "stream", () => {});
|
||||
|
||||
let query = "";
|
||||
|
@ -659,7 +673,8 @@ test("sent_by_me_suggestions", ({override}) => {
|
|||
assert.deepEqual(suggestions.strings, expected);
|
||||
});
|
||||
|
||||
test("topic_suggestions", ({override}) => {
|
||||
test("topic_suggestions", ({override, mock_template}) => {
|
||||
mock_template("search_description.hbs", true, (_data, html) => html);
|
||||
let suggestions;
|
||||
let expected;
|
||||
|
||||
|
@ -703,7 +718,7 @@ test("topic_suggestions", ({override}) => {
|
|||
return suggestions.lookup_table.get(q).description_html;
|
||||
}
|
||||
assert.equal(describe("te"), "Search for te");
|
||||
assert.equal(describe("stream:office topic:team"), "Stream office > team");
|
||||
assert.equal(describe("stream:office topic:team"), "Stream office > team");
|
||||
|
||||
suggestions = get_suggestions("topic:staplers stream:office");
|
||||
expected = ["topic:staplers stream:office", "topic:staplers"];
|
||||
|
@ -783,7 +798,9 @@ test("topic_suggestions (limits)", () => {
|
|||
assert_result("z", []);
|
||||
});
|
||||
|
||||
test("whitespace_glitch", ({override}) => {
|
||||
test("whitespace_glitch", ({override, mock_template}) => {
|
||||
mock_template("search_description.hbs", true, (_data, html) => html);
|
||||
|
||||
const query = "stream:office "; // note trailing space
|
||||
|
||||
override(stream_topic_history_util, "get_server_history", () => {});
|
||||
|
@ -796,7 +813,9 @@ test("whitespace_glitch", ({override}) => {
|
|||
assert.deepEqual(suggestions.strings, expected);
|
||||
});
|
||||
|
||||
test("stream_completion", ({override}) => {
|
||||
test("stream_completion", ({override, mock_template}) => {
|
||||
mock_template("search_description.hbs", true, (_data, html) => html);
|
||||
|
||||
stream_data.add_sub({stream_id: 77, name: "office", subscribed: true});
|
||||
stream_data.add_sub({stream_id: 88, name: "dev help", subscribed: true});
|
||||
|
||||
|
@ -818,7 +837,9 @@ test("stream_completion", ({override}) => {
|
|||
assert.deepEqual(suggestions.strings, expected);
|
||||
});
|
||||
|
||||
test("people_suggestions", ({override}) => {
|
||||
test("people_suggestions", ({override, mock_template}) => {
|
||||
mock_template("search_description.hbs", true, (_data, html) => html);
|
||||
|
||||
let query = "te";
|
||||
|
||||
override(narrow_state, "stream", () => {});
|
||||
|
@ -920,7 +941,9 @@ test("people_suggestions", ({override}) => {
|
|||
assert.deepEqual(suggestions.strings, expected);
|
||||
});
|
||||
|
||||
test("operator_suggestions", ({override}) => {
|
||||
test("operator_suggestions", ({override, mock_template}) => {
|
||||
mock_template("search_description.hbs", true, (_data, html) => html);
|
||||
|
||||
override(narrow_state, "stream", () => undefined);
|
||||
|
||||
// Completed operator should return nothing
|
||||
|
@ -951,7 +974,9 @@ test("operator_suggestions", ({override}) => {
|
|||
assert.deepEqual(suggestions.strings, expected);
|
||||
});
|
||||
|
||||
test("queries_with_spaces", () => {
|
||||
test("queries_with_spaces", ({mock_template}) => {
|
||||
mock_template("search_description.hbs", true, (_data, html) => html);
|
||||
|
||||
stream_data.add_sub({stream_id: 77, name: "office", subscribed: true});
|
||||
stream_data.add_sub({stream_id: 88, name: "dev help", subscribed: true});
|
||||
|
||||
|
|
Loading…
Reference in New Issue