Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/app/handle-page/handle-table/handle-table.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,16 @@ <h5 class="card-header">{{ 'handle-table.title' | translate }}</h5>
</div>
</div>
<input type="text" id="clarin-dc-search-box" class="form-control" aria-label="Text input with dropdown button"
[value]="searchQuery"
#searchInput>
<span class="input-group-append" (click)="searchHandles(searchInput.value)">
[(ngModel)]="searchQuery">
<span class="input-group-append" (click)="searchHandles()">
<button type="submit" class="btn btn-primary search-button">
<i class="fas fa-search"></i>{{'handle-table.dropdown.search-button' | translate}}</button>
</span>
</div>

<!-- The table with pagination -->
<div *ngVar="(handlesRD$ | async)?.payload as handles">
<div class="mb-2">
<div class="mb-2 table-responsive">
<ds-pagination (paginationChange)="onPageChange()"
[sortOptions]="sortConfiguration"
[hideGear]="true"
Expand Down
77 changes: 35 additions & 42 deletions src/app/handle-page/handle-table/handle-table.component.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ChangeDetectorRef, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { BehaviorSubject, combineLatest as observableCombineLatest, fromEvent } from 'rxjs';
import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
import { BehaviorSubject, combineLatest } from 'rxjs';
import { RemoteData } from '../../core/data/remote-data';
import { PaginatedList } from '../../core/data/paginated-list.model';
import { HandleDataService } from '../../core/data/handle-data.service';
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
import { debounceTime, distinctUntilChanged, switchMap, take } from 'rxjs/operators';
import { scan, switchMap, take } from 'rxjs/operators';
import { getFirstSucceededRemoteData, getRemoteDataPayload } from '../../core/shared/operators';
import { PaginationService } from '../../core/pagination/pagination.service';
import {
Expand Down Expand Up @@ -58,11 +58,6 @@ export class HandleTableComponent implements OnInit {
private notificationsService: NotificationsService,) {
}

/**
* The reference for the input html element
*/
@ViewChild('searchInput', {static: true}) searchInput: ElementRef;

/**
* The list of Handle object as BehaviorSubject object
*/
Expand Down Expand Up @@ -153,13 +148,20 @@ export class HandleTableComponent implements OnInit {
this.isLoading = true;

// load the current pagination and sorting options
const currentPagination$ = this.paginationService.getCurrentPagination(this.options.id, this.options);
const currentSort$ = this.paginationService.getCurrentSort(this.options.id, this.sortConfiguration);

observableCombineLatest([currentPagination$, currentSort$]).pipe(
switchMap(([currentPagination, currentSort]) => {
const currentPagination$ = this.getCurrentPagination();
const currentSort$ = this.getCurrentSort();
const searchTerm$ = new BehaviorSubject<string>(this.searchQuery);

combineLatest([currentPagination$, currentSort$, searchTerm$]).pipe(
scan((prevState, [currentPagination, currentSort, searchTerm]) => {
// If search term has changed, reset to page 1; otherwise, keep current page
const currentPage = prevState.searchTerm !== searchTerm ? 1 : currentPagination.currentPage;
return { currentPage, currentPagination, currentSort, searchTerm };
}, { searchTerm: '', currentPage: 1, currentPagination: this.getCurrentPagination(),
currentSort: this.getCurrentSort() }),
switchMap(({ currentPage, currentPagination, currentSort, searchTerm }) => {
return this.handleDataService.findAll({
currentPage: currentPagination.currentPage,
currentPage: currentPage,
elementsPerPage: currentPagination.pageSize,
sort: {field: currentSort.field, direction: currentSort.direction}
}, false
Expand Down Expand Up @@ -351,29 +353,6 @@ export class HandleTableComponent implements OnInit {
}, 250 );
}

/**
* If the user is typing the searchQuery is changing.
*/
setSearchQuery() {
if (isEmpty(this.searchOption)) {
return;
}

fromEvent(this.searchInput.nativeElement,'keyup')
.pipe(
debounceTime(300),
distinctUntilChanged()
)
.subscribe( cc => {
this.searchHandles(this.searchInput.nativeElement.value);
setTimeout(() => {
// click to refresh table data because without click it still shows wrong data
document.getElementById('clarin-dc-search-box').click();
}, 25);
});

}

/**
* The search option is selected from the dropdown menu.
* @param event with the selected value
Expand All @@ -386,32 +365,32 @@ export class HandleTableComponent implements OnInit {
* Update the sortConfiguration based on the `searchOption` and the `searchQuery` but parse that attributes at first.
* @param searchQuery
*/
searchHandles(searchQuery = '') {
searchHandles() {
if (isEmpty(this.searchOption)) {
return;
}

// parse searchQuery for the server request
// the new sorting query is in the format e.g. `handle:123456`, `resourceTypeId:2`, `url:internal`
let parsedSearchOption = '';
let parsedSearchQuery = searchQuery;
let parsedSearchQuery = this.searchQuery;
switch (this.searchOption) {
case this.handleOption:
parsedSearchOption = HANDLE_SEARCH_OPTION;
break;
case this.internalOption:
// if the handle doesn't have the URL - is internal, if it does - is external
parsedSearchOption = URL_SEARCH_OPTION;
if (searchQuery === 'Yes' || searchQuery === 'yes') {
if (this.searchQuery.toLowerCase() === 'yes') {
parsedSearchQuery = 'internal';
} else if (searchQuery === 'No' || searchQuery === 'no') {
} else if (this.searchQuery.toLowerCase() === 'no') {
parsedSearchQuery = 'external';
}
break;
case this.resourceTypeOption:
parsedSearchOption = RESOURCE_TYPE_SEARCH_OPTION;
// parse resourceType from string to the number because the resourceType is integer on the server
switch (searchQuery) {
switch (this.searchQuery) {
case ITEM:
parsedSearchQuery = '' + 2;
break;
Expand Down Expand Up @@ -441,4 +420,18 @@ export class HandleTableComponent implements OnInit {
private initializeSortingOptions() {
this.sortConfiguration = defaultSortConfiguration;
}

/**
* Get the current pagination options.
*/
private getCurrentPagination() {
return this.paginationService.getCurrentPagination(this.options.id, defaultPagination);
}

/**
* Get the current sorting options.
*/
private getCurrentSort() {
return this.paginationService.getCurrentSort(this.options.id, defaultSortConfiguration);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,30 @@
</a>
</div>
<div [style]="'max-height: 500px; padding: 0px; overflow: scroll'" class="panel-body">
<ul class="treeview in collapse show">
<ng-container *ngIf="fileInput.format === 'application/zip' || fileInput.format === 'application/x-tar'">
<ds-file-tree-view
*ngFor="let node of fileInput.fileInfo"
[node]="node">
</ds-file-tree-view>
</ng-container>
<ng-container *ngIf="isTxt()">
<pre>{{ fileInput.fileInfo[0]?.content }}</pre>
</ng-container>
<ng-container *ngIf="fileInput.format === 'text/html'">
<div [innerHTML]="fileInput.fileInfo[0]?.content"></div>
<ul class="treeview collapse show">
<!-- Loading Spinner -->
<div *ngIf="fileInput.fileInfo.length === 0" class="d-flex justify-content-center align-items-center my-3">
<div>{{'item.preview.no-preview' | translate}}
<a *ngIf="emailToContact" [href]="'mailto:' + emailToContact" class="email-text">{{ emailToContact }}</a>
</div>
</div>

<!-- File Content -->
<ng-container *ngIf="fileInput.fileInfo.length !== 0">
<!-- ZIP or TAR File Format -->
<ng-container *ngIf="isArchive(fileInput.format)">
<ds-file-tree-view *ngFor="let node of fileInput.fileInfo" [node]="node"></ds-file-tree-view>
</ng-container>

<!-- TXT Format -->
<ng-container *ngIf="isTxt()">
<pre>{{ fileInput.fileInfo[0]?.content }}</pre>
</ng-container>

<!-- HTML Format -->
<ng-container *ngIf="fileInput.format === 'text/html'">
<div [innerHTML]="fileInput.fileInfo[0]?.content"></div>
</ng-container>
</ng-container>
</ul>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,33 @@
import { Component, Input } from '@angular/core';
import { Component, Input, OnInit } from '@angular/core';
import { MetadataBitstream } from 'src/app/core/metadata/metadata-bitstream.model';
import { HALEndpointService } from '../../../../../core/shared/hal-endpoint.service';
import {Router} from '@angular/router';
import { ConfigurationDataService } from '../../../../../core/data/configuration-data.service';

const allowedPreviewFormats = ['text/plain', 'text/html', 'application/zip', 'application/x-tar'];
@Component({
selector: 'ds-file-description',
templateUrl: './file-description.component.html',
styleUrls: ['./file-description.component.scss'],
})
export class FileDescriptionComponent {
export class FileDescriptionComponent implements OnInit {
MIME_TYPE_IMAGES_PATH = './assets/images/mime/';
MIME_TYPE_DEFAULT_IMAGE_NAME = 'application-octet-stream.png';

@Input()
fileInput: MetadataBitstream;

constructor(protected halService: HALEndpointService, private router: Router) { }
emailToContact: string;

constructor(protected halService: HALEndpointService,
private router: Router,
private configService: ConfigurationDataService) { }

ngOnInit(): void {
this.configService.findByPropertyName('lr.help.mail').subscribe(remoteData => {
this.emailToContact = remoteData.payload.values[0];
});
}

public downloadFile() {
void this.router.navigateByUrl('bitstreams/' + this.fileInput.id + '/download');
Expand Down Expand Up @@ -45,4 +56,9 @@ export class FileDescriptionComponent {
const imgElement = event.target as HTMLImageElement;
imgElement.src = this.MIME_TYPE_IMAGES_PATH + this.MIME_TYPE_DEFAULT_IMAGE_NAME;
}

isArchive(format: string): boolean {
return format === 'application/zip' || format === 'application/x-tar';
}

}
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
<!-- Loading Spinner -->
<div *ngIf="(listOfFiles | async).length === 0" class="d-flex flex-column justify-content-center align-items-center my-3">
<div class="spinner-border text-primary" role="status"></div>
<div class="px-4 pt-2">{{'item.preview.loading-files' | translate}}
<a *ngIf="emailToContact" [href]="'mailto:' + emailToContact" class="email-text">{{ emailToContact }}</a>
</div>
</div>
<div *ngFor="let file of (listOfFiles | async)">
<ds-file-description [fileInput] = 'file'></ds-file-description>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,33 @@ import { PreviewSectionComponent } from './preview-section.component';
import { ResourceType } from 'src/app/core/shared/resource-type';
import { HALLink } from 'src/app/core/shared/hal-link.model';
import { Item } from 'src/app/core/shared/item.model';
import { ConfigurationDataService } from '../../../../core/data/configuration-data.service';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateLoaderMock } from '../../../../shared/mocks/translate-loader.mock';

describe('PreviewSectionComponent', () => {
let component: PreviewSectionComponent;
let fixture: ComponentFixture<PreviewSectionComponent>;
let mockRegistryService: any;
let mockConfigService: any;

beforeEach(async () => {
mockConfigService = jasmine.createSpyObj(['findByPropertyName']);
mockRegistryService = jasmine.createSpyObj('RegistryService', [
'getMetadataBitstream',
]);

await TestBed.configureTestingModule({
imports: [TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderMock
}
})],
declarations: [PreviewSectionComponent],
providers: [{ provide: RegistryService, useValue: mockRegistryService }],
providers: [
{ provide: RegistryService, useValue: mockRegistryService },
{ provide: ConfigurationDataService, useValue: mockConfigService }],
}).compileComponents();
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { MetadataBitstream } from 'src/app/core/metadata/metadata-bitstream.mode
import { RegistryService } from 'src/app/core/registry/registry.service';
import { Item } from 'src/app/core/shared/item.model';
import { getAllSucceededRemoteListPayload } from 'src/app/core/shared/operators';
import { ConfigurationDataService } from '../../../../core/data/configuration-data.service';

@Component({
selector: 'ds-preview-section',
Expand All @@ -14,8 +15,10 @@ export class PreviewSectionComponent implements OnInit {
@Input() item: Item;

listOfFiles: BehaviorSubject<MetadataBitstream[]> = new BehaviorSubject<MetadataBitstream[]>([] as any);
emailToContact: string;

constructor(protected registryService: RegistryService) {} // Modified
constructor(protected registryService: RegistryService,
private configService: ConfigurationDataService) {} // Modified

ngOnInit(): void {
this.registryService
Expand All @@ -24,5 +27,10 @@ export class PreviewSectionComponent implements OnInit {
.subscribe((data: MetadataBitstream[]) => {
this.listOfFiles.next(data);
});
this.configService.findByPropertyName('lr.help.mail')?.subscribe(remoteData => {
this.emailToContact = remoteData.payload.values[0];
});
}


}
4 changes: 4 additions & 0 deletions src/assets/i18n/cs.json5
Original file line number Diff line number Diff line change
Expand Up @@ -3380,6 +3380,10 @@
"item.preview.authors.show.everyone": "Zobraz všechny autory",
// "item.preview.authors.et.al": " ; et al.",
"item.preview.authors.et.al": "; et al.",
// "item.preview.loading-files": "Loading files... This may take a few seconds as file previews are being generated. If the process takes too long, please contact the system administrator",
"item.preview.loading-files": "Načítání souborů... Může to trvat několik sekund, protože se generují náhledy souborů. Pokud proces trvá příliš dlouho, kontaktujte prosím správce systému",
// "item.preview.no-preview": "The file preview wasn't successfully generated, please contact the system administrator",
"item.preview.no-preview": "Náhled souboru nebyl úspěšně vygenerován, kontaktujte prosím správce systému",
// "item.refbox.modal.copy.instruction": ["Press", "ctrl + c", "to copy"],
"item.refbox.modal.copy.instruction": ["Stiskněte", "ctrl + c", "pro kopírování"],
// "item.refbox.modal.submit": "Ok",
Expand Down
4 changes: 4 additions & 0 deletions src/assets/i18n/en.json5
Original file line number Diff line number Diff line change
Expand Up @@ -2832,6 +2832,10 @@

"item.preview.authors.et.al": " ; et al.",

"item.preview.loading-files": "Loading files... This may take a few seconds as file previews are being generated. If the process takes too long, please contact the system administrator",

"item.preview.no-preview": "The file preview wasn't successfully generated, please contact the system administrator",

"item.refbox.modal.copy.instruction": ["Press", "ctrl + c", "to copy"],

"item.refbox.modal.submit": "Ok",
Expand Down