Add transparent PyPI proxy and improve upstream sources UI

- Implement PEP 503 Simple API endpoints for pip compatibility:
  - GET /pypi/simple/ - package index
  - GET /pypi/simple/{package}/ - version list with rewritten links
  - GET /pypi/simple/{package}/{filename} - download with auto-caching

- Improve upstream sources table UI:
  - Center text under column headers
  - Remove separate Source column, show ENV badge inline with name
  - Make Test/Edit buttons more prominent with secondary button style
This commit is contained in:
Mondo Diaz
2026-01-29 15:30:57 -06:00
parent e8cf2462b7
commit a9de32d922
6 changed files with 673 additions and 16 deletions

View File

@@ -65,7 +65,7 @@
.sources-table th,
.sources-table td {
padding: 0.75rem 1rem;
text-align: left;
text-align: center;
border-bottom: 1px solid var(--border-color);
}
@@ -91,6 +91,11 @@
white-space: nowrap;
}
/* Name column should be left-aligned */
.sources-table td:first-child {
text-align: left;
}
.url-cell {
font-family: monospace;
font-size: 0.9rem;
@@ -98,6 +103,7 @@
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-align: left;
}
/* Badges */
@@ -243,10 +249,22 @@
}
.btn-sm {
padding: 0.25rem 0.5rem;
padding: 0.25rem 0.75rem;
font-size: 0.8rem;
}
.btn-secondary {
background-color: var(--bg-tertiary);
border-color: var(--border-color);
color: var(--text-primary);
font-weight: 500;
}
.btn-secondary:hover {
background-color: var(--bg-secondary);
border-color: var(--text-secondary);
}
.empty-message {
color: var(--text-secondary);
font-style: italic;

View File

@@ -272,8 +272,7 @@ function AdminCachePage() {
<th>URL</th>
<th>Priority</th>
<th>Status</th>
<th>Source</th>
<th></th>
<th>Test</th>
<th>Actions</th>
</tr>
</thead>
@@ -282,24 +281,18 @@ function AdminCachePage() {
<tr key={source.id} className={source.enabled ? '' : 'disabled-row'}>
<td>
<span className="source-name">{source.name}</span>
{source.source === 'env' && (
<span className="env-badge" title="Defined via environment variable">ENV</span>
)}
</td>
<td>{source.source_type}</td>
<td className="url-cell">{source.url}</td>
<td className="url-cell" title={source.url}>{source.url}</td>
<td>{source.priority}</td>
<td>
<span className={`status-badge ${source.enabled ? 'enabled' : 'disabled'}`}>
{source.enabled ? 'Enabled' : 'Disabled'}
</span>
</td>
<td>
{source.source === 'env' ? (
<span className="env-badge" title="Defined via environment variable">
ENV
</span>
) : (
'Database'
)}
</td>
<td className="test-cell">
{testingId === source.id ? (
<span className="test-dot testing" title="Testing..."></span>
@@ -317,14 +310,14 @@ function AdminCachePage() {
</td>
<td className="actions-cell">
<button
className="btn btn-sm"
className="btn btn-sm btn-secondary"
onClick={() => handleTest(source)}
disabled={testingId === source.id}
>
Test
</button>
{source.source !== 'env' && (
<button className="btn btn-sm" onClick={() => openEditForm(source)}>
<button className="btn btn-sm btn-secondary" onClick={() => openEditForm(source)}>
Edit
</button>
)}