Skip to content

Commit bec11cb

Browse files
authored
UFAL/Manage Handles table UI finetunes (#1019)
* Fixed inconsistency of capital letters by making it lowercase * Implementation of combobox functionality - dropdowns for search options * Refactoring the new search functionality * Added i18n translation keys * Changed multiple styles from css to bootstrap classes in html * Using existing constants for recognizing resourceTypes * Add constant for invalid resource-type * Changed button to select elements * Fixed deserializer to return null by default * If searchQuery becomes empty, the dropdown will visually reset to show the placeholder * Removed unused methods to avoid dead code * Normalized query toLowerCase to maintain robust handling * Adding the cs translations again * Using chevron-down icon instead of image of chevron includes by url in css * Sync-i18n
1 parent 718af73 commit bec11cb

File tree

7 files changed

+208
-34
lines changed

7 files changed

+208
-34
lines changed

src/app/core/handle/HandleResourceTypeIdserializer.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ export const HandleResourceTypeIdSerializer = {
1414
return 3;
1515
case COMMUNITY:
1616
return 4;
17+
case SITE:
18+
return 5;
1719
default:
1820
return null;
1921
}
@@ -27,8 +29,10 @@ export const HandleResourceTypeIdSerializer = {
2729
return COLLECTION;
2830
case 4:
2931
return COMMUNITY;
30-
default:
32+
case 5:
3133
return SITE;
34+
default:
35+
return null;
3236
}
3337
}
3438
};

src/app/core/handle/handle.resource-type.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { ResourceType } from '../shared/resource-type';
99

1010
export const HANDLE = new ResourceType('handle');
1111
export const SUCCESSFUL_RESPONSE_START_CHAR = '2';
12+
export const INVALID_RESOURCE_TYPE_ID = -1;
1213
export const COMMUNITY = 'Community';
1314
export const COLLECTION = 'Collection';
1415
export const ITEM = 'Item';

