Release 1.0.0 - Production ready

- Fixed AdminController export/import .env endpoints (moved from ConfigUpdateRequest class)
- Added ArtistId and AlbumId to integration test fixtures
- All 225 tests passing
- Version set to 1.0.0 (semantic versioning)
- MusicBrainz service ready for future ISRC-based matching (1.1.0)
- Import/export handles full .env configuration with timestamped backups
This commit is contained in:
2026-02-04 16:33:58 -05:00
parent 39f6893741
commit 7938871556
3 changed files with 517 additions and 0 deletions

View File

@@ -734,6 +734,27 @@
</div>
</div>
<div class="card">
<h2>MusicBrainz Settings</h2>
<div class="config-section">
<div class="config-item">
<span class="label">Enabled</span>
<span class="value" id="config-musicbrainz-enabled">-</span>
<button onclick="openEditSetting('MUSICBRAINZ_ENABLED', 'MusicBrainz Enabled', 'select', '', ['true', 'false'])">Edit</button>
</div>
<div class="config-item">
<span class="label">Username</span>
<span class="value" id="config-musicbrainz-username">-</span>
<button onclick="openEditSetting('MUSICBRAINZ_USERNAME', 'MusicBrainz Username', 'text', 'Your MusicBrainz username')">Update</button>
</div>
<div class="config-item">
<span class="label">Password</span>
<span class="value" id="config-musicbrainz-password">-</span>
<button onclick="openEditSetting('MUSICBRAINZ_PASSWORD', 'MusicBrainz Password', 'password', 'Your MusicBrainz password')">Update</button>
</div>
</div>
</div>
<div class="card">
<h2>Qobuz Settings</h2>
<div class="config-section">
@@ -792,6 +813,18 @@
</div>
</div>
<div class="card">
<h2>Configuration Backup</h2>
<p style="color: var(--text-secondary); margin-bottom: 16px;">
Export your .env configuration for backup or import a previously saved configuration.
</p>
<div style="display: flex; gap: 12px; flex-wrap: wrap;">
<button onclick="exportEnv()">📥 Export .env</button>
<button onclick="document.getElementById('import-env-input').click()">📤 Import .env</button>
<input type="file" id="import-env-input" accept=".env" style="display:none" onchange="importEnv(event)">
</div>
</div>
<div class="card" style="background: rgba(248, 81, 73, 0.1); border-color: var(--error);">
<h2 style="color: var(--error);">Danger Zone</h2>
<p style="color: var(--text-secondary); margin-bottom: 16px;">
@@ -1223,6 +1256,11 @@
// SquidWTF settings
document.getElementById('config-squid-quality').textContent = data.squidWtf.quality;
// MusicBrainz settings
document.getElementById('config-musicbrainz-enabled').textContent = data.musicBrainz.enabled ? 'Yes' : 'No';
document.getElementById('config-musicbrainz-username').textContent = data.musicBrainz.username || '(not set)';
document.getElementById('config-musicbrainz-password').textContent = data.musicBrainz.password || '(not set)';
// Qobuz settings
document.getElementById('config-qobuz-token').textContent = data.qobuz.userAuthToken || '(not set)';
document.getElementById('config-qobuz-quality').textContent = data.qobuz.quality || 'FLAC';
@@ -1487,6 +1525,61 @@
}
}
async function exportEnv() {
try {
const res = await fetch('/api/admin/export-env');
if (!res.ok) {
throw new Error('Export failed');
}
const blob = await res.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `.env.backup.${new Date().toISOString().split('T')[0]}`;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
showToast('.env file exported successfully', 'success');
} catch (error) {
showToast('Failed to export .env file', 'error');
}
}
async function importEnv(event) {
const file = event.target.files[0];
if (!file) return;
if (!confirm('Import this .env file? This will replace your current configuration.\n\nA backup will be created automatically.\n\nYou will need to restart the container for changes to take effect.')) {
event.target.value = '';
return;
}
try {
const formData = new FormData();
formData.append('file', file);
const res = await fetch('/api/admin/import-env', {
method: 'POST',
body: formData
});
const data = await res.json();
if (res.ok) {
showToast(data.message, 'success');
} else {
showToast(data.error || 'Failed to import .env file', 'error');
}
} catch (error) {
showToast('Failed to import .env file', 'error');
}
event.target.value = '';
}
async function restartContainer() {
if (!confirm('Restart the container to apply configuration changes?\n\nThe dashboard will be temporarily unavailable.')) {
return;