Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8204105fd6 |
@@ -46,8 +46,13 @@
|
|||||||
let csvExporting = $state(false);
|
let csvExporting = $state(false);
|
||||||
let csvFileInput = $state<HTMLInputElement | null>(null);
|
let csvFileInput = $state<HTMLInputElement | null>(null);
|
||||||
|
|
||||||
const selectedCount = $derived(selectedIds.size);
|
const activeSelected = $derived.by(() => {
|
||||||
const allSelected = $derived(entries.length > 0 && selectedIds.size === entries.length);
|
const allowed = new Set(entries.map((e) => e.id));
|
||||||
|
return [...selectedIds].filter((id) => allowed.has(id));
|
||||||
|
});
|
||||||
|
const selectedCount = $derived(activeSelected.length);
|
||||||
|
|
||||||
|
const allSelected = $derived(entries.length > 0 && entries.every((e) => selectedIds.has(e.id)));
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ id: 'select', label: '', class: 'w-10' },
|
{ id: 'select', label: '', class: 'w-10' },
|
||||||
@@ -75,11 +80,6 @@
|
|||||||
{ id: 'actions', label: '', class: 'w-20' }
|
{ id: 'actions', label: '', class: 'w-20' }
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
$effect(() => {
|
|
||||||
const validIds = new Set(entries.map((e) => e.id));
|
|
||||||
selectedIds = new Set([...selectedIds].filter((id) => validIds.has(id)));
|
|
||||||
});
|
|
||||||
|
|
||||||
function toggleSelection(id: string) {
|
function toggleSelection(id: string) {
|
||||||
const next = new Set(selectedIds);
|
const next = new Set(selectedIds);
|
||||||
if (next.has(id)) next.delete(id);
|
if (next.has(id)) next.delete(id);
|
||||||
@@ -133,7 +133,7 @@
|
|||||||
deletingBulk = true;
|
deletingBulk = true;
|
||||||
let deleted = 0;
|
let deleted = 0;
|
||||||
try {
|
try {
|
||||||
for (const id of selectedIds) {
|
for (const id of activeSelected) {
|
||||||
try {
|
try {
|
||||||
await apiMutate(`/v1/modules/${moduleId}/as-entries/${id}`, 'DELETE', undefined, {
|
await apiMutate(`/v1/modules/${moduleId}/as-entries/${id}`, 'DELETE', undefined, {
|
||||||
idempotent: false
|
idempotent: false
|
||||||
|
|||||||
@@ -35,12 +35,23 @@
|
|||||||
|
|
||||||
let saving = $state(false);
|
let saving = $state(false);
|
||||||
let form = $state<AsEntryCreate>({ asn: 0, community_id: null });
|
let form = $state<AsEntryCreate>({ asn: 0, community_id: null });
|
||||||
|
let initKey = $state('');
|
||||||
|
|
||||||
|
function resetForm() {
|
||||||
|
form = edit
|
||||||
|
? { asn: edit.asn, community_id: edit.community_id }
|
||||||
|
: { asn: 0, community_id: null };
|
||||||
|
}
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (open) {
|
if (!open) {
|
||||||
form = edit
|
initKey = '';
|
||||||
? { asn: edit.asn, community_id: edit.community_id }
|
return;
|
||||||
: { asn: 0, community_id: null };
|
}
|
||||||
|
const nextKey = edit?.id ?? 'new';
|
||||||
|
if (nextKey !== initKey) {
|
||||||
|
initKey = nextKey;
|
||||||
|
resetForm();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -75,7 +86,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Dialog {open} onOpenChange={handleOpenChange}>
|
<Dialog bind:open onOpenChange={handleOpenChange}>
|
||||||
<DialogContent class="sm:max-w-sm">
|
<DialogContent class="sm:max-w-sm">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>{edit ? 'Редактировать запись' : 'Новая AS-запись'}</DialogTitle>
|
<DialogTitle>{edit ? 'Редактировать запись' : 'Новая AS-запись'}</DialogTitle>
|
||||||
|
|||||||
@@ -51,6 +51,7 @@
|
|||||||
prefix_path: '',
|
prefix_path: '',
|
||||||
community_id: null
|
community_id: null
|
||||||
});
|
});
|
||||||
|
let initKey = $state('');
|
||||||
|
|
||||||
function clearPreview() {
|
function clearPreview() {
|
||||||
previewLoading = false;
|
previewLoading = false;
|
||||||
@@ -61,18 +62,28 @@
|
|||||||
previewOk = false;
|
previewOk = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resetForm() {
|
||||||
|
clearPreview();
|
||||||
|
form = edit
|
||||||
|
? {
|
||||||
|
url: edit.url,
|
||||||
|
source_kind: normalizeCdnSourceKind(edit.source_kind),
|
||||||
|
prefix_path: edit.prefix_path ?? '',
|
||||||
|
community_id: edit.community_id,
|
||||||
|
refresh_interval_sec: edit.refresh_interval_sec
|
||||||
|
}
|
||||||
|
: { url: '', source_kind: 'plaintext', prefix_path: '', community_id: null };
|
||||||
|
}
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (open) {
|
if (!open) {
|
||||||
clearPreview();
|
initKey = '';
|
||||||
form = edit
|
return;
|
||||||
? {
|
}
|
||||||
url: edit.url,
|
const nextKey = edit?.id ?? 'new';
|
||||||
source_kind: normalizeCdnSourceKind(edit.source_kind),
|
if (nextKey !== initKey) {
|
||||||
prefix_path: edit.prefix_path ?? '',
|
initKey = nextKey;
|
||||||
community_id: edit.community_id,
|
resetForm();
|
||||||
refresh_interval_sec: edit.refresh_interval_sec
|
|
||||||
}
|
|
||||||
: { url: '', source_kind: 'plaintext', prefix_path: '', community_id: null };
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -150,7 +161,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Dialog {open} onOpenChange={handleOpenChange}>
|
<Dialog bind:open onOpenChange={handleOpenChange}>
|
||||||
<DialogContent class="sm:max-w-lg">
|
<DialogContent class="sm:max-w-lg">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>{edit ? 'Редактировать источник' : 'Новый CDN-источник'}</DialogTitle>
|
<DialogTitle>{edit ? 'Редактировать источник' : 'Новый CDN-источник'}</DialogTitle>
|
||||||
|
|||||||
@@ -39,8 +39,12 @@
|
|||||||
let selectedIds = $state(new Set<string>());
|
let selectedIds = $state(new Set<string>());
|
||||||
let deletingBulk = $state(false);
|
let deletingBulk = $state(false);
|
||||||
|
|
||||||
const selectedCount = $derived(selectedIds.size);
|
const activeSelected = $derived.by(() => {
|
||||||
const allSelected = $derived(sources.length > 0 && selectedIds.size === sources.length);
|
const allowed = new Set(sources.map((s) => s.id));
|
||||||
|
return [...selectedIds].filter((id) => allowed.has(id));
|
||||||
|
});
|
||||||
|
const selectedCount = $derived(activeSelected.length);
|
||||||
|
const allSelected = $derived(sources.length > 0 && sources.every((s) => selectedIds.has(s.id)));
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ id: 'select', label: '', class: 'w-10' },
|
{ id: 'select', label: '', class: 'w-10' },
|
||||||
@@ -62,11 +66,6 @@
|
|||||||
{ id: 'actions', label: '', class: 'w-20' }
|
{ id: 'actions', label: '', class: 'w-20' }
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
$effect(() => {
|
|
||||||
const validIds = new Set(sources.map((s) => s.id));
|
|
||||||
selectedIds = new Set([...selectedIds].filter((id) => validIds.has(id)));
|
|
||||||
});
|
|
||||||
|
|
||||||
function toggleSelection(id: string) {
|
function toggleSelection(id: string) {
|
||||||
const next = new Set(selectedIds);
|
const next = new Set(selectedIds);
|
||||||
if (next.has(id)) next.delete(id);
|
if (next.has(id)) next.delete(id);
|
||||||
@@ -120,7 +119,7 @@
|
|||||||
deletingBulk = true;
|
deletingBulk = true;
|
||||||
let deleted = 0;
|
let deleted = 0;
|
||||||
try {
|
try {
|
||||||
for (const id of selectedIds) {
|
for (const id of activeSelected) {
|
||||||
try {
|
try {
|
||||||
await apiMutate(`/v1/modules/${moduleId}/cdn-sources/${id}`, 'DELETE', undefined, {
|
await apiMutate(`/v1/modules/${moduleId}/cdn-sources/${id}`, 'DELETE', undefined, {
|
||||||
idempotent: false
|
idempotent: false
|
||||||
|
|||||||
@@ -72,7 +72,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Dialog {open} onOpenChange={handleOpenChange}>
|
<Dialog bind:open onOpenChange={handleOpenChange}>
|
||||||
<DialogContent class="sm:max-w-md">
|
<DialogContent class="sm:max-w-md">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Новый модуль</DialogTitle>
|
<DialogTitle>Новый модуль</DialogTitle>
|
||||||
|
|||||||
@@ -39,15 +39,15 @@
|
|||||||
<Badge variant={moduleEnabledBadgeVariant(!!mod.enabled)} class="text-xs">
|
<Badge variant={moduleEnabledBadgeVariant(!!mod.enabled)} class="text-xs">
|
||||||
{moduleEnabledRu(!!mod.enabled)}
|
{moduleEnabledRu(!!mod.enabled)}
|
||||||
</Badge>
|
</Badge>
|
||||||
<Button variant="outline" size="sm" onclick={onRefresh} disabled={refreshing}>
|
<Button variant="outline" size="sm" onclick={() => onRefresh()} disabled={refreshing}>
|
||||||
<RefreshCw class={refreshing ? 'animate-spin' : ''} />
|
<RefreshCw class={refreshing ? 'animate-spin' : ''} />
|
||||||
Обновить
|
Обновить
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="outline" size="sm" onclick={onEdit}>
|
<Button variant="outline" size="sm" onclick={() => onEdit()}>
|
||||||
<Pencil />
|
<Pencil />
|
||||||
Редактировать
|
Редактировать
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="destructive" size="sm" onclick={onDelete}>
|
<Button variant="destructive" size="sm" onclick={() => onDelete()}>
|
||||||
<Trash2 />
|
<Trash2 />
|
||||||
Удалить
|
Удалить
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -44,8 +44,12 @@
|
|||||||
let csvExporting = $state(false);
|
let csvExporting = $state(false);
|
||||||
let csvFileInput = $state<HTMLInputElement | null>(null);
|
let csvFileInput = $state<HTMLInputElement | null>(null);
|
||||||
|
|
||||||
const selectedCount = $derived(selectedIds.size);
|
const activeSelected = $derived.by(() => {
|
||||||
const allSelected = $derived(entries.length > 0 && selectedIds.size === entries.length);
|
const allowed = new Set(entries.map((e) => e.id));
|
||||||
|
return [...selectedIds].filter((id) => allowed.has(id));
|
||||||
|
});
|
||||||
|
const selectedCount = $derived(activeSelected.length);
|
||||||
|
const allSelected = $derived(entries.length > 0 && entries.every((e) => selectedIds.has(e.id)));
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ id: 'select', label: '', class: 'w-10' },
|
{ id: 'select', label: '', class: 'w-10' },
|
||||||
@@ -54,11 +58,6 @@
|
|||||||
{ id: 'actions', label: '', class: 'w-20' }
|
{ id: 'actions', label: '', class: 'w-20' }
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
$effect(() => {
|
|
||||||
const validIds = new Set(entries.map((e) => e.id));
|
|
||||||
selectedIds = new Set([...selectedIds].filter((id) => validIds.has(id)));
|
|
||||||
});
|
|
||||||
|
|
||||||
function toggleSelection(id: string) {
|
function toggleSelection(id: string) {
|
||||||
const next = new Set(selectedIds);
|
const next = new Set(selectedIds);
|
||||||
if (next.has(id)) next.delete(id);
|
if (next.has(id)) next.delete(id);
|
||||||
@@ -112,7 +111,7 @@
|
|||||||
deletingBulk = true;
|
deletingBulk = true;
|
||||||
let deleted = 0;
|
let deleted = 0;
|
||||||
try {
|
try {
|
||||||
for (const id of selectedIds) {
|
for (const id of activeSelected) {
|
||||||
try {
|
try {
|
||||||
await apiMutate(`/v1/modules/${moduleId}/domain-entries/${id}`, 'DELETE', undefined, {
|
await apiMutate(`/v1/modules/${moduleId}/domain-entries/${id}`, 'DELETE', undefined, {
|
||||||
idempotent: false
|
idempotent: false
|
||||||
|
|||||||
@@ -34,12 +34,23 @@
|
|||||||
|
|
||||||
let saving = $state(false);
|
let saving = $state(false);
|
||||||
let form = $state<DomainEntryCreate>({ fqdn: '', community_id: null });
|
let form = $state<DomainEntryCreate>({ fqdn: '', community_id: null });
|
||||||
|
let initKey = $state('');
|
||||||
|
|
||||||
|
function resetForm() {
|
||||||
|
form = edit
|
||||||
|
? { fqdn: edit.fqdn, community_id: edit.community_id }
|
||||||
|
: { fqdn: '', community_id: null };
|
||||||
|
}
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (open) {
|
if (!open) {
|
||||||
form = edit
|
initKey = '';
|
||||||
? { fqdn: edit.fqdn, community_id: edit.community_id }
|
return;
|
||||||
: { fqdn: '', community_id: null };
|
}
|
||||||
|
const nextKey = edit?.id ?? 'new';
|
||||||
|
if (nextKey !== initKey) {
|
||||||
|
initKey = nextKey;
|
||||||
|
resetForm();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -68,7 +79,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Dialog {open} onOpenChange={handleOpenChange}>
|
<Dialog bind:open onOpenChange={handleOpenChange}>
|
||||||
<DialogContent class="sm:max-w-sm">
|
<DialogContent class="sm:max-w-sm">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>{edit ? 'Редактировать домен' : 'Новый домен'}</DialogTitle>
|
<DialogTitle>{edit ? 'Редактировать домен' : 'Новый домен'}</DialogTitle>
|
||||||
|
|||||||
@@ -71,19 +71,30 @@
|
|||||||
|
|
||||||
let editForm = $state<ModulePatch>({});
|
let editForm = $state<ModulePatch>({});
|
||||||
let editSaving = $state(false);
|
let editSaving = $state(false);
|
||||||
|
let initKey = $state('');
|
||||||
|
|
||||||
|
function resetEditForm() {
|
||||||
|
editForm = {
|
||||||
|
name: mod.name,
|
||||||
|
enabled: mod.enabled,
|
||||||
|
priority: mod.priority,
|
||||||
|
refresh_interval_sec: mod.refresh_interval_sec,
|
||||||
|
cron_expr: mod.cron_expr,
|
||||||
|
default_community_id: mod.default_community_id,
|
||||||
|
doh_profile_ids: moduleDohProfileIds(mod),
|
||||||
|
doh_resolver_policy: mod.doh_resolver_policy ?? 'primary_only'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (open && mod) {
|
if (!open) {
|
||||||
editForm = {
|
initKey = '';
|
||||||
name: mod.name,
|
return;
|
||||||
enabled: mod.enabled,
|
}
|
||||||
priority: mod.priority,
|
const nextKey = mod.id;
|
||||||
refresh_interval_sec: mod.refresh_interval_sec,
|
if (nextKey !== initKey) {
|
||||||
cron_expr: mod.cron_expr,
|
initKey = nextKey;
|
||||||
default_community_id: mod.default_community_id,
|
resetEditForm();
|
||||||
doh_profile_ids: moduleDohProfileIds(mod),
|
|
||||||
doh_resolver_policy: mod.doh_resolver_policy ?? 'primary_only'
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -136,7 +147,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Dialog {open} onOpenChange={handleOpenChange}>
|
<Dialog bind:open onOpenChange={handleOpenChange}>
|
||||||
<DialogContent class="sm:max-w-md">
|
<DialogContent class="sm:max-w-md">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Редактировать модуль</DialogTitle>
|
<DialogTitle>Редактировать модуль</DialogTitle>
|
||||||
|
|||||||
@@ -28,12 +28,23 @@
|
|||||||
|
|
||||||
let saving = $state(false);
|
let saving = $state(false);
|
||||||
let form = $state<IpRangeEntryCreate>({ prefix: '', community_id: '' });
|
let form = $state<IpRangeEntryCreate>({ prefix: '', community_id: '' });
|
||||||
|
let initKey = $state('');
|
||||||
|
|
||||||
|
function resetForm() {
|
||||||
|
form = edit
|
||||||
|
? { prefix: edit.prefix, community_id: edit.community_id }
|
||||||
|
: { prefix: '', community_id: '' };
|
||||||
|
}
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (open) {
|
if (!open) {
|
||||||
form = edit
|
initKey = '';
|
||||||
? { prefix: edit.prefix, community_id: edit.community_id }
|
return;
|
||||||
: { prefix: '', community_id: '' };
|
}
|
||||||
|
const nextKey = edit?.id ?? 'new';
|
||||||
|
if (nextKey !== initKey) {
|
||||||
|
initKey = nextKey;
|
||||||
|
resetForm();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -62,7 +73,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Dialog {open} onOpenChange={handleOpenChange}>
|
<Dialog bind:open onOpenChange={handleOpenChange}>
|
||||||
<DialogContent class="sm:max-w-sm">
|
<DialogContent class="sm:max-w-sm">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>{edit ? 'Редактировать диапазон' : 'Новый IP-диапазон'}</DialogTitle>
|
<DialogTitle>{edit ? 'Редактировать диапазон' : 'Новый IP-диапазон'}</DialogTitle>
|
||||||
|
|||||||
@@ -44,8 +44,12 @@
|
|||||||
let csvExporting = $state(false);
|
let csvExporting = $state(false);
|
||||||
let csvFileInput = $state<HTMLInputElement | null>(null);
|
let csvFileInput = $state<HTMLInputElement | null>(null);
|
||||||
|
|
||||||
const selectedCount = $derived(selectedIds.size);
|
const activeSelected = $derived.by(() => {
|
||||||
const allSelected = $derived(entries.length > 0 && selectedIds.size === entries.length);
|
const allowed = new Set(entries.map((e) => e.id));
|
||||||
|
return [...selectedIds].filter((id) => allowed.has(id));
|
||||||
|
});
|
||||||
|
const selectedCount = $derived(activeSelected.length);
|
||||||
|
const allSelected = $derived(entries.length > 0 && entries.every((e) => selectedIds.has(e.id)));
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ id: 'select', label: '', class: 'w-10' },
|
{ id: 'select', label: '', class: 'w-10' },
|
||||||
@@ -59,11 +63,6 @@
|
|||||||
{ id: 'actions', label: '', class: 'w-20' }
|
{ id: 'actions', label: '', class: 'w-20' }
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
$effect(() => {
|
|
||||||
const validIds = new Set(entries.map((e) => e.id));
|
|
||||||
selectedIds = new Set([...selectedIds].filter((id) => validIds.has(id)));
|
|
||||||
});
|
|
||||||
|
|
||||||
function toggleSelection(id: string) {
|
function toggleSelection(id: string) {
|
||||||
const next = new Set(selectedIds);
|
const next = new Set(selectedIds);
|
||||||
if (next.has(id)) next.delete(id);
|
if (next.has(id)) next.delete(id);
|
||||||
@@ -120,7 +119,7 @@
|
|||||||
deletingBulk = true;
|
deletingBulk = true;
|
||||||
let deleted = 0;
|
let deleted = 0;
|
||||||
try {
|
try {
|
||||||
for (const id of selectedIds) {
|
for (const id of activeSelected) {
|
||||||
try {
|
try {
|
||||||
await apiMutate(`/v1/modules/${moduleId}/ip-range-entries/${id}`, 'DELETE', undefined, {
|
await apiMutate(`/v1/modules/${moduleId}/ip-range-entries/${id}`, 'DELETE', undefined, {
|
||||||
idempotent: false
|
idempotent: false
|
||||||
|
|||||||
@@ -15,7 +15,12 @@
|
|||||||
const open = $derived(!!state?.open);
|
const open = $derived(!!state?.open);
|
||||||
|
|
||||||
function onOpenChange(v: boolean) {
|
function onOpenChange(v: boolean) {
|
||||||
if (!v) closeConfirm();
|
if (!v && state && !state.loading) closeConfirm();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleConfirm() {
|
||||||
|
if (!state || state.loading) return;
|
||||||
|
await state.onConfirm();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -37,7 +42,10 @@
|
|||||||
? 'text-destructive-foreground bg-destructive hover:bg-destructive/90'
|
? 'text-destructive-foreground bg-destructive hover:bg-destructive/90'
|
||||||
: ''}
|
: ''}
|
||||||
disabled={state.loading}
|
disabled={state.loading}
|
||||||
onclick={state.onConfirm}
|
onclick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
void handleConfirm();
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{state.loading ? '…' : (state.confirmLabel ?? 'Подтвердить')}
|
{state.loading ? '…' : (state.confirmLabel ?? 'Подтвердить')}
|
||||||
</AlertDialogAction>
|
</AlertDialogAction>
|
||||||
|
|||||||
@@ -21,8 +21,9 @@ export function confirm(options: ConfirmOptions) {
|
|||||||
open: true,
|
open: true,
|
||||||
loading: false,
|
loading: false,
|
||||||
onConfirm: async () => {
|
onConfirm: async () => {
|
||||||
if (!confirmState.current) return;
|
const current = confirmState.current;
|
||||||
confirmState.current = { ...confirmState.current, loading: true };
|
if (!current || current.loading) return;
|
||||||
|
confirmState.current = { ...current, loading: true };
|
||||||
try {
|
try {
|
||||||
await options.onConfirm();
|
await options.onConfirm();
|
||||||
resolve(true);
|
resolve(true);
|
||||||
|
|||||||
Reference in New Issue
Block a user