flare / flare-ui /src /app /components /apis /apis.component.ts
ciyidogan's picture
Upload 22 files
7a224f7 verified
raw
history blame
8.06 kB
import { Component, inject, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { ApiService, API } from '../../services/api.service';
@Component({
selector: 'app-apis',
standalone: true,
imports: [CommonModule, FormsModule],
template: `
<div class="apis-container">
<div class="toolbar">
<h2>API Definitions</h2>
<div class="toolbar-actions">
<button class="btn btn-primary" (click)="createAPI()">
New API
</button>
<button class="btn btn-secondary" disabled>
Import
</button>
<button class="btn btn-secondary" disabled>
Export
</button>
<input
type="text"
placeholder="Search APIs..."
[(ngModel)]="searchTerm"
(input)="filterAPIs()"
class="search-input"
>
<label class="checkbox-label">
<input
type="checkbox"
[(ngModel)]="showDeleted"
(change)="loadAPIs()"
>
Display Deleted
</label>
</div>
</div>
@if (loading) {
<div class="loading">
<span class="spinner"></span> Loading APIs...
</div>
} @else if (filteredAPIs.length === 0) {
<div class="empty-state">
<p>No APIs found.</p>
<button class="btn btn-primary" (click)="createAPI()">
Create your first API
</button>
</div>
} @else {
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>URL</th>
<th>Method</th>
<th>Timeout</th>
<th>Auth</th>
<th>Deleted</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@for (api of filteredAPIs; track api.name) {
<tr [class.deleted]="api.deleted">
<td>{{ api.name }}</td>
<td class="url-cell">{{ api.url }}</td>
<td>
<span class="method-badge" [class]="'method-' + api.method.toLowerCase()">
{{ api.method }}
</span>
</td>
<td>{{ api.timeout_seconds }}s</td>
<td>
@if (api.auth?.enabled) {
<span class="status-badge enabled">βœ“</span>
} @else {
<span class="status-badge">βœ—</span>
}
</td>
<td>
@if (api.deleted) {
<span class="status-badge deleted">βœ“</span>
} @else {
<span class="status-badge">βœ—</span>
}
</td>
<td class="actions">
<button class="action-btn" title="Edit" (click)="editAPI(api)">
πŸ–ŠοΈ
</button>
<button class="action-btn" title="Test" (click)="testAPI(api)">
πŸ§ͺ
</button>
<button class="action-btn" title="Duplicate" (click)="duplicateAPI(api)">
πŸ“‹
</button>
@if (!api.deleted) {
<button class="action-btn danger" title="Delete" (click)="deleteAPI(api)">
πŸ—‘οΈ
</button>
}
</td>
</tr>
}
</tbody>
</table>
}
@if (message) {
<div class="alert" [class.alert-success]="!isError" [class.alert-danger]="isError">
{{ message }}
</div>
}
</div>
`,
styles: [`
.apis-container {
.toolbar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
h2 {
margin: 0;
}
.toolbar-actions {
display: flex;
gap: 0.5rem;
align-items: center;
}
}
.search-input {
padding: 0.375rem 0.75rem;
border: 1px solid #ced4da;
border-radius: 0.25rem;
width: 200px;
}
.checkbox-label {
display: flex;
align-items: center;
gap: 0.25rem;
cursor: pointer;
}
.loading, .empty-state {
text-align: center;
padding: 3rem;
background-color: white;
border-radius: 0.25rem;
p {
margin-bottom: 1rem;
color: #6c757d;
}
}
.url-cell {
max-width: 300px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.method-badge {
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
font-size: 0.75rem;
font-weight: 600;
&.method-get { background-color: #28a745; color: white; }
&.method-post { background-color: #007bff; color: white; }
&.method-put { background-color: #ffc107; color: #333; }
&.method-patch { background-color: #17a2b8; color: white; }
&.method-delete { background-color: #dc3545; color: white; }
}
.status-badge {
&.enabled { color: #28a745; }
&.deleted { color: #dc3545; }
}
.actions {
display: flex;
gap: 0.25rem;
}
.action-btn {
background: none;
border: none;
cursor: pointer;
font-size: 1.1rem;
padding: 0.25rem;
border-radius: 0.25rem;
&:hover {
background-color: #f8f9fa;
}
&.danger:hover {
background-color: #f8d7da;
}
}
tr.deleted {
opacity: 0.6;
background-color: #f8f9fa;
}
}
`]
})
export class ApisComponent implements OnInit {
private apiService = inject(ApiService);
apis: API[] = [];
filteredAPIs: API[] = [];
loading = true;
showDeleted = false;
searchTerm = '';
message = '';
isError = false;
ngOnInit() {
this.loadAPIs();
}
loadAPIs() {
this.loading = true;
this.apiService.getAPIs(this.showDeleted).subscribe({
next: (apis) => {
this.apis = apis;
this.filterAPIs();
this.loading = false;
},
error: (err) => {
this.showMessage('Failed to load APIs', true);
this.loading = false;
}
});
}
filterAPIs() {
const term = this.searchTerm.toLowerCase();
this.filteredAPIs = this.apis.filter(api =>
api.name.toLowerCase().includes(term) ||
api.url.toLowerCase().includes(term)
);
}
createAPI() {
// TODO: Open create dialog
console.log('Create API - not implemented yet');
}
editAPI(api: API) {
// TODO: Open edit dialog
console.log('Edit API:', api.name);
}
testAPI(api: API) {
// TODO: Test API
console.log('Test API:', api.name);
}
duplicateAPI(api: API) {
// TODO: Duplicate API
console.log('Duplicate API:', api.name);
}
deleteAPI(api: API) {
if (confirm(`Are you sure you want to delete "${api.name}"?`)) {
this.apiService.deleteAPI(api.name).subscribe({
next: () => {
this.showMessage(`API "${api.name}" deleted successfully`, false);
this.loadAPIs();
},
error: (err) => {
this.showMessage(err.error?.detail || 'Failed to delete API', true);
}
});
}
}
private showMessage(message: string, isError: boolean) {
this.message = message;
this.isError = isError;
setTimeout(() => {
this.message = '';
}, 5000);
}
}