Skip to content

Commit

Permalink
Allow filtering of incidents that have all of a selected set of tags (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
whitdog47 authored Feb 29, 2024
1 parent 35f7dff commit 4e71fb3
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 9 deletions.
49 changes: 48 additions & 1 deletion src/dispatch/database/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ def get_named_models(self):
model = self.filter_spec["model"]
if model in ["Participant", "Commander"]:
return {"IndividualContact"}
if model == "TagAll":
return {"Tag"}
else:
return {self.filter_spec["model"]}
return set()
Expand All @@ -122,6 +124,8 @@ def format_for_sqlalchemy(self, query, default_model):
filter_spec = self.filter_spec
if filter_spec.get("model") in ["Participant", "Commander"]:
filter_spec["model"] = "IndividualContact"
elif filter_spec.get("model") == "TagAll":
filter_spec["model"] = "Tag"

operator = self.operator
value = self.value
Expand Down Expand Up @@ -484,6 +488,37 @@ def common_parameters(
]


def has_tag_all(filter_spec: List[dict]):
"""Checks if the filter spec has a TagAll filter."""

if isinstance(filter_spec, list):
return False

for key, value in filter_spec.items():
if key == "and":
for condition in value:
or_condition = condition.get("or", [])
if or_condition and or_condition[0].get("model") == "TagAll":
return True
return False


def rebuild_filter_spec_without_tag_all(filter_spec: List[dict]):
"""Rebuilds the filter spec without the TagAll filter."""
new_filter_spec = []
tag_all_spec = []
for key, value in filter_spec.items():
if key == "and":
for condition in value:
or_condition = condition.get("or", [])
if or_condition and or_condition[0].get("model") == "TagAll":
for cond in or_condition:
tag_all_spec.append({"and": [{"or": [cond]}]})
else:
new_filter_spec.append(condition)
return ({"and": new_filter_spec} if len(new_filter_spec) else None, tag_all_spec)


def search_filter_sort_paginate(
db_session,
model,
Expand All @@ -508,12 +543,24 @@ def search_filter_sort_paginate(

query_restricted = apply_model_specific_filters(model_cls, query, current_user, role)

tag_all_filters = []
if filter_spec:
query = apply_filter_specific_joins(model_cls, filter_spec, query)
query = apply_filters(query, filter_spec, model_cls)
# if the filter_spec has the TagAll filter, we need to split the query up
# and intersect all of the results
if has_tag_all(filter_spec):
new_filter_spec, tag_all_spec = rebuild_filter_spec_without_tag_all(filter_spec)
if new_filter_spec:
query = apply_filters(query, new_filter_spec, model_cls)
for tag_filter in tag_all_spec:
tag_all_filters.append(apply_filters(query, tag_filter, model_cls))
else:
query = apply_filters(query, filter_spec, model_cls)

if model == "Incident":
query = query.intersect(query_restricted)
for filter in tag_all_filters:
query = query.intersect(filter)

if sort_by:
sort_spec = create_sort_spec(model, sort_by, descending)
Expand Down
33 changes: 25 additions & 8 deletions src/dispatch/static/dispatch/src/incident/TableFilterDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,28 @@
<v-list-item>
<tag-type-filter-combobox v-model="local_tag_type" label="Tag Types" />
</v-list-item>
<v-list-item>
<tag-filter-auto-complete
v-model="local_tag"
label="Tags"
model="incident"
:project="local_project"
/>
</v-list-item>
<v-card variant="outlined" class="ml-4 mr-4 mb-4">
<v-card-subtitle class="mt-2 mb-2">Has <b>all</b> of these tags</v-card-subtitle>
<v-list-item>
<tag-filter-auto-complete
v-model="local_tag_all"
label="Tags"
model="incident"
:project="local_project"
/>
</v-list-item>
</v-card>
<v-card variant="outlined" class="ml-4 mr-4">
<v-card-subtitle class="mt-2 mb-2">Has <b>any</b> of these tags</v-card-subtitle>
<v-list-item>
<tag-filter-auto-complete
v-model="local_tag"
label="Tags"
model="incident"
:project="local_project"
/>
</v-list-item>
</v-card>
<v-list-item>
<v-card class="mx-auto">
<v-card-title>Incident Participant</v-card-title>
Expand Down Expand Up @@ -120,6 +134,7 @@ export default {
local_reported_at: {},
local_status: [],
local_tag: [],
local_tag_all: [],
local_tag_type: [],
local_participant_is_commander: false,
local_participant: null,
Expand All @@ -136,6 +151,7 @@ export default {
"table.options.filters.reported_at",
"table.options.filters.status",
"table.options.filters.tag",
"table.options.filters.tag_all",
"table.options.filters.tag_type",
"table.options.filters.commander",
"table.options.filters.participant",
Expand Down Expand Up @@ -165,6 +181,7 @@ export default {
this.reported_at = this.local_reported_at
this.status = this.local_status
this.tag = this.local_tag
this.tag_all = this.local_tag_all
this.tag_type = this.local_tag_type
if (Array.isArray(this.local_participant)) {
this.local_participant = this.local_participant[0]
Expand Down
1 change: 1 addition & 0 deletions src/dispatch/static/dispatch/src/incident/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ const state = {
incident_severity: [],
status: [],
tag: [],
tag_all: [],
project: [],
tag_type: [],
reported_at: {
Expand Down

0 comments on commit 4e71fb3

Please sign in to comment.