flare / flare-ui /src /app /dialogs /api-edit-dialog /api-edit-dialog.component.html
ciyidogan's picture
Update flare-ui/src/app/dialogs/api-edit-dialog/api-edit-dialog.component.html
f6ecae1 verified
raw
history blame
22 kB
<h2 mat-dialog-title>
@if (data.mode === 'create') {
Create New API
} @else if (data.mode === 'duplicate') {
Duplicate API
} @else if (data.mode === 'test') {
Test API: {{ data.api.name }}
} @else {
Edit API: {{ data.api.name }}
}
</h2>
<mat-dialog-content>
<mat-tab-group [(selectedIndex)]="activeTabIndex">
<!-- General Tab -->
<mat-tab label="General">
<div class="tab-content">
<mat-form-field appearance="outline">
<mat-label>Name</mat-label>
<input matInput [formControl]="$any(form.get('name'))" placeholder="e.g., get_flights">
<mat-hint>Unique identifier for this API</mat-hint>
@if (form.get('name')?.hasError('required') && form.get('name')?.touched) {
<mat-error>Name is required</mat-error>
}
@if (form.get('name')?.hasError('pattern') && form.get('name')?.touched) {
<mat-error>Only alphanumeric and underscore allowed</mat-error>
}
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>URL</mat-label>
<input matInput [formControl]="$any(form.get('url'))" placeholder="https://api.example.com/endpoint">
<mat-hint>Full URL including protocol</mat-hint>
@if (form.get('url')?.hasError('required') && form.get('url')?.touched) {
<mat-error>URL is required</mat-error>
}
@if (form.get('url')?.hasError('pattern') && form.get('url')?.touched) {
<mat-error>Invalid URL format</mat-error>
}
</mat-form-field>
<div class="row">
<mat-form-field appearance="outline" class="method-field">
<mat-label>Method</mat-label>
<mat-select [formControl]="$any(form.get('method'))">
@for (method of httpMethods; track method) {
<mat-option [value]="method">{{ method }}</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="timeout-field">
<mat-label>Timeout (seconds)</mat-label>
<input matInput type="number" [formControl]="$any(form.get('timeout_seconds'))">
<mat-hint>Request timeout in seconds</mat-hint>
@if (form.get('timeout_seconds')?.hasError('min')) {
<mat-error>Minimum 1 second</mat-error>
}
@if (form.get('timeout_seconds')?.hasError('max')) {
<mat-error>Maximum 300 seconds</mat-error>
}
</mat-form-field>
</div>
<mat-form-field appearance="outline"
class="full-width"
[class.json-valid]="validateJSON('body_template')"
[class.json-invalid]="!validateJSON('body_template') && form.get('body_template')?.value">
<mat-label>Body Template</mat-label>
<textarea matInput
[formControl]="$any(form.get('body_template'))"
rows="8"
placeholder='{"key": "value"}'
(click)="saveCursorPosition('body_template', $event)"
(keyup)="saveCursorPosition('body_template', $event)"></textarea>
<mat-hint>JSON template with template variable support</mat-hint>
@if (!validateJSON('body_template')) {
<mat-error>Invalid JSON format</mat-error>
}
</mat-form-field>
<!-- JSON Validation Indicator -->
<div class="json-validation-status">
@if (validateJSON('body_template')) {
<mat-icon class="valid">check_circle</mat-icon>
<span class="valid">Valid JSON</span>
} @else {
<mat-icon class="invalid">error</mat-icon>
<span class="invalid">Invalid JSON</span>
}
</div>
<!-- Collapsible Variables Panel -->
<mat-expansion-panel class="variables-panel">
<mat-expansion-panel-header>
<mat-panel-title>
<mat-icon>code</mat-icon>
Available Variables
</mat-panel-title>
<mat-panel-description>
Click to insert template variables
</mat-panel-description>
</mat-expansion-panel-header>
<mat-chip-set>
@for (variable of getTemplateVariables(false); track variable) {
<mat-chip (click)="insertTemplateVariable('body_template', variable)">
{{ variable }}
</mat-chip>
}
</mat-chip-set>
</mat-expansion-panel>
<mat-form-field appearance="outline">
<mat-label>Proxy URL (Optional)</mat-label>
<input matInput [formControl]="$any(form.get('proxy'))" placeholder="http://proxy.example.com:8080">
<mat-hint>HTTP proxy for this API call</mat-hint>
</mat-form-field>
</div>
</mat-tab>
<!-- Headers Tab -->
<mat-tab label="Headers">
<div class="tab-content">
<div class="array-section">
<div class="section-header">
<h3>Request Headers</h3>
<button mat-button color="primary" (click)="addHeader()">
<mat-icon>add</mat-icon>
Add Header
</button>
</div>
@if (headers.length === 0) {
<p class="empty-message">No headers configured. Click "Add Header" to add one.</p>
}
@for (header of headers.controls; track header; let i = $index) {
<div class="array-item" [formGroup]="$any(header)">
<mat-form-field appearance="outline" class="key-field">
<mat-label>Header Name</mat-label>
<input matInput formControlName="key" placeholder="Content-Type">
</mat-form-field>
<mat-form-field appearance="outline" class="value-field">
<mat-label>Header Value</mat-label>
<input matInput formControlName="value" placeholder="application/json">
<button mat-icon-button matSuffix [matMenuTriggerFor]="headerMenu">
<mat-icon>code</mat-icon>
</button>
<mat-menu #headerMenu="matMenu">
@for (variable of getTemplateVariables(); track variable) {
<button mat-menu-item (click)="insertHeaderValue(i, variable)">
{{ variable }}
</button>
}
</mat-menu>
</mat-form-field>
<button mat-icon-button color="warn" (click)="removeHeader(i)">
<mat-icon>delete</mat-icon>
</button>
</div>
}
</div>
</div>
</mat-tab>
<!-- Response Tab -->
<mat-tab label="Response">
<div class="tab-content">
<mat-form-field appearance="outline" class="full-width">
<mat-label>Response Prompt</mat-label>
<textarea matInput
[formControl]="$any(form.get('response_prompt'))"
rows="4"
placeholder="Optional instructions for processing the response"></textarea>
<mat-hint>Instructions for AI to process the response (optional)</mat-hint>
</mat-form-field>
<mat-divider></mat-divider>
<div class="array-section">
<div class="section-header">
<h3>Response Mappings</h3>
<button mat-button color="primary" (click)="addResponseMapping()">
<mat-icon>add</mat-icon>
Add Mapping
</button>
</div>
<p class="info-text">
Extract values from API response and save them as variables for use in subsequent intents.
</p>
@if (responseMappings.length === 0) {
<p class="empty-message">No response mappings configured.</p>
}
@for (mapping of responseMappings.controls; track mapping; let i = $index) {
<mat-expansion-panel [formGroup]="$any(mapping)">
<mat-expansion-panel-header>
<mat-panel-title>
{{ mapping.get('variable_name')?.value || 'New Mapping' }}
</mat-panel-title>
<mat-panel-description>
{{ mapping.get('json_path')?.value || 'Configure mapping' }}
</mat-panel-description>
</mat-expansion-panel-header>
<div class="mapping-content">
<mat-form-field appearance="outline">
<mat-label>Variable Name</mat-label>
<input matInput formControlName="variable_name" placeholder="booking_ref">
<mat-hint>Name to store the extracted value</mat-hint>
@if (mapping.get('variable_name')?.hasError('pattern')) {
<mat-error>Lowercase letters, numbers and underscore only</mat-error>
}
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Caption</mat-label>
<input matInput formControlName="caption" placeholder="Booking Reference">
<mat-hint>Human-readable description</mat-hint>
</mat-form-field>
<div class="row">
<mat-form-field appearance="outline" class="type-field">
<mat-label>Type</mat-label>
<mat-select formControlName="type">
@for (type of variableTypes; track type) {
<mat-option [value]="type">{{ type }}</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="path-field">
<mat-label>JSON Path</mat-label>
<input matInput formControlName="json_path" placeholder="$.data.bookingReference">
<mat-hint>JSONPath expression to extract value</mat-hint>
</mat-form-field>
</div>
<button mat-button color="warn" (click)="removeResponseMapping(i)">
<mat-icon>delete</mat-icon>
Remove Mapping
</button>
</div>
</mat-expansion-panel>
}
</div>
<!-- Retry Settings -->
<mat-divider></mat-divider>
<div class="retry-section" [formGroup]="$any(form.get('retry'))">
<h3>Retry Settings</h3>
<div class="row">
<mat-form-field appearance="outline">
<mat-label>Retry Count</mat-label>
<input matInput type="number" formControlName="retry_count">
<mat-hint>Number of retry attempts</mat-hint>
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Backoff (seconds)</mat-label>
<input matInput type="number" formControlName="backoff_seconds">
<mat-hint>Delay between retries</mat-hint>
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Strategy</mat-label>
<mat-select formControlName="strategy">
@for (strategy of retryStrategies; track strategy) {
<mat-option [value]="strategy">{{ strategy }}</mat-option>
}
</mat-select>
</mat-form-field>
</div>
</div>
</div>
</mat-tab>
<!-- Test Tab -->
<mat-tab label="Test">
<div class="tab-content">
<div class="test-section">
<h3>Test API Call</h3>
<div class="test-controls">
<button mat-raised-button color="primary"
(click)="testAPI()"
[disabled]="testing || !form.get('url')?.valid || !form.get('method')?.valid">
@if (testing) {
<ng-container>
<mat-icon class="spin">sync</mat-icon>
Testing...
</ng-container>
} @else {
<ng-container>
<mat-icon>play_arrow</mat-icon>
Test API
</ng-container>
}
</button>
<button mat-button (click)="updateTestRequestJson()">
<mat-icon>refresh</mat-icon>
Generate Test Data
</button>
</div>
<mat-form-field appearance="outline" class="full-width">
<mat-label>Test Request Body</mat-label>
<textarea matInput
[(ngModel)]="testRequestJson"
rows="10"
placeholder="Enter test request JSON here"></textarea>
<mat-hint>Variables will be replaced with test values</mat-hint>
</mat-form-field>
@if (testResult) {
<mat-divider></mat-divider>
<div class="test-result" [class.success]="testResult.success" [class.error]="!testResult.success">
<h4>Test Result</h4>
@if (testResult.success) {
<div class="result-status">
<mat-icon>check_circle</mat-icon>
<span>Success ({{ testResult.status_code }})</span>
</div>
} @else {
<div class="result-status">
<mat-icon>error</mat-icon>
<span>Failed: {{ testResult.error }}</span>
</div>
}
@if (testResult.response_time) {
<p><strong>Response Time:</strong> {{ testResult.response_time }}ms</p>
}
@if (testResult.response_body) {
<mat-form-field appearance="outline" class="full-width">
<mat-label>Response Body</mat-label>
<textarea matInput
[value]="testResult.response_body | json"
rows="10"
readonly></textarea>
</mat-form-field>
}
@if (testResult.request_body) {
<mat-form-field appearance="outline" class="full-width">
<mat-label>Actual Request Sent</mat-label>
<textarea matInput
[value]="testResult.request_body | json"
rows="8"
readonly></textarea>
</mat-form-field>
}
</div>
}
</div>
</div>
</mat-tab>
<!-- Auth Tab -->
<mat-tab label="Authentication">
<div class="tab-content" [formGroup]="$any(form.get('auth'))">
<mat-checkbox formControlName="enabled">
Enable Authentication
</mat-checkbox>
@if (form.get('auth.enabled')?.value) {
<mat-divider></mat-divider>
<div class="auth-section">
<h3>Token Configuration</h3>
<mat-form-field appearance="outline">
<mat-label>Token Endpoint</mat-label>
<input matInput formControlName="token_endpoint" placeholder="https://api.example.com/auth/token">
<mat-hint>URL to obtain authentication token</mat-hint>
@if (form.get('auth.token_endpoint')?.hasError('required') && form.get('auth.token_endpoint')?.touched) {
<mat-error>Token endpoint is required when auth is enabled</mat-error>
}
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Token Response Path</mat-label>
<input matInput formControlName="response_token_path" placeholder="token">
<mat-hint>JSON path to extract token from response</mat-hint>
@if (form.get('auth.response_token_path')?.hasError('required') && form.get('auth.response_token_path')?.touched) {
<mat-error>Token path is required when auth is enabled</mat-error>
}
</mat-form-field>
<mat-form-field appearance="outline"
class="full-width"
[class.json-valid]="validateJSON('auth.token_request_body')"
[class.json-invalid]="!validateJSON('auth.token_request_body') && form.get('auth.token_request_body')?.value">
<mat-label>Token Request Body</mat-label>
<textarea matInput
formControlName="token_request_body"
rows="6"
(click)="saveCursorPosition('auth.token_request_body', $event)"
(keyup)="saveCursorPosition('auth.token_request_body', $event)"
placeholder='{"username": "api_user", "password": "api_pass"}'></textarea>
<mat-hint>JSON body for token request</mat-hint>
@if (!validateJSON('auth.token_request_body')) {
<mat-error>Invalid JSON format</mat-error>
}
</mat-form-field>
<!-- JSON Validation Indicator -->
<div class="json-validation-status">
@if (validateJSON('auth.token_request_body')) {
<mat-icon class="valid">check_circle</mat-icon>
<span class="valid">Valid JSON</span>
} @else {
<mat-icon class="invalid">error</mat-icon>
<span class="invalid">Invalid JSON</span>
}
</div>
<!-- Collapsible Variables Panel -->
<mat-expansion-panel class="variables-panel">
<mat-expansion-panel-header>
<mat-panel-title>
<mat-icon>code</mat-icon>
Available Variables
</mat-panel-title>
<mat-panel-description>
Click to insert template variables
</mat-panel-description>
</mat-expansion-panel-header>
<mat-chip-set>
@for (variable of getTemplateVariables(); track variable) {
<mat-chip (click)="insertTemplateVariable('auth.token_request_body', variable)">
{{ variable }}
</mat-chip>
}
</mat-chip-set>
</mat-expansion-panel>
<mat-divider></mat-divider>
<h3>Token Refresh (Optional)</h3>
<mat-form-field appearance="outline">
<mat-label>Refresh Endpoint</mat-label>
<input matInput formControlName="token_refresh_endpoint" placeholder="https://api.example.com/auth/refresh">
<mat-hint>URL to refresh expired token</mat-hint>
</mat-form-field>
<mat-form-field appearance="outline"
class="full-width"
[class.json-valid]="validateJSON('auth.token_refresh_body')"
[class.json-invalid]="!validateJSON('auth.token_refresh_body') && form.get('auth.token_refresh_body')?.value">
<mat-label>Refresh Request Body</mat-label>
<textarea matInput
formControlName="token_refresh_body"
rows="4"
(click)="saveCursorPosition('auth.token_refresh_body', $event)"
(keyup)="saveCursorPosition('auth.token_refresh_body', $event)"
placeholder='{"refresh_token": "your_refresh_token"}'></textarea>
<mat-hint>JSON body for refresh request</mat-hint>
@if (!validateJSON('auth.token_refresh_body')) {
<mat-error>Invalid JSON format</mat-error>
}
</mat-form-field>
<!-- JSON Validation Indicator -->
<div class="json-validation-status">
@if (validateJSON('auth.token_refresh_body')) {
<mat-icon class="valid">check_circle</mat-icon>
<span class="valid">Valid JSON</span>
} @else {
<mat-icon class="invalid">error</mat-icon>
<span class="invalid">Invalid JSON</span>
}
</div>
<!-- Collapsible Variables Panel -->
<mat-expansion-panel class="variables-panel">
<mat-expansion-panel-header>
<mat-panel-title>
<mat-icon>code</mat-icon>
Available Variables
</mat-panel-title>
<mat-panel-description>
Click to insert template variables
</mat-panel-description>
</mat-expansion-panel-header>
<mat-chip-set>
@for (variable of getTemplateVariables(); track variable) {
<mat-chip (click)="insertTemplateVariable('auth.token_refresh_body', variable)">
{{ variable }}
</mat-chip>
}
</mat-chip-set>
</mat-expansion-panel>
</div>
}
</div>
</mat-tab>
</mat-tab-group>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button (click)="cancel()">
@if (data.mode === 'test') {
Close
} @else {
Cancel
}
</button>
@if (data.mode !== 'test') {
<button mat-raised-button color="primary"
(click)="save()"
[disabled]="saving || form.invalid">
@if (saving) {
<ng-container>
<mat-icon class="spin">sync</mat-icon>
Saving...
</ng-container>
} @else {
@if (data.mode === 'create' || data.mode === 'duplicate') {
Create
} @else {
Update
}
}
</button>
}
</mat-dialog-actions>