chore: remove 4 unused files (theme-editor-fields, use-user-bulk-actions, user-columns, use-media-library)
This commit is contained in:
1 parent
9bc0834bbb
commit
9ae03056e2
17 files changed
+149
-1028
No files matched your search
@@ -10,15 +10,18 @@ import {
|
||||
Trash2,
|
||||
X,
|
||||
} from "lucide-react";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
BatchImportProgress,
|
||||
useBatchImport,
|
||||
} from "@/components/admin/import/use-batch-import";
|
||||
import { ImportErrorBanner } from "@/components/admin/import-error-banner";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { adminFetch } from "@/lib/admin-fetch";
|
||||
import { getAvatarUrl } from "@/lib/imager";
|
||||
import { runSseImport } from "@/lib/sse-client";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
// ── Shared types ─────────────────────────────────────────────────────────────
|
||||
@@ -97,12 +100,14 @@ function LibsView() {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
const [selected, setSelected] = useState<Set<string>>(new Set());
|
||||
const [batchProgress, setBatchProgress] = useState<{
|
||||
done: number;
|
||||
total: number;
|
||||
} | null>(null);
|
||||
const [busyLib, setBusyLib] = useState<string | null>(null);
|
||||
const batchAbortRef = useRef<AbortController | null>(null);
|
||||
const batch = useBatchImport({
|
||||
url: "/api/admin/import/clothing/batch",
|
||||
successAction: "libraries imported",
|
||||
cancelledMessage: "Import cancelled",
|
||||
onItemDone: (label) => markDone(label),
|
||||
onComplete: () => setSelected(new Set()),
|
||||
});
|
||||
|
||||
const fetchItems = useCallback(async (search: string, pageNum: number) => {
|
||||
setLoading(true);
|
||||
@@ -168,41 +173,10 @@ function LibsView() {
|
||||
}
|
||||
|
||||
async function importViaSse(toImport: FigureItem[]) {
|
||||
batchAbortRef.current?.abort();
|
||||
const abort = new AbortController();
|
||||
batchAbortRef.current = abort;
|
||||
setBatchProgress({ done: 0, total: toImport.length });
|
||||
let done = 0;
|
||||
try {
|
||||
await runSseImport(
|
||||
"/api/admin/import/clothing/batch",
|
||||
{ items: toImport, concurrency: 3 },
|
||||
(label) => {
|
||||
done++;
|
||||
markDone(label);
|
||||
setBatchProgress({ done, total: toImport.length });
|
||||
},
|
||||
(succeeded, failed) => {
|
||||
setSelected(new Set());
|
||||
if (succeeded > 0) toast.success(`${succeeded} libraries imported`);
|
||||
if (failed > 0) toast.error(`${failed} failed`);
|
||||
},
|
||||
abort.signal,
|
||||
() => {
|
||||
done++;
|
||||
setBatchProgress({ done, total: toImport.length });
|
||||
},
|
||||
);
|
||||
} catch (err) {
|
||||
if ((err as Error)?.name === "AbortError") {
|
||||
toast.info("Import cancelled");
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
} finally {
|
||||
if (batchAbortRef.current === abort) batchAbortRef.current = null;
|
||||
setBatchProgress(null);
|
||||
}
|
||||
await batch.run(
|
||||
toImport.map((p) => p.lib),
|
||||
{ items: toImport, concurrency: 3 },
|
||||
);
|
||||
}
|
||||
|
||||
async function importOne(p: FigureItem) {
|
||||
@@ -315,7 +289,7 @@ function LibsView() {
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="text-xs h-8"
|
||||
disabled={!!batchProgress}
|
||||
disabled={batch.running}
|
||||
onClick={() =>
|
||||
setSelected((prev) =>
|
||||
prev.size === importable.length
|
||||
@@ -333,9 +307,9 @@ function LibsView() {
|
||||
size="sm"
|
||||
className="h-8"
|
||||
onClick={importSelected}
|
||||
disabled={!!batchProgress}
|
||||
disabled={batch.running}
|
||||
>
|
||||
{batchProgress ? (
|
||||
{batch.running ? (
|
||||
<Loader2 className="w-4 h-4 animate-spin mr-1" />
|
||||
) : (
|
||||
<Download className="w-4 h-4 mr-1" />
|
||||
@@ -343,20 +317,11 @@ function LibsView() {
|
||||
Import {selected.size} selected
|
||||
</Button>
|
||||
)}
|
||||
{batchProgress && (
|
||||
<>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{batchProgress.done}/{batchProgress.total}
|
||||
</span>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="h-8"
|
||||
onClick={() => batchAbortRef.current?.abort()}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</>
|
||||
{batch.progress && (
|
||||
<BatchImportProgress
|
||||
progress={batch.progress}
|
||||
onCancel={batch.cancel}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
@@ -423,7 +388,7 @@ function LibsView() {
|
||||
size="sm"
|
||||
className="h-5 w-5 p-0 shrink-0"
|
||||
title="Remove library"
|
||||
disabled={busyLib === p.lib || !!batchProgress}
|
||||
disabled={busyLib === p.lib || batch.running}
|
||||
onClick={() => remove(p)}
|
||||
>
|
||||
<Trash2 className="w-3 h-3" />
|
||||
@@ -434,7 +399,7 @@ function LibsView() {
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="w-full text-xs h-7"
|
||||
disabled={busyLib === p.lib || !!batchProgress}
|
||||
disabled={busyLib === p.lib || batch.running}
|
||||
onClick={() => importOne(p)}
|
||||
>
|
||||
{busyLib === p.lib ? (
|
||||
@@ -493,12 +458,14 @@ function SetsView() {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
const [selected, setSelected] = useState<Set<string>>(new Set());
|
||||
const [batchProgress, setBatchProgress] = useState<{
|
||||
done: number;
|
||||
total: number;
|
||||
} | null>(null);
|
||||
const [busyKey, setBusyKey] = useState<string | null>(null);
|
||||
const batchAbortRef = useRef<AbortController | null>(null);
|
||||
const batch = useBatchImport({
|
||||
url: "/api/admin/import/clothing/sets/batch",
|
||||
successAction: "sets imported",
|
||||
cancelledMessage: "Import cancelled",
|
||||
onItemDone: (label) => markDone(label),
|
||||
onComplete: () => setSelected(new Set()),
|
||||
});
|
||||
|
||||
function itemKey(it: ClothingSetItem): string {
|
||||
return `${it.setType}-${it.setId}`;
|
||||
@@ -565,47 +532,16 @@ function SetsView() {
|
||||
}
|
||||
|
||||
async function importViaSse(toImport: ClothingSetItem[]) {
|
||||
batchAbortRef.current?.abort();
|
||||
const abort = new AbortController();
|
||||
batchAbortRef.current = abort;
|
||||
setBatchProgress({ done: 0, total: toImport.length });
|
||||
let done = 0;
|
||||
try {
|
||||
await runSseImport(
|
||||
"/api/admin/import/clothing/sets/batch",
|
||||
{
|
||||
items: toImport.map((it) => ({
|
||||
setType: it.setType,
|
||||
setId: it.setId,
|
||||
})),
|
||||
concurrency: 3,
|
||||
},
|
||||
(label) => {
|
||||
done++;
|
||||
markDone(label);
|
||||
setBatchProgress({ done, total: toImport.length });
|
||||
},
|
||||
(succeeded, failed) => {
|
||||
setSelected(new Set());
|
||||
if (succeeded > 0) toast.success(`${succeeded} sets imported`);
|
||||
if (failed > 0) toast.error(`${failed} failed`);
|
||||
},
|
||||
abort.signal,
|
||||
() => {
|
||||
done++;
|
||||
setBatchProgress({ done, total: toImport.length });
|
||||
},
|
||||
);
|
||||
} catch (err) {
|
||||
if ((err as Error)?.name === "AbortError") {
|
||||
toast.info("Import cancelled");
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
} finally {
|
||||
if (batchAbortRef.current === abort) batchAbortRef.current = null;
|
||||
setBatchProgress(null);
|
||||
}
|
||||
await batch.run(
|
||||
toImport.map((it) => itemKey(it)),
|
||||
{
|
||||
items: toImport.map((it) => ({
|
||||
setType: it.setType,
|
||||
setId: it.setId,
|
||||
})),
|
||||
concurrency: 3,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
async function importOne(it: ClothingSetItem) {
|
||||
@@ -698,7 +634,7 @@ function SetsView() {
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="text-xs h-8"
|
||||
disabled={!!batchProgress}
|
||||
disabled={batch.running}
|
||||
onClick={() =>
|
||||
setSelected((prev) =>
|
||||
prev.size === importable.length
|
||||
@@ -716,9 +652,9 @@ function SetsView() {
|
||||
size="sm"
|
||||
className="h-8"
|
||||
onClick={importSelected}
|
||||
disabled={!!batchProgress}
|
||||
disabled={batch.running}
|
||||
>
|
||||
{batchProgress ? (
|
||||
{batch.running ? (
|
||||
<Loader2 className="w-4 h-4 animate-spin mr-1" />
|
||||
) : (
|
||||
<Download className="w-4 h-4 mr-1" />
|
||||
@@ -726,20 +662,11 @@ function SetsView() {
|
||||
Import {selected.size} selected
|
||||
</Button>
|
||||
)}
|
||||
{batchProgress && (
|
||||
<>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{batchProgress.done}/{batchProgress.total}
|
||||
</span>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="h-8"
|
||||
onClick={() => batchAbortRef.current?.abort()}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</>
|
||||
{batch.progress && (
|
||||
<BatchImportProgress
|
||||
progress={batch.progress}
|
||||
onCancel={batch.cancel}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
@@ -824,7 +751,7 @@ function SetsView() {
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="w-full text-xs h-7"
|
||||
disabled={busyKey === key || !!batchProgress}
|
||||
disabled={busyKey === key || batch.running}
|
||||
onClick={() => importOne(it)}
|
||||
>
|
||||
{busyKey === key ? (
|
||||
|
||||
@@ -12,14 +12,17 @@ import {
|
||||
Trash2,
|
||||
X,
|
||||
} from "lucide-react";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
BatchImportProgress,
|
||||
useBatchImport,
|
||||
} from "@/components/admin/import/use-batch-import";
|
||||
import { ImportErrorBanner } from "@/components/admin/import-error-banner";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { adminFetch } from "@/lib/admin-fetch";
|
||||
import { runSseImport } from "@/lib/sse-client";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface EffectItem {
|
||||
@@ -40,12 +43,14 @@ export function ImportEffectsClient() {
|
||||
const [error, setError] = useState("");
|
||||
const [filter, setFilter] = useState<Filter>("all");
|
||||
const [selected, setSelected] = useState<Set<string>>(new Set());
|
||||
const [batchProgress, setBatchProgress] = useState<{
|
||||
done: number;
|
||||
total: number;
|
||||
} | null>(null);
|
||||
const [busyLib, setBusyLib] = useState<string | null>(null);
|
||||
const batchAbortRef = useRef<AbortController | null>(null);
|
||||
const batch = useBatchImport({
|
||||
url: "/api/admin/import/effects/batch",
|
||||
successAction: "effect(s) imported",
|
||||
cancelledMessage: "Import cancelled",
|
||||
onItemDone: (lib) => markDone(lib),
|
||||
onComplete: () => setSelected(new Set()),
|
||||
});
|
||||
|
||||
const fetchEffects = useCallback(async (search: string) => {
|
||||
setLoading(true);
|
||||
@@ -103,41 +108,10 @@ export function ImportEffectsClient() {
|
||||
}
|
||||
|
||||
async function importViaSse(items: EffectItem[]) {
|
||||
batchAbortRef.current?.abort();
|
||||
const abort = new AbortController();
|
||||
batchAbortRef.current = abort;
|
||||
setBatchProgress({ done: 0, total: items.length });
|
||||
let done = 0;
|
||||
try {
|
||||
await runSseImport(
|
||||
"/api/admin/import/effects/batch",
|
||||
{ items, concurrency: 3 },
|
||||
(lib) => {
|
||||
done++;
|
||||
markDone(lib);
|
||||
setBatchProgress({ done, total: items.length });
|
||||
},
|
||||
(succeeded, failed) => {
|
||||
setSelected(new Set());
|
||||
if (succeeded > 0) toast.success(`${succeeded} effect(s) imported`);
|
||||
if (failed > 0) toast.error(`${failed} failed`);
|
||||
},
|
||||
abort.signal,
|
||||
() => {
|
||||
done++;
|
||||
setBatchProgress({ done, total: items.length });
|
||||
},
|
||||
);
|
||||
} catch (err) {
|
||||
if ((err as Error)?.name === "AbortError") {
|
||||
toast.info("Import cancelled");
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
} finally {
|
||||
if (batchAbortRef.current === abort) batchAbortRef.current = null;
|
||||
setBatchProgress(null);
|
||||
}
|
||||
await batch.run(
|
||||
items.map((e) => e.lib),
|
||||
{ items, concurrency: 3 },
|
||||
);
|
||||
}
|
||||
|
||||
async function importOne(e: EffectItem) {
|
||||
@@ -267,7 +241,7 @@ export function ImportEffectsClient() {
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="text-xs h-8"
|
||||
disabled={!!batchProgress}
|
||||
disabled={batch.running}
|
||||
onClick={() =>
|
||||
setSelected((prev) =>
|
||||
prev.size === importable.length
|
||||
@@ -285,9 +259,9 @@ export function ImportEffectsClient() {
|
||||
size="sm"
|
||||
className="h-8"
|
||||
onClick={importSelected}
|
||||
disabled={!!batchProgress}
|
||||
disabled={batch.running}
|
||||
>
|
||||
{batchProgress ? (
|
||||
{batch.running ? (
|
||||
<Loader2 className="w-4 h-4 animate-spin mr-1" />
|
||||
) : (
|
||||
<Download className="w-4 h-4 mr-1" />
|
||||
@@ -295,20 +269,11 @@ export function ImportEffectsClient() {
|
||||
Import {selected.size} selected
|
||||
</Button>
|
||||
)}
|
||||
{batchProgress && (
|
||||
<>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{batchProgress.done}/{batchProgress.total}
|
||||
</span>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="h-8"
|
||||
onClick={() => batchAbortRef.current?.abort()}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</>
|
||||
{batch.progress && (
|
||||
<BatchImportProgress
|
||||
progress={batch.progress}
|
||||
onCancel={batch.cancel}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
@@ -392,7 +357,7 @@ export function ImportEffectsClient() {
|
||||
size="sm"
|
||||
className="h-5 w-5 p-0 shrink-0"
|
||||
title="Remove effect"
|
||||
disabled={busyLib === e.lib || !!batchProgress}
|
||||
disabled={busyLib === e.lib || batch.running}
|
||||
onClick={() => remove(e)}
|
||||
>
|
||||
<Trash2 className="w-3 h-3" />
|
||||
@@ -403,7 +368,7 @@ export function ImportEffectsClient() {
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="w-full text-xs h-7"
|
||||
disabled={busyLib === e.lib || !!batchProgress}
|
||||
disabled={busyLib === e.lib || batch.running}
|
||||
onClick={() => importOne(e)}
|
||||
>
|
||||
{busyLib === e.lib ? (
|
||||
|
||||
@@ -10,14 +10,17 @@ import {
|
||||
Trash2,
|
||||
X,
|
||||
} from "lucide-react";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
BatchImportProgress,
|
||||
useBatchImport,
|
||||
} from "@/components/admin/import/use-batch-import";
|
||||
import { ImportErrorBanner } from "@/components/admin/import-error-banner";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { adminFetch } from "@/lib/admin-fetch";
|
||||
import { runSseImport } from "@/lib/sse-client";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface PetItem {
|
||||
@@ -46,12 +49,14 @@ export function ImportPetsClient() {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
const [selected, setSelected] = useState<Set<string>>(new Set());
|
||||
const [batchProgress, setBatchProgress] = useState<{
|
||||
done: number;
|
||||
total: number;
|
||||
} | null>(null);
|
||||
const [busyLib, setBusyLib] = useState<string | null>(null);
|
||||
const batchAbortRef = useRef<AbortController | null>(null);
|
||||
const batch = useBatchImport({
|
||||
url: "/api/admin/import/pets/batch",
|
||||
successAction: "pet(s) imported",
|
||||
cancelledMessage: "Import cancelled",
|
||||
onItemDone: (lib) => markDone(lib),
|
||||
onComplete: () => setSelected(new Set()),
|
||||
});
|
||||
|
||||
const fetchPets = useCallback(async (search: string) => {
|
||||
setLoading(true);
|
||||
@@ -100,41 +105,10 @@ export function ImportPetsClient() {
|
||||
}
|
||||
|
||||
async function importViaSse(items: PetItem[]) {
|
||||
batchAbortRef.current?.abort();
|
||||
const abort = new AbortController();
|
||||
batchAbortRef.current = abort;
|
||||
setBatchProgress({ done: 0, total: items.length });
|
||||
let done = 0;
|
||||
try {
|
||||
await runSseImport(
|
||||
"/api/admin/import/pets/batch",
|
||||
{ items, concurrency: 3 },
|
||||
(lib) => {
|
||||
done++;
|
||||
markDone(lib);
|
||||
setBatchProgress({ done, total: items.length });
|
||||
},
|
||||
(succeeded, failed) => {
|
||||
setSelected(new Set());
|
||||
if (succeeded > 0) toast.success(`${succeeded} pet(s) imported`);
|
||||
if (failed > 0) toast.error(`${failed} failed`);
|
||||
},
|
||||
abort.signal,
|
||||
() => {
|
||||
done++;
|
||||
setBatchProgress({ done, total: items.length });
|
||||
},
|
||||
);
|
||||
} catch (err) {
|
||||
if ((err as Error)?.name === "AbortError") {
|
||||
toast.info("Import cancelled");
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
} finally {
|
||||
if (batchAbortRef.current === abort) batchAbortRef.current = null;
|
||||
setBatchProgress(null);
|
||||
}
|
||||
await batch.run(
|
||||
items.map((p) => p.lib),
|
||||
{ items, concurrency: 3 },
|
||||
);
|
||||
}
|
||||
|
||||
async function importOne(p: PetItem) {
|
||||
@@ -247,7 +221,7 @@ export function ImportPetsClient() {
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="text-xs h-8"
|
||||
disabled={!!batchProgress}
|
||||
disabled={batch.running}
|
||||
onClick={() =>
|
||||
setSelected((prev) =>
|
||||
prev.size === importable.length
|
||||
@@ -265,9 +239,9 @@ export function ImportPetsClient() {
|
||||
size="sm"
|
||||
className="h-8"
|
||||
onClick={importSelected}
|
||||
disabled={!!batchProgress}
|
||||
disabled={batch.running}
|
||||
>
|
||||
{batchProgress ? (
|
||||
{batch.running ? (
|
||||
<Loader2 className="w-4 h-4 animate-spin mr-1" />
|
||||
) : (
|
||||
<Download className="w-4 h-4 mr-1" />
|
||||
@@ -275,20 +249,11 @@ export function ImportPetsClient() {
|
||||
Import {selected.size} selected
|
||||
</Button>
|
||||
)}
|
||||
{batchProgress && (
|
||||
<>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{batchProgress.done}/{batchProgress.total}
|
||||
</span>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="h-8"
|
||||
onClick={() => batchAbortRef.current?.abort()}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</>
|
||||
{batch.progress && (
|
||||
<BatchImportProgress
|
||||
progress={batch.progress}
|
||||
onCancel={batch.cancel}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
@@ -351,7 +316,7 @@ export function ImportPetsClient() {
|
||||
size="sm"
|
||||
className="h-5 w-5 p-0 shrink-0"
|
||||
title="Remove pet"
|
||||
disabled={busyLib === p.lib || !!batchProgress}
|
||||
disabled={busyLib === p.lib || batch.running}
|
||||
onClick={() => remove(p)}
|
||||
>
|
||||
<Trash2 className="w-3 h-3" />
|
||||
@@ -362,7 +327,7 @@ export function ImportPetsClient() {
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="w-full text-xs h-7"
|
||||
disabled={busyLib === p.lib || !!batchProgress}
|
||||
disabled={busyLib === p.lib || batch.running}
|
||||
onClick={() => importOne(p)}
|
||||
>
|
||||
{busyLib === p.lib ? (
|
||||
|
||||
Reference in new issue
Block a user