feat(aio): add search to 404 page (#19682)
The 404 page will now run a search based on the given URL to offer suggestions for the page that the user really wanted. PR Close #19682
This commit is contained in:
parent
88c46feb20
commit
91fcfcb042
|
@ -7,3 +7,4 @@
|
|||
<p>We're sorry. The page you are looking for cannot be found.</p>
|
||||
</div>
|
||||
</div>
|
||||
<aio-file-not-found-search></aio-file-not-found-search>
|
||||
|
|
|
@ -100,4 +100,12 @@ describe('site App', function() {
|
|||
expect(page.getSearchResults().map(link => link.getText())).toContain('ControlValueAccessor');
|
||||
});
|
||||
});
|
||||
|
||||
describe('404 page', () => {
|
||||
it('should search the index for words found in the url', () => {
|
||||
page.navigateTo('http/router');
|
||||
expect(page.getSearchResults().map(link => link.getText())).toContain('Http');
|
||||
expect(page.getSearchResults().map(link => link.getText())).toContain('Router');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -20,6 +20,7 @@ import { CodeTabsComponent } from './code/code-tabs.component';
|
|||
import { ContributorListComponent } from './contributor/contributor-list.component';
|
||||
import { ContributorComponent } from './contributor/contributor.component';
|
||||
import { CurrentLocationComponent } from './current-location.component';
|
||||
import { FileNotFoundSearchComponent } from './search/file-not-found-search.component';
|
||||
import { LiveExampleComponent, EmbeddedPlunkerComponent } from './live-example/live-example.component';
|
||||
import { ResourceListComponent } from './resource/resource-list.component';
|
||||
import { ResourceService } from './resource/resource.service';
|
||||
|
@ -30,7 +31,8 @@ import { TocComponent } from './toc/toc.component';
|
|||
*/
|
||||
export const embeddedComponents: any[] = [
|
||||
ApiListComponent, CodeExampleComponent, CodeTabsComponent, ContributorListComponent,
|
||||
CurrentLocationComponent, LiveExampleComponent, ResourceListComponent, TocComponent
|
||||
CurrentLocationComponent, FileNotFoundSearchComponent, LiveExampleComponent, ResourceListComponent,
|
||||
TocComponent
|
||||
];
|
||||
|
||||
/** Injectable class w/ property returning components that can be embedded in docs */
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { Subject } from 'rxjs/Subject';
|
||||
import { LocationService } from 'app/shared/location.service';
|
||||
import { MockLocationService } from 'testing/location.service';
|
||||
import { SearchResults } from 'app/search/interfaces';
|
||||
import { SearchResultsComponent } from 'app/shared/search-results/search-results.component';
|
||||
import { SearchService } from 'app/search/search.service';
|
||||
import { FileNotFoundSearchComponent } from './file-not-found-search.component';
|
||||
|
||||
|
||||
describe('FileNotFoundSearchComponent', () => {
|
||||
let element: HTMLElement;
|
||||
let fixture: ComponentFixture<FileNotFoundSearchComponent>;
|
||||
let searchService: SearchService;
|
||||
let searchResultSubject: Subject<SearchResults>;
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ FileNotFoundSearchComponent, SearchResultsComponent ],
|
||||
providers: [
|
||||
{ provide: LocationService, useValue: new MockLocationService('base/initial-url?some-query') },
|
||||
SearchService
|
||||
]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(FileNotFoundSearchComponent);
|
||||
searchService = TestBed.get(SearchService);
|
||||
searchResultSubject = new Subject<SearchResults>();
|
||||
spyOn(searchService, 'search').and.callFake(() => searchResultSubject.asObservable());
|
||||
fixture.detectChanges();
|
||||
element = fixture.nativeElement;
|
||||
});
|
||||
|
||||
it('should run a search with a query built from the current url', () => {
|
||||
expect(searchService.search).toHaveBeenCalledWith('base initial url');
|
||||
});
|
||||
|
||||
it('should pass through any results to the `aio-search-results` component', () => {
|
||||
const searchResultsComponent = fixture.debugElement.query(By.directive(SearchResultsComponent)).componentInstance;
|
||||
expect(searchResultsComponent.searchResults).toBe(null);
|
||||
|
||||
const results = { query: 'base initial url', results: []};
|
||||
searchResultSubject.next(results);
|
||||
fixture.detectChanges();
|
||||
expect(searchResultsComponent.searchResults).toEqual(results);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,23 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { LocationService } from 'app/shared/location.service';
|
||||
import { SearchResults } from 'app/search/interfaces';
|
||||
import { SearchService } from 'app/search/search.service';
|
||||
|
||||
@Component({
|
||||
selector: 'aio-file-not-found-search',
|
||||
template:
|
||||
`<p>Let's see if any of these search results help...</p>
|
||||
<aio-search-results class="embedded" [searchResults]="searchResults | async"></aio-search-results>`
|
||||
})
|
||||
export class FileNotFoundSearchComponent implements OnInit {
|
||||
searchResults: Observable<SearchResults>;
|
||||
constructor(private location: LocationService, private search: SearchService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.searchResults = this.location.currentPath.switchMap(path => {
|
||||
const query = path.split(/\W+/).join(' ');
|
||||
return this.search.search(query);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -29,6 +29,24 @@ aio-search-results {
|
|||
}
|
||||
}
|
||||
|
||||
aio-search-results.embedded .search-results {
|
||||
padding: 0;
|
||||
color: inherit;
|
||||
width: auto;
|
||||
max-height: 100%;
|
||||
position: relative;
|
||||
background-color: inherit;
|
||||
box-shadow: none;
|
||||
box-sizing: border-box;
|
||||
|
||||
.search-area a {
|
||||
color: lighten($darkgray, 10);
|
||||
&:hover {
|
||||
color: $accentblue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-area {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
Loading…
Reference in New Issue