fix: wire catalog add buttons, fix Trans bold rendering, lint cleanup
Some checks failed
CI / ci (push) Failing after 1m44s
CI / e2e (push) Has been skipped
CI / deploy (push) Has been skipped

- CatalogSearchOverlay: replace handleAddStub with real openAddToCollection/openAddToThread routing based on catalogSearchMode
- ConfirmDialog + __root.tsx: swap t() for Trans component on deleteItemMessage, deleteCandidateMessage, pickWinnerMessage — fixes <bold> rendering as literal text
- Biome format pass: fix 23 lint/format errors across scripts, services, tests
- Planning: mark all UAT and verification gaps resolved for phases 07, 11, 16, 20, 21, 22, 24, 32, 34; close debug sessions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-19 15:36:16 +02:00
parent 16058d0f4d
commit 4ccbb2b070
40 changed files with 807 additions and 227 deletions

View File

@@ -18,9 +18,9 @@ import { communityPriceRoutes } from "./routes/community-prices.ts";
import { discoveryRoutes } from "./routes/discovery.ts";
import { exchangeRateRoutes } from "./routes/exchange-rates.ts";
import { globalItemRoutes } from "./routes/global-items.ts";
import { manufacturerRoutes } from "./routes/manufacturers.ts";
import { imageRoutes } from "./routes/images.ts";
import { itemRoutes } from "./routes/items.ts";
import { manufacturerRoutes } from "./routes/manufacturers.ts";
import { marketPriceRoutes } from "./routes/market-prices.ts";
import { oauthRoutes, wellKnownRoute } from "./routes/oauth.ts";
import { onboardingRoutes } from "./routes/onboarding.ts";

View File

@@ -22,10 +22,14 @@ function errorResult(message: string): ToolResult {
}
const catalogItemInputSchema = {
manufacturerSlug: z.string().describe("Manufacturer slug (e.g. 'revelate-designs', 'apidura')"),
manufacturerSlug: z
.string()
.describe("Manufacturer slug (e.g. 'revelate-designs', 'apidura')"),
model: z
.string()
.describe("Model name — combined with manufacturerSlug forms the unique identifier"),
.describe(
"Model name — combined with manufacturerSlug forms the unique identifier",
),
category: z
.string()
.optional()

View File

@@ -31,7 +31,10 @@ app.post("/", zValidator("json", createManufacturerSchema), async (c) => {
const manufacturer = await createManufacturer(db, data);
return c.json(manufacturer, 201);
} catch {
return c.json({ error: "Manufacturer with this name or slug already exists" }, 409);
return c.json(
{ error: "Manufacturer with this name or slug already exists" },
409,
);
}
});

View File

@@ -1,6 +1,11 @@
import { eq, sql } from "drizzle-orm";
import type { db as prodDb } from "../../db/index.ts";
import { categories, globalItems, items, manufacturers } from "../../db/schema.ts";
import {
categories,
globalItems,
items,
manufacturers,
} from "../../db/schema.ts";
import { getOrCreateUncategorized } from "./category.service.ts";
type Db = typeof prodDb;

View File

@@ -1,12 +1,21 @@
import type { SQL } from "drizzle-orm";
import { and, count, eq, ilike, or, sql } from "drizzle-orm";
import { db as prodDb } from "../../db/index.ts";
import { globalItems, globalItemTags, items, manufacturers, tags } from "../../db/schema.ts";
import {
globalItems,
globalItemTags,
items,
manufacturers,
tags,
} from "../../db/schema.ts";
type Db = typeof prodDb;
type TxDb = Parameters<Parameters<Db["transaction"]>[0]>[0];
async function resolveManufacturerId(db: Db | TxDb, slug: string): Promise<number> {
async function resolveManufacturerId(
db: Db | TxDb,
slug: string,
): Promise<number> {
const [m] = await (db as Db)
.select({ id: manufacturers.id })
.from(manufacturers)
@@ -26,7 +35,10 @@ export async function searchGlobalItems(
const escaped = query.replace(/%/g, "\\%").replace(/_/g, "\\_");
const pattern = `%${escaped}%`;
conditions.push(
or(ilike(manufacturers.name, pattern), ilike(globalItems.model, pattern))!,
or(
ilike(manufacturers.name, pattern),
ilike(globalItems.model, pattern),
)!,
);
}
@@ -221,7 +233,10 @@ export async function bulkUpsertGlobalItems(
const resultItems = [];
for (const data of itemsData) {
const manufacturerId = await resolveManufacturerId(tx as unknown as Db, data.manufacturerSlug);
const manufacturerId = await resolveManufacturerId(
tx as unknown as Db,
data.manufacturerSlug,
);
const [existing] = await tx
.select({ id: globalItems.id })

View File

@@ -1,6 +1,11 @@
import { and, eq, sql } from "drizzle-orm";
import type { db as prodDb } from "../../db/index.ts";
import { categories, globalItems, items, manufacturers } from "../../db/schema.ts";
import {
categories,
globalItems,
items,
manufacturers,
} from "../../db/schema.ts";
import type { CreateItem } from "../../shared/types.ts";
type Db = typeof prodDb;
@@ -122,7 +127,10 @@ export async function createItem(
const [gi] = await db
.select({ name: manufacturers.name, model: globalItems.model })
.from(globalItems)
.innerJoin(manufacturers, eq(globalItems.manufacturerId, manufacturers.id))
.innerJoin(
manufacturers,
eq(globalItems.manufacturerId, manufacturers.id),
)
.where(eq(globalItems.id, data.globalItemId));
if (gi) {
name = `${gi.name} ${gi.model}`;

View File

@@ -371,7 +371,10 @@ export async function resolveThread(
const [gi] = await tx
.select({ name: manufacturers.name, model: globalItems.model })
.from(globalItems)
.innerJoin(manufacturers, eq(globalItems.manufacturerId, manufacturers.id))
.innerJoin(
manufacturers,
eq(globalItems.manufacturerId, manufacturers.id),
)
.where(eq(globalItems.id, candidate.globalItemId));
const fallbackName = gi ? `${gi.name} ${gi.model}` : candidate.name;
insertValues = {