Skip to content
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
73 changes: 49 additions & 24 deletions src/assets/js/signal_sets.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,32 @@ function showWarningAlert(warningMessage, slideUpTime = 2000) {
});
}

function checkGeoCoverage(geoType, geoValue) {
var notCoveredSignals = [];
$.ajax({
url: "epidata/covidcast/geo_coverage/",
type: 'GET',
async: false,
data: {
'geo': `${geoType}:${geoValue}`
},
success: function (result) {
checkedSignalMembers.forEach(signal => {
var covered = result["epidata"].some(
e => (e.source === signal.data_source && e.signal === signal.signal)
)
if (!covered) {
notCoveredSignals.push(signal);
}
})
}
})
return notCoveredSignals;
async function checkGeoCoverage(geoType, geoValue) {
const notCoveredSignals = [];

try {
const result = await $.ajax({
url: "epidata/covidcast/geo_coverage/",
type: 'GET',
data: {
'geo': `${geoType}:${geoValue}`
}
});

checkedSignalMembers.forEach(signal => {
const covered = result["epidata"].some(
e => (e.source === signal.data_source && e.signal === signal.signal)
);
if (!covered) {
notCoveredSignals.push(signal);
}
});

return notCoveredSignals;
} catch (error) {
console.error('Error fetching geo coverage:', error);
return notCoveredSignals;
}
}


Expand Down Expand Up @@ -123,6 +128,18 @@ function addSelectedSignal(element) {
}
}

$("#showSelectedSignalsButton").click(function() {
alertPlaceholder.innerHTML = "";
$('#geographic_value').select2("data").forEach(geo => {
checkGeoCoverage(geo.geoType, geo.id).then((notCoveredSignals) => {
if (notCoveredSignals.length > 0) {
showNotCoveredGeoWarningMessage(notCoveredSignals, geo.text);
}
})

});
});

