feat(docs-infra): enable filtering by package on API list page (#24631)
PR Close #24631
This commit is contained in:
parent
d8c828c9b1
commit
74b250b146
|
@ -21,10 +21,10 @@
|
|||
|
||||
<article class="api-list-container l-content-small docs-content">
|
||||
<div *ngFor="let section of filteredSections | async" >
|
||||
<h2><a [href]="section.path">{{section.title}}</a></h2>
|
||||
<ul class="api-list">
|
||||
<h2 *ngIf="section.items"><a [href]="section.path">{{section.title}}</a></h2>
|
||||
<ul class="api-list" *ngIf="section.items?.length">
|
||||
<ng-container *ngFor="let item of section.items">
|
||||
<li *ngIf="item.show" class="api-item">
|
||||
<li class="api-item">
|
||||
<a [href]="item.path"><span class="symbol {{item.docType}}"></span> {{item.title}}</a>
|
||||
</li>
|
||||
</ng-container>
|
||||
|
|
|
@ -36,18 +36,13 @@ describe('ApiListComponent', () => {
|
|||
*/
|
||||
function expectFilteredResult(label: string, itemTest: (item: ApiItem) => boolean) {
|
||||
component.filteredSections.subscribe(filtered => {
|
||||
let badItem: ApiItem|undefined;
|
||||
filtered = filtered.filter(section => section.items);
|
||||
expect(filtered.length).toBeGreaterThan(0, 'expected something');
|
||||
expect(filtered.every(section => section.items.every(
|
||||
item => {
|
||||
const ok = item.show === itemTest(item);
|
||||
if (!ok) { badItem = item; }
|
||||
return ok;
|
||||
}
|
||||
))).toBe(true, `${label} fail: ${JSON.stringify(badItem, null, 2)}`);
|
||||
expect(filtered.every(section => section.items!.every(itemTest))).toBe(true, label);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
describe('#filteredSections', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -65,34 +60,45 @@ describe('ApiListComponent', () => {
|
|||
expectFilteredResult('query: class', item => /class/.test(item.name));
|
||||
});
|
||||
|
||||
it('item.show should be true for every item in section when query matches section name', () => {
|
||||
it('items should be an array for every item in section when query matches section name', () => {
|
||||
component.setQuery('core');
|
||||
component.filteredSections.subscribe(filtered => {
|
||||
filtered = filtered.filter(section => Array.isArray(section.items));
|
||||
expect(filtered.length).toBe(1, 'only one section');
|
||||
expect(filtered[0].name).toBe('core');
|
||||
expect(filtered[0].items.every(item => !!item.show)).toBe(true, 'all core items shown');
|
||||
expect(filtered[0].items).toEqual(sections.find(section => section.name === 'core')!.items);
|
||||
});
|
||||
});
|
||||
|
||||
it('item.show should be true for items with selected status', () => {
|
||||
component.setStatus({value: 'stable', title: 'Stable'});
|
||||
expectFilteredResult('status: stable', item => item.stability === 'stable');
|
||||
describe('section.items', () => {
|
||||
it('should null if there are no matching items and the section itself does not match', () => {
|
||||
component.setQuery('core');
|
||||
component.filteredSections.subscribe(filtered => {
|
||||
const commonSection = filtered.find(section => section.name === 'common')!;
|
||||
expect(commonSection.items).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
it('should be visible if they have the selected stability status', () => {
|
||||
component.setStatus({value: 'stable', title: 'Stable'});
|
||||
expectFilteredResult('status: stable', item => item.stability === 'stable');
|
||||
});
|
||||
|
||||
it('should be visible if they have the selected security status', () => {
|
||||
component.setStatus({value: 'security-risk', title: 'Security Risk'});
|
||||
expectFilteredResult('status: security-risk', item => item.securityRisk);
|
||||
});
|
||||
|
||||
it('should be visible if they match the selected API type', () => {
|
||||
component.setType({value: 'class', title: 'Class'});
|
||||
expectFilteredResult('type: class', item => item.docType === 'class');
|
||||
});
|
||||
});
|
||||
|
||||
it('item.show should be true for items with "security-risk" status when selected', () => {
|
||||
component.setStatus({value: 'security-risk', title: 'Security Risk'});
|
||||
expectFilteredResult('status: security-risk', item => item.securityRisk);
|
||||
});
|
||||
|
||||
it('item.show should be true for items of selected type', () => {
|
||||
component.setType({value: 'class', title: 'Class'});
|
||||
expectFilteredResult('type: class', item => item.docType === 'class');
|
||||
});
|
||||
|
||||
it('should have no sections and no items when no match', () => {
|
||||
it('should have no sections and no items visible when there is no match', () => {
|
||||
component.setQuery('fizbuzz');
|
||||
component.filteredSections.subscribe(filtered => {
|
||||
expect(filtered.length).toBe(0, 'expected no sections');
|
||||
expect(filtered.some(section => !!section.items)).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -108,9 +114,11 @@ describe('ApiListComponent', () => {
|
|||
fixture.detectChanges();
|
||||
|
||||
component.filteredSections.subscribe(filtered => {
|
||||
filtered = filtered.filter(s => s.items);
|
||||
console.log(filtered);
|
||||
expect(filtered.length).toBe(1, 'sections');
|
||||
expect(filtered[0].name).toBe(section, 'section name');
|
||||
const items = filtered[0].items.filter(i => i.show);
|
||||
const items = filtered[0].items!;
|
||||
expect(items.length).toBe(1, 'items');
|
||||
|
||||
const item = items[0];
|
||||
|
|
|
@ -49,7 +49,8 @@ export class ApiListComponent implements OnInit {
|
|||
{ value: 'function', title: 'Function' },
|
||||
{ value: 'interface', title: 'Interface' },
|
||||
{ value: 'pipe', title: 'Pipe'},
|
||||
{ value: 'type-alias', title: 'Type Alias' }
|
||||
{ value: 'type-alias', title: 'Type alias' },
|
||||
{ value: 'package', title: 'Package'}
|
||||
];
|
||||
|
||||
statuses: Option[] = [
|
||||
|
@ -71,7 +72,8 @@ export class ApiListComponent implements OnInit {
|
|||
this.apiService.sections,
|
||||
this.criteriaSubject,
|
||||
(sections, criteria) => {
|
||||
return sections.filter(section => this.filterSection(section, criteria));
|
||||
return sections
|
||||
.map(section => ({ ...section, items: this.filterSection(section, criteria) }));
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -107,13 +109,8 @@ export class ApiListComponent implements OnInit {
|
|||
//////// Private //////////
|
||||
|
||||
private filterSection(section: ApiSection, { query, status, type }: SearchCriteria) {
|
||||
let showSection = false;
|
||||
|
||||
section.items.forEach(item => {
|
||||
item.show = matchesType() && matchesStatus() && matchesQuery();
|
||||
|
||||
// show section if any of its items will be shown
|
||||
showSection = showSection || item.show;
|
||||
const items = section.items!.filter(item => {
|
||||
return matchesType() && matchesStatus() && matchesQuery();
|
||||
|
||||
function matchesQuery() {
|
||||
return !query ||
|
||||
|
@ -132,8 +129,8 @@ export class ApiListComponent implements OnInit {
|
|||
}
|
||||
});
|
||||
|
||||
return showSection;
|
||||
|
||||
// If there are no items we still return an empty array if the section name matches and the type is 'package'
|
||||
return items.length ? items : (type === 'package' && (!query || section.name.indexOf(query) !== -1)) ? [] : null;
|
||||
}
|
||||
|
||||
// Get initial search criteria from URL search params
|
||||
|
|
|
@ -14,15 +14,13 @@ export interface ApiItem {
|
|||
docType: string;
|
||||
stability: string;
|
||||
securityRisk: boolean;
|
||||
|
||||
show?: boolean;
|
||||
}
|
||||
|
||||
export interface ApiSection {
|
||||
path: string;
|
||||
name: string;
|
||||
title: string;
|
||||
items: ApiItem[];
|
||||
items: ApiItem[]|null;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
|
|
Loading…
Reference in New Issue