feat(prob): added filter for tag and storage
This commit is contained in:
@@ -248,7 +248,7 @@ class BrickPartList(BrickRecordList[BrickPart]):
|
||||
|
||||
return self
|
||||
|
||||
def problem_filtered(self, owner_id: str | None = None, color_id: str | None = None, theme_id: str | None = None, year: str | None = None, /) -> Self:
|
||||
def problem_filtered(self, owner_id: str | None = None, color_id: str | None = None, theme_id: str | None = None, year: str | None = None, storage_id: str | None = None, tag_id: str | None = None, /) -> Self:
|
||||
# Save the filter parameters for client-side filtering
|
||||
if owner_id is not None:
|
||||
self.fields.owner_id = owner_id
|
||||
@@ -265,6 +265,10 @@ class BrickPartList(BrickRecordList[BrickPart]):
|
||||
context['theme_id'] = theme_id
|
||||
if year and year != 'all':
|
||||
context['year'] = year
|
||||
if storage_id and storage_id != 'all':
|
||||
context['storage_id'] = storage_id
|
||||
if tag_id and tag_id != 'all':
|
||||
context['tag_id'] = tag_id
|
||||
if current_app.config.get('SKIP_SPARE_PARTS', False):
|
||||
context['skip_spare_parts'] = True
|
||||
|
||||
@@ -279,6 +283,8 @@ class BrickPartList(BrickRecordList[BrickPart]):
|
||||
color_id: str | None = None,
|
||||
theme_id: str | None = None,
|
||||
year: str | None = None,
|
||||
storage_id: str | None = None,
|
||||
tag_id: str | None = None,
|
||||
search_query: str | None = None,
|
||||
page: int = 1,
|
||||
per_page: int = 50,
|
||||
@@ -295,6 +301,10 @@ class BrickPartList(BrickRecordList[BrickPart]):
|
||||
filter_context['theme_id'] = theme_id
|
||||
if year and year != 'all':
|
||||
filter_context['year'] = year
|
||||
if storage_id and storage_id != 'all':
|
||||
filter_context['storage_id'] = storage_id
|
||||
if tag_id and tag_id != 'all':
|
||||
filter_context['tag_id'] = tag_id
|
||||
if search_query:
|
||||
filter_context['search_query'] = search_query
|
||||
if current_app.config.get('SKIP_SPARE_PARTS', False):
|
||||
|
||||
@@ -53,6 +53,12 @@ ON "bricktracker_sets"."set" IS NOT DISTINCT FROM "rebrickable_sets"."set"
|
||||
LEFT JOIN "bricktracker_set_owners"
|
||||
ON "bricktracker_sets"."id" IS NOT DISTINCT FROM "bricktracker_set_owners"."id"
|
||||
|
||||
-- Left join with set tags (for tag filtering)
|
||||
{% if tag_id and tag_id != 'all' %}
|
||||
LEFT JOIN "bricktracker_set_tags"
|
||||
ON "bricktracker_sets"."id" IS NOT DISTINCT FROM "bricktracker_set_tags"."id"
|
||||
{% endif %}
|
||||
|
||||
-- Left join with minifigures
|
||||
LEFT JOIN "bricktracker_minifigures"
|
||||
ON "bricktracker_parts"."id" IS NOT DISTINCT FROM "bricktracker_minifigures"."id"
|
||||
@@ -75,6 +81,12 @@ AND "bricktracker_parts"."figure" IS NOT DISTINCT FROM "bricktracker_minifigures
|
||||
{% if year and year != 'all' %}
|
||||
{% set _ = conditions.append('"rebrickable_sets"."year" = ' ~ year) %}
|
||||
{% endif %}
|
||||
{% if storage_id and storage_id != 'all' %}
|
||||
{% set _ = conditions.append('"bricktracker_sets"."storage" = \'' ~ storage_id ~ '\'') %}
|
||||
{% endif %}
|
||||
{% if tag_id and tag_id != 'all' %}
|
||||
{% set _ = conditions.append('"bricktracker_set_tags"."tag_' ~ tag_id ~ '" = 1') %}
|
||||
{% endif %}
|
||||
{% if search_query %}
|
||||
{% set search_condition = '(LOWER("rebrickable_parts"."name") LIKE LOWER(\'%' ~ search_query ~ '%\') OR LOWER("rebrickable_parts"."color_name") LIKE LOWER(\'%' ~ search_query ~ '%\') OR LOWER("bricktracker_parts"."part") LIKE LOWER(\'%' ~ search_query ~ '%\'))' %}
|
||||
{% set _ = conditions.append(search_condition) %}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
-- Get distinct storages from problem parts' sets
|
||||
SELECT DISTINCT
|
||||
"bricktracker_sets"."storage" AS "storage_id",
|
||||
"bricktracker_metadata_storages"."name" AS "storage_name",
|
||||
COUNT(DISTINCT "bricktracker_parts"."part") as "part_count"
|
||||
FROM "bricktracker_parts"
|
||||
INNER JOIN "bricktracker_sets"
|
||||
ON "bricktracker_parts"."id" IS NOT DISTINCT FROM "bricktracker_sets"."id"
|
||||
LEFT JOIN "bricktracker_metadata_storages"
|
||||
ON "bricktracker_sets"."storage" IS NOT DISTINCT FROM "bricktracker_metadata_storages"."id"
|
||||
{% if owner_id and owner_id != 'all' %}
|
||||
INNER JOIN "bricktracker_set_owners"
|
||||
ON "bricktracker_sets"."id" IS NOT DISTINCT FROM "bricktracker_set_owners"."id"
|
||||
{% endif %}
|
||||
WHERE ("bricktracker_parts"."missing" > 0 OR "bricktracker_parts"."damaged" > 0)
|
||||
AND "bricktracker_sets"."storage" IS NOT NULL
|
||||
{% if owner_id and owner_id != 'all' %}
|
||||
AND "bricktracker_set_owners"."owner_{{ owner_id }}" = 1
|
||||
{% endif %}
|
||||
GROUP BY "bricktracker_sets"."storage", "bricktracker_metadata_storages"."name"
|
||||
ORDER BY "bricktracker_metadata_storages"."name" ASC
|
||||
@@ -0,0 +1,7 @@
|
||||
-- Get list of all tags (simplified - filtering happens at application level)
|
||||
-- Tags use dynamic columns in bricktracker_set_tags, making direct SQL filtering complex
|
||||
SELECT
|
||||
"bricktracker_metadata_tags"."id" AS "tag_id",
|
||||
"bricktracker_metadata_tags"."name" AS "tag_name"
|
||||
FROM "bricktracker_metadata_tags"
|
||||
ORDER BY "bricktracker_metadata_tags"."name" ASC
|
||||
@@ -105,6 +105,8 @@ def problem() -> str:
|
||||
color_id = request.args.get('color', 'all')
|
||||
theme_id = request.args.get('theme', 'all')
|
||||
year = request.args.get('year', 'all')
|
||||
storage_id = request.args.get('storage', 'all')
|
||||
tag_id = request.args.get('tag', 'all')
|
||||
search_query, sort_field, sort_order, page = get_request_params()
|
||||
|
||||
# Get pagination configuration
|
||||
@@ -118,6 +120,8 @@ def problem() -> str:
|
||||
color_id=color_id,
|
||||
theme_id=theme_id,
|
||||
year=year,
|
||||
storage_id=storage_id,
|
||||
tag_id=tag_id,
|
||||
search_query=search_query,
|
||||
page=page,
|
||||
per_page=per_page,
|
||||
@@ -128,7 +132,7 @@ def problem() -> str:
|
||||
pagination_context = build_pagination_context(page, per_page, total_count, is_mobile)
|
||||
else:
|
||||
# ORIGINAL MODE - Single page with all data for client-side search
|
||||
parts = BrickPartList().problem_filtered(owner_id, color_id, theme_id, year)
|
||||
parts = BrickPartList().problem_filtered(owner_id, color_id, theme_id, year, storage_id, tag_id)
|
||||
pagination_context = None
|
||||
|
||||
# Get list of owners for filter dropdown
|
||||
@@ -157,6 +161,12 @@ def problem() -> str:
|
||||
# Get list of years for filter dropdown (problem parts only)
|
||||
years = BrickSQL().fetchall('part/years/list_problem', **filter_context)
|
||||
|
||||
# Get list of storages for filter dropdown (problem parts only)
|
||||
storages = BrickSQL().fetchall('part/storages/list_problem', **filter_context)
|
||||
|
||||
# Get list of tags for filter dropdown (problem parts only)
|
||||
tags = BrickSQL().fetchall('part/tags/list_problem', **filter_context)
|
||||
|
||||
return render_template(
|
||||
'problem.html',
|
||||
table_collection=parts,
|
||||
@@ -172,7 +182,11 @@ def problem() -> str:
|
||||
themes=themes,
|
||||
selected_theme=theme_id,
|
||||
years=years,
|
||||
selected_year=year
|
||||
selected_year=year,
|
||||
storages=storages,
|
||||
selected_storage=storage_id,
|
||||
tags=tags,
|
||||
selected_tag=tag_id
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -314,12 +314,14 @@ window.updateUrlParams = function(params, resetPage = true) {
|
||||
window.location.href = currentUrl.toString();
|
||||
};
|
||||
|
||||
// Shared filter application (supports owner, color, theme, year, and problems filters)
|
||||
// Shared filter application (supports owner, color, theme, year, storage, tag, and problems filters)
|
||||
window.applyPageFilters = function(tableId) {
|
||||
const ownerSelect = document.getElementById('filter-owner');
|
||||
const colorSelect = document.getElementById('filter-color');
|
||||
const themeSelect = document.getElementById('filter-theme');
|
||||
const yearSelect = document.getElementById('filter-year');
|
||||
const storageSelect = document.getElementById('filter-storage');
|
||||
const tagSelect = document.getElementById('filter-tag');
|
||||
const problemsSelect = document.getElementById('filter-problems');
|
||||
const params = {};
|
||||
|
||||
@@ -343,6 +345,16 @@ window.applyPageFilters = function(tableId) {
|
||||
params.year = yearSelect.value;
|
||||
}
|
||||
|
||||
// Handle storage filter
|
||||
if (storageSelect) {
|
||||
params.storage = storageSelect.value;
|
||||
}
|
||||
|
||||
// Handle tag filter
|
||||
if (tagSelect) {
|
||||
params.tag = tagSelect.value;
|
||||
}
|
||||
|
||||
// Handle problems filter (for minifigures page)
|
||||
if (problemsSelect) {
|
||||
params.problems = problemsSelect.value;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div id="table-filter" class="collapse {% if config['SHOW_GRID_FILTERS'] %}show{% endif %} row row-cols-lg-auto g-1 justify-content-center align-items-center">
|
||||
{% if owners | length %}
|
||||
<div class="col-12 col-md-6 col-lg-3 flex-grow-1">
|
||||
<div class="col-12 col-md-6 col-lg-2 flex-grow-1">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="ri-user-line"></i><span class="ms-1 d-none d-md-inline"> Owner</span></span>
|
||||
<select id="filter-owner" class="form-select" onchange="applyFiltersAndKeepOpen()" autocomplete="off">
|
||||
@@ -13,7 +13,7 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if colors | length %}
|
||||
<div class="col-12 col-md-6 col-lg-3 flex-grow-1">
|
||||
<div class="col-12 col-md-6 col-lg-2 flex-grow-1">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="ri-palette-line"></i><span class="ms-1 d-none d-md-inline"> Color</span></span>
|
||||
<select id="filter-color" class="form-select" onchange="applyFiltersAndKeepOpen()" autocomplete="off">
|
||||
@@ -28,7 +28,7 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if themes | length %}
|
||||
<div class="col-12 col-md-6 col-lg-3 flex-grow-1">
|
||||
<div class="col-12 col-md-6 col-lg-2 flex-grow-1">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="ri-price-tag-3-line"></i><span class="ms-1 d-none d-md-inline"> Theme</span></span>
|
||||
<select id="filter-theme" class="form-select" onchange="applyFiltersAndKeepOpen()" autocomplete="off">
|
||||
@@ -41,7 +41,7 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if years | length %}
|
||||
<div class="col-12 col-md-6 col-lg-3 flex-grow-1">
|
||||
<div class="col-12 col-md-6 col-lg-2 flex-grow-1">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="ri-calendar-line"></i><span class="ms-1 d-none d-md-inline"> Year</span></span>
|
||||
<select id="filter-year" class="form-select" onchange="applyFiltersAndKeepOpen()" autocomplete="off">
|
||||
@@ -53,4 +53,30 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if storages | length %}
|
||||
<div class="col-12 col-md-6 col-lg-2 flex-grow-1">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="ri-inbox-line"></i><span class="ms-1 d-none d-md-inline"> Storage</span></span>
|
||||
<select id="filter-storage" class="form-select" onchange="applyFiltersAndKeepOpen()" autocomplete="off">
|
||||
<option value="all" {% if selected_storage == 'all' %}selected{% endif %}>All storages</option>
|
||||
{% for storage in storages %}
|
||||
<option value="{{ storage.storage_id }}" {% if selected_storage == storage.storage_id %}selected{% endif %}>{{ storage.storage_name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if tags | length %}
|
||||
<div class="col-12 col-md-6 col-lg-2 flex-grow-1">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="ri-price-tag-line"></i><span class="ms-1 d-none d-md-inline"> Tag</span></span>
|
||||
<select id="filter-tag" class="form-select" onchange="applyFiltersAndKeepOpen()" autocomplete="off">
|
||||
<option value="all" {% if selected_tag == 'all' %}selected{% endif %}>All tags</option>
|
||||
{% for tag in tags %}
|
||||
<option value="{{ tag.tag_id }}" {% if selected_tag == tag.tag_id %}selected{% endif %}>{{ tag.tag_name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
Reference in New Issue
Block a user