Spaces:
Running
Running
import { Component, inject, OnInit } from '@angular/core'; | |
import { CommonModule } from '@angular/common'; | |
import { FormsModule } from '@angular/forms'; | |
import { MatCardModule } from '@angular/material/card'; | |
import { MatFormFieldModule } from '@angular/material/form-field'; | |
import { MatInputModule } from '@angular/material/input'; | |
import { MatSelectModule } from '@angular/material/select'; | |
import { MatButtonModule } from '@angular/material/button'; | |
import { MatIconModule } from '@angular/material/icon'; | |
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; | |
import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar'; | |
import { MatExpansionModule } from '@angular/material/expansion'; | |
import { ApiService, Environment } from '../../services/api.service'; | |
({ | |
selector: 'app-environment', | |
standalone: true, | |
imports: [ | |
CommonModule, | |
FormsModule, | |
MatCardModule, | |
MatFormFieldModule, | |
MatInputModule, | |
MatSelectModule, | |
MatButtonModule, | |
MatIconModule, | |
MatProgressSpinnerModule, | |
MatSnackBarModule, | |
MatExpansionModule | |
], | |
template: ` | |
<div class="environment-container"> | |
<mat-card> | |
<mat-card-header> | |
<mat-card-title> | |
<mat-icon>settings</mat-icon> | |
Environment Configuration | |
</mat-card-title> | |
</mat-card-header> | |
<mat-card-content> | |
<form (ngSubmit)="save()" #envForm="ngForm"> | |
<mat-form-field appearance="outline" class="full-width"> | |
<mat-label>Work Mode</mat-label> | |
<mat-select | |
name="workMode" | |
[(ngModel)]="environment.work_mode" | |
(selectionChange)="onWorkModeChange()" | |
required | |
[disabled]="loading" | |
> | |
<mat-option value="hfcloud">HF Cloud</mat-option> | |
<mat-option value="cloud">Cloud</mat-option> | |
<mat-option value="on-premise">On-Premise</mat-option> | |
</mat-select> | |
<mat-icon matPrefix>cloud</mat-icon> | |
</mat-form-field> | |
<mat-form-field appearance="outline" class="full-width"> | |
<mat-label>Cloud Token</mat-label> | |
<input | |
matInput | |
type="password" | |
name="cloudToken" | |
[(ngModel)]="environment.cloud_token" | |
[disabled]="loading || environment.work_mode === 'on-premise'" | |
placeholder="Enter cloud token" | |
> | |
<mat-icon matPrefix>vpn_key</mat-icon> | |
<mat-hint>Required for HF Cloud and Cloud modes</mat-hint> | |
</mat-form-field> | |
<mat-form-field appearance="outline" class="full-width"> | |
<mat-label>Spark Endpoint</mat-label> | |
<input | |
matInput | |
type="url" | |
name="sparkEndpoint" | |
[(ngModel)]="environment.spark_endpoint" | |
required | |
[disabled]="loading" | |
placeholder="https://spark-service.example.com" | |
> | |
<mat-icon matPrefix>link</mat-icon> | |
<button | |
mat-icon-button | |
matSuffix | |
type="button" | |
(click)="testConnection()" | |
[disabled]="loading || !environment.spark_endpoint" | |
matTooltip="Test Connection" | |
> | |
<mat-icon>wifi_tethering</mat-icon> | |
</button> | |
</mat-form-field> | |
<mat-expansion-panel class="prompt-panel"> | |
<mat-expansion-panel-header> | |
<mat-panel-title> | |
<mat-icon>psychology</mat-icon> | |
Internal System Prompt | |
</mat-panel-title> | |
<mat-panel-description> | |
Advanced configuration for Spark LLM | |
</mat-panel-description> | |
</mat-expansion-panel-header> | |
<mat-form-field appearance="outline" class="full-width"> | |
<mat-label>Internal Prompt</mat-label> | |
<textarea | |
matInput | |
name="internalPrompt" | |
[(ngModel)]="environment.internal_prompt" | |
[disabled]="loading" | |
rows="10" | |
placeholder="Enter internal system prompt for Spark..." | |
></textarea> | |
<mat-hint>This prompt will be prepended to all project prompts</mat-hint> | |
</mat-form-field> | |
</mat-expansion-panel> | |
<div class="form-actions"> | |
<button | |
mat-raised-button | |
color="primary" | |
type="submit" | |
[disabled]="loading || !envForm.valid || saving" | |
> | |
@if (saving) { | |
<mat-spinner diameter="20"></mat-spinner> | |
Saving... | |
} @else { | |
<mat-icon>save</mat-icon> | |
Save | |
} | |
</button> | |
<button | |
mat-raised-button | |
type="button" | |
(click)="reloadFromSpark()" | |
[disabled]="loading" | |
> | |
<mat-icon>refresh</mat-icon> | |
Reload from Spark | |
</button> | |
</div> | |
</form> | |
</mat-card-content> | |
</mat-card> | |
</div> | |
`, | |
styles: [` | |
.environment-container { | |
max-width: 800px; | |
margin: 0 auto; | |
} | |
mat-card-header { | |
margin-bottom: 24px; | |
mat-card-title { | |
display: flex; | |
align-items: center; | |
gap: 8px; | |
font-size: 24px; | |
mat-icon { | |
font-size: 28px; | |
width: 28px; | |
height: 28px; | |
} | |
} | |
} | |
.full-width { | |
width: 100%; | |
margin-bottom: 20px; | |
} | |
.prompt-panel { | |
margin-bottom: 20px; | |
mat-expansion-panel-header { | |
mat-panel-title { | |
display: flex; | |
align-items: center; | |
gap: 8px; | |
mat-icon { | |
color: #666; | |
} | |
} | |
} | |
} | |
.form-actions { | |
display: flex; | |
gap: 16px; | |
margin-top: 24px; | |
padding-top: 24px; | |
border-top: 1px solid #e0e0e0; | |
button { | |
display: flex; | |
align-items: center; | |
gap: 8px; | |
mat-spinner { | |
margin-right: 8px; | |
} | |
} | |
} | |
::ng-deep { | |
.mat-mdc-form-field-icon-prefix { | |
padding-right: 12px; | |
} | |
.mat-mdc-progress-spinner { | |
--mdc-circular-progress-active-indicator-color: white; | |
} | |
.mat-expansion-panel-body { | |
padding: 16px 0 !important; | |
} | |
} | |
`] | |
}) | |
export class EnvironmentComponent implements OnInit { | |
private apiService = inject(ApiService); | |
private snackBar = inject(MatSnackBar); | |
environment: Environment = { | |
work_mode: 'hfcloud', | |
cloud_token: '', | |
spark_endpoint: '', | |
internal_prompt: '' | |
}; | |
loading = true; | |
saving = false; | |
ngOnInit() { | |
this.loadEnvironment(); | |
} | |
loadEnvironment() { | |
this.loading = true; | |
this.apiService.getEnvironment().subscribe({ | |
next: (env) => { | |
this.environment = env; | |
this.loading = false; | |
}, | |
error: (err) => { | |
this.snackBar.open('Failed to load environment configuration', 'Close', { | |
duration: 5000, | |
panelClass: 'error-snackbar' | |
}); | |
this.loading = false; | |
} | |
}); | |
} | |
onWorkModeChange() { | |
if (this.environment.work_mode === 'on-premise') { | |
this.environment.cloud_token = ''; | |
} | |
} | |
save() { | |
this.saving = true; | |
this.apiService.updateEnvironment(this.environment).subscribe({ | |
next: () => { | |
this.snackBar.open('Environment configuration saved successfully', 'Close', { | |
duration: 3000 | |
}); | |
this.saving = false; | |
}, | |
error: (err) => { | |
this.snackBar.open( | |
err.error?.detail || 'Failed to save configuration', | |
'Close', | |
{ duration: 5000, panelClass: 'error-snackbar' } | |
); | |
this.saving = false; | |
} | |
}); | |
} | |
testConnection() { | |
this.snackBar.open('Testing connection to Spark endpoint...', undefined, { | |
duration: 2000 | |
}); | |
// TODO: Implement actual connection test | |
setTimeout(() => { | |
this.snackBar.open('Connection successful!', 'Close', { | |
duration: 3000 | |
}); | |
}, 2000); | |
} | |
reloadFromSpark() { | |
this.snackBar.open('Reloading configuration from Spark...', undefined, { | |
duration: 2000 | |
}); | |
setTimeout(() => { | |
this.loadEnvironment(); | |
this.snackBar.open('Configuration reloaded', 'Close', { | |
duration: 3000 | |
}); | |
}, 1000); | |
} | |
} |