Smart Filters & Dashboard Customization (#2282)

Co-authored-by: Robbie Davis <robbie@therobbiedavis.com>
This commit is contained in:
Joe Milazzo 2023-09-12 11:24:47 -07:00 committed by GitHub
parent 3d501c9532
commit 84f85b4f24
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
92 changed files with 7149 additions and 555 deletions

View file

@ -0,0 +1,11 @@
<ul>
<li class="list-group-item" *ngFor="let f of filters">
<span (click)="loadFilter(f)">{{f.name}}</span>
<button class="btn btn-danger float-end" (click)="deleteFilter(f)">
<i class="fa-solid fa-trash" aria-hidden="true"></i>
<span class="visually-hidden">Delete</span>
</button>
</li>
<li class="list-group-item" *ngIf="filters.length === 0">No Smart Filters created</li>
</ul>

View file

@ -0,0 +1,21 @@
ul {
margin:0;
padding: 0;
li {
padding: 0.5rem 1rem;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
border-radius: 5px;
margin: 5px 0;
color: var(--list-group-hover-text-color);
background-color: var(--list-group-hover-bg-color);
span {
cursor: pointer;
}
}
}

View file

@ -0,0 +1,51 @@
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, inject} from '@angular/core';
import {CommonModule} from '@angular/common';
import {FilterService} from "../../_services/filter.service";
import {SmartFilter} from "../../_models/metadata/v2/smart-filter";
import {Router} from "@angular/router";
import {ConfirmService} from "../../shared/confirm.service";
import {translate} from "@ngneat/transloco";
import {ToastrService} from "ngx-toastr";
@Component({
selector: 'app-manage-smart-filters',
standalone: true,
imports: [CommonModule],
templateUrl: './manage-smart-filters.component.html',
styleUrls: ['./manage-smart-filters.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ManageSmartFiltersComponent {
private readonly filterService = inject(FilterService);
private readonly confirmService = inject(ConfirmService);
private readonly router = inject(Router);
private readonly cdRef = inject(ChangeDetectorRef);
private readonly toastr = inject(ToastrService);
filters: Array<SmartFilter> = [];
constructor() {
this.loadData();
}
loadData() {
this.filterService.getAllFilters().subscribe(filters => {
this.filters = filters;
this.cdRef.markForCheck();
});
}
async loadFilter(f: SmartFilter) {
await this.router.navigateByUrl('all-series?' + f.filter);
}
async deleteFilter(f: SmartFilter) {
if (!await this.confirmService.confirm(translate('toasts.confirm-delete-smart-filter'))) return;
this.filterService.deleteFilter(f.id).subscribe(() => {
this.toastr.success(translate('toasts.smart-filter-deleted'));
this.loadData();
});
}
}

View file

@ -428,6 +428,9 @@
<ng-container *ngIf="tab.fragment === FragmentID.Stats">
<app-user-stats></app-user-stats>
</ng-container>
<ng-container *ngIf="tab.fragment === FragmentID.SmartFilters">
<app-manage-smart-filters></app-manage-smart-filters>
</ng-container>
<ng-container *ngIf="tab.fragment === FragmentID.Scrobbling">
<app-user-scrobble-history></app-user-scrobble-history>
<app-user-holds></app-user-holds>

View file

@ -49,6 +49,7 @@ import { SideNavCompanionBarComponent } from '../../sidenav/_components/side-nav
import {LocalizationService} from "../../_services/localization.service";
import {Language} from "../../_models/metadata/language";
import {translate, TranslocoDirective, TranslocoService} from "@ngneat/transloco";
import {ManageSmartFiltersComponent} from "../manage-smart-filters/manage-smart-filters.component";
enum AccordionPanelID {
ImageReader = 'image-reader',
@ -63,6 +64,7 @@ enum FragmentID {
Theme = 'theme',
Devices = 'devices',
Stats = 'stats',
SmartFilters = 'smart-filters',
Scrobbling = 'scrobbling'
}
@ -76,7 +78,8 @@ enum FragmentID {
imports: [SideNavCompanionBarComponent, NgbNav, NgFor, NgbNavItem, NgbNavItemRole, NgbNavLink, RouterLink, NgbNavContent, NgIf, ChangeEmailComponent,
ChangePasswordComponent, ChangeAgeRestrictionComponent, AnilistKeyComponent, ReactiveFormsModule, NgbAccordionDirective, NgbAccordionItem, NgbAccordionHeader,
NgbAccordionToggle, NgbAccordionButton, NgbCollapse, NgbAccordionCollapse, NgbAccordionBody, NgbTooltip, NgTemplateOutlet, ColorPickerModule, ApiKeyComponent,
ThemeManagerComponent, ManageDevicesComponent, UserStatsComponent, UserScrobbleHistoryComponent, UserHoldsComponent, NgbNavOutlet, TitleCasePipe, SentenceCasePipe, TranslocoDirective]
ThemeManagerComponent, ManageDevicesComponent, UserStatsComponent, UserScrobbleHistoryComponent, UserHoldsComponent, NgbNavOutlet, TitleCasePipe, SentenceCasePipe,
TranslocoDirective, ManageSmartFiltersComponent]
})
export class UserPreferencesComponent implements OnInit, OnDestroy {
@ -107,6 +110,7 @@ export class UserPreferencesComponent implements OnInit, OnDestroy {
{title: '3rd-party-clients-tab', fragment: FragmentID.Clients},
{title: 'theme-tab', fragment: FragmentID.Theme},
{title: 'devices-tab', fragment: FragmentID.Devices},
{title: 'smart-filters-tab', fragment: FragmentID.SmartFilters},
{title: 'stats-tab', fragment: FragmentID.Stats},
];
locales: Array<Language> = [{title: 'English', isoCode: 'en'}];
@ -115,7 +119,6 @@ export class UserPreferencesComponent implements OnInit, OnDestroy {
opdsUrl: string = '';
makeUrl: (val: string) => string = (val: string) => { return this.opdsUrl; };
private readonly destroyRef = inject(DestroyRef);
private readonly trasnlocoService = inject(TranslocoService);
get AccordionPanelID() {
return AccordionPanelID;
@ -304,7 +307,7 @@ export class UserPreferencesComponent implements OnInit, OnDestroy {
};
this.observableHandles.push(this.accountService.updatePreferences(data).subscribe((updatedPrefs) => {
this.toastr.success(this.trasnlocoService.translate('user-preferences.success-toast'));
this.toastr.success(translate('user-preferences.success-toast'));
if (this.user) {
this.user.preferences = updatedPrefs;
this.cdRef.markForCheck();