Cleaning up the dynamic routing between /api/items & /api/shows for the browse component

This commit is contained in:
Zoe Roux 2020-09-27 02:42:02 +02:00
parent 3ec72bbead
commit 3328568bd2
2 changed files with 51 additions and 52 deletions

View File

@ -27,30 +27,34 @@ const routes: Routes = [
{path: "browse", component: ItemsGridComponent, pathMatch: "full",
resolve: {items: PageResolver.forResource<LibraryItem>("items", ItemsGridComponent.routeMapper)},
canLoad: [AuthGuard.forPermissions("read")],
canActivate: [AuthGuard.forPermissions("read")]
canActivate: [AuthGuard.forPermissions("read")],
runGuardsAndResolvers: "always"
},
{path: "browse/:slug", component: ItemsGridComponent,
resolve: {items: PageResolver.forResource<LibraryItem>("library/:slug/items", ItemsGridComponent.routeMapper)},
canLoad: [AuthGuard.forPermissions("read")],
canActivate: [AuthGuard.forPermissions("read")]
canActivate: [AuthGuard.forPermissions("read")],
runGuardsAndResolvers: "always"
},
{path: "genre/:slug", component: ItemsGridComponent, pathMatch: "full",
resolve: {items: PageResolver.forResource<LibraryItem>("shows", ["genres", "studio"], "genres=ctn::slug")},
resolve: {items: PageResolver.forResource<Show>("shows", ItemsGridComponent.routeMapper, "genres=ctn::slug")},
canLoad: [AuthGuard.forPermissions("read")],
canActivate: [AuthGuard.forPermissions("read")]
canActivate: [AuthGuard.forPermissions("read")],
runGuardsAndResolvers: "always"
},
{path: "studio/:slug", component: ItemsGridComponent, pathMatch: "full",
resolve: {items: PageResolver.forResource<Show>("shows", ItemsGridComponent.routeMapper, "studio=:slug")},
canLoad: [AuthGuard.forPermissions("read")],
canActivate: [AuthGuard.forPermissions("read")],
runGuardsAndResolvers: "always"
},
{path: "show/:slug", component: ShowDetailsComponent,
resolve: {show: ItemResolver.forResource<Show>("shows/:slug")},
canLoad: [AuthGuard.forPermissions("read")],
canActivate: [AuthGuard.forPermissions("read")]
},
{path: "collection/:slug", component: CollectionComponent,
resolve:
{
collection: ItemResolver.forResource<Collection>("collections/:slug"),
shows: PageResolver.forResource<Show>("collections/:slug/shows")
shows: PageResolver.forResource<Show>("collections/:slug/shows", ItemsGridComponent.routeMapper)
},
canLoad: [AuthGuard.forPermissions("read")],
canActivate: [AuthGuard.forPermissions("read")]
@ -59,12 +63,18 @@ const routes: Routes = [
resolve:
{
collection: ItemResolver.forResource<Collection>("people/:slug"),
shows: PageResolver.forResource<Show>("people/:slug/roles")
shows: PageResolver.forResource<Show>("people/:slug/roles", ItemsGridComponent.routeMapper)
},
canLoad: [AuthGuard.forPermissions("read")],
canActivate: [AuthGuard.forPermissions("read")]
},
{path: "show/:slug", component: ShowDetailsComponent,
resolve: {show: ItemResolver.forResource<Show>("shows/:slug")},
canLoad: [AuthGuard.forPermissions("read")],
canActivate: [AuthGuard.forPermissions("read")]
},
{path: "search/:query", component: SearchComponent,
resolve: {items: ItemResolver.forResource<SearchResult>("search/:query")},
canLoad: [AuthGuard.forPermissions("read")],
@ -77,7 +87,7 @@ const routes: Routes = [
canActivate: [AuthGuard.forPermissions("play")]
},
// TODO implement missing pages: /genre, /studio & an home page.
// TODO implement an home page.
{path: "", pathMatch: 'full', redirectTo: "/browse"},
{path: "**", component: NotFoundComponent}

View File

@ -29,6 +29,8 @@ export class ItemsGridComponent implements OnInit
sortKeys: string[] = ["title", "start year", "end year"]
sortUp: boolean = true;
public static readonly showOnlyFilters: string[] = ["genres", "studio"]
public static readonly filters: string[] = [].concat(...ItemsGridComponent.showOnlyFilters)
filters: {genres: Genre[], studio: Studio} = {genres: [], studio: null};
genres: Genre[] = [];
studios: Studio[] = [];
@ -58,20 +60,31 @@ export class ItemsGridComponent implements OnInit
});
}
// TODO need to put every filter available in one place (it is everywhere for now)
// TODO clean route change
// TODO support dynamic switching between /genre & /browse & /whatever.
/*
* /browse -> /api/items | /api/shows
* /browse/:library -> /api/library/:slug/items | /api/library/:slug/shows
* /genre/:slug -> /api/shows
* /studio/:slug -> /api/shows
*
* /collection/:slug -> /api/collection/:slug/shows |> AS @Input
* /people/:slug -> /api/people/:slug/roles |> AS @Input
*/
static routeMapper(route: ActivatedRouteSnapshot, endpoint: string, query: [string, string][]): string
{
const filter: string[] = ["genres", "studio"];
let queryParams: [string, string][] = Object.entries(route.queryParams).filter(x => filter.includes(x[0]));
let queryParams: [string, string][] = Object.entries(route.queryParams)
.filter(x => ItemsGridComponent.filters.includes(x[0]) || x[0] == "sortBy");
if (query)
queryParams.push(...query)
if (queryParams.length > 0)
endpoint = "shows";
let params: string = '?' + queryParams.map(x => `${x[0]}=${x[1]}`).join('&');
if (queryParams.some(x => ItemsGridComponent.showOnlyFilters.includes(x[0])))
endpoint = endpoint.replace(/items?$/, "show");
let params: string = queryParams.length > 0
? '?' + queryParams.map(x => `${x[0]}=${x[1]}`).join('&')
: "";
return `api/${endpoint}${params}`
}
@ -91,63 +104,36 @@ export class ItemsGridComponent implements OnInit
addFilter(category: string, filter: IResource, isArray: boolean = true, isShowOnly: boolean = true)
{
if (!this.complexFiltersEnabled)
if (!this.complexFiltersEnabled && isShowOnly)
return;
let useShow: boolean;
if (isArray)
{
if (this.filters[category].includes(filter))
{
this.filters[category].splice(this.filters[category].indexOf(filter), 1);
useShow = this.getFilterCount() != 0;
}
else
{
this.filters[category].push(filter);
useShow = true;
}
}
else
{
if (this.filters[category] == filter)
{
this.filters[category] = null;
useShow = false;
}
else
{
this.filters[category] = filter;
useShow = filter != null;
}
}
let url: URL = new URL(this.page.first);
if (isShowOnly)
{
url = useShow
? new URL(this.page.changeType("shows"))
: new URL(this.page.changeType(this.defaultType));
}
let param: string;
let param: string = null;
if (isArray && this.filters[category].length > 0)
param = `ctn:${this.filters[category].map(x => x.slug).join(',')}`;
else if (!isArray && this.filters[category] != null)
param = filter.slug;
if (param != null)
url.searchParams.set(category, param);
else
url.searchParams.delete(category)
this.router.navigate([], {
relativeTo: this.route,
queryParams: { [category]: param },
replaceUrl: true,
queryParamsHandling: "merge"
});
this.client.get<Page<Show>>(url.toString())
.subscribe(x => this.page = Object.assign(new Page<Show>(), x));
}
getThumb(slug: string)
@ -170,9 +156,12 @@ export class ItemsGridComponent implements OnInit
this.sortType = type;
this.sortUp = order;
let url: URL = new URL(this.page.first);
url.searchParams.set("sortBy", `${this.sortType.replace(/\s/g, "")}:${this.sortUp ? "asc" : "desc"}`);
this.client.get<Page<LibraryItem | Show>>(url.toString())
.subscribe(x => this.page = Object.assign(new Page<LibraryItem | Show>(), x));
let param: string = `${this.sortType.replace(/\s/g, "")}:${this.sortUp ? "asc" : "desc"}`;
this.router.navigate([], {
relativeTo: this.route,
queryParams: { sortBy: param },
replaceUrl: true,
queryParamsHandling: "merge"
});
}
}