// Add an event listener to each 'bulk-select' element
let bulkSelectDivs = document.querySelectorAll('.bulk-select');
bulkSelectDivs.forEach(div => {
Expand Down Expand Up @@ -439,15 +456,23 @@ function showNotCoveredGeoWarningMessage(notCoveredSignals, geoValue) {

$('#geographic_value').on('select2:select', function (e) {
var geo = e.params.data;
var notCoveredSignals = checkGeoCoverage(geo.geoType, geo.id)
if (notCoveredSignals.length > 0) {
showNotCoveredGeoWarningMessage(notCoveredSignals, geo.text);
checkGeoCoverage(geo.geoType, geo.id).then((notCoveredSignals) => {
if (notCoveredSignals.length > 0) {
showNotCoveredGeoWarningMessage(notCoveredSignals, geo.text);
}
}
);
});


function submitMode(event) {
event.preventDefault();
var geographicValues = $('#geographic_value').select2('data');

if (geographicValues.length === 0) {
appendAlert("Please select at least one geographic location", "warning")
return;
}

if (currentMode === 'epivis') {
plotData();
Expand Down
13 changes: 12 additions & 1 deletion src/datasources/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,21 @@ def process_links(row, dua_column_name="DUA", link_column_name="Link"):
links.append(link.id)
else:
for match in matches:
link, _ = Link.objects.get_or_create(url=match[1], defaults={'link_type': match[0], })
link, _ = Link.objects.get_or_create(
url=match[1],
defaults={
"link_type": match[0],
},
)
links.append(link.id)
row["Links"] = links


def process_datasource_name(row):
if row["Name"]:
row["Name"] = row["Name"].capitalize()


def process_datasources(row):
datasource, _ = DataSource.objects.get_or_create(
name=row["DB Source"],
Expand Down Expand Up @@ -67,5 +77,6 @@ class Meta:
skip_unchanged = True

def before_import_row(self, row, **kwargs):
process_datasource_name(row)
process_links(row)
process_datasources(row)
34 changes: 22 additions & 12 deletions src/fixtures/severity_pyramid_rungs.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,10 @@
"fields": {
"created": "2024-08-15T09:57:49.327Z",
"modified": "2024-08-15T13:07:46.136Z",
"name": "Population",
"display_name": "Population",
"used_in": "signal_sets"
"name": "Entire Population",
"display_name": "Entire Population",
"used_in": "signal_sets",
"display_order_number": 1
}
},
{
Expand All @@ -95,7 +96,8 @@
"modified": "2024-08-15T13:07:46.136Z",
"name": "Vaccinated",
"display_name": "Vaccinated",
"used_in": "signal_sets"
"used_in": "signal_sets",
"display_order_number": 2
}
},
{
Expand All @@ -106,7 +108,8 @@
"modified": "2024-08-15T13:07:46.136Z",
"name": "Infected",
"display_name": "Infected",
"used_in": "signal_sets"
"used_in": "signal_sets",
"display_order_number": 3
}
},
{
Expand All @@ -117,7 +120,8 @@
"modified": "2024-08-15T13:07:46.136Z",
"name": "Tested",
"display_name": "Tested",
"used_in": "signal_sets"
"used_in": "signal_sets",
"display_order_number": 4
}
},
{
Expand All @@ -128,7 +132,8 @@
"modified": "2024-08-15T13:07:46.136Z",
"name": "Ascertained (Case)",
"display_name": "Ascertained (Case)",
"used_in": "signal_sets"
"used_in": "signal_sets",
"display_order_number": 5
}
},
{
Expand All @@ -139,7 +144,8 @@
"modified": "2024-08-15T13:07:46.136Z",
"name": "Symptomatic",
"display_name": "Symptomatic",
"used_in": "signal_sets"
"used_in": "signal_sets",
"display_order_number": 6
}
},
{
Expand All @@ -150,7 +156,8 @@
"modified": "2024-08-15T13:07:46.136Z",
"name": "Outpatient / ED",
"display_name": "Outpatient / ED",
"used_in": "signal_sets"
"used_in": "signal_sets",
"display_order_number": 7
}
},
{
Expand All @@ -161,7 +168,8 @@
"modified": "2024-08-15T13:07:46.136Z",
"name": "Hospitalized",
"display_name": "Hospitalized",
"used_in": "signal_sets"
"used_in": "signal_sets",
"display_order_number": 8
}
},
{
Expand All @@ -172,7 +180,8 @@
"modified": "2024-08-15T13:07:46.136Z",
"name": "ICU",
"display_name": "ICU",
"used_in": "signal_sets"
"used_in": "signal_sets",
"display_order_number": 9
}
},
{
Expand All @@ -183,7 +192,8 @@
"modified": "2024-08-15T13:07:46.136Z",
"name": "Deceased",
"display_name": "Deceased",
"used_in": "signal_sets"
"used_in": "signal_sets",
"display_order_number": 10
}
}
]
2 changes: 1 addition & 1 deletion src/signal_sets/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class SignalSetFilterForm(forms.ModelForm):
queryset=SeverityPyramidRung.objects.filter(
# id__in=SignalSet.objects.values_list("severity_pyramid_rungs", flat="True")
used_in="signal_sets"
),
).order_by("display_order_number"),
widget=forms.CheckboxSelectMultiple(),
)

Expand Down
5 changes: 3 additions & 2 deletions src/signal_sets/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,10 @@ def skip_row(self, instance, original, row, import_validation_errors=None):
def after_import_row(self, row, row_result, **kwargs):
try:
signal_set_obj = SignalSet.objects.get(id=row_result.object_id)
signal_set_obj.pathogens.clear()
signal_set_obj.severity_pyramid_rungs.clear()
signal_set_obj.available_geographies.clear()
for pathogen in row["Pathogen(s)/Syndrome(s)"].split(","):
signal_set_obj.pathogens.clear()
pathogen = Pathogen.objects.get(name=pathogen, used_in="signal_sets")
signal_set_obj.pathogens.add(pathogen)
for severity_pyramid_rung in row["Surveillance Categories"].split(","):
Expand All @@ -231,7 +233,6 @@ def after_import_row(self, row, row_result, **kwargs):
used_in="signal_sets"
).first()
signal_set_obj.severity_pyramid_rungs.add(severity_pyramid_rung)