src/app/handle-page/handle-table/handle-table.component.html

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ <h5 class="card-header">{{ 'handle-table.title' | translate }}</h5>
1111
class="btn btn-outline-secondary dropdown-toggle"
1212
data-bs-toggle="dropdown" aria-haspopup="true"
1313
aria-expanded="false">
14-
<span *ngIf="searchOption != null" [ngModel]="searchOption" name="searchOption" ngDefaultControl>{{searchOption}}</span>
14+
<span *ngIf="searchOption != null">{{searchOption}}</span>
1515
<span *ngIf="searchOption == null" >{{'handle-table.dropdown.search-option' | translate}}</span>
1616
</button>
1717
<div ngbDropdownMenu aria-labelledby="resultdropdown">
@@ -20,9 +20,53 @@ <h5 class="card-header">{{ 'handle-table.title' | translate }}</h5>
2020
<button class="dropdown-item" (click)="setSearchOption($event)">{{"handle-table.table.resource-type" | translate}}</button>
2121
</div>
2222
</div>
23-
<input type="text" id="clarin-dc-search-box" class="form-control" aria-label="Text input with dropdown button"
24-
[(ngModel)]="searchQuery"
25-
[disabled]="!searchOption">
23+
24+
<!-- Search input area -->
25+
<div class="search-input-container flex-fill">
26+
<!-- Default disabled search input when no option is selected -->
27+
<input *ngIf="!searchOption"
28+
type="text"
29+
class="form-control search-input"
30+
[placeholder]="'handle-table.search.placeholder.no-option' | translate"
31+
disabled>
32+
33+
<!-- Text input for Handle search -->
34+
<input *ngIf="searchOption === handleOption"
35+
type="text"
36+
class="form-control search-input"
37+
[(ngModel)]="searchQuery"
38+
(keyup.enter)="searchHandles()"
39+
[placeholder]="'handle-table.search.placeholder.handle' | translate">
40+
41+
<!-- Dropdown for Internal search -->
42+
<div *ngIf="searchOption === internalOption" class="select-wrapper">
43+
<select class="form-select w-100"
44+
[(ngModel)]="searchQuery"
45+
(change)="searchHandles()"
46+
[attr.aria-label]="'handle-table.search.aria.select-internal' | translate">
47+
<option value="" disabled [selected]="!searchQuery">{{'handle-table.search.internal.select' | translate}}</option>
48+
<option value="yes">{{'handle-table.search.internal.yes' | translate}}</option>
49+
<option value="no">{{'handle-table.search.internal.no' | translate}}</option>
50+
</select>
51+
<i class="fas fa-chevron-down select-icon"></i>
52+
</div>
53+
54+
<!-- Dropdown for Resource Type search -->
55+
<div *ngIf="searchOption === resourceTypeOption" class="select-wrapper">
56+
<select class="form-select w-100"
57+
[(ngModel)]="searchQuery"
58+
(change)="searchHandles()"
59+
[attr.aria-label]="'handle-table.search.aria.select-resource-type' | translate">
60+
<option value="" disabled [selected]="!searchQuery">{{'handle-table.search.resource-type.select' | translate}}</option>
61+
<option value="Site">{{'handle-table.search.resource-type.site' | translate}}</option>
62+
<option value="Community">{{'handle-table.search.resource-type.community' | translate}}</option>
63+
<option value="Collection">{{'handle-table.search.resource-type.collection' | translate}}</option>
64+
<option value="Item">{{'handle-table.search.resource-type.item' | translate}}</option>
65+
</select>
66+
<i class="fas fa-chevron-down select-icon"></i>
67+
</div>
68+
</div>
69+
2670
<span class="input-group-append" (click)="searchHandles()">
2771
<button type="submit" class="btn btn-primary search-button">
2872
<i class="fas fa-search"></i>{{'handle-table.dropdown.search-button' | translate}}</button>
@@ -70,7 +114,7 @@ <h5 class="card-header">{{ 'handle-table.title' | translate }}</h5>
70114
</a>
71115
</td>
72116
<td class="version-row-element-editor">
73-
{{handle?.resourceTypeID}}
117+
{{getTranslatedResourceType(handle?.resourceTypeID)}}
74118
</td>
75119
<td class="version-row-element-editor">
76120
<span *ngIf="handle?.resourceId != null">
Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,48 @@
11
/**
2-
The file for styling `handle-table.component.html`. No styling needed.
2+
* Styling for handle-table component search functionality
33
*/
4+
5+
// Make select elements look like buttons to match previous dropdown styling
6+
.search-input-container {
7+
.select-wrapper {
8+
position: relative;
9+
display: inline-block;
10+
width: 100%;
11+
}
12+
13+
.form-select {
14+
background: white;
15+
border: 1px solid #ced4da;
16+
border-radius: 0.25rem;
17+
padding: 0.375rem 2.5rem 0.375rem 0.75rem;
18+
color: #495057;
19+
appearance: none;
20+
cursor: pointer;
21+
22+
&:focus {
23+
border-color: #80bdff;
24+
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
25+
outline: 0;
26+
}
27+
28+
&:disabled {
29+
background-color: #f8f9fa;
30+
color: #6c757d;
31+
cursor: not-allowed;
32+
}
33+
}
34+
35+
.select-icon {
36+
position: absolute;
37+
right: 0.75rem;
38+
top: 50%;
39+
transform: translateY(-50%);
40+
pointer-events: none;
41+
color: #495057;
42+
font-size: 0.875rem;
43+
}
44+
45+
.form-control {
46+
border-radius: 0;
47+
}
48+
}

src/app/handle-page/handle-table/handle-table.component.ts

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@ import { Handle } from '../../core/handle/handle.model';
2424
import {
2525
COLLECTION,
2626
COMMUNITY,
27+
INVALID_RESOURCE_TYPE_ID,
2728
ITEM,
2829
SITE,
2930
SUCCESSFUL_RESPONSE_START_CHAR
3031
} from '../../core/handle/handle.resource-type';
3132
import { getCommunityPageRoute } from '../../community-page/community-page-routing-paths';
3233
import { getCollectionPageRoute } from '../../collection-page/collection-page-routing-paths';
3334
import { getEntityPageRoute } from '../../item-page/item-page-routing-paths';
35+
import { HandleResourceTypeIdSerializer } from '../../core/handle/HandleResourceTypeIdserializer';
3436

