From 1981dc28ed72b913f195319f399257d6cfce0eda Mon Sep 17 00:00:00 2001 From: kempersc Date: Sun, 7 Dec 2025 19:21:58 +0100 Subject: [PATCH] fix(frontend): normalize org_type names to letter codes in DuckLake hook DuckLake stores full names like 'MUSEUM' but map expects single-letter codes like 'M' for color styling. Also includes CSS fixes for Database page. --- .../schemas/20251121/linkml/manifest.json | 2 +- frontend/src/hooks/useDuckLakeInstitutions.ts | 51 +++++++- frontend/src/pages/Database.css | 122 ++++++++++++++++++ 3 files changed, 173 insertions(+), 2 deletions(-) diff --git a/frontend/public/schemas/20251121/linkml/manifest.json b/frontend/public/schemas/20251121/linkml/manifest.json index 9d462e068d..88212c777d 100644 --- a/frontend/public/schemas/20251121/linkml/manifest.json +++ b/frontend/public/schemas/20251121/linkml/manifest.json @@ -1,5 +1,5 @@ { - "generated": "2025-12-07T18:19:27.338Z", + "generated": "2025-12-07T18:21:53.617Z", "version": "1.0.0", "categories": [ { diff --git a/frontend/src/hooks/useDuckLakeInstitutions.ts b/frontend/src/hooks/useDuckLakeInstitutions.ts index 2713988230..3dd46c8738 100644 --- a/frontend/src/hooks/useDuckLakeInstitutions.ts +++ b/frontend/src/hooks/useDuckLakeInstitutions.ts @@ -35,6 +35,54 @@ const TYPE_COLORS: Record = { 'T': '#ff5722', // Taste/smell - deep orange }; +// Map full type names to single-letter codes +// DuckLake stores full names like "MUSEUM", but frontend expects "M" +const TYPE_NAME_TO_CODE: Record = { + 'GALLERY': 'G', + 'LIBRARY': 'L', + 'ARCHIVE': 'A', + 'MUSEUM': 'M', + 'OFFICIAL': 'O', + 'OFFICIAL_INSTITUTION': 'O', + 'RESEARCH': 'R', + 'RESEARCH_CENTER': 'R', + 'CORPORATION': 'C', + 'UNKNOWN': 'U', + 'BOTANICAL': 'B', + 'BOTANICAL_ZOO': 'B', + 'EDUCATION': 'E', + 'EDUCATION_PROVIDER': 'E', + 'SOCIETY': 'S', + 'COLLECTING_SOCIETY': 'S', + 'FEATURES': 'F', + 'INTANGIBLE': 'I', + 'INTANGIBLE_HERITAGE_GROUP': 'I', + 'MIXED': 'X', + 'PERSONAL': 'P', + 'PERSONAL_COLLECTION': 'P', + 'HOLY_SITES': 'H', + 'DIGITAL': 'D', + 'DIGITAL_PLATFORM': 'D', + 'NGO': 'N', + 'TASTE_SMELL': 'T', +}; + +// Convert org_type from DuckLake to single-letter code +function normalizeTypeCode(orgType: string): string { + if (!orgType) return 'U'; + + // If already a single letter code, return it + if (orgType.length === 1 && TYPE_COLORS[orgType]) { + return orgType; + } + + // Handle compound types like "MUSEUM,FEATURES" - take first type + const firstType = orgType.split(',')[0].trim().toUpperCase(); + + // Look up the mapping + return TYPE_NAME_TO_CODE[firstType] || 'U'; +} + // Institution type code to name mapping const TYPE_NAMES: Record = { 'G': 'Gallery', @@ -259,7 +307,8 @@ export function useDuckLakeInstitutions(): UseDuckLakeInstitutionsReturn { const name = String(row[2] || ''); const city = String(row[3] || ''); const ghcidCurrent = row[4] ? String(row[4]) : undefined; - const typeCode = String(row[5] || 'U'); + const rawOrgType = String(row[5] || 'U'); + const typeCode = normalizeTypeCode(rawOrgType); // Convert "MUSEUM" -> "M" const wikidataId = row[6] ? String(row[6]) : ''; const rating = row[7] ? Number(row[7]) : undefined; const totalRatings = row[8] ? Number(row[8]) : undefined; diff --git a/frontend/src/pages/Database.css b/frontend/src/pages/Database.css index 1cef38d543..f5f93aa941 100644 --- a/frontend/src/pages/Database.css +++ b/frontend/src/pages/Database.css @@ -3540,3 +3540,125 @@ body.resizing-row * { color: #777; } } + +/* ========================================================================== + Table Search Bar + ========================================================================== */ + +.table-search-bar { + display: flex; + align-items: center; + gap: 1rem; + padding: 0.75rem 1rem; + background: #f8f9fa; + border-bottom: 1px solid #e0e0e0; + margin-bottom: 0; +} + +.search-input-wrapper { + display: flex; + align-items: center; + flex: 1; + max-width: 400px; + position: relative; + background: white; + border: 1px solid #ddd; + border-radius: 8px; + padding: 0.5rem 0.75rem; + transition: all 0.2s ease; +} + +.search-input-wrapper:focus-within { + border-color: #FFC107; + box-shadow: 0 0 0 2px rgba(255, 193, 7, 0.2); +} + +.search-icon { + font-size: 0.9rem; + margin-right: 0.5rem; + color: #888; +} + +.search-input { + flex: 1; + border: none; + outline: none; + font-size: 0.9rem; + background: transparent; + padding: 0; +} + +.search-input::placeholder { + color: #aaa; +} + +.clear-search-btn { + background: #e9ecef; + border: none; + border-radius: 50%; + width: 20px; + height: 20px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + font-size: 0.7rem; + color: #666; + transition: all 0.15s; + margin-left: 0.5rem; +} + +.clear-search-btn:hover { + background: #FFC107; + color: #000; +} + +.search-results-count { + font-size: 0.8rem; + color: #666; + white-space: nowrap; +} + +/* Dark mode for search bar */ +@media (prefers-color-scheme: dark) { + .table-search-bar { + background: #1a1a2e; + border-color: #333; + } + + .search-input-wrapper { + background: #252538; + border-color: #404050; + } + + .search-input-wrapper:focus-within { + border-color: #FFC107; + box-shadow: 0 0 0 2px rgba(255, 193, 7, 0.15); + } + + .search-icon { + color: #777; + } + + .search-input { + color: #e0e0e0; + } + + .search-input::placeholder { + color: #666; + } + + .clear-search-btn { + background: #3a3a4e; + color: #aaa; + } + + .clear-search-btn:hover { + background: #FFC107; + color: #000; + } + + .search-results-count { + color: #888; + } +}