Skip to content

Commit 9c1910b

Browse files
Merge pull request #709 from pitangainnovare/impl/indicator-to-search
Cria botão para abrir tela de busca a partir de tela de indicadores
2 parents 1328883 + 7ed4d70 commit 9c1910b

4 files changed

Lines changed: 139 additions & 1 deletion

File tree

indicator/models.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from indicator.metrics.config import ComputedMetric, MetricGroup, PhysicalMetric
2727
from institution.models import Institution
2828
from location.models import Location
29+
from search.models import SearchPage
2930
from search_gateway.filter_ui import build_data_source_form_payload, render_filter_sidebar
3031
from search_gateway.request_filters import extract_applied_filters
3132
from usefulmodels.models import ActionAndPractice, ThematicArea
@@ -926,6 +927,19 @@ class ChartBasePage(Page):
926927
class Meta:
927928
abstract = True
928929

930+
def get_search_page_url(self):
931+
qs = SearchPage.objects.filter(live=True, data_source=self.data_source)
932+
933+
if getattr(self, "locale_id", None):
934+
localized = qs.filter(locale_id=self.locale_id).first()
935+
936+
if localized:
937+
return localized.url
938+
939+
page = qs.first()
940+
941+
return page.url if page else ""
942+
929943
def get_indicator_nav_urls(self):
930944
urls = {"indicator_home_url": self.url}
931945
navigation = (self.data_source.metric_config_schema or {}).get("navigation") or {}
@@ -1106,6 +1120,7 @@ def get_context(self, request, *args, **kwargs):
11061120
"analysis_unit_options": analysis_unit_options,
11071121
"study_unit": study_unit,
11081122
"charts": charts,
1123+
"search_page_url": self.get_search_page_url(),
11091124
})
11101125
context.update(self.get_indicator_nav_urls())
11111126
context["applied_filters_json"] = json.dumps(context["applied_filters"])

indicator/static/indicator/css/custom.css

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,55 @@
7171
margin-left: auto;
7272
}
7373

74+
.indicator-controls-bar__search-section {
75+
padding-top: 0.95rem;
76+
border-top: 1px solid #ebf0f6;
77+
}
78+
79+
.indicator-controls-bar__search-total-row {
80+
display: flex;
81+
align-items: center;
82+
gap: 0.55rem;
83+
}
84+
85+
.indicator-controls-bar__search-total {
86+
font-size: 1.25rem;
87+
font-weight: 700;
88+
color: #1e3a5f;
89+
font-variant-numeric: tabular-nums;
90+
}
91+
92+
.indicator-controls-bar__search-icon {
93+
display: inline-flex;
94+
align-items: center;
95+
justify-content: center;
96+
width: 1.65rem;
97+
height: 1.65rem;
98+
padding: 0;
99+
border: 1px solid #c8d8f2;
100+
border-radius: 4px;
101+
background: var(--sg-accent-soft, #eef4ff);
102+
cursor: pointer;
103+
transition: background-color 0.16s ease, border-color 0.16s ease;
104+
}
105+
106+
.indicator-controls-bar__search-icon::before {
107+
content: "";
108+
display: block;
109+
width: 0.92rem;
110+
height: 0.92rem;
111+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 16 16' fill='none'%3E%3Ccircle cx='7' cy='7' r='4.5' stroke='%232F4EA1' stroke-width='1.35'/%3E%3Cpath d='M10.5 10.5L14 14' stroke='%232F4EA1' stroke-width='1.35' stroke-linecap='round'/%3E%3C/svg%3E");
112+
background-repeat: no-repeat;
113+
background-position: center;
114+
background-size: contain;
115+
}
116+
117+
.indicator-controls-bar__search-icon:hover,
118+
.indicator-controls-bar__search-icon:focus-visible {
119+
background: #dfe9ff;
120+
border-color: #b8caef;
121+
}
122+
74123
.indicator-controls-bar__form {
75124
margin: 0;
76125
}
@@ -81,6 +130,7 @@
81130
letter-spacing: 0.18em;
82131
text-transform: uppercase;
83132
color: #8fa2b8;
133+
font-family: 'Poppins', sans-serif;
84134
}
85135

