Skip to content

Commit fc45cfb

Browse files
committed
Fix catalog matching for partially specified source presets
1 parent 596f8f9 commit fc45cfb

2 files changed

Lines changed: 40 additions & 0 deletions

File tree

src/core/preset-search.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,13 @@ export function getFilterFields(parts: PartDefinition[]): PresetFilterField[] {
160160

161161
export function seedCurrentFilters(part: PartDefinition, parameters: Parameters): PresetFilters {
162162
const filters = emptyPresetFilters(part);
163+
const currentPreset =
164+
part.presets.find((preset) => preset.catalog && preset.parameters === parameters) ??
165+
part.presets.find(
166+
(preset) =>
167+
preset.catalog &&
168+
part.parameters.every((field) => preset.parameters[field.key] === parameters[field.key]),
169+
);
163170
const keys =
164171
part.presetMatchKeys ??
165172
part.parameters
@@ -170,6 +177,15 @@ export function seedCurrentFilters(part: PartDefinition, parameters: Parameters)
170177
if (field.filterable === false) continue;
171178
if (!keys.includes(field.key) || (field.visibleWhen && !field.visibleWhen(parameters)))
172179
continue;
180+
// An exact catalog configuration also contains editable prototype dimensions.
181+
// Do not turn those assumptions into automatic catalog requirements.
182+
if (
183+
currentPreset?.catalog &&
184+
field.type === 'number' &&
185+
!currentPreset.catalog.verifiedParameters.includes(field.key) &&
186+
!getPresetParameterRange(currentPreset, field.key)
187+
)
188+
continue;
173189
const value = parameters[field.key];
174190
if (field.type === 'number' && typeof value === 'number' && Number.isFinite(value)) {
175191
filters.parameters[fieldId(field)] = { min: String(value), max: String(value) };

tests/preset-search.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,30 @@ test('current-parameter matching is opt-in and ignores hidden or invalid fields'
309309
);
310310
});
311311

312+
test('exact catalog matching skips assumed dimensions while custom matching preserves requested values', () => {
313+
const preset: Preset = {
314+
id: 'nominal-only',
315+
name: 'Nominal bore reference',
316+
description: 'Width is an editable prototype assumption.',
317+
parameters: { bore: 20, width: 14 },
318+
catalog: { ...source, verifiedParameters: ['bore'] },
319+
};
320+
const configurable = {
321+
...part('reference', [bore, width], [preset]),
322+
defaults: { ...preset.parameters },
323+
presetMatchKeys: ['bore', 'width'],
324+
};
325+
for (const values of [preset.parameters, { ...preset.parameters }]) {
326+
const filters = seedCurrentFilters(configurable, values);
327+
assert.deepEqual(filters.parameters[boreId], { min: '20', max: '20' });
328+
assert.equal(filters.parameters[fieldId(width)], undefined);
329+
assert.equal(filterPresets(buildPresetIndex([configurable]), filters).items[0].preset, preset);
330+
}
331+
const custom = seedCurrentFilters(configurable, { ...preset.parameters, width: 16 });
332+
assert.deepEqual(custom.parameters[fieldId(width)], { min: '16', max: '16' });
333+
assert.equal(filterPresets(buildPresetIndex([configurable]), custom).items.length, 0);
334+
});
335+
312336
test('a hidden conditional parameter never matches an inactive preset feature', () => {
313337
const socket: ParameterDefinition = {
314338
key: 'socketDepth',

0 commit comments

Comments
 (0)