From df54ea035a380aca6c91507431c076fffc903182 Mon Sep 17 00:00:00 2001
From: Daniel Melanson <30221758+daniel-melanson@users.noreply.github.com>
Date: Tue, 21 Nov 2023 12:45:01 -0500
Subject: [PATCH 1/2] feat(rxjs.dev): add api list deprecated filter
---
.../custom-elements/api/api-list.component.ts | 26 ++++++++++++++++---
.../custom-elements/api/api-list.module.ts | 3 ++-
.../src/styles/2-modules/_api-list.scss | 6 +++++
3 files changed, 30 insertions(+), 5 deletions(-)
diff --git a/apps/rxjs.dev/src/app/custom-elements/api/api-list.component.ts b/apps/rxjs.dev/src/app/custom-elements/api/api-list.component.ts
index d0eb89d3cf..b287b25608 100644
--- a/apps/rxjs.dev/src/app/custom-elements/api/api-list.component.ts
+++ b/apps/rxjs.dev/src/app/custom-elements/api/api-list.component.ts
@@ -20,6 +20,7 @@ class SearchCriteria {
query? = '';
status? = 'all';
type? = 'all';
+ includeDeprecated? = true;
}
@Component({
@@ -31,6 +32,11 @@ class SearchCriteria {
search
+
+
@@ -62,6 +68,7 @@ export class ApiListComponent implements OnInit {
status: Option;
type: Option;
+ includeDeprecated: boolean;
// API types
types: Option[] = [
@@ -99,6 +106,10 @@ export class ApiListComponent implements OnInit {
this.setSearchCriteria({ query: (query || '').toLowerCase().trim() });
}
+ onIncludeDeprecatedChange() {
+ this.setSearchCriteria({ includeDeprecated: this.includeDeprecated });
+ }
+
setStatus(status: Option) {
this.toggleStatusMenu();
this.status = status;
@@ -121,9 +132,9 @@ export class ApiListComponent implements OnInit {
//////// Private //////////
- private filterSection(section: ApiSection, { query, status, type }: SearchCriteria) {
+ private filterSection(section: ApiSection, { query, status, type, includeDeprecated }: SearchCriteria) {
const items = section.items!.filter((item) => {
- return matchesType() && matchesStatus() && matchesQuery();
+ return matchesType() && matchesStatus() && matchesQuery() && matchesStability();
function matchesQuery() {
return !query || section.name.indexOf(query) !== -1 || item.name.indexOf(query) !== -1;
@@ -136,6 +147,10 @@ export class ApiListComponent implements OnInit {
function matchesType() {
return type === 'all' || type === item.docType;
}
+
+ function matchesStability() {
+ return includeDeprecated || item.stability !== 'deprecated';
+ }
});
// If there are no items we still return an empty array if the section name matches and the type is 'package'
@@ -144,7 +159,7 @@ export class ApiListComponent implements OnInit {
// Get initial search criteria from URL search params
private initializeSearchCriteria() {
- const { query, status, type } = this.locationService.search();
+ const { query, status, type, includeDeprecated } = this.locationService.search();
const q = (query || '').toLowerCase();
// Hack: can't bind to query because input cursor always forced to end-of-line.
@@ -152,22 +167,25 @@ export class ApiListComponent implements OnInit {
this.status = this.statuses.find((x) => x.value === status) || this.statuses[0];
this.type = this.types.find((x) => x.value === type) || this.types[0];
+ this.includeDeprecated = includeDeprecated === 'false' ? false : true;
this.searchCriteria = {
query: q,
status: this.status.value,
type: this.type.value,
+ includeDeprecated: this.includeDeprecated,
};
this.criteriaSubject.next(this.searchCriteria);
}
private setLocationSearch() {
- const { query, status, type } = this.searchCriteria;
+ const { query, status, type, includeDeprecated } = this.searchCriteria;
const params = {
query: query ? query : undefined,
status: status !== 'all' ? status : undefined,
type: type !== 'all' ? type : undefined,
+ includeDeprecated: includeDeprecated ? undefined : 'false',
};
this.locationService.setSearch('API Search', params);
diff --git a/apps/rxjs.dev/src/app/custom-elements/api/api-list.module.ts b/apps/rxjs.dev/src/app/custom-elements/api/api-list.module.ts
index aff550f37f..20abff404f 100644
--- a/apps/rxjs.dev/src/app/custom-elements/api/api-list.module.ts
+++ b/apps/rxjs.dev/src/app/custom-elements/api/api-list.module.ts
@@ -1,4 +1,5 @@
import { NgModule, Type } from '@angular/core';
+import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { SharedModule } from '../../shared/shared.module';
@@ -7,7 +8,7 @@ import { ApiService } from './api.service';
import { WithCustomElementComponent } from '../element-registry';
@NgModule({
- imports: [ CommonModule, SharedModule, HttpClientModule ],
+ imports: [ CommonModule, FormsModule, SharedModule, HttpClientModule ],
declarations: [ ApiListComponent ],
providers: [ ApiService ]
})
diff --git a/apps/rxjs.dev/src/styles/2-modules/_api-list.scss b/apps/rxjs.dev/src/styles/2-modules/_api-list.scss
index 26d1a04cd7..ed0972218d 100644
--- a/apps/rxjs.dev/src/styles/2-modules/_api-list.scss
+++ b/apps/rxjs.dev/src/styles/2-modules/_api-list.scss
@@ -26,10 +26,16 @@ aio-api-list {
margin-top: 16px;
}
}
+
+ label.show-deprecated {
+ margin-left: auto;
+ width: unset;
+ }
}
.api-filter {
display: flex;
+ align-items: center;
margin: 0 auto;
@media (max-width: 600px) {
From 7620fb13a65b1c28d8707cffbb653a462271b659 Mon Sep 17 00:00:00 2001
From: Daniel Melanson <30221758+daniel-melanson@users.noreply.github.com>
Date: Tue, 21 Nov 2023 13:46:16 -0500
Subject: [PATCH 2/2] test: deprecated filter
---
.../api/api-list.component.spec.ts | 44 ++++++++++++++++---
.../custom-elements/api/api-list.component.ts | 6 +++
2 files changed, 45 insertions(+), 5 deletions(-)
diff --git a/apps/rxjs.dev/src/app/custom-elements/api/api-list.component.spec.ts b/apps/rxjs.dev/src/app/custom-elements/api/api-list.component.spec.ts
index 6b31361315..680b8cb830 100644
--- a/apps/rxjs.dev/src/app/custom-elements/api/api-list.component.spec.ts
+++ b/apps/rxjs.dev/src/app/custom-elements/api/api-list.component.spec.ts
@@ -42,6 +42,18 @@ describe('ApiListComponent', () => {
});
}
+ /**
+ * Expectation Utility: Assert that filteredSections has no items
+ *
+ * Subscribes to `filteredSections` and performs expectation within subscription callback.
+ */
+ function expectNoItems() {
+ component.filteredSections.subscribe(filtered => {
+ expect(filtered.some(section => !!section.items)).toBeFalsy();
+ });
+ }
+
+
describe('#filteredSections', () => {
@@ -95,11 +107,17 @@ describe('ApiListComponent', () => {
});
});
- it('should have no sections and no items visible when there is no match', () => {
+ it('should have no sections or items visible when there is no query match', () => {
component.setQuery('fizzbuzz');
- component.filteredSections.subscribe(filtered => {
- expect(filtered.some(section => !!section.items)).toBeFalsy();
- });
+
+ expectNoItems();
+ });
+
+ it('should have no sections or items visible when there is no non-deprecated match', () => {
+ component.setQuery('function_1');
+ component.setIncludeDeprecated(false);
+
+ expectNoItems();
});
});
@@ -182,6 +200,20 @@ describe('ApiListComponent', () => {
expect(search.query).toBe('foo');
});
+ it('should have includeDeprecated', () => {
+ component.setIncludeDeprecated(false);
+
+ const search = locationService.setSearch.calls.mostRecent().args[1];
+ expect(search.includeDeprecated).toBe('false');
+ });
+
+ it('should not have includeDeprecated', () => {
+ component.setIncludeDeprecated(true);
+
+ const search = locationService.setSearch.calls.mostRecent().args[1];
+ expect(search.includeDeprecated).toBe(undefined);
+ });
+
it('should keep last of multiple query settings (in lowercase)', () => {
component.setQuery('foo');
component.setQuery('fooBar');
@@ -190,15 +222,17 @@ describe('ApiListComponent', () => {
expect(search.query).toBe('foobar');
});
- it('should have query, status, and type', () => {
+ it('should have query, status, type, and includeDeprecated', () => {
component.setQuery('foo');
component.setStatus({value: 'stable', title: 'Stable'});
component.setType({value: 'class', title: 'Class'});
+ component.setIncludeDeprecated(false);
const search = locationService.setSearch.calls.mostRecent().args[1];
expect(search.query).toBe('foo');
expect(search.status).toBe('stable');
expect(search.type).toBe('class');
+ expect(search.includeDeprecated).toBe('false');
});
});
});
diff --git a/apps/rxjs.dev/src/app/custom-elements/api/api-list.component.ts b/apps/rxjs.dev/src/app/custom-elements/api/api-list.component.ts
index b287b25608..be459a4d0a 100644
--- a/apps/rxjs.dev/src/app/custom-elements/api/api-list.component.ts
+++ b/apps/rxjs.dev/src/app/custom-elements/api/api-list.component.ts
@@ -106,6 +106,12 @@ export class ApiListComponent implements OnInit {
this.setSearchCriteria({ query: (query || '').toLowerCase().trim() });
}
+ // NOTE includeDeprecated is model bound - the following method is used for testing
+ setIncludeDeprecated(includeDeprecated: boolean) {
+ this.includeDeprecated = includeDeprecated;
+ this.onIncludeDeprecatedChange();
+ }
+
onIncludeDeprecatedChange() {
this.setSearchCriteria({ includeDeprecated: this.includeDeprecated });
}