diff --git a/tools/test-js-with-node b/tools/test-js-with-node index 990d6a2644..74e43dba30 100755 --- a/tools/test-js-with-node +++ b/tools/test-js-with-node @@ -153,7 +153,6 @@ EXEMPT_FILES = make_set( "web/src/scheduled_messages_overlay_ui.js", "web/src/scroll_bar.ts", "web/src/scroll_util.ts", - "web/src/search_pill_widget.js", "web/src/sent_messages.js", "web/src/sentry.ts", "web/src/server_events.js", diff --git a/web/src/hotkey.js b/web/src/hotkey.js index 7a54966566..53194dfa4a 100644 --- a/web/src/hotkey.js +++ b/web/src/hotkey.js @@ -25,7 +25,6 @@ import * as list_util from "./list_util"; import * as message_edit from "./message_edit"; import * as message_lists from "./message_lists"; import * as message_scroll from "./message_scroll"; -import * as message_view_header from "./message_view_header"; import * as muted_topics_ui from "./muted_topics_ui"; import * as narrow from "./narrow"; import * as narrow_state from "./narrow_state"; @@ -320,17 +319,6 @@ export function process_escape_key(e) { return true; } - if ($("#searchbox").has(":focus")) { - $("input:focus,textarea:focus").trigger("blur"); - if (page_params.search_pills_enabled) { - $("#searchbox .pill").trigger("blur"); - $("#searchbox #search_query").trigger("blur"); - } else { - message_view_header.exit_search(); - } - return true; - } - // We pressed Esc and something was focused, and the composebox // wasn't open. In that case, we should blur the input. $("input:focus,textarea:focus").trigger("blur"); diff --git a/web/src/message_view_header.js b/web/src/message_view_header.js index c22c252748..3aa1a60e83 100644 --- a/web/src/message_view_header.js +++ b/web/src/message_view_header.js @@ -4,7 +4,6 @@ import render_message_view_header from "../templates/message_view_header.hbs"; import {$t} from "./i18n"; import * as narrow_state from "./narrow_state"; -import {page_params} from "./page_params"; import * as peer_data from "./peer_data"; import * as popovers from "./popovers"; import * as recent_topics_util from "./recent_topics_util"; @@ -132,11 +131,7 @@ function build_message_view_header(filter) { const message_view_header_data = make_message_view_header(filter); append_and_display_title_area(message_view_header_data); bind_title_area_handlers(); - if (page_params.search_pills_enabled && $("#search_query").is(":focus")) { - open_search_bar_and_close_narrow_description(); - } else { - close_search_bar_and_open_narrow_description(); - } + close_search_bar_and_open_narrow_description(); } } @@ -145,7 +140,7 @@ function build_message_view_header(filter) { export function reset_searchbox_text() { let search_string = narrow_state.search_string(); if (search_string !== "") { - if (!page_params.search_pills_enabled && !narrow_state.filter().is_search()) { + if (!narrow_state.filter().is_search()) { // saves the user a keystroke for quick searches search_string = search_string + " "; } diff --git a/web/src/narrow.js b/web/src/narrow.js index 7886d97a83..6fb2bea434 100644 --- a/web/src/narrow.js +++ b/web/src/narrow.js @@ -36,8 +36,6 @@ import * as recent_topics_ui from "./recent_topics_ui"; import * as recent_topics_util from "./recent_topics_util"; import * as resize from "./resize"; import * as search from "./search"; -import * as search_pill from "./search_pill"; -import * as search_pill_widget from "./search_pill_widget"; import {web_mark_read_on_scroll_policy_values} from "./settings_config"; import * as spectators from "./spectators"; import * as stream_data from "./stream_data"; @@ -534,15 +532,6 @@ export function activate(raw_operators, opts) { hashchange.save_narrow(operators); } - if (page_params.search_pills_enabled && opts.trigger !== "search") { - search_pill_widget.widget.clear(true); - - for (const operator of operators) { - const search_string = Filter.unparse([operator]); - search_pill.append_search_string(search_string, search_pill_widget.widget); - } - } - if (filter.contains_only_private_messages()) { compose_closed_ui.update_buttons_for_private(); } else { @@ -995,11 +984,6 @@ export function to_compose_target() { function handle_post_narrow_deactivate_processes() { compose_fade.update_message_list(); - // clear existing search pills - if (page_params.search_pills_enabled) { - search_pill_widget.widget.clear(true); - } - top_left_corner.handle_narrow_deactivated(); pm_list.handle_narrow_deactivated(); stream_list.handle_narrow_deactivated(); diff --git a/web/src/search.js b/web/src/search.js index 21f90c006c..488c792fe6 100644 --- a/web/src/search.js +++ b/web/src/search.js @@ -7,11 +7,7 @@ import * as keydown_util from "./keydown_util"; import * as message_view_header from "./message_view_header"; import * as narrow from "./narrow"; import * as narrow_state from "./narrow_state"; -import {page_params} from "./page_params"; -import * as search_pill from "./search_pill"; -import * as search_pill_widget from "./search_pill_widget"; import * as search_suggestion from "./search_suggestion"; -import * as ui_util from "./ui_util"; // Exported for unit testing export let is_using_input_method = false; @@ -25,18 +21,7 @@ export function narrow_or_search_for_term(search_string) { return $search_query_box.val(); } - let operators; - if (page_params.search_pills_enabled) { - // We have to take care to append the new pill before calling this - // function, so that the base_query includes the suggestion selected - // along with query corresponding to the existing pills. - const base_query = search_pill.get_search_string_for_current_filter( - search_pill_widget.widget, - ); - operators = Filter.parse(base_query); - } else { - operators = Filter.parse(search_string); - } + const operators = Filter.parse(search_string); narrow.activate(operators, {trigger: "search"}); // It's sort of annoying that this is not in a position to @@ -45,9 +30,7 @@ export function narrow_or_search_for_term(search_string) { // Narrowing will have already put some operators in the search box, // so leave the current text in. - if (!page_params.search_pills_enabled) { - $search_query_box.trigger("blur"); - } + $search_query_box.trigger("blur"); return $search_query_box.val(); } @@ -68,7 +51,6 @@ export function update_button_visibility() { export function initialize() { const $search_query_box = $("#search_query"); const $searchbox_form = $("#searchbox_form"); - const $searchbox = $("#searchbox"); // Data storage for the typeahead. // This maps a search string to an object with a "description_html" field. @@ -79,23 +61,15 @@ export function initialize() { $search_query_box.typeahead({ source(query) { - let base_query = ""; - if (page_params.search_pills_enabled) { - base_query = search_pill.get_search_string_for_current_filter( - search_pill_widget.widget, - ); - } + const base_query = ""; const suggestions = search_suggestion.get_suggestions(base_query, query); // Update our global search_map hash search_map = suggestions.lookup_table; return suggestions.strings; }, - parentElement: "#searchbox_legacy", + parentElement: "#searchbox", items: search_suggestion.max_num_of_search_results, helpOnEmptyStrings: true, - // With search pills, the contenteditable input will be empty - // even if some pills are present. - hideOnEmpty: page_params.search_pills_enabled, naturalSearch: true, highlighter(item) { const obj = search_map.get(item); @@ -105,23 +79,13 @@ export function initialize() { return true; }, updater(search_string) { - if (page_params.search_pills_enabled) { - search_pill.append_search_string(search_string, search_pill_widget.widget); - return $search_query_box.val(); - } return narrow_or_search_for_term(search_string); }, sorter(items) { return items; }, - stopAdvance: page_params.search_pills_enabled, advanceKeyCodes: [8], - on_move() { - if (page_params.search_pills_enabled) { - ui_util.place_caret_at_end($search_query_box[0]); - } - }, // Use our custom typeahead `on_escape` hook to exit // the search bar as soon as the user hits Esc. on_escape: message_view_header.exit_search, @@ -172,7 +136,7 @@ export function initialize() { // more work to re-order everything and make them private. $search_query_box.on("focus", focus_search); - $search_query_box.on("blur", (e) => { + $search_query_box.on("blur", () => { // The search query box is a visual cue as to // whether search or narrowing is active. If // the user blurs the search box, then we should @@ -187,33 +151,10 @@ export function initialize() { // enough for the search to have gone through, but // short enough that the user won't notice (though // really it would be OK if they did). - - if (page_params.search_pills_enabled) { - const $element = $(e.relatedTarget).closest(".pill"); - const search_pill = search_pill_widget.widget.getByElement($element[0]); - if (search_pill) { - // The searchbox loses focus while the search - // pill element gains focus. - // We do not consider the searchbox to actually - // lose focus when a pill inside it gets selected - // or deleted by a click. - return; - } - } setTimeout(() => { update_button_visibility(); }, 100); }); - - if (page_params.search_pills_enabled) { - // Uses jquery instead of pure css as the `:focus` event occurs on `#search_query`, - // while we want to add box-shadow to `#searchbox`. This could have been done - // with `:focus-within` CSS selector, but it is not supported in IE or Opera. - $searchbox.on("focusout", () => { - message_view_header.close_search_bar_and_open_narrow_description(); - $searchbox.css({"box-shadow": "unset"}); - }); - } } export function focus_search() { @@ -223,12 +164,7 @@ export function focus_search() { export function initiate_search() { message_view_header.open_search_bar_and_close_narrow_description(); - $("#searchbox").css({"box-shadow": "inset 0px 0px 0px 2px hsl(204, 20%, 74%)"}); $("#search_query").typeahead("lookup").trigger("select"); - if (page_params.search_pills_enabled) { - $("#search_query").trigger("focus"); - ui_util.place_caret_at_end($("#search_query")[0]); - } } export function clear_search_form() { diff --git a/web/src/search_pill.js b/web/src/search_pill.js deleted file mode 100644 index edfa33c119..0000000000 --- a/web/src/search_pill.js +++ /dev/null @@ -1,41 +0,0 @@ -import {Filter} from "./filter"; -import * as input_pill from "./input_pill"; - -export function create_item_from_search_string(search_string) { - const operator = Filter.parse(search_string); - const description_html = Filter.describe(operator); - return { - display_value: search_string, - description_html, - }; -} - -export function get_search_string_from_item(item) { - return item.display_value; -} - -export function create_pills($pill_container) { - const pills = input_pill.create({ - $container: $pill_container, - create_item_from_text: create_item_from_search_string, - get_text_from_item: get_search_string_from_item, - }); - return pills; -} - -export function append_search_string(search_string, pill_widget) { - const operators = Filter.parse(search_string); - for (const operator of operators) { - const input = Filter.unparse([operator]); - pill_widget.appendValue(input); - } - if (pill_widget.clear_text !== undefined) { - pill_widget.clear_text(); - } -} - -export function get_search_string_for_current_filter(pill_widget) { - const items = pill_widget.items(); - const search_strings = items.map((item) => item.display_value); - return search_strings.join(" "); -} diff --git a/web/src/search_pill_widget.js b/web/src/search_pill_widget.js deleted file mode 100644 index ad271477b5..0000000000 --- a/web/src/search_pill_widget.js +++ /dev/null @@ -1,23 +0,0 @@ -import $ from "jquery"; - -import * as browser_history from "./browser_history"; -import {page_params} from "./page_params"; -import * as search_pill from "./search_pill"; - -export let widget; - -export function initialize() { - if (!page_params.search_pills_enabled) { - return; - } - const $container = $("#search_arrows"); - widget = search_pill.create_pills($container); - - widget.onPillRemove(() => { - if (widget.items().length === 0) { - browser_history.go_to_location(""); - } - }); - - widget.createPillonPaste(() => false); -} diff --git a/web/src/search_suggestion.js b/web/src/search_suggestion.js index 966dbcf4bd..fee5b40e02 100644 --- a/web/src/search_suggestion.js +++ b/web/src/search_suggestion.js @@ -707,28 +707,14 @@ class Attacher { export function get_search_result(base_query, query) { let suggestion; - let all_operators; // search_operators correspond to the operators for the query in the input. - // For search_pills_enabled, this includes just editable query where search pills - // have not been created yet. - // And for this disabled case, this includes the entire query entered in the searchbox. + // This includes the entire query entered in the searchbox. // operators correspond to the operators for the entire query entered in the searchbox. - if (page_params.search_pills_enabled) { - all_operators = Filter.parse((base_query + " " + query).trim()); - } const search_operators = Filter.parse(query); let last = {operator: "", operand: "", negated: false}; if (search_operators.length > 0) { last = search_operators.at(-1); - } else if (page_params.search_pills_enabled) { - // We push an empty term so that we can get suggestions - // on the empty string based on the base query which is - // calculated from the created search pills. - // Else search results are returned as if the user is still - // typing the non-editable last search pill. - all_operators.push(last); - search_operators.push(last); } const person_suggestion_ops = ["sender", "dm", "dm-including", "from", "pm-with"]; @@ -751,10 +737,6 @@ export function get_search_result(base_query, query) { operand: person_op.operand + " " + last.operand, negated: person_op.negated, }; - if (page_params.search_pills_enabled) { - all_operators.splice(-2); - all_operators.push(last); - } search_operators.splice(-2); search_operators.push(last); } @@ -808,10 +790,7 @@ export function get_search_result(base_query, query) { ]; } - if (!page_params.search_pills_enabled) { - all_operators = search_operators; - } - const base_operators = all_operators.slice(0, -1); + const base_operators = search_operators.slice(0, -1); const max_items = max_num_of_search_results; for (const filterer of filterers) { @@ -821,15 +800,7 @@ export function get_search_result(base_query, query) { } } - if ( - !page_params.search_pills_enabled && - // This is unique to the legacy search system. With pills - // it is difficult to "suggest" a subset of operators, - // and there's a more natural mechanism under that paradigm, - // where the user just deletes one or more pills. So you - // won't see this is in the new code. - attacher.result.length < max_items - ) { + if (attacher.result.length < max_items) { const subset_suggestions = get_operator_subset_suggestions(search_operators); attacher.push_many(subset_suggestions); } diff --git a/web/src/ui_init.js b/web/src/ui_init.js index b3b4645cdb..2d4fbf716b 100644 --- a/web/src/ui_init.js +++ b/web/src/ui_init.js @@ -80,7 +80,6 @@ import * as scheduled_messages_overlay_ui from "./scheduled_messages_overlay_ui" import * as scroll_bar from "./scroll_bar"; import * as scroll_util from "./scroll_util"; import * as search from "./search"; -import * as search_pill_widget from "./search_pill_widget"; import * as sent_messages from "./sent_messages"; import * as server_events from "./server_events"; import * as settings from "./settings"; @@ -221,7 +220,6 @@ function initialize_right_sidebar() { function initialize_navbar() { const rendered_navbar = render_navbar({ embedded: page_params.narrow_stream !== undefined, - search_pills_enabled: page_params.search_pills_enabled, }); $("#header-container").html(rendered_navbar); @@ -676,7 +674,6 @@ export function initialize_everything() { compose_recipient.initialize(); compose_pm_pill.initialize(); compose_closed_ui.initialize(); - search_pill_widget.initialize(); reload.initialize(); user_groups.initialize(user_groups_params); unread.initialize(unread_params); diff --git a/web/styles/search.css b/web/styles/search.css index 80384ed79b..97e9911e35 100644 --- a/web/styles/search.css +++ b/web/styles/search.css @@ -1,5 +1,4 @@ -#searchbox, -#searchbox_legacy { +#searchbox { width: 100%; height: var(--header-height); @@ -67,7 +66,6 @@ font-size: 16px; height: calc(var(--header-height) - 1px); padding: 0; - padding-left: 5px; padding-right: 40px; border: none; border-radius: 0; @@ -77,6 +75,7 @@ text-overflow: ellipsis; overflow: hidden; white-space: nowrap; + padding-left: 35px; @media (width < $sm_min) { vertical-align: text-bottom; @@ -107,6 +106,8 @@ } .search_close_button { + right: 0; + &:hover { opacity: 1; } @@ -133,59 +134,8 @@ #search_arrows { font-size: 90%; letter-spacing: normal; - } -} - -/* in progress: searchbox with pills */ -#searchbox { - #search_arrows { - padding-left: 35px; - } - - .pill-container { - display: flex; - flex-wrap: nowrap; - align-items: center; - border: none; - padding: 0; - } - - @media (width >= $sm_min) { - .pill { - padding: 2px 0 !important; - font-size: 14px; - } - } - - @media (width < $sm_min) { - #search_arrows .pill { - line-height: 20px; - - .exit { - top: 0; - } - } - } -} - -#searchbox_legacy { - #search_arrows { padding-left: 0; } - - #search_query { - padding-left: 35px; - } - - .search_close_button { - right: 0; - } - - .navbar-search.expanded { - .search_close_button { - margin-right: 5px; - } - } } .typeahead-menu li a { diff --git a/web/styles/zulip.css b/web/styles/zulip.css index a2e0947425..3b956943ad 100644 --- a/web/styles/zulip.css +++ b/web/styles/zulip.css @@ -3036,7 +3036,6 @@ select.invite-as { .navbar-search, #message_view_header, #searchbox, - #searchbox_legacy, .header { line-height: var(--header-height); height: var(--header-height); diff --git a/web/templates/navbar.hbs b/web/templates/navbar.hbs index 3e3f54eb82..a45fd3c8fd 100644 --- a/web/templates/navbar.hbs +++ b/web/templates/navbar.hbs @@ -17,22 +17,7 @@
- {{#if search_pills_enabled }} - {{else}} -
- {{/if}}
diff --git a/web/tests/search_now.test.js b/web/tests/search.test.js similarity index 97% rename from web/tests/search_now.test.js rename to web/tests/search.test.js index 0c00d36e4b..b03ca6654a 100644 --- a/web/tests/search_now.test.js +++ b/web/tests/search.test.js @@ -5,9 +5,6 @@ const {strict: assert} = require("assert"); const {mock_esm, set_global, zrequire} = require("./lib/namespace"); const {run_test} = require("./lib/test"); const $ = require("./lib/zjquery"); -const {page_params} = require("./lib/zpage_params"); - -page_params.search_pills_enabled = false; const narrow = mock_esm("../src/narrow"); const narrow_state = mock_esm("../src/narrow_state"); @@ -386,21 +383,11 @@ run_test("initiate_search", () => { is_searchbox_text_selected = true; }); - let searchbox_css_args; - - $("#searchbox").css = (args) => { - searchbox_css_args = args; - }; - search.initiate_search(); assert.ok(typeahead_forced_open); assert.ok(is_searchbox_text_selected); assert.equal($("#search_query").val(), "ver"); - assert.deepEqual(searchbox_css_args, { - "box-shadow": "inset 0px 0px 0px 2px hsl(204, 20%, 74%)", - }); - // test that we append space for user convenience narrow_state.filter = () => ({is_search: () => false}); search.initiate_search(); diff --git a/web/tests/search_future.test.js b/web/tests/search_future.test.js deleted file mode 100644 index 3e72226b1d..0000000000 --- a/web/tests/search_future.test.js +++ /dev/null @@ -1,457 +0,0 @@ -"use strict"; - -const {strict: assert} = require("assert"); - -const {mock_esm, zrequire} = require("./lib/namespace"); -const {run_test} = require("./lib/test"); -const $ = require("./lib/zjquery"); -const {page_params} = require("./lib/zpage_params"); - -const noop = () => {}; - -const narrow = mock_esm("../src/narrow"); -const narrow_state = mock_esm("../src/narrow_state", { - filter: () => false, -}); -const search_suggestion = mock_esm("../src/search_suggestion"); - -mock_esm("../src/search_pill_widget", { - widget: { - getByElement: () => true, - }, -}); -mock_esm("../src/ui_util", { - place_caret_at_end: noop, -}); - -const search = zrequire("search"); -const search_pill = zrequire("search_pill"); -const {Filter} = zrequire("../src/filter"); - -function test(label, f) { - run_test(label, ({override, mock_template}) => { - page_params.search_pills_enabled = true; - f({override, mock_template}); - }); -} - -test("clear_search_form", () => { - $("#search_query").val("noise"); - $("#search_query").trigger("focus"); - $(".search_close_button").prop("disabled", false); - - search.clear_search_form(); - - assert.equal($("#search_query").is_focused(), false); - assert.equal($("#search_query").val(), ""); - assert.equal($(".search_close_button").prop("disabled"), true); -}); - -test("update_button_visibility", () => { - const $search_query = $("#search_query"); - const $close_button = $(".search_close_button"); - - $search_query.is = () => false; - $search_query.val(""); - narrow_state.active = () => false; - $close_button.prop("disabled", true); - search.update_button_visibility(); - assert.ok($close_button.prop("disabled")); - - $search_query.is = () => true; - $search_query.val(""); - delete narrow_state.active; - $close_button.prop("disabled", true); - search.update_button_visibility(); - assert.ok(!$close_button.prop("disabled")); - - $search_query.is = () => false; - $search_query.val("Test search term"); - delete narrow_state.active; - $close_button.prop("disabled", true); - search.update_button_visibility(); - assert.ok(!$close_button.prop("disabled")); - - $search_query.is = () => false; - $search_query.val(""); - narrow_state.active = () => true; - $close_button.prop("disabled", true); - search.update_button_visibility(); - assert.ok(!$close_button.prop("disabled")); -}); - -test("initialize", ({mock_template}) => { - const $search_query_box = $("#search_query"); - const $searchbox_form = $("#searchbox_form"); - const $close_button = $(".search_close_button"); - const $searchbox = $("#searchbox"); - - mock_template("search_list_item.hbs", true, (data, html) => { - assert.equal(typeof data.description_html, "string"); - if (data.is_person) { - assert.equal(typeof data.user_pill_context.id, "number"); - assert.equal(typeof data.user_pill_context.display_value, "string"); - assert.equal(typeof data.user_pill_context.has_image, "boolean"); - assert.equal(typeof data.user_pill_context.img_src, "string"); - } - return html; - }); - - $search_query_box[0] = "stub"; - - search_pill.get_search_string_for_current_filter = () => "is:starred"; - - search_suggestion.max_num_of_search_results = 99; - $search_query_box.typeahead = (opts) => { - assert.equal(opts.items, 99); - assert.equal(opts.naturalSearch, true); - assert.equal(opts.helpOnEmptyStrings, true); - assert.equal(opts.matcher(), true); - opts.on_move(); - - { - const search_suggestions = { - lookup_table: new Map([ - [ - "stream:Verona", - { - description_html: "Stream Verona", - search_string: "stream:Verona", - }, - ], - [ - "ver", - { - description_html: "Search for ver", - search_string: "ver", - }, - ], - ]), - strings: ["ver", "stream:Verona"], - }; - - /* Test source */ - search_suggestion.get_suggestions = () => search_suggestions; - const expected_source_value = search_suggestions.strings; - const source = opts.source("ver"); - assert.equal(source, expected_source_value); - - /* Test highlighter */ - let expected_value = `
\n Search for ver\n
\n`; - assert.equal(opts.highlighter(source[0]), expected_value); - - expected_value = `
\n Stream Verona\n
\n`; - assert.equal(opts.highlighter(source[1]), expected_value); - - /* Test sorter */ - assert.equal(opts.sorter(search_suggestions.strings), search_suggestions.strings); - } - - { - const search_suggestions = { - lookup_table: new Map([ - [ - "dm-including:zo", - { - description_html: "group direct messages including", - is_person: true, - search_string: "dm-including:user7@zulipdev.com", - user_pill_context: { - display_value: "Zoe", - has_image: true, - id: 7, - img_src: - "https://secure.gravatar.com/avatar/0f030c97ab51312c7bbffd3966198ced?d=identicon&version=1&s=50", - }, - }, - ], - [ - "dm:zo", - { - description_html: "direct messages with", - is_person: true, - search_string: "dm:user7@zulipdev.com", - user_pill_context: { - display_value: "Zoe", - has_image: true, - id: 7, - img_src: - "https://secure.gravatar.com/avatar/0f030c97ab51312c7bbffd3966198ced?d=identicon&version=1&s=50", - }, - }, - ], - [ - "sender:zo", - { - description_html: "sent by", - is_person: true, - search_string: "sender:user7@zulipdev.com", - user_pill_context: { - display_value: "Zoe", - has_image: true, - id: 7, - img_src: - "https://secure.gravatar.com/avatar/0f030c97ab51312c7bbffd3966198ced?d=identicon&version=1&s=50", - }, - }, - ], - [ - "zo", - { - description_html: "Search for zo", - search_string: "zo", - }, - ], - ]), - strings: ["zo", "sender:zo", "dm:zo", "dm-including:zo"], - }; - - /* Test source */ - search_suggestion.get_suggestions = () => search_suggestions; - const expected_source_value = search_suggestions.strings; - const source = opts.source("zo"); - assert.equal(source, expected_source_value); - - /* Test highlighter */ - let expected_value = `
\n Search for zo\n
\n`; - assert.equal(opts.highlighter(source[0]), expected_value); - - expected_value = `
\n sent by\n \n
\n \n <strong>Zo</strong>e\n
\n \n
\n
\n
\n
\n`; - assert.equal(opts.highlighter(source[1]), expected_value); - - expected_value = `
\n direct messages with\n \n
\n \n <strong>Zo</strong>e\n
\n \n
\n
\n
\n
\n`; - assert.equal(opts.highlighter(source[2]), expected_value); - - expected_value = `
\n group direct messages including\n \n
\n \n <strong>Zo</strong>e\n
\n \n
\n
\n
\n
\n`; - assert.equal(opts.highlighter(source[3]), expected_value); - - /* Test sorter */ - assert.equal(opts.sorter(search_suggestions.strings), search_suggestions.strings); - } - - { - let operators; - let is_blurred; - let is_append_search_string_called; - $search_query_box.on( - "blur", - /* istanbul ignore next */ - () => { - is_blurred = true; - }, - ); - search_pill.append_search_string = () => { - is_append_search_string_called = true; - }; - /* Test updater */ - const _setup = (search_box_val) => { - is_blurred = false; - is_append_search_string_called = false; - $search_query_box.val(search_box_val); - /* istanbul ignore next */ - Filter.parse = (search_string) => { - assert.equal(search_string, search_box_val); - return operators; - }; - /* istanbul ignore next */ - narrow.activate = (raw_operators, options) => { - assert.deepEqual(raw_operators, operators); - assert.deepEqual(options, {trigger: "search"}); - }; - /* istanbul ignore next */ - search_pill.get_search_string_for_current_filter = () => search_box_val; - }; - - operators = [ - { - negated: false, - operator: "search", - operand: "ver", - }, - ]; - _setup("ver"); - - assert.equal(opts.updater("ver"), "ver"); - assert.ok(!is_blurred); - assert.ok(is_append_search_string_called); - - operators = [ - { - negated: false, - operator: "stream", - operand: "Verona", - }, - ]; - _setup("stream:Verona"); - - assert.equal(opts.updater("stream:Verona"), "stream:Verona"); - assert.ok(!is_blurred); - assert.ok(is_append_search_string_called); - - search.__Rewire__("is_using_input_method", true); - _setup("stream:Verona"); - - assert.equal(opts.updater("stream:Verona"), "stream:Verona"); - assert.ok(!is_blurred); - assert.ok(is_append_search_string_called); - - $search_query_box.off("blur"); - } - }; - - search.initialize(); - - const $search_pill_stub = $.create(".pill"); - $search_pill_stub.closest = () => ({data: noop}); - const stub_event = { - // FIXME: event.relatedTarget should not be a jQuery object - relatedTarget: $search_pill_stub, - }; - $search_query_box.val("test string"); - narrow_state.search_string = () => "ver"; - $search_query_box.trigger(new $.Event("blur", stub_event)); - assert.equal($search_query_box.val(), "test string"); - - let css_args; - $searchbox.css = (args) => { - css_args = args; - }; - $searchbox.trigger("focusout"); - assert.deepEqual(css_args, {"box-shadow": "unset"}); - - search.__Rewire__("is_using_input_method", false); - $searchbox_form.trigger("compositionend"); - assert.ok(search.is_using_input_method); - - const keydown = $searchbox_form.get_on_handler("keydown"); - let default_prevented = false; - let ev = { - type: "keydown", - key: "a", - preventDefault() { - default_prevented = true; - }, - }; - $search_query_box.is = () => false; - assert.equal(keydown(ev), undefined); - assert.ok(!default_prevented); - - ev.key = "Enter"; - assert.equal(keydown(ev), undefined); - assert.ok(!default_prevented); - - ev.key = "Enter"; - $search_query_box.is = () => true; - assert.equal(keydown(ev), undefined); - assert.ok(default_prevented); - - let operators; - let is_blurred; - narrow_state.active = () => false; - $search_query_box.off("blur"); - $search_query_box.on("blur", () => { - is_blurred = true; - }); - - const _setup = (search_box_val) => { - is_blurred = false; - $close_button.prop("disabled", false); - $search_query_box.val(search_box_val); - Filter.parse = (search_string) => { - assert.equal(search_string, search_box_val); - return operators; - }; - narrow.activate = (raw_operators, options) => { - assert.deepEqual(raw_operators, operators); - assert.deepEqual(options, {trigger: "search"}); - }; - search_pill.get_search_string_for_current_filter = () => search_box_val; - }; - - operators = [ - { - negated: false, - operator: "search", - operand: "", - }, - ]; - _setup(""); - - ev = { - type: "keyup", - which: 15, - }; - /* istanbul ignore next */ - $search_query_box.is = () => false; - $searchbox_form.trigger(ev); - - assert.ok(!is_blurred); - assert.ok(!$close_button.prop("disabled")); - - ev.key = "Enter"; - $search_query_box.is = () => false; - $searchbox_form.trigger(ev); - - assert.ok(!is_blurred); - assert.ok(!$close_button.prop("disabled")); - - ev.key = "Enter"; - $search_query_box.is = () => true; - $searchbox_form.trigger(ev); - assert.ok(is_blurred); - - _setup("ver"); - search.__Rewire__("is_using_input_method", true); - $searchbox_form.trigger(ev); - // No change on Enter keyup event when using input tool - assert.ok(!is_blurred); - assert.ok(!$close_button.prop("disabled")); - - _setup("ver"); - ev.key = "Enter"; - $search_query_box.is = () => true; - $searchbox_form.trigger(ev); - assert.ok(is_blurred); - assert.ok(!$close_button.prop("disabled")); - - $close_button.prop("disabled", true); - $search_query_box.trigger("focus"); - assert.ok(!$close_button.prop("disabled")); -}); - -test("initiate_search", () => { - // open typeahead and select text when navbar is open - // this implicitly expects the code to used the chained - // function calls, which is something to keep in mind if - // this test ever fails unexpectedly. - let typeahead_forced_open = false; - let is_searchbox_text_selected = false; - let is_searchbox_focused = false; - $("#search_query").off("focus"); - $("#search_query").on("focus", () => { - is_searchbox_focused = true; - }); - $("#search_query").typeahead = (lookup) => { - if (lookup === "lookup") { - typeahead_forced_open = true; - } - return $("#search_query"); - }; - $("#search_query").on("select", () => { - is_searchbox_text_selected = true; - }); - - $("#search_query")[0] = "stub"; - - const $searchbox = $("#searchbox"); - let css_args; - $searchbox.css = (args) => { - css_args = args; - }; - - search.initiate_search(); - assert.ok(typeahead_forced_open); - assert.ok(is_searchbox_text_selected); - assert.ok(is_searchbox_focused); - assert.deepEqual(css_args, {"box-shadow": "inset 0px 0px 0px 2px hsl(204, 20%, 74%)"}); -}); diff --git a/web/tests/search_pill.test.js b/web/tests/search_pill.test.js deleted file mode 100644 index 6d436bf121..0000000000 --- a/web/tests/search_pill.test.js +++ /dev/null @@ -1,85 +0,0 @@ -"use strict"; - -const {strict: assert} = require("assert"); - -const {mock_esm, zrequire} = require("./lib/namespace"); -const {run_test} = require("./lib/test"); - -const input_pill = mock_esm("../src/input_pill"); - -const search_pill = zrequire("search_pill"); - -const is_starred_item = { - display_value: "is:starred", - description_html: "starred messages", -}; - -const is_private_item = { - display_value: "is:private", - description_html: "direct messages", -}; - -run_test("create_item", () => { - function test_create_item(search_string, current_items, expected_item) { - const item = search_pill.create_item_from_search_string(search_string, current_items); - assert.deepEqual(item, expected_item); - } - - test_create_item("is:starred", [], is_starred_item); -}); - -run_test("get_search_string", () => { - assert.equal(search_pill.get_search_string_from_item(is_starred_item), "is:starred"); -}); - -run_test("append", () => { - let appended; - let cleared; - - function fake_append(search_string) { - appended = true; - assert.equal(search_string, is_starred_item.display_value); - } - - function fake_clear() { - cleared = true; - } - - const pill_widget = { - appendValue: fake_append, - clear_text: fake_clear, - }; - - search_pill.append_search_string(is_starred_item.display_value, pill_widget); - - assert.ok(appended); - assert.ok(cleared); -}); - -run_test("get_items", () => { - const items = [is_starred_item, is_private_item]; - - const pill_widget = { - items() { - return items; - }, - }; - - assert.deepEqual( - search_pill.get_search_string_for_current_filter(pill_widget), - is_starred_item.display_value + " " + is_private_item.display_value, - ); -}); - -run_test("create_pills", ({override}) => { - let input_pill_create_called = false; - - override(input_pill, "create", () => { - input_pill_create_called = true; - return {dummy: "dummy"}; - }); - - const pills = search_pill.create_pills({}); - assert.ok(input_pill_create_called); - assert.deepEqual(pills, {dummy: "dummy"}); -}); diff --git a/web/tests/search_suggestion_now.test.js b/web/tests/search_suggestion.test.js similarity index 99% rename from web/tests/search_suggestion_now.test.js rename to web/tests/search_suggestion.test.js index 17da94a5b3..08302bd287 100644 --- a/web/tests/search_suggestion_now.test.js +++ b/web/tests/search_suggestion.test.js @@ -53,7 +53,6 @@ const example_avatar_url = "http://example.com/example.png"; function init() { page_params.is_admin = true; - page_params.search_pills_enabled = false; people.init(); people.add_active_user(bob); diff --git a/web/tests/search_suggestion_future.test.js b/web/tests/search_suggestion_future.test.js deleted file mode 100644 index 7fd96daebf..0000000000 --- a/web/tests/search_suggestion_future.test.js +++ /dev/null @@ -1,1020 +0,0 @@ -"use strict"; - -const {strict: assert} = require("assert"); - -const {mock_esm, zrequire} = require("./lib/namespace"); -const {run_test} = require("./lib/test"); -const {page_params} = require("./lib/zpage_params"); - -const narrow_state = mock_esm("../src/narrow_state"); -const stream_topic_history_util = mock_esm("../src/stream_topic_history_util"); - -const huddle_data = zrequire("huddle_data"); - -const stream_data = zrequire("stream_data"); -const stream_topic_history = zrequire("stream_topic_history"); -const people = zrequire("people"); -const search = zrequire("search_suggestion"); - -search.__Rewire__("max_num_of_search_results", 15); - -const me = { - email: "myself@zulip.com", - full_name: "Me Myself", - user_id: 41, -}; - -const bob = { - email: "bob@zulip.com", - full_name: "Bob Roberts", - user_id: 42, -}; - -const ted = { - email: "ted@zulip.com", - delivery_email: "ted@zulip.com", - user_id: 101, - full_name: "Ted Smith", -}; - -const alice = { - email: "alice@zulip.com", - user_id: 102, - full_name: "Alice Ignore", -}; - -const jeff = { - email: "jeff@zulip.com", - user_id: 103, - full_name: "Jeff Zoolipson", -}; - -const noop = () => {}; -const example_avatar_url = "http://example.com/example.png"; - -function init() { - page_params.is_admin = true; - page_params.search_pills_enabled = true; - - people.init(); - people.add_active_user(bob); - people.add_active_user(me); - people.add_active_user(ted); - people.add_active_user(alice); - people.add_active_user(jeff); - - people.initialize_current_user(me.user_id); - - stream_topic_history.reset(); - huddle_data.clear_for_testing(); - stream_data.clear_subscriptions(); -} - -function get_suggestions(base_query, query) { - return search.get_suggestions(base_query, query); -} - -function test(label, f) { - run_test(label, (helpers) => { - init(); - f(helpers); - }); -} - -test("basic_get_suggestions", ({override}) => { - const query = "fred"; - - override(narrow_state, "stream", () => "office"); - - const suggestions = get_suggestions("", query); - - const expected = ["fred"]; - assert.deepEqual(suggestions.strings, expected); -}); - -test("basic_get_suggestions_for_spectator", () => { - page_params.is_spectator = true; - - const query = ""; - const suggestions = get_suggestions("", query); - assert.deepEqual(suggestions.strings, ["", "has:link", "has:image", "has:attachment"]); - page_params.is_spectator = false; -}); - -test("subset_suggestions", () => { - const query = "shakespeare"; - const base_query = "stream:Denmark topic:Hamlet"; - - const suggestions = get_suggestions(base_query, query); - - const expected = ["shakespeare"]; - - assert.deepEqual(suggestions.strings, expected); -}); - -test("dm_suggestions", ({override}) => { - let query = "is:dm"; - let suggestions = get_suggestions("", query); - let expected = [ - "is:dm", - "dm:alice@zulip.com", - "dm:bob@zulip.com", - "dm:jeff@zulip.com", - "dm:myself@zulip.com", - "dm:ted@zulip.com", - ]; - assert.deepEqual(suggestions.strings, expected); - - query = "al"; - let base_query = "is:dm"; - suggestions = get_suggestions(base_query, query); - expected = [ - "al", - "is:alerted", - "sender:alice@zulip.com", - "dm:alice@zulip.com", - "dm-including:alice@zulip.com", - ]; - assert.deepEqual(suggestions.strings, expected); - - // "is:private" was renamed to "is:dm", so - // we suggest "is:dm" to anyone with "is:private" - // in their muscle memory. - query = "is:pr"; - suggestions = get_suggestions("", query); - expected = ["is:dm"]; - assert.deepEqual(suggestions.strings, expected); - - query = "is:private"; - suggestions = get_suggestions("", query); - expected = ["is:dm"]; - assert.deepEqual(suggestions.strings, expected); - - query = "dm:t"; - suggestions = get_suggestions("", query); - expected = ["dm:t", "dm:ted@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); - - query = "-dm:t"; - suggestions = get_suggestions("", query); - expected = ["-dm:t", "is:dm -dm:ted@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); - - query = "dm:ted@zulip.com"; - suggestions = get_suggestions("", query); - expected = ["dm:ted@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); - - query = "sender:ted"; - suggestions = get_suggestions("", query); - expected = ["sender:ted", "sender:ted@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); - - query = "sender:te"; - suggestions = get_suggestions("", query); - expected = ["sender:te", "sender:ted@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); - - query = "-sender:te"; - suggestions = get_suggestions("", query); - expected = ["-sender:te", "-sender:ted@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); - - query = "sender:ted@zulip.com"; - suggestions = get_suggestions("", query); - expected = ["sender:ted@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); - - query = "from:ted"; - base_query = "is:unread"; - suggestions = get_suggestions(base_query, query); - expected = ["from:ted", "from:ted@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); - - // Users can enter bizarre queries, and if they do, we want to - // be conservative with suggestions. - query = "near:3"; - base_query = "is:dm"; - suggestions = get_suggestions(base_query, query); - expected = ["near:3"]; - assert.deepEqual(suggestions.strings, expected); - - query = "near:3"; - base_query = "dm:ted@zulip.com"; - suggestions = get_suggestions(base_query, query); - expected = ["near:3"]; - assert.deepEqual(suggestions.strings, expected); - - // Make sure suggestions still work if preceding tokens - query = "sender:ted@zulip.com"; - base_query = "is:alerted"; - suggestions = get_suggestions(base_query, query); - expected = ["sender:ted@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); - - query = "al"; - base_query = "is:starred has:link is:dm"; - suggestions = get_suggestions(base_query, query); - expected = [ - "al", - "is:alerted", - "sender:alice@zulip.com", - "dm:alice@zulip.com", - "dm-including:alice@zulip.com", - ]; - assert.deepEqual(suggestions.strings, expected); - - // Make sure it handles past context correctly - query = "dm:"; - base_query = "stream:Denmark"; - suggestions = get_suggestions(base_query, query); - expected = ["dm:"]; - assert.deepEqual(suggestions.strings, expected); - - query = "sender:"; - base_query = "sender:ted@zulip.com"; - suggestions = get_suggestions(base_query, query); - expected = ["sender:"]; - assert.deepEqual(suggestions.strings, expected); - - // "pm-with" operator returns search result - // and "dm" operator as a suggestions - override(narrow_state, "stream", () => undefined); - query = "pm-with"; - suggestions = get_suggestions("", query); - expected = ["pm-with", "dm:"]; - assert.deepEqual(suggestions.strings, expected); - - query = "pm-with:t"; - suggestions = get_suggestions("", query); - expected = ["pm-with:t", "dm:ted@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); -}); - -test("group_suggestions", () => { - // Entering a comma in a dm query should immediately generate - // suggestions for the next person. - let query = "dm:bob@zulip.com,"; - let suggestions = get_suggestions("", query); - let expected = [ - "dm:bob@zulip.com,", - "dm:bob@zulip.com,alice@zulip.com", - "dm:bob@zulip.com,jeff@zulip.com", - "dm:bob@zulip.com,ted@zulip.com", - ]; - assert.deepEqual(suggestions.strings, expected); - - // Only the last part of a comma-separated dm query should be used to - // generate suggestions. - query = "dm:bob@zulip.com,t"; - suggestions = get_suggestions("", query); - expected = ["dm:bob@zulip.com,t", "dm:bob@zulip.com,ted@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); - - // Smit should also generate ted@zulip.com (Ted Smith) as a suggestion. - query = "dm:bob@zulip.com,Smit"; - suggestions = get_suggestions("", query); - expected = ["dm:bob@zulip.com,Smit", "dm:bob@zulip.com,ted@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); - - // Do not suggest "myself@zulip.com" (the name of the current user) - query = "dm:ted@zulip.com,mys"; - suggestions = get_suggestions("", query); - expected = ["dm:ted@zulip.com,mys"]; - assert.deepEqual(suggestions.strings, expected); - - // No superfluous suggestions should be generated. - query = "dm:bob@zulip.com,red"; - suggestions = get_suggestions("", query); - expected = ["dm:bob@zulip.com,red"]; - assert.deepEqual(suggestions.strings, expected); - - // "is:dm" should be properly prepended to each suggestion - // if the "dm" operator is negated. - - query = "-dm:bob@zulip.com,"; - suggestions = get_suggestions("", query); - expected = [ - "-dm:bob@zulip.com,", - "is:dm -dm:bob@zulip.com,alice@zulip.com", - "is:dm -dm:bob@zulip.com,jeff@zulip.com", - "is:dm -dm:bob@zulip.com,ted@zulip.com", - ]; - assert.deepEqual(suggestions.strings, expected); - - query = "-dm:bob@zulip.com,t"; - suggestions = get_suggestions("", query); - expected = ["-dm:bob@zulip.com,t", "is:dm -dm:bob@zulip.com,ted@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); - - query = "-dm:bob@zulip.com,Smit"; - suggestions = get_suggestions("", query); - expected = ["-dm:bob@zulip.com,Smit", "is:dm -dm:bob@zulip.com,ted@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); - - query = "-dm:bob@zulip.com,red"; - suggestions = get_suggestions("", query); - expected = ["-dm:bob@zulip.com,red"]; - assert.deepEqual(suggestions.strings, expected); - - // If user types "pm-with" operator, an email and a comma, - // show suggestions for group direct messages with the "dm" - // operator. - query = "pm-with:bob@zulip.com,"; - suggestions = get_suggestions("", query); - expected = [ - "pm-with:bob@zulip.com,", - "dm:bob@zulip.com,alice@zulip.com", - "dm:bob@zulip.com,jeff@zulip.com", - "dm:bob@zulip.com,ted@zulip.com", - ]; - assert.deepEqual(suggestions.strings, expected); - - // Test multiple operators - query = "dm:bob@zulip.com,Smit"; - let base_query = "is:starred has:link"; - suggestions = get_suggestions(base_query, query); - expected = ["dm:bob@zulip.com,Smit", "dm:bob@zulip.com,ted@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); - - query = "dm:bob@zulip.com,Smit"; - base_query = "stream:Denmark has:link"; - suggestions = get_suggestions(base_query, query); - expected = ["dm:bob@zulip.com,Smit"]; - assert.deepEqual(suggestions.strings, expected); - - function message(user_ids, timestamp) { - return { - type: "private", - display_recipient: user_ids.map((id) => ({ - id, - })), - timestamp, - }; - } - - huddle_data.process_loaded_messages([ - message([bob.user_id, ted.user_id], 99), - message([bob.user_id, ted.user_id, jeff.user_id], 98), - ]); - - // Simulate a past group direct message which should now - // prioritize ted over alice - query = "dm:bob@zulip.com,"; - suggestions = get_suggestions("", query); - expected = [ - "dm:bob@zulip.com,", - "dm:bob@zulip.com,ted@zulip.com", - "dm:bob@zulip.com,alice@zulip.com", - "dm:bob@zulip.com,jeff@zulip.com", - ]; - assert.deepEqual(suggestions.strings, expected); - - // bob, ted, and jeff are already an existing group direct message, - // so prioritize this one - query = "dm:bob@zulip.com,ted@zulip.com,"; - suggestions = get_suggestions("", query); - expected = [ - "dm:bob@zulip.com,ted@zulip.com,", - "dm:bob@zulip.com,ted@zulip.com,jeff@zulip.com", - "dm:bob@zulip.com,ted@zulip.com,alice@zulip.com", - ]; - assert.deepEqual(suggestions.strings, expected); - - // bob, ted, and jeff are already an existing group direct message, - // but if we start with just jeff, then don't prioritize ted over - // alice because it doesn't complete the full group direct message. - query = "dm:jeff@zulip.com,"; - suggestions = get_suggestions("", query); - expected = [ - "dm:jeff@zulip.com,", - "dm:jeff@zulip.com,alice@zulip.com", - "dm:jeff@zulip.com,bob@zulip.com", - "dm:jeff@zulip.com,ted@zulip.com", - ]; - assert.deepEqual(suggestions.strings, expected); - - query = "dm:jeff@zulip.com,ted@zulip.com hi"; - suggestions = get_suggestions("", query); - expected = ["dm:jeff@zulip.com,ted@zulip.com hi"]; - assert.deepEqual(suggestions.strings, expected); -}); - -test("empty_query_suggestions", () => { - const query = ""; - - stream_data.add_sub({stream_id: 44, name: "devel", subscribed: true}); - stream_data.add_sub({stream_id: 77, name: "office", subscribed: true}); - - const suggestions = get_suggestions("", query); - - const expected = [ - "", - "streams:public", - "is:dm", - "is:starred", - "is:mentioned", - "is:alerted", - "is:unread", - "is:resolved", - "sender:myself@zulip.com", - "stream:devel", - "stream:office", - "has:link", - "has:image", - "has:attachment", - ]; - - assert.deepEqual(suggestions.strings, expected); - - function describe(q) { - return suggestions.lookup_table.get(q).description_html; - } - assert.equal(describe("is:dm"), "Direct messages"); - assert.equal(describe("is:starred"), "Starred messages"); - assert.equal(describe("is:mentioned"), "@-mentions"); - assert.equal(describe("is:alerted"), "Alerted messages"); - assert.equal(describe("is:unread"), "Unread messages"); - assert.equal(describe("is:resolved"), "Topics marked as resolved"); - assert.equal(describe("sender:myself@zulip.com"), "Sent by me"); - assert.equal(describe("has:link"), "Messages with one or more link"); - assert.equal(describe("has:image"), "Messages with one or more image"); - assert.equal(describe("has:attachment"), "Messages with one or more attachment"); -}); - -test("has_suggestions", ({override}) => { - // Checks that category wise suggestions are displayed instead of a single - // default suggestion when suggesting `has` operator. - let query = "h"; - 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", () => {}); - - let suggestions = get_suggestions("", query); - let expected = ["h", "has:link", "has:image", "has:attachment"]; - assert.deepEqual(suggestions.strings, expected); - - function describe(q) { - return suggestions.lookup_table.get(q).description_html; - } - - assert.equal(describe("has:link"), "Messages with one or more link"); - assert.equal(describe("has:image"), "Messages with one or more image"); - assert.equal(describe("has:attachment"), "Messages with one or more attachment"); - - query = "-h"; - suggestions = get_suggestions("", query); - expected = ["-h", "-has:link", "-has:image", "-has:attachment"]; - assert.deepEqual(suggestions.strings, expected); - assert.equal(describe("-has:link"), "Exclude messages with one or more link"); - assert.equal(describe("-has:image"), "Exclude messages with one or more image"); - assert.equal(describe("-has:attachment"), "Exclude messages with one or more attachment"); - - // operand suggestions follow. - - query = "has:"; - suggestions = get_suggestions("", query); - expected = ["has:link", "has:image", "has:attachment"]; - assert.deepEqual(suggestions.strings, expected); - - query = "has:im"; - suggestions = get_suggestions("", query); - expected = ["has:image"]; - assert.deepEqual(suggestions.strings, expected); - - query = "-has:im"; - suggestions = get_suggestions("", query); - expected = ["-has:image"]; - assert.deepEqual(suggestions.strings, expected); - - query = "att"; - suggestions = get_suggestions("", query); - expected = ["att", "has:attachment"]; - assert.deepEqual(suggestions.strings, expected); - - query = "has:lin"; - const base_query = "stream:Denmark is:alerted"; - suggestions = get_suggestions(base_query, query); - expected = ["has:link"]; - assert.deepEqual(suggestions.strings, expected); -}); - -test("check_is_suggestions", ({override}) => { - let query = "i"; - 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", () => {}); - - let suggestions = get_suggestions("", query); - let expected = [ - "i", - "is:dm", - "is:starred", - "is:mentioned", - "is:alerted", - "is:unread", - "is:resolved", - "sender:alice@zulip.com", - "dm:alice@zulip.com", - "dm-including:alice@zulip.com", - "has:image", - ]; - assert.deepEqual(suggestions.strings, expected); - - function describe(q) { - return suggestions.lookup_table.get(q).description_html; - } - - assert.equal(describe("is:dm"), "Direct messages"); - assert.equal(describe("is:starred"), "Starred messages"); - assert.equal(describe("is:mentioned"), "@-mentions"); - assert.equal(describe("is:alerted"), "Alerted messages"); - assert.equal(describe("is:unread"), "Unread messages"); - assert.equal(describe("is:resolved"), "Topics marked as resolved"); - - query = "-i"; - suggestions = get_suggestions("", query); - expected = [ - "-i", - "-is:dm", - "-is:starred", - "-is:mentioned", - "-is:alerted", - "-is:unread", - "-is:resolved", - ]; - assert.deepEqual(suggestions.strings, expected); - - assert.equal(describe("-is:dm"), "Exclude direct messages"); - assert.equal(describe("-is:starred"), "Exclude starred messages"); - assert.equal(describe("-is:mentioned"), "Exclude @-mentions"); - assert.equal(describe("-is:alerted"), "Exclude alerted messages"); - assert.equal(describe("-is:unread"), "Exclude unread messages"); - assert.equal(describe("-is:resolved"), "Exclude topics marked as resolved"); - - query = ""; - suggestions = get_suggestions("", query); - expected = [ - "", - "streams:public", - "is:dm", - "is:starred", - "is:mentioned", - "is:alerted", - "is:unread", - "is:resolved", - "sender:myself@zulip.com", - "stream:devel", - "stream:office", - "has:link", - "has:image", - "has:attachment", - ]; - assert.deepEqual(suggestions.strings, expected); - - query = ""; - let base_query = "is:dm"; - suggestions = get_suggestions(base_query, query); - expected = [ - "is:starred", - "is:mentioned", - "is:alerted", - "is:unread", - "sender:myself@zulip.com", - "has:link", - "has:image", - "has:attachment", - ]; - assert.deepEqual(suggestions.strings, expected); - - // operand suggestions follow. - - query = "is:"; - suggestions = get_suggestions("", query); - expected = ["is:dm", "is:starred", "is:mentioned", "is:alerted", "is:unread", "is:resolved"]; - assert.deepEqual(suggestions.strings, expected); - - query = "is:st"; - suggestions = get_suggestions("", query); - expected = ["is:starred"]; - assert.deepEqual(suggestions.strings, expected); - - query = "-is:st"; - suggestions = get_suggestions("", query); - expected = ["-is:starred"]; - assert.deepEqual(suggestions.strings, expected); - - query = "st"; - suggestions = get_suggestions("", query); - expected = ["st", "streams:public", "is:starred", "stream:"]; - assert.deepEqual(suggestions.strings, expected); - - query = "is:sta"; - base_query = "stream:Denmark has:link"; - suggestions = get_suggestions(base_query, query); - expected = ["is:starred"]; - assert.deepEqual(suggestions.strings, expected); -}); - -test("sent_by_me_suggestions", ({override}) => { - override(narrow_state, "stream", () => {}); - - let query = ""; - let suggestions = get_suggestions("", query); - assert.ok(suggestions.strings.includes("sender:myself@zulip.com")); - assert.equal( - suggestions.lookup_table.get("sender:myself@zulip.com").description_html, - "Sent by me", - ); - - query = "sender"; - suggestions = get_suggestions("", query); - let expected = ["sender", "sender:myself@zulip.com", "sender:"]; - assert.deepEqual(suggestions.strings, expected); - - query = "-sender"; - suggestions = get_suggestions("", query); - expected = ["-sender", "-sender:myself@zulip.com", "-sender:"]; - assert.deepEqual(suggestions.strings, expected); - - query = "from"; - suggestions = get_suggestions("", query); - expected = ["from", "from:myself@zulip.com", "from:"]; - assert.deepEqual(suggestions.strings, expected); - - query = "-from"; - suggestions = get_suggestions("", query); - expected = ["-from", "-from:myself@zulip.com", "-from:"]; - assert.deepEqual(suggestions.strings, expected); - - query = "sender:bob@zulip.com"; - suggestions = get_suggestions("", query); - expected = ["sender:bob@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); - - query = "from:bob@zulip.com"; - suggestions = get_suggestions("", query); - expected = ["from:bob@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); - - query = "sent"; - suggestions = get_suggestions("", query); - expected = ["sent", "sender:myself@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); - - query = "-sent"; - suggestions = get_suggestions("", query); - expected = ["-sent", "-sender:myself@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); - - query = "sent"; - let base_query = "stream:Denmark topic:Denmark1"; - suggestions = get_suggestions(base_query, query); - expected = ["sent", "sender:myself@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); - - query = "sender:m"; - base_query = "is:starred"; - suggestions = get_suggestions(base_query, query); - expected = ["sender:m", "sender:myself@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); - - query = "sender:"; - base_query = "is:starred"; - suggestions = get_suggestions(base_query, query); - expected = [ - "sender:", - "sender:myself@zulip.com", - "sender:alice@zulip.com", - "sender:bob@zulip.com", - "sender:jeff@zulip.com", - "sender:ted@zulip.com", - ]; - assert.deepEqual(suggestions.strings, expected); -}); - -test("topic_suggestions", ({override}) => { - let suggestions; - let expected; - - override(stream_topic_history_util, "get_server_history", () => {}); - stream_data.add_sub({stream_id: 77, name: "office", subscribed: true}); - override(narrow_state, "stream", () => "office"); - - const devel_id = 44; - const office_id = 77; - stream_data.add_sub({stream_id: devel_id, name: "devel", subscribed: true}); - stream_data.add_sub({stream_id: office_id, name: "office", subscribed: true}); - - suggestions = get_suggestions("", "te"); - expected = ["te", "sender:ted@zulip.com", "dm:ted@zulip.com", "dm-including:ted@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); - - stream_topic_history.add_message({ - stream_id: devel_id, - topic_name: "REXX", - }); - - for (const topic_name of ["team", "ignore", "test"]) { - stream_topic_history.add_message({ - stream_id: office_id, - topic_name, - }); - } - - suggestions = get_suggestions("", "te"); - expected = [ - "te", - "sender:ted@zulip.com", - "dm:ted@zulip.com", - "dm-including:ted@zulip.com", - "stream:office topic:team", - "stream:office topic:test", - ]; - assert.deepEqual(suggestions.strings, expected); - - function describe(q) { - 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"); - - suggestions = get_suggestions("topic:staplers", "stream:office"); - expected = ["stream:office"]; - assert.deepEqual(suggestions.strings, expected); - - suggestions = get_suggestions("stream:devel", "topic:"); - expected = ["topic:", "topic:REXX"]; - assert.deepEqual(suggestions.strings, expected); - - suggestions = get_suggestions("stream:devel", "-topic:"); - expected = ["-topic:", "-topic:REXX"]; - assert.deepEqual(suggestions.strings, expected); - - suggestions = get_suggestions("", "-topic:te"); - expected = ["-topic:te", "stream:office -topic:team", "stream:office -topic:test"]; - assert.deepEqual(suggestions.strings, expected); - - suggestions = get_suggestions("is:alerted stream:devel is:starred", "topic:"); - expected = ["topic:", "topic:REXX"]; - assert.deepEqual(suggestions.strings, expected); - - suggestions = get_suggestions("is:dm stream:devel", "topic:"); - expected = ["topic:"]; - assert.deepEqual(suggestions.strings, expected); - - suggestions = get_suggestions("topic:REXX stream:devel", "topic:"); - expected = ["topic:"]; - assert.deepEqual(suggestions.strings, expected); -}); - -test("topic_suggestions (limits)", () => { - let candidate_topics = []; - - function assert_result(guess, expected_topics) { - assert.deepEqual( - search.get_topic_suggestions_from_candidates({candidate_topics, guess}), - expected_topics, - ); - } - - assert_result("", []); - assert_result("zzz", []); - - candidate_topics = ["a", "b", "c"]; - assert_result("", ["a", "b", "c"]); - assert_result("b", ["b"]); - assert_result("z", []); - - candidate_topics = [ - "a1", - "a2", - "b1", - "b2", - "a3", - "a4", - "a5", - "c1", - "a6", - "a7", - "a8", - "c2", - "a9", - "a10", - "a11", - "a12", - ]; - // We max out at 10 topics, so as not to overwhelm the user. - assert_result("", ["a1", "a2", "b1", "b2", "a3", "a4", "a5", "c1", "a6", "a7"]); - assert_result("a", ["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10"]); - assert_result("b", ["b1", "b2"]); - assert_result("z", []); -}); - -test("whitespace_glitch", ({override}) => { - const query = "stream:office "; // note trailing space - - override(stream_topic_history_util, "get_server_history", () => {}); - stream_data.add_sub({stream_id: 77, name: "office", subscribed: true}); - - const suggestions = get_suggestions("", query); - - const expected = ["stream:office"]; - - assert.deepEqual(suggestions.strings, expected); -}); - -test("stream_completion", ({override}) => { - stream_data.add_sub({stream_id: 77, name: "office", subscribed: true}); - stream_data.add_sub({stream_id: 88, name: "dev help", subscribed: true}); - - override(narrow_state, "stream", () => {}); - - let query = "stream:of"; - let suggestions = get_suggestions("", query); - let expected = ["stream:of", "stream:office"]; - assert.deepEqual(suggestions.strings, expected); - - query = "-stream:of"; - suggestions = get_suggestions("", query); - expected = ["-stream:of", "-stream:office"]; - assert.deepEqual(suggestions.strings, expected); - - query = "hel"; - suggestions = get_suggestions("", query); - expected = ["hel", "stream:dev+help"]; - assert.deepEqual(suggestions.strings, expected); -}); - -function people_suggestion_setup() { - const ted = { - email: "ted@zulip.com", - user_id: 201, - full_name: "Ted Smith", - }; - people.add_active_user(ted); - - const bob = { - email: "bob@zulip.com", - user_id: 202, - full_name: "Bob Térry", - avatar_url: example_avatar_url, - }; - - people.add_active_user(bob); - const alice = { - email: "alice@zulip.com", - user_id: 203, - full_name: "Alice Ignore", - }; - people.add_active_user(alice); -} - -test("people_suggestions", ({override}) => { - override(narrow_state, "stream", noop); - people_suggestion_setup(); - - let query = "te"; - let suggestions = get_suggestions("", query); - let expected = [ - "te", - "sender:bob@zulip.com", - "sender:ted@zulip.com", - "dm:bob@zulip.com", // bob térry - "dm:ted@zulip.com", - "dm-including:bob@zulip.com", - "dm-including:ted@zulip.com", - ]; - - assert.deepEqual(suggestions.strings, expected); - - const is_person = (q) => suggestions.lookup_table.get(q).is_person; - assert.equal(is_person("dm:ted@zulip.com"), true); - assert.equal(is_person("sender:ted@zulip.com"), true); - assert.equal(is_person("dm-including:ted@zulip.com"), true); - - const has_image = (q) => suggestions.lookup_table.get(q).user_pill_context.has_image; - assert.equal(has_image("dm:bob@zulip.com"), true); - assert.equal(has_image("sender:bob@zulip.com"), true); - assert.equal(has_image("dm-including:bob@zulip.com"), true); - - const describe = (q) => suggestions.lookup_table.get(q).description_html; - assert.equal(describe("dm:ted@zulip.com"), "Direct messages with"); - assert.equal(describe("sender:ted@zulip.com"), "Sent by"); - assert.equal(describe("dm-including:ted@zulip.com"), "Direct messages including"); - - let expectedString = "Ted Smith"; - - const get_full_name = (q) => - suggestions.lookup_table.get(q).user_pill_context.display_value.string; - assert.equal(get_full_name("sender:ted@zulip.com"), expectedString); - assert.equal(get_full_name("dm:ted@zulip.com"), expectedString); - assert.equal(get_full_name("dm-including:ted@zulip.com"), expectedString); - - expectedString = `${example_avatar_url}?s=50`; - - const get_avatar_url = (q) => suggestions.lookup_table.get(q).user_pill_context.img_src; - assert.equal(get_avatar_url("dm:bob@zulip.com"), expectedString); - assert.equal(get_avatar_url("sender:bob@zulip.com"), expectedString); - assert.equal(get_avatar_url("dm-including:bob@zulip.com"), expectedString); - - suggestions = get_suggestions("", "Ted "); // note space - expected = ["Ted", "sender:ted@zulip.com", "dm:ted@zulip.com", "dm-including:ted@zulip.com"]; - - assert.deepEqual(suggestions.strings, expected); - - query = "sender:ted sm"; - let base_query = ""; - expected = ["sender:ted+sm", "sender:ted@zulip.com"]; - suggestions = get_suggestions(base_query, query); - assert.deepEqual(suggestions.strings, expected); - - query = "new"; - base_query = "sender:ted@zulip.com"; - expected = ["new"]; - suggestions = get_suggestions(base_query, query); - assert.deepEqual(suggestions.strings, expected); - - query = "sender:ted@tulip.com new"; - base_query = ""; - expected = ["sender:ted@tulip.com+new"]; - suggestions = get_suggestions(base_query, query); - assert.deepEqual(suggestions.strings, expected); - - query = "new"; - base_query = "sender:ted@tulip.com"; - expected = ["new"]; - suggestions = get_suggestions(base_query, query); - assert.deepEqual(suggestions.strings, expected); -}); - -test("operator_suggestions", ({override}) => { - override(narrow_state, "stream", () => undefined); - - // Completed operator should return nothing - let query = "stream:"; - let suggestions = get_suggestions("", query); - let expected = ["stream:"]; - assert.deepEqual(suggestions.strings, expected); - - query = "st"; - suggestions = get_suggestions("", query); - expected = ["st", "streams:public", "is:starred", "stream:"]; - assert.deepEqual(suggestions.strings, expected); - - query = "-s"; - suggestions = get_suggestions("", query); - expected = ["-s", "-streams:public", "-sender:myself@zulip.com", "-stream:", "-sender:"]; - assert.deepEqual(suggestions.strings, expected); - - query = "-f"; - const base_query = "stream:Denmark is:alerted"; - suggestions = get_suggestions(base_query, query); - expected = ["-f", "-from:myself@zulip.com", "-from:"]; - assert.deepEqual(suggestions.strings, expected); -}); - -test("queries_with_spaces", () => { - stream_data.add_sub({stream_id: 77, name: "office", subscribed: true}); - stream_data.add_sub({stream_id: 88, name: "dev help", subscribed: true}); - - // test allowing spaces with quotes surrounding operand - let query = 'stream:"dev he"'; - let suggestions = get_suggestions("", query); - let expected = ["stream:dev+he", "stream:dev+help"]; - assert.deepEqual(suggestions.strings, expected); - - // test mismatched quote - query = 'stream:"dev h'; - suggestions = get_suggestions("", query); - expected = ["stream:dev+h", "stream:dev+help"]; - assert.deepEqual(suggestions.strings, expected); - - // test extra space after operator still works - query = "stream: offi"; - suggestions = get_suggestions("", query); - expected = ["stream:offi", "stream:office"]; - assert.deepEqual(suggestions.strings, expected); -}); - -// When input search query contains multiple operators -// and a pill hasn't been formed from those operators. -test("multiple_operators_without_pills", () => { - let query = "is:dm al"; - let base_query = ""; - let suggestions = get_suggestions(base_query, query); - let expected = [ - "is:dm al", - "is:dm is:alerted", - "is:dm sender:alice@zulip.com", - "is:dm dm:alice@zulip.com", - "is:dm dm-including:alice@zulip.com", - ]; - assert.deepEqual(suggestions.strings, expected); - - query = "abc is:alerted sender:ted@zulip.com"; - base_query = ""; - suggestions = get_suggestions(base_query, query); - expected = ["abc is:alerted sender:ted@zulip.com"]; - assert.deepEqual(suggestions.strings, expected); -}); diff --git a/zerver/lib/home.py b/zerver/lib/home.py index 370eeb598a..4d123efe59 100644 --- a/zerver/lib/home.py +++ b/zerver/lib/home.py @@ -187,7 +187,6 @@ def build_page_params_for_home_page_load( insecure_desktop_app=insecure_desktop_app, login_page=settings.HOME_NOT_LOGGED_IN, warn_no_email=settings.WARN_NO_EMAIL, - search_pills_enabled=settings.SEARCH_PILLS_ENABLED, # Only show marketing email settings if on Zulip Cloud corporate_enabled=settings.CORPORATE_ENABLED, ## Misc. extra data. diff --git a/zerver/tests/test_home.py b/zerver/tests/test_home.py index b03d6ab80a..14f9256c59 100644 --- a/zerver/tests/test_home.py +++ b/zerver/tests/test_home.py @@ -188,7 +188,6 @@ class HomeTest(ZulipTestCase): "recent_private_conversations", "request_language", "scheduled_messages", - "search_pills_enabled", "server_avatar_changes_disabled", "server_emoji_data_url", "server_generation", @@ -355,7 +354,6 @@ class HomeTest(ZulipTestCase): "queue_id", "realm_rendered_description", "request_language", - "search_pills_enabled", "server_sentry_dsn", "show_billing", "show_plans", diff --git a/zproject/default_settings.py b/zproject/default_settings.py index 9941671964..7523a97fbe 100644 --- a/zproject/default_settings.py +++ b/zproject/default_settings.py @@ -293,9 +293,6 @@ ALWAYS_SEND_ALL_HOTSPOTS = False # self-hosters who want to disable the tutorial entirely on their system. TUTORIAL_ENABLED = True -# In-development search pills feature. -SEARCH_PILLS_ENABLED = False - # We log emails in development environment for accessing # them easily through /emails page DEVELOPMENT_LOG_EMAILS = DEVELOPMENT diff --git a/zproject/dev_settings.py b/zproject/dev_settings.py index b45085c30b..2033fbbdec 100644 --- a/zproject/dev_settings.py +++ b/zproject/dev_settings.py @@ -164,8 +164,6 @@ if FAKE_LDAP_MODE: THUMBNAIL_IMAGES = True -SEARCH_PILLS_ENABLED = bool(os.getenv("SEARCH_PILLS_ENABLED")) - BILLING_ENABLED = True LANDING_PAGE_NAVBAR_MESSAGE: Optional[str] = None diff --git a/zproject/test_extra_settings.py b/zproject/test_extra_settings.py index 14e8e97f65..ee546e59d9 100644 --- a/zproject/test_extra_settings.py +++ b/zproject/test_extra_settings.py @@ -49,10 +49,6 @@ else: CAMO_URI = "https://external-content.zulipcdn.net/external_content/" CAMO_KEY = "dummy" -if PUPPETEER_TESTS: - # Disable search pills prototype for production use - SEARCH_PILLS_ENABLED = False - if "RUNNING_OPENAPI_CURL_TEST" in os.environ: RUNNING_OPENAPI_CURL_TEST = True