3537
/**
3638
* Constants for converting the searchQuery for the server
@@ -359,6 +361,47 @@ export class HandleTableComponent implements OnInit {
359361
*/
360362
setSearchOption(event) {
361363
this.searchOption = event?.target?.innerHTML;
364+
// Reset search query when changing search option
365+
this.searchQuery = '';
366+
}
367+
368+
/**
369+
* Get translated resource type name for table display
370+
* Converts constants like 'Community', 'Collection', 'Item', 'Site' to translated strings
371+
*/
372+
getTranslatedResourceType(resourceTypeID: string): string {
373+
if (!resourceTypeID) {
374+
return '';
375+
}
376+
377+
// Map the constant values to lowercase for translation keys
378+
const resourceTypeKey = resourceTypeID.toLowerCase();
379+
const translationKey = `handle-table.search.resource-type.${resourceTypeKey}`;
380+
381+
// Return translated value, fallback to original if translation not found
382+
const translated = this.translateService.instant(translationKey);
383+
return translated !== translationKey ? translated : resourceTypeID;
384+
}
385+
386+
/**
387+
* Parse internal search query to server format
388+
*/
389+
private parseInternalSearchQuery(searchQuery: string): string {
390+
const normalizedQuery = searchQuery.toLowerCase();
391+
if (normalizedQuery === 'yes') {
392+
return 'internal';
393+
} else if (normalizedQuery === 'no') {
394+
return 'external';
395+
}
396+
return searchQuery;
397+
}
398+
399+
/**
400+
* Parse resource type search query to server format (converts to numeric ID)
401+
*/
402+
private parseResourceTypeSearchQuery(searchQuery: string): string {
403+
const id = HandleResourceTypeIdSerializer.Serialize(searchQuery);
404+
return id ? id.toString() : INVALID_RESOURCE_TYPE_ID.toString();
362405
}
363406