86136
.indicator-controls-bar__section-title--label {

indicator/static/indicator/js/menu.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,14 @@ function initIndicatorForm(dataSource, studyUnit) {
310310

311311
clearAppliedFiltersContainer();
312312
renderChartsContainer(data, dataSource, studyUnit, formData.get('csrfmiddlewaretoken'));
313+
314+
const firstChart = Array.isArray(data.charts) && data.charts.find(c => !c.is_relative);
315+
if (firstChart) {
316+
const total = (firstChart.series || []).reduce(
317+
(sum, s) => sum + (s.data || []).reduce((a, b) => a + (Number(b) || 0), 0), 0
318+
);
319+
updateSearchButtonTotal(total);
320+
}
313321
})
314322
.catch(error => {
315323
console.error('Error:', error);
@@ -354,9 +362,57 @@ function initIndicatorForm(dataSource, studyUnit) {
354362
}
355363
}
356364

365+
function updateSearchButtonTotal(total) {
366+
const el = document.getElementById('indicator-search-total');
367+
if (!el) return;
368+
el.textContent = typeof total === 'number' ? total.toLocaleString() : total;
369+
}
370+
371+
function initGoToSearchButton() {
372+
const btn = document.getElementById('indicator-go-to-search');
373+
if (!btn) return;
374+
375+
btn.addEventListener('click', (event) => {
376+
event.preventDefault();
377+
378+
const searchUrl = (btn.dataset.searchUrl || '').trim();
379+
if (!searchUrl) return;
380+
381+
const menuForm = document.getElementById('indicator-filter-form');
382+
const filters = menuForm && window.SearchGatewayFilterForm
383+
? window.SearchGatewayFilterForm.serializeForm(menuForm)
384+
: {};
385+
386+
const scopeFromUrl = getScopeFilterFromUrl();
387+
const existingScope = filters.scope;
388+
const hasScopeInFilters = Array.isArray(existingScope)
389+
? existingScope.some(v => String(v || '').trim())
390+
: !!String(existingScope || '').trim();
391+
if (!hasScopeInFilters && scopeFromUrl) {
392+
filters.scope = scopeFromUrl;
393+
}
394+
395+
delete filters.breakdown_variable;
396+
397+
const params = new URLSearchParams();
398+
Object.entries(filters).forEach(([key, value]) => {
399+
if (value == null || value === '') return;
400+
if (Array.isArray(value)) {
401+
value.forEach(v => { if (v != null && v !== '') params.append(key, v); });
402+
} else {
403+
params.append(key, value);
404+
}
405+
});
406+
407+
const query = params.toString();
408+
window.open(query ? `${searchUrl}?${query}` : searchUrl, '_blank');
409+
});
410+
}
411+
357412
document.addEventListener('DOMContentLoaded', () => {
358413
initIndicatorControlBarSelects();
359414
initScopeControls();
415+
initGoToSearchButton();
360416
});
361417

362418
if (typeof window !== 'undefined' && typeof window.gettext !== 'function') {

indicator/templates/controls_bar.html

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,23 @@
7878
</div>
7979
</div>
8080

81+
{% if search_page_url and study_unit == "document" %}
82+
<div class="indicator-controls-bar__search-section">
83+
<div class="indicator-controls-bar__section-title indicator-controls-bar__section-title--label">{% trans "Total documents" %}</div>
84+
<div class="indicator-controls-bar__search-total-row">
85+
<span class="indicator-controls-bar__search-total" id="indicator-search-total">&mdash;</span>
86+
<button
87+
type="button"
88+
id="indicator-go-to-search"
89+
class="indicator-controls-bar__search-icon"
90+
data-search-url="{{ search_page_url }}"
91+
title="{% trans 'Search documents with current filters' %}"
92+
aria-label="{% trans 'Search documents' %}"
93+
></button>
94+
</div>
95+
</div>
96+
{% endif %}
97+
8198
{% if indicator_config_fields %}
8299
<div
83100
class="indicator-controls-bar__config"
@@ -87,7 +104,7 @@
87104
>
88105
<div class="indicator-controls-bar__config-head">
89106
<div class="indicator-controls-bar__config-intro">
90-
<div class="indicator-controls-bar__section-title indicator-controls-bar__config-title">{% trans "Ranking setup" %}</div>
107+
<div class="indicator-controls-bar__section-title indicator-controls-bar__section-title--label indicator-controls-bar__config-title">{% trans "Ranking setup" %}</div>
91108
<p class="indicator-controls-bar__config-text">
92109
{% trans "Configuration values that shape the ranking before the lateral filters refine the result set." %}
93110
</p>

0 commit comments

Comments
 (0)