[TLC-380] Template link, spec test, doc fixup as per review

This commit is contained in:
Kim Shepherd
2023-02-06 13:01:33 +13:00
parent 6883b8c782
commit d86e8ed0a8
12 changed files with 117 additions and 72 deletions

View File

@@ -2,27 +2,66 @@ import { BrowseDefinitionDataService } from './browse-definition-data.service';
import { followLink } from '../../shared/utils/follow-link-config.model';
import { EMPTY } from 'rxjs';
import { FindListOptions } from '../data/find-list-options.model';
import { getMockRemoteDataBuildService } from '../../shared/mocks/remote-data-build.service.mock';
import { RequestService } from '../data/request.service';
import { HALEndpointServiceStub } from '../../shared/testing/hal-endpoint-service.stub';
import { getMockObjectCacheService } from '../../shared/mocks/object-cache.service.mock';
describe(`BrowseDefinitionDataService`, () => {
let requestService: RequestService;
let service: BrowseDefinitionDataService;
const findAllDataSpy = jasmine.createSpyObj('findAllData', {
findAll: EMPTY,
});
let findAllDataSpy;
let searchDataSpy;
const browsesEndpointURL = 'https://rest.api/browses';
const halService: any = new HALEndpointServiceStub(browsesEndpointURL);
const options = new FindListOptions();
const linksToFollow = [
followLink('entries'),
followLink('items')
];
function initTestService() {
return new BrowseDefinitionDataService(
requestService,
getMockRemoteDataBuildService(),
getMockObjectCacheService(),
halService,
);
}
beforeEach(() => {
service = new BrowseDefinitionDataService(null, null, null, null);
service = initTestService();
findAllDataSpy = jasmine.createSpyObj('findAllData', {
findAll: EMPTY,
});
searchDataSpy = jasmine.createSpyObj('searchData', {
searchBy: EMPTY,
getSearchByHref: EMPTY,
});
(service as any).findAllData = findAllDataSpy;
(service as any).searchData = searchDataSpy;
});
describe('findByFields', () => {
it(`should call searchByHref on searchData`, () => {
service.findByFields(['test'], true, false, ...linksToFollow);
expect(searchDataSpy.getSearchByHref).toHaveBeenCalled();
});
});
describe('searchBy', () => {
it(`should call searchBy on searchData`, () => {
service.searchBy('test', options, true, false, ...linksToFollow);
expect(searchDataSpy.searchBy).toHaveBeenCalledWith('test', options, true, false, ...linksToFollow);
});
});
describe(`findAll`, () => {
it(`should call findAll on findAllData`, () => {
service.findAll(options, true, false, ...linksToFollow);
expect(findAllDataSpy.findAll).toHaveBeenCalledWith(options, true, false, ...linksToFollow);
});
});
});

View File

