Skip to content

Commit 24ac516

Browse files
committed
Initial tabbed Primo/TIMDEX interface
Why these changes are being introduced: USE UI needs affordances to switch between results from different sources. Primo results should be the default view. Relevant ticket(s): * [USE-31](https://mitlibraries.atlassian.net/browse/USE-31) * [TIMX-549](https://mitlibraries.atlassian.net/browse/TIMX-549) How this addresses that need: * Integrates Primo search into the controller and view layers * Adds Turbo frame 'tabs' to switch between Primo and TIMDEX results. Side effects of this change: * Maintaining separate views for each result type is probably not ideal, but I'm accepting it as a risk until we normalize TIMDEX records similarly to how we normalize Primo. * Several tests have been skipped for features that are no longer relevant to USE UI, but are core to GDT. We will need to revise our overall test strategy such that these features are tested as part of GDT. * FRBRized full record links don't always work. It the method we use breaks FRBR links for CDI records. Predictably, Ex Libris documentation on FRBR does not address this issue. We might decide to forgo FRBR links in general, or perhaps limit them by content type (assuming book results always come from Alma).
1 parent a86ecf7 commit 24ac516

File tree

7 files changed

+650
-384
lines changed

7 files changed

+650
-384
lines changed

app/controllers/search_controller.rb

Lines changed: 73 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,32 +15,76 @@ def results
1515
# inject session preference for boolean type if it is present
1616
params[:booleanType] = cookies[:boolean_type] || 'AND'
1717

18-
# hand off to Enhancer chain
19-
@enhanced_query = Enhancer.new(params).enhanced_query
18+
# Determine which tab to load - default to primo unless gdt is enabled
19+
@active_tab = if Flipflop.enabled?(:gdt)
20+
'gdt' # Keep existing GDT behavior unchanged
21+
else
22+
params[:tab] || 'primo' # Default to primo for new tabbed interface
23+
end
24+
25+
# Route to appropriate search based on active tab
26+
if Flipflop.enabled?(:gdt)
27+
# Keep existing GDT behavior unchanged
28+
load_gdt_results
29+
else
30+
case @active_tab
31+
when 'primo'
32+
load_primo_results
33+
when 'timdex'
34+
load_timdex_results
35+
end
36+
end
37+
end
2038

21-
# hand off enhanced query to builder
22-
query = QueryBuilder.new(@enhanced_query).query
39+
private
2340

24-
# builder hands off to wrapper which returns raw results here
25-
response = if Flipflop.enabled?(:gdt)
26-
execute_geospatial_query(query)
27-
else
28-
TimdexBase::Client.query(TimdexSearch::BaseQuery, variables: query)
29-
end
41+
def load_gdt_results
42+
@enhanced_query = Enhancer.new(params).enhanced_query
43+
query = QueryBuilder.new(@enhanced_query).query
44+
response = execute_geospatial_query(query)
3045

31-
# Handle errors
3246
@errors = extract_errors(response)
33-
34-
# Analayze results
35-
# The @pagination instance variable includes info about next/previous pages (where they exist) to assist the UI.
3647
@pagination = Analyzer.new(@enhanced_query, response).pagination if @errors.nil?
37-
38-
# Display results
3948
@results = extract_results(response)
4049
@filters = extract_filters(response)
4150
end
4251

43-
private
52+
def load_primo_results
53+
@enhanced_query = Enhancer.new(params).enhanced_query
54+
@errors = nil
55+
@results = []
56+
@pagination = nil
57+
58+
begin
59+
primo_search = PrimoSearch.new
60+
per_page = params[:per_page] || 20
61+
primo_response = primo_search.search(params[:q], per_page)
62+
63+
@results = NormalizePrimoResults.new(primo_response, params[:q]).normalize
64+
65+
# Basic pagination for now.
66+
if @results.present?
67+
@pagination = {
68+
hits: @results.count,
69+
start: 1,
70+
end: @results.count
71+
}
72+
end
73+
74+
rescue StandardError => e
75+
@errors = handle_primo_errors(e)
76+
end
77+
end
78+
79+
def load_timdex_results
80+
@enhanced_query = Enhancer.new(params).enhanced_query
81+
query = QueryBuilder.new(@enhanced_query).query
82+
response = TimdexBase::Client.query(TimdexSearch::BaseQuery, variables: query)
83+
84+
@errors = extract_errors(response)
85+
@pagination = Analyzer.new(@enhanced_query, response).pagination if @errors.nil?
86+
@results = extract_results(response)
87+
end
4488

4589
def active_filters
4690
ENV.fetch('ACTIVE_FILTERS', '').split(',').map(&:strip)
@@ -188,4 +232,16 @@ def validate_geobox_values!
188232
flash[:error] = 'Maximum latitude cannot exceed minimum latitude.'
189233
redirect_to root_url
190234
end
235+
236+
def handle_primo_errors(error)
237+
Rails.logger.error("Primo search error: #{error.message}")
238+
239+
if error.is_a?(ArgumentError)
240+
[{ 'message' => 'Primo search is not properly configured.' }]
241+
elsif error.is_a?(HTTP::TimeoutError)
242+
[{ 'message' => 'The Primo service is currently slow to respond. Please try again.' }]
243+
else
244+
[{ 'message' => error.message }]
245+
end
246+
end
191247
end

app/views/search/_form.html.erb

Lines changed: 108 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -31,118 +31,117 @@ keyword_placeholder = search_required ? "Enter your search" : "Keyword anywhere"
3131
<%= 'aria-describedby=site-desc' if Flipflop.enabled?(:gdt) %>>
3232

3333
<% if Flipflop.enabled?(:gdt) %>
34-
<details id="geobox-search-panel" class="form-panel" <%= "open" if params[:geobox] == "true" %>>
35-
<summary class="btn button-secondary" id="geobox-summary">
36-
<span id="geobox-search-label"><%= geobox_label %></span>
37-
</summary>
38-
<input id="geobox-search-field" class="fieldset-toggle" type="hidden" name="geobox"
39-
value="<%= params[:geobox] %>">
40-
<fieldset>
41-
<legend>Search within a geospatial bounding box</legend>
42-
<p>* All fields in this section are required</p>
43-
<div class="gridband layout-2c">
44-
<div class="field-wrap grid-item">
45-
<label class="geo-label" for="geobox-minLongitude">Minimum longitude</label>
46-
<input type="number" step="0.000001" min="-180.0" max="180.0"
47-
class="field field-text <%= "required" if geobox_required %>"
48-
id="geobox-minLongitude" name="geoboxMinLongitude" value="<%= params[:geoboxMinLongitude] %>"
49-
<%= 'required' if geobox_required %>
50-
aria-describedby="minLong-desc">
51-
<span class="geo-desc" id="minLong-desc">
52-
A decimal between -180.0 and 180.0 (Ex: -73.507239)
34+
<details id="geobox-search-panel" class="form-panel" <%= "open" if params[:geobox] == "true" %>>
35+
<summary class="btn button-secondary" id="geobox-summary">
36+
<span id="geobox-search-label"><%= geobox_label %></span>
37+
</summary>
38+
<input id="geobox-search-field" class="fieldset-toggle" type="hidden" name="geobox"
39+
value="<%= params[:geobox] %>">
40+
<fieldset>
41+
<legend>Search within a geospatial bounding box</legend>
42+
<p>* All fields in this section are required</p>
43+
<div class="gridband layout-2c">
44+
<div class="field-wrap grid-item">
45+
<label class="geo-label" for="geobox-minLongitude">Minimum longitude</label>
46+
<input type="number" step="0.000001" min="-180.0" max="180.0"
47+
class="field field-text <%= "required" if geobox_required %>"
48+
id="geobox-minLongitude" name="geoboxMinLongitude" value="<%= params[:geoboxMinLongitude] %>"
49+
<%= 'required' if geobox_required %>
50+
aria-describedby="minLong-desc">
51+
<span class="geo-desc" id="minLong-desc">
52+
A decimal between -180.0 and 180.0 (Ex: -73.507239)
53+
<span class="hint">Western Hemisphere is negative</span>
54+
</span>
55+
</div>
56+
<div class="field-wrap grid-item">
57+
<label class="geo-label" for="geobox-minLatitude">Minimum latitude</label>
58+
<input type="number" step="0.000001" min="-90.0" max="90.0"
59+
class="field field-text <%= "required" if geobox_required %>"
60+
id="geobox-minLatitude" name="geoboxMinLatitude" value="<%= params[:geoboxMinLatitude] %>"
61+
<%= 'required' if geobox_required %>
62+
aria-describedby="minLat-desc">
63+
<span class="geo-desc" id="minLat-desc">
64+
A decimal between -90.0 and 90.0 (Ex: 41.239083)
65+
<span class="hint">Southern Hemisphere is negative</span>
66+
</span>
67+
</div>
68+
<div class="field-wrap grid-item">
69+
<label class="geo-label" for="geobox-maxLongitude">Maximum longitude</label>
70+
<input type="number" step="0.000001" min="-180.0" max="180.0"
71+
class="field field-text <%= "required" if geobox_required %>"
72+
id="geobox-maxLongitude" name="geoboxMaxLongitude" value="<%= params[:geoboxMaxLongitude] %>"
73+
<%= 'required' if geobox_required %>
74+
aria-describedby="maxLong-desc">
75+
<span class="geo-desc" id="maxLong-desc">
76+
A decimal between -180.0 and 180.0 (Ex: -69.928713)
5377
<span class="hint">Western Hemisphere is negative</span>
5478
</span>
55-
</div>
56-
<div class="field-wrap grid-item">
57-
<label class="geo-label" for="geobox-minLatitude">Minimum latitude</label>
58-
<input type="number" step="0.000001" min="-90.0" max="90.0"
59-
class="field field-text <%= "required" if geobox_required %>"
60-
id="geobox-minLatitude" name="geoboxMinLatitude" value="<%= params[:geoboxMinLatitude] %>"
61-
<%= 'required' if geobox_required %>
62-
aria-describedby="minLat-desc">
63-
<span class="geo-desc" id="minLat-desc">
64-
A decimal between -90.0 and 90.0 (Ex: 41.239083)
65-
<span class="hint">Southern Hemisphere is negative</span>
66-
</span>
67-
</div>
68-
<div class="field-wrap grid-item">
69-
<label class="geo-label" for="geobox-maxLongitude">Maximum longitude</label>
79+
</div>
80+
<div class="field-wrap grid-item">
81+
<label class="geo-label" for="geobox-maxLatitude">Maximum latitude</label>
82+
<input type="number" step="0.000001" min="-90.0" max="90.0"
83+
class="field field-text <%= "required" if geobox_required %>"
84+
id="geobox-maxLatitude" name="geoboxMaxLatitude" value="<%= params[:geoboxMaxLatitude] %>"
85+
<%= 'required' if geobox_required %>
86+
aria-describedby="maxLat-desc">
87+
<span class="geo-desc" id="maxLat-desc">
88+
A decimal between -90.0 and 90.0 (Ex: 42.886759)
89+
<span class="hint">Southern Hemisphere is negative</span>
90+
</span>
91+
</div>
92+
</div>
93+
</fieldset>
94+
</details>
95+
<details id="geodistance-search-panel" class="form-panel" <%= "open" if params[:geodistance] == "true" %>>
96+
<summary class="btn button-secondary" id="geodistance-summary">
97+
<span id="geodistance-search-label"><%= geodistance_label %></span>
98+
</summary>
99+
<input id="geodistance-search-field" class="fieldset-toggle" type="hidden" name="geodistance"
100+
value="<%= params[:geodistance] %>">
101+
<fieldset>
102+
<legend>Search within a distance of a geographic point</legend>
103+
<p>* All fields in this section are required</p>
104+
<div class="gridband layout-2c">
105+
<div class="field-wrap grid-item">
106+
<label class="geo-label" for="geodistance-latitude">Latitude</label>
107+
<input type="number" step="0.000001" min="-90.0" max="90.0"
108+
class="field field-text <%= "required" if geodistance_required %>"
109+
id="geodistance-latitude" name="geodistanceLatitude"
110+
value="<%= params[:geodistanceLatitude] %>" aria-describedby="lat-desc"
111+
<%= 'required' if geodistance_required %>
112+
aria-describedby="lat-desc">
113+
<span class="geo-desc" id="lat-desc">
114+
A decimal between -90.0 and 90.0 (Ex: 42.279594)
115+
<span class="hint">Southern Hemisphere is negative</span>
116+
</span>
117+
</div>
118+
<div class="field-wrap grid-item">
119+
<label class="geo-label" for="geodistance-longitude">Longitude</label>
70120
<input type="number" step="0.000001" min="-180.0" max="180.0"
71-
class="field field-text <%= "required" if geobox_required %>"
72-
id="geobox-maxLongitude" name="geoboxMaxLongitude" value="<%= params[:geoboxMaxLongitude] %>"
73-
<%= 'required' if geobox_required %>
74-
aria-describedby="maxLong-desc">
75-
<span class="geo-desc" id="maxLong-desc">
76-
A decimal between -180.0 and 180.0 (Ex: -69.928713)
77-
<span class="hint">Western Hemisphere is negative</span>
78-
</span>
79-
</div>
80-
<div class="field-wrap grid-item">
81-
<label class="geo-label" for="geobox-maxLatitude">Maximum latitude</label>
82-
<input type="number" step="0.000001" min="-90.0" max="90.0"
83-
class="field field-text <%= "required" if geobox_required %>"
84-
id="geobox-maxLatitude" name="geoboxMaxLatitude" value="<%= params[:geoboxMaxLatitude] %>"
85-
<%= 'required' if geobox_required %>
86-
aria-describedby="maxLat-desc">
87-
<span class="geo-desc" id="maxLat-desc">
88-
A decimal between -90.0 and 90.0 (Ex: 42.886759)
89-
<span class="hint">Southern Hemisphere is negative</span>
90-
</span>
91-
</div>
121+
class="field field-text <%= "required" if geodistance_required %>"
122+
id="geodistance-longitude" name="geodistanceLongitude"
123+
value="<%= params[:geodistanceLongitude] %>" aria-describedby="long-desc"
124+
<%= 'required' if geodistance_required %>
125+
aria-describedby="long-desc">
126+
<span class="geo-desc" id="long-desc">
127+
A decimal between -180.0 and 180.0 (Ex: -83.732124)
128+
<span class="hint">Western Hemisphere is negative</span>
129+
</span>
92130
</div>
93-
</fieldset>
94-
</details>
95-
<details id="geodistance-search-panel" class="form-panel" <%= "open" if params[:geodistance] == "true" %>>
96-
<summary class="btn button-secondary" id="geodistance-summary">
97-
<span id="geodistance-search-label"><%= geodistance_label %></span>
98-
</summary>
99-
<input id="geodistance-search-field" class="fieldset-toggle" type="hidden" name="geodistance"
100-
value="<%= params[:geodistance] %>">
101-
<fieldset>
102-
<legend>Search within a distance of a geographic point</legend>
103-
<p>* All fields in this section are required</p>
104-
<div class="gridband layout-2c">
105-
<div class="field-wrap grid-item">
106-
<label class="geo-label" for="geodistance-latitude">Latitude</label>
107-
<input type="number" step="0.000001" min="-90.0" max="90.0"
108-
class="field field-text <%= "required" if geodistance_required %>"
109-
id="geodistance-latitude" name="geodistanceLatitude"
110-
value="<%= params[:geodistanceLatitude] %>" aria-describedby="lat-desc"
111-
<%= 'required' if geodistance_required %>
112-
aria-describedby="lat-desc">
113-
<span class="geo-desc" id="lat-desc">
114-
A decimal between -90.0 and 90.0 (Ex: 42.279594)
115-
<span class="hint">Southern Hemisphere is negative</span>
116-
</span>
117-
</div>
118-
<div class="field-wrap grid-item">
119-
<label class="geo-label" for="geodistance-longitude">Longitude</label>
120-
<input type="number" step="0.000001" min="-180.0" max="180.0"
121-
class="field field-text <%= "required" if geodistance_required %>"
122-
id="geodistance-longitude" name="geodistanceLongitude"
123-
value="<%= params[:geodistanceLongitude] %>" aria-describedby="long-desc"
124-
<%= 'required' if geodistance_required %>
125-
aria-describedby="long-desc">
126-
<span class="geo-desc" id="long-desc">
127-
A decimal between -180.0 and 180.0 (Ex: -83.732124)
128-
<span class="hint">Western Hemisphere is negative</span>
129-
</span>
130-
</div>
131-
<div class="field-wrap grid-item">
132-
<label class="geo-label" for="geodistance-distance">Distance from the location</label>
133-
<input type="text" class="field field-text <%= "required" if geodistance_required %>"
134-
id="geodistance-distance" name="geodistanceDistance"
135-
value="<%= params[:geodistanceDistance] %>" aria-describedby="distance-desc"
136-
<%= 'required' if geodistance_required %>
137-
aria-describedby="distance-desc">
138-
<span class="geo-desc" id="distance-desc">
139-
Distance is in meters by default; add other units if preferred (Ex: '100km' or '50mi')
140-
</span>
141-
</div>
131+
<div class="field-wrap grid-item">
132+
<label class="geo-label" for="geodistance-distance">Distance from the location</label>
133+
<input type="text" class="field field-text <%= "required" if geodistance_required %>"
134+
id="geodistance-distance" name="geodistanceDistance"
135+
value="<%= params[:geodistanceDistance] %>" aria-describedby="distance-desc"
136+
<%= 'required' if geodistance_required %>
137+
aria-describedby="distance-desc">
138+
<span class="geo-desc" id="distance-desc">
139+
Distance is in meters by default; add other units if preferred (Ex: '100km' or '50mi')
140+
</span>
142141
</div>
143-
</fieldset>
144-
</details>
145-
<% end %>
142+
</div>
143+
</fieldset>
144+
</details>
146145

147146
<details id="advanced-search-panel" class="form-panel" <%= "open" if params[:advanced] == "true" %>>
148147
<summary class="btn button-secondary" id="advanced-summary">
@@ -158,33 +157,11 @@ keyword_placeholder = search_required ? "Enter your search" : "Keyword anywhere"
158157
</div>
159158

160159
<div class="field-wrap">
161-
<label for="advanced-contributors" class="field-label">
162-
<%= Flipflop.enabled?(:gdt) ? "Authors" : "Contributors" %>
163-
</label>
160+
<label for="advanced-contributors" class="field-label">Authors</label>
164161
<input type="text" class="field field-text wide" id="advanced-contributors" name="contributors"
165162
value="<%= params[:contributors] %>">
166163
</div>
167164

168-
<% unless Flipflop.enabled?(:gdt) %>
169-
<div class="field-wrap">
170-
<label for="advanced-citation" class="field-label">Citation</label>
171-
<input type="text" class="field field-text wide" id="advanced-citation" name="citation"
172-
value="<%= params[:citation] %>">
173-
</div>
174-
175-
<div class="field-wrap">
176-
<label for="advanced-fundingInformation" class="field-label">Funding information</label>
177-
<input type="text" class="field field-text wide" id="advanced-fundingInformation" name="fundingInformation"
178-
value="<%= params[:fundingInformation] %>">
179-
</div>
180-
181-
<div class="field-wrap">
182-
<label for="advanced-identifiers" class="field-label">Identifiers</label>
183-
<input type="text" class="field field-text wide" id="advanced-identifiers" name="identifiers"
184-
value="<%= params[:identifiers] %>">
185-
</div>
186-
<% end %>
187-
188165
<div class="field-wrap">
189166
<label for="advanced-subjects" class="field-label">Subjects</label>
190167
<input type="text" class="field field-text wide" id="advanced-subjects" name="subjects"
@@ -196,21 +173,9 @@ keyword_placeholder = search_required ? "Enter your search" : "Keyword anywhere"
196173
<input type="text" class="field field-text wide" id="advanced-locations" name="locations"
197174
value="<%= params[:locations] %>">
198175
</div>
199-
200-
<% unless Flipflop.enabled?(:gdt) %>
201-
<div class="field-wrap list-checkboxes">
202-
<%# https://www.w3.org/WAI/tutorials/forms/grouping/ %>
203-
<fieldset>
204-
<legend>Limit search to checked sources.</legend>
205-
206-
<% timdex_sources.each do |source| %>
207-
<%= source_checkbox(source, params) %>
208-
<% end %>
209-
</fieldset>
210-
</div>
211-
<% end %>
212176
</div>
213177
</details>
178+
<% end %>
214179
</div>
215180

216181
<div class="basic-search-submit">

0 commit comments

Comments
 (0)