mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-31 10:37:12 -04:00 
			
		
		
		
	Use password and select config fields
This commit is contained in:
		
							parent
							
								
									e14f508327
								
							
						
					
					
						commit
						a3eed49638
					
				| @ -35,6 +35,7 @@ | |||||||
|                                                     @case (ConfigOptionType.String) { <pngx-input-text [formControlName]="option.key" [error]="errors[option.key]"></pngx-input-text> } |                                                     @case (ConfigOptionType.String) { <pngx-input-text [formControlName]="option.key" [error]="errors[option.key]"></pngx-input-text> } | ||||||
|                                                     @case (ConfigOptionType.JSON) { <pngx-input-text [formControlName]="option.key" [error]="errors[option.key]"></pngx-input-text> } |                                                     @case (ConfigOptionType.JSON) { <pngx-input-text [formControlName]="option.key" [error]="errors[option.key]"></pngx-input-text> } | ||||||
|                                                     @case (ConfigOptionType.File) { <pngx-input-file [formControlName]="option.key" (upload)="uploadFile($event, option.key)" [error]="errors[option.key]"></pngx-input-file> } |                                                     @case (ConfigOptionType.File) { <pngx-input-file [formControlName]="option.key" (upload)="uploadFile($event, option.key)" [error]="errors[option.key]"></pngx-input-file> } | ||||||
|  |                                                     @case (ConfigOptionType.Password) { <pngx-input-password [formControlName]="option.key" [error]="errors[option.key]"></pngx-input-password> } | ||||||
|                                                 } |                                                 } | ||||||
|                                             </div> |                                             </div> | ||||||
|                                         </div> |                                         </div> | ||||||
|  | |||||||
| @ -29,6 +29,7 @@ import { SettingsService } from 'src/app/services/settings.service' | |||||||
| import { ToastService } from 'src/app/services/toast.service' | import { ToastService } from 'src/app/services/toast.service' | ||||||
| import { FileComponent } from '../../common/input/file/file.component' | import { FileComponent } from '../../common/input/file/file.component' | ||||||
| import { NumberComponent } from '../../common/input/number/number.component' | import { NumberComponent } from '../../common/input/number/number.component' | ||||||
|  | import { PasswordComponent } from '../../common/input/password/password.component' | ||||||
| import { SelectComponent } from '../../common/input/select/select.component' | import { SelectComponent } from '../../common/input/select/select.component' | ||||||
| import { SwitchComponent } from '../../common/input/switch/switch.component' | import { SwitchComponent } from '../../common/input/switch/switch.component' | ||||||
| import { TextComponent } from '../../common/input/text/text.component' | import { TextComponent } from '../../common/input/text/text.component' | ||||||
| @ -46,6 +47,7 @@ import { LoadingComponentWithPermissions } from '../../loading-component/loading | |||||||
|     TextComponent, |     TextComponent, | ||||||
|     NumberComponent, |     NumberComponent, | ||||||
|     FileComponent, |     FileComponent, | ||||||
|  |     PasswordComponent, | ||||||
|     AsyncPipe, |     AsyncPipe, | ||||||
|     NgbNavModule, |     NgbNavModule, | ||||||
|     FormsModule, |     FormsModule, | ||||||
|  | |||||||
| @ -1,5 +1,11 @@ | |||||||
| <div class="mb-3"> | <div class="mb-3" [class.pb-3]="error"> | ||||||
|   <label class="form-label" [for]="inputId">{{title}}</label> |   <div class="row"> | ||||||
|  |     <div class="d-flex align-items-center position-relative hidden-button-container" [class.col-md-3]="horizontal"> | ||||||
|  |       @if (title) { | ||||||
|  |         <label class="form-label" [class.mb-md-0]="horizontal" [for]="inputId">{{title}}</label> | ||||||
|  |       } | ||||||
|  |     </div> | ||||||
|  |   <div class="position-relative" [class.col-md-9]="horizontal"> | ||||||
|     <div class="input-group" [class.is-invalid]="error"> |     <div class="input-group" [class.is-invalid]="error"> | ||||||
|       <input #inputField [type]="showReveal && textVisible ? 'text' : 'password'" class="form-control" [class.is-invalid]="error" [id]="inputId" [(ngModel)]="value" (focus)="onFocus()" (focusout)="onFocusOut()" (change)="onChange(value)" [disabled]="disabled" [autocomplete]="autocomplete"> |       <input #inputField [type]="showReveal && textVisible ? 'text' : 'password'" class="form-control" [class.is-invalid]="error" [id]="inputId" [(ngModel)]="value" (focus)="onFocus()" (focusout)="onFocusOut()" (change)="onChange(value)" [disabled]="disabled" [autocomplete]="autocomplete"> | ||||||
|       @if (showReveal) { |       @if (showReveal) { | ||||||
| @ -14,4 +20,5 @@ | |||||||
|     @if (hint) { |     @if (hint) { | ||||||
|       <small class="form-text text-muted" [innerHTML]="hint | safeHtml"></small> |       <small class="form-text text-muted" [innerHTML]="hint | safeHtml"></small> | ||||||
|     } |     } | ||||||
|  |   </div> | ||||||
| </div> | </div> | ||||||
|  | |||||||
| @ -44,6 +44,7 @@ export enum ConfigOptionType { | |||||||
|   Boolean = 'boolean', |   Boolean = 'boolean', | ||||||
|   JSON = 'json', |   JSON = 'json', | ||||||
|   File = 'file', |   File = 'file', | ||||||
|  |   Password = 'password', | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export const ConfigCategory = { | export const ConfigCategory = { | ||||||
| @ -52,6 +53,11 @@ export const ConfigCategory = { | |||||||
|   AI: $localize`AI Settings`, |   AI: $localize`AI Settings`, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | export const LLMBackendConfig = { | ||||||
|  |   OPENAI: 'openai', | ||||||
|  |   OLLAMA: 'ollama', | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export interface ConfigOption { | export interface ConfigOption { | ||||||
|   key: string |   key: string | ||||||
|   title: string |   title: string | ||||||
| @ -191,7 +197,8 @@ export const PaperlessConfigOptions: ConfigOption[] = [ | |||||||
|   { |   { | ||||||
|     key: 'llm_backend', |     key: 'llm_backend', | ||||||
|     title: $localize`LLM Backend`, |     title: $localize`LLM Backend`, | ||||||
|     type: ConfigOptionType.String, |     type: ConfigOptionType.Select, | ||||||
|  |     choices: mapToItems(LLMBackendConfig), | ||||||
|     config_key: 'PAPERLESS_LLM_BACKEND', |     config_key: 'PAPERLESS_LLM_BACKEND', | ||||||
|     category: ConfigCategory.AI, |     category: ConfigCategory.AI, | ||||||
|   }, |   }, | ||||||
| @ -205,7 +212,7 @@ export const PaperlessConfigOptions: ConfigOption[] = [ | |||||||
|   { |   { | ||||||
|     key: 'llm_api_key', |     key: 'llm_api_key', | ||||||
|     title: $localize`LLM API Key`, |     title: $localize`LLM API Key`, | ||||||
|     type: ConfigOptionType.String, |     type: ConfigOptionType.Password, | ||||||
|     config_key: 'PAPERLESS_LLM_API_KEY', |     config_key: 'PAPERLESS_LLM_API_KEY', | ||||||
|     category: ConfigCategory.AI, |     category: ConfigCategory.AI, | ||||||
|   }, |   }, | ||||||
|  | |||||||
| @ -32,9 +32,8 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase): | |||||||
| 
 | 
 | ||||||
|         self.assertEqual(response.status_code, status.HTTP_200_OK) |         self.assertEqual(response.status_code, status.HTTP_200_OK) | ||||||
|         self.maxDiff = None |         self.maxDiff = None | ||||||
|         self.assertEqual( |         self.assertDictEqual( | ||||||
|             json.dumps(response.data[0]), |             response.data[0], | ||||||
|             json.dumps( |  | ||||||
|             { |             { | ||||||
|                 "id": 1, |                 "id": 1, | ||||||
|                 "user_args": None, |                 "user_args": None, | ||||||
| @ -58,7 +57,6 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase): | |||||||
|                 "llm_api_key": None, |                 "llm_api_key": None, | ||||||
|                 "llm_url": None, |                 "llm_url": None, | ||||||
|             }, |             }, | ||||||
|             ), |  | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     def test_api_get_ui_settings_with_config(self): |     def test_api_get_ui_settings_with_config(self): | ||||||
|  | |||||||
| @ -185,6 +185,10 @@ class ProfileSerializer(serializers.ModelSerializer): | |||||||
| 
 | 
 | ||||||
| class ApplicationConfigurationSerializer(serializers.ModelSerializer): | class ApplicationConfigurationSerializer(serializers.ModelSerializer): | ||||||
|     user_args = serializers.JSONField(binary=True, allow_null=True) |     user_args = serializers.JSONField(binary=True, allow_null=True) | ||||||
|  |     llm_api_key = ObfuscatedPasswordField( | ||||||
|  |         required=False, | ||||||
|  |         allow_null=True, | ||||||
|  |     ) | ||||||
| 
 | 
 | ||||||
|     def run_validation(self, data): |     def run_validation(self, data): | ||||||
|         # Empty strings treated as None to avoid unexpected behavior |         # Empty strings treated as None to avoid unexpected behavior | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user