@@ -27,19 +27,6 @@ export class BrowseDefinitionDataService extends IdentifiableDataService<BrowseD
private findAllData: FindAllDataImpl<BrowseDefinition>;
private searchData: SearchDataImpl<BrowseDefinition>;
public static toSearchKeyArray(metadataKey: string): string[] {
const keyParts = metadataKey.split('.');
const searchFor = [];
searchFor.push('*');
for (let i = 0; i < keyParts.length - 1; i++) {
const prevParts = keyParts.slice(0, i + 1);
const nextPart = [...prevParts, '*'].join('.');
searchFor.push(nextPart);
}
searchFor.push(metadataKey);
return searchFor;
}
constructor(
protected requestService: RequestService,
protected rdbService: RemoteDataBuildService,
@@ -100,54 +87,16 @@ export class BrowseDefinitionDataService extends IdentifiableDataService<BrowseD
return this.searchData.getSearchByHref(searchMethod, options, ...linksToFollow);
}
findByField(
field: string,
useCachedVersionIfAvailable = true,
reRequestOnStale = true,
...linksToFollow: FollowLinkConfig<BrowseDefinition>[]
): Observable<RemoteData<BrowseDefinition>> {
const searchParams = [];
searchParams.push(new RequestParam('field', field));
const hrefObs = this.getSearchByHref(
'byField',
{ searchParams },
...linksToFollow
);
return this.findByHref(
hrefObs,
useCachedVersionIfAvailable,
reRequestOnStale,
...linksToFollow,
);
}
findAllLinked(
useCachedVersionIfAvailable = true,
reRequestOnStale = true,
...linksToFollow: FollowLinkConfig<BrowseDefinition>[]
): Observable<RemoteData<BrowseDefinition>> {
const searchParams = [];
const hrefObs = this.getSearchByHref(
'allLinked',
{ searchParams },
...linksToFollow
);
return this.findByHref(
hrefObs,
useCachedVersionIfAvailable,
reRequestOnStale,
...linksToFollow,
);
}
/**
* Get the browse URL by providing a list of metadata keys
* @param metadatumKey
* @param linkPath
* Get the browse URL by providing a list of metadata keys. The first matching browse index definition
* for any of the fields is returned. This is used in eg. item page field component, which can be configured
* with several fields for a component like 'Author', and needs to know if and how to link the values
* to configured browse indices.
*
* @param fields an array of field strings, eg. ['dc.contributor.author', 'dc.creator']
* @param useCachedVersionIfAvailable Override the data service useCachedVersionIfAvailable parameter (default: true)
* @param reRequestOnStale Override the data service reRequestOnStale parameter (default: true)
* @param linksToFollow Override the data service linksToFollow parameter (default: empty array)
*/
findByFields(
fields: string[],

View File

@@ -52,6 +52,7 @@ describe('MetadataValuesComponent', () => {
comp.mdValues = mockMetadata;
comp.separator = mockSeperator;
comp.label = mockLabel;
comp.urlRegex = /^.*test.*$/;
fixture.detectChanges();
}));
@@ -67,4 +68,9 @@ describe('MetadataValuesComponent', () => {
expect(separators.length).toBe(mockMetadata.length - 1);
});
it('should correctly detect a pattern on string containing "test"', () => {
const mdValue = {value: "This is a test value"} as MetadataValue;
expect(comp.hasLink(mdValue)).toBe(true);
});
});

View File

