Skip to content
This repository was archived by the owner on Sep 3, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 34 additions & 3 deletions src/dispatch/database/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ def get_named_models(self):
return {"IndividualContact"}
if model == "TagAll":
return {"Tag"}
if model == "NotCaseType":
return {"CaseType"}
else:
return {self.filter_spec["model"]}
return set()
Expand All @@ -124,6 +126,8 @@ def format_for_sqlalchemy(self, query, default_model):
filter_spec = self.filter_spec
if filter_spec.get("model") in ["Participant", "Commander", "Assignee"]:
filter_spec["model"] = "IndividualContact"
elif filter_spec.get("model") == "NotCaseType":
filter_spec["model"] = "CaseType"
elif filter_spec.get("model") == "TagAll":
filter_spec["model"] = "Tag"

Expand Down Expand Up @@ -501,7 +505,7 @@ def common_parameters(
]


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

if isinstance(filter_spec, list):
Expand All @@ -511,12 +515,35 @@ def has_tag_all(filter_spec: List[dict]):
if key == "and":
for condition in value:
or_condition = condition.get("or", [])
if or_condition and or_condition[0].get("model") == "TagAll":
if or_condition and or_condition[0].get("model") == model:
return True
return False


def rebuild_filter_spec_without_tag_all(filter_spec: List[dict]):
def has_tag_all(filter_spec: List[dict]):
return has_filter_model("TagAll", filter_spec)


def has_not_case_type(filter_spec: List[dict]):
return has_filter_model("NotCaseType", filter_spec)


def rebuild_filter_spec_for_not_case_type(filter_spec: dict):
new_filter_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") == "NotCaseType":
for cond in or_condition:
cond["op"] = "!="
new_filter_spec.append({"and": [{"and": [cond]}]})
else:
new_filter_spec.append(condition)
Comment thread
whitdog47 marked this conversation as resolved.
return {"and": new_filter_spec}


def rebuild_filter_spec_without_tag_all(filter_spec: dict):
"""Rebuilds the filter spec without the TagAll filter."""
new_filter_spec = []
tag_all_spec = []
Expand Down Expand Up @@ -565,6 +592,10 @@ def search_filter_sort_paginate(
query = apply_filter_specific_joins(model_cls, filter_spec, query)
# if the filter_spec has the TagAll filter, we need to split the query up
# and intersect all of the results
if has_not_case_type(filter_spec):
new_filter_spec = rebuild_filter_spec_for_not_case_type(filter_spec)
if new_filter_spec:
query = apply_filters(query, new_filter_spec, model_cls)
if has_tag_all(filter_spec):
new_filter_spec, tag_all_spec = rebuild_filter_spec_without_tag_all(filter_spec)
if new_filter_spec:
Expand Down
29 changes: 25 additions & 4 deletions src/dispatch/static/dispatch/src/case/TableFilterDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,23 @@
<project-combobox v-model="local_project" label="Projects" />
</v-list-item>
<v-list-item>
<case-type-combobox :project="local_project" v-model="local_case_type" />
<v-card variant="outlined" class="pa-3">
<case-type-combobox :project="local_project" v-model="local_selected_case_types" />
<div class="d-flex align-center mt-1">
<v-switch
v-model="exclude_mode"
:disabled="!local_selected_case_types.length"
color="primary"
inset
hide-details
density="compact"
class="ml-2 mt-0"
/>
<span class="ml-2">{{
exclude_mode ? "Exclude selected" : "Include only selected"
}}</span>
</div>
</v-card>
</v-list-item>
<v-list-item>
<case-severity-combobox :project="local_project" v-model="local_case_severity" />
Expand Down Expand Up @@ -102,7 +118,12 @@ const props = defineProps({
const display = ref(false)
const local_case_priority = ref([])
const local_case_severity = ref([])
const local_case_type = ref([])
const local_selected_case_types = ref([])
const exclude_mode = ref(false) // Default to "include only selected" mode
const local_case_type = computed(() => (!exclude_mode.value ? local_selected_case_types.value : []))
const local_not_case_type = computed(() =>
exclude_mode.value ? local_selected_case_types.value : []
)
const local_closed_at = ref({})
const local_project = ref(props.projects)
const local_reported_at = ref({})
Expand All @@ -118,7 +139,6 @@ const case_priority = computed(
const case_severity = computed(
() => store.state.case_management.table.options.filters.case_severity
)
const case_type = computed(() => store.state.case_management.table.options.filters.case_type)
const project = computed(() => store.state.case_management.table.options.filters.project)
const status = computed(() => store.state.case_management.table.options.filters.status)
const tag = computed(() => store.state.case_management.table.options.filters.tag)
Expand All @@ -128,7 +148,7 @@ const numFilters = computed(() => {
return sum([
case_priority.value?.length || 0,
case_severity.value?.length || 0,
case_type.value?.length || 0,
local_selected_case_types.value?.length || 0,
project.value?.length || 0,
status.value?.length || 0,
tag.value?.length || 0,
Expand All @@ -152,6 +172,7 @@ const applyFilters = () => {
case_priority: local_case_priority.value,
case_severity: local_case_severity.value,
case_type: local_case_type.value,
not_case_type: local_not_case_type.value,
closed_at: local_closed_at.value,
project: local_project.value,
reported_at: local_reported_at.value,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export default {
computed: {
totalCost: function () {
var totalCost = this.caseCosts.reduce(function (accumulator, item) {
if (item.case_cost_type.model_type == "New") {
if (item.case_cost_type?.model_type == "New") {
return accumulator
}
return accumulator + item.amount
Expand Down
Loading