fix: restore replication and KMS actions (#171)

This commit is contained in:
Zhengchao An
2026-07-18 10:40:34 +08:00
committed by GitHub
parent 7ad5c7761d
commit 2a78a8075e
6 changed files with 36 additions and 27 deletions
+22 -19
View File
@@ -25,6 +25,7 @@ import { Card, CardAction, CardContent, CardDescription, CardHeader, CardTitle }
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
@@ -376,25 +377,27 @@ export default function SiteReplicationPage() {
}
/>
<DropdownMenuContent align="end">
<DropdownMenuLabel>{peer.name || t("Peer site")}</DropdownMenuLabel>
{canManageSites ? (
<DropdownMenuItem onClick={() => setEditingPeer(peer)}>
<RiArrowLeftRightLine className="size-4" aria-hidden />
{t("Edit Site")}
</DropdownMenuItem>
) : null}
{canResyncSites ? (
<DropdownMenuItem onClick={() => void handleResync(peer, "start")}>
<RiRestartLine className="size-4" aria-hidden />
{t("Start Resync")}
</DropdownMenuItem>
) : null}
{canResyncSites ? (
<DropdownMenuItem onClick={() => void handleResync(peer, "cancel")}>
<RiRefreshLine className="size-4" aria-hidden />
{t("Cancel Resync")}
</DropdownMenuItem>
) : null}
<DropdownMenuGroup>
<DropdownMenuLabel>{peer.name || t("Peer site")}</DropdownMenuLabel>
{canManageSites ? (
<DropdownMenuItem onClick={() => setEditingPeer(peer)}>
<RiArrowLeftRightLine className="size-4" aria-hidden />
{t("Edit Site")}
</DropdownMenuItem>
) : null}
{canResyncSites ? (
<DropdownMenuItem onClick={() => void handleResync(peer, "start")}>
<RiRestartLine className="size-4" aria-hidden />
{t("Start Resync")}
</DropdownMenuItem>
) : null}
{canResyncSites ? (
<DropdownMenuItem onClick={() => void handleResync(peer, "cancel")}>
<RiRefreshLine className="size-4" aria-hidden />
{t("Cancel Resync")}
</DropdownMenuItem>
) : null}
</DropdownMenuGroup>
{canRemoveSites ? <DropdownMenuSeparator /> : null}
{canRemoveSites ? (
<DropdownMenuItem variant="destructive" onClick={() => confirmRemoveSite(peer)}>
+2 -1
View File
@@ -905,7 +905,7 @@ export default function SSEPage() {
const isPendingDefaultKey = pendingKeyAction?.key.key_id === status?.config_summary?.default_key_id
const mutationLocked = Boolean(activeMutation || statusError || loadingStatus)
const localKmsReadOnly = formState.backendType === "local"
const localKmsReadOnly = hasConfiguration && formState.backendType === "local"
const formDisabled = mutationLocked || loadingStatus || submittingConfig || localKmsReadOnly
const mutationInFlight = Boolean(activeMutation || submittingConfig || creatingKey || processingKeyAction)
const canSetCreatedKeyAsDefault = status?.backend_type !== "Local" && !isConfigDirty
@@ -1079,6 +1079,7 @@ export default function SSEPage() {
) : null}
<form
className="space-y-6"
noValidate
onSubmit={(event) => {
event.preventDefault()
void submitConfiguration()
+1 -6
View File
@@ -101,12 +101,7 @@ export function BucketReplicationTab({ bucketName, hideTitle = false, renderHead
Rules: remaining,
})
}
if (
remaining.length > 0 &&
!role &&
targetArn &&
!remaining.some((item) => item.Destination?.Bucket === targetArn)
) {
if (!role && targetArn && !remaining.some((item) => item.Destination?.Bucket === targetArn)) {
try {
await deleteRemoteReplicationTarget(bucketName, targetArn)
} catch (cleanupError) {
+2 -1
View File
@@ -215,7 +215,8 @@ test("replication creation rereads rules and never removes an uncertain remote t
assert.match(replicationFormSource, /normalizeReplicationRulesForRolelessConfig/)
assert.match(replicationFormSource, /Role: ""/)
assert.match(replicationTabSource, /Role: role/)
assert.match(replicationTabSource, /remaining\.length > 0 &&[\s\S]{0,80}!role &&/)
assert.match(replicationTabSource, /if \(\s*!role &&[\s\S]{0,120}!remaining\.some/)
assert.doesNotMatch(replicationTabSource, /remaining\.length > 0 &&[\s\S]{0,80}!role &&/)
assert.doesNotMatch(replicationTabSource, /Replication configuration Role is missing/)
})
+7
View File
@@ -63,3 +63,10 @@ test("site replication overview reports each peer TLS trust mode", async () => {
assert.match(source, /formatTlsVerification/)
assert.match(source, /TLS Verification/)
})
test("site replication action labels stay inside a Base UI menu group", async () => {
const source = await readFile(new URL("../../app/(dashboard)/site-replication/page.tsx", import.meta.url), "utf8")
assert.match(source, /DropdownMenuGroup/)
assert.match(source, /<DropdownMenuGroup>[\s\S]*?<DropdownMenuLabel>[\s\S]*?<\/DropdownMenuGroup>/)
})
+2
View File
@@ -51,6 +51,7 @@ test("default-key creation uses a safe status baseline and clears secrets after
test("Local KMS cannot be reconfigured until the backend supports safe secret rotation", () => {
assert.match(source, /backendType: "vault-transit"/)
assert.match(source, /const localKmsReadOnly = hasConfiguration && formState\.backendType === "local"/)
assert.match(
source,
/Local filesystem KMS configuration is read-only in Console until safe master-key rotation is available\./,
@@ -61,6 +62,7 @@ test("Local KMS cannot be reconfigured until the backend supports safe secret ro
})
test("SSE form and dialogs stay reachable on narrow screens", () => {
assert.match(source, /<form\s+className="space-y-6"\s+noValidate/)
assert.match(source, /<fieldset className="space-y-4 border-t pt-4">/)
assert.match(source, /grid-rows-\[auto_minmax\(0,1fr\)_auto\]/)
assert.match(source, /md:hidden/)