@@ -67,9 +67,9 @@ export class MetadataValuesComponent implements OnChanges {
/**
* Does this metadata value have a valid URL that should be rendered as a link?
* @param value
* @param value A MetadataValue being displayed
*/
hasLink(value): boolean {
hasLink(value: MetadataValue): boolean {
if (hasValue(this.urlRegex)) {
const pattern = new RegExp(this.urlRegex);
return pattern.test(value.value);

View File

@@ -43,7 +43,7 @@ export class GenericItemPageFieldComponent extends ItemPageFieldComponent {
/**
* Whether any valid HTTP(S) URL should be rendered as a link
*/
@Input() urlRegex?;
@Input() urlRegex?: string;
}

View File

@@ -1,7 +1,8 @@
<div>
<a *ngIf="(metadataRepresentation.representationType=='browse_link')"
target="_blank" class="dont-break-out"
href="/browse/{{metadataRepresentation.browseDefinition.id}}?{{metadataRepresentation.browseDefinition.metadataBrowse?'value':'startsWith'}}={{metadataRepresentation.getValue()}}">
[routerLink]="['/browse/', metadataRepresentation.browseDefinition.id]"
[queryParams]="getQueryParams()">
{{metadataRepresentation.getValue()}}
</a>
<b>(new browse link page)</b>

View File

@@ -8,6 +8,11 @@ const mockMetadataRepresentation = Object.assign(new MetadatumRepresentation('ty
value: 'Test Author'
});
const mockMetadataRepresentationWithUrl = Object.assign(new MetadatumRepresentation('type'), {
key: 'dc.subject',
value: 'http://purl.org/test/subject'
});
describe('BrowseLinkMetadataListElementComponent', () => {
let comp: BrowseLinkMetadataListElementComponent;
let fixture: ComponentFixture<BrowseLinkMetadataListElementComponent>;
@@ -33,6 +38,25 @@ describe('BrowseLinkMetadataListElementComponent', () => {
it('should contain the value as a browse link', () => {
expect(fixture.debugElement.nativeElement.textContent).toContain(mockMetadataRepresentation.value);
});
it('should NOT match isLink', () => {
expect(comp.isLink).toBe(false);
})
});
beforeEach(waitForAsync(() => {
fixture = TestBed.createComponent(BrowseLinkMetadataListElementComponent);
comp = fixture.componentInstance;
comp.metadataRepresentation = mockMetadataRepresentationWithUrl;
fixture.detectChanges();
}));
waitForAsync(() => {
it('should contain the value expected', () => {
expect(fixture.debugElement.nativeElement.textContent).toContain(mockMetadataRepresentationWithUrl.value);
});
it('should match isLink', () => {
expect(comp.isLink).toBe(true);
})
});
});

View File

@@ -15,4 +15,15 @@ import { metadataRepresentationComponent } from '../../../metadata-representatio
* It will simply use the value retrieved from MetadataRepresentation.getValue() to display as plain text
*/
export class BrowseLinkMetadataListElementComponent extends MetadataRepresentationListElementComponent {
/**
* Get the appropriate query parameters for this browse link, depending on whether the browse definition
* expects 'startsWith' (eg browse by date) or 'value' (eg browse by title)
*/
getQueryParams() {
let queryParams = {startsWith: this.metadataRepresentation.getValue()};
if (this.metadataRepresentation.browseDefinition.metadataBrowse) {
return {value: this.metadataRepresentation.getValue()};
}
return queryParams;
}
}

View File

@@ -14,6 +14,9 @@ export class MetadataRepresentationListElementComponent {
*/
metadataRepresentation: MetadataRepresentation;
/**
* Returns true if this component's value matches a basic regex "Is this an HTTP URL" test
*/
isLink(): boolean {
// Match any http:// or https://
const linkPattern = /^https?\/\//;

View File

@@ -4,13 +4,14 @@
{{metadataRepresentation.getValue()}}
</span>
<a *ngIf="(metadataRepresentation.representationType=='plain_text') && isLink()" class="dont-break-out"
target="_blank" href="{{metadataRepresentation.getValue()}}">
target="_blank" [href]="metadataRepresentation.getValue()">
{{metadataRepresentation.getValue()}}
</a>
<span *ngIf="(metadataRepresentation.representationType=='authority_controlled')" class="dont-break-out">{{metadataRepresentation.getValue()}}</span>
<a *ngIf="(metadataRepresentation.representationType=='browse_link')"
class="dont-break-out ds-browse-link"
href="/browse/{{metadataRepresentation.browseDefinition.id}}?{{metadataRepresentation.browseDefinition.metadataBrowse?'value':'startsWith'}}={{metadataRepresentation.getValue()}}&bbm.page=1">
[routerLink]="['/browse/', metadataRepresentation.browseDefinition.id]"
[queryParams]="getQueryParams()">
{{metadataRepresentation.getValue()}}
</a>
</div>

View File

@@ -15,4 +15,15 @@ import { metadataRepresentationComponent } from '../../../metadata-representatio
* It will simply use the value retrieved from MetadataRepresentation.getValue() to display as plain text
*/
export class PlainTextMetadataListElementComponent extends MetadataRepresentationListElementComponent {
/**
* Get the appropriate query parameters for this browse link, depending on whether the browse definition
* expects 'startsWith' (eg browse by date) or 'value' (eg browse by title)
*/
getQueryParams() {
let queryParams = {startsWith: this.metadataRepresentation.getValue()};
if (this.metadataRepresentation.browseDefinition.metadataBrowse) {
return {value: this.metadataRepresentation.getValue()};
}
return queryParams;
}
}

View File

@@ -48,8 +48,8 @@ export const BrowseDefinitionDataServiceStub: any = {
/**
* Get the browse URL by providing a list of metadata keys
* @param metadatumKey
* @param linkPath
*
* @param metadataKeys a list of fields eg. ['dc.contributor.author', 'dc.creator']
*/
findByFields(metadataKeys: string[]): Observable<RemoteData<BrowseDefinition>> {
let searchKeyArray: string[] = [];