fix: address code review findings for DNS management
- CRITICAL: Change DNS zones endpoint from GET to POST to avoid leaking API token in URL query parameters - HIGH: Add sync.RWMutex to protect dnsProvider field in Server, Deployer, and proxy Manager against concurrent read/write races - HIGH: Capture old DNS provider reference synchronously before launching background cleanup goroutine - HIGH: Use getDNS()/getDNSProviderLocked() accessors instead of direct field reads in all DNS operations
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
import { b as attr_class, g as stringify, e as escape_html, s as store_get, u as unsubscribe_stores, i as derived, h as head, a as attr, f as ensure_array_like } from "../../../../chunks/index.js";
|
||||
import { c as cleanupStaleContainer, b as bulkCleanupStaleContainers } from "../../../../chunks/api.js";
|
||||
import { I as IconTrash } from "../../../../chunks/IconTrash.js";
|
||||
import { I as IconLoader } from "../../../../chunks/IconLoader.js";
|
||||
import { t } from "../../../../chunks/index2.js";
|
||||
import { I as IconAlert } from "../../../../chunks/IconAlert.js";
|
||||
import { S as SkeletonCard } from "../../../../chunks/SkeletonCard.js";
|
||||
import { t as toasts } from "../../../../chunks/toast.js";
|
||||
function ConfirmDialog($$renderer, $$props) {
|
||||
$$renderer.component(($$renderer2) => {
|
||||
var $$store_subs;
|
||||
const {
|
||||
open,
|
||||
title,
|
||||
message,
|
||||
confirmLabel = "Confirm",
|
||||
confirmVariant = "primary",
|
||||
onconfirm,
|
||||
oncancel
|
||||
} = $$props;
|
||||
const confirmClass = derived(() => confirmVariant === "danger" ? "bg-[var(--color-danger)] hover:bg-[var(--color-danger-dark)] focus-visible:outline-[var(--color-danger)]" : "bg-[var(--color-brand-600)] hover:bg-[var(--color-brand-700)] focus-visible:outline-[var(--color-brand-600)]");
|
||||
const iconBgClass = derived(() => confirmVariant === "danger" ? "bg-[var(--color-danger-light)]" : "bg-[var(--color-brand-50)]");
|
||||
const iconColorClass = derived(() => confirmVariant === "danger" ? "text-[var(--color-danger)]" : "text-[var(--color-brand-600)]");
|
||||
if (open) {
|
||||
$$renderer2.push("<!--[0-->");
|
||||
$$renderer2.push(`<div class="fixed inset-0 z-40 bg-[var(--surface-overlay)] animate-fade-in" role="presentation"></div> <div class="fixed inset-0 z-50 flex items-center justify-center p-4"><div class="w-full max-w-md rounded-2xl bg-[var(--surface-card)] p-6 shadow-xl animate-scale-in"><div class="flex items-start gap-4"><div${attr_class(`flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-full ${stringify(iconBgClass())}`)}>`);
|
||||
IconAlert($$renderer2, { size: 20, class: iconColorClass() });
|
||||
$$renderer2.push(`<!----></div> <div class="flex-1"><h3 class="text-lg font-semibold text-[var(--text-primary)]">${escape_html(title)}</h3> <p class="mt-2 text-sm text-[var(--text-secondary)] leading-relaxed">${escape_html(message)}</p></div></div> <div class="mt-6 flex justify-end gap-3"><button type="button" class="rounded-lg px-4 py-2 text-sm font-medium text-[var(--text-secondary)] hover:bg-[var(--surface-card-hover)] transition-colors active:animate-press">${escape_html(store_get($$store_subs ??= {}, "$t", t)("common.cancel"))}</button> <button type="button"${attr_class(`rounded-lg px-4 py-2 text-sm font-medium text-white ${stringify(confirmClass())} shadow-sm transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 active:animate-press`)}>${escape_html(confirmLabel)}</button></div></div></div>`);
|
||||
} else {
|
||||
$$renderer2.push("<!--[-1-->");
|
||||
}
|
||||
$$renderer2.push(`<!--]-->`);
|
||||
if ($$store_subs) unsubscribe_stores($$store_subs);
|
||||
});
|
||||
}
|
||||
function _page($$renderer, $$props) {
|
||||
$$renderer.component(($$renderer2) => {
|
||||
var $$store_subs;
|
||||
let containers = [];
|
||||
let confirmSingleId = "";
|
||||
let confirmBulk = false;
|
||||
let cleaningIds = /* @__PURE__ */ new Set();
|
||||
let bulkCleaning = false;
|
||||
async function handleConfirmCleanup() {
|
||||
const id = confirmSingleId;
|
||||
confirmSingleId = "";
|
||||
cleaningIds = /* @__PURE__ */ new Set([...cleaningIds, id]);
|
||||
try {
|
||||
await cleanupStaleContainer(id);
|
||||
containers = containers.filter((c) => c.id !== id);
|
||||
toasts.success(store_get($$store_subs ??= {}, "$t", t)("stale.cleanedUp"));
|
||||
} catch (e) {
|
||||
toasts.error(e instanceof Error ? e.message : store_get($$store_subs ??= {}, "$t", t)("stale.cleanupFailed"));
|
||||
} finally {
|
||||
const next = new Set(cleaningIds);
|
||||
next.delete(id);
|
||||
cleaningIds = next;
|
||||
}
|
||||
}
|
||||
async function handleConfirmBulkCleanup() {
|
||||
confirmBulk = false;
|
||||
bulkCleaning = true;
|
||||
try {
|
||||
const result = await bulkCleanupStaleContainers();
|
||||
containers = [];
|
||||
toasts.success(store_get($$store_subs ??= {}, "$t", t)("stale.bulkCleanedUp", { count: String(result.deleted) }));
|
||||
} catch (e) {
|
||||
toasts.error(e instanceof Error ? e.message : store_get($$store_subs ??= {}, "$t", t)("stale.cleanupFailed"));
|
||||
} finally {
|
||||
bulkCleaning = false;
|
||||
}
|
||||
}
|
||||
head("r4vrn", $$renderer2, ($$renderer3) => {
|
||||
$$renderer3.title(($$renderer4) => {
|
||||
$$renderer4.push(`<title>${escape_html(store_get($$store_subs ??= {}, "$t", t)("stale.title"))} - ${escape_html(store_get($$store_subs ??= {}, "$t", t)("app.name"))}</title>`);
|
||||
});
|
||||
});
|
||||
$$renderer2.push(`<div class="space-y-6"><div class="flex items-center justify-between"><h1 class="text-2xl font-bold text-[var(--text-primary)]">${escape_html(store_get($$store_subs ??= {}, "$t", t)("stale.title"))}</h1> `);
|
||||
if (containers.length > 0) {
|
||||
$$renderer2.push("<!--[0-->");
|
||||
$$renderer2.push(`<button type="button"${attr("disabled", bulkCleaning, true)} class="inline-flex items-center gap-2 rounded-lg border border-[var(--color-danger)] px-4 py-2.5 text-sm font-medium text-[var(--color-danger)] transition-colors hover:bg-[var(--color-danger-light)] disabled:opacity-50 active:animate-press">`);
|
||||
if (bulkCleaning) {
|
||||
$$renderer2.push("<!--[0-->");
|
||||
IconLoader($$renderer2, { size: 16 });
|
||||
} else {
|
||||
$$renderer2.push("<!--[-1-->");
|
||||
}
|
||||
$$renderer2.push(`<!--]--> `);
|
||||
IconTrash($$renderer2, { size: 16 });
|
||||
$$renderer2.push(`<!----> ${escape_html(store_get($$store_subs ??= {}, "$t", t)("stale.cleanupAll"))}</button>`);
|
||||
} else {
|
||||
$$renderer2.push("<!--[-1-->");
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div> `);
|
||||
{
|
||||
$$renderer2.push("<!--[0-->");
|
||||
$$renderer2.push(`<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3"><!--[-->`);
|
||||
const each_array = ensure_array_like(Array(3));
|
||||
for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
|
||||
each_array[$$index];
|
||||
SkeletonCard($$renderer2);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div> `);
|
||||
ConfirmDialog($$renderer2, {
|
||||
open: confirmSingleId !== "",
|
||||
title: store_get($$store_subs ??= {}, "$t", t)("stale.cleanup"),
|
||||
message: store_get($$store_subs ??= {}, "$t", t)("stale.confirmCleanup"),
|
||||
confirmLabel: store_get($$store_subs ??= {}, "$t", t)("stale.cleanup"),
|
||||
confirmVariant: "danger",
|
||||
onconfirm: handleConfirmCleanup,
|
||||
oncancel: () => {
|
||||
confirmSingleId = "";
|
||||
}
|
||||
});
|
||||
$$renderer2.push(`<!----> `);
|
||||
ConfirmDialog($$renderer2, {
|
||||
open: confirmBulk,
|
||||
title: store_get($$store_subs ??= {}, "$t", t)("stale.cleanupAll"),
|
||||
message: store_get($$store_subs ??= {}, "$t", t)("stale.confirmBulkCleanup"),
|
||||
confirmLabel: store_get($$store_subs ??= {}, "$t", t)("stale.cleanupAll"),
|
||||
confirmVariant: "danger",
|
||||
onconfirm: handleConfirmBulkCleanup,
|
||||
oncancel: () => {
|
||||
confirmBulk = false;
|
||||
}
|
||||
});
|
||||
$$renderer2.push(`<!---->`);
|
||||
if ($$store_subs) unsubscribe_stores($$store_subs);
|
||||
});
|
||||
}
|
||||
export {
|
||||
_page as default
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
const ssr = false;
|
||||
export {
|
||||
ssr
|
||||
};
|
||||
Reference in New Issue
Block a user