From 74b250b1465661292dfcdd67444261cacb78bf3f Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Sun, 1 Jul 2018 21:23:45 +0100 Subject: [PATCH] feat(docs-infra): enable filtering by package on API list page (#24631) PR Close #24631 --- .../api/api-list.component.html | 6 +- .../api/api-list.component.spec.ts | 60 +++++++++++-------- .../custom-elements/api/api-list.component.ts | 19 +++--- .../app/custom-elements/api/api.service.ts | 4 +- 4 files changed, 46 insertions(+), 43 deletions(-) diff --git a/aio/src/app/custom-elements/api/api-list.component.html b/aio/src/app/custom-elements/api/api-list.component.html index aa65d70291..3011853b14 100644 --- a/aio/src/app/custom-elements/api/api-list.component.html +++ b/aio/src/app/custom-elements/api/api-list.component.html @@ -21,10 +21,10 @@
-

{{section.title}}

-
    +

    {{section.title}}

    +
      -
    • +
    • {{item.title}}
    • diff --git a/aio/src/app/custom-elements/api/api-list.component.spec.ts b/aio/src/app/custom-elements/api/api-list.component.spec.ts index 035a07f134..ac10868bf5 100644 --- a/aio/src/app/custom-elements/api/api-list.component.spec.ts +++ b/aio/src/app/custom-elements/api/api-list.component.spec.ts @@ -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]; diff --git a/aio/src/app/custom-elements/api/api-list.component.ts b/aio/src/app/custom-elements/api/api-list.component.ts index a343bfb949..666b05aa49 100644 --- a/aio/src/app/custom-elements/api/api-list.component.ts +++ b/aio/src/app/custom-elements/api/api-list.component.ts @@ -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 diff --git a/aio/src/app/custom-elements/api/api.service.ts b/aio/src/app/custom-elements/api/api.service.ts index c2398e7d91..f90599c8af 100644 --- a/aio/src/app/custom-elements/api/api.service.ts +++ b/aio/src/app/custom-elements/api/api.service.ts @@ -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()