Embed labels in filter criteria (Stash-style) to retire pill resolver

Store {id, label} objects instead of bare IDs in MultiCriterion value/excludes.
FilterSelect pills now render directly from the embedded labels — no DB round-trip
to _resolve_game/device/platform_options. The filter URL and saved presets are
self-describing. MultiCriterion.to_q() extracts ids for querying; bare ints are
still accepted for backward compatibility.

Closes #9

https://claude.ai/code/session_01EyAJcMoDktLrY9tSbdHViA
This commit is contained in:
Claude
2026-06-08 17:18:38 +00:00
committed by Lukáš Kucharczyk
parent 112d3107ef
commit 0285243172
4 changed files with 104 additions and 63 deletions
+27 -5
View File
@@ -76,11 +76,33 @@
field === "game" ||
field === "device" ||
field === "games";
filter[field] = {
value: isIdField ? included.map(Number) : included,
excludes: isIdField ? excluded.map(Number) : excluded,
modifier: modifier || "INCLUDES",
};
if (isIdField) {
// Store {id, label} objects so the filter URL/preset is self-describing
// and pills can be rendered without a DB lookup (Stash-style).
filter[field] = {
value: included.map(function (item) {
return typeof item === "object"
? {id: parseInt(item.id, 10), label: item.label || ""}
: {id: parseInt(item, 10), label: ""};
}),
excludes: excluded.map(function (item) {
return typeof item === "object"
? {id: parseInt(item.id, 10), label: item.label || ""}
: {id: parseInt(item, 10), label: ""};
}),
modifier: modifier || "INCLUDES",
};
} else {
filter[field] = {
value: included.map(function (item) {
return typeof item === "object" ? item.id : item;
}),
excludes: excluded.map(function (item) {
return typeof item === "object" ? item.id : item;
}),
modifier: modifier || "INCLUDES",
};
}
}
});
+4 -2
View File
@@ -435,10 +435,12 @@
return;
}
var value = pill.getAttribute("data-value");
var label = pill.getAttribute("data-label") || "";
var entry = label ? {id: value, label: label} : value;
if (pill.getAttribute("data-search-select-type") === "exclude") {
excluded.push(value);
excluded.push(entry);
} else {
included.push(value);
included.push(entry);
}
});
}