364407
/**
@@ -381,35 +424,12 @@ export class HandleTableComponent implements OnInit {
381424
parsedSearchOption = HANDLE_SEARCH_OPTION;
382425
break;
383426
case this.internalOption:
384-
// if the handle doesn't have the URL - is internal, if it does - is external
385427
parsedSearchOption = URL_SEARCH_OPTION;
386-
if (this.searchQuery.toLowerCase() === 'yes') {
387-
parsedSearchQuery = 'internal';
388-
} else if (this.searchQuery.toLowerCase() === 'no') {
389-
parsedSearchQuery = 'external';
390-
}
428+
parsedSearchQuery = this.parseInternalSearchQuery(this.searchQuery);
391429
break;
392430
case this.resourceTypeOption:
393431
parsedSearchOption = RESOURCE_TYPE_SEARCH_OPTION;
394-
// parse resourceType from string to the number because the resourceType is integer on the server
395-
switch (this.searchQuery.toLowerCase()) {
396-
case ITEM.toLowerCase():
397-
parsedSearchQuery = '' + 2;
398-
break;
399-
case COLLECTION.toLowerCase():
400-
parsedSearchQuery = '' + 3;
401-
break;
402-
case COMMUNITY.toLowerCase():
403-
parsedSearchQuery = '' + 4;
404-
break;
405-
case SITE.toLowerCase():
406-
parsedSearchQuery = '' + 5;
407-
break;
408-
// no results for invalid search inputs
409-
default:
410-
parsedSearchQuery = '' + -1;
411-
break;
412-
}
432+
parsedSearchQuery = this.parseResourceTypeSearchQuery(this.searchQuery);
413433
break;
414434
}
415435
}

src/assets/i18n/cs.json5

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8525,7 +8525,7 @@
85258525
// "handle-table.table.handle": "Handle",
85268526
"handle-table.table.handle": "Handle",
85278527

8528-
// "handle-table.table.internal": "Is Internal",
8528+
// "handle-table.table.internal": "Is internal",
85298529
"handle-table.table.internal": "Je interní",
85308530

85318531
// "handle-table.table.is-internal": "Yes",
@@ -8558,6 +8558,42 @@
85588558
// "handle-table.dropdown.search-button": "Search",
85598559
"handle-table.dropdown.search-button": "Hledat",
85608560

8561+
// "handle-table.search.placeholder.no-option": "Please select a search option first",
8562+
"handle-table.search.placeholder.no-option": "Nejprve vyberte možnost vyhledávání",
8563+
8564+
// "handle-table.search.placeholder.handle": "Enter handle",
8565+
"handle-table.search.placeholder.handle": "Zadejte Handle",
8566+
8567+
// "handle-table.search.internal.select": "Select internal option",
8568+
"handle-table.search.internal.select": "Vyberte možnost interní",
8569+
8570+
// "handle-table.search.internal.yes": "Yes",
8571+
"handle-table.search.internal.yes": "Ano",
8572+
8573+
// "handle-table.search.internal.no": "No",
8574+
"handle-table.search.internal.no": "Ne",
8575+
8576+
// "handle-table.search.resource-type.select": "Select resource type",
8577+
"handle-table.search.resource-type.select": "Vyberte typ zdroje",
8578+
8579+
// "handle-table.search.resource-type.site": "Site",
8580+
"handle-table.search.resource-type.site": "Stránka",
8581+
8582+
// "handle-table.search.resource-type.community": "Community",
8583+
"handle-table.search.resource-type.community": "Komunita",
8584+
8585+
// "handle-table.search.resource-type.collection": "Collection",
8586+
"handle-table.search.resource-type.collection": "Kolekce",
8587+
8588+
// "handle-table.search.resource-type.item": "Item",
8589+
"handle-table.search.resource-type.item": "Záznam",
8590+
8591+
// "handle-table.search.aria.select-internal": "Select internal option",
8592+
"handle-table.search.aria.select-internal": "Vyberte možnost interní",
8593+
8594+
// "handle-table.search.aria.select-resource-type": "Select resource type",
8595+
"handle-table.search.aria.select-resource-type": "Vyberte typ zdroje",
8596+
85618597
// "handle-table.global-actions.title": "Global Actions",
85628598
"handle-table.global-actions.title": "Globální akce",
85638599

src/assets/i18n/en.json5

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5683,7 +5683,7 @@
56835683

56845684
"handle-table.table.handle": "Handle",
56855685

5686-
"handle-table.table.internal": "Is Internal",
5686+
"handle-table.table.internal": "Is internal",
56875687

56885688
"handle-table.table.is-internal": "Yes",
56895689

@@ -5705,6 +5705,30 @@
57055705

57065706
"handle-table.dropdown.search-button": "Search",
57075707

5708+
"handle-table.search.placeholder.no-option": "Please select a search option first",
5709+
5710+
"handle-table.search.placeholder.handle": "Enter handle",
5711+
5712+
"handle-table.search.internal.select": "Select internal option",
5713+
5714+
"handle-table.search.internal.yes": "Yes",
5715+
5716+
"handle-table.search.internal.no": "No",
5717+
5718+
"handle-table.search.resource-type.select": "Select resource type",
5719+
5720+
"handle-table.search.resource-type.site": "Site",
5721+
5722+
"handle-table.search.resource-type.community": "Community",
5723+
5724+
"handle-table.search.resource-type.collection": "Collection",
5725+
5726+
"handle-table.search.resource-type.item": "Item",
5727+
5728+
"handle-table.search.aria.select-internal": "Select internal option",
5729+
5730+
"handle-table.search.aria.select-resource-type": "Select resource type",
5731+
57085732
"handle-table.global-actions.title": "Global Actions",
57095733

57105734
"handle-table.global-actions.actions-list-message": "This is the list of available global actions.",

0 commit comments

Comments
 (0)