Simplify cache management UI and improve test status display (#107)
This commit is contained in:
@@ -7,10 +7,8 @@ import {
|
||||
updateUpstreamSource,
|
||||
deleteUpstreamSource,
|
||||
testUpstreamSource,
|
||||
getCacheSettings,
|
||||
updateCacheSettings,
|
||||
} from '../api';
|
||||
import { UpstreamSource, CacheSettings, SourceType, AuthType } from '../types';
|
||||
import { UpstreamSource, SourceType, AuthType } from '../types';
|
||||
import './AdminCachePage.css';
|
||||
|
||||
const SOURCE_TYPES: SourceType[] = ['npm', 'pypi', 'maven', 'docker', 'helm', 'nuget', 'deb', 'rpm', 'generic'];
|
||||
@@ -25,11 +23,6 @@ function AdminCachePage() {
|
||||
const [loadingSources, setLoadingSources] = useState(true);
|
||||
const [sourcesError, setSourcesError] = useState<string | null>(null);
|
||||
|
||||
// Cache settings state
|
||||
const [settings, setSettings] = useState<CacheSettings | null>(null);
|
||||
const [loadingSettings, setLoadingSettings] = useState(true);
|
||||
const [settingsError, setSettingsError] = useState<string | null>(null);
|
||||
|
||||
// Create/Edit form state
|
||||
const [showForm, setShowForm] = useState(false);
|
||||
const [editingSource, setEditingSource] = useState<UpstreamSource | null>(null);
|
||||
@@ -53,9 +46,6 @@ function AdminCachePage() {
|
||||
// Delete confirmation state
|
||||
const [deletingId, setDeletingId] = useState<string | null>(null);
|
||||
|
||||
// Settings update state
|
||||
const [updatingSettings, setUpdatingSettings] = useState(false);
|
||||
|
||||
// Success message
|
||||
const [successMessage, setSuccessMessage] = useState<string | null>(null);
|
||||
|
||||
@@ -72,7 +62,6 @@ function AdminCachePage() {
|
||||
useEffect(() => {
|
||||
if (user && user.is_admin) {
|
||||
loadSources();
|
||||
loadSettings();
|
||||
}
|
||||
}, [user]);
|
||||
|
||||
@@ -96,19 +85,6 @@ function AdminCachePage() {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadSettings() {
|
||||
setLoadingSettings(true);
|
||||
setSettingsError(null);
|
||||
try {
|
||||
const data = await getCacheSettings();
|
||||
setSettings(data);
|
||||
} catch (err) {
|
||||
setSettingsError(err instanceof Error ? err.message : 'Failed to load settings');
|
||||
} finally {
|
||||
setLoadingSettings(false);
|
||||
}
|
||||
}
|
||||
|
||||
function openCreateForm() {
|
||||
setEditingSource(null);
|
||||
setFormData({
|
||||
@@ -255,30 +231,6 @@ function AdminCachePage() {
|
||||
setShowErrorModal(true);
|
||||
}
|
||||
|
||||
async function handleSettingsToggle(field: 'auto_create_system_projects') {
|
||||
if (!settings) return;
|
||||
|
||||
// Check if env override is active
|
||||
const isOverridden = field === 'auto_create_system_projects' && settings.auto_create_system_projects_env_override !== null;
|
||||
|
||||
if (isOverridden) {
|
||||
alert('This setting is overridden by an environment variable and cannot be changed via UI.');
|
||||
return;
|
||||
}
|
||||
|
||||
setUpdatingSettings(true);
|
||||
try {
|
||||
const update = { [field]: !settings[field] };
|
||||
const newSettings = await updateCacheSettings(update);
|
||||
setSettings(newSettings);
|
||||
setSuccessMessage(`Setting "${field}" updated`);
|
||||
} catch (err) {
|
||||
setSettingsError(err instanceof Error ? err.message : 'Failed to update settings');
|
||||
} finally {
|
||||
setUpdatingSettings(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (authLoading) {
|
||||
return <div className="admin-cache-page">Loading...</div>;
|
||||
}
|
||||
@@ -293,49 +245,13 @@ function AdminCachePage() {
|
||||
|
||||
return (
|
||||
<div className="admin-cache-page">
|
||||
<h1>Cache Management</h1>
|
||||
<h1>Upstream Sources</h1>
|
||||
|
||||
{successMessage && <div className="success-message">{successMessage}</div>}
|
||||
|
||||
{/* Cache Settings Section */}
|
||||
<section className="settings-section">
|
||||
<h2>Global Settings</h2>
|
||||
{loadingSettings ? (
|
||||
<p>Loading settings...</p>
|
||||
) : settingsError ? (
|
||||
<div className="error-message">{settingsError}</div>
|
||||
) : settings ? (
|
||||
<div className="settings-grid">
|
||||
<div className="setting-item">
|
||||
<label className="toggle-label">
|
||||
<span className="setting-name">
|
||||
Auto-create System Projects
|
||||
{settings.auto_create_system_projects_env_override !== null && (
|
||||
<span className="env-badge" title="Overridden by environment variable">
|
||||
ENV
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
<span className="setting-description">
|
||||
Automatically create system projects (_npm, _pypi, etc.) on first cache request.
|
||||
</span>
|
||||
</label>
|
||||
<button
|
||||
className={`toggle-button ${settings.auto_create_system_projects ? 'on' : 'off'}`}
|
||||
onClick={() => handleSettingsToggle('auto_create_system_projects')}
|
||||
disabled={updatingSettings || settings.auto_create_system_projects_env_override !== null}
|
||||
>
|
||||
{settings.auto_create_system_projects ? 'Enabled' : 'Disabled'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</section>
|
||||
|
||||
{/* Upstream Sources Section */}
|
||||
<section className="sources-section">
|
||||
<div className="section-header">
|
||||
<h2>Upstream Sources</h2>
|
||||
<button className="btn btn-primary" onClick={openCreateForm}>
|
||||
Add Source
|
||||
</button>
|
||||
@@ -357,7 +273,7 @@ function AdminCachePage() {
|
||||
<th>Priority</th>
|
||||
<th>Status</th>
|
||||
<th>Source</th>
|
||||
<th>Test</th>
|
||||
<th></th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -384,26 +300,20 @@ function AdminCachePage() {
|
||||
'Database'
|
||||
)}
|
||||
</td>
|
||||
<td>
|
||||
<td className="test-cell">
|
||||
{testingId === source.id ? (
|
||||
<span className="test-result testing">Testing...</span>
|
||||
<span className="test-dot testing" title="Testing...">●</span>
|
||||
) : testResults[source.id] ? (
|
||||
testResults[source.id].success ? (
|
||||
<span className="test-result success" title={testResults[source.id].message}>
|
||||
OK
|
||||
</span>
|
||||
<span className="test-dot success" title={testResults[source.id].message}>●</span>
|
||||
) : (
|
||||
<span
|
||||
className="test-result failure"
|
||||
title="Click to see details"
|
||||
className="test-dot failure"
|
||||
title="Click to see error"
|
||||
onClick={() => showError(source.name, testResults[source.id].message)}
|
||||
>
|
||||
Error
|
||||
</span>
|
||||
>●</span>
|
||||
)
|
||||
) : (
|
||||
<span className="test-result" style={{ opacity: 0.5 }}>—</span>
|
||||
)}
|
||||
) : null}
|
||||
</td>
|
||||
<td className="actions-cell">
|
||||
<button
|
||||
@@ -414,18 +324,9 @@ function AdminCachePage() {
|
||||
Test
|
||||
</button>
|
||||
{source.source !== 'env' && (
|
||||
<>
|
||||
<button className="btn btn-sm" onClick={() => openEditForm(source)}>
|
||||
Edit
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-sm btn-danger"
|
||||
onClick={() => handleDelete(source)}
|
||||
disabled={deletingId === source.id}
|
||||
>
|
||||
{deletingId === source.id ? 'Deleting...' : 'Delete'}
|
||||
</button>
|
||||
</>
|
||||
<button className="btn btn-sm" onClick={() => openEditForm(source)}>
|
||||
Edit
|
||||
</button>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -561,12 +462,27 @@ function AdminCachePage() {
|
||||
)}
|
||||
|
||||
<div className="form-actions">
|
||||
<button type="button" className="btn" onClick={() => setShowForm(false)}>
|
||||
Cancel
|
||||
</button>
|
||||
<button type="submit" className="btn btn-primary" disabled={isSaving}>
|
||||
{isSaving ? 'Saving...' : editingSource ? 'Update' : 'Create'}
|
||||
</button>
|
||||
{editingSource && (
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-danger"
|
||||
onClick={() => {
|
||||
handleDelete(editingSource);
|
||||
setShowForm(false);
|
||||
}}
|
||||
disabled={deletingId === editingSource.id}
|
||||
>
|
||||
{deletingId === editingSource.id ? 'Deleting...' : 'Delete'}
|
||||
</button>
|
||||
)}
|
||||
<div className="form-actions-right">
|
||||
<button type="button" className="btn" onClick={() => setShowForm(false)}>
|
||||
Cancel
|
||||
</button>
|
||||
<button type="submit" className="btn btn-primary" disabled={isSaving}>
|
||||
{isSaving ? 'Saving...' : editingSource ? 'Update' : 'Create'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user