fix: remove lingering FM references from insights services
CI / Lint · Typecheck · Test · Build (push) Successful in 59s
CI / Playwright (smoke) (push) Has been skipped
CI / Build & push images (push) Successful in 2m22s

tx.fm.count calls + fmsImplicating fields were missed in the main FM
removal pass. Drops the field from Category/Manufacturer/PartModel
insights types, services, tests, and detail-page stat cards.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-19 18:51:56 -04:00
parent db8e86b749
commit da6bd071ee
12 changed files with 12 additions and 60 deletions
+2 -8
View File
@@ -17,7 +17,6 @@ interface FakeArgs {
};
repairCount: number;
distinctFailedBrokenPartIds: string[];
fmCount: number;
modelStateGroups: { partModelId: string; state: string; count: number }[];
allModels: {
id: string;
@@ -65,9 +64,6 @@ function makeTx(args: FakeArgs): Tx {
return args.repairsWithModel;
},
},
fm: {
count: async () => args.fmCount,
},
};
return tx as unknown as Tx;
}
@@ -79,7 +75,6 @@ const empty: FakeArgs = {
priceAgg: { sum: null, avg: null, min: null, max: null, count: 0 },
repairCount: 0,
distinctFailedBrokenPartIds: [],
fmCount: 0,
modelStateGroups: [],
allModels: [],
eolModels: [],
@@ -124,15 +119,14 @@ describe('categories.getInsights', () => {
});
});
it('counts repairs, distinct failed parts, and FMs implicating the category', async () => {
it('counts repairs and distinct failed parts', async () => {
const tx = makeTx({
...empty,
repairCount: 5,
distinctFailedBrokenPartIds: ['p1', 'p2', 'p3'],
fmCount: 4,
});
const r = await getInsights(tx, 'cat');
expect(r!.failures).toEqual({ repairs: 5, distinctFailedParts: 3, fmsImplicating: 4 });
expect(r!.failures).toEqual({ repairs: 5, distinctFailedParts: 3 });
});
it('derives topModelsByUnits from modelStateGroups, sorted desc, truncated to 8', async () => {
-5
View File
@@ -28,7 +28,6 @@ export async function getInsights(tx: Tx, id: string): Promise<CategoryInsights
priceAgg,
repairsCount,
distinctFailedParts,
fmsImplicating,
modelStateGroups,
allModels,
eolModels,
@@ -50,9 +49,6 @@ export async function getInsights(tx: Tx, id: string): Promise<CategoryInsights
select: { brokenPartId: true },
distinct: ['brokenPartId'],
}),
tx.fm.count({
where: { problemParts: { some: { part: modelWhere } } },
}),
tx.part.groupBy({
by: ['partModelId', 'state'],
where: modelWhere,
@@ -145,7 +141,6 @@ export async function getInsights(tx: Tx, id: string): Promise<CategoryInsights
failures: {
repairs: repairsCount,
distinctFailedParts: distinctFailedParts.length,
fmsImplicating,
},
byManufacturer,
topModelsByUnits,
+2 -8
View File
@@ -17,7 +17,6 @@ interface FakeArgs {
};
repairCount: number;
distinctFailedBrokenPartIds: string[];
fmCount: number;
// rows used by part.groupBy({ by: ['partModelId','state'] })
modelStateGroups: { partModelId: string; state: string; count: number }[];
// rows for the partModel.findMany(select: { id, mpn, category }) call
@@ -71,9 +70,6 @@ function makeTx(args: FakeArgs): Tx {
return args.repairsWithModel;
},
},
fm: {
count: async () => args.fmCount,
},
};
return tx as unknown as Tx;
}
@@ -85,7 +81,6 @@ const empty: FakeArgs = {
priceAgg: { sum: null, avg: null, min: null, max: null, count: 0 },
repairCount: 0,
distinctFailedBrokenPartIds: [],
fmCount: 0,
modelStateGroups: [],
allModels: [],
eolModels: [],
@@ -130,15 +125,14 @@ describe('manufacturers.getInsights', () => {
});
});
it('counts repairs, distinct failed parts, and FMs implicating the manufacturer', async () => {
it('counts repairs and distinct failed parts', async () => {
const tx = makeTx({
...empty,
repairCount: 5,
distinctFailedBrokenPartIds: ['p1', 'p2', 'p3'],
fmCount: 4,
});
const r = await getInsights(tx, 'mfr');
expect(r!.failures).toEqual({ repairs: 5, distinctFailedParts: 3, fmsImplicating: 4 });
expect(r!.failures).toEqual({ repairs: 5, distinctFailedParts: 3 });
});
it('derives topModelsByUnits from modelStateGroups, sorted desc, truncated to 8', async () => {
-3
View File
@@ -27,7 +27,6 @@ export async function getInsights(tx: Tx, id: string): Promise<ManufacturerInsig
priceAgg,
repairsCount,
distinctFailedParts,
fmsImplicating,
modelStateGroups,
allModels,
eolModels,
@@ -49,7 +48,6 @@ export async function getInsights(tx: Tx, id: string): Promise<ManufacturerInsig
select: { brokenPartId: true },
distinct: ['brokenPartId'],
}),
tx.fm.count({ where: { problemParts: { some: { part: { manufacturerId: id } } } } }),
tx.part.groupBy({
by: ['partModelId', 'state'],
where: { manufacturerId: id },
@@ -143,7 +141,6 @@ export async function getInsights(tx: Tx, id: string): Promise<ManufacturerInsig
failures: {
repairs: repairsCount,
distinctFailedParts: distinctFailedParts.length,
fmsImplicating,
},
byCategory,
topModelsByUnits,
+1 -12
View File
@@ -17,7 +17,6 @@ function makeTx(args: {
};
repairCount: number;
distinctFailedBrokenPartIds: string[];
fmCount: number;
}): Tx {
const tx = {
partModel: {
@@ -44,9 +43,6 @@ function makeTx(args: {
findMany: async () =>
args.distinctFailedBrokenPartIds.map((brokenPartId) => ({ brokenPartId })),
},
fm: {
count: async () => args.fmCount,
},
};
return tx as unknown as Tx;
}
@@ -60,7 +56,6 @@ describe('part-models.getInsights', () => {
priceAgg: { sum: null, avg: null, min: null, max: null, count: 0 },
repairCount: 0,
distinctFailedBrokenPartIds: [],
fmCount: 0,
});
const r = await getInsights(tx, 'nope');
expect(r).toBeNull();
@@ -77,7 +72,6 @@ describe('part-models.getInsights', () => {
priceAgg: { sum: 900, avg: 450, min: 100, max: 500, count: 2 },
repairCount: 0,
distinctFailedBrokenPartIds: [],
fmCount: 0,
});
const r = await getInsights(tx, 'pm');
@@ -98,7 +92,6 @@ describe('part-models.getInsights', () => {
priceAgg: { sum: 600, avg: 300, min: 100, max: 500, count: 2 },
repairCount: 0,
distinctFailedBrokenPartIds: [],
fmCount: 0,
});
const r = await getInsights(tx, 'pm');
@@ -119,7 +112,6 @@ describe('part-models.getInsights', () => {
priceAgg: { sum: null, avg: null, min: null, max: null, count: 0 },
repairCount: 0,
distinctFailedBrokenPartIds: [],
fmCount: 0,
});
const r = await getInsights(tx, 'pm');
@@ -132,23 +124,20 @@ describe('part-models.getInsights', () => {
});
});
it('counts repairs, distinct failed parts, and FMs implicating the model', async () => {
it('counts repairs and distinct failed parts', async () => {
const tx = makeTx({
modelExists: true,
partCount: 5,
stateRows: [],
priceAgg: { sum: 0, avg: null, min: null, max: null, count: 0 },
repairCount: 3,
// one part failed twice → 2 distinct broken parts
distinctFailedBrokenPartIds: ['part-a', 'part-b'],
fmCount: 2,
});
const r = await getInsights(tx, 'pm');
expect(r!.failures).toEqual({
repairs: 3,
distinctFailedParts: 2,
fmsImplicating: 2,
});
});
});
+1 -3
View File
@@ -43,7 +43,7 @@ export async function getInsights(tx: Tx, id: string): Promise<PartModelInsights
const model = await tx.partModel.findUnique({ where: { id }, select: { id: true } });
if (!model) return null;
const [totalParts, stateRows, priceAgg, repairs, failedParts, fmsImplicating] = await Promise.all([
const [totalParts, stateRows, priceAgg, repairs, failedParts] = await Promise.all([
tx.part.count({ where: { partModelId: id } }),
tx.part.groupBy({
by: ['state'],
@@ -65,7 +65,6 @@ export async function getInsights(tx: Tx, id: string): Promise<PartModelInsights
select: { brokenPartId: true },
distinct: ['brokenPartId'],
}),
tx.fm.count({ where: { problemParts: { some: { part: { partModelId: id } } } } }),
]);
const byState = stateRows.map((row) => ({
@@ -87,7 +86,6 @@ export async function getInsights(tx: Tx, id: string): Promise<PartModelInsights
failures: {
repairs,
distinctFailedParts: failedParts.length,
fmsImplicating,
},
};
}
+2 -6
View File
@@ -270,9 +270,9 @@ export default function CategoryDetail() {
</div>
</div>
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6">
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5">
{insightsQuery.isPending || !insights ? (
Array.from({ length: 6 }).map((_, i) => <Skeleton key={i} className="h-20" />)
Array.from({ length: 5 }).map((_, i) => <Skeleton key={i} className="h-20" />)
) : (
<>
<StatCard label="MPNs" value={insights.totalPartModels.toLocaleString()} />
@@ -300,10 +300,6 @@ export default function CategoryDetail() {
: undefined
}
/>
<StatCard
label="FMs implicated"
value={insights.failures.fmsImplicating.toLocaleString()}
/>
</>
)}
</div>
+2 -6
View File
@@ -256,9 +256,9 @@ export default function ManufacturerDetail() {
</div>
</div>
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6">
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5">
{insightsQuery.isPending || !insights ? (
Array.from({ length: 6 }).map((_, i) => <Skeleton key={i} className="h-20" />)
Array.from({ length: 5 }).map((_, i) => <Skeleton key={i} className="h-20" />)
) : (
<>
<StatCard label="MPNs" value={insights.totalPartModels.toLocaleString()} />
@@ -286,10 +286,6 @@ export default function ManufacturerDetail() {
: undefined
}
/>
<StatCard
label="FMs implicated"
value={insights.failures.fmsImplicating.toLocaleString()}
/>
</>
)}
</div>
+2 -6
View File
@@ -262,9 +262,9 @@ export default function PartModelDetail() {
</div>
</div>
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-5">
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
{insightsQuery.isPending || !insights ? (
Array.from({ length: 5 }).map((_, i) => <Skeleton key={i} className="h-20" />)
Array.from({ length: 4 }).map((_, i) => <Skeleton key={i} className="h-20" />)
) : (
<>
<StatCard label="Units" value={insights.totalParts.toLocaleString()} />
@@ -291,10 +291,6 @@ export default function PartModelDetail() {
: undefined
}
/>
<StatCard
label="FMs implicated"
value={insights.failures.fmsImplicating.toLocaleString()}
/>
</>
)}
</div>