list_widget: Explicitly pass generic sort functions to the list widget.

This is a prep commit for typescript migration of this module. In this commit
I made all the users of ListWidget pass generic sort functions like 'alphabetic'
and 'numeric' explicitly to avoid type conversions which we may need when moving
to typescript, also it simplifies our `set_sorting_function` a bit more.
This commit is contained in:
Lalit 2023-05-03 10:36:19 +05:30 committed by Tim Abbott
parent 3720fd5c76
commit b04dfd8c29
22 changed files with 96 additions and 34 deletions

View File

@ -29,6 +29,9 @@ export function rerender_alert_words_ui() {
},
$parent_container: $("#alert-word-settings"),
$simplebar_container: $("#alert-word-settings .progressive-table-wrapper"),
sort_fields: {
...ListWidget.generic_sort_functions("alphabetic", ["word"]),
},
});
}

View File

@ -110,10 +110,12 @@ function render_attachments_ui() {
},
},
$parent_container: $("#attachments-settings").expectOne(),
init_sort: ["numeric", "create_time"],
init_sort: "create_time_numeric",
initially_descending_sort: true,
sort_fields: {
mentioned_in: sort_mentioned_in,
...ListWidget.generic_sort_functions("alphabetic", ["name"]),
...ListWidget.generic_sort_functions("numeric", ["create_time", "size"]),
},
$simplebar_container: $("#attachments-settings .progressive-table-wrapper"),
});

View File

@ -92,6 +92,21 @@ export function numeric_sort(prop) {
};
}
const generic_sorts = {
alphabetic: alphabetic_sort,
numeric: numeric_sort,
};
export function generic_sort_functions(generic_func, props) {
const sorting_functions = {};
for (const prop of props) {
const key = `${prop}_${generic_func}`;
sorting_functions[key] = generic_sorts[generic_func](prop);
}
return sorting_functions;
}
export function valid_filter_opts(opts) {
if (!opts.filter) {
return true;
@ -146,10 +161,6 @@ export function create($container, list, opts) {
const meta = {
sorting_function: null,
sorting_functions: new Map(),
generic_sorting_functions: {
alphabetic: alphabetic_sort,
numeric: numeric_sort,
},
offset: 0,
list,
filtered_list: list,
@ -281,18 +292,20 @@ export function create($container, list, opts) {
meta.reverse_mode = reverse_mode;
},
// the sorting function is either the function or string that calls the
// function to sort the list by. The prop is used for generic functions
// that can be called to sort with a particular prop.
set_sorting_function(sorting_function, prop) {
// the sorting function is either the function or a string which will be a key
// for the sorting_functions map to get the function. In case of generic sort
// functions like numeric and alphabetic, we pass the string in the given format -
// "{property}_{numeric|alphabetic}" - e.g. "email_alphabetic" or "age_numeric".
set_sorting_function(sorting_function) {
if (typeof sorting_function === "function") {
meta.sorting_function = sorting_function;
} else if (typeof sorting_function === "string") {
if (typeof prop === "string") {
meta.sorting_function = meta.generic_sorting_functions[sorting_function](prop);
} else {
meta.sorting_function = meta.sorting_functions.get(sorting_function);
if (!meta.sorting_functions.has(sorting_function)) {
blueslip.error("Sorting function not found: " + sorting_function);
return;
}
meta.sorting_function = meta.sorting_functions.get(sorting_function);
}
},
@ -407,7 +420,8 @@ export function create($container, list, opts) {
},
sort(sorting_function, prop) {
widget.set_sorting_function(sorting_function, prop);
const key = prop ? `${prop}_${sorting_function}` : sorting_function;
widget.set_sorting_function(key);
widget.hard_redraw();
},
@ -431,7 +445,7 @@ export function create($container, list, opts) {
}
if (opts.init_sort) {
widget.set_sorting_function(...opts.init_sort);
widget.set_sorting_function(opts.init_sort);
}
if (opts.initially_descending_sort) {
@ -483,7 +497,7 @@ export function handle_sort($th, list) {
list.set_reverse_mode($th.hasClass("descend"));
// if `prop_name` is defined, it will trigger the generic codepath,
// if `prop_name` is defined, it will trigger the generic sort functions,
// and not if it is undefined.
list.sort(sort_type, prop_name);
}

View File

@ -858,6 +858,7 @@ export function complete_rerender() {
sort_fields: {
stream_sort,
topic_sort,
...ListWidget.generic_sort_functions("numeric", ["last_msg_id"]),
},
html_selector: get_topic_row,
$simplebar_container: $("#recent_topics_table .table_fix_head"),

View File

@ -138,8 +138,9 @@ export function populate_emoji() {
$parent_container: $("#emoji-settings").expectOne(),
sort_fields: {
author_full_name: sort_author_full_name,
...ListWidget.generic_sort_functions("alphabetic", ["name"]),
},
init_sort: ["alphabetic", "name"],
init_sort: "name_alphabetic",
$simplebar_container: $("#emoji-settings .progressive-table-wrapper"),
});

View File

@ -83,9 +83,10 @@ export function populate_exports_table(exports) {
},
},
$parent_container: $("#data-exports").expectOne(),
init_sort: [sort_user],
init_sort: sort_user,
sort_fields: {
user: sort_user,
...ListWidget.generic_sort_functions("numeric", ["export_time"]),
},
$simplebar_container: $("#data-exports .progressive-table-wrapper"),
});

View File

@ -90,9 +90,15 @@ function populate_invites(invites_data) {
},
},
$parent_container: $("#admin-invites-list").expectOne(),
init_sort: [sort_invitee],
init_sort: sort_invitee,
sort_fields: {
invitee: sort_invitee,
...ListWidget.generic_sort_functions("alphabetic", ["ref"]),
...ListWidget.generic_sort_functions("numeric", [
"invited",
"expires_at",
"invited_as",
]),
},
$simplebar_container: $("#admin-invites-list .progressive-table-wrapper"),
});

View File

@ -160,7 +160,7 @@ export function populate_linkifiers(linkifiers_data) {
},
},
$parent_container: $("#linkifier-settings").expectOne(),
init_sort: [sort_pattern],
init_sort: sort_pattern,
sort_fields: {
pattern: sort_pattern,
url: sort_url,

View File

@ -36,6 +36,10 @@ export function populate_list() {
);
},
},
sort_fields: {
...ListWidget.generic_sort_functions("alphabetic", ["user_name"]),
...ListWidget.generic_sort_functions("numeric", ["date_muted"]),
},
$parent_container: $("#muted-user-settings"),
$simplebar_container: $("#muted-user-settings .progressive-table-wrapper"),
});

