* Draw protocol distribution donut chart
(protocols, colors = {})
| 16092 | } |
| 16093 | if (updateBtn) { |
| 16094 | updateBtn.disabled = true; |
| 16095 | updateBtn.className = 'w-full bg-gray-600 text-white py-2 px-4 rounded cursor-not-allowed'; |
| 16096 | } |
| 16097 | addConsoleMessage('System is up to date', 'success'); |
| 16098 | } |
| 16099 | |
| 16100 | const modifiedCount = Array.isArray(gitStatus.modified_files) ? gitStatus.modified_files.length : 0; |
| 16101 | if (gitStatus.status_error) { |
| 16102 | addConsoleMessage(`git status: ${gitStatus.status_error}`, 'warning'); |
| 16103 | } |
| 16104 | if (data.commits_ahead > 0) { |
| 16105 | addConsoleMessage(`This box has ${data.commits_ahead} local commit(s); updating will sync it to the released version.`, 'warning'); |
| 16106 | } |
| 16107 | |
| 16108 | updateElement('update-info', infoMessage); |
| 16109 | |
| 16110 | // A conflicted or dirty tree is no longer a separate, riskier button: |
| 16111 | // the updater stashes and force-syncs whatever it finds. Say what will |
| 16112 | // happen to the user's edits, then use the same update path. |
| 16113 | if (data.updates_available && data.commits_behind > 0 && updateBtn) { |
| 16114 | updateBtn.onclick = performUpdate; |
| 16115 | updateElement('update-btn-text', 'Update System'); |
| 16116 | if (gitStatus.has_conflicts) { |
| 16117 | addConsoleMessage('Local merge conflicts detected - the update will clear them and save your edits to a git stash.', 'warning'); |
| 16118 | } else if (gitStatus.is_dirty) { |
| 16119 | addConsoleMessage(`${modifiedCount} local change${modifiedCount === 1 ? '' : 's'} detected - they will be saved and replayed after the update.`, 'info'); |
| 16120 | } |
| 16121 | } else if (gitStatus.has_conflicts && updateBtn) { |
| 16122 | // Nothing to pull, but the tree is in a bad state - offer the repair. |
| 16123 | updateBtn.disabled = false; |
| 16124 | updateBtn.onclick = resolveGitConflicts; |
| 16125 | updateBtn.className = 'w-full bg-red-600 hover:bg-red-700 text-white py-2 px-4 rounded transition-colors'; |
| 16126 | updateElement('update-btn-text', 'Repair Git State'); |
| 16127 | updateElement('update-status', 'Local Conflict'); |
| 16128 | if (updateStatusEl) { |
| 16129 | updateStatusEl.className = 'text-sm px-2 py-1 rounded bg-red-700 text-red-200'; |
| 16130 | } |
| 16131 | } |
| 16132 | |
| 16133 | } catch (error) { |
| 16134 | console.error('Error checking for updates:', error); |
| 16135 | updateElement('update-status', 'Error'); |
| 16136 | const statusEl = document.getElementById('update-status'); |
| 16137 | if (statusEl) { |
| 16138 | statusEl.className = 'text-sm px-2 py-1 rounded bg-red-700 text-red-300'; |
| 16139 | } |
| 16140 | updateElement('update-info', 'Failed to check for updates'); |
| 16141 | addConsoleMessage(`Failed to check for updates: ${error.message}`, 'error'); |
| 16142 | // The check endpoint answers even when git is unhappy, so a thrown error |
| 16143 | // means the web app itself is unreachable - retrying is all we can do. |
| 16144 | const updateBtn = document.getElementById('update-btn'); |
| 16145 | if (updateBtn) { |
| 16146 | updateBtn.disabled = false; |
no test coverage detected