for available_geography in row["Geographic Granularity - Delphi"].split(","):
available_geography = Geography.objects.get(name=available_geography, used_in="signal_sets")
signal_set_obj.available_geographies.add(available_geography)
Expand Down
33 changes: 32 additions & 1 deletion src/signals/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from django.contrib import admin
from import_export.admin import ImportExportModelAdmin

from signals.resources import SignalResource, SignalBaseResource
from signals.resources import SignalResource, SignalBaseResource, OtherEndpointSignalResource


from signals.models import (
Expand All @@ -14,6 +14,7 @@
Pathogen,
SeverityPyramidRung,
Signal,
OtherEndointSignal,
SignalType,
SignalGeography,
GeographyUnit,
Expand Down Expand Up @@ -102,6 +103,7 @@ class SeverityPyramidRungAdmin(admin.ModelAdmin):
"name",
"display_name",
"used_in",
"display_order_number",
)
exclude = ("id",)
search_fields: tuple[Literal["name"]] = ("name",)
Expand Down Expand Up @@ -149,6 +151,35 @@ class SignalAdmin(ImportExportModelAdmin):
resource_classes: list[type[SignalResource]] = [SignalResource, SignalBaseResource]


@admin.register(OtherEndointSignal)
class OtherEndpointsSignalAdmin(ImportExportModelAdmin):
"""
Admin interface for managing signal objects.
"""

list_display: tuple[
Literal["name"],
Literal["signal_type"],
Literal["format_type"],
Literal["category"],
Literal["geographic_scope"],
] = ("name", "signal_type", "format_type", "category", "geographic_scope")
search_fields: tuple[
Literal["name"],
Literal["signal_type__name"],
Literal["format_type__name"],
Literal["category__name"],
Literal["geographic_scope__name"],
] = (
"name",
"signal_type__name",
"format_type__name",
"category__name",
"geographic_scope__name",
)
resource_classes: list[type[SignalResource]] = [OtherEndpointSignalResource]


@admin.register(SignalGeography)
class SignalGeographyAdmin(admin.ModelAdmin):
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.0.7 on 2025-03-12 17:52

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('signals', '0016_signal_source_view'),
]

operations = [
migrations.AddField(
model_name='severitypyramidrung',
name='display_order_number',
field=models.IntegerField(help_text='Display order number of the severity pyramid rung.', null=True, verbose_name='display order number'),
),
]
26 changes: 26 additions & 0 deletions src/signals/migrations/0018_otherendointsignal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Generated by Django 5.0.7 on 2025-03-27 18:21

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('signals', '0017_severitypyramidrung_display_order_number'),
]

operations = [
migrations.CreateModel(
name='OtherEndointSignal',
fields=[
],
options={
'verbose_name': 'Other Endpoint Signal',
'verbose_name_plural': 'Other Endpoint Signals',
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('signals.signal',),
),
]
13 changes: 13 additions & 0 deletions src/signals/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ class SeverityPyramidRung(TimeStampedModel):
default="signals",
)

display_order_number: models.IntegerField = models.IntegerField(
verbose_name=_("display order number"),
help_text=_("Display order number of the severity pyramid rung."),
null=True,
)

class Meta:
verbose_name_plural: str = "Severity Pyramid Rungs"
unique_together: list[str] = ["name", "used_in"]
Expand Down Expand Up @@ -569,6 +575,13 @@ def get_display_name(self):
return self.name


class OtherEndointSignal(Signal):
class Meta:
proxy = True
verbose_name = "Other Endpoint Signal"
verbose_name_plural = "Other Endpoint Signals"


class SignalsDbView(models.Model):
id = models.BigIntegerField(primary_key=True)
name = models.CharField(max_length=255)
Expand Down
Loading
Loading