Opened 14 months ago
Last modified 12 months ago
#9983 assigned defect
Exclude filter for display doesn't work
| Reported by: | rochi | Owned by: | ChrisNelson |
|---|---|---|---|
| Priority: | normal | Component: | TracJsGanttPlugin |
| Severity: | normal | Keywords: | |
| Cc: | Trac Release: | 0.11 |
Description
If I want to display only open tickets with
display!=status:closed
The closed tickets are still displayed.
Attachments (2)
Change History (16)
comment:1 in reply to: ↑ description Changed 14 months ago by ChrisNelson
comment:2 Changed 14 months ago by rochi
In your code comments you are talking about TracQuery so I was a little bit confused.
That would be a variant.
But, I've also tried:
display=status:new|status:assigned|status:accepted
It shows also not all posible tickets.
comment:3 follow-up: ↓ 4 Changed 14 months ago by rochi
I've done some changes for the filter algorithm, it's not perfect and there are a lof of TODOs...
# Process each part into the display filter displayFilter = {} for f in displayList: field, value = f.split(':') if field in displayFilter: displayFilter[field].append(value) else: displayFilter[field] = [value] # Filter the tickets displayTickets = [] self.env.log.debug("Tickets available: %s", len(self.tickets)) for ticket in self.tickets: # Default to showing every ticket display = True # Process each element and disable display if all # filters fails to match. ((or) disjunction) for f in displayFilter: for v in displayFilter[f]: if ticket[f] == v: #self.env.log.debug("Display filter match '%s': '%s' for ticket #%s", # f, # v, # ticket['id']) display = True break #self.env.log.debug("Display filter '%s' not match: '%s' for ticket #%s", # f, # v, # ticket['id']) display = False if display: displayTickets.append(ticket) # Sort the tickets displayTickets.sort(self._compare_tickets)
Further work:
- disjunction for fields with same key otherwise conjunction.
There is still a problem with the order of subtasks, they are sometimes placed far away from their parents.
comment:4 in reply to: ↑ 3 ; follow-up: ↓ 5 Changed 14 months ago by ChrisNelson
Replying to rochi:
I've done some changes for the filter algorithm, it's not perfect and there are a lof of TODOs...
Thanks for working on this.
if field in displayFilter: displayFilter[field].append(value) else: displayFilter[field] = [value]
I wonder if value shouldn't be split on |. You can do id=1|2|3, so I think it would be natural to do display=owner:curly|moe.
Further work:
- disjunction for fields with same key otherwise conjunction.
There is still a problem with the order of subtasks, they are sometimes placed far away from their parents.
That may be deliberate. My original use case for filters was: schedule everything then show me what I should do next" so I sort by date after filtering. You could add a displaySort option to control that.
comment:5 in reply to: ↑ 4 Changed 14 months ago by rochi
Replying to ChrisNelson:
I wonder if value shouldn't be split on |. You can do id=1|2|3, so I think it would be natural to do display=owner:curly|moe.
You are right, but I think it's better to support both.
That may be deliberate. My original use case for filters was: schedule everything then show me what I should do next" so I sort by date after filtering. You could add a displaySort option to control that.
You missed my point, move the next task to the top is the correct behavior, but on a parent-child relation the parent have also move up.
This can be a variant:
- first item to schedule
- child from parent next to schedule
- parent
- other childs
comment:6 Changed 14 months ago by rochi
Support for: disjunction for fields with same key otherwise conjunction
# Process each part into the display filter
displayFilter = {}
for f in displayList:
field, value = f.split(':')
if field in displayFilter:
displayFilter[field].append(value)
else:
displayFilter[field] = [value]
# Filter the tickets
displayTickets = []
self.env.log.debug("Tickets available: %s",
len(self.tickets))
for ticket in self.tickets:
# Default to showing every ticket
fieldDisplay = True
# Process each element and disable display if all
# filters fails to match. ((or) disjunction)
for f in displayFilter:
display = True
for v in displayFilter[f]:
if ticket[f] == v:
#self.env.log.debug("Display filter match '%s': '%s' for ticket #%s",
# f,
# v,
# ticket['id'])
display = True
break
#self.env.log.debug("Display filter '%s' not match: '%s' for ticket #%s",
# f,
# v,
# ticket['id'])
display = False
fieldDisplay = fieldDisplay & display
if fieldDisplay:
displayTickets.append(ticket)
# Sort the tickets
displayTickets.sort(self._compare_tickets)
comment:7 follow-up: ↓ 8 Changed 14 months ago by rochi
Ok, I've finished my improvements (see patch)
New features are:
- Filter with 'display'
- display:status=new|status=assigned or by status=new|assigned
- The parent is now always on top of its childs and still considereds the schedule
- The first item in schedule is than the second item on front because the parent is always the first item
I'm sorry for some code snippets looking strange, but I'm very new to python.
comment:8 in reply to: ↑ 7 Changed 14 months ago by ChrisNelson
Replying to rochi:
Ok, I've finished my improvements (see patch)
Thanks! I'll try to review it in the next few days.
New features are:
- Filter with 'display'
- display:status=new|status=assigned or by status=new|assigned
- The parent is now always on top of its childs and still considereds the schedule
- The first item in schedule is than the second item on front because the parent is always the first item
I'm sorry for some code snippets looking strange, but I'm very new to python.
No problem. If the problems are minor, I'll clean them up. If I don't understand something, I'll let you know.
comment:9 Changed 12 months ago by ChrisNelson
- Status changed from new to assigned
I tried to apply this patch and can't get it to work. I end up with:
# If no display filter, just display all tickets if not options.get('display') or options['display'] == '': displayTickets = self.tickets # Otherwise, process the filter else: # Build the list of display filters from the configured value # The general form is # 'display=field:value|field:value...'. Split on pipe # to get each part displayList = options['display'].split('|') # Process each part into the display filter displayFilter = {} for f in displayList: field, value = f.split(':') values = value.split('|') if field in displayFilter: displayFilter[field].extend(values) else: displayFilter[field] = values
Note that the display filter is parsed twice on '|': once for multiple fields (field1:value1|field2:value2) and once for multiple values (field1:value1|value2).
I imagine both could be supported if we kept track of the previous field so that if the second split failed, we'd use the first field. That is, field1:value1|value2 would parse to field1:value1 and value2 and when the split of value2 on : failed, the code would know to look back to field1. This is more than I can do right now.
comment:10 follow-up: ↓ 11 Changed 12 months ago by rochi
That ist only the processing of the filters, right?
The real ticket filtering looks like:
# Filter the tickets displayTickets = [] self.env.log.debug("Tickets available: %s", len(self.tickets)) self.ticketsByID.clear() for ticket in self.tickets: # Default to showing every ticket fieldDisplay = True # Process each element and disable display if all # filters fails to match. ((or) disjunction) for f in displayFilter: display = True for v in displayFilter[f]: if ticket[f] == v: #self.env.log.debug("Display filter match '%s': '%s' for ticket #%s", # f, # v, # ticket['id']) display = True break #self.env.log.debug("Display filter '%s' not match: '%s' for ticket #%s", # f, # v, # ticket['id']) display = False fieldDisplay = fieldDisplay & display if fieldDisplay: displayTickets.append(ticket) self.ticketsByID[ticket['id']] = ticket # Sort the tickets by date and successor dependencies displayTickets.sort(self._compare_tickets)
and comes directly after the filter processing.
What is yout specific issue?
I have this code now running several months without problems.
comment:11 in reply to: ↑ 10 Changed 12 months ago by anonymous
Replying to rochi:
That ist only the processing of the filters, right?
...
What is yout specific issue?
I have this code now running several months without problems.
I have have a chart that shows 7 tasks if I don't add a display option.
- If I use display=owner:owner1|owner:owner2 I get "No tasks selected".
- If I use display=owner:owner1|owner2, I get "need more than 1 value to unpack" from field, value = f.split(':')
comment:12 Changed 12 months ago by ChrisNelson
comment:13 Changed 12 months ago by anonymous
After [11704], I can do
- display=field1:value1|field2:value2
- display=field1:value1|field1:value2
- display=field1:value1|value2
and all work as expected.
comment:14 Changed 12 months ago by ChrisNelson
I'm not yet comfortable enough with the sorting additions to put them on the main line but I attached a patch which should implement them on top of my commit.


Replying to rochi:
The filter specifies what tickets to include. The way it is written there really isn't a way to negate that to exclude tickets. We might add an "hide" filter (the opposite of display) so you could