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
32 changes: 27 additions & 5 deletions enferno/admin/models/Bulletin.py
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,9 @@ def to_compact(self) -> dict[str, Any]:
sources_json = []
if self.sources and len(self.sources):
for source in self.sources:
sources_json.append({"id": source.id, "title": source.title})
sources_json.append(
{"id": source.id, "title": source.title, "title_ar": source.title_ar}
)

return {
"id": self.id,
Expand Down Expand Up @@ -697,19 +699,37 @@ def to_dict(self, mode: Optional[str] = None) -> dict[str, Any]:
sources_json = []
if self.sources and len(self.sources):
for source in self.sources:
sources_json.append({"id": source.id, "title": source.title})
sources_json.append(
{"id": source.id, "title": source.title, "title_ar": source.title_ar}
)

# labels json
labels_json = []
if self.labels and len(self.labels):
for label in self.labels:
labels_json.append({"id": label.id, "title": label.title})
labels_json.append(
{
"id": label.id,
"title": label.title,
"title_ar": label.title_ar,
"path": label._build_path(),
"path_ar": label._build_path(translated=True),
}
)

# verified labels json
ver_labels_json = []
if self.ver_labels and len(self.ver_labels):
for vlabel in self.ver_labels:
ver_labels_json.append({"id": vlabel.id, "title": vlabel.title})
ver_labels_json.append(
{
"id": vlabel.id,
"title": vlabel.title,
"title_ar": vlabel.title_ar,
"path": vlabel._build_path(),
"path_ar": vlabel._build_path(translated=True),
}
)

# events json
events_json = []
Expand Down Expand Up @@ -806,7 +826,9 @@ def to_mode2(self) -> dict[str, Any]:
sources_json = []
if self.sources and len(self.sources):
for source in self.sources:
sources_json.append({"id": source.id, "title": source.title})
sources_json.append(
{"id": source.id, "title": source.title, "title_ar": source.title_ar}
)

return {
"class": "Bulletin",
Expand Down
20 changes: 18 additions & 2 deletions enferno/admin/models/Incident.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,15 @@ def to_dict(self, mode: Optional[str] = None) -> dict[str, Any]:
labels_json = []
if self.labels and len(self.labels):
for label in self.labels:
labels_json.append({"id": label.id, "title": label.title})
labels_json.append(
{
"id": label.id,
"title": label.title,
"title_ar": label.title_ar,
"path": label._build_path(),
"path_ar": label._build_path(translated=True),
}
)

# Locations json
locations_json = []
Expand Down Expand Up @@ -577,7 +585,15 @@ def to_mode2(self) -> dict[str, Any]:
labels_json = []
if self.labels and len(self.labels):
for label in self.labels:
labels_json.append({"id": label.id, "title": label.title})
labels_json.append(
{
"id": label.id,
"title": label.title,
"title_ar": label.title_ar,
"path": label._build_path(),
"path_ar": label._build_path(translated=True),
}
)

# Locations json
locations_json = []
Expand Down
20 changes: 16 additions & 4 deletions enferno/admin/models/Label.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,19 @@ class Label(db.Model, BaseMixin):
parent_label_id = db.Column(db.Integer, db.ForeignKey("label.id"), index=True, nullable=True)
parent = db.relationship("Label", remote_side=id, backref="sub_label")

def _build_path(self) -> str:
"""Walk up parent chain, return 'Grandparent > Parent' (excludes self)."""
def _build_path(self, translated: bool = False) -> str:
"""Walk up parent chain, return 'Grandparent > Parent' (excludes self).

With translated=True, use each ancestor's Arabic title, falling back to the
English title per level for ancestors that have no translation yet.
"""
parts = []
current = self.parent
seen = set()
while current and current.id not in seen:
seen.add(current.id)
parts.append(current.title)
title = (current.title_ar or current.title) if translated else current.title
parts.append(title)
current = current.parent
parts.reverse()
return " > ".join(parts) if parts else ""
Expand Down Expand Up @@ -77,7 +82,7 @@ def _is_valid_parent(self, parent_id) -> bool:
@staticmethod
def build_tree(verified=None):
"""Build nested tree structure using raw SQL for performance."""
query = "SELECT id, title, parent_label_id, verified, for_bulletin, for_actor, for_incident, for_offline FROM label"
query = "SELECT id, title, parent_label_id, verified, for_bulletin, for_actor, for_incident, for_offline, title_ar, comments, comments_ar FROM label"
conditions = []
if verified is True:
conditions.append("verified = true")
Expand All @@ -101,6 +106,9 @@ def build_tree(verified=None):
"for_actor": r[5],
"for_incident": r[6],
"for_offline": r[7],
"title_ar": r[8],
"comments": r[9],
"comments_ar": r[10],
"children": [],
}

Expand Down Expand Up @@ -151,6 +159,8 @@ def to_dict(self, mode: str = "1") -> dict[str, Any]:
"id": self.id,
"title": self.title,
"title_ar": self.title_ar if self.title_ar else None,
"path": self._build_path(),
"path_ar": self._build_path(translated=True),
"comments": self.comments if self.comments else None,
"comments_ar": self.comments_ar if self.comments_ar else None,
"order": self.order,
Expand Down Expand Up @@ -181,7 +191,9 @@ def to_mode2(self) -> dict[str, Any]:
return {
"id": self.id,
"title": self.title,
"title_ar": self.title_ar,
"path": self._build_path(),
"path_ar": self._build_path(translated=True),
"verified": self.verified,
"for_bulletin": self.for_bulletin,
"for_actor": self.for_actor,
Expand Down
1 change: 1 addition & 0 deletions enferno/admin/models/Source.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def to_dict(self) -> dict[str, Any]:
return {
"id": self.id,
"title": self.title,
"title_ar": self.title_ar,
"etl_id": self.etl_id,
"parent": {"id": self.parent.id, "title": self.parent.title} if self.parent else None,
"comments": self.comments,
Expand Down
130 changes: 65 additions & 65 deletions enferno/admin/templates/admin/activity.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{% extends 'layout.html' %}

{% block css %}
<link rel="stylesheet" href="/static/js/videojs/video-js.min.css">
<link rel="stylesheet" href="/static/js/videojs/video-js.min.css?v={{ config.VERSION }}">
{% endblock %}

{% block content %}
Expand Down Expand Up @@ -146,74 +146,74 @@

{% block js %}

<script src="/static/js/tinymce-vue.min.js"></script>

<script src="/static/js/dropzone/dropzone.min.js"></script>
<script src="/static/js/components/VueDropzone.js"></script>

<script src="/static/js/mixins/media-mixin.js"></script>
<script src="/static/js/mixins/form-builder-mixin.js"></script>

<script src="/static/js/components/GeoMap.js"></script>
<script src="/static/js/components/GlobalMap.js"></script>
<script src="/static/js/components/EntityFlowMap.js"></script>
<script src="/static/js/components/MobilityMap.js"></script>
<script src="/static/js/utils/MobilityMapUtils.js"></script>
<script src="/static/js/components/GeoLocations.js"></script>

<script src="/static/js/components/UniField.js"></script>
<script src="/static/js/components/DualField.js"></script>
<script src="/static/js/components/SearchField.js"></script>

<script src="/static/js/components/BulletinCard.js"></script>
<script src="/static/js/components/ActorProfiles.js"></script>
<script src="/static/js/components/ActorCard.js"></script>
<script src="/static/js/components/IncidentCard.js"></script>
<script src="/static/js/components/EventCard.js"></script>
<script src="/static/js/components/MediaCard.js"></script>
<script src="/static/js/components/MediaThumbnail.js"></script>
<script src="/static/js/components/PreviewCard.js"></script>
<script src="/static/js/components/ReadMore.js"></script>

<script src="/static/js/components/BulletinSearchBox.js"></script>
<script src="/static/js/components/ActorSearchBox.js"></script>
<script src="/static/js/components/IncidentSearchBox.js"></script>
<script src="/static/js/components/ActivitySearchBox.js"></script>

<script src="/static/js/components/BulletinResult.js"></script>
<script src="/static/js/components/ActorResult.js"></script>
<script src="/static/js/components/IncidentResult.js"></script>

<script src="/static/js/components/RelatedBulletinsCard.js"></script>
<script src="/static/js/components/RelatedActorsCard.js"></script>
<script src="/static/js/components/RelatedIncidentsCard.js"></script>

<script src="/static/js/components/PopDateField.js"></script>
<script src="/static/js/components/PopDateRangeField.js"></script>
<script src="/static/js/components/PopDateTimeField.js"></script>

<script src="/static/js/components/MediaGrid.js"></script>
<script src="/static/js/components/PdfViewer.js"></script>
<script src="/static/js/components/NativePdfViewer.js"></script>
<script src="/static/js/components/DocxViewer.js"></script>
<script src="/static/js/components/ImageViewer.js"></script>
<script src="/static/js/components/InlineMediaRenderer.js"></script>

<script src="/static/js/components/Visualization.js"></script>
<script src="/static/js/force-graph.min.js"></script>

<script src="/static/js/components/MissingPersonCard.js"></script>
<script src="/static/js/components/MissingPersonField.js"></script>
<script src="/static/js/components/MixYesNoField.js"></script>
<script src="/static/js/components/MixSelectField.js"></script>
<script src="/static/js/components/MixReportersField.js"></script>

<script src="/static/js/videojs/video.min.js"></script>
<script src="/static/js/tinymce-vue.min.js?v={{ config.VERSION }}"></script>

<script src="/static/js/dropzone/dropzone.min.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/VueDropzone.js?v={{ config.VERSION }}"></script>

<script src="/static/js/mixins/media-mixin.js?v={{ config.VERSION }}"></script>
<script src="/static/js/mixins/form-builder-mixin.js?v={{ config.VERSION }}"></script>

<script src="/static/js/components/GeoMap.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/GlobalMap.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/EntityFlowMap.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/MobilityMap.js?v={{ config.VERSION }}"></script>
<script src="/static/js/utils/MobilityMapUtils.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/GeoLocations.js?v={{ config.VERSION }}"></script>

<script src="/static/js/components/UniField.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/DualField.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/SearchField.js?v={{ config.VERSION }}"></script>

<script src="/static/js/components/BulletinCard.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/ActorProfiles.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/ActorCard.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/IncidentCard.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/EventCard.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/MediaCard.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/MediaThumbnail.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/PreviewCard.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/ReadMore.js?v={{ config.VERSION }}"></script>

<script src="/static/js/components/BulletinSearchBox.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/ActorSearchBox.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/IncidentSearchBox.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/ActivitySearchBox.js?v={{ config.VERSION }}"></script>

<script src="/static/js/components/BulletinResult.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/ActorResult.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/IncidentResult.js?v={{ config.VERSION }}"></script>

<script src="/static/js/components/RelatedBulletinsCard.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/RelatedActorsCard.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/RelatedIncidentsCard.js?v={{ config.VERSION }}"></script>

<script src="/static/js/components/PopDateField.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/PopDateRangeField.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/PopDateTimeField.js?v={{ config.VERSION }}"></script>

<script src="/static/js/components/MediaGrid.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/PdfViewer.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/NativePdfViewer.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/DocxViewer.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/ImageViewer.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/InlineMediaRenderer.js?v={{ config.VERSION }}"></script>

<script src="/static/js/components/Visualization.js?v={{ config.VERSION }}"></script>
<script src="/static/js/force-graph.min.js?v={{ config.VERSION }}"></script>

<script src="/static/js/components/MissingPersonCard.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/MissingPersonField.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/MixYesNoField.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/MixSelectField.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/MixReportersField.js?v={{ config.VERSION }}"></script>

<script src="/static/js/videojs/video.min.js?v={{ config.VERSION }}"></script>

{% if config.GOOGLE_MAPS_API_KEY %}
{{ '<script src="https://maps.googleapis.com/maps/api/js?key='|safe + config.GOOGLE_MAPS_API_KEY + '&loading=async" async defer></script>'|safe }}
{% endif %}
<script src="/static/js/Leaflet.GoogleMutant.js"></script>
<script src="/static/js/Leaflet.GoogleMutant.js?v={{ config.VERSION }}"></script>



Expand Down
12 changes: 6 additions & 6 deletions enferno/admin/templates/admin/actor-fields.html
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,13 @@
</v-main>

{% endblock %} {% block outside %} {% endblock %} {% block js %}
<script src="/static/js/Sortable.min.js"></script>
<script src="/static/js/vuedraggable.umd.js"></script>
<script src="/static/js/Sortable.min.js?v={{ config.VERSION }}"></script>
<script src="/static/js/vuedraggable.umd.js?v={{ config.VERSION }}"></script>

<script src="/static/js/mixins/form-builder-mixin.js"></script>
<script src="/static/js/components/FieldListItem.js"></script>
<script src="/static/js/components/SelectFieldTypeDialog.js"></script>
<script src="/static/js/components/ShowDetails.js"></script>
<script src="/static/js/mixins/form-builder-mixin.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/FieldListItem.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/SelectFieldTypeDialog.js?v={{ config.VERSION }}"></script>
<script src="/static/js/components/ShowDetails.js?v={{ config.VERSION }}"></script>

<script nonce="{{ csp_nonce() }}">
const { createApp } = Vue;
Expand Down
Loading
Loading