diff --git a/src-ui/src/app/components/admin/config/config.component.html b/src-ui/src/app/components/admin/config/config.component.html index e453a3fae..48cac6bfa 100644 --- a/src-ui/src/app/components/admin/config/config.component.html +++ b/src-ui/src/app/components/admin/config/config.component.html @@ -29,6 +29,7 @@ @case (ConfigOptionType.Number) { } @case (ConfigOptionType.Boolean) { } @case (ConfigOptionType.String) { } + @case (ConfigOptionType.JSON) { } } diff --git a/src-ui/src/app/components/admin/config/config.component.spec.ts b/src-ui/src/app/components/admin/config/config.component.spec.ts index 2e15c4399..5d70881b6 100644 --- a/src-ui/src/app/components/admin/config/config.component.spec.ts +++ b/src-ui/src/app/components/admin/config/config.component.spec.ts @@ -87,7 +87,7 @@ describe('ConfigComponent', () => { it('should support discard changes', () => { component.initialConfig = { output_type: OutputTypeConfig.PDF_A2 } as any - component.configForm.get('output_type').patchValue(OutputTypeConfig.PDF_A) + component.configForm.patchValue({ output_type: OutputTypeConfig.PDF_A }) component.discardChanges() expect(component.configForm.get('output_type').value).toEqual( OutputTypeConfig.PDF_A2 @@ -95,9 +95,9 @@ describe('ConfigComponent', () => { }) it('should support JSON validation for e.g. user_args', () => { - component.configForm.get('user_args').patchValue('{ foo bar }') + component.configForm.patchValue({ user_args: '{ foo bar }' }) expect(component.errors).toEqual({ user_args: 'Invalid JSON' }) - component.configForm.get('user_args').patchValue('{ "foo": "bar" }') + component.configForm.patchValue({ user_args: '{ "foo": "bar" }' }) expect(component.errors).toEqual({ user_args: null }) }) }) diff --git a/src-ui/src/app/components/admin/config/config.component.ts b/src-ui/src/app/components/admin/config/config.component.ts index 56cd027cc..66d7b537f 100644 --- a/src-ui/src/app/components/admin/config/config.component.ts +++ b/src-ui/src/app/components/admin/config/config.component.ts @@ -31,22 +31,8 @@ export class ConfigComponent { public readonly ConfigOptionType = ConfigOptionType - public configForm = new FormGroup({ - id: new FormControl(), - output_type: new FormControl(), - pages: new FormControl(), - language: new FormControl(), - mode: new FormControl(), - skip_archive_file: new FormControl(), - image_dpi: new FormControl(), - unpaper_clean: new FormControl(), - deskew: new FormControl(), - rotate_pages: new FormControl(), - rotate_pages_threshold: new FormControl(), - max_image_pixels: new FormControl(), - color_conversion_strategy: new FormControl(), - user_args: new FormControl(), - }) + // generated dynamically + public configForm = new FormGroup({}) public errors = {} @@ -72,6 +58,10 @@ export class ConfigComponent private toastService: ToastService ) { super() + this.configForm.addControl('id', new FormControl()) + PaperlessConfigOptions.forEach((option) => { + this.configForm.addControl(option.key, new FormControl()) + }) } ngOnInit(): void { @@ -90,27 +80,32 @@ export class ConfigComponent }, }) - // validate JSON input for user_args - this.configForm - .get('user_args') - .addValidators((control: AbstractControl) => { - if (!control.value || control.value.toString().length === 0) return null - try { - JSON.parse(control.value) - } catch (e) { - return [ - { - user_args: e, - }, - ] - } - return null + // validate JSON inputs + PaperlessConfigOptions.filter( + (o) => o.type === ConfigOptionType.JSON + ).forEach((option) => { + this.configForm + .get(option.key) + .addValidators((control: AbstractControl) => { + if (!control.value || control.value.toString().length === 0) + return null + try { + JSON.parse(control.value) + } catch (e) { + return [ + { + user_args: e, + }, + ] + } + return null + }) + this.configForm.get(option.key).statusChanges.subscribe((status) => { + this.errors[option.key] = + status === 'INVALID' ? $localize`Invalid JSON` : null }) - this.configForm.get('user_args').statusChanges.subscribe((status) => { - this.errors['user_args'] = - status === 'INVALID' ? $localize`Invalid JSON` : null + this.configForm.get(option.key).updateValueAndValidity() }) - this.configForm.get('user_args').updateValueAndValidity() } ngOnDestroy(): void { @@ -131,7 +126,6 @@ export class ConfigComponent this.isDirty$ = dirtyCheck(this.configForm, this.store.asObservable()) } - this.configForm.patchValue(config) this.initialConfig = config diff --git a/src-ui/src/app/data/paperless-config.ts b/src-ui/src/app/data/paperless-config.ts index 5720235e3..dd9dfdb33 100644 --- a/src-ui/src/app/data/paperless-config.ts +++ b/src-ui/src/app/data/paperless-config.ts @@ -42,6 +42,7 @@ export enum ConfigOptionType { Number = 'number', Select = 'select', Boolean = 'boolean', + JSON = 'json', } export const ConfigCategory = { @@ -52,12 +53,12 @@ export interface ConfigOption { key: string title: string type: ConfigOptionType - choices?: Array + choices?: Array<{ id: string; name: string }> config_key?: string category: string } -function mapToFlatChoices(enumObj: Object): Array { +function mapToItems(enumObj: Object): Array<{ id: string; name: string }> { return Object.keys(enumObj).map((key) => { return { id: enumObj[key], @@ -71,10 +72,17 @@ export const PaperlessConfigOptions: ConfigOption[] = [ key: 'output_type', title: $localize`Output Type`, type: ConfigOptionType.Select, - choices: mapToFlatChoices(OutputTypeConfig), + choices: mapToItems(OutputTypeConfig), config_key: 'PAPERLESS_OCR_OUTPUT_TYPE', category: ConfigCategory.OCR, }, + { + key: 'language', + title: $localize`Language`, + type: ConfigOptionType.String, + config_key: 'PAPERLESS_OCR_LANGUAGE', + category: ConfigCategory.OCR, + }, { key: 'pages', title: $localize`Pages`, @@ -86,7 +94,7 @@ export const PaperlessConfigOptions: ConfigOption[] = [ key: 'mode', title: $localize`Mode`, type: ConfigOptionType.Select, - choices: mapToFlatChoices(ModeConfig), + choices: mapToItems(ModeConfig), config_key: 'PAPERLESS_OCR_MODE', category: ConfigCategory.OCR, }, @@ -94,7 +102,7 @@ export const PaperlessConfigOptions: ConfigOption[] = [ key: 'skip_archive_file', title: $localize`Skip Archive File`, type: ConfigOptionType.Select, - choices: mapToFlatChoices(ArchiveFileConfig), + choices: mapToItems(ArchiveFileConfig), config_key: 'PAPERLESS_OCR_SKIP_ARCHIVE_FILE', category: ConfigCategory.OCR, }, @@ -109,7 +117,7 @@ export const PaperlessConfigOptions: ConfigOption[] = [ key: 'unpaper_clean', title: $localize`Clean`, type: ConfigOptionType.Select, - choices: mapToFlatChoices(CleanConfig), + choices: mapToItems(CleanConfig), config_key: 'PAPERLESS_OCR_CLEAN', category: ConfigCategory.OCR, }, @@ -145,14 +153,14 @@ export const PaperlessConfigOptions: ConfigOption[] = [ key: 'color_conversion_strategy', title: $localize`Color Conversion Strategy`, type: ConfigOptionType.Select, - choices: mapToFlatChoices(ColorConvertConfig), + choices: mapToItems(ColorConvertConfig), config_key: 'PAPERLESS_OCR_COLOR_CONVERSION_STRATEGY', category: ConfigCategory.OCR, }, { key: 'user_args', title: $localize`OCR Arguments`, - type: ConfigOptionType.String, + type: ConfigOptionType.JSON, config_key: 'PAPERLESS_OCR_USER_ARGS', category: ConfigCategory.OCR, },