properly display item errors

This commit is contained in:
Gareth
2025-12-23 15:50:10 -08:00
parent 4606733f43
commit 421fbed099
14 changed files with 151 additions and 57 deletions
+10 -2
View File
@@ -95,9 +95,17 @@ func BackupProgressEntryToBackupError(b *restic.BackupProgressEntry) (*v1.Backup
return nil, errors.New("BackupProgressEntry is not of type error")
}
message := ""
if errMap, ok := b.Error.(map[string]interface{}); ok {
if msg, ok := errMap["message"].(string); ok {
message = msg
}
}
return &v1.BackupProgressError{
Item: b.Item,
During: b.During,
Item: b.Item,
During: b.During,
Message: message,
}, nil
}
+5 -1
View File
@@ -344,5 +344,9 @@
"op_row_removed_header": "تمت إزالة اللقطات",
"op_row_removed_none": "لم يتم حذف أي لقطات.",
"op_row_removed_id_col": "معرف اللقطة",
"op_row_removed_time_col": "وقت"
"op_row_removed_time_col": "وقت",
"op_row_restore_source": "مسار المصدر",
"op_row_restore_target": "مسار الوجهة",
"op_row_error_path": "طريق",
"op_row_error_message": "خطأ"
}
+5 -1
View File
@@ -344,5 +344,9 @@
"op_row_removed_header": "স্ন্যাপশটগুলি সরানো হয়েছে",
"op_row_removed_none": "কোনও স্ন্যাপশট সরানো হয়নি।",
"op_row_removed_id_col": "স্ন্যাপশট আইডি",
"op_row_removed_time_col": "সময়"
"op_row_removed_time_col": "সময়",
"op_row_restore_source": "উৎস পথ",
"op_row_restore_target": "গন্তব্য পথ",
"op_row_error_path": "পথ",
"op_row_error_message": "ত্রুটি"
}
+5 -1
View File
@@ -344,5 +344,9 @@
"op_row_removed_header": "Snapshots entfernt",
"op_row_removed_none": "Es wurden keine Snapshots entfernt.",
"op_row_removed_id_col": "Snapshot-ID",
"op_row_removed_time_col": "Zeit"
"op_row_removed_time_col": "Zeit",
"op_row_restore_source": "Quellpfad",
"op_row_restore_target": "Zielpfad",
"op_row_error_path": "Weg",
"op_row_error_message": "Fehler"
}
+5 -1
View File
@@ -344,5 +344,9 @@
"op_row_removed_header": "Removed snapshots",
"op_row_removed_none": "No snapshots were removed.",
"op_row_removed_id_col": "Snapshot ID",
"op_row_removed_time_col": "Time"
"op_row_removed_time_col": "Time",
"op_row_restore_source": "Source Path",
"op_row_restore_target": "Destination Path",
"op_row_error_path": "Path",
"op_row_error_message": "Error"
}
+5 -1
View File
@@ -344,5 +344,9 @@
"op_row_removed_header": "Instantáneas eliminadas",
"op_row_removed_none": "No se eliminaron instantáneas.",
"op_row_removed_id_col": "ID de instantánea",
"op_row_removed_time_col": "Tiempo"
"op_row_removed_time_col": "Tiempo",
"op_row_restore_source": "Ruta de origen",
"op_row_restore_target": "Ruta de destino",
"op_row_error_path": "Camino",
"op_row_error_message": "Error"
}
+5 -1
View File
@@ -344,5 +344,9 @@
"op_row_removed_header": "Suppression des instantanés",
"op_row_removed_none": "Aucune capture d'écran n'a été supprimée.",
"op_row_removed_id_col": "ID de l'instantané",
"op_row_removed_time_col": "Temps"
"op_row_removed_time_col": "Temps",
"op_row_restore_source": "Chemin source",
"op_row_restore_target": "Chemin de destination",
"op_row_error_path": "Chemin",
"op_row_error_message": "Erreur"
}
+5 -1
View File
@@ -344,5 +344,9 @@
"op_row_removed_header": "स्नैपशॉट हटा दिए गए",
"op_row_removed_none": "कोई भी स्नैपशॉट नहीं हटाया गया।",
"op_row_removed_id_col": "स्नैपशॉट आईडी",
"op_row_removed_time_col": "समय"
"op_row_removed_time_col": "समय",
"op_row_restore_source": "स्रोत पथ",
"op_row_restore_target": "गंतव्य पथ",
"op_row_error_path": "पथ",
"op_row_error_message": "गलती"
}
+5 -1
View File
@@ -344,5 +344,9 @@
"op_row_removed_header": "Cuplikan layar dihapus",
"op_row_removed_none": "Tidak ada foto yang dihapus.",
"op_row_removed_id_col": "ID Cuplikan",
"op_row_removed_time_col": "Waktu"
"op_row_removed_time_col": "Waktu",
"op_row_restore_source": "Jalur Sumber",
"op_row_restore_target": "Jalur Tujuan",
"op_row_error_path": "Jalur",
"op_row_error_message": "Kesalahan"
}
+5 -1
View File
@@ -344,5 +344,9 @@
"op_row_removed_header": "Istantanee rimosse",
"op_row_removed_none": "Nessuna istantanea è stata rimossa.",
"op_row_removed_id_col": "ID istantanea",
"op_row_removed_time_col": "Tempo"
"op_row_removed_time_col": "Tempo",
"op_row_restore_source": "Percorso di origine",
"op_row_restore_target": "Percorso di destinazione",
"op_row_error_path": "Sentiero",
"op_row_error_message": "Errore"
}
+5 -1
View File
@@ -344,5 +344,9 @@
"op_row_removed_header": "Capturas de tela removidas",
"op_row_removed_none": "Nenhuma captura de tela foi removida.",
"op_row_removed_id_col": "ID do instantâneo",
"op_row_removed_time_col": "Tempo"
"op_row_removed_time_col": "Tempo",
"op_row_restore_source": "Caminho de origem",
"op_row_restore_target": "Caminho de destino",
"op_row_error_path": "Caminho",
"op_row_error_message": "Erro"
}
+5 -1
View File
@@ -344,5 +344,9 @@
"op_row_removed_header": "Удалены снимки экрана",
"op_row_removed_none": "Никакие снимки не были удалены.",
"op_row_removed_id_col": "Идентификатор снимка",
"op_row_removed_time_col": "Время"
"op_row_removed_time_col": "Время",
"op_row_restore_source": "Путь к источнику",
"op_row_restore_target": "Путь назначения",
"op_row_error_path": "Путь",
"op_row_error_message": "Ошибка"
}
+5 -1
View File
@@ -344,5 +344,9 @@
"op_row_removed_header": "已删除快照",
"op_row_removed_none": "没有删除任何快照。",
"op_row_removed_id_col": "快照 ID",
"op_row_removed_time_col": "时间"
"op_row_removed_time_col": "时间",
"op_row_restore_source": "源路径",
"op_row_restore_target": "目标路径",
"op_row_error_path": "小路",
"op_row_error_message": "错误"
}
+81 -43
View File
@@ -210,11 +210,26 @@ export const OperationRow = ({
key: "errors",
label: m.op_row_item_errors(),
children: (
<pre>
{backupOp.errors
.map((e) => m.op_row_error_on_item({ item: e.item }))
.join("\n")}
</pre>
<Table.Root size="sm" variant="outline">
<Table.Header>
<Table.Row>
<Table.ColumnHeader>{m.op_row_error_path()}</Table.ColumnHeader>
<Table.ColumnHeader>{m.op_row_error_message()}</Table.ColumnHeader>
</Table.Row>
</Table.Header>
<Table.Body>
{backupOp.errors.map((e, idx) => (
<Table.Row key={idx}>
<Table.Cell fontFamily="mono" verticalAlign="top">
{e.item}
</Table.Cell>
<Table.Cell verticalAlign="top">
{e.message || "Unknown error"}
</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table.Root>
),
});
}
@@ -476,19 +491,31 @@ const RestoreOperationStatus = ({ operation }: { operation: Operation }) => {
return (
<>
{m.op_row_restore_desc({
path: restoreOp.path,
target: restoreOp.target,
})}
<Stack gap={4} mb={4}>
<Box>
<Text fontWeight="bold" fontSize="xs" color="fg.muted" mb={1}>{m.op_row_restore_source()}</Text>
<Code p={2} borderRadius="md" width="full" display="block" whiteSpace="pre-wrap">
{restoreOp.path}
</Code>
</Box>
<Box>
<Text fontWeight="bold" fontSize="xs" color="fg.muted" mb={1}>{m.op_row_restore_target()}</Text>
<Code p={2} borderRadius="md" width="full" display="block" whiteSpace="pre-wrap">
{restoreOp.target}
</Code>
</Box>
</Stack>
{!isDone ? (
<ProgressRoot value={progress * 100} max={100} size="sm">
<ProgressRoot value={progress * 100} max={100} size="sm" mb={4}>
<ProgressBar />
</ProgressRoot>
) : null}
{operation.status == OperationStatus.STATUS_SUCCESS ? (
<>
<Box mb={4}>
<Button
variant="plain"
variant="outline"
size="sm"
onClick={() => {
backrestService
@@ -503,33 +530,38 @@ const RestoreOperationStatus = ({ operation }: { operation: Operation }) => {
>
{m.op_row_download_files()}
</Button>
</>
</Box>
) : null}
<br />
{m.op_row_restored_snapshot_id({
id: normalizeSnapshotId(operation.snapshotId!),
})}
{lastStatus && (
<SimpleGrid columns={2} gap={4}>
<Box>
<Text fontWeight="bold">
{m.op_row_bytes_done_total()}
</Text>
<Text>
{formatBytes(Number(lastStatus.bytesRestored))}/
{formatBytes(Number(lastStatus.totalBytes))}
</Text>
</Box>
<Box>
<Text fontWeight="bold">
{m.op_row_files_done_total()}
</Text>
<Text>
{Number(lastStatus.filesRestored)}/{Number(lastStatus.totalFiles)}
</Text>
</Box>
</SimpleGrid>
)}
<SimpleGrid columns={2} gap={4}>
<Box>
<Text fontWeight="bold">{m.op_row_snapshot_id()}</Text>
<Text fontFamily="mono">
{normalizeSnapshotId(operation.snapshotId!)}
</Text>
</Box>
{lastStatus && (
<>
<Box>
<Text fontWeight="bold">
{m.op_row_bytes_done_total()}
</Text>
<Text color="fg.muted">
{formatBytes(Number(lastStatus.bytesRestored))}/
{formatBytes(Number(lastStatus.totalBytes))}
</Text>
</Box>
<Box>
<Text fontWeight="bold">
{m.op_row_files_done_total()}
</Text>
<Text color="fg.muted">
{Number(lastStatus.filesRestored)}/{Number(lastStatus.totalFiles)}
</Text>
</Box>
</>
)}
</SimpleGrid>
</>
);
};
@@ -601,17 +633,17 @@ const BackupOperationStatus = ({
? normalizeSnapshotId(sum.snapshotId!)
: m.op_row_no_snapshot()}
</Text>
<SimpleGrid columns={3} gap={4} mt={2}>
<SimpleGrid columns={{ base: 1, md: 3 }} gap={4} mt={2}>
<Box>
<Text fontWeight="bold">{m.op_row_files_added()}</Text>
<Text color="fg.muted">
{sum.filesNew.toString()}
{Number(sum.filesNew).toLocaleString()}
</Text>
</Box>
<Box>
<Text fontWeight="bold">{m.op_row_files_changed()}</Text>
<Text color="fg.muted">
{sum.filesChanged.toString()}
{Number(sum.filesChanged).toLocaleString()}
</Text>
</Box>
<Box>
@@ -619,11 +651,11 @@ const BackupOperationStatus = ({
{m.op_row_files_unmodified()}
</Text>
<Text color="fg.muted">
{sum.filesUnmodified.toString()}
{Number(sum.filesUnmodified).toLocaleString()}
</Text>
</Box>
</SimpleGrid>
<SimpleGrid columns={2} gap={4} mt={2}>
<SimpleGrid columns={{ base: 1, md: 3 }} gap={4} mt={2}>
<Box>
<Text fontWeight="bold">{m.op_row_bytes_added()}</Text>
<Text color="fg.muted">
@@ -636,6 +668,12 @@ const BackupOperationStatus = ({
{formatBytes(Number(sum.totalBytesProcessed))}
</Text>
</Box>
<Box>
<Text fontWeight="bold">{m.op_row_total_files()}</Text>
<Text color="fg.muted">
{Number(sum.totalFilesProcessed).toLocaleString()}
</Text>
</Box>
</SimpleGrid>
</>
);