View File

@ -60,7 +60,14 @@ export function populate_playgrounds(playgrounds_data) {
},
},
$parent_container: $("#playground-settings").expectOne(),
init_sort: ["alphabetic", "pygments_language"],
init_sort: "pygments_language_alphabetic",
sort_fields: {
...ListWidget.generic_sort_functions("alphabetic", [
"pygments_language",
"name",
"url_prefix",
]),
},
$simplebar_container: $("#playground-settings .progressive-table-wrapper"),
});
}

View File

@ -125,7 +125,10 @@ export function build_default_stream_table() {
},
},
$parent_container: $("#admin-default-streams-list").expectOne(),
init_sort: ["alphabetic", "name"],
init_sort: "name_alphabetic",
sort_fields: {
...ListWidget.generic_sort_functions("alphabetic", ["name"]),
},
$simplebar_container: $("#admin-default-streams-list .progressive-table-wrapper"),
});

View File

@ -45,7 +45,11 @@ export function populate_list() {
);
},
},
init_sort: ["numeric", "date_updated"],
init_sort: "date_updated_numeric",
sort_fields: {
...ListWidget.generic_sort_functions("alphabetic", ["stream", "topic"]),
...ListWidget.generic_sort_functions("numeric", ["date_updated", "visibility_policy"]),
},
initially_descending_sort: true,
$parent_container: $("#user-topic-settings"),
$simplebar_container: $("#user-topic-settings .progressive-table-wrapper"),

View File

@ -302,11 +302,12 @@ section.bots.create_table = () => {
onupdate: reset_scrollbar($bots_table),
},
$parent_container: $("#admin-bot-list").expectOne(),
init_sort: ["alphabetic", "full_name"],
init_sort: "full_name_alphabetic",
sort_fields: {
email: sort_bot_email,
bot_owner: sort_bot_owner,
role: sort_role,
...ListWidget.generic_sort_functions("alphabetic", ["full_name", "bot_type"]),
},
$simplebar_container: $("#admin-bot-list .progressive-table-wrapper"),
});
@ -330,12 +331,13 @@ section.active.create_table = (active_users) => {
onupdate: reset_scrollbar($users_table),
},
$parent_container: $("#admin-user-list").expectOne(),
init_sort: ["alphabetic", "full_name"],
init_sort: "full_name_alphabetic",
sort_fields: {
email: sort_email,
last_active: sort_last_active,
role: sort_role,
id: sort_user_id,
...ListWidget.generic_sort_functions("alphabetic", ["full_name"]),
},
$simplebar_container: $("#admin-user-list .progressive-table-wrapper"),
});
@ -359,11 +361,12 @@ section.deactivated.create_table = (deactivated_users) => {
onupdate: reset_scrollbar($deactivated_users_table),
},
$parent_container: $("#admin-deactivated-users-list").expectOne(),
init_sort: ["alphabetic", "full_name"],
init_sort: "full_name_alphabetic",
sort_fields: {
email: sort_email,
role: sort_role,
id: sort_user_id,
...ListWidget.generic_sort_functions("alphabetic", ["full_name"]),
},
$simplebar_container: $("#admin-deactivated-users-list .progressive-table-wrapper"),
});

