import { Component, inject, OnInit } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { MatDialog, MatDialogModule } from '@angular/material/dialog'; import { MatTableModule } from '@angular/material/table'; import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatProgressBarModule } from '@angular/material/progress-bar'; import { MatChipsModule } from '@angular/material/chips'; import { MatMenuModule } from '@angular/material/menu'; import { MatTooltipModule } from '@angular/material/tooltip'; import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar'; import { MatDividerModule } from '@angular/material/divider'; import { ApiService, API } from '../../services/api.service'; @Component({ selector: 'app-apis', standalone: true, imports: [ CommonModule, FormsModule, MatDialogModule, MatTableModule, MatButtonModule, MatIconModule, MatFormFieldModule, MatInputModule, MatCheckboxModule, MatProgressBarModule, MatChipsModule, MatMenuModule, MatTooltipModule, MatSnackBarModule, MatDividerModule ], template: `

API Definitions

Search APIs search Display Deleted
@if (!loading && filteredAPIs.length === 0) {
api

No APIs found.

} @else if (!loading) {
Name {{ api.name }} URL {{ api.url }} Method {{ api.method }} Timeout {{ api.timeout_seconds }}s Auth {{ api.auth?.enabled ? 'lock' : 'lock_open' }} Deleted @if (api.deleted) { delete } Actions @if (!api.deleted) { }
}
`, styles: [` .apis-container { .toolbar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; flex-wrap: wrap; gap: 16px; h2 { margin: 0; font-size: 24px; } .toolbar-actions { display: flex; gap: 16px; align-items: center; flex-wrap: wrap; .search-field { width: 250px; } } } .empty-state { text-align: center; padding: 60px 20px; background-color: white; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); mat-icon { font-size: 64px; width: 64px; height: 64px; color: #e0e0e0; margin-bottom: 16px; } p { margin-bottom: 24px; color: #666; font-size: 16px; } } .apis-table { width: 100%; background: white; box-shadow: 0 2px 4px rgba(0,0,0,0.1); .url-cell { max-width: 300px; span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; } } mat-chip { font-size: 12px; min-height: 24px; padding: 4px 12px; &.method-get { background-color: #4caf50; color: white; } &.method-post { background-color: #2196f3; color: white; } &.method-put { background-color: #ff9800; color: white; } &.method-patch { background-color: #9c27b0; color: white; } &.method-delete { background-color: #f44336; color: white; } } tr.mat-mdc-row { cursor: pointer; transition: background-color 0.2s; &:hover { background-color: #f5f5f5; } &.deleted-row { opacity: 0.6; background-color: #fafafa; } } } } ::ng-deep { .mat-mdc-form-field { font-size: 14px; } .mat-mdc-checkbox { .mdc-form-field { font-size: 14px; } } } `] }) export class ApisComponent implements OnInit { private apiService = inject(ApiService); private dialog = inject(MatDialog); private snackBar = inject(MatSnackBar); apis: API[] = []; filteredAPIs: API[] = []; loading = true; showDeleted = false; searchTerm = ''; displayedColumns: string[] = ['name', 'url', 'method', 'timeout', 'auth', 'deleted', 'actions']; 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.snackBar.open('Failed to load APIs', 'Close', { duration: 5000, panelClass: 'error-snackbar' }); 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) ); } async createAPI() { const { default: ApiEditDialogComponent } = await import('../../dialogs/api-edit-dialog/api-edit-dialog.component'); const dialogRef = this.dialog.open(ApiEditDialogComponent, { width: '800px', data: { mode: 'create' } }); dialogRef.afterClosed().subscribe((result: any) => { if (result) { this.loadAPIs(); } }); } async editAPI(api: API) { const { default: ApiEditDialogComponent } = await import('../../dialogs/api-edit-dialog/api-edit-dialog.component'); const dialogRef = this.dialog.open(ApiEditDialogComponent, { width: '800px', data: { mode: 'edit', api: { ...api } } }); dialogRef.afterClosed().subscribe((result: any) => { if (result) { this.loadAPIs(); } }); } async testAPI(api: API) { const { default: ApiEditDialogComponent } = await import('../../dialogs/api-edit-dialog/api-edit-dialog.component'); const dialogRef = this.dialog.open(ApiEditDialogComponent, { width: '800px', data: { mode: 'test', // Test modunda açıyoruz api: { ...api }, activeTab: 4 // Test tab'ını aktif yap (0-based index) } }); dialogRef.afterClosed().subscribe((result: any) => { if (result) { this.loadAPIs(); } }); } async duplicateAPI(api: API) { const { default: ApiEditDialogComponent } = await import('../../dialogs/api-edit-dialog/api-edit-dialog.component'); const dialogRef = this.dialog.open(ApiEditDialogComponent, { width: '800px', data: { mode: 'duplicate', api: { ...api } } }); dialogRef.afterClosed().subscribe((result: any) => { if (result) { this.loadAPIs(); } }); } async deleteAPI(api: API) { const { default: ConfirmDialogComponent } = await import('../../dialogs/confirm-dialog/confirm-dialog.component'); const dialogRef = this.dialog.open(ConfirmDialogComponent, { width: '400px', data: { title: 'Delete API', message: `Are you sure you want to delete "${api.name}"?`, confirmText: 'Delete', confirmColor: 'warn' } }); dialogRef.afterClosed().subscribe((confirmed) => { if (confirmed) { this.apiService.deleteAPI(api.name).subscribe({ next: () => { this.snackBar.open(`API "${api.name}" deleted successfully`, 'Close', { duration: 3000 }); this.loadAPIs(); }, error: (err) => { this.snackBar.open(err.error?.detail || 'Failed to delete API', 'Close', { duration: 5000, panelClass: 'error-snackbar' }); } }); } }); } importAPIs() { const input = document.createElement('input'); input.type = 'file'; input.accept = '.json'; input.onchange = async (event: any) => { const file = event.target.files[0]; if (!file) return; try { const text = await file.text(); const apis = JSON.parse(text); if (!Array.isArray(apis)) { this.snackBar.open('Invalid file format. Expected an array of APIs.', 'Close', { duration: 5000, panelClass: 'error-snackbar' }); return; } let imported = 0; let failed = 0; for (const api of apis) { try { await this.apiService.createAPI(api).toPromise(); imported++; } catch (err: any) { failed++; console.error(`Failed to import API ${api.name}:`, err); } } this.snackBar.open(`Imported ${imported} APIs. ${failed} failed.`, 'Close', { duration: 5000 }); this.loadAPIs(); } catch (error) { this.snackBar.open('Failed to read file', 'Close', { duration: 5000, panelClass: 'error-snackbar' }); } }; input.click(); } exportAPIs() { const selectedAPIs = this.filteredAPIs.filter(api => !api.deleted); if (selectedAPIs.length === 0) { this.snackBar.open('No APIs to export', 'Close', { duration: 3000 }); return; } const data = JSON.stringify(selectedAPIs, null, 2); const blob = new Blob([data], { type: 'application/json' }); const url = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = `apis_export_${new Date().getTime()}.json`; link.click(); window.URL.revokeObjectURL(url); this.snackBar.open(`Exported ${selectedAPIs.length} APIs`, 'Close', { duration: 3000 }); } }