-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor system table filter and sorter #518
Conversation
hi, @qjiang002 Cool, thanks for such a fast implementation.
I wonder whether it could work when users just type a system name, such as |
Now it requires the prefix "system: bert" to search systems. One way to simplify this is to add a dropdown list before the search bar to auto-fill the prefix. WDYT |
@qjiang002 : what about if it doesn't start with "system:" or "dataset:" then we allow it to search any field. Would that work? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @qjiang002 ! I think we can definitely make the filtering UI better and this is in the right direction!
I think the reason why we wanted to change the design is that the search bar has become too crowded. Moving the task filter and dataset split filter to the table seems to be a good strategy and they are quite intuitive to use.
-
[dataset/system filter] I think it'll be more intuitive to use if we have separate input boxes for them. Or, if we want to save more space, could we move the dataset filter to the table header as well (It can be an input box instead of a list of options to select)? I guess the system filter may be the most used (?) so we can leave it in the search bar.
- I think we should provide options (or autocomplete) for dataset filtering. i.e.
GET /systems?dataset= cnn_dailymail
only supports filtering by the full dataset name. The client can get a list of datasets for autocompletion by queryingGET /datasets?name=cnn
- Regarding @neubig's suggestion, I think it is doable but could we create a separate PR for that? We need to change the backend and the "URL linking" logic for the frontend to make it work.
- We still need to support filtering by dataset only for the leaderboard to work. We can add another filter called
dataset_or_system
forGET /systems
. - To make it obvious why the records show up in the results, I think we should highlight the cells that match the query.
- May not be a good example, but if a user wants to see all systems for "cnn_dailymail" and they typed in "cnn". They would get a bunch of systems that have "cnn" (the model) in their names. This may be confusing.
- We still need to support filtering by dataset only for the leaderboard to work. We can add another filter called
- I think we should provide options (or autocomplete) for dataset filtering. i.e.
-
[Sorting] We have many columns (the table is very wide) so I am not sure if putting the sorter in the table header is the best option. Also, when we are sorting, the order of columns may change. If we want to put it in the header, I think we should make it obvious which column is currently being used to sort the records. We can make that column always visible (fixed to the right or left) and/or highlight it. And all the other columns should not change order.
@@ -135,11 +135,13 @@ def find_systems( | |||
if ids: | |||
search_conditions.append({"_id": {"$in": [ObjectId(_id) for _id in ids]}}) | |||
if system_name: | |||
search_conditions.append({"system_name": {"$regex": rf"^{system_name}.*"}}) | |||
search_conditions.append({"system_name": {"$regex": rf"{system_name}.*"}}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these would require scanning the entire database which may not scale. Could you please confirm?
@@ -220,6 +247,50 @@ export function SystemTableContent({ | |||
}, | |||
}; | |||
|
|||
const handleTableChange = ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of implementing all the table change logic in one function, I think it'll be more readable if it is implemented for each column where the filter is defined so you don't have to write these if-else statements to match filter names. There does not seem to be an onSort()
so we probably have to write sorter logic in this function though. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lyuyangh, I try to use the onFilter
property in ColumnsType
definition to call the onFilterChange
function to update the filtered system table, but I met some problems.
onFilter: (value, record) => boolean
: reseting the filter doesn't set the value to be null.onFilter
is not called.<Table onChange={onChange} />
must have aonChange
function so that the column'sonFilter
can be called.
Therefore, in PR #528 , I still keep the handleTableChange
function since Table's onChange
property must have value and filters can get the reset null value directly.
@@ -158,6 +184,7 @@ export function SystemTableContent({ | |||
render: (_, record) => record.created_at.format("MM/DD/YYYY HH:mm"), | |||
width: 130, | |||
align: "center", | |||
sorter: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the sorters also need to be controlled by filterValue
similar to the filters. This would allow the table to react to URL changes and show the default sort field.
} | ||
// Handle sorter change | ||
// Only one sorted column allowed now | ||
if (!(sorter instanceof Array)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It took me a while to understand how sort columns and directions are determined. I think something like this would be easier to read:
if (!(sorter instanceof Array)) {
if (sorter.column?.title == null || sorter.order == null) {
// user cleared sorter, set to default
// if not currently using the default sorter
onFilterChange({ sortField: "created_at", sortDir: "desc" });
} else {
// user modified sorter, apply sorter to filterValue
let sortFieldName = sorter.column.title;
if (sortFieldName === "Created At") sortFieldName = "created_at";
if (typeof sortFieldName !== "string") {
console.error(`sortFieldName=${sortFieldName} is not a string`);
} else {
onFilterChange({
sortField: sortFieldName,
sortDir: sorter.order === "descend" ? "desc" : "asc",
});
}
}
}
I put the default sorter before the more complex sorter logic. The if statement also handles null checks so we don't have to do it in the else block. I think you added toString()
to make tsc happy because column.title
is a union of many types. Using toString()
forces the value to be a string which may hide bugs though so I think using a type check is the safer thing to do.
@@ -195,6 +190,24 @@ export function SystemTableTools({ | |||
); | |||
} | |||
|
|||
const handleSearch = (query: string) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this sends out a request even if the query is incorrect. Also, it sends requests for each character when the user is entering the first part of the query (e.g. "dataset:"). This will increase the load of the backend and it also makes the frontend less responsive because the requests are in sequence.
filters[k]?.toString() !== filterValue.split | ||
) { | ||
onFilterChange({ split: filters[k]?.toString() }); | ||
} else if (k === "task" && filters[k]?.toString() !== filterValue.task) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like filters[k]
can sometimes be an array so this does not work properly. I would suggest to avoid toString()
as a type cast.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now the filters only allow one filtered value, so filters[k]
is of type FilterValue | null
. FilterValue
is defined as React.Key | boolean
, but the split
is of type string | undefined
.
In PR #528 , I try to separate the null/undefined
and Key/string
cases, but I don't find a way to avoid type casting.
Thanks @lyuyangh for the detailed suggestions! Here are some of my thoughts to improve the filter/sort function. [system/dataset]
[sorting]
|
I was just thinking that it's easier to type "sst2" than it is to type "dataset:sst2". If we have separate search bars I think that's not really an issue. |
@qjiang002 Sounds good! Let's have separate search bars for the dataset and system names. And yeah, I think we can put the sort column selector in the search bar for now. That seems easier to do and it also provides a better user experience. If you want, feel free to split these into multiple PRs. |
This PR is related to issue #485
Previous filters and sorters
Refactor: move filter lists and sorter to the system table header
Created At
in descending order.