feat : improve import UI
This commit is contained in:
+74
-1
@@ -1,6 +1,6 @@
|
||||
import "server-only";
|
||||
|
||||
import { and, asc, eq, inArray, isNotNull, isNull } from "drizzle-orm";
|
||||
import { and, asc, eq, inArray, isNotNull, isNull, ne } from "drizzle-orm";
|
||||
import * as z from "zod";
|
||||
|
||||
import { getDb } from "@/db";
|
||||
@@ -134,6 +134,79 @@ export async function listGuideCards(includeTrash = false) {
|
||||
}));
|
||||
}
|
||||
|
||||
export async function listAdminTeamImportGuides(excludeGuideId: string) {
|
||||
const rows = await getDb()
|
||||
.select({
|
||||
id: guides.id,
|
||||
name: guides.name,
|
||||
characterKey: guides.characterKey,
|
||||
isPublic: guides.isPublic,
|
||||
coverObjectKey: media.objectKey,
|
||||
})
|
||||
.from(guides)
|
||||
.innerJoin(media, eq(media.id, guides.coverMediaId))
|
||||
.where(and(isNull(guides.trashedAt), ne(guides.id, excludeGuideId)))
|
||||
.orderBy(asc(guides.sortOrder), asc(guides.name));
|
||||
|
||||
return rows.map(({ coverObjectKey, ...guide }) => ({
|
||||
...guide,
|
||||
coverUrl: publicMediaUrl(coverObjectKey),
|
||||
}));
|
||||
}
|
||||
|
||||
export async function getAdminTeamImportGuide(guideId: string) {
|
||||
const [guide] = await getDb()
|
||||
.select({ id: guides.id, name: guides.name })
|
||||
.from(guides)
|
||||
.where(and(eq(guides.id, guideId), isNull(guides.trashedAt)))
|
||||
.limit(1);
|
||||
if (!guide) return null;
|
||||
|
||||
const [conditions, teams] = await Promise.all([
|
||||
getDb().select().from(teamConditions)
|
||||
.where(eq(teamConditions.guideId, guideId))
|
||||
.orderBy(asc(teamConditions.sortOrder)),
|
||||
getDb().select().from(teamCompositions)
|
||||
.where(eq(teamCompositions.guideId, guideId))
|
||||
.orderBy(asc(teamCompositions.sortOrder)),
|
||||
]);
|
||||
const members = teams.length
|
||||
? await getDb()
|
||||
.select({ member: teamMembers, characterName: catalogCharacters.name })
|
||||
.from(teamMembers)
|
||||
.leftJoin(catalogCharacters, eq(catalogCharacters.key, teamMembers.characterKey))
|
||||
.where(inArray(teamMembers.teamId, teams.map((team) => team.id)))
|
||||
.orderBy(asc(teamMembers.position))
|
||||
: [];
|
||||
const hydratedTeams = teams.map((team) => ({
|
||||
id: team.id,
|
||||
title: team.title,
|
||||
rotationSeconds: team.rotationSeconds,
|
||||
combo: team.combo,
|
||||
members: members.filter(({ member }) => member.teamId === team.id).map(({ member, characterName }) => ({
|
||||
characterKey: member.characterKey,
|
||||
characterName: characterName ?? member.characterKey,
|
||||
weaponKey: member.weaponKey,
|
||||
artifactKey: member.artifactKey,
|
||||
secondArtifactKey: member.secondArtifactKey,
|
||||
constellation: member.constellation,
|
||||
refinement: member.refinement,
|
||||
damage: member.damage,
|
||||
})),
|
||||
}));
|
||||
|
||||
return {
|
||||
...guide,
|
||||
groups: conditions.length
|
||||
? conditions.map((condition) => ({
|
||||
id: condition.id,
|
||||
name: condition.name,
|
||||
teams: hydratedTeams.filter((team) => teams.find((candidate) => candidate.id === team.id)?.conditionId === condition.id),
|
||||
}))
|
||||
: [{ id: "team-condition-default", name: null, teams: hydratedTeams }],
|
||||
};
|
||||
}
|
||||
|
||||
export async function listPublicGuideCards() {
|
||||
const [rows, aliases] = await Promise.all([getDb()
|
||||
.select({
|
||||
|
||||
@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
applyTeamFields,
|
||||
cloneTeamImports,
|
||||
findInvalidTeamCatalogReference,
|
||||
findUnsupportedTeamWeapon,
|
||||
limitPresets,
|
||||
@@ -144,6 +145,21 @@ describe("team bulk tools", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("clones imported teams with new ids and independent members", () => {
|
||||
const source = team("source");
|
||||
const transfer = {
|
||||
title: source.title,
|
||||
rotationSeconds: source.rotationSeconds,
|
||||
combo: source.combo,
|
||||
members: source.members,
|
||||
};
|
||||
const imported = cloneTeamImports([transfer], () => "imported-1");
|
||||
|
||||
expect(imported[0]).toEqual({ ...source, clientId: "imported-1" });
|
||||
expect(imported[0].members).not.toBe(source.members);
|
||||
expect(imported[0].members[0]).not.toBe(source.members[0]);
|
||||
});
|
||||
|
||||
it("rejects malformed and unsupported team transfers", () => {
|
||||
expect(() => parseTeamTransfer("not-json")).toThrow();
|
||||
expect(() => parseTeamTransfer(JSON.stringify({
|
||||
|
||||
@@ -106,6 +106,17 @@ export function parseTeamTransfer(serialized: string): Omit<TeamToolValue, "clie
|
||||
};
|
||||
}
|
||||
|
||||
export function cloneTeamImports(
|
||||
teams: readonly Omit<TeamToolValue, "clientId">[],
|
||||
createId: () => string,
|
||||
): TeamToolValue[] {
|
||||
return teams.map((team) => ({
|
||||
clientId: createId(),
|
||||
...team,
|
||||
members: team.members.map((member) => ({ ...member })),
|
||||
}));
|
||||
}
|
||||
|
||||
export function findInvalidTeamCatalogReference(
|
||||
team: Omit<TeamToolValue, "clientId">,
|
||||
characters: readonly TeamToolCatalogItem[],
|
||||
|
||||
Reference in New Issue
Block a user