Spaces:
Running
Running
Update flare-ui/src/app/components/environment/environment.component.ts
Browse files
flare-ui/src/app/components/environment/environment.component.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
import { Component, OnInit } from '@angular/core';
|
2 |
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
|
3 |
import { FormsModule } from '@angular/forms';
|
4 |
import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
|
@@ -18,6 +18,7 @@ import { MatDividerModule } from '@angular/material/divider';
|
|
18 |
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
19 |
import { MatTooltipModule } from '@angular/material/tooltip';
|
20 |
import { MatDialogModule } from '@angular/material/dialog';
|
|
|
21 |
|
22 |
// Provider interfaces
|
23 |
interface ProviderConfig {
|
@@ -69,7 +70,7 @@ interface EnvironmentConfig {
|
|
69 |
templateUrl: './environment.component.html',
|
70 |
styleUrls: ['./environment.component.scss']
|
71 |
})
|
72 |
-
export class EnvironmentComponent implements OnInit {
|
73 |
form: FormGroup;
|
74 |
loading = false;
|
75 |
saving = false;
|
@@ -120,6 +121,12 @@ export class EnvironmentComponent implements OnInit {
|
|
120 |
{ value: 'phone_call', name: 'Phone Call (Optimized for telephony)' }
|
121 |
];
|
122 |
|
|
|
|
|
|
|
|
|
|
|
|
|
123 |
constructor(
|
124 |
private fb: FormBuilder,
|
125 |
private apiService: ApiService,
|
@@ -160,6 +167,11 @@ export class EnvironmentComponent implements OnInit {
|
|
160 |
this.loadEnvironment();
|
161 |
}
|
162 |
|
|
|
|
|
|
|
|
|
|
|
163 |
// Safe getters for template
|
164 |
get currentLLMProviderSafe(): ProviderConfig | null {
|
165 |
return this.currentLLMProvider || null;
|
@@ -173,28 +185,55 @@ export class EnvironmentComponent implements OnInit {
|
|
173 |
return this.currentSTTProvider || null;
|
174 |
}
|
175 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
176 |
loadEnvironment(): void {
|
177 |
this.loading = true;
|
178 |
this.isLoading = true;
|
179 |
|
180 |
-
this.apiService.getEnvironment()
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
187 |
}
|
188 |
-
|
189 |
-
this.isLoading = false;
|
190 |
-
},
|
191 |
-
error: (err) => {
|
192 |
-
console.error('Failed to load environment:', err);
|
193 |
-
this.snackBar.open('Failed to load environment configuration', 'Close', { duration: 3000 });
|
194 |
-
this.loading = false;
|
195 |
-
this.isLoading = false;
|
196 |
-
}
|
197 |
-
});
|
198 |
}
|
199 |
|
200 |
handleNewFormat(data: EnvironmentConfig): void {
|
@@ -481,8 +520,11 @@ export class EnvironmentComponent implements OnInit {
|
|
481 |
}
|
482 |
|
483 |
saveEnvironment(): void {
|
484 |
-
if (this.form.invalid) {
|
485 |
-
this.snackBar.open('Please fix validation errors', 'Close', {
|
|
|
|
|
|
|
486 |
return;
|
487 |
}
|
488 |
|
@@ -513,17 +555,47 @@ export class EnvironmentComponent implements OnInit {
|
|
513 |
}
|
514 |
};
|
515 |
|
516 |
-
this.apiService.updateEnvironment(saveData as any)
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
527 |
}
|
528 |
|
529 |
// Icon helpers
|
|
|
1 |
+
import { Component, OnInit, OnDestroy } from '@angular/core';
|
2 |
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
|
3 |
import { FormsModule } from '@angular/forms';
|
4 |
import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
|
|
|
18 |
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
19 |
import { MatTooltipModule } from '@angular/material/tooltip';
|
20 |
import { MatDialogModule } from '@angular/material/dialog';
|
21 |
+
import { Subject, takeUntil } from 'rxjs';
|
22 |
|
23 |
// Provider interfaces
|
24 |
interface ProviderConfig {
|
|
|
70 |
templateUrl: './environment.component.html',
|
71 |
styleUrls: ['./environment.component.scss']
|
72 |
})
|
73 |
+
export class EnvironmentComponent implements OnInit, OnDestroy {
|
74 |
form: FormGroup;
|
75 |
loading = false;
|
76 |
saving = false;
|
|
|
121 |
{ value: 'phone_call', name: 'Phone Call (Optimized for telephony)' }
|
122 |
];
|
123 |
|
124 |
+
// API key visibility tracking
|
125 |
+
showApiKeys: { [key: string]: boolean } = {};
|
126 |
+
|
127 |
+
// Memory leak prevention
|
128 |
+
private destroyed$ = new Subject<void>();
|
129 |
+
|
130 |
constructor(
|
131 |
private fb: FormBuilder,
|
132 |
private apiService: ApiService,
|
|
|
167 |
this.loadEnvironment();
|
168 |
}
|
169 |
|
170 |
+
ngOnDestroy() {
|
171 |
+
this.destroyed$.next();
|
172 |
+
this.destroyed$.complete();
|
173 |
+
}
|
174 |
+
|
175 |
// Safe getters for template
|
176 |
get currentLLMProviderSafe(): ProviderConfig | null {
|
177 |
return this.currentLLMProvider || null;
|
|
|
185 |
return this.currentSTTProvider || null;
|
186 |
}
|
187 |
|
188 |
+
// API key masking methods
|
189 |
+
maskApiKey(key?: string): string {
|
190 |
+
if (!key) return '';
|
191 |
+
if (key.length <= 8) return '••••••••';
|
192 |
+
return key.substring(0, 4) + '••••' + key.substring(key.length - 4);
|
193 |
+
}
|
194 |
+
|
195 |
+
toggleApiKeyVisibility(fieldName: string): void {
|
196 |
+
this.showApiKeys[fieldName] = !this.showApiKeys[fieldName];
|
197 |
+
}
|
198 |
+
|
199 |
+
getApiKeyInputType(fieldName: string): string {
|
200 |
+
return this.showApiKeys[fieldName] ? 'text' : 'password';
|
201 |
+
}
|
202 |
+
|
203 |
+
formatApiKeyForDisplay(fieldName: string, value?: string): string {
|
204 |
+
if (this.showApiKeys[fieldName]) {
|
205 |
+
return value || '';
|
206 |
+
}
|
207 |
+
return this.maskApiKey(value);
|
208 |
+
}
|
209 |
+
|
210 |
loadEnvironment(): void {
|
211 |
this.loading = true;
|
212 |
this.isLoading = true;
|
213 |
|
214 |
+
this.apiService.getEnvironment()
|
215 |
+
.pipe(takeUntil(this.destroyed$))
|
216 |
+
.subscribe({
|
217 |
+
next: (data: any) => {
|
218 |
+
// Check if it's new format or legacy
|
219 |
+
if (data.llm_provider) {
|
220 |
+
this.handleNewFormat(data);
|
221 |
+
} else {
|
222 |
+
this.handleLegacyFormat(data);
|
223 |
+
}
|
224 |
+
this.loading = false;
|
225 |
+
this.isLoading = false;
|
226 |
+
},
|
227 |
+
error: (err) => {
|
228 |
+
console.error('Failed to load environment:', err);
|
229 |
+
this.snackBar.open('Failed to load environment configuration', 'Close', {
|
230 |
+
duration: 3000,
|
231 |
+
panelClass: ['error-snackbar']
|
232 |
+
});
|
233 |
+
this.loading = false;
|
234 |
+
this.isLoading = false;
|
235 |
}
|
236 |
+
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
237 |
}
|
238 |
|
239 |
handleNewFormat(data: EnvironmentConfig): void {
|
|
|
520 |
}
|
521 |
|
522 |
saveEnvironment(): void {
|
523 |
+
if (this.form.invalid || this.saving) {
|
524 |
+
this.snackBar.open('Please fix validation errors', 'Close', {
|
525 |
+
duration: 3000,
|
526 |
+
panelClass: ['error-snackbar']
|
527 |
+
});
|
528 |
return;
|
529 |
}
|
530 |
|
|
|
555 |
}
|
556 |
};
|
557 |
|
558 |
+
this.apiService.updateEnvironment(saveData as any)
|
559 |
+
.pipe(takeUntil(this.destroyed$))
|
560 |
+
.subscribe({
|
561 |
+
next: () => {
|
562 |
+
this.saving = false;
|
563 |
+
this.snackBar.open('Environment configuration saved successfully', 'Close', {
|
564 |
+
duration: 3000,
|
565 |
+
panelClass: ['success-snackbar']
|
566 |
+
});
|
567 |
+
|
568 |
+
// Update environment service
|
569 |
+
this.environmentService.updateEnvironment(saveData as any);
|
570 |
+
|
571 |
+
// Clear form dirty state
|
572 |
+
this.form.markAsPristine();
|
573 |
+
},
|
574 |
+
error: (error) => {
|
575 |
+
this.saving = false;
|
576 |
+
|
577 |
+
// Race condition handling
|
578 |
+
if (error.status === 409) {
|
579 |
+
const details = error.error?.details || {};
|
580 |
+
this.snackBar.open(
|
581 |
+
`Settings were modified by ${details.last_update_user || 'another user'}. Please reload.`,
|
582 |
+
'Reload',
|
583 |
+
{ duration: 0 }
|
584 |
+
).onAction().subscribe(() => {
|
585 |
+
this.loadEnvironment();
|
586 |
+
});
|
587 |
+
} else {
|
588 |
+
this.snackBar.open(
|
589 |
+
error.error?.detail || 'Failed to save environment configuration',
|
590 |
+
'Close',
|
591 |
+
{
|
592 |
+
duration: 5000,
|
593 |
+
panelClass: ['error-snackbar']
|
594 |
+
}
|
595 |
+
);
|
596 |
+
}
|
597 |
+
}
|
598 |
+
});
|
599 |
}
|
600 |
|
601 |
// Icon helpers
|