View File

@ -99,6 +99,7 @@ export function build_widgets() {
sort_fields: {
email: settings_users.sort_email,
id: settings_users.sort_user_id,
...ListWidget.generic_sort_functions("alphabetic", ["full_name"]),
},
filter: {
$element: $("#people_to_add .add-user-list-filter"),

View File

@ -129,6 +129,7 @@ function make_list_widget({$parent_container, name, user_ids, user_can_remove_su
sort_fields: {
email: settings_users.sort_email,
id: settings_users.sort_user_id,
...ListWidget.generic_sort_functions("alphabetic", ["full_name"]),
},
$simplebar_container,
});

View File

@ -97,6 +97,7 @@ export function build_widgets() {
sort_fields: {
email: settings_users.sort_email,
id: settings_users.sort_user_id,
...ListWidget.generic_sort_functions("alphabetic", ["full_name"]),
},
modifier(user) {
const item = {

View File

@ -71,6 +71,7 @@ function make_list_widget({$parent_container, name, user_ids}) {
sort_fields: {
email: settings_users.sort_email,
id: settings_users.sort_user_id,
...ListWidget.generic_sort_functions("alphabetic", ["full_name"]),
},
modifier(item) {
return format_member_list_elem(item);

View File

@ -31,6 +31,7 @@ run_test("rerender_alert_words_ui", ({mock_template}) => {
list_widget_create_called = true;
return alert_words;
},
generic_sort_functions: noop,
});
mock_template("settings/alert_word_settings_item.hbs", false, (args) => {
assert.ok(["foo", "bar"].includes(args.alert_word.word));

View File

@ -401,6 +401,10 @@ run_test("sorting", () => {
filter: {
predicate: () => true,
},
sort_fields: {
...ListWidget.generic_sort_functions("alphabetic", ["name"]),
...ListWidget.generic_sort_functions("numeric", ["salary"]),
},
$simplebar_container: $scroll_container,
};
@ -503,7 +507,7 @@ run_test("custom sort", () => {
product: sort_by_product,
x_value: sort_by_x,
},
init_sort: [sort_by_product],
init_sort: sort_by_product,
$simplebar_container: $scroll_container,
});

View File

@ -43,7 +43,7 @@ let expected_data_to_replace_in_list_widget;
const ListWidget = mock_esm("../src/list_widget", {
modifier: noop,
generic_sort_functions: noop,
create(_container, mapped_topic_values, opts) {
const formatted_topics = [];
ListWidget.modifier = opts.modifier;

View File

@ -6,15 +6,17 @@ const {mock_esm, zrequire} = require("./lib/namespace");
const {run_test} = require("./lib/test");
const $ = require("./lib/zjquery");
const list_widget = mock_esm("../src/list_widget");
const noop = () => {};
const list_widget = mock_esm("../src/list_widget", {
generic_sort_functions: noop,
});
const muted_users_ui = mock_esm("../src/muted_users_ui");
const settings_muted_users = zrequire("settings_muted_users");
const muted_users = zrequire("muted_users");
const people = zrequire("people");
const noop = () => {};
run_test("settings", ({override}) => {
people.add_active_user({user_id: 5, email: "five@zulip.com", full_name: "Feivel Fiverson"});
muted_users.add_muted_user(5, 1577836800);

View File

@ -6,14 +6,16 @@ const {mock_esm, zrequire} = require("./lib/namespace");
const {run_test} = require("./lib/test");
const $ = require("./lib/zjquery");
const list_widget = mock_esm("../src/list_widget");
const noop = () => {};
const list_widget = mock_esm("../src/list_widget", {
generic_sort_functions: noop,
});
const settings_user_topics = zrequire("settings_user_topics");
const stream_data = zrequire("stream_data");
const user_topics = zrequire("user_topics");
const noop = () => {};
const frontend = {
stream_id: 101,
name: "frontend",