Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 51 additions & 7 deletions app/(dashboard)/site-replication/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import { useSystem } from "@/hooks/use-system"
import { formatDateTime, niceBytes } from "@/lib/functions"
import { useDialog } from "@/lib/feedback/dialog"
import { useMessage } from "@/lib/feedback/message"
import { siteReplicationResyncAdvice } from "@/lib/site-replication-edit"
import { extractServerDeploymentId, resolveSiteReplicationLocalSite } from "@/lib/site-replication-local-site"
import { isHttpsSiteReplicationEndpoint } from "@/lib/site-replication-tls"
import type {
Expand Down Expand Up @@ -240,6 +241,43 @@ export default function SiteReplicationPage() {
[loadData, message, resyncSiteReplication, t],
)

// Edits do not replay writes made while the old address was unreachable, so
// an endpoint change is followed by the resync that recovers them.
const handleEditSuccess = (peer: SiteReplicationPeerInfo, nextEndpoint: string) => {
void loadData()

const advice = siteReplicationResyncAdvice({
isLocal: peer.deploymentId === localDeploymentId,
previousEndpoint: peer.endpoint,
nextEndpoint,
})

if (advice === "resync-from-peers") {
dialog.warning({
title: t("Resync Recommended"),
content: t(
"This site's address changed. Objects written on other sites while the old address was unreachable were not replicated here. Start a resync toward this site from each peer site's console.",
),
positiveText: t("Close"),
})
} else if (advice === "resync-peer") {
dialog.warning({
title: t("Resync Recommended"),
content: t(
"The address of {name} changed. Objects written on this site while the old address was unreachable were not replicated to it. Run a resync for this site to copy them.",
{ name: peer.name || peer.endpoint },
),
...(canResyncSites
? {
positiveText: t("Start Resync"),
negativeText: t("Later"),
onPositiveClick: () => void handleResync({ ...peer, endpoint: nextEndpoint }, "start"),
}
: { positiveText: t("Close") }),
})
}
}

const confirmRemoveSite = useCallback(
(peer: SiteReplicationPeerInfo) => {
dialog.error({
Expand Down Expand Up @@ -379,7 +417,10 @@ export default function SiteReplicationPage() {
const isBusy =
pendingRemoveDeploymentId === peer.deploymentId || pendingResyncDeploymentId === peer.deploymentId

if (isLocal) {
// The local site's stored endpoint is only inferred when replication
// is set up, so it must stay editable for address changes; resync and
// removal still only make sense for remote peers.
if (isLocal && !canManageSites) {
return <span className="text-xs text-muted-foreground">{t("Managed automatically")}</span>
}

Expand All @@ -395,28 +436,28 @@ export default function SiteReplicationPage() {
/>
<DropdownMenuContent align="end">
<DropdownMenuGroup>
<DropdownMenuLabel>{peer.name || t("Peer site")}</DropdownMenuLabel>
<DropdownMenuLabel>{peer.name || (isLocal ? t("Current Site") : t("Peer site"))}</DropdownMenuLabel>
{canManageSites ? (
<DropdownMenuItem onClick={() => setEditingPeer(peer)}>
<RiArrowLeftRightLine className="size-4" aria-hidden />
{t("Edit Site")}
</DropdownMenuItem>
) : null}
{canResyncSites ? (
{canResyncSites && !isLocal ? (
<DropdownMenuItem onClick={() => void handleResync(peer, "start")}>
<RiRestartLine className="size-4" aria-hidden />
{t("Start Resync")}
</DropdownMenuItem>
) : null}
{canResyncSites ? (
{canResyncSites && !isLocal ? (
<DropdownMenuItem onClick={() => void handleResync(peer, "cancel")}>
<RiRefreshLine className="size-4" aria-hidden />
{t("Cancel Resync")}
</DropdownMenuItem>
) : null}
</DropdownMenuGroup>
{canRemoveSites ? <DropdownMenuSeparator /> : null}
{canRemoveSites ? (
{canRemoveSites && !isLocal ? <DropdownMenuSeparator /> : null}
{canRemoveSites && !isLocal ? (
<DropdownMenuItem variant="destructive" onClick={() => confirmRemoveSite(peer)}>
<RiDeleteBin5Line className="size-4" aria-hidden />
{t("Remove Site")}
Expand Down Expand Up @@ -795,7 +836,10 @@ export default function SiteReplicationPage() {
}
}}
peer={editingPeer}
onSuccess={() => void loadData()}
isLocal={!!editingPeer && editingPeer.deploymentId === localDeploymentId}
onSuccess={(endpoint) => {
if (editingPeer) handleEditSuccess(editingPeer, endpoint)
}}
/>
</Page>
)
Expand Down
25 changes: 19 additions & 6 deletions components/site-replication/edit-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,19 @@ interface SiteReplicationEditFormProps {
open: boolean
onOpenChange: (open: boolean) => void
peer: SiteReplicationPeerInfo | null
onSuccess?: () => void
/** True when `peer` is the site this console is connected to. */
isLocal?: boolean
/** Called with the saved endpoint after the server accepted the edit. */
onSuccess?: (endpoint: string) => void
}

export function SiteReplicationEditForm({ open, onOpenChange, peer, onSuccess }: SiteReplicationEditFormProps) {
export function SiteReplicationEditForm({
open,
onOpenChange,
peer,
isLocal = false,
onSuccess,
}: SiteReplicationEditFormProps) {
const { t } = useTranslation()
const message = useMessage()
const { editSiteReplication } = useSiteReplication()
Expand Down Expand Up @@ -98,7 +107,7 @@ export function SiteReplicationEditForm({ open, onOpenChange, peer, onSuccess }:
}

message.success(response.status || t("Save Success"))
onSuccess?.()
onSuccess?.(endpoint.trim())
onOpenChange(false)
} catch (error) {
message.error((error as Error).message || t("Save Failed"))
Expand Down Expand Up @@ -137,9 +146,13 @@ export function SiteReplicationEditForm({ open, onOpenChange, peer, onSuccess }:
<DialogHeader className="space-y-2">
<DialogTitle>{t("Edit Site")}</DialogTitle>
<DialogDescription>
{t(
"Update the peer details that RustFS uses for site replication management. Fields not shown here are preserved from the current configuration.",
)}
{isLocal
? t(
"This is the address other sites use to reach this site. Update it after this server's address changes; every peer site receives the new address.",
)
: t(
"Update the peer details that RustFS uses for site replication management. Fields not shown here are preserved from the current configuration.",
)}
</DialogDescription>
</DialogHeader>

Expand Down
5 changes: 5 additions & 0 deletions i18n/locales/ar-MA.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
"Resync Recommended": "يُوصى بإعادة المزامنة",
"Later": "لاحقًا",
"This is the address other sites use to reach this site. Update it after this server's address changes; every peer site receives the new address.": "هذا هو العنوان الذي تستخدمه المواقع الأخرى للوصول إلى هذا الموقع. حدّثه بعد تغيّر عنوان هذا الخادم؛ وستتلقى جميع المواقع النظيرة العنوان الجديد.",
"This site's address changed. Objects written on other sites while the old address was unreachable were not replicated here. Start a resync toward this site from each peer site's console.": "تغيّر عنوان هذا الموقع. لم تُنسخ إلى هنا الكائنات التي كُتبت على المواقع الأخرى أثناء تعذّر الوصول إلى العنوان القديم. ابدأ إعادة مزامنة نحو هذا الموقع من وحدة تحكم كل موقع نظير.",
"The address of {name} changed. Objects written on this site while the old address was unreachable were not replicated to it. Run a resync for this site to copy them.": "تغيّر عنوان {name}. لم تُنسخ إليه الكائنات التي كُتبت على هذا الموقع أثناء تعذّر الوصول إلى العنوان القديم. شغّل إعادة مزامنة لهذا الموقع لنسخها.",
"Path": "المسار",
"Force Cleanup Folder": "تنظيف المجلد بالقوة",
"Permanently delete all objects, versions, delete markers, and residual files in this folder. This cannot be undone.": "حذف جميع الكائنات والإصدارات وعلامات الحذف والملفات المتبقية في هذا المجلد نهائيًا. لا يمكن التراجع عن هذا الإجراء.",
Expand Down
5 changes: 5 additions & 0 deletions i18n/locales/de-DE.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
"Resync Recommended": "Neusynchronisierung empfohlen",
"Later": "Später",
"This is the address other sites use to reach this site. Update it after this server's address changes; every peer site receives the new address.": "Unter dieser Adresse erreichen andere Sites diese Site. Aktualisieren Sie sie, nachdem sich die Adresse dieses Servers geändert hat; alle Peer-Sites erhalten die neue Adresse.",
"This site's address changed. Objects written on other sites while the old address was unreachable were not replicated here. Start a resync toward this site from each peer site's console.": "Die Adresse dieser Site hat sich geändert. Objekte, die auf anderen Sites geschrieben wurden, während die alte Adresse nicht erreichbar war, wurden nicht hierher repliziert. Starten Sie in der Konsole jeder Peer-Site eine Neusynchronisierung zu dieser Site.",
"The address of {name} changed. Objects written on this site while the old address was unreachable were not replicated to it. Run a resync for this site to copy them.": "Die Adresse von {name} hat sich geändert. Objekte, die auf dieser Site geschrieben wurden, während die alte Adresse nicht erreichbar war, wurden nicht dorthin repliziert. Führen Sie für diese Site eine Neusynchronisierung aus, um sie zu kopieren.",
"Path": "Pfad",
"Force Cleanup Folder": "Ordner zwangsweise bereinigen",
"Permanently delete all objects, versions, delete markers, and residual files in this folder. This cannot be undone.": "Alle Objekte, Versionen, Löschmarkierungen und verbliebenen Dateien in diesem Ordner dauerhaft löschen. Dies kann nicht rückgängig gemacht werden.",
Expand Down
5 changes: 5 additions & 0 deletions i18n/locales/en-US.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
"Resync Recommended": "Resync Recommended",
"Later": "Later",
"This is the address other sites use to reach this site. Update it after this server's address changes; every peer site receives the new address.": "This is the address other sites use to reach this site. Update it after this server's address changes; every peer site receives the new address.",
"This site's address changed. Objects written on other sites while the old address was unreachable were not replicated here. Start a resync toward this site from each peer site's console.": "This site's address changed. Objects written on other sites while the old address was unreachable were not replicated here. Start a resync toward this site from each peer site's console.",
"The address of {name} changed. Objects written on this site while the old address was unreachable were not replicated to it. Run a resync for this site to copy them.": "The address of {name} changed. Objects written on this site while the old address was unreachable were not replicated to it. Run a resync for this site to copy them.",
"Path": "Path",
"Force Cleanup Folder": "Force Cleanup Folder",
"Permanently delete all objects, versions, delete markers, and residual files in this folder. This cannot be undone.": "Permanently delete all objects, versions, delete markers, and residual files in this folder. This cannot be undone.",
Expand Down
5 changes: 5 additions & 0 deletions i18n/locales/es-ES.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
"Resync Recommended": "Se recomienda resincronizar",
"Later": "Más tarde",
"This is the address other sites use to reach this site. Update it after this server's address changes; every peer site receives the new address.": "Esta es la dirección que usan los demás sitios para acceder a este sitio. Actualízala cuando cambie la dirección de este servidor; todos los sitios pares recibirán la nueva dirección.",
"This site's address changed. Objects written on other sites while the old address was unreachable were not replicated here. Start a resync toward this site from each peer site's console.": "La dirección de este sitio ha cambiado. Los objetos escritos en otros sitios mientras la dirección anterior no era accesible no se replicaron aquí. Inicia una resincronización hacia este sitio desde la consola de cada sitio par.",
"The address of {name} changed. Objects written on this site while the old address was unreachable were not replicated to it. Run a resync for this site to copy them.": "La dirección de {name} ha cambiado. Los objetos escritos en este sitio mientras la dirección anterior no era accesible no se replicaron allí. Ejecuta una resincronización para este sitio para copiarlos.",
"Path": "Ruta",
"Force Cleanup Folder": "Forzar limpieza de carpeta",
"Permanently delete all objects, versions, delete markers, and residual files in this folder. This cannot be undone.": "Eliminar permanentemente todos los objetos, versiones, marcadores de eliminación y archivos residuales de esta carpeta. Esta acción no se puede deshacer.",
Expand Down
5 changes: 5 additions & 0 deletions i18n/locales/fr-FR.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
"Resync Recommended": "Resynchronisation recommandée",
"Later": "Plus tard",
"This is the address other sites use to reach this site. Update it after this server's address changes; every peer site receives the new address.": "Il s'agit de l'adresse que les autres sites utilisent pour joindre ce site. Mettez-la à jour après un changement d'adresse de ce serveur ; tous les sites pairs reçoivent la nouvelle adresse.",
"This site's address changed. Objects written on other sites while the old address was unreachable were not replicated here. Start a resync toward this site from each peer site's console.": "L'adresse de ce site a changé. Les objets écrits sur les autres sites pendant que l'ancienne adresse était injoignable n'ont pas été répliqués ici. Lancez une resynchronisation vers ce site depuis la console de chaque site pair.",
"The address of {name} changed. Objects written on this site while the old address was unreachable were not replicated to it. Run a resync for this site to copy them.": "L'adresse de {name} a changé. Les objets écrits sur ce site pendant que l'ancienne adresse était injoignable n'y ont pas été répliqués. Lancez une resynchronisation pour ce site afin de les copier.",
"Path": "Chemin",
"Force Cleanup Folder": "Forcer le nettoyage du dossier",
"Permanently delete all objects, versions, delete markers, and residual files in this folder. This cannot be undone.": "Supprimer définitivement tous les objets, versions, marqueurs de suppression et fichiers résiduels de ce dossier. Cette action est irréversible.",
Expand Down
5 changes: 5 additions & 0 deletions i18n/locales/id-ID.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
"Resync Recommended": "Sinkronisasi ulang disarankan",
"Later": "Nanti",
"This is the address other sites use to reach this site. Update it after this server's address changes; every peer site receives the new address.": "Ini adalah alamat yang digunakan situs lain untuk menjangkau situs ini. Perbarui setelah alamat server ini berubah; semua situs peer akan menerima alamat baru.",
"This site's address changed. Objects written on other sites while the old address was unreachable were not replicated here. Start a resync toward this site from each peer site's console.": "Alamat situs ini berubah. Objek yang ditulis di situs lain selama alamat lama tidak dapat dijangkau tidak direplikasi ke sini. Mulai sinkronisasi ulang ke situs ini dari konsol setiap situs peer.",
"The address of {name} changed. Objects written on this site while the old address was unreachable were not replicated to it. Run a resync for this site to copy them.": "Alamat {name} berubah. Objek yang ditulis di situs ini selama alamat lama tidak dapat dijangkau tidak direplikasi ke sana. Jalankan sinkronisasi ulang untuk situs ini untuk menyalinnya.",
"Path": "Jalur",
"Force Cleanup Folder": "Bersihkan Folder Secara Paksa",
"Permanently delete all objects, versions, delete markers, and residual files in this folder. This cannot be undone.": "Hapus secara permanen semua objek, versi, penanda penghapusan, dan berkas sisa dalam folder ini. Tindakan ini tidak dapat dibatalkan.",
Expand Down
5 changes: 5 additions & 0 deletions i18n/locales/it-IT.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
"Resync Recommended": "Risincronizzazione consigliata",
"Later": "Più tardi",
"This is the address other sites use to reach this site. Update it after this server's address changes; every peer site receives the new address.": "Questo è l'indirizzo che gli altri siti usano per raggiungere questo sito. Aggiornalo dopo che l'indirizzo di questo server è cambiato; tutti i siti peer ricevono il nuovo indirizzo.",
"This site's address changed. Objects written on other sites while the old address was unreachable were not replicated here. Start a resync toward this site from each peer site's console.": "L'indirizzo di questo sito è cambiato. Gli oggetti scritti sugli altri siti mentre il vecchio indirizzo non era raggiungibile non sono stati replicati qui. Avvia una risincronizzazione verso questo sito dalla console di ogni sito peer.",
"The address of {name} changed. Objects written on this site while the old address was unreachable were not replicated to it. Run a resync for this site to copy them.": "L'indirizzo di {name} è cambiato. Gli oggetti scritti su questo sito mentre il vecchio indirizzo non era raggiungibile non sono stati replicati lì. Esegui una risincronizzazione per questo sito per copiarli.",
"Path": "Percorso",
"Force Cleanup Folder": "Forza pulizia cartella",
"Permanently delete all objects, versions, delete markers, and residual files in this folder. This cannot be undone.": "Elimina definitivamente tutti gli oggetti, le versioni, i marcatori di eliminazione e i file residui in questa cartella. Questa operazione è irreversibile.",
Expand Down
5 changes: 5 additions & 0 deletions i18n/locales/ja-JP.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
"Resync Recommended": "再同期を推奨",
"Later": "後で",
"This is the address other sites use to reach this site. Update it after this server's address changes; every peer site receives the new address.": "これは他のサイトがこのサイトに接続する際のアドレスです。このサーバーのアドレスが変わったら更新してください。新しいアドレスはすべてのピアサイトに反映されます。",
"This site's address changed. Objects written on other sites while the old address was unreachable were not replicated here. Start a resync toward this site from each peer site's console.": "このサイトのアドレスが変更されました。旧アドレスに到達できなかった間に他のサイトへ書き込まれたオブジェクトは、このサイトにレプリケートされていません。各ピアサイトのコンソールから、このサイトへの再同期を開始してください。",
"The address of {name} changed. Objects written on this site while the old address was unreachable were not replicated to it. Run a resync for this site to copy them.": "{name} のアドレスが変更されました。旧アドレスに到達できなかった間にこのサイトへ書き込まれたオブジェクトは、そのサイトにレプリケートされていません。このサイトの再同期を実行してコピーしてください。",
"Path": "パス",
"Force Cleanup Folder": "フォルダーを強制クリーンアップ",
"Permanently delete all objects, versions, delete markers, and residual files in this folder. This cannot be undone.": "このフォルダー内のすべてのオブジェクト、バージョン、削除マーカー、残存ファイルを完全に削除します。この操作は取り消せません。",
Expand Down
Loading