Wire up automatic first-run detection for setup wizard
Wizard now shows automatically on fresh installs. Detection uses a server-side flag (setup.completed) plus download_source.mode as a fallback for existing users who configured settings before the wizard existed. Config.json template defaults no longer fool the check. Script load order fixed — setup-wizard.js loads before script.js so openSetupWizard exists when DOMContentLoaded fires. Both finish and skip paths set the server flag and localStorage, then continue app initialization via callback.
This commit is contained in:
parent
08de91685d
commit
eff22f55d7
4 changed files with 71 additions and 23 deletions
|
|
@ -6125,18 +6125,22 @@ def get_mirrored_playlists_list():
|
|||
@app.route('/api/setup/status', methods=['GET'])
|
||||
def setup_status_endpoint():
|
||||
"""Check if first-run setup has been completed."""
|
||||
# Consider setup incomplete if no slskd URL and no download source configured
|
||||
slskd_url = config_manager.get('soulseek.slskd_url', '')
|
||||
# The setup wizard sets this flag when completed. download_source.mode is only
|
||||
# set by user action (wizard or settings page), never by config.json defaults.
|
||||
setup_done = config_manager.get('setup.completed', False)
|
||||
download_mode = config_manager.get('download_source.mode', '')
|
||||
transfer_path = config_manager.get('soulseek.transfer_path', '')
|
||||
has_any_config = bool(slskd_url) or bool(download_mode) or bool(transfer_path)
|
||||
# Either the explicit flag or a user-configured download source means setup is done
|
||||
has_user_config = bool(setup_done) or bool(download_mode)
|
||||
return jsonify({
|
||||
"setup_complete": has_any_config,
|
||||
"has_download_source": bool(download_mode),
|
||||
"has_slskd": bool(slskd_url),
|
||||
"has_transfer_path": bool(transfer_path),
|
||||
"setup_complete": has_user_config,
|
||||
})
|
||||
|
||||
@app.route('/api/setup/complete', methods=['POST'])
|
||||
def setup_complete_endpoint():
|
||||
"""Mark first-run setup as completed."""
|
||||
config_manager.set('setup.completed', True)
|
||||
return jsonify({"success": True})
|
||||
|
||||
@app.route('/api/test-connection', methods=['POST'])
|
||||
def test_connection_endpoint():
|
||||
data = request.get_json()
|
||||
|
|
|
|||
|
|
@ -7351,6 +7351,7 @@
|
|||
|
||||
<script src="{{ url_for('static', filename='vendor/socket.io.min.js') }}"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.min.js"></script>
|
||||
<script src="{{ url_for('static', filename='setup-wizard.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='script.js') }}"></script>
|
||||
<!-- Notification bell + floating helper toggle — always accessible above modals -->
|
||||
<!-- Global Search Bar — Spotlight-style search from anywhere -->
|
||||
|
|
@ -7376,7 +7377,6 @@
|
|||
<script src="{{ url_for('static', filename='helper.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='particles.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='worker-orbs.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='setup-wizard.js') }}"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -2616,6 +2616,36 @@ async function checkAdminPinRequired() {
|
|||
document.addEventListener('DOMContentLoaded', async function () {
|
||||
console.log('SoulSync WebUI initializing...');
|
||||
|
||||
// Check if first-run setup wizard should be shown
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const forceSetup = params.get('setup') === '1';
|
||||
let showWizard = forceSetup;
|
||||
|
||||
if (!forceSetup) {
|
||||
try {
|
||||
const setupResp = await fetch('/api/setup/status');
|
||||
const setupData = await setupResp.json();
|
||||
if (!setupData.setup_complete) {
|
||||
showWizard = true;
|
||||
localStorage.removeItem('soulsync_setup_complete');
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Setup status check failed, continuing normal init:', e);
|
||||
}
|
||||
}
|
||||
|
||||
if (showWizard && typeof openSetupWizard === 'function') {
|
||||
window._onSetupWizardComplete = function () {
|
||||
_continueAppInit();
|
||||
};
|
||||
openSetupWizard();
|
||||
return; // Defer init until wizard closes
|
||||
}
|
||||
|
||||
_continueAppInit();
|
||||
});
|
||||
|
||||
async function _continueAppInit() {
|
||||
// Initialize profile management UI handlers
|
||||
initProfileManagement();
|
||||
|
||||
|
|
@ -2627,7 +2657,7 @@ document.addEventListener('DOMContentLoaded', async function () {
|
|||
}
|
||||
|
||||
initApp();
|
||||
});
|
||||
}
|
||||
|
||||
function initApp() {
|
||||
// Initialize components
|
||||
|
|
|
|||
|
|
@ -62,6 +62,16 @@ function openSetupWizard() {
|
|||
function closeSetupWizard() {
|
||||
const overlay = document.getElementById('setup-wizard-overlay');
|
||||
if (overlay) overlay.style.display = 'none';
|
||||
|
||||
// Mark as complete so it doesn't show again (server + client)
|
||||
localStorage.setItem('soulsync_setup_complete', 'true');
|
||||
fetch('/api/setup/complete', { method: 'POST' }).catch(() => {});
|
||||
|
||||
// Continue app initialization if wizard was shown on first run
|
||||
if (typeof window._onSetupWizardComplete === 'function') {
|
||||
window._onSetupWizardComplete();
|
||||
window._onSetupWizardComplete = null;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Navigation ----
|
||||
|
|
@ -957,12 +967,26 @@ async function _wizardFinish() {
|
|||
console.error('Wizard final save error:', e);
|
||||
}
|
||||
|
||||
// Mark setup complete on both server and client
|
||||
try {
|
||||
await fetch('/api/setup/complete', { method: 'POST' });
|
||||
} catch (e) {
|
||||
console.error('Failed to mark setup complete on server:', e);
|
||||
}
|
||||
localStorage.setItem('soulsync_setup_complete', 'true');
|
||||
closeSetupWizard();
|
||||
|
||||
const overlay = document.getElementById('setup-wizard-overlay');
|
||||
if (overlay) overlay.style.display = 'none';
|
||||
|
||||
// Reload settings into the main UI
|
||||
if (typeof loadSettings === 'function') loadSettings();
|
||||
if (typeof showToast === 'function') showToast('Setup complete — welcome to SoulSync!', 'success');
|
||||
|
||||
// Continue app initialization if wizard was shown on first run
|
||||
if (typeof window._onSetupWizardComplete === 'function') {
|
||||
window._onSetupWizardComplete();
|
||||
window._onSetupWizardComplete = null;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Utility ----
|
||||
|
|
@ -973,18 +997,8 @@ function _escHtml(str) {
|
|||
}
|
||||
|
||||
// ---- Dev Trigger ----
|
||||
// Open wizard with: openSetupWizard() from console, or ?setup=1 URL param
|
||||
|
||||
(function _checkWizardAutoOpen() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
if (params.get('setup') === '1') {
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', () => setTimeout(openSetupWizard, 300));
|
||||
} else {
|
||||
setTimeout(openSetupWizard, 300);
|
||||
}
|
||||
}
|
||||
})();
|
||||
// Open wizard manually: openSetupWizard() from console, or ?setup=1 URL param
|
||||
// First-run auto-detection is handled in script.js DOMContentLoaded
|
||||
|
||||
// Expose globally
|
||||
window.openSetupWizard = openSetupWizard;
|
||||
|
|
|
|||
Loading…
Reference in a new issue