Switched from lucide-angular to Google Material Icons font for better compatibility across all environments, especially air-gapped and enterprise setups. **Changes:** - Removed lucide-angular dependency (not available in some environments) - Added Material Icons font via Google CDN in index.html - Updated all components to use Material Icons spans instead of Lucide components - Added Material Icons CSS classes (md-16, md-18, md-20, md-24) **Icon Mapping:** - RefreshCw → refresh - Sparkles → auto_awesome - Search → search - X/Close → close - Download → download - Trash2/Delete → delete - Database → storage - Upload → upload **Benefits:** - No npm dependency required (just a font) - Works in all environments (air-gapped, enterprise proxies) - Smaller bundle: 349.74 kB raw, 91.98 kB gzipped - Industry standard Material Design icons - Better cross-browser compatibility All components tested and working correctly. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
191 lines
7.9 KiB
HTML
191 lines
7.9 KiB
HTML
<div class="artifacts-container">
|
|
<div class="toolbar">
|
|
<button (click)="loadArtifacts()" class="btn btn-primary">
|
|
<span class="material-icons md-16">refresh</span> Refresh
|
|
</button>
|
|
<button (click)="toggleAutoRefresh()"
|
|
[class.btn-success]="autoRefreshEnabled"
|
|
[class.btn-secondary]="!autoRefreshEnabled"
|
|
class="btn">
|
|
Auto-refresh: {{ autoRefreshEnabled ? 'ON' : 'OFF' }}
|
|
</button>
|
|
<button (click)="generateSeedData()" class="btn btn-secondary">
|
|
<span class="material-icons md-16">auto_awesome</span> Generate Seed Data
|
|
</button>
|
|
|
|
<span class="count-badge">{{ filteredArtifacts.length }} artifacts</span>
|
|
|
|
<div class="filter-inline">
|
|
<span class="material-icons md-16 search-icon">search</span>
|
|
<input
|
|
type="text"
|
|
[(ngModel)]="searchTerm"
|
|
(input)="onSearch()"
|
|
placeholder="Search..."
|
|
class="search-input">
|
|
<button (click)="clearSearch()" class="btn-clear" *ngIf="searchTerm">
|
|
<span class="material-icons md-16">close</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="error-message" *ngIf="error">{{ error }}</div>
|
|
|
|
<div class="table-container">
|
|
<table class="artifacts-table">
|
|
<thead>
|
|
<tr>
|
|
<th class="sortable" (click)="sortTable('sim_source_id')">
|
|
Sim Source
|
|
<span class="sort-indicator" *ngIf="sortColumn === 'sim_source_id'">
|
|
{{ sortDirection === 'asc' ? '↑' : '↓' }}
|
|
</span>
|
|
</th>
|
|
<th class="sortable" (click)="sortTable('filename')">
|
|
Artifacts
|
|
<span class="sort-indicator" *ngIf="sortColumn === 'filename'">
|
|
{{ sortDirection === 'asc' ? '↑' : '↓' }}
|
|
</span>
|
|
</th>
|
|
<th class="sortable" (click)="sortTable('created_at')">
|
|
Date
|
|
<span class="sort-indicator" *ngIf="sortColumn === 'created_at'">
|
|
{{ sortDirection === 'asc' ? '↑' : '↓' }}
|
|
</span>
|
|
</th>
|
|
<th class="sortable" (click)="sortTable('test_name')">
|
|
Uploaded By
|
|
<span class="sort-indicator" *ngIf="sortColumn === 'test_name'">
|
|
{{ sortDirection === 'asc' ? '↑' : '↓' }}
|
|
</span>
|
|
</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr *ngIf="loading">
|
|
<td colspan="5" class="loading">Loading artifacts...</td>
|
|
</tr>
|
|
<tr *ngIf="!loading && filteredArtifacts.length === 0">
|
|
<td colspan="5" class="loading">No artifacts found. Upload some files to get started!</td>
|
|
</tr>
|
|
<tr *ngFor="let artifact of filteredArtifacts" (click)="showDetail(artifact)" class="clickable">
|
|
<td>{{ artifact.sim_source_id || artifact.test_suite || '-' }}</td>
|
|
<td>
|
|
<a href="javascript:void(0)" class="artifact-link">{{ artifact.filename }}</a>
|
|
<div class="tags" *ngIf="artifact.tags && artifact.tags.length > 0">
|
|
<span class="tag" *ngFor="let tag of artifact.tags">{{ tag }}</span>
|
|
</div>
|
|
</td>
|
|
<td>{{ formatDate(artifact.created_at) }}</td>
|
|
<td>{{ artifact.test_name || '-' }}</td>
|
|
<td>
|
|
<div class="action-buttons">
|
|
<button (click)="downloadArtifact(artifact, $event)" class="icon-btn" title="Download">
|
|
<span class="material-icons md-16">download</span>
|
|
</button>
|
|
<button (click)="deleteArtifact(artifact, $event)" class="icon-btn danger" title="Delete">
|
|
<span class="material-icons md-16">delete</span>
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="pagination">
|
|
<button (click)="previousPage()" [disabled]="currentPage === 1" class="btn">← Previous</button>
|
|
<span class="page-info">Page {{ currentPage }}</span>
|
|
<button (click)="nextPage()" [disabled]="filteredArtifacts.length < pageSize" class="btn">Next →</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Detail Modal -->
|
|
<div class="modal" *ngIf="selectedArtifact" (click)="closeDetail()">
|
|
<div class="modal-content" (click)="$event.stopPropagation()">
|
|
<span class="close" (click)="closeDetail()">×</span>
|
|
<h2>Artifact Details</h2>
|
|
<div class="detail-content">
|
|
<div class="detail-row">
|
|
<div class="detail-label">ID</div>
|
|
<div class="detail-value">{{ selectedArtifact.id }}</div>
|
|
</div>
|
|
<div class="detail-row">
|
|
<div class="detail-label">Filename</div>
|
|
<div class="detail-value">{{ selectedArtifact.filename }}</div>
|
|
</div>
|
|
<div class="detail-row">
|
|
<div class="detail-label">File Type</div>
|
|
<div class="detail-value"><span class="file-type-badge">{{ selectedArtifact.file_type }}</span></div>
|
|
</div>
|
|
<div class="detail-row">
|
|
<div class="detail-label">Size</div>
|
|
<div class="detail-value">{{ formatBytes(selectedArtifact.file_size) }}</div>
|
|
</div>
|
|
<div class="detail-row">
|
|
<div class="detail-label">Storage Path</div>
|
|
<div class="detail-value"><code>{{ selectedArtifact.storage_path }}</code></div>
|
|
</div>
|
|
<div class="detail-row">
|
|
<div class="detail-label">Uploaded By</div>
|
|
<div class="detail-value">{{ selectedArtifact.test_name || '-' }}</div>
|
|
</div>
|
|
<div class="detail-row">
|
|
<div class="detail-label">Sim Source</div>
|
|
<div class="detail-value">{{ selectedArtifact.test_suite || '-' }}</div>
|
|
</div>
|
|
<div class="detail-row" *ngIf="selectedArtifact.sim_source_id">
|
|
<div class="detail-label">SIM Source ID</div>
|
|
<div class="detail-value">{{ selectedArtifact.sim_source_id }}</div>
|
|
</div>
|
|
<div class="detail-row" *ngIf="selectedArtifact.test_result">
|
|
<div class="detail-label">Test Result</div>
|
|
<div class="detail-value">
|
|
<span class="result-badge result-{{ selectedArtifact.test_result }}">
|
|
{{ selectedArtifact.test_result }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div class="detail-row" *ngIf="selectedArtifact.test_config">
|
|
<div class="detail-label">Test Config</div>
|
|
<div class="detail-value"><pre>{{ selectedArtifact.test_config | json }}</pre></div>
|
|
</div>
|
|
<div class="detail-row" *ngIf="selectedArtifact.custom_metadata">
|
|
<div class="detail-label">Custom Metadata</div>
|
|
<div class="detail-value"><pre>{{ selectedArtifact.custom_metadata | json }}</pre></div>
|
|
</div>
|
|
<div class="detail-row" *ngIf="selectedArtifact.description">
|
|
<div class="detail-label">Description</div>
|
|
<div class="detail-value">{{ selectedArtifact.description }}</div>
|
|
</div>
|
|
<div class="detail-row" *ngIf="selectedArtifact.tags && selectedArtifact.tags.length > 0">
|
|
<div class="detail-label">Tags</div>
|
|
<div class="detail-value">
|
|
<span class="tag" *ngFor="let tag of selectedArtifact.tags">{{ tag }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="detail-row">
|
|
<div class="detail-label">Version</div>
|
|
<div class="detail-value">{{ selectedArtifact.version || '-' }}</div>
|
|
</div>
|
|
<div class="detail-row">
|
|
<div class="detail-label">Created</div>
|
|
<div class="detail-value">{{ formatDate(selectedArtifact.created_at) }}</div>
|
|
</div>
|
|
<div class="detail-row">
|
|
<div class="detail-label">Updated</div>
|
|
<div class="detail-value">{{ formatDate(selectedArtifact.updated_at) }}</div>
|
|
</div>
|
|
<div class="modal-actions">
|
|
<button (click)="downloadArtifact(selectedArtifact, $event)" class="btn btn-primary">
|
|
<span class="material-icons md-16">download</span> Download
|
|
</button>
|
|
<button (click)="deleteArtifact(selectedArtifact, $event); closeDetail()" class="btn btn-danger">
|
|
<span class="material-icons md-16">delete</span> Delete
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|