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
Allow configuration of sorting for Project Lists #15288
Conversation
c54a2cd
to
14faf9a
Compare
82cfd74
to
e0b5dd4
Compare
6c48d96
to
d1b6dc6
Compare
d1b6dc6
to
376974f
Compare
58f2050
to
4717be3
Compare
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.
The code structure is heading into the right direction. Unfortunately I found a larger number of issues that need to be worked on before merging.
From a user perspective I struggled with removing a sorting. It took me a while to understand that I could set it to the blank value again. This is how I see it specified as well but it felt akward.
- Brush up design of component by adding descriptive text, placeholder and margin:
-
Persist sorting when saving a list. Currently the sorting falls back to the "Project hierarchy"
-
Add feature spec that covers both the changing of unpersisted lists as well as saving the sort order upon persisting a list and then querying for it again e.g. in: https://github.com/opf/openproject/blob/dev/spec/features/projects/persisted_lists_spec.rb and https://github.com/opf/openproject/blob/dev/spec/features/projects/projects_index_spec.rb
-
Sorting by "Project hierarchy" is currently mutually exclusive with sorting by any other column. The reason for this is the inability to sort by a second/third argument on each level. That is why the projects table upon clicking on the hierarchy sorting trigger resets the sorting to only work with the "Project hierarchy".
-
Sorting by "Project hierarchy" only makes sense in a single direction. When having selected that option, the "Asc"/"Desc" toggle should be removed I think.
-
When exporting a project list (e.g. to PDF) the sort order should be applied as well.
@selectable_columns ||= [ | ||
{ id: :lft, name: I18n.t(:label_project_hierarchy) } | ||
] + helpers.projects_columns_options | ||
end |
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 method would be better placed in the SortByComponent
since that component is the only one using the method. It could then even become a private method.
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.
No, it cannot be part of the SortByComponent
as this component does not know that it is used in a project query context. So we need to pass in the selectable columns and this place is the right place, as it is the last component in the hierarchy that knows that it is dealing with a ProjectQuery
@@ -29,11 +33,20 @@ | |||
dragAreaLabel: I18n.t(:'queries.configure_view.columns.drag_area_label'), | |||
appendToComponent: 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.
Now that the SortByComponent
is in, it would make sense to extract the part about the columns into its own component that could then also be reused in the administration. There wouldn't be too much template code in it but a number of helper methods could be moved into it.
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.
Isn't this PR about implementing the sorting functionality? Extracting the column stuff is a perfect candidate for a Code maintenance follow up ticket. I'd like not to extend the range of this PR as it already is way to much for what it does.
|
||
def current_orders | ||
JSON.dump(query.orders.map { |order| [order.attribute, order.direction] }) | ||
end |
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.
This code serializes the query's order so that it can be placed in the form. I guess using the params-from-query
controller will not work since the values would be overwritten. And I am still unsure about whether the js based approach turns out to be a good one (currently also discussing with @toy).
But if we go this way, then I'd think extracting the serialization into a shared helper right away would make sense as I would then expect the functionality to be reused time and again.
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.
Looking at the JS code which does the same, do we need to have this code in here at all? We could let the JS set the value upon initialization.
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.
This serializes the queries orders to the exact format how they need to be added to the query string. Can we PLEASE PLEASE PLEASE, not throw a reformatting of the query string in this PR, as we did in other places. We can do that in a follow up and change the serialization format ... But I don't know why we should ...
# Keys from the order can be symbols, strings or regexes | ||
selectable_columns.select do |column_option| | ||
all_order_keys.any? { |order_key| order_key === column_option[:id] } | ||
end |
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 would move the code finding the available orders into the Queries::Orders::AvailableOrders
as that reduces the interface exposed and only keep the part about the interception between the orders and the columns in here.
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.
This will not work as for example the lft
virtual column is not mentioned in the selects, so it would not work there.
declare readonly inputRowContainerTarget:HTMLElement; | ||
|
||
connect():void { | ||
this.inputRowTargets.forEach((row) => { |
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.
You should be able to also use inputRowTargetConnected
. Not necessary, though.
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.
Why would I want to do this. As we are dealing with multiple targets here, the TargetConnected method would fire 3 times and thus this code would be executed 3 times.
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.
My suggestion was to use the inputRowTargetConnected
not with this.inputRowTargets.forEach
but rather with only the single row that is connected when the element is called. In either case, it was just a suggestion.
I don't know how you got the screenshot you posted, but there is definetly spacing, so I don't know what commit you tested. I'll add the headlines. But the way how the dropdowns are styled are how the primer component looks. There is no chevron indicator, and I don't think we should apply a special styling here... |
This is a bit annoying as we are already doing special things like adding the |
The Opening
I see that the export link correctly points to
So that looks correct. I added a debug output to the
So, something goes wrong when the Also, looking at the job params that get stored in the database, we already have a wrong order: {
"job_id": "2277295d-025e-4383-8dfe-e436e8c0022e",
"locale": "en",
"priority": 7,
"timezone": "UTC",
"arguments": [
{
"user": {
"_aj_globalid": "gid://open-project/User/4"
},
"query": {
"user": {
"_aj_globalid": "gid://open-project/User/4"
},
"orders": {
"name": {
"value": "desc",
"_aj_serialized": "ActiveJob::Serializers::SymbolSerializer"
},
"cf_13": {
"value": "desc",
"_aj_serialized": "ActiveJob::Serializers::SymbolSerializer"
},
"_aj_symbol_keys": [
]
},
"filters": [
{
"name": {
"value": "active",
"_aj_serialized": "ActiveJob::Serializers::SymbolSerializer"
},
"values": [
"t"
],
"operator": "=",
"_aj_symbol_keys": [
"name",
"operator",
"values"
]
}
],
"selects": [
{
"value": "name",
"_aj_serialized": "ActiveJob::Serializers::SymbolSerializer"
},
{
"value": "created_at",
"_aj_serialized": "ActiveJob::Serializers::SymbolSerializer"
},
{
"value": "public",
"_aj_serialized": "ActiveJob::Serializers::SymbolSerializer"
},
{
"value": "cf_13",
"_aj_serialized": "ActiveJob::Serializers::SymbolSerializer"
}
],
"group_by": null,
"_aj_symbol_keys": [
"filters",
"orders",
"group_by",
"selects",
"user"
]
},
"export": {
"_aj_globalid": "gid://open-project/Projects::Export/7"
},
"mime_type": {
"value": "csv",
"_aj_serialized": "ActiveJob::Serializers::SymbolSerializer"
},
"_aj_ruby2_keywords": [
"export",
"user",
"mime_type",
"query"
]
}
],
"job_class": "Projects::ExportJob",
"executions": 0,
"queue_name": "default",
"enqueued_at": "2024-05-08T06:41:44.632141000Z",
"scheduled_at": null,
"provider_job_id": null,
"exception_executions": {
}
} |
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.
All is fine now functionality wise. I'd still prefer some changes to the code but yes, we can also do it in subsequent PRs.
Good job on digging up the reason for the export problems, @klaustopher |
Implements https://community.openproject.org/work_packages/51671