mirror of
https://github.com/zulip/zulip.git
synced 2025-11-03 05:23:35 +00:00
resolve topic: Add frontend support for is:resolved search keyword/filtering.
This commit adds the frontend support for `is:resolved` search keyword. Test cases are added for the same. Fixes: #18990.
This commit is contained in:
@@ -7,6 +7,7 @@ const {run_test} = require("../zjsunit/test");
|
||||
const $ = require("../zjsunit/zjquery");
|
||||
const {page_params} = require("../zjsunit/zpage_params");
|
||||
|
||||
const message_edit = mock_esm("../../static/js/message_edit");
|
||||
const message_store = mock_esm("../../static/js/message_store");
|
||||
|
||||
const stream_data = zrequire("stream_data");
|
||||
@@ -201,6 +202,14 @@ test("basics", () => {
|
||||
assert.ok(filter.contains_only_private_messages());
|
||||
assert.ok(!filter.has_operator("search"));
|
||||
assert.ok(filter.can_apply_locally());
|
||||
|
||||
operators = [{operator: "is", operand: "resolved"}];
|
||||
filter = new Filter(operators);
|
||||
assert.ok(!filter.contains_only_private_messages());
|
||||
assert.ok(filter.can_mark_messages_read());
|
||||
assert.ok(!filter.has_operator("search"));
|
||||
assert.ok(filter.can_apply_locally());
|
||||
assert.ok(!filter.is_personal_filter());
|
||||
});
|
||||
|
||||
function assert_not_mark_read_with_has_operands(additional_operators_to_test) {
|
||||
@@ -266,6 +275,18 @@ function assert_not_mark_read_with_is_operands(additional_operators_to_test) {
|
||||
is_operator = [{operator: "is", operand: "unread", negated: true}];
|
||||
filter = new Filter(additional_operators_to_test.concat(is_operator));
|
||||
assert.ok(!filter.can_mark_messages_read());
|
||||
|
||||
is_operator = [{operator: "is", operand: "resolved"}];
|
||||
filter = new Filter(additional_operators_to_test.concat(is_operator));
|
||||
if (additional_operators_to_test.length === 0) {
|
||||
assert.ok(filter.can_mark_messages_read());
|
||||
} else {
|
||||
assert.ok(!filter.can_mark_messages_read());
|
||||
}
|
||||
|
||||
is_operator = [{operator: "is", operand: "resolved", negated: true}];
|
||||
filter = new Filter(additional_operators_to_test.concat(is_operator));
|
||||
assert.ok(!filter.can_mark_messages_read());
|
||||
}
|
||||
|
||||
function assert_not_mark_read_when_searching(additional_operators_to_test) {
|
||||
@@ -605,6 +626,12 @@ test("predicate_basics", () => {
|
||||
predicate = get_predicate([["in", "all"]]);
|
||||
assert.ok(predicate({}));
|
||||
|
||||
predicate = get_predicate([["is", "resolved"]]);
|
||||
const resolved_topic_name = message_edit.RESOLVED_TOPIC_PREFIX + "foo";
|
||||
assert.ok(predicate({type: "stream", topic: resolved_topic_name}));
|
||||
assert.ok(!predicate({topic: resolved_topic_name}));
|
||||
assert.ok(!predicate({type: "stream", topic: "foo"}));
|
||||
|
||||
const unknown_stream_id = 999;
|
||||
predicate = get_predicate([["in", "home"]]);
|
||||
assert.ok(!predicate({stream_id: unknown_stream_id, stream: "unknown"}));
|
||||
@@ -1190,6 +1217,14 @@ test("can_bucket_by", () => {
|
||||
filter = new Filter(terms);
|
||||
assert.equal(filter.can_bucket_by("is-mentioned"), false);
|
||||
assert.equal(filter.can_bucket_by("is-private"), false);
|
||||
|
||||
terms = [{operator: "is", operand: "resolved"}];
|
||||
filter = new Filter(terms);
|
||||
assert.equal(filter.can_bucket_by("stream", "topic"), false);
|
||||
assert.equal(filter.can_bucket_by("stream"), false);
|
||||
assert.equal(filter.can_bucket_by("pm-with"), false);
|
||||
assert.equal(filter.can_bucket_by("is-mentioned"), false);
|
||||
assert.equal(filter.can_bucket_by("is-private"), false);
|
||||
});
|
||||
|
||||
test("term_type", () => {
|
||||
@@ -1358,6 +1393,7 @@ test("navbar_helpers", () => {
|
||||
const is_starred = [{operator: "is", operand: "starred"}];
|
||||
const is_private = [{operator: "is", operand: "private"}];
|
||||
const is_mentioned = [{operator: "is", operand: "mentioned"}];
|
||||
const is_resolved = [{operator: "is", operand: "resolved"}];
|
||||
const streams_public = [{operator: "streams", operand: "public"}];
|
||||
const stream_topic_operators = [
|
||||
{operator: "stream", operand: "foo"},
|
||||
@@ -1416,6 +1452,13 @@ test("navbar_helpers", () => {
|
||||
title: "translated: Mentions",
|
||||
redirect_url_with_search: "/#narrow/is/mentioned",
|
||||
},
|
||||
{
|
||||
operator: is_resolved,
|
||||
is_common_narrow: true,
|
||||
icon: "check",
|
||||
title: "translated: Topics marked as resolved",
|
||||
redirect_url_with_search: "/#narrow/topics/is/resolved",
|
||||
},
|
||||
{
|
||||
operator: stream_topic_operators,
|
||||
is_common_narrow: true,
|
||||
|
||||
@@ -6,6 +6,7 @@ const {mock_esm, zrequire} = require("../zjsunit/namespace");
|
||||
const {run_test} = require("../zjsunit/test");
|
||||
|
||||
const all_messages_data = mock_esm("../../static/js/all_messages_data");
|
||||
const message_edit = mock_esm("../../static/js/message_edit");
|
||||
|
||||
const {Filter} = zrequire("../js/filter");
|
||||
const {MessageListData} = zrequire("../js/message_list_data");
|
||||
@@ -300,6 +301,54 @@ run_test("is:alerted with no unreads and one match", () => {
|
||||
test_with(fixture);
|
||||
});
|
||||
|
||||
run_test("is:resolved with one unread", () => {
|
||||
const resolved_topic_name = message_edit.RESOLVED_TOPIC_PREFIX + "foo";
|
||||
const fixture = {
|
||||
filter_terms: [{operator: "is", operand: "resolved"}],
|
||||
unread_info: {
|
||||
flavor: "found",
|
||||
msg_id: 56,
|
||||
},
|
||||
has_found_newest: true,
|
||||
all_messages: [
|
||||
{id: 55, type: "stream", topic: resolved_topic_name},
|
||||
{id: 56, type: "stream", topic: resolved_topic_name},
|
||||
{id: 57, type: "stream", topic: "foo"},
|
||||
],
|
||||
expected_id_info: {
|
||||
target_id: undefined,
|
||||
final_select_id: 56,
|
||||
local_select_id: 56,
|
||||
},
|
||||
expected_msg_ids: [55, 56],
|
||||
};
|
||||
|
||||
test_with(fixture);
|
||||
});
|
||||
|
||||
run_test("is:resolved with no unreads", () => {
|
||||
const resolved_topic_name = message_edit.RESOLVED_TOPIC_PREFIX + "foo";
|
||||
const fixture = {
|
||||
filter_terms: [{operator: "is", operand: "resolved"}],
|
||||
unread_info: {
|
||||
flavor: "not_found",
|
||||
},
|
||||
has_found_newest: true,
|
||||
all_messages: [
|
||||
{id: 55, type: "stream", topic: resolved_topic_name},
|
||||
{id: 57, type: "stream", topic: "foo"},
|
||||
],
|
||||
expected_id_info: {
|
||||
target_id: undefined,
|
||||
final_select_id: 55,
|
||||
local_select_id: 55,
|
||||
},
|
||||
expected_msg_ids: [55],
|
||||
};
|
||||
|
||||
test_with(fixture);
|
||||
});
|
||||
|
||||
run_test("search", () => {
|
||||
const fixture = {
|
||||
filter_terms: [{operator: "search", operand: "whatever"}],
|
||||
|
||||
@@ -130,6 +130,11 @@ run_test("get_unread_ids", () => {
|
||||
unread_ids = candidate_ids();
|
||||
assert.deepEqual(unread_ids, [stream_msg.id]);
|
||||
|
||||
terms = [{operator: "is", operand: "resolved"}];
|
||||
set_filter(terms);
|
||||
unread_ids = candidate_ids();
|
||||
assert.deepEqual(unread_ids, [stream_msg.id]);
|
||||
|
||||
terms = [{operator: "sender", operand: "me@example.com"}];
|
||||
set_filter(terms);
|
||||
// note that our candidate ids are just "all" ids now
|
||||
|
||||
@@ -2,6 +2,7 @@ import Handlebars from "handlebars/runtime";
|
||||
import _ from "lodash";
|
||||
|
||||
import {$t} from "./i18n";
|
||||
import * as message_edit from "./message_edit";
|
||||
import * as message_parser from "./message_parser";
|
||||
import * as message_store from "./message_store";
|
||||
import {page_params} from "./page_params";
|
||||
@@ -92,6 +93,11 @@ function message_matches_search_term(message, operator, operand) {
|
||||
return message.alerted;
|
||||
case "unread":
|
||||
return unread.message_unread(message);
|
||||
case "resolved":
|
||||
return (
|
||||
message.type === "stream" &&
|
||||
message.topic.startsWith(message_edit.RESOLVED_TOPIC_PREFIX)
|
||||
);
|
||||
default:
|
||||
return false; // is:whatever returns false
|
||||
}
|
||||
@@ -451,6 +457,10 @@ export class Filter {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_.isEqual(term_types, ["is-resolved"])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_.isEqual(term_types, [])) {
|
||||
// All view
|
||||
return true;
|
||||
@@ -484,7 +494,7 @@ export class Filter {
|
||||
// can_mark_messages_read tests the following filters:
|
||||
// stream, stream + topic,
|
||||
// is: private, pm-with:,
|
||||
// is: mentioned
|
||||
// is: mentioned, is: resolved
|
||||
if (this.can_mark_messages_read()) {
|
||||
return true;
|
||||
}
|
||||
@@ -554,6 +564,8 @@ export class Filter {
|
||||
"/#narrow/pm-with/" +
|
||||
people.emails_to_slug(this.operands("pm-with").join(","))
|
||||
);
|
||||
case "is-resolved":
|
||||
return "/#narrow/topics/is/resolved";
|
||||
// TODO: It is ambiguous how we want to handle the 'sender' case,
|
||||
// we may remove it in the future based on design decisions
|
||||
case "sender":
|
||||
@@ -590,6 +602,8 @@ export class Filter {
|
||||
return "at";
|
||||
case "pm-with":
|
||||
return "envelope";
|
||||
case "is-resolved":
|
||||
return "check";
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
@@ -640,6 +654,8 @@ export class Filter {
|
||||
// can have the same return type as other cases.
|
||||
return names.join(", ");
|
||||
}
|
||||
case "is-resolved":
|
||||
return $t({defaultMessage: "Topics marked as resolved"});
|
||||
}
|
||||
}
|
||||
/* istanbul ignore next */
|
||||
@@ -849,6 +865,7 @@ export class Filter {
|
||||
"is-private",
|
||||
"is-starred",
|
||||
"is-unread",
|
||||
"is-resolved",
|
||||
"has-link",
|
||||
"has-image",
|
||||
"has-attachment",
|
||||
|
||||
Reference in New Issue
Block a user