Basic frontend settings retrieval

This commit is contained in:
Michael Shamoon 2022-05-07 00:05:51 -07:00
parent 4b37c1963b
commit a697eb8530
3 changed files with 146 additions and 87 deletions

View File

@ -17,7 +17,7 @@ import {
} from 'src/app/services/settings.service' } from 'src/app/services/settings.service'
import { ToastService } from 'src/app/services/toast.service' import { ToastService } from 'src/app/services/toast.service'
import { dirtyCheck, DirtyComponent } from '@ngneat/dirty-check-forms' import { dirtyCheck, DirtyComponent } from '@ngneat/dirty-check-forms'
import { Observable, Subscription, BehaviorSubject } from 'rxjs' import { Observable, Subscription, BehaviorSubject, first } from 'rxjs'
@Component({ @Component({
selector: 'app-settings', selector: 'app-settings',
@ -72,85 +72,93 @@ export class SettingsComponent implements OnInit, OnDestroy, DirtyComponent {
ngOnInit() { ngOnInit() {
this.savedViewService.listAll().subscribe((r) => { this.savedViewService.listAll().subscribe((r) => {
this.savedViews = r.results this.savedViews = r.results
let storeData = { this.settings
bulkEditConfirmationDialogs: this.settings.get( .retrieveSettings()
SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS .pipe(first())
), .subscribe(() => {
bulkEditApplyOnClose: this.settings.get( let storeData = {
SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE bulkEditConfirmationDialogs: this.settings.get(
), SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS
documentListItemPerPage: this.settings.get( ),
SETTINGS_KEYS.DOCUMENT_LIST_SIZE bulkEditApplyOnClose: this.settings.get(
), SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE
darkModeUseSystem: this.settings.get( ),
SETTINGS_KEYS.DARK_MODE_USE_SYSTEM documentListItemPerPage: this.settings.get(
), SETTINGS_KEYS.DOCUMENT_LIST_SIZE
darkModeEnabled: this.settings.get(SETTINGS_KEYS.DARK_MODE_ENABLED), ),
darkModeInvertThumbs: this.settings.get( darkModeUseSystem: this.settings.get(
SETTINGS_KEYS.DARK_MODE_THUMB_INVERTED SETTINGS_KEYS.DARK_MODE_USE_SYSTEM
), ),
themeColor: this.settings.get(SETTINGS_KEYS.THEME_COLOR), darkModeEnabled: this.settings.get(SETTINGS_KEYS.DARK_MODE_ENABLED),
useNativePdfViewer: this.settings.get( darkModeInvertThumbs: this.settings.get(
SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER SETTINGS_KEYS.DARK_MODE_THUMB_INVERTED
), ),
savedViews: {}, themeColor: this.settings.get(SETTINGS_KEYS.THEME_COLOR),
displayLanguage: this.settings.getLanguage(), useNativePdfViewer: this.settings.get(
dateLocale: this.settings.get(SETTINGS_KEYS.DATE_LOCALE), SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER
dateFormat: this.settings.get(SETTINGS_KEYS.DATE_FORMAT), ),
notificationsConsumerNewDocument: this.settings.get( savedViews: {},
SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT displayLanguage: this.settings.getLanguage(),
), dateLocale: this.settings.get(SETTINGS_KEYS.DATE_LOCALE),
notificationsConsumerSuccess: this.settings.get( dateFormat: this.settings.get(SETTINGS_KEYS.DATE_FORMAT),
SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS notificationsConsumerNewDocument: this.settings.get(
), SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT
notificationsConsumerFailed: this.settings.get( ),
SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_FAILED notificationsConsumerSuccess: this.settings.get(
), SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS
notificationsConsumerSuppressOnDashboard: this.settings.get( ),
SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD notificationsConsumerFailed: this.settings.get(
), SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_FAILED
} ),
notificationsConsumerSuppressOnDashboard: this.settings.get(
SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD
),
}
for (let view of this.savedViews) { for (let view of this.savedViews) {
storeData.savedViews[view.id.toString()] = { storeData.savedViews[view.id.toString()] = {
id: view.id, id: view.id,
name: view.name, name: view.name,
show_on_dashboard: view.show_on_dashboard, show_on_dashboard: view.show_on_dashboard,
show_in_sidebar: view.show_in_sidebar, show_in_sidebar: view.show_in_sidebar,
} }
this.savedViewGroup.addControl( this.savedViewGroup.addControl(
view.id.toString(), view.id.toString(),
new FormGroup({ new FormGroup({
id: new FormControl(null), id: new FormControl(null),
name: new FormControl(null), name: new FormControl(null),
show_on_dashboard: new FormControl(null), show_on_dashboard: new FormControl(null),
show_in_sidebar: new FormControl(null), show_in_sidebar: new FormControl(null),
})
)
}
this.store = new BehaviorSubject(storeData)
this.storeSub = this.store.asObservable().subscribe((state) => {
this.settingsForm.patchValue(state, { emitEvent: false })
}) })
)
}
this.store = new BehaviorSubject(storeData) // Initialize dirtyCheck
this.isDirty$ = dirtyCheck(
this.settingsForm,
this.store.asObservable()
)
this.storeSub = this.store.asObservable().subscribe((state) => { // Record dirty in case we need to 'undo' appearance settings if not saved on close
this.settingsForm.patchValue(state, { emitEvent: false }) this.isDirty$.subscribe((dirty) => {
}) this.isDirty = dirty
})
// Initialize dirtyCheck // "Live" visual changes prior to save
this.isDirty$ = dirtyCheck(this.settingsForm, this.store.asObservable()) this.settingsForm.valueChanges.subscribe(() => {
this.settings.updateAppearanceSettings(
// Record dirty in case we need to 'undo' appearance settings if not saved on close this.settingsForm.get('darkModeUseSystem').value,
this.isDirty$.subscribe((dirty) => { this.settingsForm.get('darkModeEnabled').value,
this.isDirty = dirty this.settingsForm.get('themeColor').value
}) )
})
// "Live" visual changes prior to save })
this.settingsForm.valueChanges.subscribe(() => {
this.settings.updateAppearanceSettings(
this.settingsForm.get('darkModeUseSystem').value,
this.settingsForm.get('darkModeEnabled').value,
this.settingsForm.get('themeColor').value
)
})
}) })
} }
@ -227,10 +235,23 @@ export class SettingsComponent implements OnInit, OnDestroy, DirtyComponent {
this.settingsForm.value.notificationsConsumerSuppressOnDashboard this.settingsForm.value.notificationsConsumerSuppressOnDashboard
) )
this.settings.setLanguage(this.settingsForm.value.displayLanguage) this.settings.setLanguage(this.settingsForm.value.displayLanguage)
this.store.next(this.settingsForm.value) this.settings
this.documentListViewService.updatePageSize() .storeSettings()
this.settings.updateAppearanceSettings() .pipe(first())
this.toastService.showInfo($localize`Settings saved successfully.`) .subscribe({
next: () => {
this.store.next(this.settingsForm.value)
this.documentListViewService.updatePageSize()
this.settings.updateAppearanceSettings()
this.toastService.showInfo($localize`Settings saved successfully.`)
},
error: (error) => {
this.toastService.showError(
$localize`An error occurred while saving settings.`
)
console.log(error)
},
})
} }
get displayLanguageOptions(): LanguageOption[] { get displayLanguageOptions(): LanguageOption[] {

View File

@ -1,4 +1,5 @@
import { DOCUMENT } from '@angular/common' import { DOCUMENT } from '@angular/common'
import { HttpClient } from '@angular/common/http'
import { import {
Inject, Inject,
Injectable, Injectable,
@ -9,11 +10,14 @@ import {
} from '@angular/core' } from '@angular/core'
import { Meta } from '@angular/platform-browser' import { Meta } from '@angular/platform-browser'
import { CookieService } from 'ngx-cookie-service' import { CookieService } from 'ngx-cookie-service'
import { first, Observable } from 'rxjs'
import { import {
BRIGHTNESS, BRIGHTNESS,
estimateBrightnessForColor, estimateBrightnessForColor,
hexToHsl, hexToHsl,
} from 'src/app/utils/color' } from 'src/app/utils/color'
import { environment } from 'src/environments/environment'
import { Results } from '../data/results'
export interface PaperlessSettings { export interface PaperlessSettings {
key: string key: string
@ -132,17 +136,34 @@ const SETTINGS: PaperlessSettings[] = [
}) })
export class SettingsService { export class SettingsService {
private renderer: Renderer2 private renderer: Renderer2
protected baseUrl: string = environment.apiBaseUrl + 'frontend_settings/'
private settings: Object = {}
private settings$: Observable<Results<any>>
constructor( constructor(
private rendererFactory: RendererFactory2, rendererFactory: RendererFactory2,
@Inject(DOCUMENT) private document, @Inject(DOCUMENT) private document,
private cookieService: CookieService, private cookieService: CookieService,
private meta: Meta, private meta: Meta,
@Inject(LOCALE_ID) private localeId: string @Inject(LOCALE_ID) private localeId: string,
protected http: HttpClient
) { ) {
this.renderer = rendererFactory.createRenderer(null, null) this.renderer = rendererFactory.createRenderer(null, null)
this.updateAppearanceSettings() this.retrieveSettings()
.pipe(first())
.subscribe((response) => {
Object.assign(this.settings, response['settings'])
this.updateAppearanceSettings()
})
}
public retrieveSettings(): Observable<Results<any>> {
if (!this.settings$)
this.settings$ = this.http.get<Results<any>>(this.baseUrl)
return this.settings$
} }
public updateAppearanceSettings( public updateAppearanceSettings(
@ -390,7 +411,16 @@ export class SettingsService {
return null return null
} }
let value = localStorage.getItem(key) let value = null
// parse key:key:key into nested object
const keys = key.replace('general-settings:', '').split(':')
let settingObj = this.settings
keys.forEach((keyPart, index) => {
keyPart = keyPart.replace(/-/g, '_')
if (!settingObj.hasOwnProperty(keyPart)) return
if (index == keys.length - 1) value = settingObj[keyPart]
else settingObj = settingObj[keyPart]
})
if (value != null) { if (value != null) {
switch (setting.type) { switch (setting.type) {
@ -409,10 +439,18 @@ export class SettingsService {
} }
set(key: string, value: any) { set(key: string, value: any) {
localStorage.setItem(key, value.toString()) // parse key:key:key into nested object
let settingObj = this.settings
const keys = key.replace('general-settings:', '').split(':')
keys.forEach((keyPart, index) => {
keyPart = keyPart.replace(/-/g, '_')
if (!settingObj.hasOwnProperty(keyPart)) settingObj[keyPart] = {}
if (index == keys.length - 1) settingObj[keyPart] = value
else settingObj = settingObj[keyPart]
})
} }
unset(key: string) { storeSettings(): Observable<any> {
localStorage.removeItem(key) return this.http.post(this.baseUrl, { settings: this.settings })
} }
} }

View File

@ -515,5 +515,5 @@ class FrontendSettingsViewSerializer(serializers.ModelSerializer):
return instance return instance
def create(self, validated_data): def create(self, validated_data):
frontend_settings = FrontendSettings.objects.create(**validated_data) frontend_settings = FrontendSettings.objects.update_or_create(**validated_data)
return frontend_settings return frontend_settings