Spaces:
Paused
Paused
| <html> | |
| <head> | |
| <title>Restore Backup</title> | |
| <script type="module"> | |
| import { store } from "/components/settings/backup/backup-store.js"; | |
| </script> | |
| </head> | |
| <body> | |
| <div x-data> | |
| <template x-if="$store.backupStore"> | |
| <div x-init="$store.backupStore.initRestore()" x-destroy="$store.backupStore.onClose()"> | |
| <!-- File Upload Section --> | |
| <div class="upload-section"> | |
| <label for="backup-file" class="upload-label"> | |
| Select Backup File (.zip) | |
| </label> | |
| <input type="file" id="backup-file" accept=".zip" | |
| @change="$store.backupStore.handleFileUpload($event)"> | |
| </div> | |
| <!-- Warning Message (only show when backup file is loaded) --> | |
| <div x-show="$store.backupStore.backupMetadata" class="restore-warning"> | |
| <span class="warning-icon">⚠️</span> | |
| <span class="warning-text">After restoring a backup you will have to restart Agent-Zero to fully load the backed-up configuration (button in the left pane).</span> | |
| <span class="warning-icon">⚠️</span> | |
| </div> | |
| <!-- File Conflict Policy (Dropdown) --> | |
| <div x-show="$store.backupStore.backupMetadata" class="overwrite-policy"> | |
| <label class="policy-label"> | |
| <span class="policy-label-text">File Conflict Policy:</span> | |
| <select x-model="$store.backupStore.overwritePolicy" class="policy-dropdown"> | |
| <option value="overwrite">Overwrite existing files</option> | |
| <option value="skip">Skip existing files</option> | |
| <option value="backup">Backup existing files (.backup.timestamp)</option> | |
| </select> | |
| </label> | |
| </div> | |
| <!-- Clean Before Restore Option --> | |
| <div x-show="$store.backupStore.backupMetadata" class="clean-before-restore"> | |
| <label class="checkbox-label"> | |
| <input type="checkbox" x-model="$store.backupStore.cleanBeforeRestore"> | |
| <span class="checkbox-text">Clean before restore (delete existing files matching original backup patterns)</span> | |
| </label> | |
| <div class="clean-description"> | |
| When enabled, all existing files matching the original backup patterns will be deleted before restoring files from the archive. This ensures a completely clean restore state. | |
| </div> | |
| </div> | |
| <!-- Loading indicator --> | |
| <div x-show="$store.backupStore.loading" class="restore-loading"> | |
| <span x-text="$store.backupStore.loadingMessage || 'Processing...'"></span> | |
| </div> | |
| <!-- Error display --> | |
| <div x-show="$store.backupStore.error" class="restore-error"> | |
| <span x-text="$store.backupStore.error"></span> | |
| </div> | |
| <!-- Success display --> | |
| <div x-show="$store.backupStore.restoreResult" class="restore-result"> | |
| <h4>Restore Complete</h4> | |
| <div class="result-stats"> | |
| <div x-show="$store.backupStore.restoreResult?.deleted_files?.length > 0">Deleted: <span x-text="$store.backupStore.restoreResult?.deleted_files?.length || 0"></span></div> | |
| <div>Restored: <span x-text="$store.backupStore.restoreResult?.restored_files?.length || 0"></span></div> | |
| <div>Skipped: <span x-text="$store.backupStore.restoreResult?.skipped_files?.length || 0"></span></div> | |
| <div>Errors: <span x-text="$store.backupStore.restoreResult?.errors?.length || 0"></span></div> | |
| </div> | |
| </div> | |
| <!-- Header with buttons (following MCP servers pattern) --> | |
| <h3 x-show="$store.backupStore.backupMetadata">Restore Configuration JSON | |
| <button class="btn slim" style="margin-left: 0.5em;" | |
| @click="$store.backupStore.formatJson()">Format</button> | |
| <button class="btn slim" style="margin-left: 0.5em;" | |
| @click="$store.backupStore.resetToOriginalMetadata()">Reset</button> | |
| <button class="btn slim" style="margin-left: 0.5em;" | |
| @click="$store.backupStore.dryRun()" :disabled="$store.backupStore.loading">Dry Run</button> | |
| <button class="btn slim primary" style="margin-left: 0.5em;" | |
| @click="$store.backupStore.performRestore()" :disabled="$store.backupStore.loading">Restore Files</button> | |
| </h3> | |
| <!-- JSON Editor (upper part) --> | |
| <div x-show="$store.backupStore.backupMetadata" id="restore-metadata-editor"></div> | |
| <!-- File Operations Display (lower part) --> | |
| <h3 x-show="$store.backupStore.backupMetadata" id="restore-operations">File Operations</h3> | |
| <!-- File listing textarea --> | |
| <div x-show="$store.backupStore.backupMetadata" class="file-operations-container"> | |
| <textarea id="restore-file-list" | |
| x-model="$store.backupStore.fileOperationsLog" | |
| readonly | |
| placeholder="File operations will be displayed here..."></textarea> | |
| </div> | |
| </div> | |
| </template> | |
| </div> | |
| <style> | |
| .upload-section { | |
| margin-bottom: 1.5rem; | |
| padding: 1rem; | |
| border: 2px dashed var(--color-border); | |
| border-radius: 4px; | |
| text-align: center; | |
| } | |
| .upload-label { | |
| display: block; | |
| margin-bottom: 0.5rem; | |
| font-weight: 600; | |
| } | |
| .restore-loading { | |
| width: 100%; | |
| text-align: center; | |
| margin-top: 2rem; | |
| margin-bottom: 2rem; | |
| color: var(--color-secondary); | |
| } | |
| #restore-metadata-editor { | |
| width: 100%; | |
| height: 25em; | |
| } | |
| .file-operations-container { | |
| margin-top: 0.5em; | |
| margin-bottom: 1em; | |
| } | |
| #restore-file-list { | |
| width: 100%; | |
| height: 15em; | |
| font-family: monospace; | |
| font-size: 0.85em; | |
| background: var(--color-input); | |
| color: var(--color-text); | |
| border: 1px solid var(--color-border); | |
| border-radius: 4px; | |
| padding: 0.5em; | |
| resize: vertical; | |
| } | |
| .overwrite-policy { | |
| margin: 1rem 0; | |
| } | |
| .policy-label { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| margin: 0.5rem 0; | |
| } | |
| .clean-before-restore { | |
| margin: 1rem 0; | |
| padding: 0.75rem; | |
| background: var(--color-input); | |
| border: 1px solid var(--color-border); | |
| border-radius: 4px; | |
| } | |
| .checkbox-label { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| margin-bottom: 0.5rem; | |
| cursor: pointer; | |
| } | |
| .checkbox-label input[type="checkbox"] { | |
| width: 1rem; | |
| height: 1rem; | |
| } | |
| .checkbox-text { | |
| font-weight: 600; | |
| color: var(--color-text); | |
| } | |
| .clean-description { | |
| font-size: 0.85rem; | |
| color: var(--color-secondary); | |
| line-height: 1.4; | |
| margin-left: 1.5rem; | |
| } | |
| .policy-label-text { | |
| font-weight: 600; | |
| white-space: nowrap; | |
| } | |
| .policy-dropdown { | |
| flex: 1; | |
| padding: 0.5rem; | |
| border: 1px solid var(--color-border); | |
| border-radius: 4px; | |
| background: var(--color-input); | |
| color: var(--color-text); | |
| font-size: 0.9rem; | |
| } | |
| .restore-error { | |
| color: var(--color-error); | |
| margin: 0.5rem 0; | |
| padding: 0.5rem; | |
| background: var(--color-input); | |
| border: 1px solid var(--color-error); | |
| border-radius: 4px; | |
| } | |
| .restore-result { | |
| margin: 1rem 0; | |
| padding: 1rem; | |
| background: var(--color-secondary); | |
| border-radius: 4px; | |
| } | |
| .result-stats { | |
| display: flex; | |
| gap: 1rem; | |
| margin-top: 0.5rem; | |
| } | |
| .restore-warning { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| margin: 1rem 0; | |
| padding: 1rem; | |
| background: var(--color-background); | |
| border: 2px solid #f1c40f; | |
| border-radius: 4px; | |
| color: var(--color-text); | |
| } | |
| .warning-icon { | |
| font-size: 1.2em; | |
| margin: 0 1rem; | |
| color: #f39c12; | |
| } | |
| .warning-text { | |
| text-align: center; | |
| font-weight: 500; | |
| flex: 1; | |
| } | |
| </style> | |
| </body> | |
| </html> | |