Skip to content

Commit 809f441

Browse files
authored
Merge pull request #42 from alphagov/search-button
Search button
2 parents 9f32fe2 + 85c76a7 commit 809f441

2 files changed

Lines changed: 127 additions & 96 deletions

File tree

static/css/metrics.css

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
*, *::before, *::after {
2+
box-sizing: border-box;
3+
}
4+
15
body {
26
font-family: -apple-system, BlinkMacSystemFont, "Inter", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
37
margin: 0;
@@ -43,7 +47,7 @@ body {
4347

4448
.search-bar {
4549
width: 100%;
46-
padding: 8px 12px 8px 32px;
50+
padding: 8px 8px 8px 32px;
4751
border: 1px solid #d1d5db;
4852
border-radius: 4px;
4953
font-size: 0.875rem;
@@ -54,6 +58,7 @@ body {
5458
box-shadow: 0 0 0 1px #3b82f6;
5559
}
5660

61+
5762
.actions-section {
5863
display: flex;
5964
align-items: center;
@@ -233,13 +238,27 @@ tr.selected td:first-child {
233238
max-width: 400px;
234239
}
235240

236-
/* Detail Pane */
241+
/* Expanded Inline Details directly under row */
242+
.expanded-detail-row {
243+
cursor: default;
244+
}
245+
.expanded-detail-row:hover {
246+
background-color: transparent;
247+
}
248+
249+
.expanded-detail-cell {
250+
padding: 0 !important;
251+
border-bottom: 2px solid #9ca3af !important;
252+
}
253+
254+
/* Detail Pane (restored original style) */
237255
.detail-pane {
238256
display: flex;
239257
height: 40vh;
240258
min-height: 250px;
241259
border-top: 1px solid #e5e7eb;
242260
background-color: #f9fafb;
261+
width: 100%;
243262
}
244263

245264
.detail-sidebar {

templates/metrics.html

Lines changed: 106 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@
259259
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
260260
</svg>
261261
<input
262-
type="text"
262+
type="search"
263263
className="search-bar"
264264
placeholder="Search entities, aliases, or context..."
265265
value={filters[0] || ""}
@@ -341,52 +341,115 @@
341341
{paginatedEntities.map(entity => {
342342
const isSelected = selectedEntityId === entity.data.id;
343343
const category = entity.data.id.split('__')[0];
344+
345+
let currentSelectedAlias = null;
346+
if (isSelected) {
347+
currentSelectedAlias = entity.aliases.find(a => a.data.id === selectedAliasId);
348+
if (!currentSelectedAlias && entity.aliases.length > 0) {
349+
currentSelectedAlias = entity.aliases[0];
350+
}
351+
}
352+
const occurrencesForAlias = currentSelectedAlias?.data.occurrences || [];
353+
344354
return (
345-
<tr
346-
key={entity.data.id}
347-
className={isSelected ? 'selected' : ''}
348-
onClick={() => setSelectedEntityId(isSelected ? null : entity.data.id)}
349-
>
350-
<td className="text-center" onClick={e => e.stopPropagation()}>
351-
<input
352-
type="checkbox"
353-
checked={checkedEntityIds.has(entity.data.id)}
354-
onChange={(e) => {
355-
const newChecked = new Set(checkedEntityIds);
356-
if (e.target.checked) {
357-
newChecked.add(entity.data.id);
358-
} else {
359-
newChecked.delete(entity.data.id);
360-
}
361-
setCheckedEntityIds(newChecked);
362-
}}
363-
/>
364-
</td>
365-
<td>
366-
<div className="entity-name">{entity.data.label || entity.data.id}</div>
367-
<div className="entity-id">{entity.data.id}</div>
368-
</td>
369-
<td>
370-
<span className="badge badge-category">{category}</span>
371-
</td>
372-
<td>
373-
<div className="aliases-container">
374-
{entity.aliases.slice(0, 3).map((alias, idx) => (
375-
<span key={idx} className="badge badge-alias">{alias.data.label}</span>
376-
))}
377-
{entity.aliases.length > 3 && (
378-
<span className="alias-more-count">+{entity.aliases.length - 3} more</span>
379-
)}
380-
</div>
381-
</td>
382-
<td className="text-center">{entity.aliasCount}</td>
383-
<td className="text-center">{entity.totalOccurrences}</td>
384-
</tr>
355+
<React.Fragment key={entity.data.id}>
356+
<tr
357+
className={isSelected ? 'selected' : ''}
358+
onClick={() => setSelectedEntityId(isSelected ? null : entity.data.id)}
359+
>
360+
<td className="text-center" onClick={e => e.stopPropagation()}>
361+
<input
362+
type="checkbox"
363+
checked={checkedEntityIds.has(entity.data.id)}
364+
onChange={(e) => {
365+
const newChecked = new Set(checkedEntityIds);
366+
if (e.target.checked) {
367+
newChecked.add(entity.data.id);
368+
} else {
369+
newChecked.delete(entity.data.id);
370+
}
371+
setCheckedEntityIds(newChecked);
372+
}}
373+
/>
374+
</td>
375+
<td>
376+
<div className="entity-name">{entity.data.label || entity.data.id}</div>
377+
<div className="entity-id">{entity.data.id}</div>
378+
</td>
379+
<td>
380+
<span className="badge badge-category">{category}</span>
381+
</td>
382+
<td>
383+
<div className="aliases-container">
384+
{entity.aliases.slice(0, 3).map((alias, idx) => (
385+
<span key={idx} className="badge badge-alias">{alias.data.label}</span>
386+
))}
387+
{entity.aliases.length > 3 && (
388+
<span className="alias-more-count">+{entity.aliases.length - 3} more</span>
389+
)}
390+
</div>
391+
</td>
392+
<td className="text-center">{entity.aliasCount}</td>
393+
<td className="text-center">{entity.totalOccurrences}</td>
394+
</tr>
395+
{isSelected && (
396+
<tr className="expanded-detail-row">
397+
<td colSpan="6" className="expanded-detail-cell" onClick={e => e.stopPropagation()}>
398+
<div className="detail-pane">
399+
<div className="detail-sidebar">
400+
<div className="detail-header">Aliases</div>
401+
<div className="detail-content scrollable-content">
402+
{entity.aliases.map(alias => (
403+
<div
404+
key={alias.data.id}
405+
className={`alias-list-item ${selectedAliasId === alias.data.id ? 'active' : ''}`}
406+
onClick={() => setSelectedAliasId(alias.data.id)}
407+
>
408+
<div className="alias-name">{alias.data.label}</div>
409+
<div className="alias-list-count">{(alias.data.occurrences || []).length} occurrences</div>
410+
</div>
411+
))}
412+
{entity.aliases.length === 0 && (
413+
<div className="empty-state-text">No aliases found.</div>
414+
)}
415+
</div>
416+
</div>
417+
<div className="detail-main">
418+
<div className="detail-header">
419+
Occurrences for: {currentSelectedAlias?.data.label || 'None'}
420+
</div>
421+
<div className="detail-content">
422+
{currentSelectedAlias ? (
423+
<div className="occurrences-list">
424+
{occurrencesForAlias.map((occ, idx) => (
425+
<div key={idx} className="occurrence-card">
426+
<div dangerouslySetInnerHTML={{ __html: occ.context }}></div>
427+
{occ.link && (
428+
<a href={occ.link} target="_blank" rel="noopener noreferrer" className="occurrence-link">
429+
View on GOV.UK ↗
430+
</a>
431+
)}
432+
</div>
433+
))}
434+
{occurrencesForAlias.length === 0 && (
435+
<div className="empty-state-text-minimal">No occurrences found for this alias.</div>
436+
)}
437+
</div>
438+
) : (
439+
<div className="empty-state-text-padded">Select an alias to view occurrences.</div>
440+
)}
441+
</div>
442+
</div>
443+
</div>
444+
</td>
445+
</tr>
446+
)}
447+
</React.Fragment>
385448
);
386449
})}
387450
{paginatedEntities.length === 0 && (
388451
<tr>
389-
<td colSpan="4" className="empty-state-row">
452+
<td colSpan="6" className="empty-state-row">
390453
No entities match the current filters.
391454
</td>
392455
</tr>
@@ -420,8 +483,7 @@
420483
</div>
421484
<div>
422485
<select
423-
className="search-bar"
424-
className="page-select"
486+
className="search-bar page-select"
425487
value={pageSize}
426488
onChange={(e) => { setPageSize(Number(e.target.value)); setCurrentPage(1); }}
427489
>
@@ -432,56 +494,6 @@
432494
</div>
433495
</div>
434496
)}
435-
436-
{/* Detail Pane */}
437-
{selectedEntityId && selectedEntity && (
438-
<div className="detail-pane">
439-
<div className="detail-sidebar">
440-
<div className="detail-header">Aliases</div>
441-
<div className="detail-content" className="scrollable-content">
442-
{selectedEntity.aliases.map(alias => (
443-
<div
444-
key={alias.data.id}
445-
className={`alias-list-item ${selectedAliasId === alias.data.id ? 'active' : ''}`}
446-
onClick={() => setSelectedAliasId(alias.data.id)}
447-
>
448-
<div className="alias-name">{alias.data.label}</div>
449-
<div className="alias-list-count">{(alias.data.occurrences || []).length} occurrences</div>
450-
</div>
451-
))}
452-
{selectedEntity.aliases.length === 0 && (
453-
<div className="empty-state-text">No aliases found.</div>
454-
)}
455-
</div>
456-
</div>
457-
<div className="detail-main">
458-
<div className="detail-header">
459-
Occurrences for: {selectedAlias?.data.label || 'None'}
460-
</div>
461-
<div className="detail-content">
462-
{selectedAlias ? (
463-
<div className="occurrences-list">
464-
{occurrencesForAlias.map((occ, idx) => (
465-
<div key={idx} className="occurrence-card">
466-
<div dangerouslySetInnerHTML={{ __html: occ.context }}></div>
467-
{occ.link && (
468-
<a href={occ.link} target="_blank" rel="noopener noreferrer" className="occurrence-link">
469-
View on GOV.UK ↗
470-
</a>
471-
)}
472-
</div>
473-
))}
474-
{occurrencesForAlias.length === 0 && (
475-
<div className="empty-state-text-minimal">No occurrences found for this alias.</div>
476-
)}
477-
</div>
478-
) : (
479-
<div className="empty-state-text-padded">Select an alias to view occurrences.</div>
480-
)}
481-
</div>
482-
</div>
483-
</div>
484-
)}
485497
</div>
486498
);
487499
}

0 commit comments

Comments
 (0)