mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-06-20 21:00:41 +00:00
feat: enhance backup and restore functionality with integrity checks and progress tracking
- Added support for backup integrity verification during export and restore processes. - Introduced progress dispatching for backup export and restore operations. - Implemented new API endpoints for inspecting remote backup integrity. - Enhanced user interface with progress indicators and warning dialogs for integrity issues. - Updated localization strings for new features and user feedback. - Refactored backup-related functions for better clarity and maintainability.
This commit is contained in:
@@ -80,6 +80,11 @@ body {
|
||||
color var(--dur-medium) var(--ease-smooth);
|
||||
}
|
||||
|
||||
body.dialog-open {
|
||||
overflow: hidden;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
|
||||
body::before {
|
||||
content: none;
|
||||
}
|
||||
@@ -2929,6 +2934,148 @@ input[type='file'].input::file-selector-button:hover {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.restore-progress-card {
|
||||
margin: 8px 0 12px;
|
||||
padding: 14px 16px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid #d7e2f1;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.10);
|
||||
}
|
||||
|
||||
.restore-progress-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 1250;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 20px;
|
||||
background: rgba(15, 23, 42, 0.30);
|
||||
}
|
||||
|
||||
.restore-progress-modal {
|
||||
width: min(520px, 100%);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.restore-progress-head {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.restore-progress-kicker {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.02em;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.restore-progress-title {
|
||||
margin: 4px 0 2px;
|
||||
font-size: 20px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.restore-progress-subtitle {
|
||||
margin: 0;
|
||||
color: #6b7280;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.restore-progress-elapsed {
|
||||
flex: 0 0 auto;
|
||||
min-width: 88px;
|
||||
padding: 6px 8px;
|
||||
border-radius: 10px;
|
||||
background: #f8fbff;
|
||||
border: 1px solid #d7e2f1;
|
||||
color: #475569;
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.restore-progress-meter {
|
||||
height: 6px;
|
||||
border-radius: 999px;
|
||||
background: #e7eef8;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.restore-progress-meter-bar {
|
||||
display: block;
|
||||
height: 100%;
|
||||
border-radius: inherit;
|
||||
background: #3a71d8;
|
||||
transition: width 280ms ease;
|
||||
}
|
||||
|
||||
.restore-progress-current {
|
||||
margin-top: 12px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 10px;
|
||||
background: #f8fbff;
|
||||
border: 1px solid #d7e2f1;
|
||||
}
|
||||
|
||||
.restore-progress-current strong {
|
||||
display: block;
|
||||
color: #0f172a;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.restore-progress-current p {
|
||||
margin: 4px 0 0;
|
||||
color: #64748b;
|
||||
line-height: 1.45;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.restore-progress-list {
|
||||
list-style: none;
|
||||
margin: 12px 0 0;
|
||||
padding: 0;
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.restore-progress-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
min-height: 30px;
|
||||
color: #64748b;
|
||||
font-weight: 500;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.restore-progress-item.active {
|
||||
color: #1d4ed8;
|
||||
}
|
||||
|
||||
.restore-progress-item.done {
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.restore-progress-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 999px;
|
||||
background: #cbd5e1;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.restore-progress-item.active .restore-progress-dot {
|
||||
background: #1d4ed8;
|
||||
}
|
||||
|
||||
.restore-progress-item.done .restore-progress-dot {
|
||||
background: #94a3b8;
|
||||
}
|
||||
|
||||
.kv-line strong {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
@@ -3022,6 +3169,8 @@ input[type='file'].input::file-selector-button:hover {
|
||||
.dialog-mask {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
width: 100vw;
|
||||
height: 100dvh;
|
||||
background: rgba(15, 23, 42, 0.5);
|
||||
display: grid;
|
||||
place-items: center;
|
||||
@@ -3029,6 +3178,8 @@ input[type='file'].input::file-selector-button:hover {
|
||||
padding: 20px;
|
||||
opacity: 0;
|
||||
animation: fade-in var(--dur-medium) var(--ease-smooth) both;
|
||||
backdrop-filter: blur(6px);
|
||||
-webkit-backdrop-filter: blur(6px);
|
||||
}
|
||||
|
||||
.dialog-card {
|
||||
@@ -3043,6 +3194,54 @@ input[type='file'].input::file-selector-button:hover {
|
||||
animation: dialog-in 240ms var(--ease-out-strong) both;
|
||||
}
|
||||
|
||||
.dialog-mask.warning {
|
||||
background:
|
||||
radial-gradient(circle at top, rgba(255, 237, 213, 0.32), transparent 34%),
|
||||
linear-gradient(180deg, rgba(127, 29, 29, 0.36), rgba(15, 23, 42, 0.72));
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.dialog-card.warning {
|
||||
width: min(520px, 100%);
|
||||
border: 1px solid rgba(220, 38, 38, 0.22);
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255, 246, 246, 0.98), rgba(255, 255, 255, 0.99));
|
||||
box-shadow:
|
||||
0 36px 90px rgba(69, 10, 10, 0.28),
|
||||
0 0 0 1px rgba(255, 255, 255, 0.7) inset;
|
||||
}
|
||||
|
||||
.dialog-warning-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.dialog-warning-badge {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 16px;
|
||||
background: linear-gradient(180deg, #fff1f2, #ffe4e6);
|
||||
color: #dc2626;
|
||||
box-shadow:
|
||||
0 12px 30px rgba(220, 38, 38, 0.18),
|
||||
0 0 0 1px rgba(220, 38, 38, 0.08) inset;
|
||||
}
|
||||
|
||||
.dialog-warning-kicker {
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.16em;
|
||||
text-transform: uppercase;
|
||||
color: #b91c1c;
|
||||
}
|
||||
|
||||
.dialog-mask.closing {
|
||||
animation: fade-out 220ms var(--ease-smooth) both;
|
||||
}
|
||||
@@ -3070,6 +3269,22 @@ input[type='file'].input::file-selector-button:hover {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.dialog-card.warning .dialog-title {
|
||||
color: #7f1d1d;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.dialog-message.warning {
|
||||
margin-bottom: 16px;
|
||||
padding: 14px 16px;
|
||||
border-radius: 16px;
|
||||
border: 1px solid rgba(220, 38, 38, 0.16);
|
||||
background: linear-gradient(180deg, rgba(255, 241, 242, 0.94), rgba(255, 247, 237, 0.9));
|
||||
color: #7a2832;
|
||||
line-height: 1.65;
|
||||
box-shadow: 0 10px 28px rgba(248, 113, 113, 0.08) inset;
|
||||
}
|
||||
|
||||
.dialog-btn {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
@@ -4132,6 +4347,14 @@ input[type='file'].input::file-selector-button:hover {
|
||||
padding: 18px 16px calc(18px + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
.dialog-card.warning {
|
||||
max-width: 520px;
|
||||
}
|
||||
|
||||
.dialog-warning-strip {
|
||||
margin: -18px -16px 16px;
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
font-size: 24px;
|
||||
}
|
||||
@@ -4252,6 +4475,40 @@ input[type='file'].input::file-selector-button:hover {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
:root[data-theme='dark'] .dialog-card.warning {
|
||||
border-color: rgba(248, 113, 113, 0.36);
|
||||
background: linear-gradient(180deg, rgba(39, 16, 16, 0.98), rgba(27, 12, 12, 0.98));
|
||||
box-shadow:
|
||||
0 36px 90px rgba(5, 5, 5, 0.56),
|
||||
0 0 0 1px rgba(248, 113, 113, 0.12) inset;
|
||||
}
|
||||
|
||||
:root[data-theme='dark'] .dialog-mask.warning {
|
||||
background:
|
||||
radial-gradient(circle at top, rgba(127, 29, 29, 0.28), transparent 34%),
|
||||
linear-gradient(180deg, rgba(20, 12, 12, 0.64), rgba(2, 6, 23, 0.82));
|
||||
}
|
||||
|
||||
:root[data-theme='dark'] .dialog-warning-badge {
|
||||
background: linear-gradient(180deg, rgba(127, 29, 29, 0.8), rgba(69, 10, 10, 0.86));
|
||||
color: #fda4af;
|
||||
box-shadow:
|
||||
0 12px 30px rgba(0, 0, 0, 0.32),
|
||||
0 0 0 1px rgba(248, 113, 113, 0.14) inset;
|
||||
}
|
||||
|
||||
:root[data-theme='dark'] .dialog-warning-kicker,
|
||||
:root[data-theme='dark'] .dialog-card.warning .dialog-title {
|
||||
color: #fecaca;
|
||||
}
|
||||
|
||||
:root[data-theme='dark'] .dialog-message.warning {
|
||||
border-color: rgba(248, 113, 113, 0.18);
|
||||
background: linear-gradient(180deg, rgba(69, 10, 10, 0.54), rgba(67, 20, 7, 0.46));
|
||||
color: #fecdd3;
|
||||
box-shadow: 0 10px 28px rgba(0, 0, 0, 0.18) inset;
|
||||
}
|
||||
|
||||
:root[data-theme='dark'] .app-side,
|
||||
:root[data-theme='dark'] .sidebar,
|
||||
:root[data-theme='dark'] .mobile-sidebar-sheet .sidebar-block {
|
||||
|
||||
Reference in New Issue
Block a user