From 0b620f7da4045938661c74cc6c9cfab750a4119a Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 25 Nov 2022 15:48:51 +0000 Subject: [PATCH] added state --- src/Ombi/ClientApp/src/app/app.module.ts | 5 +- .../src/app/login/login.component.ts | 19 ++++--- .../movie/movie-details.component.ts | 2 +- .../services/applications/radarr.service.ts | 16 +++++- .../app/settings/radarr/radarr.component.ts | 55 ++++++++++--------- .../admin-request-dialog.component.ts | 2 +- .../ClientApp/src/app/state/radarr/index.ts | 4 ++ .../app/state/radarr/radarr-initializer.ts | 12 ++++ .../src/app/state/radarr/radarr.actions.ts | 10 ++++ .../src/app/state/radarr/radarr.facade.ts | 27 +++++++++ .../src/app/state/radarr/radarr.selectors.ts | 26 +++++++++ .../src/app/state/radarr/radarr.state.ts | 41 ++++++++++++++ .../ClientApp/src/app/state/radarr/types.ts | 8 +++ 13 files changed, 187 insertions(+), 40 deletions(-) create mode 100644 src/Ombi/ClientApp/src/app/state/radarr/index.ts create mode 100644 src/Ombi/ClientApp/src/app/state/radarr/radarr-initializer.ts create mode 100644 src/Ombi/ClientApp/src/app/state/radarr/radarr.actions.ts create mode 100644 src/Ombi/ClientApp/src/app/state/radarr/radarr.facade.ts create mode 100644 src/Ombi/ClientApp/src/app/state/radarr/radarr.selectors.ts create mode 100644 src/Ombi/ClientApp/src/app/state/radarr/radarr.state.ts create mode 100644 src/Ombi/ClientApp/src/app/state/radarr/types.ts diff --git a/src/Ombi/ClientApp/src/app/app.module.ts b/src/Ombi/ClientApp/src/app/app.module.ts index 0400d3351..c651216b6 100644 --- a/src/Ombi/ClientApp/src/app/app.module.ts +++ b/src/Ombi/ClientApp/src/app/app.module.ts @@ -14,6 +14,7 @@ import { BrowserModule } from "@angular/platform-browser"; import { ButtonModule } from "primeng/button"; import { CUSTOMIZATION_INITIALIZER } from "./state/customization/customization-initializer"; import { SONARR_INITIALIZER } from "./state/sonarr/sonarr-initializer"; +import { RADARR_INITIALIZER } from "./state/radarr/radarr-initializer"; import { ConfirmDialogModule } from "primeng/confirmdialog"; import { CookieComponent } from "./auth/cookie.component"; import { CookieService } from "ng2-cookies"; @@ -24,6 +25,7 @@ import { DialogModule } from "primeng/dialog"; import { FEATURES_INITIALIZER } from "./state/features/features-initializer"; import { FeatureState } from "./state/features"; import { SonarrSettingsState } from "./state/sonarr"; +import { RadarrSettingsState } from "./state/radarr"; import { JwtModule } from "@auth0/angular-jwt"; import { LandingPageComponent } from "./landingpage/landingpage.component"; import { LandingPageService } from "./services"; @@ -163,7 +165,7 @@ export function JwtTokenGetter() { }), SidebarModule, MatNativeDateModule, MatIconModule, MatSidenavModule, MatListModule, MatToolbarModule, LayoutModule, MatSlideToggleModule, - NgxsModule.forRoot([CustomizationState, FeatureState, SonarrSettingsState], { + NgxsModule.forRoot([CustomizationState, FeatureState, SonarrSettingsState, RadarrSettingsState], { developmentMode: !environment.production, }), ...environment.production ? [] : @@ -212,6 +214,7 @@ export function JwtTokenGetter() { FEATURES_INITIALIZER, SONARR_INITIALIZER, CUSTOMIZATION_INITIALIZER, + RADARR_INITIALIZER, { provide: APP_BASE_HREF, useValue: window["baseHref"] diff --git a/src/Ombi/ClientApp/src/app/login/login.component.ts b/src/Ombi/ClientApp/src/app/login/login.component.ts index f2aacdae4..0e0c2a836 100644 --- a/src/Ombi/ClientApp/src/app/login/login.component.ts +++ b/src/Ombi/ClientApp/src/app/login/login.component.ts @@ -6,14 +6,13 @@ import { TranslateService } from "@ngx-translate/core"; import { APP_BASE_HREF } from "@angular/common"; import { AuthService } from "../auth/auth.service"; import { IAuthenticationSettings, ICustomizationSettings } from "../interfaces"; -import { PlexTvService } from "../services"; -import { SettingsService } from "../services"; -import { StatusService } from "../services"; +import { PlexTvService, StatusService, SettingsService } from "../services"; import { StorageService } from "../shared/storage/storage-service"; import { MatSnackBar } from "@angular/material/snack-bar"; import { CustomizationFacade } from "../state/customization"; import { SonarrFacade } from "app/state/sonarr"; +import { RadarrFacade } from "app/state/radarr"; @Component({ templateUrl: "./login.component.html", @@ -62,6 +61,7 @@ export class LoginComponent implements OnDestroy, OnInit { private plexTv: PlexTvService, private store: StorageService, private sonarrFacade: SonarrFacade, + private radarrFacade: RadarrFacade, private readonly notify: MatSnackBar ) { this.href = href; @@ -89,7 +89,7 @@ export class LoginComponent implements OnDestroy, OnInit { }); if (authService.loggedIn()) { - this.router.navigate(["/"]); + this.loadStores(); } } @@ -144,7 +144,7 @@ export class LoginComponent implements OnDestroy, OnInit { if (this.authService.loggedIn()) { this.ngOnDestroy(); - this.sonarrFacade.load().subscribe(); + this.loadStores(); this.router.navigate(["/"]); } else { this.notify.open(this.errorBody, "OK", { @@ -221,7 +221,7 @@ export class LoginComponent implements OnDestroy, OnInit { this.oAuthWindow.close(); } this.oauthLoading = false; - this.sonarrFacade.load().subscribe(); + this.loadStores(); this.router.navigate(["search"]); return; } @@ -252,7 +252,7 @@ export class LoginComponent implements OnDestroy, OnInit { if (this.authService.loggedIn()) { this.ngOnDestroy(); - this.sonarrFacade.load().subscribe(); + this.loadStores(); this.router.navigate(["/"]); } else { this.notify.open(this.errorBody, "OK", { @@ -274,4 +274,9 @@ export class LoginComponent implements OnDestroy, OnInit { public ngOnDestroy() { clearInterval(this.pinTimer); } + + private loadStores() { + this.sonarrFacade.load().subscribe(); + this.radarrFacade.load().subscribe(); + } } diff --git a/src/Ombi/ClientApp/src/app/media-details/components/movie/movie-details.component.ts b/src/Ombi/ClientApp/src/app/media-details/components/movie/movie-details.component.ts index e40945ebb..0479858a7 100644 --- a/src/Ombi/ClientApp/src/app/media-details/components/movie/movie-details.component.ts +++ b/src/Ombi/ClientApp/src/app/media-details/components/movie/movie-details.component.ts @@ -75,7 +75,7 @@ export class MovieDetailsComponent implements OnInit{ this.isAdmin = this.auth.hasRole("admin") || this.auth.hasRole("poweruser"); if (this.isAdmin) { - this.showAdvanced = await this.radarrService.isRadarrEnabled(); + this.showAdvanced = await firstValueFrom(this.radarrService.isRadarrEnabled()); } if (this.imdbId) { diff --git a/src/Ombi/ClientApp/src/app/services/applications/radarr.service.ts b/src/Ombi/ClientApp/src/app/services/applications/radarr.service.ts index eaa785233..33db4f72e 100644 --- a/src/Ombi/ClientApp/src/app/services/applications/radarr.service.ts +++ b/src/Ombi/ClientApp/src/app/services/applications/radarr.service.ts @@ -3,7 +3,7 @@ import { HttpClient } from "@angular/common/http"; import { Injectable, Inject } from "@angular/core"; import { Observable } from "rxjs"; -import { IRadarrProfile, IRadarrRootFolder } from "../../interfaces"; +import { IRadarrProfile, IRadarrRootFolder, ITag } from "../../interfaces"; import { IRadarrSettings } from "../../interfaces"; import { ServiceHelpers } from "../service.helpers"; @@ -23,10 +23,20 @@ export class RadarrService extends ServiceHelpers { public getRootFoldersFromSettings(): Observable { return this.http.get(`${this.url}/RootFolders/`, { headers: this.headers }); } + public getQualityProfilesFromSettings(): Observable { return this.http.get(`${this.url}/Profiles/`, { headers: this.headers }); } - public isRadarrEnabled(): Promise { - return this.http.get(`${this.url}/enabled/`, { headers: this.headers }).toPromise(); + + public isRadarrEnabled(): Observable { + return this.http.get(`${this.url}/enabled/`, { headers: this.headers }); + } + + public getTagsWithSettings(settings: IRadarrSettings): Observable { + return this.http.post(`${this.url}/enabled/`, JSON.stringify(settings), { headers: this.headers }); + } + + public getTags(): Observable { + return this.http.get(`${this.url}/enabled/`, { headers: this.headers }) } } diff --git a/src/Ombi/ClientApp/src/app/settings/radarr/radarr.component.ts b/src/Ombi/ClientApp/src/app/settings/radarr/radarr.component.ts index 2a6443074..14b1c56b2 100644 --- a/src/Ombi/ClientApp/src/app/settings/radarr/radarr.component.ts +++ b/src/Ombi/ClientApp/src/app/settings/radarr/radarr.component.ts @@ -1,8 +1,9 @@ -import { Component, OnInit, QueryList, ViewChild, ViewChildren } from "@angular/core"; +import { Component, OnInit, QueryList, ViewChildren } from "@angular/core"; import { UntypedFormBuilder, UntypedFormGroup } from "@angular/forms"; +import { RadarrFacade } from "app/state/radarr"; import { IMinimumAvailability, IRadarrCombined, IRadarrProfile, IRadarrRootFolder } from "../../interfaces"; -import { NotificationService, SettingsService } from "../../services"; +import { NotificationService } from "../../services"; import { FeaturesFacade } from "../../state/features/features.facade"; import { RadarrFormComponent } from "./components/radarr-form.component"; @@ -23,7 +24,7 @@ export class RadarrComponent implements OnInit { @ViewChildren('4kForm') public form4k: QueryList; @ViewChildren('normalForm') public normalForm: QueryList; - constructor(private settingsService: SettingsService, + constructor(private radarrFacade: RadarrFacade, private notificationService: NotificationService, private featureFacade: FeaturesFacade, private fb: UntypedFormBuilder) { } @@ -31,34 +32,34 @@ export class RadarrComponent implements OnInit { public ngOnInit() { this.is4kEnabled = this.featureFacade.is4kEnabled(); - this.settingsService.getRadarr() + this.radarrFacade.state$() .subscribe(x => { this.form = this.fb.group({ radarr: this.fb.group({ - enabled: [x.radarr.enabled], - apiKey: [x.radarr.apiKey], - defaultQualityProfile: [+x.radarr.defaultQualityProfile], - defaultRootPath: [x.radarr.defaultRootPath], - ssl: [x.radarr.ssl], - subDir: [x.radarr.subDir], - ip: [x.radarr.ip], - port: [x.radarr.port], - addOnly: [x.radarr.addOnly], - minimumAvailability: [x.radarr.minimumAvailability], - scanForAvailability: [x.radarr.scanForAvailability] + enabled: [x.settings.radarr.enabled], + apiKey: [x.settings.radarr.apiKey], + defaultQualityProfile: [+x.settings.radarr.defaultQualityProfile], + defaultRootPath: [x.settings.radarr.defaultRootPath], + ssl: [x.settings.radarr.ssl], + subDir: [x.settings.radarr.subDir], + ip: [x.settings.radarr.ip], + port: [x.settings.radarr.port], + addOnly: [x.settings.radarr.addOnly], + minimumAvailability: [x.settings.radarr.minimumAvailability], + scanForAvailability: [x.settings.radarr.scanForAvailability] }), radarr4K: this.fb.group({ - enabled: [x.radarr4K.enabled], - apiKey: [x.radarr4K.apiKey], - defaultQualityProfile: [+x.radarr4K.defaultQualityProfile], - defaultRootPath: [x.radarr4K.defaultRootPath], - ssl: [x.radarr4K.ssl], - subDir: [x.radarr4K.subDir], - ip: [x.radarr4K.ip], - port: [x.radarr4K.port], - addOnly: [x.radarr4K.addOnly], - minimumAvailability: [x.radarr4K.minimumAvailability], - scanForAvailability: [x.radarr4K.scanForAvailability] + enabled: [x.settings.radarr4K.enabled], + apiKey: [x.settings.radarr4K.apiKey], + defaultQualityProfile: [+x.settings.radarr4K.defaultQualityProfile], + defaultRootPath: [x.settings.radarr4K.defaultRootPath], + ssl: [x.settings.radarr4K.ssl], + subDir: [x.settings.radarr4K.subDir], + ip: [x.settings.radarr4K.ip], + port: [x.settings.radarr4K.port], + addOnly: [x.settings.radarr4K.addOnly], + minimumAvailability: [x.settings.radarr4K.minimumAvailability], + scanForAvailability: [x.settings.radarr4K.scanForAvailability] }), }); this.normalForm.changes.forEach((comp => { @@ -92,7 +93,7 @@ export class RadarrComponent implements OnInit { } const settings = form.value; - this.settingsService.saveRadarr(settings).subscribe(x => { + this.radarrFacade.updateSettings(settings).subscribe(x => { if (x) { this.notificationService.success("Successfully saved Radarr settings"); } else { diff --git a/src/Ombi/ClientApp/src/app/shared/admin-request-dialog/admin-request-dialog.component.ts b/src/Ombi/ClientApp/src/app/shared/admin-request-dialog/admin-request-dialog.component.ts index d0e99b19f..0256fbe77 100644 --- a/src/Ombi/ClientApp/src/app/shared/admin-request-dialog/admin-request-dialog.component.ts +++ b/src/Ombi/ClientApp/src/app/shared/admin-request-dialog/admin-request-dialog.component.ts @@ -80,7 +80,7 @@ export class AdminRequestDialogComponent implements OnInit { } } if (this.data.type === RequestType.movie) { - this.radarrEnabled = await this.radarrService.isRadarrEnabled(); + this.radarrEnabled = await firstValueFrom(this.radarrService.isRadarrEnabled()); if (this.radarrEnabled) { this.radarrService.getQualityProfilesFromSettings().subscribe(c => { this.radarrProfiles = c; diff --git a/src/Ombi/ClientApp/src/app/state/radarr/index.ts b/src/Ombi/ClientApp/src/app/state/radarr/index.ts new file mode 100644 index 000000000..417d27996 --- /dev/null +++ b/src/Ombi/ClientApp/src/app/state/radarr/index.ts @@ -0,0 +1,4 @@ +export * from './radarr.state'; +export * from './radarr.actions'; +export * from './radarr.facade'; +export * from './radarr.selectors'; diff --git a/src/Ombi/ClientApp/src/app/state/radarr/radarr-initializer.ts b/src/Ombi/ClientApp/src/app/state/radarr/radarr-initializer.ts new file mode 100644 index 000000000..fa8759016 --- /dev/null +++ b/src/Ombi/ClientApp/src/app/state/radarr/radarr-initializer.ts @@ -0,0 +1,12 @@ +import { APP_INITIALIZER } from "@angular/core"; +import { Observable } from "rxjs"; +import { RadarrFacade } from "./radarr.facade"; + +export const RADARR_INITIALIZER = { + provide: APP_INITIALIZER, + useFactory: (radarrFacade: RadarrFacade) => (): Observable => { + return radarrFacade.load(); + }, + multi: true, + deps: [RadarrFacade], +}; \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/state/radarr/radarr.actions.ts b/src/Ombi/ClientApp/src/app/state/radarr/radarr.actions.ts new file mode 100644 index 000000000..f97ba7c1a --- /dev/null +++ b/src/Ombi/ClientApp/src/app/state/radarr/radarr.actions.ts @@ -0,0 +1,10 @@ +import { IRadarrCombined } from "../../interfaces"; + +export class LoadSettings { + public static readonly type = '[Radarr] LoadSettings'; +} + +export class UpdateSettings { + public static readonly type = '[Radarr] UpdateSettings'; + constructor(public settings: IRadarrCombined) { } +} \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/state/radarr/radarr.facade.ts b/src/Ombi/ClientApp/src/app/state/radarr/radarr.facade.ts new file mode 100644 index 000000000..11afa1996 --- /dev/null +++ b/src/Ombi/ClientApp/src/app/state/radarr/radarr.facade.ts @@ -0,0 +1,27 @@ +import { IRadarrCombined } from "../../interfaces"; +import { Injectable } from "@angular/core"; +import { Observable } from "rxjs"; +import { Store } from "@ngxs/store"; +import { RadarrState } from "./types"; +import { RadarrSelectors } from "./radarr.selectors"; +import { LoadSettings, UpdateSettings } from "./radarr.actions"; + +@Injectable({ + providedIn: 'root', +}) +export class RadarrFacade { + + public constructor(private store: Store) {} + + public state$ = (): Observable => this.store.select(RadarrSelectors.state); + + public updateSettings = (settings: IRadarrCombined): Observable => this.store.dispatch(new UpdateSettings(settings)); + + public load = (): Observable => this.store.dispatch(new LoadSettings()); + + public settings = (): IRadarrCombined => this.store.selectSnapshot(RadarrSelectors.settings); + + public isEnabled = (): boolean => this.store.selectSnapshot(RadarrSelectors.isEnabled); + + public is4KEnabled = (): boolean => this.store.selectSnapshot(RadarrSelectors.is4KEnabled); +} \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/state/radarr/radarr.selectors.ts b/src/Ombi/ClientApp/src/app/state/radarr/radarr.selectors.ts new file mode 100644 index 000000000..381469199 --- /dev/null +++ b/src/Ombi/ClientApp/src/app/state/radarr/radarr.selectors.ts @@ -0,0 +1,26 @@ +import { RadarrState, RADARR_STATE_TOKEN } from "./types"; +import { Selector } from "@ngxs/store"; +import { IRadarrCombined } from "../../interfaces"; + +export class RadarrSelectors { + + @Selector([RADARR_STATE_TOKEN]) + public static state(state: RadarrState): RadarrState { + return state; + } + + @Selector([RadarrSelectors.state]) + public static settings(state: RadarrState): IRadarrCombined { + return state.settings; + } + + @Selector([RadarrSelectors.settings]) + public static isEnabled(settings: IRadarrCombined): boolean { + return settings?.radarr?.enabled ?? false; + } + + @Selector([RadarrSelectors.settings]) + public static is4KEnabled(settings: IRadarrCombined): boolean { + return settings?.radarr4K?.enabled ?? false; + } +} \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/state/radarr/radarr.state.ts b/src/Ombi/ClientApp/src/app/state/radarr/radarr.state.ts new file mode 100644 index 000000000..b59faa624 --- /dev/null +++ b/src/Ombi/ClientApp/src/app/state/radarr/radarr.state.ts @@ -0,0 +1,41 @@ +import { Action, State, StateContext } from "@ngxs/store"; + +import { RadarrState, RADARR_STATE_TOKEN } from "./types"; +import { SettingsService } from "../../services"; +import { AuthService } from "../../auth/auth.service"; +import { Injectable } from "@angular/core"; +import { combineLatest, Observable, of } from "rxjs"; +import { map, tap } from "rxjs/operators"; +import { IRadarrCombined } from "../../interfaces"; +import { LoadSettings, UpdateSettings } from "./radarr.actions"; + +@State({ + name: RADARR_STATE_TOKEN +}) +@Injectable() +export class RadarrSettingsState { + constructor(private settingsService: SettingsService, private authService: AuthService) { } + + @Action(LoadSettings) + public load({ setState }: StateContext): Observable { + const isAdmin = this.authService.isAdmin(); + const calls = isAdmin ? [this.settingsService.getRadarr()] : [of({})]; + + return combineLatest(calls).pipe( + tap(([settings]) => + { + setState({settings: settings as IRadarrCombined}); + }), + map((result) => {settings: result[0]}) + ); + } + + @Action(UpdateSettings) + public enable(ctx: StateContext, { settings }: UpdateSettings): Observable { + const state = ctx.getState(); + return this.settingsService.saveRadarr(settings).pipe( + tap((_) => ctx.setState({...state, settings})), + map(_ => {...state, settings}) + ); + } +} \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/state/radarr/types.ts b/src/Ombi/ClientApp/src/app/state/radarr/types.ts new file mode 100644 index 000000000..2a1facd8d --- /dev/null +++ b/src/Ombi/ClientApp/src/app/state/radarr/types.ts @@ -0,0 +1,8 @@ +import { IRadarrCombined } from "../../interfaces"; +import { StateToken } from "@ngxs/store"; + +export const RADARR_STATE_TOKEN = new StateToken('RadarrState'); + +export interface RadarrState { + settings: IRadarrCombined; +} \ No newline at end of file